/* =====================================================================
   COWBOY'S AC — v14 "NEW YEAR"
   Additive layer on top of css/site.css?v=4.0. Never edit site.css —
   79 other pages load it. Everything new lives here.

   MOBILE FIRST. 80%+ of this site's traffic is a phone, so every block
   below is authored at phone width and widened with min-width queries.
   ===================================================================== */

/* ---------------------------------------------------------------
   0 · BOOT LOADER
   First visit only, hard-capped at 1.6s, determinate progress tied to
   real preloads. Fades instantly under prefers-reduced-motion.
   --------------------------------------------------------------- */
.boot{position:fixed;inset:0;z-index:200;display:grid;place-items:center;
  background:var(--bg);overflow:hidden;
  transition:opacity .5s var(--ease),visibility .5s var(--ease)}
.boot[hidden]{display:none}
.boot.is-done{opacity:0;visibility:hidden;pointer-events:none}
html.booting,html.booting body{overflow:hidden;height:100%}

.boot__plate{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:.34;filter:saturate(.72) contrast(1.06)}
.boot__scrim{position:absolute;inset:0;
  background:radial-gradient(120% 85% at 50% 42%,rgba(14,9,7,.35),rgba(14,9,7,.93) 72%)}

.boot__in{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;
  gap:1.15rem;padding:0 1.5rem;text-align:center;width:100%}

/* the real brand mark, revealed by a rising wipe rather than a fake
   stroke-draw of a logo we do not have as vector art */
.boot__logo{width:min(190px,52vw);height:auto;
  clip-path:inset(0 0 100% 0);animation:markup .66s var(--ease) .06s forwards}
@keyframes markup{to{clip-path:inset(0 0 0 0)}}

/* 72 -> 100 */
.boot__temp{font-family:var(--display);font-weight:700;line-height:.9;
  font-size:clamp(3.6rem,17vw,6.4rem);color:var(--cream);font-variant-numeric:tabular-nums}
.boot__temp sup{font-size:.38em;color:var(--red2);vertical-align:super;margin-left:.06em}

.boot__line{font-family:var(--mono);font-size:.6rem;letter-spacing:.26em;text-transform:uppercase;
  color:var(--t3);opacity:0;animation:fadein .5s ease .46s forwards}
@keyframes fadein{to{opacity:1}}

.boot__track{width:min(220px,58vw);height:2px;background:rgba(244,234,214,.14);overflow:hidden}
.boot__bar{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--red),var(--gold));
  transition:width .28s linear}

/* the gold sweep that hands off to the hero */
.boot__wipe{position:absolute;inset:0;z-index:3;pointer-events:none;
  background:linear-gradient(105deg,transparent 42%,var(--gold2) 50%,transparent 58%);
  transform:translate3d(-130%,0,0)}
.boot.is-wiping .boot__wipe{animation:wipe .62s var(--ease) forwards}
@keyframes wipe{to{transform:translate3d(130%,0,0)}}

@media (min-width:99999px) /* was prefers-reduced-motion:reduce — motion forced on */{
  .boot__logo{animation:none;clip-path:none}
  .boot__line{animation:none;opacity:1}
  .boot.is-wiping .boot__wipe{animation:none}
  .boot{transition:opacity .2s linear}
}

/* ---------------------------------------------------------------
   1 · FILM GRAIN
   One fixed tiled layer at ~3.5%. Cheap: a 64px tile, no blend mode,
   no filter, promoted to its own layer once and never repainted.
   --------------------------------------------------------------- */
.grain{position:fixed;inset:0;z-index:90;pointer-events:none;opacity:.035;
  background-image:var(--grain-tile);background-size:128px 128px}
@media (min-width:99999px) /* was prefers-reduced-motion:reduce — motion forced on */{.grain{opacity:.025}}

/* ---------------------------------------------------------------
   2 · CINEMATIC HERO
   Phone: 100dvh so the iOS URL bar cannot cause a jump, content pinned
   to the bottom above the safe area, single-column stacked CTAs.
   --------------------------------------------------------------- */
