/* ==========================================================================
   CRAYTON — the cinematic layer
   Loaded AFTER styles.css. It does three things:
     1. Re-grades every design token to colours sampled out of the hero
        footage itself, so page and film read as one room.
     2. Adds the scroll-scrubbed hero (the aperture).
     3. Adds the fixed environment layer and the light-fall.
   The page's structure, copy and form behaviour are untouched.
   ========================================================================== */

/* --------------------------------------------------------------------- */
/* 1 · The grade                                                          */
/*                                                                        */
/* Every value below was sampled out of the hero footage itself with      */
/* ffmpeg (scale=8:11, rgb24) rather than                                 */
/* picked by eye. Two things came out of that sample and both drive the   */
/* palette: the shadows in this footage carry almost no blue at all       */
/* (#0c0a00, #100b00), so the dark is a warm olive-black, not a neutral   */
/* one. And the window glass reads as a desaturated sage-grey (#7f817a,   */
/* #9b9d96) — the one tone in the frame that is neither warm nor neutral. */
/* That sage is the structural colour here. It is also what keeps this    */
/* page off the amber-accent-on-near-black look that every cinematic AI   */
/* site defaults to.                                                      */
/* --------------------------------------------------------------------- */

:root{
  /* Surfaces */
  --bone:#F3EFE5;        /* window light, sampled #f6f3ed */
  --paper:#FBF8F1;       /* the brightest pane, #fffbf0, pulled back */
  --dark:#0B0A05;        /* the wall plane, sampled #0c0a00 */
  --dark-2:#15120A;      /* the same wall one stop up */

  /* Ink */
  --ink:#17150F;
  --ink-2:#46443B;
  --muted:#5C5B51;
  --on-dark:#F1ECE1;
  --on-dark-2:#BFBAAD;

  /* Lines */
  --line:#DFD9CC;
  --line-strong:#C6BFAF;
  --line-dark:rgba(241,236,225,.14);

  /* Accent — the window glass. Rules, kickers, numerals, focus. */
  --accent:#5D6058;
  --accent-on-dark:#9BA093;

  /* Supporting mid-tones, used in atmosphere only, never as an accent */
  --oak:#8A6A4A;         /* the floor */
  --haze:#E9DFCB;        /* the light coming through the glass */

  /* Hero geometry. 832 x 1114 is the encoded footage. */
  --ap-ratio:.74686;
  --header-h:74px;
  --ease-cine:cubic-bezier(.16,1,.3,1);
}

/* The browser chrome should match the room the page opens in. */
/* (theme-color is set in the markup; this is the scrollbar.) */
html{color-scheme:light;scrollbar-color:var(--line-strong) var(--bone);}

/* Selection follows the new accent. The list has to name the dark grounds
   this stylesheet created as well as the ones styles.css knew about, or
   dragging across the hero, the pull quote or the dark comparison card
   paints dark ink on a dark ground and the words vanish while selected. */
.section-dark ::selection,
.section-request ::selection,
.site-footer ::selection,
.cine ::selection,
.pullquote-dark ::selection,
.compare-new ::selection{background:rgb(155 160 147 / .32);color:var(--on-dark);}

/* --------------------------------------------------------------------- */
/* 2 · The environment                                                    */
/*                                                                        */
/* One fixed layer behind the whole document carrying a slow warm         */
/* light-fall, so scrolling reads as moving through a room rather than    */
/* past stacked blocks. 96 second cycle, negative delay so it is already  */
/* mid-drift at first paint. It only reads through the dark sections,     */
/* which is why those are the ones given a translucent ground below.      */
/* --------------------------------------------------------------------- */

.env{
  position:fixed;
  inset:-10%;
  z-index:0;
  pointer-events:none;
  background:
    radial-gradient(60% 44% at 78% 22%,rgba(233,223,203,.20) 0%,rgba(233,223,203,0) 68%),
    radial-gradient(52% 38% at 14% 78%,rgba(138,106,74,.16) 0%,rgba(138,106,74,0) 70%);
  animation:envdrift 96s var(--ease) infinite alternate -31s;
}
@keyframes envdrift{
  from{transform:translate3d(-1.4%,-1%,0) scale(1.02);}
  to{transform:translate3d(1.8%,1.6%,0) scale(1.08);}
}

/* Everything real sits above the environment. The header keeps its own
   position and stacking order: folding it into this rule quietly turned it
   from sticky into relative and the hero scrolled straight over it. */
main,.site-footer{position:relative;z-index:1;}
.site-header{z-index:100;}
.sticky-cta{z-index:90;}

/* The dark grounds go translucent so the light-fall genuinely modulates
   them. The light grounds stay solid: an 8% wash over bone is invisible
   and only costs a composite. */
.section-dark,
.section-request,
.pullquote-dark,
.site-footer{
  /* background-color plus background-image, never the shorthand: the
     shorthand here silently deleted the within-section light-fall that
     styles.css draws, and all four dark sections rendered as flat slabs.
     The gradient is translucent so the fixed .env-lift behind still reads
     through and the calibrated ground value is unchanged. */
  background-color:rgb(11 10 5 / .93);
  background-image:radial-gradient(120% 90% at 12% 0%,
    rgb(233 223 203 / .055) 0%, rgb(233 223 203 / 0) 60%);
}

.section-dark,.section-request,.pullquote-dark{position:relative;}
.section-dark > *,
.section-request > *,
.pullquote-dark > *{position:relative;z-index:1;}

/* The light-fall itself, angled the way the light arrives through the glass
   in the footage: from the upper right.

   It is one FIXED layer over the whole document rather than a gradient
   inside each dark section. Per-section glows restart at every boundary,
   and two dark sections in a row (the pull quote above the experience) met
   in a hard horizontal seam where one glow ended and the next began. Being
   anchored to the window instead means the light stays where it is while
   the page moves through it, which is what being in a room actually feels
   like, and there is no boundary for it to break at.

   soft-light is what lets a single layer serve both grounds: it opens up
   the dark sections and barely touches the light ones. */
.env-lift{
  position:fixed;
  inset:-15%;
  /* BEHIND the content, not over it. This used to sit at z-index 5 on
     mix-blend-mode:soft-light, and it was the single most expensive thing on
     the site. A blended layer cannot be composited on its own: the browser has
     to read back everything underneath and re-blend it every time either one
     moves. This layer is fixed, covers 130% of the viewport in both directions,
     and drifts on a 96-second animation that never stops, so that read-back was
     running on every frame of every scroll anywhere on the page, and on plenty
     of frames where nobody was scrolling at all.

     Measured on a 1440x900 laptop at 4x CPU throttle, scrolling the ordinary
     page below the hero:
         with soft-light   p95 42.1ms, worst 183.8ms, 17 frames over 33ms
         without           p95 22.9ms, worst  40.6ms,  2 frames over 33ms
     That is the whole "the whole page feels laggy, and lower down too".

     The look survives because the effect never actually needed a blend mode.
     The point of this layer, stated in the note above, is that it opens up the
     dark sections and barely touches the light ones. The dark sections are
     already translucent and the light ones are opaque, so a layer sitting
     BEHIND them does exactly that by construction: it reads through the dark
     grounds and is completely hidden by the light ones. Same single fixed
     light, same no-seam-between-dark-sections behaviour, no per-frame
     read-back.

     Calibrated by sampling rendered pixels against the live site rather than
     by eye, and the sampling corrected a wrong assumption: the dark grounds
     did NOT need opening up to compensate. Sweeping ground opacity against
     gradient strength showed .93, the original value, reproduces the old
     footer and pull quote to within one value per channel, while .88 came out
     nine too bright. The soft-light pass was only ever worth about +1 of
     brightness on those grounds, which is why losing it costs nothing
     visible. The gradient alphas below are raised because they now read
     through a 93% opaque ground instead of blending over the top of it. */
  z-index:0;
  pointer-events:none;
  background:
    radial-gradient(66% 54% at 90% 8%,rgba(255,231,196,.46) 0%,rgba(255,231,196,0) 70%),
    radial-gradient(52% 46% at 4% 94%,rgba(206,160,110,.20) 0%,rgba(206,160,110,0) 74%);
  animation:envdrift 96s var(--ease) infinite alternate -31s;
}

