/*
 * engine.css: the hero's structure, its legibility layers and the page's plumbing
 * (smwd-cinematic starter, engine file).
 *
 * Identical on every site and never edited for one: check-site compares it with the
 * starter's hashes. A change to a hero rule is a hero change and needs Stanley's
 * written yes. No design lives here: no colour outside the legibility block, no face,
 * type scale, spacing, radius, shadow, gradient or easing value. tokens.css, hero.css
 * and site.css load after this file and carry the look.
 */

/* ---- Page plumbing */

/* clip on both, hidden first as the fallback (scrub-pipeline.md, overflow) */
html,body{overflow-x:hidden;overflow-x:clip}

/* Fields take the page's type, so an iPhone does not zoom into a small one. */
input,select,textarea,button{font:inherit}

.visually-hidden:not(:focus):not(:active){position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;padding:0!important;overflow:hidden!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;white-space:nowrap!important;border:0!important}

/* The skip link focuses <main id="main" tabindex="-1">; the region needs no ring. */
#main:focus{outline:none}
:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* Touch targets of 44px without changing layout (scrub-pipeline.md, quality floor). */
@media (pointer:coarse){
  input:not([type=hidden],[type=checkbox],[type=radio]),select,textarea,button{min-height:44px}
  [data-tap]{display:inline-flex;align-items:center;justify-content:center;min-height:44px;min-width:44px}
}

/* The enquiry's honeypot: a person never sees it (references/wordpress.md, the enquiry). */
[name="smwd_hp"]{position:absolute!important;left:-9999px!important}
[aria-hidden="true"]:has([name="smwd_hp"]){position:absolute!important;left:-9999px!important}

/* Hidden tabs pause every loop; animation-play-state does not inherit, so it is set on
   every element and pseudo-element (scrub-pipeline.md, the motion system). */
body.paused *,body.paused *::before,body.paused *::after{animation-play-state:paused!important}

/* Reduced motion, completely: no animation or transition anywhere, every delay zeroed,
   and an entrance that fills forwards lands at once on its final state. The hero takes
   its own route: gate 5 gives it the static hero and no film. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;animation-delay:0s!important;transition-duration:0s!important;transition-delay:0s!important;scroll-behavior:auto!important}
}

/* ---- The hero (scrub-pipeline.md, the hero structure)
   Without JavaScript the stage stays hidden and the static hero is the hero (T-052).
   With it, the stage pins inside a hero as tall as hero.json's height. */
.hero{position:relative}
.stage{display:none}
.js .hero{height:var(--hero-h,400vh)}
.js .stage{display:block;position:sticky;top:0;height:100vh;overflow:hidden}

/* hero.js paints the chosen cut's poster here, inside the gated path. */
.poster{position:absolute;inset:0;background-position:center;background-size:cover;background-repeat:no-repeat}

/* The film, on its own compositor layer, fades in over the poster once it can play.
   A film that fails is hidden over the poster, and the page carries on (T-051). */
#hero{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;will-change:transform;transition:opacity .6s var(--ease-out)}
.video-ready #hero{opacity:1}
.video-failed #hero{display:none}

/* Bands: hero.js writes opacity and --k; hero.css positions them. A band is its own
   stacking context, so its scrim sits under its words and over the film. Opacity 0
   still takes clicks, so a band's links and buttons take a click or tap only while
   hero.js marks the band data-shown (at least half visible); keyboard focus still
   reaches them. */
.band{position:absolute;isolation:isolate;pointer-events:none}
.band::before{z-index:-1}
.band[data-shown] a,.band[data-shown] button{pointer-events:auto}
.js .band{opacity:0}
.band > *{position:relative}

/* The splitter's spans: transforms need boxes, and a word never breaks inside. */
.band .w,.band .c{display:inline-block}
.band .w{white-space:nowrap}
.band .sharp{position:absolute;left:0;top:0;width:100%}

/* The default entrance, scatter (scrub-pipeline.md, menu item a). A band whose own
   entrance threw or is unknown falls back to it. Every other entrance is per site. */