/* The hero sits BELOW the util strip + sticky header, so a flat 100dvh
   pushes its own CTAs under the fold. --chrome is that stack's height and
   is subtracted so the buttons land on the first screenful. */
.chero{--chrome:104px;
  position:relative;min-height:calc(100svh - var(--chrome));
  min-height:calc(100dvh - var(--chrome));display:flex;
  align-items:flex-end;overflow:hidden;background:var(--bg2);isolation:isolate}
@media(max-width:1100px){.chero{--chrome:100px}}
/* a short phone in landscape must not letterbox the headline away */
@media(max-height:560px){.chero{--chrome:0px;min-height:auto;padding-top:2.5rem}}
.chero__media{position:absolute;inset:0;z-index:0}
.chero__media img,.chero__media video{width:100%;height:100%;object-fit:cover;object-position:50% 42%}
.chero__media video{position:absolute;inset:0;opacity:0;transition:opacity 1.1s ease}
.chero__media video.is-playing{opacity:1}
/* Two layers: a soft top wash so the header reads, and a hard bottom
   floor so cream type never has to fight a bright van panel. */
.chero__scrim{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(180deg,rgba(14,9,7,.72) 0%,rgba(14,9,7,.16) 30%,transparent 46%),
    linear-gradient(180deg,transparent 40%,rgba(14,9,7,.72) 66%,rgba(14,9,7,.94) 86%,var(--bg) 100%)}

.chero__in{position:relative;z-index:2;width:100%;
  padding-block:clamp(1.4rem,5vh,3rem) calc(clamp(1.8rem,6vh,3.2rem) + env(safe-area-inset-bottom))}

.chero__ttl{font-family:var(--display);font-weight:700;text-transform:uppercase;
  line-height:.9;letter-spacing:-.015em;font-size:clamp(2.6rem,12vw,6.6rem);
  text-wrap:balance;margin-top:.85rem;text-shadow:0 2px 30px rgba(0,0,0,.45)}
.chero__ttl em{font-style:normal;color:var(--red2)}
.chero__sub{color:var(--t2);max-width:46ch;margin-top:1rem;font-size:clamp(.98rem,3.6vw,1.18rem);text-wrap:pretty}

/* rotating sub-line: absolutely stacked so frames never overlap mid-fade */
.chero__rot{position:relative;min-height:1.6em;margin-top:.9rem}
.chero__rot b{position:absolute;inset-inline-start:0;top:0;font-weight:400;
  font-family:var(--mono);font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--gold2);opacity:0;transition:opacity .5s ease}
.chero__rot b.on{opacity:1}

.chero__cta{display:grid;gap:.6rem;margin-top:1.6rem}
.chero__cta .btn{width:100%}
@media(min-width:560px){
  .chero__cta{display:flex;flex-wrap:wrap}
  .chero__cta .btn{width:auto}
}

/* live weather + dispatch HUD — a real readout, not decoration */
.hud{display:flex;flex-wrap:wrap;gap:.45rem;margin-bottom:.2rem}
.hud__pill{display:inline-flex;align-items:center;gap:.5rem;min-height:34px;
  padding:.3rem .8rem;border:1px solid var(--line);border-radius:999px;
  background:rgba(14,9,7,.55);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  font-family:var(--mono);font-size:.58rem;letter-spacing:.17em;text-transform:uppercase;color:var(--t3)}
.hud__pill b{color:var(--cream);font-weight:400;font-size:.74rem;font-variant-numeric:tabular-nums}
.hud__pill i{width:6px;height:6px;border-radius:50%;background:var(--red);flex:none;
  animation:pulse 2.6s ease-in-out infinite}
.hud__pill--live b{color:var(--gold2)}

.chero__cue{position:absolute;left:50%;bottom:calc(.5rem + env(safe-area-inset-bottom));z-index:3;
  transform:translateX(-50%);display:none;width:1px;height:38px;
  background:linear-gradient(180deg,transparent,var(--gold))}