/* --------------------------------------------------------------------- */
/* 3 · The aperture — the scroll-scrubbed hero                            */
/*                                                                        */
/* The footage is 832 x 1114, portrait. Rather than upscale it 1.7x to    */
/* fill a desktop viewport and lose both the sharpness and the floor,     */
/* it is presented at close to native size inside a full-height window,   */
/* with the type held in the dark beside it. The frame is the window in   */
/* the shot; the page is measured against it. That is the signature.      */
/* --------------------------------------------------------------------- */

.cine{
  position:relative;
  /* Was 460vh. The founder's words: "too much scrolling before the real
     site", and that is his call to make. The stage is sticky and 100vh, so
     the scrolled range is this minus 100vh: 360vh became 220vh, which is a
     39% shorter entrance. On a 900px laptop that is 11 trackpad flicks down
     to 7 before the page proper begins.

     Cutting it does not rush the zoom. Scroll maps to time through
     f(p) = p + p^3(1-p), so the film still runs 0 to 1 across whatever
     distance is given and still comes to rest on the last frame. The beats
     hold less scroll each, which is checked by the beat map rather than
     assumed: every band must still reach full opacity and hold. */
  /* One screen. It was 460vh, then 280, then 220, and all of it was scroll
     spent driving a film frame by frame. The film plays itself now, so
     that scroll bought nothing and cost about nine trackpad flicks before
     the page proper began. */
  height:100vh;
  height:100svh;
  background:var(--dark);
  z-index:1;
  /* The header is sticky and takes 74px of flow. The room has to start at
     the very top of the window, so the hero is pulled up under it and the
     header rides over the footage on a scrim of its own. */
  margin-top:calc(-1 * var(--header-h));
}
.cine-stage{
  /* The stage is the measuring reference for the type column's left edge,
     so it declares itself a container. cqw is the stage's own width, which
     excludes the scrollbar; 100vw does not, and the headline would sit
     eight pixels off the line every other section is on. */
  container-type:inline-size;
  position:sticky;
  top:0;
  height:100vh;
  height:100svh;
  overflow:hidden;
  background:var(--dark);
  display:grid;
  grid-template-columns:1fr min(74.686vh,50vw);
  align-items:center;
  isolation:isolate;
}

/* The room the words are held in: the wall plane from the footage, lit
   from the aperture side so the two halves share one light source. */
.cine-stage::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  background:
    radial-gradient(110% 80% at 96% 30%,rgba(233,223,203,.14) 0%,rgba(233,223,203,0) 58%),
    linear-gradient(180deg,#0A0904 0%,#0E0C06 52%,#080703 100%);
}

/* ---- the media window ---- */
.ap{
  grid-area:1/2;
  position:relative;
  z-index:1;
  height:100vh;
  height:100svh;
  overflow:hidden;
  background:#0A0904;
  /* A hairline on the inner edge: the mullion. It is the same rule that
     sits under every kicker further down the page. */
  box-shadow:-1px 0 0 0 rgba(241,236,225,.13);
}
.ap-poster,
.ap-video{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:58% 50%;
}
.ap-poster{
  /* Declared here, not only painted by hero.js. The largest paint on the
     page was gated behind main.js and hero.js executing, so on a slow
     connection the room appeared seconds later than the bytes that drew it.
     The still is preloaded from the head at high priority; with the URL in
     CSS it paints the moment both arrive, script or no script. hero.js
     still calls paintPoster() with this same file, which the browser
     dedupes, and the test harness's ?poster= override wins as an inline
     style, exactly as before. */
  background-image:url("assets/hero-still.jpg");
  background-position:58% 50%;
  background-size:cover;
  background-repeat:no-repeat;
  transition:opacity .9s var(--ease-cine);
}
.ap-video{
  opacity:0;
  transition:opacity .9s var(--ease-cine);
  transform:translateZ(0);      /* its own compositor layer */
  will-change:transform;
}
.cine-stage.video-ready .ap-video{opacity:1;}
.cine-stage.video-ready .ap-poster{opacity:0;}
.cine-stage.video-failed .ap-video{display:none;}

/* A soft inner vignette so the bright pane never hits the page edge raw. */
.ap-veil{
  position:absolute;
  inset:0;
  pointer-events:none;
  background:
    linear-gradient(90deg,rgba(8,7,3,.55) 0%,rgba(8,7,3,0) 26%),
    linear-gradient(180deg,rgba(8,7,3,.42) 0%,rgba(8,7,3,0) 22% 76%,rgba(8,7,3,.5) 100%);
}

/* The loading ring. It only ever appears if the footage is slow. */
/* The loading ring lived here. It drew progress from a streaming loader
   that no longer exists; the poster covers the wait on its own. */


/* ---- the type column ---- */
/* The headline's left edge is the strongest line on the page, so it sits on
   the same rule as the wordmark above it and every section below it: the
   page's 1180px measure, not the viewport edge. */
.cine-copy{
  grid-area:1/1;
  position:relative;
  z-index:2;
  display:grid;
  align-content:center;
  padding-block:clamp(4rem,9vh,7rem);
  padding-right:clamp(1.75rem,3vw,3.25rem);
  padding-left:max(var(--gutter),calc((100vw - var(--shell))/2 + var(--gutter)));
  min-width:0;
}
@supports (width:1cqw){
  .cine-copy{padding-left:max(var(--gutter),calc((100cqw - var(--shell))/2 + var(--gutter)));}
}
.band{
  grid-area:1/1;
  align-self:center;
  opacity:var(--o,0);
  min-width:0;
}
/* No scrim. It is written down because its absence is the design decision,
   not an oversight: the type never sits on the footage at any width, so
   there is nothing to darken. An early version put the words over the film
   and needed a scrim per band; when the band layout replaced that, the
   scrim stayed in the file doing nothing while the comment above it still
   claimed it was what carried legibility on phones. Deleted rather than
   left at opacity zero, so nobody trusts it later. */

.cine-kicker{
  margin:0 0 clamp(1.1rem,2.4vh,1.9rem);
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:var(--ls-micro);
  text-transform:uppercase;
  color:var(--accent-on-dark);
  display:flex;
  align-items:center;
  gap:.9rem;
}
.cine-kicker::after{
  content:"";
  height:1px;
  flex:1 1 auto;
  max-width:7rem;
  background:currentColor;
  opacity:.4;
  transform:scaleX(var(--k,1));
  transform-origin:left;
}
.band-1{--k:1;}

