/* Task 12 — the opening title card, and the page-wide entry treatment.

   TWO THINGS LIVE HERE and they degrade differently:

   1. The TITLE CARD is ordinary layout. #hero opens on a viewport-height panel
      with the eyebrow and the headline set over one of the owner's own hero
      photographs (Task 13 — art-directed per viewport, see the 48rem rule
      below). That is the resting page: it needs no JavaScript, it is what a
      reader with scripting off gets, and because it is in the cascade at
      first paint it costs no layout shift.

   2. The MOTION is not here at all. js/scroll.js sets every start state
      inline, from script, and this file only describes where things come to
      rest. Grep it: there is no `opacity: 0`, no `visibility: hidden` and no
      off-screen transform in any rule below. If the script never runs — 404,
      blocked, thrown, reduced motion — the headline, the eyebrow, the CTAs,
      the price line and all twelve sections are already exactly where the
      animation would have put them.

   The one rule that reads like an exception is `.hero--live .hero__plate`,
   which pins the photograph over the act so it can be pushed off it as a cut
   (Task 13 — see the "live" block below for why this is a cut and not a
   dissolve). The class is added by js/scroll.js and by nothing else, so it
   cannot apply on a page whose script did not run — and even then it hides
   nothing: it is the plate itself that moves, never the copy. */

:root {
  /* The sentinel js/scroll.js reads before it touches anything, the same
     contract css/cinematic.css has with js/cinematic.js. A page served without
     this stylesheet must not get a half-applied opening. */
  --scroll-css: 1;

  /* The entry treatment, defined once. Every section uses these three numbers
     and no element is hand-tuned, because divergence is exactly what makes a
     page read as unfinished. js/scroll.js reads them from here so the timing
     is stated in one place rather than two. */
  --entry-duration: 420ms;
  --entry-stagger: 70ms;
  --entry-rise: 14px;
}

/* ---- the title card ------------------------------------------------------ */

#hero { position: relative; }

/* Full-bleed to the section's edges by cancelling the band's own padding, then
   putting it back inside — so .inner still centres on the same measure as
   every other band. No 100vw anywhere: that would count the scrollbar and put
   the page into horizontal overflow. */
.hero__card {
  position: relative;
  z-index: 1;
  margin: calc(-1 * var(--band-pad)) calc(-1 * var(--gutter)) 0;
  padding: var(--band-pad) var(--gutter) clamp(1.5rem, 4vw, 2.5rem);
  display: grid;
  /* Task 13: top-anchored by default. hero-photo-mobile.webp holds its open
     space at the TOP of the frame (the ceiling and pendant lights above the
     subject), not the middle, so centring the copy the way the old plate did
     would drop it over the busiest part of the photo. The 48rem rule below
     restores centring for the desktop photo, whose open room runs the full
     height of its left third. */
  align-content: start;
  min-height: calc(100vh - var(--band-pad));
  min-height: calc(100svh - var(--band-pad));
}
.hero__card-copy {
  text-align: center;
  /* Clears the padded top edge and lands inside the photo's open ceiling
     band rather than flush against it. */
  margin-top: clamp(2rem, 9vh, 4.5rem);
}
.hero__card-copy .eyebrow { margin-bottom: 0.75rem; }
.hero__card-copy h1 { margin-bottom: 0; }

/* Task 13: the owner's own photographs replace the generated office plate,
   art-directed rather than cropped — a portrait frame below 48rem (the same
   breakpoint the rest of the page switches layout at, css/page.css:76-77 and
   :172) and a landscape frame at and above it. Each was composed with empty
   space held open for this text: the portrait keeps its open ceiling at the
   top, the landscape keeps its open room at the left, so the two rules below
   just point the card at whichever image the viewport gets — nothing here
   crops one asset to fit both shapes. */
.hero__plate {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: url("../assets/plates/hero-photo-mobile.webp") 50% 50% / cover no-repeat;
  pointer-events: none;
}
/* A real photograph, not the generated plate the doctrine's "insurance" scrim
   was written for — cafe wood tones and daylight vary far more than a modest
   radial ever had to cover. This is a real, load-bearing scrim, sized to the
   text's own corner of the frame rather than smeared over the whole photo, so
   the rest of the room stays exactly the photograph the owner supplied.
   Mixed from the token, so no colour is stated here that tokens.css does not
   own; never applied to a screenshot, only to this photograph. */
.hero__plate::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--surface-capture) 80%, transparent) 0%,
    color-mix(in srgb, var(--surface-capture) 55%, transparent) 34%,
    color-mix(in srgb, var(--surface-capture) 0%, transparent) 60%
  );
}