@media(min-width:900px) and (min-height:700px){
  .chero__cue{display:block;animation:cue 2.6s var(--ease) infinite}
}
@keyframes cue{0%{opacity:0;transform:translateX(-50%) scaleY(.2)}
  40%{opacity:1;transform:translateX(-50%) scaleY(1)}
  100%{opacity:0;transform:translateX(-50%) scaleY(1)}}
@media (min-width:99999px) /* was prefers-reduced-motion:reduce — motion forced on */{.chero__cue{animation:none;opacity:.7}}

/* ---------------------------------------------------------------
   3 · SECTION MARKER — the "00 /" chapter number
   --------------------------------------------------------------- */
.chap{display:flex;align-items:baseline;gap:.8rem;
  font-family:var(--mono);font-size:.62rem;letter-spacing:.24em;text-transform:uppercase}
.chap span{color:var(--red2)}
.chap em{font-style:normal;color:var(--t3)}

/* ---------------------------------------------------------------
   4 · BENTO — the services lineup, deliberately asymmetric.
   Phone: one column, the lead tile first. 900px+: 6-col bento.
   --------------------------------------------------------------- */
.bento{display:grid;gap:.8rem;grid-template-columns:1fr}
.tile{position:relative;overflow:hidden;border:1px solid var(--line);border-radius:1rem;
  background:linear-gradient(168deg,rgba(44,28,21,.6),rgba(22,14,10,.88));
  display:flex;flex-direction:column;justify-content:flex-end;
  min-height:210px;padding:clamp(1.1rem,4vw,1.6rem);isolation:isolate;
  transition:border-color .35s ease,transform .5s var(--ease)}
.tile:hover{border-color:var(--line2)}
@media(hover:hover){.tile:hover{transform:translateY(-3px)}}
/* ONE GRADE FOR ALL SIX.
   These photos come from six different cameras across several years —
   a green UV-lit duct, a blown-out daylight fleet shot, a near-black
   product render. Ungraded they read as a scrapbook. Pulling saturation
   down, warmth up and exposure to a common level makes them read as one
   set, and it neutralises the green and blue casts that fight the brand. */
.tile__bg{position:absolute;inset:0;z-index:-1;width:100%;height:100%;object-fit:cover;
  opacity:.62;
  filter:grayscale(.34) sepia(.22) saturate(1.06) contrast(1.05) brightness(.74);
  transition:opacity .5s ease,transform .9s var(--ease),filter .5s ease}
@media(hover:hover){
  .tile:hover .tile__bg{opacity:.76;transform:scale(1.04);
    filter:grayscale(.16) sepia(.14) saturate(1.12) contrast(1.06) brightness(.84)}
}
/* A floor, not a wash. The copy always sits on near-solid ground, so a
   bright sky in one photo can never bleach a headline in another. */
.tile::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,
    rgba(14,9,7,.30) 0%,
    rgba(14,9,7,.42) 34%,
    rgba(14,9,7,.86) 68%,
    rgba(14,9,7,.96) 100%)}
.tile b{font-family:var(--mono);font-size:.6rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--gold);font-weight:400}
.tile h3{font-family:var(--display);font-weight:700;text-transform:uppercase;line-height:1;
  font-size:clamp(1.35rem,5.5vw,1.9rem);margin-top:.5rem}
.tile p{color:var(--t2);font-size:.92rem;margin-top:.5rem;text-wrap:pretty}
.tile .go{font-family:var(--mono);font-size:.64rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--red2);margin-top:.9rem}
.tile--lead{min-height:300px}
@media(min-width:900px){
  .bento{grid-template-columns:repeat(6,1fr);gap:1rem}
  .tile--lead{grid-column:span 4;min-height:360px}
  .tile--tall{grid-column:span 2;grid-row:span 2}
  .tile--wide{grid-column:span 4}
  .tile--half{grid-column:span 2}
}

/* ---------------------------------------------------------------
   5 · THE CARD — a real 3D flip. Tap on touch, hover on pointer.
   --------------------------------------------------------------- */