.cine-h1{
  margin:0;
  font-family:var(--serif);
  font-weight:200;
  font-size:clamp(2.2rem,1rem + 3.1vw,4rem);
  line-height:1.03;
  letter-spacing:-.026em;
  color:var(--on-dark);
  max-width:15em;
  text-wrap:balance;
}
.cine-lede{
  margin:0;
  font-family:var(--serif);
  font-weight:200;
  font-size:clamp(1.5rem,.9rem + 1.8vw,2.6rem);
  line-height:1.24;
  letter-spacing:-.014em;
  color:var(--on-dark);
  max-width:19em;
}
.cine-lede em{font-style:italic;font-weight:300;color:var(--haze);}

.cine-settle-line{
  margin:0 0 clamp(1.5rem,3vh,2.2rem);
  font-family:var(--serif);
  font-weight:200;
  font-size:clamp(1.9rem,1rem + 2.4vw,3.2rem);
  line-height:1.1;
  letter-spacing:-.02em;
  color:var(--on-dark);
  max-width:14em;
}
.cine-actions{
  display:flex;
  flex-wrap:wrap;
  gap:.85rem;
  margin-bottom:1.5rem;
}
.cine-actions .btn{text-shadow:none;}

/* Beat one's action and price line. Deliberately NOT driven by --k the way
   band 3's are: this beat is the first thing painted and its job is to be
   readable and actionable on arrival, not to assemble itself. Tighter
   margins than band 3 because beat one now carries five elements over the
   footage and the tallest of them is a display headline. */
.cine-actions--lead{
  margin-top:1.6rem;
  margin-bottom:.95rem;
}
/* The lede grew from one sentence to two when it took on the "complete
   professional environment" idea, so it steps down a size here to keep the
   beat inside a short laptop window. Still the second-largest thing in the
   beat, still serif, still the voice. */
.band-1 .cine-lede{
  font-size:clamp(1.28rem,.86rem + 1.28vw,1.95rem);
  line-height:1.3;
}
.cine-direct{
  margin:0 0 1.15rem;
  font-size:.9rem;
  line-height:1.6;
  color:var(--on-dark-2);
  max-width:38em;
}
.cine-direct a{color:var(--on-dark);text-decoration:none;border-bottom:1px solid var(--line-dark);}
.cine-direct a:hover{color:var(--haze);border-bottom-color:currentColor;}
.cine-meta{
  margin:0;
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  gap:.45rem .8rem;
  font-size:.8125rem;
  letter-spacing:.02em;
  color:var(--on-dark-2);
}
.cine-meta strong{color:var(--on-dark);font-weight:500;}
.cine-meta .dot{color:rgba(241,236,225,.3);}

/* The scroll cue. It fades out as soon as the journey has started. */
.cine-cue{
  position:absolute;
  /* Same measure as the headline. 100vw includes the scrollbar and cqw does
     not; the cqw correction below the block must come AFTER this rule —
     it used to sit above it, where equal specificity made it dead code and
     the cue rode 7.6px right of the page spine. */
  left:max(var(--gutter),calc((100vw - var(--shell))/2 + var(--gutter)));
  bottom:clamp(1.4rem,3.4vh,2.4rem);
  z-index:3;
  display:flex;
  align-items:center;
  gap:.7rem;
  font-size:.625rem;
  font-weight:500;
  letter-spacing:.26em;
  text-transform:uppercase;
  color:rgba(241,236,225,.5);
  opacity:var(--cue,1);
  transition:opacity .5s linear;
  pointer-events:none;
}
.cine-cue i{
  display:block;
  width:34px;
  height:1px;
  background:currentColor;
  transform-origin:left;
  animation:cuepull 3.2s var(--ease) infinite -0.6s;
}
@keyframes cuepull{
  0%,100%{transform:scaleX(.35);opacity:.45;}
  46%{transform:scaleX(1);opacity:1;}
}

/* ---- word / character choreography ---------------------------------- */
/* Split copies: a visually hidden true sentence for assistive tech and a
   decorative split copy for the eye. Transform and opacity only. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}
.split{display:block;}
.w{
  display:inline-block;
  white-space:pre;
  /* em-based breathing room so descenders are never clipped by a mask */
  padding-bottom:.06em;
  margin-bottom:-.06em;
  /* No blanket will-change here any more. It promoted all 37 hero words to
     compositor layers for the life of the page, and a composited layer
     rasterises its text with greyscale antialiasing instead of subpixel:
     the three largest pieces of type on the site rendered measurably softer
     than the body copy below them, permanently, to speed up an entrance
     that plays once. styles.css:1932 warns against exactly this. Promotion
     is granted below only where words genuinely animate: band 1 during its
     entrance window, bands 2 and 3 while the scrub drives them. */
}

/* Band 1's words move once, on arrival. .entered lands when that settle
   finishes, the promotion drops with it, and the headline re-rasterises
   sharp for the rest of the visit.

   Guarded to the scrubbing hero explicitly. The static hero never plays the
   entrance, never adds .entered, and hero.js never runs at all without
   JavaScript — so a bare :not(.entered) promoted every headline word
   FOREVER on exactly the phones and fallback paths this fix existed to
   protect. The head script stamps html.hero-scrub before first paint, only
   for visitors who will actually scrub; :not(.is-static) drops the layer
   again if a gate later parks the hero mid-visit. */
html.hero-scrub .cine:not(.entered):not(.is-static) .band-1 .w{will-change:transform;}
/* These are driven through --k on every scrolled frame while their band is
   live, so a standing layer is cheaper than re-painting serif glyphs 60
   times a second. They live over the footage, never beside body text, so
   greyscale antialiasing has nothing to be compared against. */
.band-3 .cine-settle-line .w{will-change:transform,opacity;}

/* Band 1 — a word rise in reading order.

   It began as a blur-to-sharp crossfade with two stacked copies of the
   headline. That went when the entrance was rewritten to use transform
   only: the soft copy had to fade from one to zero, and a stalled fade
   would have left a permanent blurred ghost across the opening headline.
   The room resolving out of haze is left to the footage, which does it
   literally.

   This one beat runs on a CSS entrance instead of the scroll drive. There
   is nothing above the first beat to scroll back to, so it never has to
   reverse, and tying it to the animation frame loop meant that any moment
   the loop was late, the hero opened on a headline that had not arrived. */
/* The resting state is the DEFAULT and the entrance is what JavaScript
   opts into, never the other way round. Written as keyframes that start at
   zero opacity, the opening headline is invisible until something advances
   the animation, and the one thing a hero must never do is open on nothing.
   Here the words are simply there, and .pre-enter is added for a single
   frame to give them somewhere to arrive from. */