@media (min-width: 48rem) {
  .hero__plate { background-image: url("../assets/plates/hero-photo-desktop.webp"); }
  .hero__plate::after {
    background: linear-gradient(
      100deg,
      color-mix(in srgb, var(--surface-capture) 78%, transparent) 0%,
      color-mix(in srgb, var(--surface-capture) 52%, transparent) 30%,
      color-mix(in srgb, var(--surface-capture) 0%, transparent) 52%
    );
  }
  /* Left-aligned into the room's own open third rather than centred over the
     desk and the screen — the desktop photograph left that side clear on
     purpose, for its full height, so vertical centring (the page's original
     rule) is restored here rather than the mobile top-anchor above. Equal
     specificity to .inner's max-width/margin-inline (page.css) and loaded
     after it, so this wins without !important. */
  .hero__card { justify-items: start; align-content: center; }
  .hero__card-copy { text-align: left; max-width: 28rem; margin-inline: 0; margin-top: 0; }
}

/* Everything in the hero that is not the plate sits above it. .cin is given a
   layer here as well as in css/cinematic.css, because that file may be absent
   while this one is present, and a static .cin would otherwise paint under the
   positioned plate and lose the capture behind it. */
#hero > .inner { position: relative; z-index: 1; }
#hero .cin { position: relative; z-index: 1; }

/* ---- live: the photo is pushed out, not dissolved ------------------------ */
/* Task 13 ruling: the office plate and still-hero-01 were the SAME ROOM, so a
   cross-fade between them read as a camera pulling in. A cafe photograph is a
   DIFFERENT room, and dissolving between two unrelated rooms is the scene cut
   that ruling forbids — it reads as a mistake, not a move. So this is a cut:
   pinned to the viewport, then pushed off the top of the frame (translate +a
   small scale, both written every frame by js/scroll.js) rather than faded
   through opacity. Nothing here blends the two rooms; the photo is fully
   opaque until it is off-screen, and js/scroll.js parks visibility once it is,
   so the layer never sits over the rest of the page. */
.hero--live .hero__plate { position: fixed; z-index: 2; will-change: transform; }
.hero--live .hero__card,
.hero--live > .inner { z-index: 3; }

/* ---- the entry treatment ------------------------------------------------- */
/* One transform-and-opacity settle, applied by js/scroll.js to every section.
   Nothing here starts hidden; these two rules exist only so the animated
   elements get their own compositing layer while they are moving, and give it
   back afterwards. */
.entry--moving { will-change: opacity, transform; }
.entry--settled { will-change: auto; }

@media (prefers-reduced-motion: reduce) {
  /* js/scroll.js bails before it adds a class or writes a style, so this block
     is belt and braces: if .hero--live were ever present under reduced motion
     the plate would stay the card's own background rather than a pinned layer,
     which is the resting page. */
  .hero--live .hero__plate { position: absolute; z-index: 0; }
  .entry--moving, .entry--settled { will-change: auto; }
}

/* ---- #cost — owner addition, Task 13 -------------------------------------
   Aligned to the pivoting capture directly above it: the same width and the
   same centred edges as .cin__screen at its resting size — min(78vw,1100px),
   css/cinematic.css:40 — rather than the page's usual 68ch measure or 72rem
   band width. #cost .inner carries an ID selector, so this wins over both
   .band > .inner (page.css:45) and .measure (page.css:46) without
   !important; the "measure" class was dropped from the markup rather than
   left as dead weight that no longer does anything.
   Larger heading, bolder body: both requested explicitly, scoped to this
   section only. The paragraphs' own entrance is written from script in
   js/scroll.js's "part 3"; nothing here sets a resting state, so that part
   of this block is inert until that script runs.
   THE HEADING NEVER LEAVES THIS BLOCK. While the act runs, js/cinematic.js
   builds a separate aria-hidden panel carrying the same sentence and
   keystones it onto the capture's own plane (see that file, and
   css/cinematic.css's .cin__title). This <h2> stays in normal document flow
   throughout — never fixed, never taken out of flow, and nothing here or
   anywhere else positions it. That is what makes the handoff cost nothing:
   no spacer holds space open, so there is no empty band to see, and no
   element enters or leaves flow, so there is no layout shift to measure.
   The card treatment is gone with it. .scope-col means "one of several
   parallel items" and this is a single full-width block carrying the page's
   central argument; drawn around a block whose heading was elsewhere, it
   rendered as a 126px (1280) / 161px (375) void. The band is .band--capture
   now — the same dark ground the act itself sits on — so the composed slide
   the act ends on and this block read as one continuous surface. */
#cost .inner { max-width: min(78vw, 1100px); }
#cost h2 { font-size: var(--cost-heading-size); }
#cost p { font-weight: 600; max-width: none; }

/* css/cinematic.css widens the capture to 92vw below this breakpoint, and the
   handoff at the end of the act finishes by swapping the act's heading panel —
   which is exactly as wide as the capture — for this block's own <h2>. Two
   different widths there means two different wraps and a sideways step at the
   swap, so the block follows the capture at both sizes rather than only at the
   one it was written for. The band's own padding still bounds it, which costs
   a pixel of the 92vw and nothing else. */
@media (max-width: 63.99rem) {
  #cost .inner { max-width: 92vw; }
}