.flip{perspective:1400px;max-width:520px;margin-inline:auto;width:100%}
.flip__in{position:relative;width:100%;aspect-ratio:1.586/1;
  transform-style:preserve-3d;transition:transform .9s var(--ease);cursor:pointer;
  border:0;padding:0;background:transparent;display:block}
.flip.is-flipped .flip__in{transform:rotateY(180deg)}
@media(hover:hover){.flip:hover .flip__in{transform:rotateY(180deg)}}
.flip__face{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;
  border:1px solid var(--line2);border-radius:.9rem;overflow:hidden;background:var(--panel)}
.flip__face video,.flip__face img{width:100%;height:100%;object-fit:cover}
.flip__face--back{transform:rotateY(180deg)}
.flip__hint{display:block;margin-top:.9rem;text-align:center;
  font-family:var(--mono);font-size:.6rem;letter-spacing:.2em;text-transform:uppercase;color:var(--t3)}
@media (min-width:99999px) /* was prefers-reduced-motion:reduce — motion forced on */{.flip__in{transition:none}}

/* ---------------------------------------------------------------
   6 · 3D MODULE MOUNT
   A phone gets a still + a real link instead of a WebGL context it may
   not afford. The iframe only mounts when the device clears the bar.
   --------------------------------------------------------------- */
.mod{position:relative;border:1px solid var(--line);border-radius:1rem;overflow:hidden;
  background:radial-gradient(120% 90% at 50% 10%,rgba(232,176,74,.10),transparent 60%),
             linear-gradient(180deg,#150e09,#0e0907);
  aspect-ratio:4/3}
@media(min-width:820px){.mod{aspect-ratio:16/9}}

/* A module sitting in a two-column row is only ~640px wide, so the scene
   inside it collapses to a single column and stacks its controls BELOW the
   model. 16/9 is far too short for that — it needs portrait room.
   Only applies where the iframe actually mounts (>=900px); narrower than
   that the module is a poster and a link, and keeps its 4/3. */
@media(min-width:900px){
  .mod--stack{aspect-ratio:auto;height:clamp(540px,58vh,620px)}
}
.mod iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.mod__poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.5;
  transition:opacity .6s ease}
.mod.is-live .mod__poster{opacity:0;pointer-events:none}
.mod__cta{position:absolute;inset:0;z-index:2;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:.7rem;text-align:center;padding:1.2rem;
  background:linear-gradient(180deg,rgba(14,9,7,.35),rgba(14,9,7,.82))}
.mod.is-live .mod__cta{display:none}
.mod__cta b{font-family:var(--display);font-weight:700;text-transform:uppercase;
  font-size:clamp(1.1rem,4.5vw,1.5rem);line-height:1.05}
.mod__cta span{font-family:var(--mono);font-size:.6rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--t3)}

/* ---------------------------------------------------------------
   7 · PROOF STRIP — live numbers, tabular so they cannot jitter
   --------------------------------------------------------------- */
.proof{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--hair);
  border:1px solid var(--hair);border-radius:1rem;overflow:hidden}
@media(min-width:760px){.proof{grid-template-columns:repeat(4,1fr)}}
.proof>div{background:var(--bg);padding:clamp(1rem,4vw,1.5rem)}
.proof b{display:block;font-family:var(--display);font-weight:700;line-height:1;
  font-size:clamp(1.7rem,7vw,2.5rem);font-variant-numeric:tabular-nums;color:var(--cream)}
.proof span{display:block;margin-top:.5rem;font-family:var(--mono);font-size:.57rem;
  letter-spacing:.17em;text-transform:uppercase;color:var(--t3)}

/* ---------------------------------------------------------------
   8 · SCROLL-DRIVEN MOTION — progressive enhancement only.
   Native where supported (Chrome/Edge/Safari 26+). Firefox and older
   simply get the static layout; site.js's IntersectionObserver still
   drives the [data-m] reveals, so nothing is ever gated to invisible.
   --------------------------------------------------------------- */