.band-1 .split{position:relative;}
.band-1 .split-sharp{opacity:1;}
.band-1 .w{
  opacity:1;
  transform:none;
  /* Transform only, deliberately. An entrance written on opacity leaves the
     opening headline invisible for as long as anything delays the animation
     clock, and a hero that opens on nothing is the one failure worth
     engineering out. Stalled, this arrives a third of a line low, which
     nobody would ever notice. */
  transition:transform 1.05s var(--ease-cine);
  transition-delay:calc(var(--th,0) * .75s);
}
.band-1 .cine-kicker::after{
  transform:scaleX(1);
  transform-origin:left;
  transition:transform 1.1s var(--ease-cine) .1s;
}
.cine.pre-enter .band-1 .w{
  transform:translateY(.42em) scale(.985);
  transition:none;
}
.cine.pre-enter .band-1 .cine-kicker::after{transform:scaleX(0);transition:none;}
/* Once the opening has played, the stagger delays are retired so nothing
   downstream ever inherits a three-quarter-second lag. */
.cine.entered .band-1 .w,
.cine.entered .band-1 .cine-kicker::after{transition-delay:0s;}

/* Band 2 is gone: the lede now arrives with the headline in band one,
   through the same once-only entrance. It needs its own air under the
   headline, which used to come from being a separate band. */
.band-1 .cine-lede{margin-top:clamp(1.1rem,2.6vh,1.8rem);}

/* Band 3 — the staged settle. Three arrivals in one band, matching the
   footage arriving at rest: the line, then the buttons, then the detail. */
.band-3 .cine-settle-line .w{
  --kc:clamp(0,(var(--k,0) - var(--th,0))*3,1);
  opacity:var(--kc);
  transform:translateY(calc((1 - var(--kc))*.5em));
}
.band-3 .cine-actions{
  --kb:clamp(0,(var(--k,0) - .42)*2.6,1);
  opacity:var(--kb);
  transform:translateY(calc((1 - var(--kb))*14px));
}
.band-3 .cine-direct,
.band-3 .cine-meta{
  --kd:clamp(0,(var(--k,0) - .62)*3,1);
  opacity:var(--kd);
  transform:translateY(calc((1 - var(--kd))*10px));
}

/* --------------------------------------------------------------------- */
/* 4 · The band layout                                                    */
/*                                                                        */
/* Everything narrower than 1024px, plus every visitor who gets the still */
/* instead of the scrub. The footage sits in a band across the top and    */
/* the words sit on solid ground beneath it.                              */
/*                                                                        */
/* This replaced an overlay where the type sat on the footage. A phone is */
/* 0.46 wide to tall against footage that is 0.75, so covering the screen */
/* throws away a third of the frame and then drops the copy straight over */
/* the chair, which is the one thing in the shot worth looking at. A band */
/* keeps the composition whole, turns legibility into a plain contrast    */
/* problem instead of a scrim-tuning exercise, and reads as a layout      */
/* somebody drew rather than a crop that happened.                        */
/* --------------------------------------------------------------------- */

/* The still hero is not pinned, so the section is only as tall as it needs
   to be and the stage stretches to whatever the stacked words come to. */
.cine.is-static{height:auto;}
.cine.is-static .cine-stage{height:auto;min-height:100vh;min-height:100svh;align-items:stretch;}
/* Only the split layout lets the window stretch to the stacked words. Left
   unscoped this beat the band's own height, because a class selector wins
   over a media query no matter which order they are in, and the footage
   collapsed to nothing on every phone. */
@media (min-width:1024px){
  .cine.is-static .ap{height:auto;}
}
@supports (width:1cqw){
  .cine-cue{left:max(var(--gutter),calc((100cqw - var(--shell))/2 + var(--gutter)));}
}
.cine.is-static .cine-cue{display:none;}
/* Stacked at display scale the three beats run past a screen and a half, so
   the still hero holds them a size down. */
.cine.is-static .cine-h1{font-size:clamp(2.05rem,1.15rem + 2.1vw,2.95rem);max-width:15em;}
.cine.is-static .cine-lede{font-size:clamp(1.2rem,.95rem + 1.1vw,1.65rem);max-width:24em;}

.cine-overlay .cine-stage{display:block;grid-template-columns:1fr;}
.cine-overlay .ap{
  grid-area:auto;
  position:relative;
  inset:auto;
  width:100%;
  /* vh first: an unsupported unit invalidates the whole declaration at parse
     time, and without a fallback the media window fell back to height:auto
     and collapsed to nothing. */
  height:clamp(230px,42vh,460px);
  height:clamp(230px,42svh,460px);
  box-shadow:none;
}
/* .ap-poster is a div carrying a background image, so it takes
   background-position; object-position only steers the <video>. */
.cine-overlay .ap-poster{background-position:56% 60%;}
.cine-overlay .ap-video{object-position:56% 60%;}
.cine-overlay .ap-veil{
  background:linear-gradient(180deg,
    rgba(6,5,2,.52) 0%,rgba(6,5,2,.06) 22%,rgba(6,5,2,0) 40%,
    rgba(11,10,5,.12) 56%,rgba(11,10,5,.4) 74%,rgba(11,10,5,.78) 88%,
    rgba(11,10,5,.96) 97%,rgba(11,10,5,1) 100%);
}
.cine-overlay .cine-copy{
  padding:clamp(2.25rem,5vh,3.25rem) var(--gutter) clamp(2.75rem,6vh,4rem);
  align-content:start;
}
/* Words on solid ground need no shadow either. */
.cine-overlay .band{text-shadow:none;}
.cine-overlay .cine-h1{font-size:clamp(2.05rem,1.15rem + 3.2vw,3.1rem);max-width:14em;}
.cine-overlay .cine-lede{font-size:clamp(1.2rem,.95rem + 1.3vw,1.75rem);max-width:23em;}
.cine-overlay .cine-settle-line{font-size:clamp(1.5rem,1rem + 2.2vw,2.3rem);max-width:16em;}

/* In the static presentation every band is simply on, stacked, read in
   one pass. It is a composed layout, not an apology for the video. */
.cine.is-static .cine-copy{display:block;}
.cine.is-static .band{
  opacity:1;
  position:relative;
  margin-bottom:clamp(1.5rem,3.5vh,2.4rem);
}
.cine.is-static .band:last-child{margin-bottom:0;}
.cine.is-static .w{opacity:1;transform:none;}
.cine.is-static .cine-kicker::after{transform:scaleX(1);}
.cine.is-static .band-3 .cine-actions,
.cine.is-static .band-3 .cine-direct,
.cine.is-static .band-3 .cine-meta{opacity:1;transform:none;}
/* Beat one's button exists because on a scrubbing desktop hero band 3 is out
   of sight at first paint. Stacked, both bands are on screen together, so it
   would simply be the same button twice about two hundred pixels apart. The
   price line stays — that is the fact, not the repetition. */
.cine.is-static .cine-actions--lead{display:none;}
/* With the button gone the price line lost the margin the button was
   providing and sat directly against the lede. */
.cine.is-static .band-1 .cine-meta{margin-top:1.15rem;}
/* Stacked, the settle line is simply the third sentence of the lede, so it
   drops back to the lede's size and sits directly under it rather than
   holding the weight it carries as its own beat over the footage. */
.cine.is-static .cine-settle-line{
  font-size:clamp(1.2rem,.95rem + 1.3vw,1.75rem);
  max-width:23em;
  margin-bottom:clamp(1.5rem,3.5vh,2.4rem);
}