.band[data-entrance="scatter"] .c,.band[data-entrance-fallback] .c{--kc:clamp(0,(var(--k,0) - var(--th,0))*2.6,1);opacity:var(--kc);
   transform:translate(calc((1 - var(--kc))*var(--jx,0px)),calc((1 - var(--kc))*var(--jy,0px)))
             rotate(calc((1 - var(--kc))*var(--jr,0deg)))}

/* The loading ring, and the honest scroll cue that replaces it when a cut fails
   (T-051). The ring is SVG, which has no hidden property, so its states are classes. */
.ring{position:absolute;z-index:1;left:50%;bottom:4rem;width:3rem;height:3rem;margin-left:-1.5rem;transform:rotate(-90deg);transition:opacity .6s var(--ease-out)}
.video-ready .ring{opacity:0}
.video-failed .ring{display:none}
.chevron{position:absolute;z-index:1;left:50%;bottom:4rem;width:1.5rem;height:.9rem;margin-left:-.75rem;background:currentColor;clip-path:polygon(0 0,50% 64%,100% 0,100% 36%,50% 100%,0 36%)}
.hero [hidden]{display:none!important}

/* ---- The gates (scrub-pipeline.md, the hero's gates). The five strings match hero.js
   character for character. Before hero.js decides, the queries choose as it will:
   gates 1 to 4 give an upright phone its own cut and the phone height. */
@media (max-width: 720px), (orientation: portrait) and (max-width: 1024px), (orientation: portrait) and (pointer: coarse), (orientation: landscape) and (pointer: coarse) and (max-height: 560px){
  .js .hero{height:var(--hero-h-phone,var(--hero-h,400vh))}
}
/* The static hero: gate 5, and a phone gate held sideways. */
@media (prefers-reduced-motion: reduce), (orientation: landscape) and (pointer: coarse) and (max-height: 560px), (max-width: 720px) and (orientation: landscape){
  .js .hero{height:auto}
  .js .stage{display:none}
}
/* Then hero.js's choice, on <html data-hero>, which also covers Save-Data and a theme
   with no mobile cut. */
.js[data-hero="still"] .hero{height:auto}
.js[data-hero="still"] .stage{display:none}
/* The static hero is hidden only where a scrub hero runs: none of the static queries
   match and hero.js has not chosen it. Hidden from the start, so a scrub visitor never
   downloads the static hero's image; the site's own display value is kept otherwise. */
@media not all and (prefers-reduced-motion: reduce){
  @media not all and (orientation: landscape) and (pointer: coarse) and (max-height: 560px){
    @media not all and (max-width: 720px) and (orientation: landscape){
      .js:not([data-hero="still"]) .static-hero{display:none}
    }
  }
}

/* A short screen keeps the scrub but drops the small overlays marked for it. */
@media (max-height:560px){[data-short-hide]{display:none}}

/* The four layers for text over live footage, verbatim from scrub-pipeline.md, and the
   one place colour lives in this file. A site may tint them toward its film's grade in
   hero.css, keeping the alphas and passing the worst-frame audit, with Stanley's yes. */
/* legibility: scrub-pipeline.md */
.scrim{position:absolute;inset:0;pointer-events:none;background:radial-gradient(ellipse 120% 90% at 50% 45%,rgba(10,10,18,0) 35%,rgba(10,10,18,.62) 100%)}
.band::before{content:"";position:absolute;inset:-4%;pointer-events:none;opacity:calc(.25 + .75*var(--k,1));background:radial-gradient(ellipse 74% 62% at 50% 50%,rgba(5,5,10,.66) 0%,rgba(5,5,10,.44) 46%,rgba(5,5,10,0) 76%)}
:root{--tshadow:0 1px 2px rgba(5,5,10,.95),0 3px 12px rgba(5,5,10,.78),0 10px 44px rgba(5,5,10,.8)}
.band{text-shadow:var(--tshadow)}
.band .btn{text-shadow:none}
.chip{background:rgba(8,8,15,.55);border:1px solid rgba(96,96,126,.3);border-radius:10px;backdrop-filter:blur(10px);text-shadow:0 1px 3px rgba(5,5,10,.85)}
/* /legibility */