@media all{ /* was prefers-reduced-motion:no-preference — motion forced on */
  @supports ((animation-timeline:view()) and (animation-range:entry)){
    @keyframes riseIn{from{opacity:0;transform:translateY(22px)}}
    [data-rise]{animation:riseIn auto var(--ease) both}
    [data-rise]{animation-timeline:view();animation-range:entry 4% cover 26%}

    /* hero parallax — the plate drifts slower than the page */
    @keyframes plateDrift{to{transform:translateY(9%) scale(1.06)}}
    .chero__media{animation:plateDrift auto linear both}
    .chero__media{animation-timeline:view();animation-range:exit-crossing}
  }
}

/* ---------------------------------------------------------------
   9 · MOBILE CORRECTNESS
   --------------------------------------------------------------- */
/* the loader must clear the notch */
.boot__in{padding-top:env(safe-area-inset-top)}
/* nothing tappable under 44px */
.flip__in,.mod__cta a,.tile{min-height:44px}
/* the sticky call bar already reserves body padding in site.css — the hero
   is full-bleed above it and must not inherit that gap */
.chero{margin-bottom:0}
/* long service names must never force a sideways scroll */
.tile h3,.chero__ttl{overflow-wrap:break-word}

@media(max-width:400px){
  .chero__ttl{font-size:clamp(2.2rem,11.5vw,3rem)}
  .hud__pill{font-size:.54rem;letter-spacing:.14em}
}

/* On a phone the sub-line earns its place only if it is short. The long
   version is desktop copy; below 640px we show the tightened one. */
.chero__sub .long{display:none}
@media(min-width:640px){
  .chero__sub .short{display:none}
  .chero__sub .long{display:inline}
}

/* ---------------------------------------------------------------
   10 · TAP TARGETS
   site.css only enforces 44px under @media(hover:none). Real phones
   and tablets can report a hover-capable pointer (stylus, trackpad,
   emulation), so the footer links were still landing at 18-20px.
   Enforce it by VIEWPORT instead, which cannot be spoofed away.
   --------------------------------------------------------------- */
@media(max-width:1100px){
  .footer li a,
  .footer__legal a,
  .social a{min-height:44px;display:inline-flex;align-items:center}
  .footer li{margin-bottom:.1rem}
  .footer__legal{gap:.4rem 1.1rem}
  .footer__bottom{gap:.4rem}
}

/* ---------------------------------------------------------------
   10 · FORCED MOBILE MOTION (2026-09-22)
   Live 3D scenes now mount on phones too. They need real height, and
   on touch they sit behind a clear shield until tapped so a swipe
   scrolls the page instead of spinning the model.
   --------------------------------------------------------------- */
@media(max-width:899px){
  .mod.is-live{aspect-ratio:auto;height:min(78svh,620px)}
  .mod--stack.is-live{height:min(86svh,700px)}
}
.mod__shield{position:absolute;inset:0;z-index:3;border:0;padding:0;margin:0;background:transparent;
  display:flex;align-items:center;justify-content:center;cursor:pointer}
.mod__shield span{font-family:var(--mono);font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--cream);background:rgba(14,9,7,.78);border:1px solid var(--line2);border-radius:99px;padding:.6rem 1rem;
  box-shadow:0 0 0 0 rgba(232,176,74,.4);animation:shieldPulse 2.4s ease-out infinite}
@keyframes shieldPulse{0%{box-shadow:0 0 0 0 rgba(232,176,74,.45)}80%,100%{box-shadow:0 0 0 12px rgba(232,176,74,0)}}
.mod__lock{display:none;position:absolute;z-index:4;top:.7rem;right:.7rem;min-height:44px;padding:.5rem 1rem;border-radius:99px;
  border:1px solid var(--line2);background:rgba(14,9,7,.82);color:var(--cream);font-family:var(--mono);font-size:.62rem;letter-spacing:.18em;text-transform:uppercase}
.mod.is-grabbed .mod__shield{display:none}
.mod.is-grabbed .mod__lock{display:block}
.mod:not(.is-live) .mod__shield,.mod:not(.is-live) .mod__lock{display:none}