/* The hero when nothing is driving it.

   Two ways to get here. JavaScript is switched off entirely, so main.js
   never removes the no-js class. Or hero.js specifically failed, in which
   case main.js already removed no-js and an inline watcher in index.html
   adds no-hero on load. Either way the bands have no drive, and the only
   thing making the hero visible is these rules, so they have to produce a
   complete hero on their own: image, headline, lede, both buttons, price.
   The composed layout a phone gets, with the words simply stacked. */
:is(.no-js, .no-hero, .hero-still) .cine{height:auto;margin-top:calc(-1 * var(--header-h));}
:is(.no-js, .no-hero, .hero-still) .cine-stage{position:relative;height:auto;min-height:100vh;min-height:100svh;align-items:stretch;}
:is(.no-js, .no-hero, .hero-still) .ap{height:auto;}

/* Below 1024 the window becomes a band across the top. Above it the split
   holds and simply stands still, so a desktop visitor who has asked for less
   motion is not dropped into the phone layout. */
@media (max-width:1023px){
  :is(.no-js, .no-hero, .hero-still) .cine-stage{display:block;grid-template-columns:1fr;}
  :is(.no-js, .no-hero, .hero-still) .ap{
    grid-area:auto;position:relative;inset:auto;width:100%;
    height:clamp(230px,42vh,460px);height:clamp(230px,42svh,460px);box-shadow:none;
  }
}
:is(.no-js, .no-hero, .hero-still) .ap-poster{background-image:url('assets/hero-still.jpg');background-position:56% 60%;}
:is(.no-js, .no-hero, .hero-still) .ap-veil{
  background:linear-gradient(180deg,
    rgba(6,5,2,.52) 0%,rgba(6,5,2,.06) 22%,rgba(6,5,2,0) 40%,
    rgba(11,10,5,.12) 56%,rgba(11,10,5,.4) 74%,rgba(11,10,5,.78) 88%,
    rgba(11,10,5,.96) 97%,rgba(11,10,5,1) 100%);
}
:is(.no-js, .no-hero, .hero-still) .ap-video,
:is(.no-js, .no-hero, .hero-still) .ap-ring,
:is(.no-js, .no-hero, .hero-still) .cine-cue{display:none;}
:is(.no-js, .no-hero, .hero-still) .cine-copy{
  display:block;
  padding:clamp(2.25rem,5vh,3.25rem) var(--gutter) clamp(2.75rem,6vh,4rem);
}
/* visibility and inert are cleared too: hero.js may have made a band
   non-interactive on its way to failing. */
:is(.no-js, .no-hero, .hero-still) .band{
  /* !important on these two only. hero.js writes opacity and visibility as
     inline styles while it is driving, and if it dies mid-drive the fallback
     has to be able to take them back. A stylesheet cannot beat an inline
     style any other way, and band three is where the call to action lives. */
  opacity:1 !important;
  visibility:visible !important;
  position:relative;
  margin-bottom:clamp(1.5rem,3.5vh,2.4rem);
  text-shadow:none;
}
:is(.no-js, .no-hero, .hero-still) .w{opacity:1;transform:none;}
:is(.no-js, .no-hero, .hero-still) .cine-h1{font-size:clamp(2.05rem,1.15rem + 3.2vw,3.1rem);max-width:14em;}
:is(.no-js, .no-hero, .hero-still) .cine-lede,
:is(.no-js, .no-hero, .hero-still) .cine-settle-line{font-size:clamp(1.2rem,.95rem + 1.3vw,1.75rem);max-width:23em;}
/* The settle band's three arrivals are driven off --k, which nothing sets
   when nothing is driving, so the buttons, the direct line and the price
   line all sat at zero opacity. A hero with no call to action in it is not
   a fallback, it is a broken page. */
:is(.no-js, .no-hero, .hero-still) .band-3 .cine-actions,
:is(.no-js, .no-hero, .hero-still) .band-3 .cine-direct,
:is(.no-js, .no-hero, .hero-still) .band-3 .cine-meta{opacity:1;transform:none;}
:is(.no-js, .no-hero, .hero-still) .cine-kicker::after{transform:scaleX(1);}

/* --------------------------------------------------------------------- */
/* 5 · The static-hero gates                                              */
/*                                                                        */
/* These five queries are character for character the same list the       */
/* JavaScript holds. If one side ever changes, the other loads assets     */
/* this side is hiding. They are re-evaluated live, on both sides.        */
/* --------------------------------------------------------------------- */

@media (max-width:720px),
       (orientation:portrait) and (max-width:1024px),
       (orientation:portrait) and (pointer:coarse),
       (orientation:landscape) and (pointer:coarse) and (max-height:560px),
       (prefers-reduced-motion:reduce){
  .cine{height:auto;}
  .cine-stage{position:relative;height:auto;min-height:100vh;min-height:100svh;align-items:stretch;}
  .ap{height:auto;}
  .cine-cue{display:none;}
  .band{opacity:1;position:relative;}
}

/* The band is a matter of width, not of motion. Under 1024 there is no room
   to hold the split, so the footage goes to a band across the top whether
   it is scrubbing or standing still; above it, a desktop with motion turned
   off still gets the composed split, which is what the scrub settles on
   anyway. hero.js applies .cine-overlay on exactly this width. */
@media (max-width:1023px){
  .cine-stage{display:block;grid-template-columns:1fr;}
  .ap{
    grid-area:auto;position:relative;inset:auto;width:100%;
    height:clamp(230px,42vh,460px);height:clamp(230px,42svh,460px);box-shadow:none;
  }
}

/* A shallow window has no room for the cue. */
@media (max-height:600px){
  .cine-cue{display:none;}
  .cine{height:360vh;}   /* same pixel range as 280vh on a normal window */
}

/* The bone/paper alternation measured 1.08:1 — invisible — and worse, the
   opaque paper sections blocked the fixed atmosphere drift while the bone
   ones let it through, so the one perceivable difference was the wrong one.
   Slight translucency makes the atmosphere continuous down the page, and a
   hairline carries the section boundary honestly at this lightness. */
.section-value,.section-pricing,.section-proof{
  background:rgb(251 248 241 / .94);
  border-top:1px solid rgb(23 21 15 / .07);
  border-bottom:1px solid rgb(23 21 15 / .07);
}

/* --------------------------------------------------------------------- */
/* 6 · The page below, re-graded                                          */
/* --------------------------------------------------------------------- */

/* The area bar is now the first thing that arrives when the pin releases,
   so it gets the weight of a threshold rather than a footnote. */
.areabar{
  border-top:0;
  border-bottom:1px solid var(--line);
  background:var(--paper);
  position:relative;
  z-index:1;
}

/* The pull quote returns to the room. */
.pullquote-dark{background:rgb(11 10 5 / .93);border-bottom:0;}
.pullquote-dark blockquote{color:var(--on-dark);}
.pullquote-dark blockquote::before{color:var(--accent-on-dark);opacity:.55;}
.pullquote-dark .pullquote-by{color:var(--on-dark-2);}

/* Kickers get the mullion: the same hairline as the aperture's edge. */
.eyebrow{color:var(--accent);}
.section-dark .eyebrow,
.section-request .eyebrow{color:var(--accent-on-dark);}

/* Buttons. On the dark grounds the call to action is filled with the
   window light itself — the accent on this page is light, not a colour. */
.btn-ink{--btn-bg:var(--ink);--btn-fg:var(--bone);}
.btn-ink:hover{--btn-bg:#2B281E;}
.section-dark .btn-ink,
.section-request .btn-ink,
.cine .btn-ink{--btn-bg:var(--bone);--btn-fg:#100E08;}
.section-dark .btn-ink:hover,
.section-request .btn-ink:hover,
.cine .btn-ink:hover{--btn-bg:#FFFCF5;}
/* .34 alpha measured 2.78:1 against the wall, under the 3:1 an interactive
   border needs. .42 measures 3.65:1. */
.cine .btn-ghost,
.section-dark .btn-ghost,
.section-request .btn-ghost{
  --btn-fg:var(--on-dark);
  border-color:rgba(241,236,225,.42);
}
.cine .btn-ghost:hover,
.section-dark .btn-ghost:hover,
.section-request .btn-ghost:hover{border-color:rgba(241,236,225,.78);}

/* Focus follows the accent on both grounds. */
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;}
.section-dark :focus-visible,
.section-request :focus-visible,
.cine :focus-visible,
.site-footer :focus-visible{outline-color:var(--accent-on-dark);}

/* The header rides over the room until the page has left it. Half of it
   sits over the dark wall and half over the bright glass, so a scrim
   carries the nav across both rather than a background carrying it across
   one. It fades out the moment the header goes solid. */
.site-header{
  background:transparent;
  border-bottom-color:transparent;
  box-shadow:none;
  transition:background .5s var(--ease-cine),border-color .5s var(--ease-cine),box-shadow .5s var(--ease-cine);
}
.site-header::before{
  content:"";
  position:absolute;
  inset:0 0 -32px;
  z-index:-1;
  pointer-events:none;
  opacity:1;
  transition:opacity .45s var(--ease-cine);
  background:linear-gradient(180deg,rgba(6,5,2,.72) 0%,rgba(6,5,2,.46) 46%,rgba(6,5,2,0) 100%);
}
body.header-solid .site-header::before{opacity:0;}
.site-header.is-scrolled{background:transparent;box-shadow:none;}
body.header-solid .site-header.is-scrolled{
  background:var(--paper);
  box-shadow:0 1px 0 var(--line);
}
.site-header .wordmark-name,
.site-header .wordmark-sub,
.site-header .site-nav a,
.site-header .header-phone span{transition:color .5s var(--ease-cine);}
body:not(.header-solid) .site-header .wordmark-name{color:var(--on-dark);}
body:not(.header-solid) .site-header .wordmark-sub,
body:not(.header-solid) .site-header .site-nav a,
body:not(.header-solid) .site-header .header-phone-label,
body:not(.header-solid) .site-header .header-phone span{color:var(--on-dark-2);}
body:not(.header-solid) .site-header .site-nav a:hover{color:var(--on-dark);}
body:not(.header-solid) .site-header .site-nav a::after{background:var(--on-dark-2);}
body:not(.header-solid) .site-header .btn-ink{--btn-bg:var(--bone);--btn-fg:#100E08;}
body.header-solid .site-header{
  background:var(--paper);
  border-bottom-color:var(--line);
}

/* --------------------------------------------------------------------- */
/* 7 · Reduced motion                                                     */
/*                                                                        */
/* Honoured completely and in both directions. Everything scroll-drawn    */
/* pins to its finished state; nothing is left mid-assembly.              */
/* --------------------------------------------------------------------- */

@media (prefers-reduced-motion:reduce){
  .env,.env-lift{animation:none;}
  .cine-cue i{animation:none;transform:scaleX(1);}
  .ap-poster,.ap-video,.ap-ring,.ap-ring circle{transition:none;}
  .band-1 .w,.band-1 .cine-kicker::after{transition:none;transform:none;}
  .site-header,.site-header *{transition:none;}
}

/* The JS pins these when the preference flips on mid-session. */
/* motion-pinned marks a hero that is standing still, which is not the same
   thing as a visitor who asked for less motion. The environment's drift is
   left alone here; the reduced-motion media query above already stops it for
   the people who actually asked. */
.motion-pinned .cine-cue i{animation:none;transform:scaleX(1);}
.motion-pinned .band{opacity:1;}
.motion-pinned .w{opacity:1;transform:none;transition:none;}
.motion-pinned .split-sharp{opacity:1;}
.motion-pinned .cine-kicker::after{transform:scaleX(1);}
.motion-pinned .band-3 .cine-actions,
.motion-pinned .band-3 .cine-direct,
.motion-pinned .band-3 .cine-meta{opacity:1;transform:none;}

/* A hidden tab does no work. animation-play-state is not inherited, so it
   has to be aimed at the pseudo-elements too or the grain and the drift
   keep running behind a tab nobody is looking at. */
body.paused *,
body.paused *::before,
body.paused *::after{animation-play-state:paused !important;}

/* Touch targets. A finger needs 44px, and every small button on this page
   measures 36 to 41. The height is added without changing the layout: keep
   the alignment properties when swapping display, or a bare inline-flex
   left-aligns every label and shrinks the full-width rows to their text. */
@media (pointer:coarse){
  /* Height only. Nothing in here may set display.

     .btn is already an inline-flex box that centres its own label, so a
     display declaration bought nothing here and cost something real: it
     outranked .header-cta{display:none} and brought the header's button back
     on every touch device, where it ran 106px off the right edge of a phone.
     The page never scrolled sideways to show it, because html and body clip
     the overflow, so the only visible symptom was a pale sliver at the top
     corner. Raise the target, leave the layout alone. */
  .btn,
  .tier-switch-btn,
  .faq-item summary{min-height:44px;}

  /* Nav links are inline, and a height does not apply to an inline box, so
     these are the one case that genuinely needs a display. Nothing hides an
     individual nav link, only the whole nav, so this is safe. */
  .site-nav a{display:inline-flex;align-items:center;min-height:44px;}

  /* The cadence marks are grid items with an absolutely positioned tick
     above them; they grow downward instead. */
  .cadence-step{min-height:44px;padding-bottom:.6rem;}

  /* Links that stand on their own get real padding, which is honest about
     taking the space. The footer's row of links is the case that needs it:
     expanding their hit areas invisibly would overlap the row above once
     they wrap, and a tap would land on the wrong one. */
  .footer-nav a{display:inline-block;padding-block:.8rem;}
  .wordmark{display:block;padding-block:.2rem;}
  .header-phone{padding-block:.82rem;}

  /* Links that sit inside a sentence cannot take padding without pushing the
     line apart, so they get an invisible hit area centred on themselves.
     The phone number in the hero is the single highest-intent thing on the
     page for a man who has just landed, and it measured eighteen pixels.

     .legal-shell covers the prose links on the privacy and terms pages: the
     email address someone taps to exercise a data right, and the cross-link
     between the two documents. Those paragraphs are far enough apart that
     the expanded areas cannot overlap and steal each other's taps. */
  .cine-direct a,
  .request-alt a,
  .footer-legal a,
  .offer-foot-note a,
  .legal-shell p a,
  .legal-shell li a{position:relative;}
  .cine-direct a::after,
  .request-alt a::after,
  .footer-legal a::after,
  .offer-foot-note a::after,
  .legal-shell p a::after,
  .legal-shell li a::after{
    content:"";
    position:absolute;
    left:0;
    right:0;
    top:50%;
    height:44px;
    transform:translateY(-50%);
  }
}

/* Two bordered panels back to back inside the same column read as one
   broken box. They are separate promises and need to look it. */
.assurance + .assurance{margin-top:clamp(.85rem,2vw,1.15rem);}

/* [23] The cadence control made the left card taller than the right one, and
   the right one is the only card with a filled ground, so the surplus showed
   as a slab of empty black under its last sentence. Letting the dark card
   distribute its own content puts that space between the total and the note,
   where it reads as air instead of as a void. */
.compare-new{display:flex;flex-direction:column;}
.compare-new .compare-note{margin-top:auto;}

/* The step numerals carry the sequence, so they are structure rather than
   decoration and have to be readable before a pointer ever finds them. */
.section-dark .step-num{opacity:.5;}

/* Nothing on the page may push it sideways. */
html,body{overflow-x:hidden;overflow-x:clip;}

/* --------------------------------------------------------------------- */
/* 8 · The cadence control                                                */
/*                                                                        */
/* The site's one interactive moment, and it sits where the argument      */
/* already is rather than somewhere it would read as a trick. The page    */
/* claims a conventional appointment costs about forty hours a year, and  */
/* that figure rests entirely on how often the reader actually gets cut,  */
/* which is the one number they know better than the page does. Moving    */
/* the mark re-counts the year in front of them.                          */
/*                                                                        */
/* It is three radio buttons wearing a drawn scale. Radios rather than a  */
/* pointer-driven slider because they arrive keyboard-operable and        */
/* announced correctly with nothing invented on top, and the rule they    */
/* sit on is the same hairline the aperture draws down its inner edge.    */
/* --------------------------------------------------------------------- */

.cadence{
  margin:clamp(1.5rem,3vw,2.1rem) 0 0;
  padding:0;
  border:0;
  min-width:0;    /* a fieldset will not shrink below its content without this */
}
:is(.no-js, .no-hero, .hero-still) .cadence{display:none;}

/* The kicker carries its own drawn rule, the way every other label on the
   page does. The fieldset's own border is left off deliberately: a legend
   sits inside the top border and interrupts it, which drew a line that
   started halfway across the card for no reason a visitor could read. */
.cadence-legend{
  padding:0;
  margin-bottom:clamp(1.6rem,3.2vw,2rem);
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:var(--ls-label);
  text-transform:uppercase;
  color:var(--accent);
}
.cadence-legend::after{
  content:"";
  display:inline-block;
  width:clamp(1.5rem,4vw,3.5rem);
  height:1px;
  margin-left:.9rem;
  vertical-align:middle;
  background:currentColor;
  opacity:.45;
}

.cadence-scale{
  position:relative;
  display:grid;
  grid-template-columns:repeat(3,1fr);
  padding-top:1.5rem;
}

/* The track runs from the first mark to the last, so the distance the dot
   travels is exactly the range on offer. The marks sit at the centre of
   each third, which puts them at one sixth, one half and five sixths. */
.cadence-track{
  position:absolute;
  left:16.667%;
  right:16.667%;
  top:.55rem;
  height:1px;
  background:var(--line-strong);
}

/* The dot is carried by a half-width box so its travel can be written as a
   percentage of its own width. That keeps this a transform animation
   instead of a layout one. --cad is 0, 1 or 2. */
.cadence-dot{
  position:absolute;
  left:0;
  top:0;
  width:50%;
  height:1px;
  transform:translateX(calc(var(--cad,1) * 100%));
  transition:transform .55s var(--ease-out);
}
.cadence-dot::before{
  content:"";
  position:absolute;
  left:-4.5px;
  top:-4px;
  width:9px;
  height:9px;
  border-radius:50%;
  background:var(--ink);
}

.cadence-step{
  position:relative;
  display:block;
  padding-top:1.15rem;
  text-align:center;
  cursor:pointer;
  min-width:0;
}
/* Centred on the track, not hung from it: at 13px the selected mark
   poked out from under the dot and read as a stem on a pin. The dot is
   the indicator, so the mark only changes colour. */
.cadence-tick{
  position:absolute;
  top:calc(-.95rem - 4px);
  left:50%;
  width:1px;
  height:9px;
  margin-left:-.5px;
  background:var(--line-strong);
  transition:background-color .35s var(--ease);
}
.cadence-step input:checked ~ .cadence-tick{background:var(--ink);}

/* The radio itself is the accessible element, so it stays in the page and
   is only made invisible. display:none would take it out of the tab order
   and out of the accessibility tree along with it. */
.cadence-step input{
  position:absolute;
  width:1px;
  height:1px;
  opacity:0;
  margin:0;
  pointer-events:none;
}

.cadence-text{
  display:block;
  font-size:.75rem;
  line-height:1.3;
  letter-spacing:.01em;
  color:var(--muted);
  transition:color .35s var(--ease);
}
.cadence-step input:checked ~ .cadence-text{color:var(--ink);font-weight:500;}
@media (hover:hover){
  .cadence-step:hover .cadence-text{color:var(--ink-2);}
  .cadence-step:hover .cadence-tick{background:var(--ink-2);}
}

/* The focus ring goes on the mark, because the input it belongs to is the
   invisible one. */
.cadence-step input:focus-visible ~ .cadence-tick{
  outline:2px solid var(--accent);
  outline-offset:4px;
}

/* The figure being changed. It re-settles rather than blinking. */
.compare-note [data-cad-hours]{
  font-variant-numeric:tabular-nums;
  color:var(--ink);
  font-weight:500;
}
.compare-note [data-cad-freq],
.compare-note [data-cad-week]{transition:opacity .28s var(--ease);}
.compare-note.is-recounting [data-cad-freq],
.compare-note.is-recounting [data-cad-week]{opacity:.35;}

@media (max-width:420px){
  .cadence-text{font-size:.6875rem;}
}

@media (prefers-reduced-motion:reduce){
  .cadence-dot,
  .cadence-tick,
  .cadence-text,
  .compare-note [data-cad-freq],
  .compare-note [data-cad-week]{transition:none;}
}

/* A telephone number is one word. Left to wrap it broke after the area code,
   which reads badly and also splits the tap target across two line boxes, so
   the middle of it is not the number at all. */
[data-phone-tel]{white-space:nowrap;}

/* --------------------------------------------------------------------- */
/* 9 · Print                                                              */
/*                                                                        */
/* The only print rule the site had was written for the old hero and hid  */
/* an element that no longer exists. Left alone, paged media kept the     */
/* 320vh pinned region and the sticky stage, so the first three sheets    */
/* came out very nearly blank, and every dark section printed its own     */
/* light type onto white paper and disappeared.                           */
/*                                                                        */
/* A printed page is not a lesser page. Someone printing this is taking   */
/* it into a meeting or handing it to a partner, so it gets the whole     */
/* argument in black on white, with the addresses spelled out.            */
/* --------------------------------------------------------------------- */

@media print{
  html,body{background:#fff !important;color:#000 !important;}

  /* Unpin the hero and let it be one composed block. */
  .cine{height:auto !important;margin-top:0 !important;background:#fff !important;}
  .cine-stage{
    position:static !important;
    display:block !important;
    height:auto !important;
    min-height:0 !important;
    background:#fff !important;
    overflow:visible !important;
  }
  .cine-stage::before,.ap-veil,.ap-ring,.cine-cue,.env,.env-lift{display:none !important;}
  .ap{
    position:relative !important;
    inset:auto !important;
    grid-area:auto !important;
    width:100% !important;
    height:auto !important;
    aspect-ratio:16/9;
    box-shadow:none !important;
    break-inside:avoid;
  }
  .ap-video{display:none !important;}
  .ap-poster{
    position:absolute !important;
    inset:0 !important;
    background-image:url('assets/hero-still.jpg') !important;
    opacity:1 !important;
  }

  /* Every band is on, stacked, in ink. */
  .cine-copy{display:block !important;padding:1.5rem 0 0 !important;}
  .band{
    opacity:1 !important;
    visibility:visible !important;
    position:relative !important;
    grid-area:auto !important;
    text-shadow:none !important;
    break-inside:avoid;
  }
  .w{opacity:1 !important;transform:none !important;}
  .cine-h1,.cine-lede,.cine-settle-line,.cine-meta,.cine-direct{color:#000 !important;}
  .cine-kicker{color:#333 !important;}

  /* The dark grounds have to invert or their type prints white on white. */
  .section-dark,.section-request,.pullquote-dark,.site-footer,.compare-new{
    background:#fff !important;
    color:#000 !important;
  }
  .section-dark *,.section-request *,.pullquote-dark *,.site-footer *,.compare-new *{
    color:#000 !important;
    text-shadow:none !important;
  }
  .section-dark::before,.section-request::before,.pullquote-dark::before{display:none !important;}
  .compare-new,.tier,.member-card,.assurance,.compare-card{
    border:1px solid #999 !important;
    break-inside:avoid;
  }
  /* On paper the sage check printed pale and the "not included" dash printed
     solid black — the exact inverse of what the marks mean. Included prints
     ink; not-included prints light. */
  .matrix .mx-yes,.matrix .mx-yes::before,.matrix .mx-yes::after{
    color:#000 !important;border-color:#000 !important;background:#000 !important;
  }
  .matrix tbody td.mx-off,.matrix tbody td.mx-off *{color:#AAA !important;}

  /* Nothing that only makes sense on a screen. */
  .site-header,.sticky-cta,.about-media,.cadence,.btn,.midcta,.request-form-wrap,
  .skip-link,.tier-switch{display:none !important;}

  /* A paper page is narrower than the matrix's breakpoint. US Letter is
     about 739px of usable width and A4 about 717px, so the one-column-at-a-
     time rules written for phones apply, and they hide two of the three
     retainers and the tier names with them. On screen that is fine because
     the tier buttons sit above the table; in print those buttons are hidden
     by the rule directly above this one, so what printed was a single
     column headed only "$950/mo", with no name, no caption, and no sign
     that two thirds of the comparison had been dropped. */
  .matrix [data-col]{display:table-cell !important;}
  .matrix .mx-name{display:block !important;}
  .matrix caption{
    position:static !important;
    width:auto !important;
    height:auto !important;
    clip:auto !important;
    clip-path:none !important;
    overflow:visible !important;
    margin-bottom:.6rem;
    text-align:left;
    font-weight:500;
  }
  .matrix{font-size:.72rem;}
  .matrix th,.matrix td{padding:.35rem .5rem !important;}
  body::after{display:none !important;}

  /* Anything the reveal system has not lit yet must not print blank. */
  .reveal{opacity:1 !important;transform:none !important;}

  /* A printed link cannot be clicked, so spell the important ones out. */
  .footer-legal a::after,.request-alt a::after{content:" (" attr(href) ")";font-size:.85em;}
  a[href^="tel:"]::after{content:"";}

  h2,h3{break-after:avoid;}
  .section{padding-block:1.25rem !important;}
}


/* --------------------------------------------------------------------- */
/* 10 · The request form is a light card inside a dark section            */
/*                                                                        */
/* Section 6 inverts the call to action on the dark grounds: fills it with */
/* light instead of ink. The request form sits inside one of those        */
/* sections but is itself a bone card, so the inversion reached into it   */
/* and painted bone buttons on a bone card. Continue rendered as bare     */
/* letterspaced text with no fill, no border and no shadow — the only way */
/* forward in the form did not look like a button at all.                 */
/*                                                                        */
/* It survived every functional test because a click works perfectly well */
/* on something invisible.                                                */
/* --------------------------------------------------------------------- */

.section-request .request-form-wrap .btn-ink{
  --btn-bg:var(--ink);
  --btn-fg:var(--bone);
}
.section-request .request-form-wrap .btn-ink:hover{--btn-bg:#2B281E;}
.section-request .request-form-wrap .btn-ghost{
  --btn-fg:var(--ink);
  border-color:var(--line-strong);
}
.section-request .request-form-wrap .btn-ghost:hover{border-color:var(--ink);}
.section-request .request-form-wrap :focus-visible{outline-color:var(--accent);}

/* On a phone the request section stacks in source order, which put the call
   button, the text button and the email address above the form: three ways
   to leave offered before the thing the visitor was sent here to do. Paid
   traffic lands on this screen. */
@media (max-width:959px){
  .request-inner{display:flex;flex-direction:column;}
  .request-form-wrap{order:1;}
  .request-copy{order:2;}
}

/* The hero lede is a supporting line, not a second headline. Sized below
   the h1 by a clear step so the two are never read as equals. */
.cine-lede{
  font-size:clamp(1.125rem,.85rem + .78vw,1.6rem);
  font-weight:300;
  line-height:1.34;
  letter-spacing:-.006em;
  color:var(--on-dark-2);
  max-width:26em;
}

/* Dots between meta items orphan at the wrap. Space does not. */
.cine-meta{gap:.5rem 1.75rem;}
.cine-meta .dot{display:none;}

/* ===================================================================== */
/* 16 - The hero plays, it is not scrubbed                               */
/* ===================================================================== */

/* The stage was sticky so it could hold still while the page scrolled
   through it. There is nothing to scroll through now. */
.cine-stage{position:relative;}

/* Band opacity was written by the drive loop, frame by frame. With one
   beat there is nothing to reveal: it is simply the hero. */
.cine .band{opacity:1;}
.cine .band-1{--o:1;}

/* ---- the statement strip ---------------------------------------- */
/* The ground, the light-fall and every dark-context button rule come from
   .section-dark, which this shares. Only the rhythm is its own: it is a
   single line, so it does not need a full section of air. */
.section-statement{
  color:var(--on-dark);
  padding-block:clamp(3.5rem,8vw,6rem);
}
.statement-inner{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  justify-content:space-between;
  gap:1.5rem 3rem;
}
.statement-line{
  margin:0;
  flex:1 1 22ch;
  max-width:24em;
  font-family:var(--serif);
  font-weight:200;
  font-size:clamp(1.5rem,1rem + 1.9vw,2.6rem);
  line-height:1.22;
  letter-spacing:-.012em;
  text-wrap:balance;
  color:var(--on-dark);
}
.statement-actions{margin:0;flex:0 0 auto;}
