/* ==========================================================================
   BLVCKOS™ Landing Page

   Design system inherited from the LOCKED TQW landing page (HQ\tqw-landing,
   DESIGN.md): same type scale, same ink ramp, same video box geometry
   (aspect-ratio 1113/607, height clamp, 92vw cap, 1.5px accent border, 14px
   radius, 20px/4px glow), same pearl button (4-layer glow, hover lift), same
   entrance motion (opacity + translateY(14px), cubic-bezier(.2,.7,.2,1)).

   ONE deliberate divergence: the accent is BLVCKOS teal #4ab897, never TQW's
   #61e8de. Brand mark and headings glow white/silver, actions are teal.

   Every visible word is Jay's, verbatim. Design executes around the copy.
   ========================================================================== */

:root {
  --bg: #000000;

  /* Ink ramp, straight from the TQW system */
  --ink: #ffffff;
  --ink-soft: #cfd2d6;
  --ink-dim: #9aa0a6;

  /* BLVCKOS accent (NOT TQW teal) */
  --teal: #4ab897;
  --teal-line: rgba(74, 184, 151, 0.45);
  --teal-tint: rgba(74, 184, 151, 0.08);
  --teal-glow: rgba(74, 184, 151, 0.42);

  /* THE PAGE ACCENT IS NOW WHITE, MIRRORING THE APP (Patrick, 11-09-26).
     Names and values copied from blvckos-app/src/app/globals.css lines 60-61,
     so the two read as one brand:

       --accent: #f2f5f7;  --accent-rgb: 242, 245, 247;

     NOT #ffffff. The app's white is #f2f5f7, which is a measurably cooler and
     softer white, and on a black ground the difference between the two is
     visible side by side. The results cards and the open FAQ card were built
     at pure #fff earlier today and are moved onto this variable in the same
     pass, because a page carrying two different whites is the exact drift
     this variable exists to stop.

     --teal is NOT deleted. It still carries ::selection, the FAQ section's
     decorative wash and the keyboard focus ring, and the app's own rule still
     holds that green is the single yes/on/complete signal. */
  --accent: #f2f5f7;
  --accent-rgb: 242, 245, 247;

  /* GREEN WON, 17-09-26, and it is now a token rather than a toggle.

     Jay decided three of the four things --accent used to drive: "It looks
     really nice on my phone, so I think we do that" (dividers), "I think I
     like the FAQ better as green as well", and the two lower CTAs, which he
     conceded on Patrick's argument rather than on taste after being "90%
     certain I'm gonna want to keep it white". Patrick's question was the one
     that moved it: "is there any specific reason we're keeping the white
     besides design? The whole purpose is to try and get them to click the
     fucking button."

     THE TOP BUTTON IS NOT DECIDED. "Let's get the thumbnail in there and then
     have a look." So --accent now reaches exactly one element on this page,
     the hero CTA, and the green switch top right still flips it, which is
     precisely the one open question. Everything else below is settled.

     Same value as the app's C.green and as the Day label above the 1 and 30. */
  --green: #02e8a3;
  --green-rgb: 2, 232, 163;

  --hair: rgba(255, 255, 255, 0.08);
  --surface: rgba(12, 12, 14, 0.55);
  --card: #090909;
  --border: #1a1a1a;
  --red: #f05050;

  --sans: "Montserrat", system-ui, -apple-system, sans-serif;
  --mono: "Space Mono", ui-monospace, SFMono-Regular, monospace;

  /* TQW's LOCKED hero scaling system, copied exactly (05-08, Patrick's call:
     video + CTA must be the same size as the TQW landing page). One --u/--up
     unit = one design pixel of TQW's locked canvases:
       desktop canvas 2558 x 1304  ->  --u,  video 1086 x 673, button 700 wide
       phone   canvas  430 x  739  ->  --up, video  410 x 254, button 320 wide
     Every content column reads --media-w so the copy, the cards and the
     player keep sharing one set of edges. */
  /* --winw is the TRUE window width, set by the inline script in index.html.
     It exists because `scrollbar-gutter: stable both-edges` (see the html rule)
     SHRINKS every CSS viewport unit: on a 1440 window 100vw measures 1410, and
     100dvw / 100lvw / 100svw / 100% all do the same. The TQW landing page has no
     scrollbar, so its 100vw is the full 1440. Reading the gutter-reduced value
     here would size this page's video and CTA ~2% smaller than TQW's, which
     breaks the requirement stated at the top of this block. The 100vw fallback
     keeps the page sane with JS off. */
  --winw: 100vw;
  --u: min(calc(var(--winw) / 2558), calc(100dvh / 1304));

  /* PHONE UNIT IS WIDTH-ONLY, capped at the canvas. Changed 11-09-26.
     It was min(100vw/430, 100svh/739), so a phone's TEXT WIDTH was decided by
     its browser's visible HEIGHT. Two consequences, both measured:

     1. The page balanced on a cliff. On Patrick's own phone (430 x 932,
        Chrome iOS, visible height 745) the width term won by SIX pixels. Seven
        pixels more browser chrome and the height term takes over and the whole
        canvas starts shrinking. Anyone opening the page from an in-app browser
        was already the other side of that line.
     2. Short viewports got punished twice. An iPhone SE at 553 visible pulled
        the column to 306.8px inside a 375px screen, 34px of margin each side,
        for no reason connected to reading.

     The height term was there so the hero would fit one screen. It does not:
     the hero measures 850px in a 664px viewport, so it is ~200px past the fold
     whatever this unit does. It was costing layout consistency and buying
     nothing.

     Capped at 1px so the canvas stops growing past its 430 design width and
     the measure cannot run long on a wide phone or a foldable. --u keeps its
     height term: the desktop hero genuinely does fit its canvas. */
  --up: min(calc(var(--winw) / 430), 1px);
  --media-w: calc(410 * var(--up));
  --media-h: calc(254 * var(--up));

  /* THE DIVIDER'S AIR, above and below, as ONE number. Added 15-09-26.

     Before this the gap above a divider was the sum of three or four separate
     values and came out different every time: measured at 98, 78, 78, 76, 98
     and 114 on a phone against a flat 52 below. Patrick called it inconsistent
     and the measurement agreed.

     The fix is structural, not a set of nudges. Sections no longer carry ANY
     vertical padding, so the only thing that can put space around a divider is
     the divider itself, and it uses this one value on both sides. */
  /* MEASURED OFF IDENTITY SURGEON, 15-09-26 (Patrick: their spacing between
     the text, the divider and the text below is larger than ours).

     Read out of a full-page render at both widths, ink to divider, since the
     divider is not a readable DOM box on a Framer site:

       1440   above 118, 118, 117, 118      below 115, 115, 115, 115
       430    above ~102                    below ~76

     The desktop figure is the reliable one, four dividers agreeing within a
     pixel. The phone pass found fewer clean samples because their hero
     boundary reads as a divider to the same detector, so 100 is taken as the
     floor rather than the mean of a noisy set.

     Was clamp(60px, 6vw, 78px), so desktop was 78 against their 116. */
  --divider-space: clamp(100px, 8vw, 116px);
}

/* TQW's desktop breakpoint is 641px; the hero sizes switch canvases there. */
@media (min-width: 641px) {
  :root {
    --media-w: calc(1086 * var(--u));
    --media-h: calc(673 * var(--u));
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  background: var(--bg);
  overflow-x: hidden;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Reserve the scrollbar gutter on BOTH sides. This page scrolls and the TQW
     landing page does not, so without it every centred element here sits half a
     scrollbar (about 7.5px on Windows) left of where the same element sits on
     TQW, and the video jumps sideways when you switch between the two tabs.
     "both-edges" keeps the centre line on the true window centre instead of the
     scrollbar-reduced one. It is 0 on overlay-scrollbar systems (macOS, iOS), so
     nothing changes there. Widths are unaffected: they come off --u, which is
     measured in 100vw, and 100vw already includes the scrollbar. */
  scrollbar-gutter: stable both-edges;
}

body {
  background: var(--bg);
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.7;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Modern standard: kills double-tap zoom without blocking pinch-out */
html,
body,
button,
a {
  touch-action: manipulation;
}

::selection {
  background: rgba(74, 184, 151, 0.3);
  color: #fff;
}

img,
video {
  max-width: 100%;
  display: block;
}

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */
.wrap,
.wrap-wide {
  width: var(--media-w);
  max-width: 100%;
  margin: 0 auto;
}

/* TEXT NEEDS MORE EDGE THAN MEDIA DOES. Added 14-09-26.

   Measured before changing anything: the column was --media-w, which is 410
   design px, inside a 430 phone. That is TEN pixels of margin, falling to 8 at
   360 and 7 at 320, so Jay's copy was very nearly touching the side of the
   screen at every phone size. It also explains something already known: the
   results-card glow was cut off by the screen edge at 10px, and the cause was
   never the glow, it was the column.

   22px a side now. Media is deliberately NOT narrowed with it: the video is
   TQW's locked 410x254 box and both its width and height come from tokens, so
   narrowing width alone would distort a locked shape. It bleeds back out of
   the text column instead, centred, which is ordinary editorial practice and
   the reason the numbers below are negative.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .wrap,
  .wrap-wide {
    width: min(var(--media-w), calc(100vw - 44px));
  }
}


section {
  /* CUT ROUGHLY IN HALF, 11-09-26. Was clamp(64px, 7vw, 110px).

     The rule now sits at the top of a section, after this padding, so the
     distance from the last line of the previous section to the rule is the
     previous section's bottom padding PLUS this one's top padding. Measured
     at the old value that was 202px on desktop and 128px on phone, against
     20px from the rule down to its own heading: a ratio of 10 to 1, which
     left the rule glued to the heading and marooned from everything above it.
     Patrick called it as a massive gap and he is right.

     The old number was sized for a boundary made of nothing but air. There is
     a full-column rule doing that job now, so the air can come down: 202 to
     88 on desktop and 128 to 56 on phone, about 56% off both, which puts the
     rule roughly 4.4x its own heading distance rather than 10x. */
  /* ZERO. Replaced 15-09-26 by --divider-space on the divider itself.

     The comment above describes the old arrangement, where the gap above a
     rule was "the previous section's bottom padding PLUS this one's top
     padding". That is exactly why it could never be consistent: two values
     that nobody set together decided one visible distance, and any section
     with its own override moved it again. Now one value sets both sides and
     there is nothing else in the chain to disagree with it. */
  padding: 0;
  position: relative;
}

/* TWO GAP SIZES, NORMAL AND MAJOR. Added 14-09-26.

   Until now all seven boundaries weighed exactly the same, which flattened
   the page: the turn from an argument into its proof read no differently from
   one paragraph block following another. The rule above is the NORMAL break,
   about 76px on a phone and 92 on desktop (the gap is the previous section's
   bottom padding plus this one's top, so 38 + 38).

   Two boundaries are the real turns in the argument and get more:
     section 5, where the page stops making claims and the men who did it
       speak instead;
     section 7, the close.
   Both land near 96px on a phone (38 + 58).

   ONLY TWO SIZES, deliberately. A bespoke gap per section is how a page ends
   up with seven slightly different rhythms and no rhythm at all.

   nth-of-type, scoped to body.lp, for the same reason the old alternating
   ground was: written unscoped it leaks into every other page that loads this
   stylesheet, and inserting a section keeps the count correct by itself. */
/* REMOVED 15-09-26. This is what made sections 5 and 7 sit 20px further down
   than the rest, and it is the single biggest contributor to the 76-to-114px
   spread measured above the dividers.

   The intent behind it was good and is NOT abandoned: two boundaries in the
   argument really are bigger turns than the others. But weighting them by
   moving a padding that also feeds the divider gap meant buying emphasis by
   breaking rhythm. If that emphasis is wanted back it belongs on something
   that is not load-bearing for the divider. */
body.lp > section:last-of-type {
  /* The only section that still needs padding: nothing follows it but the
     footer, so there is no next divider to provide the air. */
  padding-bottom: var(--divider-space);
}

/* --------------------------------------------------------------------------
   SECTION BOUNDARIES: nothing. Every section is pure black.
   Patrick 11-09-26, superseding the alternating ground shipped this morning.

   That version lifted sections 1, 3, 5 and 7 onto #030304 with a lit top
   edge, so every adjacency was a change of surface. It worked, and it is
   being removed anyway because the full-column rule now above every heading
   already separates the sections. Two markers for one boundary is the exact
   fault the original hairline had, and this page has now removed that fault
   twice: once by deleting the hr elements, once by deleting the ground.

   The `body.lp` class on index.html is left in place. It costs nothing and it
   is the hook any future page-scoped rule needs, which the ground rule proved
   is necessary: written unscoped it leaked into every other page that loads
   this stylesheet.
   -------------------------------------------------------------------------- */

/* Hairline separator, TQW weight */
.rule {
  height: 1px;
  border: 0;
  background: linear-gradient(to right, transparent, var(--hair) 20%, var(--hair) 80%, transparent);
}

/* --------------------------------------------------------------------------
   Brand wordmark: the real transparent brand asset (BLVKCOS TRANSPARENT
   3000X750), which carries the true silver gradient and letterforms. Safe to
   use as an image because this file contains NO baked copy, unlike the LP card
   (that one bakes in its own tagline + scarcity line and would duplicate Jay's
   words). Glow is applied with drop-shadow so it matches the brand card.
   -------------------------------------------------------------------------- */
.wordmark {
  display: block;
  margin: 0 auto;
  height: auto;
  filter:
    drop-shadow(0 0 16px rgba(255, 255, 255, 0.42))
    drop-shadow(0 0 44px rgba(255, 255, 255, 0.2));
}

/* SIGNIFICANTLY SMALLER ON PHONE, 11-09-26. It was clamp(250px, 66vw, 440px),
   which rendered 283.8px on Patrick's 430 phone: 66% of the screen width, and
   the first thing on the page shouting before a word had been read.

   Three references, all measured rather than remembered:
     110px  the app's own in-app header wordmark (pre-challenge/page.tsx)
     150px  the LOCKED TQW landing page's .logo on a phone
     380px  the app's welcome screen, which is bigger than this page's was

   160 design px sits just above TQW's landing value, which is right for a mark
   that is the page's first impression rather than a header. Expressed in --up
   so it scales with the same canvas as the video, the CTA and the copy column
   instead of being the one element on its own scale.

   THE GLOW SCALES WITH IT. 16px and 44px of blur were 5.6% and 15.5% of a
   283.8px mark; left alone on a 160px mark they become 10% and 27.5%, which is
   the halo blooming to nearly double its relative size. Derived, not guessed:
   16 x (160/284) = 9, 44 x (160/284) = 25. Desktop restores the originals in
   the 641 block below, so nothing there moves. */
.wordmark-hero {
  width: calc(160 * var(--up));
  /* NO GLOW ON PHONE (Patrick, 11-09: "it looks like a box").

     The asset is not the problem. brand/wordmark.png is RGBA with fully
     transparent corners and zero ink anywhere on its outer border, so
     drop-shadow traces the letterforms, not the rectangle.

     The screen is. On an OLED, black is the pixel switched OFF, so every
     pixel the halo touches above zero is visibly emitting. A wide low-alpha
     shadow that is literally invisible on a monitor (grey 3 against grey 0)
     fills the space between and around the glyphs on the phone and reads as a
     lit rectangle. Same failure as 23-08-26, and it is why a desktop
     screenshot cannot catch it.

     Rather than chase a radius that survives OLED, the mark carries no CSS
     glow on phone at all. The PNG has its own silver treatment and does not
     need one. Desktop keeps 16/44 in the 641 block below. */
  filter: none;
}

/* SMALLER AND TUCKED AWAY (Jay, 14-09-26): "the logo adds no anything, it's
   literally just a branding thing, so you want to make it small and tucked
   away as opposed to a feature."

   100px matches the hero mark exactly, and it moves hard left for the same
   reason the hero one did, so the page opens and closes on the same gesture
   rather than opening left and closing centred. Opacity stays at 0.45: it was
   already doing the "tucked away" half of the instruction. */
.wordmark-foot {
  width: 100px;
  margin-left: 0;
  margin-right: auto;
  opacity: 0.45;
  filter: none;
}


/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero {
  /* BOTTOM PADDING TO ZERO, 15-09-26. It was clamp(58px, 6.5vw, 104px), and
     it stacked on top of the first divider's own margin-top: measured 120px
     above divider 1 against 60 below it, the worst offender on the page. The
     hero's separation from what follows is the divider's job now, same as
     every other boundary. */
  padding: clamp(42px, 5vw, 84px) 0 0;
  text-align: center;
  background:
    radial-gradient(126% 60% at 50% -10%, rgba(255, 255, 255, 0.075), transparent 60%),
    var(--bg);
}

/* THE FOLD CUE IS OFF EVERYWHERE BY DEFAULT and is switched on inside the
   (max-width: 640px) block, which carries the whole treatment and the
   reasoning for it.

   THIS RULE IS NOT REDUNDANT, and it was caught by measuring rather than by
   reading. Scoping the cue's styles to the phone query is not the same as
   scoping the ELEMENT to phones: with no desktop rule at all the div still
   exists and still renders, as a default block in normal flow, and it painted
   a 31.6px arrow in inherited --ink-soft at the bottom of the desktop hero.
   A phone-only element needs to be turned off, not merely left unstyled. */
.fold-cue { display: none; }

/* 700, NOT 800 (Patrick, 15-09-26). The Affinity wireframe is set in
   Montserrat BOLD, which is 700; this rule had been running 800, ExtraBold,
   one full step heavier, since the original build. Patrick spotted it as the
   page reading chunkier than his drawing and he was right.

   MEASURED before changing it, ink inside the headline box: 800 carries 24.5%
   solid stem against 700's 20.6%, so the letterforms really were 18.7% fatter,
   not an illusion. The glow is a separate effect and is NOT touched here: it
   triples the lit area (+176%) while thickening the stems by 1.6%, so it reads
   as soft rather than heavy. If the halo still looks like weight, that is the
   lever to pull, not this one. */
h1 {
  font-family: var(--sans);
  font-weight: 700;
  font-size: clamp(30px, 8.4vw, 52px);
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-top: clamp(22px, 3vw, 34px);
  /* MEASURED, NOT GUESSED, 17-09-26. Jay's second consecutive ask: "No,
     more... it still looks like flat white to me."

     The whole difference between this heading and the logo is a RIM. Profiled
     against the logo as painted at DPR 4: at half a pixel out the logo is 91.5
     and this was 15.6, and by two pixels they are level. So the answer is a
     third, TIGHT layer at 0.05em, not more spread. Widening the radii is what
     was tried before and it cannot work, because the difference was never in
     the far field.

     The two existing layers roughly halve and their alphas rise: 20px -> 0.57em
     (14.1px on the h1 here) and 52px -> 1.13em (28.0px).

     em, not px, so one declaration serves the h1 at 24.77 and the h2 at 31.5
     and neither has to be re-guessed. Same reason .lp-n is in em.

     Verified by render at 1440: painted 79.3 / 41.8 / 22.8 / 15.7 at
     0.5 / 1 / 2 / 4 css px against a logo target of 76.8 / 32.9 / 19.3 / 16.7.
     The tail past 12px runs short of the logo on purpose, since that layer is
     the bloom risk and the target there is 4.8 of 255. */
  /* DOUBLED, 17-09-26, Patrick: "double the glow on Stop breaking your word
     and wasting your potential". The h1 ONLY; the sub-headings keep the
     measured values and are now half this.

     Doubling could not come from alpha alone: the rim was already at 0.85 and
     1.0 is only +18 percent. So the rim radius doubles as well, and the two
     outer alphas go up about 1.8x. Four candidates were rendered and banded by
     distance from the letter before picking this one.

     MEASURED at 430, luminance by distance out in device px:
       0-2    2-5    5-10   10-20
       139.3   78.8   34.8   16.6   this
       101.8   32.1   15.4    6.9   the measured values it replaces
        51.9   20.7   15.1    8.6   what the page carried this morning
     So 2.45x through the bands that actually carry the halo. The 0-2 band only
     reads 1.37x because it is already near saturation and cannot double.

     WORTH KNOWING: the far field at 10-20px is now 16.6 against 8.6 this
     morning, roughly 1.9x what the page has ever carried there. That band is
     the one that filled in and made a grey box on an OLED on 11-09, so this
     wants looking at on the real phone rather than trusted from a render. */
  text-shadow:
    0 0 0.10em rgba(255, 255, 255, 1),
    0 0 0.63em rgba(255, 255, 255, 0.59),
    0 0 1.22em rgba(255, 255, 255, 0.33);
}

/* TWO break points, one per width, toggled rather than moved. br-lg is the
   desktop break after "wasting"; br-sm is the phone break after "and", which is
   where Jay's wireframe puts it. br-sm must be OFF by default: a <br> with no
   rule still breaks, so leaving it unstyled put THREE lines on desktop and
   tablet. Caught by rendering at four widths, not by reading the phone. */
h1 br.br-sm {
  display: none;
}

/* TQW .sub */
.hero-sub {
  margin-top: clamp(14px, 1.7vw, 24px);
  color: var(--ink-soft);
  font-weight: 400;
  line-height: 1.55;
  font-size: clamp(15px, 1.2vw, 20px);
}

/* TQW .above: brighter, heavier, the line that carries weight */
.hero-purpose {
  margin-top: clamp(14px, 1.6vw, 22px);
  color: var(--ink);
  font-weight: 600;
  line-height: 1.45;
  font-size: clamp(15px, 1.1vw, 19px);
}

/* --------------------------------------------------------------------------
   Video box: TQW geometry exactly (aspect 1113/607, height clamp, 92vw cap,
   1.5px accent border, 14px radius, 20px 4px glow, hover lift)
   -------------------------------------------------------------------------- */
.video {
  position: relative;
  display: block;
  margin: clamp(24px, 3vw, 42px) auto 0;
  padding: 0;
  /* TQW's exact locked box: 1086x673 design px on desktop, 410x254 on phone,
     both scaled by the shared unit. Width AND height come from the tokens, so
     the box is always exactly TQW's shape (1.614, the 1920x1190 video shape). */
  width: var(--media-w);
  height: var(--media-h);
  /* GONE, 17-09-26. Settled on the call the way Patrick said it would be,
     off the screenshot pair rather than in the stylesheet: "I like no border
     better." His reason is that the frame is no longer what carries the
     colour: "because there's now gonna be green and me in the thumbnail, I
     think that'll work a lot better."

     THE GLOW GOES WITH IT, and that is not an extra liberty. The borderless
     variant he chose was rendered with the halo off too, because a glow still
     draws a lit edge and a "borderless" box with a halo is just a softer
     border. He picked the one with neither.

     History: 1.5px was TQW's locked value, removed on 15-09 against Jay's
     14-09 list, put straight back because Patrick had not approved it, then
     questioned again on 16-09 and tested. */
  border: 0;
  /* SQUARE, 17-09-26. Jay, 16-09: "Make it completely square, not rounded."
     Decided on the call, not a test, so it ships regardless of how the border
     question lands. Was 14px.

     The border above is STILL OPEN. Jay asked "how certain are you that the
     white border around the video is what looks best?" and the answer going
     back to him is a screenshot pair, bordered and borderless, both square.
     It stays until he picks. */
  border-radius: 0;
  overflow: hidden;
  background: #050b09;
  /* No halo. See the border note above: the variant Jay chose had neither. */
  box-shadow: none;
  transition: transform 0.2s ease;
}

/* --------------------------------------------------------------------------
   Play button, overlaid dead centre.

   It used to be baked into the poster artwork, which was fine when the poster
   was an empty frame. The new thumbnail has the wordmark at its optical
   centre, and baking a button in meant either covering the wordmark
   permanently or shoving the button down into the empty lower band, which is
   what it was doing and it looked wrong.

   Overlaying it is what a real player does: YouTube, Vimeo and Wistia all put
   the control OVER whatever is in the frame. So the poster goes back to clean
   artwork and the button sits on top of it, always dead centre, always sharp
   at any size because it is scaling one asset rather than being resampled
   along with the photo.

   14% of the box width is not a guess: it is the proportion the button
   occupied in the original poster, measured at 202px of 1440.

   :has() scopes it to a box holding a POSTER. Swap the img for a real <video>
   and this disappears on its own, so the native control is never doubled up. */
.video:has(> img, > picture)::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 14%;
  aspect-ratio: 1 / 1;
  background: url("brand/play-button.png") center / contain no-repeat;
  pointer-events: none;
  z-index: 2;
  filter: drop-shadow(0 6px 22px rgba(0, 0, 0, 0.75));
}

.video img,
.video video,
.video iframe {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border: 0;
}

/* Approved Jay / Vanta poster, 18-09-26. Match the source on desktop and
   phone, including the later phone rule, and keep its baked 250px button.
   20-09-26: the locked master (ECOSYSTEM 2 - BLVCKOS, "Halo Fix and 4K",
   3840x2160) is EXACTLY 16:9, so the box is 16/9 rather than the old file's
   1672/941. That was 1.77683 against 1.77778 and cover-cropped a sliver off
   the sides. Keep this in step with the master or the crop comes back. */
.hero .video.video--jay-thumbnail {
  height: auto;
  aspect-ratio: 16 / 9;
}

.video.video--jay-thumbnail::after {
  content: none;
}

/* ---- the hero video, once it is playing ---------------------------------
   Added 21-09-26 with the Livid embed.

   Nothing here sets a shape. Dropping `video--jay-thumbnail` is the whole
   mechanism: the box falls back to --media-w / --media-h, which is TQW's
   locked 1086x673, an aspect of 1.614, which is exactly the 1920x1190 the
   video is. The extra height over 16:9 is the burned-in caption bar, so
   matching the box to the source keeps both the picture and the captions
   whole. Forcing the video into the thumbnail's 16:9 instead would have
   pillarboxed it, which is the "a video has ONE shape" lesson.

   The button reset matters: `.video` is now a <button>, and a UA button
   brings its own font, padding, border and background. */
.video {
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: pointer;
}

.video.is-playing {
  cursor: default;
}

.video.is-playing img {
  display: none;
}

/* THE BAKED PLAY BUTTON HAS TO GO WHEN THE VIDEO STARTS, and hiding the poster
   was not enough. `.video:has(> img, > picture)::after` is scoped by :has() to
   a box that still CONTAINS a poster, and display:none does not remove the node,
   so the button kept drawing over the playing video. Its own comment says it
   "disappears on its own" once the img is swapped out, which is true only if the
   img actually leaves the DOM.

   So the script now removes the node, and this rule is the guarantee in case it
   ever does not. Reported by Patrick 21-09-26 off a phone screenshot: the silver
   button sitting on top of Livid's own controls. */
.video.is-playing::after {
  content: none;
}

.video.is-playing:hover {
  transform: none;
}

.video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.video:hover {
  transform: translateY(-2px);
}

/* THE VIDEO BLEEDS BACK OUT of the narrowed text column on a phone, so it
   keeps TQW's locked 410x254 box while Jay's copy gets its 22px of edge.

   THIS RULE HAS TO SIT AFTER `.video` ABOVE, not with the other phone
   overrides higher up the file. It was written there first and silently did
   nothing: `.video { margin: clamp(...) auto 0 }` is the same specificity and
   comes later, so `auto` won and the video rendered 22px in on the left and
   2px PAST the screen on the right instead of centred. Measured, not noticed.

   50% is half the narrowed wrap; subtracting half the locked box gives an
   exact symmetric bleed at any width. Only the sides are set, so the top
   margin from the shorthand survives. */
@media (max-width: 640px) {
  .video {
    margin-left: calc(50% - var(--media-w) / 2);
    margin-right: calc(50% - var(--media-w) / 2);
  }
}

/* --------------------------------------------------------------------------
   Pearl CTA: the exact tqw-ct-app .btn-pearl treatment, BLVCKOS teal
   -------------------------------------------------------------------------- */
.cta-block {
  margin-top: clamp(24px, 2.8vw, 40px);
  text-align: center;
}

/* THE TWO IN-PAGE CTAs SIT FURTHER OFF THE LINE ABOVE THEM. Patrick, 16-09-26:
   60px on desktop, 40px on phone.

   They were 24 on a phone and 40 on desktop, both coming off the base rule
   above. Measured before the change, box to box from the paragraph above to
   the top of the button: mid-page 24 / 40, closing 26 / 40, where the 2px on
   the closing one is the bold line's descender rather than a different gap.

   `section .cta-block` is the whole scope. The hero's CTA is inside a
   <header class="hero">, so it is excluded by structure rather than by a
   :not() somebody has to maintain, and it keeps the tighter margin it needs to
   stay above the fold.

   The clamp reaches both of his numbers exactly: 4.2vw is under 40 until
   952px so the floor holds across every phone, and it passes 60 at 1429px so
   the ceiling holds across every desktop. Between those it ramps rather than
   stepping, which is what the rest of this file does. */
section .cta-block {
  margin-top: clamp(40px, 4.2vw, 60px);
}

.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* PHONE VALUES ARE FIXED, not scaled. Changed 11-09-26.

     These were calc(320 * --up) / calc(14 * --up) / calc(13 * --up), so the
     button shrank with the canvas. Both apps use a FIXED 320 x 50 button on
     every phone, and measured side by side the two systems only agreed on
     Patrick's own 430 screen, where --up happens to be exactly 1. At 390 the
     landing button was 290.2 against the app's 320, and at 375 it was 279.1.

     Now identical to blvckos-app's .btn-primary and the TQW app's .btn-pearl
     at every phone size: 320 wide, 16/28 padding, 13px, line-height normal,
     which together give the same 50px height. 92vw still caps it so a 340px
     phone cannot overflow.

     Desktop keeps its own locked geometry in the 641 block below, including
     the inherited 1.7 line-height, so nothing there moves. */
  /* MATCHED TO THE TQW LANDING PAGE, not to the apps (Patrick, 11-09: the two
     landing pages should agree with each other). Its hero button is

       width: calc(320 * --up)   padding: calc(14 * --up) calc(20 * --up)
       font-size: calc(13 * --up)   weight 600   radius: calc(10 * --up)

     read straight out of HQ	qw-landing/index.html, and these are the same
     expressions on the same 430-wide canvas, so at 430 both render 320 x 46.

     ONE DELIBERATE DIVERGENCE. TQW's --up still carries its height term, so on
     a short viewport its button shrinks with the browser chrome: measured, it
     renders a 9.7px font on a 239px button on an iPhone SE and 11.3px at
     430x640. This page's --up is width-only since the cliff fix, so the two
     are pixel-identical wherever TQW is not shrinking itself, and this one
     stays legible where TQW does not. */
  width: calc(320 * var(--up));
  max-width: 92vw;
  padding: calc(14 * var(--up)) calc(20 * var(--up));
  font-family: var(--sans);
  font-weight: 600;
  font-size: calc(13 * var(--up));
  line-height: normal;
  letter-spacing: 0.01em;
  color: #fff;
  text-decoration: none;
  text-align: center;
  background: #000;
  /* GREEN, and no longer switchable (Patrick, 21-09-26). This was --accent,
     which the top-right switch used to flip. Jay parked the top button on
     17-09 until the thumbnail was in; it is in, the video is in, and Patrick
     has called it green, so all three buttons now come off --green from this
     one rule and the `section .cta` override that used to green the lower two
     is gone as redundant. */
  border: 1.5px solid var(--green);
  /* TQW uses calc(10 * --up); identical at 430 and it scales with the box. */
  border-radius: calc(10 * var(--up));
  cursor: pointer;
  /* EXACTLY THE APP'S RESTING GLOW. Restored 15-09-26.

     These four layers are a verbatim copy of .btn-primary in
     blvckos-app/src/app/globals.css, which is what this button was before I
     widened it that morning under Jay's "button: more glow". Patrick asked
     whether the two still matched, they did not, and he called it back.

     Jay's item 14 is therefore still OPEN, not done. If it is actioned later,
     the app's own HOVER values are the honest source to take it to
     (4px .65 / 14px .50 / 32px .35 / 64px .18) rather than invented numbers.
     Note the app's hover state never appears on a phone, so a man on a device
     has never seen that brighter version. */
  box-shadow:
    0 0 4px rgba(var(--green-rgb), 0.5),
    0 0 12px rgba(var(--green-rgb), 0.4),
    0 0 28px rgba(var(--green-rgb), 0.28),
    0 0 56px rgba(var(--green-rgb), 0.14);
  transition: transform 0.18s ease, box-shadow 0.25s ease;
}

@media (min-width: 641px) {
  .cta {
    width: calc(700 * var(--u));
    padding: calc(22 * var(--u)) calc(32 * var(--u));
    font-weight: 700;
    font-size: calc(22 * var(--u));
    /* `normal`, NOT the 1.7 this used to restate from body. TQW's hero button
       sets no line-height at all, so it inherits `normal`, and an inline-flex
       button's height is padding + line box. 1.7 made this button 47.8px tall
       against TQW's 41.8px at 1440: same width, 6px taller. Measured, both are
       Montserrat, so `normal` resolves to the same ratio on both pages. */
    line-height: normal;
    /* The phone rule's calc(10 * --up) resolves to a FLAT 10px up here, because
       --up is capped at 1px past the phone canvas. TQW scales its radius with
       the canvas, so its corners are 5.6px at 1440 against this button's 10px. */
    border-radius: calc(10 * var(--u));
  }
}

.cta:hover,
.cta:focus-visible {
  transform: translateY(-2px);
  box-shadow:
    0 0 6px rgba(var(--green-rgb), 0.6),
    0 0 16px rgba(var(--green-rgb), 0.48),
    0 0 36px rgba(var(--green-rgb), 0.34),
    0 0 72px rgba(var(--green-rgb), 0.18);
}

.cta:active {
  transform: translateY(0);
}

/* Tagline: Jay's words, brand-card treatment (Space Mono, letterspaced, dim
   silver). Capitalisation left exactly as Jay wrote it. No text-transform. */
.tagline {
  margin-top: clamp(13px, 1.4vw, 20px);
  font-family: var(--mono);
  font-size: clamp(11.5px, 0.75vw, 14px);
  font-weight: 400;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  text-shadow: 0 0 18px rgba(255, 255, 255, 0.16);
}

/* TQW .below */
/* The free line under every CTA. Scoped to .cta-block, which is (0,2,0), so
   it beats `.copy p` at (0,1,1). That specificity accident is the whole reason
   the three instances were different: the closing one sits inside a .copy
   column and was silently rendering at the body clamp's 16px while the other
   two rendered this rule's 13.5px. Patrick picked the larger one, so the
   larger one is now the declared style rather than a side effect. */
.cta-block .scarcity {
  margin: clamp(12px, 1.3vw, 18px) auto 0;
  max-width: 30em;
  color: var(--ink-soft);
  font-weight: 500;
  font-size: clamp(16px, 0.95vw, 18px);
  line-height: 1.6;
}

/* THE EMPHASIS GOES PURE WHITE, AT EVERY WIDTH (Patrick, 15-09-26: "same as
   the $1,000 USD per year on thequantumworld.co").

   Measured on TQW: its <b>$1,000USD/year</b> is weight 700 at rgb(255,255,255)
   sitting inside a rgb(207,210,214) sentence, so the bold run is BOTH heavier
   and a different colour. BLVCKOS had the weight but not the colour: its
   <strong> computed to 700 at rgb(207,210,214), identical to the text around
   it, so the emphasis was doing half its job and read as barely emphasised.

   MOVED OUT OF THE PHONE BLOCK 16-09-26. It was written inside
   `@media (max-width: 640px)` on 15-09, so only the phone ever got it and
   desktop kept rendering the bold run in the same grey as its sentence.
   Patrick caught it on the deployed site. The rule was always meant to be
   unconditional: nothing about "the emphasis is a different colour from the
   sentence" is a phone idea. It now sits next to the rule it modifies, which
   is also where it stops being easy to lose.

   Pure #fff deliberately, NOT the page accent #f2f5f7. TQW uses pure white
   here and matching it is the whole instruction. */
.scarcity strong,
.scarcity b {
  color: #ffffff;
}

/* --------------------------------------------------------------------------
   Section headings + long copy
   -------------------------------------------------------------------------- */
h2 {
  font-family: var(--sans);
  /* BACK TO 800 (Patrick, 15-09-26): "the main heading on the hero section is
     Montserrat bold, make all the other main headings Montserrat bold as well".

     This REVERSES the 800 -> 500 change made earlier today off Jay's 14-09
     note ("headings far too fat and bulky", target the app's weight). Patrick
     is the one looking at it and has called it, so 800 stands, but the
     contradiction is live and belongs on the call: Jay asked for lighter, this
     is heavier, and both instructions are on the record.

     UPDATED SAME DAY: 700, not 800. Patrick matched both headings to the
     Affinity file, which is Montserrat Bold. See the h1 rule for the ink
     measurement that settled it. */
  /* 600, DOWN FROM 700 (Patrick, 15-09-26). The headings were matched exactly
     to the hero headline earlier today and he has now split them back apart:
     one step smaller and one weight lighter, so the hero stays the largest
     thing on the page. */
  font-weight: 600;
  /* GLOW, 17-09-26, and on desktop this is the FIRST one these have ever had.
     Measured before writing: at 1440 `section h2` computed text-shadow: none.
     The only rule that ever gave a sub-heading a halo was inside the phone
     media query, so on a monitor they have always been flat.

     Jay, 17-09: "more glow on the sub-headings too", the same treatment as the
     main heading. Same three em layers as the h1, so at 31.5px they resolve to
     1.58 / 17.96 / 35.60px and the halo tracks the glyph instead of being
     re-guessed for a second size.

     80 PERCENT OF THE H1, 17-09-26 (Patrick). The RADII are now identical to
     the h1 and only the ALPHAS come down, to 0.8x of its 1 / 0.59 / 0.33.

     Identical radii is the right way to read "80 percent of the glow h1 uses"
     because they are in em: at the h2 own size the halo is already
     proportionally smaller in painted pixels, so scaling the radii as well
     would take it down twice. The alphas are the only lever that expresses a
     percentage cleanly.

     Measured after the change, so it is 80 percent in painted light and not
     just on paper. */
  text-shadow:
    0 0 0.10em rgba(255, 255, 255, 0.8),
    0 0 0.63em rgba(255, 255, 255, 0.47),
    0 0 1.22em rgba(255, 255, 255, 0.26);
  /* Floor raised 23 -> 27 so the phone lands on Identity Surgeon's 27px. At
     weight 500 the old 24.9 read undersized; a lighter face needs a little
     more size to hold the same presence. */
  /* Desktop ceiling 35 -> 31.5, one step of a 1.111 modular scale below what
     it was. The phone value is set separately below against the hero's own
     25.1. */
  font-size: clamp(24px, 5.8vw, 31.5px);
  line-height: 1.15;
  /* -0.02em, the h1's exact value, so the two headings are set as one face.
     800 crowds itself without it, which is what the tracking was there for
     before the weight briefly went to 500. */
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-bottom: clamp(24px, 2.6vw, 38px);
  /* NO GLOW, 14-09-26. This was `0 0 26px rgba(255,255,255,0.17)` on all seven
     headings. On an OLED black is the pixel switched OFF, so a 26px halo at
     17% lights every pixel it touches and fills the counters of the letters:
     the wordmark failure from 11-09, repeated at heading scale seven times
     down the page. Invisible on a monitor, so no screenshot taken here could
     have caught it. The h1 keeps its own, already-reduced, glow. */
}

/* THE HEADING MARK: 46 x 2, radius 2, with a 12px halo at 75%.
   Patrick 14-09-26, going back to treatment 01 off heading-marks.html.

   WHAT THIS REPLACES. The full-column hard rule taken off
   docs/board-heading.html on 11-09. That rule was doing two jobs: marking the
   heading AND separating the section, which is why the alternating section
   ground came off at the same time.

   SO NOTE WHAT NOW CARRIES THE SEPARATION: the spacing alone. Section gaps
   are two sizes, 76px normal and 96px major on a phone (92 and 115 on
   desktop), and with a 46px mark there is no longer a full-width object at
   the boundary. That is a coherent position rather than an oversight, and it
   is the one most modern long-form pages take, but it does mean the gaps are
   load-bearing now: shrink them and the sections stop separating.

   The mark keeps its own halo even though the h2 TEXT lost its glow on
   14-09. Those are different objects: a 46 x 2 bar with a 12px halo is a
   small bright accent, where a 26px glow on seven headings was light spread
   across whole letterforms and filling their counters on an OLED.

   No centring rules are needed. `.decision` resolves to text-align: left
   (declared twice, the later one wins), and the hero carries an h1 and no h2,
   so a left-aligned mark is correct in every section that has one. */
/* --------------------------------------------------------------------------
   THE SECTION DIVIDER. Replaces the 46x2 heading mark (Patrick, 15-09-26:
   "that specific line we remove and replace with a divider").

   Copied from theidentitysurgeon.com, in white instead of their green, and
   MEASURED OUT OF THE PAINTED PIXELS rather than their CSS: the site is built
   in Framer and the divider is not a readable DOM box. A full sweep for
   gradients, borders and thin painted elements returned two candidates and
   neither was it, so the profile below was sampled off a render.

   WHAT THE SAMPLE SHOWED, and why it is not a two-stop gradient. Their line is
   1px, full viewport width, peaking dead centre at rgb(0,216,136). Across the
   half-width the green channel runs 0.04, 0.18, 0.39, 0.68, 1.00 of peak at
   10/20/30/40/50%. A plain `transparent -> colour -> transparent` ramps
   linearly (0.2, 0.4, 0.6, 0.8) and reads far too flat and far too wide. The
   measured curve is almost exactly linear SQUARED, so the stops below
   reproduce it instead of approximating it.

   Full-bleed via the margin-left trick rather than 100vw positioning, because
   `scrollbar-gutter: stable both-edges` on this page means 100vw and the body
   box are not the same width on desktop.

   No glow. Their line has none, and on an OLED a halo on a 1px rule blooms
   into a grey band, which is the wordmark fault from 11-09 all over again.
   -------------------------------------------------------------------------- */
h2::before {
  content: "";
  display: block;
  /* 920px CAPPED AT THE VIEWPORT, not a flat 100vw (Patrick, 15-09-26: the
     desktop divider is too long, copy the Identity Surgeon width).

     MEASURED on their live site at 1440 by scanning the painted rows of a full
     page render, since the divider is not a readable DOM box. Four samples:
     919, 893, 919 and 907px, all centred on x=718 against a 720 viewport
     centre. That is 62-64% of the viewport, and the spread is threshold noise
     from the gradient tail, not four different widths.

     A fixed width capped at the viewport is what produces both measurements:
     at 430 the cap wins and it runs edge to edge, which is what the phone pass
     showed, and at 1440 it sits at 64%. A percentage would have been wrong on
     the phone and a flat 100vw is what is wrong on desktop now.

     The margin reproduces the centring against the heading column rather than
     the viewport: the column is 611px at 1440, so a 920px rule has to start
     outside it. */
  width: min(920px, 100vw);
  margin-left: calc(50% - min(920px, 100vw) / 2);
  height: 1px;
  background: linear-gradient(
    90deg,
    rgba(var(--green-rgb), 0) 0%,
    rgba(var(--green-rgb), 0.04) 10%,
    rgba(var(--green-rgb), 0.18) 20%,
    rgba(var(--green-rgb), 0.39) 30%,
    rgba(var(--green-rgb), 0.68) 40%,
    rgba(var(--green-rgb), 1) 50%,
    rgba(var(--green-rgb), 0.68) 60%,
    rgba(var(--green-rgb), 0.39) 70%,
    rgba(var(--green-rgb), 0.18) 80%,
    rgba(var(--green-rgb), 0.04) 90%,
    rgba(var(--green-rgb), 0) 100%
  );
  /* EQUAL ON BOTH SIDES, from one token. The margin-top is what used to be
     the section's padding-top and the previous section's padding-bottom
     combined; now it is simply the same number as the margin-bottom, so the
     rule sits dead centre in its own gap by construction rather than by
     tuning. */
  margin-top: var(--divider-space);
  margin-bottom: var(--divider-space);
}
/* The centred-mark rules that used to live here are GONE. They set auto side
   margins on a 46px mark so it could sit centred under the hero and the
   close; a rule that is 100% of the column has nothing left to centre, and an
   inert rule describing behaviour the page no longer has is how a stylesheet
   starts lying. The hero carries an h1 and no h2, so that half was already
   dead. */

/* THE IDENTITY SURGEON BODY SCALE (Jay, 14-09-26: "take the sizing from the
   Identity Surgeon site", "copy the Identity Surgeon spacing between blocks of
   text, you see how it's more spaced out").

   MEASURED off theidentitysurgeon.com at 430 wide, not eyeballed: its dominant
   body style is 15px / 23px line-height / weight 400, appearing 70 times, with
   26px between sibling paragraphs.

   THE COUNTER-INTUITIVE HALF, and the reason the page will read airier while
   using LESS vertical space per paragraph: their leading is TIGHTER than ours
   was (1.53 against 1.72) and their paragraph gap is BIGGER (26 against 20).
   Tight lines inside a block and a wide gap between blocks is what makes the
   blocks read as distinct objects. Loosening the leading instead, which is the
   obvious move when someone says "more space", melts the paragraphs into one
   grey field and reads as MORE text, not less. */
.copy p {
  margin-bottom: 26px;
  /* 14 on phone (Patrick, 15-09-26), down from the Identity Surgeon 15.
     The desktop ceiling comes down with it so the ratio between the two
     breakpoints is unchanged. */
  font-size: clamp(14px, 0.95vw, 16px);
  line-height: 1.533;
  color: var(--ink-soft);
}

.copy p:last-child {
  margin-bottom: 0;
}

/* The lines Jay bolded: bare weight (anchor-styles option 1, Patrick 05-08).
   White, 700, a hair larger, extra air, nothing else. Emphasis via weight,
   single ink colour. */
/* THE LEDGER VOICE. Treatment 11 off anchor-styles.html, Patrick 14-09-26.

   Jay's payoff line stops being prose and becomes a line of record: Space
   Mono, the app's own label face, with a caret still blinking as though the
   entry is open. There are two of these on the page, the close of the problem
   section and the close of the mechanism section, and both get it.

   SIZE COMES DOWN, deliberately. Mono sets wider than Montserrat at the same
   nominal size, so holding 16.5-19px would have made the anchor run longer
   than the heading above it. 15-17.5px lands on roughly the same measure. The
   leading opens from 1.6 to 1.75 for the same reason: monospace at 700 across
   three lines is a lot of ink in the middle of long copy.

   The !important on font-size and line-height is inherited from the rule this
   replaces, not a new decision: `.copy p` sits at (0,1,1) and would otherwise
   win on source order. That trap has bitten this file repeatedly. */
.anchor {
  margin: 28px 0 0;
  /* MONTSERRAT, NOT SPACE MONO. Patrick, 15-09-26, pointing at the app's
     "WELCOME TO DAY 1 OF YOUR BLVCKOS(tm) 30 DAY CHALLENGE." line: use that
     font here and on the Day label. That line is T.tagline in the app and its
     family is FH, Montserrat.

     This retires the last of the mono voice from the body of the page. The
     anchors and the Day label were the only two things still set in Space
     Mono, which is exactly the "consistent with everything else, and
     something we could use from the app" that Jay asked for on 14-09.

     WEIGHT STAYS 700 AND THE CASE STAYS AS WRITTEN. The tagline is 400 and
     uppercase because it is an 8px eyebrow of six words. These are three
     full sentences at 14px, and uppercase at 0.2em would turn each of them
     into a block of tracked capitals that nobody reads. The instruction was
     the font; the font is what changed.

     Space Mono is still on the page where it belongs: the ledger stamps and
     the small system labels. */
  font-family: var(--sans);
  font-weight: 700;
  color: var(--ink);
  /* 14 on phone (Patrick, 15-09-26), tracking the body copy down. */
  font-size: clamp(14px, 0.92vw, 16.5px) !important;
  line-height: 1.75 !important;
  /* TRACKED OUT, 15-09-26. Patrick: the app's line is spaced wider than this.
     It was, because this was on zero.

     The app's welcome line paints 0.200em, MEASURED off brand/ledger-day-one
     .png rather than read off the token: the Ledger title on the same screen
     is Montserrat 500 at 17px with no tracking, so its 505px of painted ink
     fixes the capture's scale to 0.2%, and at that scale the tagline's 385px
     of ink is reproduced at 0.200em and nowhere else. (Normalising by cap
     height instead gives 0.26em and is worthless: the cap is 10 painted
     pixels, so half a pixel of antialiasing moves the answer by 0.04em.)

     0.06em, not 0.2em. 0.2em is authored for an 8px eyebrow of six words;
     tracking has to come DOWN as type goes up or a sentence stops being a
     sentence. At 14px it runs every anchor to four lines and reads as a
     poster. 0.06em is the largest value that leaves the line counts on
     Patrick's 430 exactly where they are now (3 / 2 / 2); 0.08em tips the
     second anchor to three lines there.

     Measured across 320 to 1920: line counts hold and the shortest last line
     never drops below 53% of the column. */
  letter-spacing: 0.06em;
  /* BALANCED, and this is what makes the tracking safe. Without it the last
     line of an anchor lands on 8-15% of the column at 360, 375, 768 and 1440,
     which is one word alone. That fault is not new, it is there today at zero
     tracking (desktop anchor 2 sits at 13%), and adding any tracking moves
     which widths it bites at rather than fixing it. Balance takes the worst
     case across every width from 8% to 53%.

     Safe to add: it changes line BREAKING only, never the text, and a browser
     that does not support it simply wraps the way it does now. */
  text-wrap: balance;
}

/* The caret. It rides on the mark's ::after rather than the paragraph's, so
   it lands immediately after the final full stop instead of at the end of the
   line box, which on a short second anchor are very different places. */
.anchor mark::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 0.95em;
  vertical-align: -0.14em;
  margin-left: 5px;
  background: var(--teal);
  animation: anchor-blink 1.05s steps(1) infinite;
}

@keyframes anchor-blink {
  50% { opacity: 0; }
}

/* A thing blinking forever in the middle of a long read is a genuine
   accessibility problem, not a stylistic one. It holds still for anyone who
   has asked their system for less motion. */
@media (prefers-reduced-motion: reduce) {
  .anchor mark::after { animation: none; }
}

.anchor mark {
  background: none;
  color: inherit;
  padding: 0;
}

/* --------------------------------------------------------------------------
   TYPEWRITER, added 14-09-26. The line prints itself out when it scrolls into
   view, at a fixed ~62 characters per second, so all three anchors type at the
   same SPEED rather than over the same DURATION. Equal durations would make
   the 79-character line crawl next to the 124-character one and read as the
   page going sluggish; equal speed reads as one machine printing.

   THE WHOLE TRICK IS `visibility`, NOT `display`. An untyped character still
   occupies its exact final box, so the paragraph is laid out at full height
   from the first frame and nothing below it moves while the line prints.
   Revealing by appending text instead would reflow the page on every single
   character, and on a three-line anchor that means the entire rest of the page
   jumping twice as the line wraps.

   Splitting into per-character spans does NOT change where the line wraps:
   inline boxes add no break opportunities of their own, breaking still follows
   the text. That is asserted by the test rather than trusted.
   -------------------------------------------------------------------------- */
.anchor .tw {
  visibility: hidden;
}

.anchor .tw.is-lit {
  visibility: visible;
}

/* While printing, the permanent end caret is out of the way: two carets on one
   line reads as a fault. It comes back the moment the line finishes. */
.anchor mark.is-typing::after {
  display: none;
}

/* The travelling caret. SOLID, not blinking: a cursor that moves AND blinks
   looks broken, and a real terminal only blinks once it is idle. Sits 2px off
   the last printed character rather than the 5px the resting caret uses,
   because mid-word that gap reads as a space. */
.anchor .tw.is-cursor::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 0.95em;
  vertical-align: -0.14em;
  margin-left: 2px;
  background: var(--teal);
}

/* The final CTA line, bold in full (Jay, 14-09-26). White as well as bold,
   because at 700 in the body grey it reads as a heavier paragraph rather than
   as the close. */
/* Scoped through .copy deliberately. `.copy p` sets the body grey at
   specificity 0,1,1 and a bare `.closing-line` is 0,1,0, so the weight applied
   and the colour silently did not: the line came back 700 in rgb(207,210,214).
   Measured, not assumed. */
.copy p.closing-line {
  font-weight: 700;
  color: var(--ink);
}

/* Cost section closes here, give it air */
.closer {
  padding-top: 8px;
  color: var(--ink);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   Ledger strip: the page's ONE illustrative visual, and it is the app's REAL
   Discipline Ledger block. Re-ported 09-09-26 from the live source, because
   the first port (05-08) predated two redesigns and had drifted badly: it was
   still painting the retired 135deg #5ECBA6 to #2E9470 green Jay asked to
   move off, rounded corners against Jay's 20-08 square lock, a 1px border
   where the app uses an inset ring, and a single drop shadow where the app
   uses four light layers.

   Source of truth, read rather than remembered:
     HQ\blvckos-app\src\lib\tokens.ts            greenTile / redTile / todayTile,
                                                 the *TileBorder and *TileGlow
                                                 sets, tileRing, tileRadius
     HQ\blvckos-app\src\app\(app)\challenge\page.tsx   the grid and the cell

   THE LINE IS AN INSET RING, NOT A BORDER (the app's own comment): a border
   eats a pixel off each side of the content box, so the DAY label and the
   number would sit in a narrower square than the block they are centred in.
   The ring paints in the same place and takes nothing. It is also why the
   width can be 0.75px at all, since Chrome floors border-width to whole
   pixels but box-shadow spread takes sub-pixel values.

   SCALING. Every number in the app is authored for a real 29px block, and a
   component's light is authored for its shipped size (Build Lessons). So this
   does not re-guess any value: it derives ONE unit, --s, from the container
   and multiplies every app value by it. 10 cells at 29 plus 9 gaps at 3 is a
   317 design-px row, so --s = 100cqw / 317 is one app pixel. At phone width
   --s lands at ~0.93, which is the app's own size.
   -------------------------------------------------------------------------- */
.ledger {
  /* The query container is the WRAPPER, not the grid: an element cannot
     query itself, and this box's content width IS the grid's width, so
     100cqw below is exactly the row the app draws. */
  container-type: inline-size;
  margin: clamp(30px, 3.2vw, 44px) auto 0;
  /* FULL COLUMN WIDTH (Patrick, 10-09). It now matches the copy column and
     the video player exactly, because it simply fills .wrap.

     What that trades away, recorded rather than argued: it used to be capped
     at 460px so the cells stayed near the ~29px block a member actually uses
     in the app, about 1.3x at most. At full column width the cells scale with
     the column, so on a wide monitor they land closer to 2x the real thing.
     Everything still scales together and stays in proportion, because --s is
     derived from the container width rather than fixed, so it reads as the
     same object, just larger. */
  max-width: 100%;
  /* The app's own panel, from tokens.ts `panel` as used at the ledger call
     site in challenge/page.tsx: 14px 16px on rgba(10,10,12,0.5), a 0.06 white
     hairline, radius 12, and NO drop shadow. The landing page had invented a
     slightly different card and hung a heavy shadow under it.
     NOTE for Patrick: in the app this panel belongs to the IN-PROGRESS ledger.
     A finished 30-day record is the FinalLedger screen and renders bare on
     black with no card at all, which is the state this strip depicts. Keeping
     the panel is a landing-page framing call, not an app match. */
  padding: 14px 16px;
  background: rgba(10, 10, 12, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 12px;
}

/* The panel's contents, straight off challenge/page.tsx: a 13/700 count
   line, a 12px supporting sentence, 18px, then the blocks.

   --s lives HERE and not on .ledger, because .ledger is the query container
   and an element cannot query itself. This wrapper is a child, so its 100cqw
   resolves against .ledger's content width, which is the row the app draws.
   Putting it on .ledger would silently resolve against the SCREEN instead,
   padding included, and every derived value would run a few percent large. */
.ledger-inner {
  --s: calc(100cqw / 317);
}

/* T.sectionHead: 13 / 700, 12px under it.

   Selector is .ledger-inner .ledger-count, NOT .ledger-count. These are <p>
   elements inside .copy, so `.copy p` at (0,1,1) beats a bare class at
   (0,1,0) and silently swallows the font-size, leaving the app UI rendering
   at page body size inside a phone frame. That specificity trap has now bitten
   this project on the offer card, the empty-state mark, the tslot labels and
   the scarcity line. (0,2,0) clears it. */
.ledger-inner .ledger-count {
  font-family: var(--sans);
  font-weight: 700;
  font-size: calc(13 * var(--s));
  line-height: 1.3;
  margin: 0 0 calc(12 * var(--s));
  color: var(--ink);
}

/* C.green #02E8A3. The count is the manual's day outcome being counted, so
   it reads the Green token and never the page accent. */
.ledger-inner .ledger-count .c {
  color: #02e8a3;
}

/* T.pageSub: 12. Same specificity reasoning as the count above. */
.ledger-inner .ledger-explain {
  font-family: var(--sans);
  font-size: calc(12 * var(--s));
  line-height: 1.45;
  margin: 0 0 calc(18 * var(--s));
  color: var(--ink-dim);
}

.ledger-grid {
  display: grid;
  /* challenge/page.tsx: repeat(10,minmax(0,1fr)), gap 3 */
  grid-template-columns: repeat(10, minmax(0, 1fr));
  --s: calc(100cqw / 317);
  gap: calc(3 * var(--s));
}

.ledger-cell {
  /* TQW's .ct-block: a SQUARE, padding 0, contents centred by flex. */
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0;
  /* C.tileRadius = 0. Jay, 20-08-26: every ledger block is a square with
     square corners. A 6% radius was tried on 25-08 and taken back off the
     same day, so the lock stands. */
  border-radius: 0;
  border: 0;
  /* Pending day: C.card face, C.border ring, no glow. */
  background: var(--card);
  box-shadow: inset 0 0 0 calc(0.75 * var(--s)) var(--border);
}

/* T.blockLabel: Montserrat 7 / 600 / 0.05em / lh 1, marginBottom 1 */
.ledger-cell .d {
  font-family: var(--sans);
  font-weight: 600;
  font-size: calc(7 * var(--s));
  letter-spacing: 0.05em;
  line-height: 1;
  margin-bottom: calc(1 * var(--s));
  color: #444444;
}

/* T.blockNum: Montserrat 14 / 700 / lh 1 */
.ledger-cell .n {
  font-family: var(--sans);
  font-weight: 700;
  font-size: calc(14 * var(--s));
  line-height: 1;
  color: #8a8a8a;
}

/* Finalised GREEN day. C.greenTile: two white sheen passes over #01C66D.
   The 126deg pass is the diagonal gloss, the vertical pass is the lift off
   the top edge. Both are percentage-based, so they scale with the block. */
.ledger-cell.green {
  background:
    linear-gradient(126deg, rgba(255, 255, 255, 0) 37%, rgba(255, 255, 255, 0.25) 45%, rgba(255, 255, 255, 0.25) 53%, rgba(255, 255, 255, 0) 61%),
    linear-gradient(rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 62%),
    #01c66d;
  /* C.greenTileBorder #E6FFF9 as the ring, then C.greenTileGlow: an inner
     light gathering just inside the rim, then three halo layers. */
  box-shadow:
    inset 0 0 0 calc(0.75 * var(--s)) #e6fff9,
    inset 0 0 calc(5.44 * var(--s)) rgba(146, 254, 229, 0.275),
    0 0 calc(1.81 * var(--s)) rgba(146, 254, 229, 1),
    0 0 calc(4.53 * var(--s)) rgba(146, 254, 229, 0.768),
    0 0 calc(9.97 * var(--s)) rgba(146, 254, 229, 0.32);
}

/* Finalised RED day. Built by the identical method so the pair are siblings:
   same face stack, same rim-toward-white move, same four-layer light. */
.ledger-cell.red {
  background:
    linear-gradient(126deg, rgba(255, 255, 255, 0) 37%, rgba(255, 255, 255, 0.25) 45%, rgba(255, 255, 255, 0.25) 53%, rgba(255, 255, 255, 0) 61%),
    linear-gradient(rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 62%),
    #ec211f;
  box-shadow:
    inset 0 0 0 calc(0.75 * var(--s)) #ffe6e5,
    inset 0 0 calc(5.44 * var(--s)) rgba(255, 81, 77, 0.275),
    0 0 calc(1.81 * var(--s)) rgba(255, 81, 77, 1),
    0 0 calc(4.53 * var(--s)) rgba(255, 81, 77, 0.768),
    0 0 calc(9.97 * var(--s)) rgba(255, 81, 77, 0.32);
}

/* TODAY, before the day has finalised. Same construction in grey so the
   active block is unmistakably the same OBJECT as a finalized one, just
   unlit. Ported for completeness; the strip on this page shows a finished
   30-day record, so nothing currently uses it. */
.ledger-cell.today {
  background:
    linear-gradient(126deg, rgba(255, 255, 255, 0) 37%, rgba(255, 255, 255, 0.25) 45%, rgba(255, 255, 255, 0.25) 53%, rgba(255, 255, 255, 0) 61%),
    linear-gradient(rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 62%),
    #3a3a3c;
  box-shadow:
    inset 0 0 0 calc(0.75 * var(--s)) #ababad,
    inset 0 0 calc(5.44 * var(--s)) rgba(150, 150, 152, 0.275),
    0 0 calc(1.81 * var(--s)) rgba(150, 150, 152, 1),
    0 0 calc(4.53 * var(--s)) rgba(150, 150, 152, 0.768),
    0 0 calc(9.97 * var(--s)) rgba(150, 150, 152, 0.32);
}

.ledger-cell.today .d {
  color: #888888;
}

.ledger-cell.today .n {
  color: #cccccc;
}

.ledger-cell.green .d,
.ledger-cell.green .n,
.ledger-cell.red .d,
.ledger-cell.red .n {
  color: #ffffff;
}

/* --------------------------------------------------------------------------
   BEFORE / AFTER LEDGER PHONES (Patrick, 10-09)

   Replaces the single wide ledger. The CRO template's photo cadence is
   product hero, then TRANSFORMATION, and "nothing sells like a before and
   after" - so the mechanism section now shows the same object in two states
   rather than one.

   Two things make this honest rather than a mockup. The ledgers inside are
   the REAL component, the same .ledger-cell rules the app's tokens were
   ported into, not a picture of one. And the "before" is the state the app
   actually shows on day one: day 1 lit grey (C.todayTile) and days 2 to 30
   as bare pending blocks, because those days have not happened yet.

   The device frame earns its place by answering a question the bare grid
   left open: a visitor could reasonably read a grid of coloured squares as
   an infographic. In a phone it is unmistakably a thing you open at night.
   -------------------------------------------------------------------------- */
.ledger-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 2.6vw, 32px);
  align-items: start;
  margin: clamp(30px, 3.2vw, 44px) auto 0;
  max-width: 100%;
}

.ledger-phone {
  margin: 0;
  min-width: 0;
}

/* The screenshots arrive already framed by phone_frame.py, with the case, the
   rounded screen and a transparent margin around a soft shadow. So there is no
   CSS device here any more: the asset IS the device, which also means the
   frame on the page and the frame in the Operating Manual are the same object
   rather than two things drifting apart. Alpha is kept rather than flattened
   onto black, so the same file drops onto the metal hero or a social card
   without a black rectangle around it. */
.ledger-phone picture,
.ledger-phone img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---- the captions ---------------------------------------------------------
   These are the app's own 30/30 treatment, not a caption style (Patrick,
   11-09). Every value is lifted from FinalLedger.tsx, which sets the Green Day
   Count at Montserrat 35px / weight 400 / line-height 1.1 in C.white, over the
   welcome wordmark's glow pushed up on Patrick's own call: 3px at 95%, 9px at
   55%, 18px at 16%.

   THE GLOW IS IN em, NOT px. Those three stops are authored for a 35px
   numeral, and this page runs the same numeral at up to 62px. Expressed as
   em (3/35 = 0.086, 9/35 = 0.257, 18/35 = 0.514) the halo scales with the
   glyph automatically, which is the derived multiplier the Build Lesson asks
   for rather than a guessed one.

   text-shadow, never a filter. A filter traces the DIV and paints a glowing
   rectangle; text-shadow traces each GLYPH. That is the exact bug the wordmark
   hit on Patrick's phone on 23-08-26.

   The is-after caption was #6cfed2. It is white now, because the app's 30/30
   IS white: green there is reserved for the completion RATE, and the contrast
   between the two phones is already carried by the screenshots themselves,
   one grey grid and one of thirty green tiles.
   --------------------------------------------------------------------------- */
.ledger-phone figcaption {
  margin-top: clamp(14px, 1.7vw, 24px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(3px, 0.4vw, 7px);
  text-align: center;
}

.lp-n {
  font-family: var(--sans);
  font-weight: 400;
  font-size: clamp(40px, 4.4vw, 62px);
  line-height: 1.1;
  color: #f2f5f7;
  /* Tabular figures, or the box changes width on every tick while it counts
     and the whole caption jitters sideways. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  text-shadow:
    0 0 0.086em rgba(242, 245, 247, 0.95),
    0 0 0.257em rgba(242, 245, 247, 0.55),
    0 0 0.514em rgba(242, 245, 247, 0.16);
}

/* The label sits ABOVE the number (Patrick, 11-09), which turns it from a
   caption into an eyebrow, so it is treated as one.

   TREATMENT 26 off day-styles.html, picked 11-09. Mono caps at 0.34em in the
   app's Green Day colour #02E8A3, and NO hairline rules: 26 is the bare
   typographic treatment recoloured, and the rules belong to 01. They come off
   with it rather than being kept as a silent extra.

   MONO, not the app's Montserrat. Inside the app that label is surrounded by
   app chrome and Montserrat is simply the UI face. Out here it is a lone word
   on black under a photograph, and this page already has a voice for that:
   .tw-date, the scarcity line and the old caption are all Space Mono.

   #02E8A3 is C.green, the colour tokens.ts puts behind "every piece of green
   text" in the app. It is NOT the ledger tile's #01C66D, which is a fill for
   blocks; this is text on black, and the app uses the one green for that. */
/* THE WORD "DAY" IS THE APP'S LABEL, NOT A MONO LABEL. Changed 15-09-26.

   Jay, 14-09: the word "day" uses "a font that hasn't really been incorporated
   into anything", and should be replaced with one already used and approved in
   the app, keeping the same treatment.

   The app writes this exact element in two places, FinalLedger.tsx and the
   challenge screen, both as `T.blockLabel`:

       fontFamily: Montserrat   fontSize: 7   fontWeight: 600
       letterSpacing: 0.05em    lineHeight: 1

   So the family, weight and tracking below are the app's values, not chosen
   ones. Space Mono DOES exist in the app, but for exactly one thing, the
   rolling timer in the top bar, so this label had borrowed the mono face for
   something the app itself sets in Montserrat. That is precisely the fault
   Jay named.

   Size and colour are left alone: "keeping the same treatment". */
.lp-l {
  font-family: var(--sans);
  font-weight: 600;
  /* 0.75vw, not 0.68: the numeral maxes out at 62px when 4.4vw reaches it,
     which is a 1409px viewport, and at 0.68vw the label was still climbing
     there and sat at 9.79px against the board's 10.5. Both now reach their
     ceiling at the same width, so the lockup's proportions stop moving at
     the same moment the number does. */
  font-size: clamp(8.5px, 0.75vw, 10.5px);
  /* THE APP'S TAGLINE, 15-09-26. It was the app's blockLabel (600 at 0.05em),
     which is the label inside a Ledger day block. Patrick has pointed at a
     different line in the app and asked for that one instead: the welcome
     eyebrow under the greeting, T.tagline, which is 400 at 0.2em.

     Both are Montserrat uppercase, so the face does not move. What moves is
     the weight, down one notch from 600, and the tracking, from 0.05em to
     0.2em. At this size that is the difference between a small bold word and
     a spaced-out system label, and the spaced one is what sits over "Day 1"
     inside the app.

     Size is NOT taken from the token. The app's 8px is fixed because it lives
     in a fixed phone layout; here the label is tied to a numeral that scales
     from 40px to 62px, and the clamp above is what keeps the two in
     proportion. Colour stays the Green Day #02E8A3 for the same reason: the
     app's tagline is white because it sits in app chrome, and this one is a
     lone word on black under a photograph.

     LEFT AT 0.2em ON PURPOSE, 15-09-26. Patrick read this as tighter than the
     app and it is not: the app's line was measured out of its own screenshot
     (brand/ledger-day-one.png, scale fixed by the Ledger title, which carries
     no tracking) and it paints 0.200em, the same value that is declared here.

     Why the two do not read the same anyway: tracking is only visible in the
     GAPS, and "DAY" has two of them where the app's line has thirty-two. The
     same value cannot show the same rhythm across three letters. If it is to
     LOOK like the app rather than measure like it, this has to go wider than
     the app, not equal to it. That is a decision for Patrick, not a bug to
     fix quietly, so the value stays on the app's number until he says
     otherwise. 0.34em is the one to reach for: it is what this label wore as
     treatment 26 on day-styles.html before it moved to the app's token. */
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #02e8a3;
  /* Letter-spacing is added after the LAST glyph too, so the word's BOX is
     0.34em wider than the word. Centring that box leaves the visible letters
     sitting half a letter-space left of the numeral below. Pulling the right
     edge back by exactly the trailing space makes the outer box equal the
     glyphs, so the two centre on each other. */
  /* Must equal the tracking above, negated. This cancels the letter-space
     added after the FINAL glyph, which otherwise makes the word's box wider
     than the word and throws it off-centre against the numeral. It moved from
     -0.34 to -0.05 to -0.2 with the tracking; the two are one value, not
     two. */
  margin-right: -0.2em;
}

/* ---- the count-up ---------------------------------------------------------
   PROGRESSIVE ENHANCEMENT. The real numbers are in the HTML and this is armed
   by script, so with no JS the captions simply read 1 and 30. The script zeroes
   them, hides them, and releases both when the pair scrolls into view.
   --------------------------------------------------------------------------- */
.ledger-pair.is-armed figcaption {
  opacity: 0;
}
.ledger-pair.is-armed .lp-n {
  transform: translateY(14px) scale(0.94);
}
.ledger-pair.is-armed .lp-l {
  transform: translateY(10px);
}

.ledger-pair.is-in figcaption {
  opacity: 1;
  transition: opacity 0.5s ease;
}
.ledger-pair.is-in .lp-n,
.ledger-pair.is-in .lp-l {
  transform: none;
  transition: transform 0.66s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Eyebrow first, number a beat behind it, so the lockup assembles downward
   the way it is read rather than arriving as one block. */
.ledger-pair.is-in .lp-n { transition-delay: 0.09s; }
/* The right-hand phone arrives a beat later, so the pair reads left to right
   rather than as one block appearing. */
.ledger-pair.is-in .is-after figcaption,
.ledger-pair.is-in .is-after .lp-n,
.ledger-pair.is-in .is-after .lp-l {
  transition-delay: 0.14s;
}

@media (prefers-reduced-motion: reduce) {
  .ledger-pair.is-armed figcaption { opacity: 1; }
  .ledger-pair.is-armed .lp-n,
  .ledger-pair.is-armed .lp-l { transform: none; }
}

/* Below this the two phones are so narrow that the DAY label inside each
   block stops being legible. The label is dropped rather than the layout
   changed, because stacking them would destroy the comparison, which is the
   entire point of the pair. */
@media (max-width: 560px) {
  .ledger-pair .ledger-cell .d {
    display: none;
  }
}


/* --------------------------------------------------------------------------
   Results
   -------------------------------------------------------------------------- */
/* THE RESULTS ARE NOT CARDS ANY MORE. Unboxed 14-09-26.

   They were nine rounded rectangles with a white outline and a four-layer
   glow, and on a black page that made them the loudest thing on it: you
   registered the containers before you could read the outcomes. These nine
   lines are Jay's most persuasive content and they were wrapped in furniture.

   EVERY WORD IS UNCHANGED. What is gone is the background, the border, the
   radius, the padding and the glow, plus two things that existed only to
   serve the boxes: `grid-auto-rows: 1fr`, which forced every row to the height
   of its tallest card so the boxes would line up, and `height: 100%` on the
   item, which filled that cell. With no box to line up, equal rows only padded
   the short entries with empty space.

   Spacing groups them now, so the gap goes from 13px to about 32. Column
   counts are untouched: one on a phone, two from 1000px, three above 1900.
   -------------------------------------------------------------------------- */
.results {
  list-style: none;
  margin: clamp(26px, 2.8vw, 38px) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(26px, 2.2vw, 32px);
}

/* THE LINE IS NOT BOLD. THE LEAD-IN PHRASE IS. Corrected 15-09-26.

   A first pass set the whole li to 700, reading the note's "bold all eight
   outcome lines" as the whole sentence. The transcript says otherwise: Jay
   reads out the OPENING PHRASE of each line and says "bold" after each one,
   eight times. "900 minutes of focused high-impact work bold. 900 minutes of
   physical training completed bold. A significant reduction in procrastination
   bold..." The emphasis is a lead-in, not a line.

   The phrases are marked up in index.html, so this rule holds the body weight
   and nothing else. */
.results li {
  position: relative;
  margin: 0;
  padding-left: 30px;
  /* THE SAME SIZE AS THE BODY COPY, 14-09-26.

     These were 15.5px flat with 1.62 leading, inherited from when they were
     cards: inside a box, slightly smaller and tighter text is right, because
     the box supplies the grouping and the density reads as deliberate. Out in
     the open column they are simply body copy in list form, and being smaller
     than the paragraph directly above says "less important than that" about
     the nine outcomes the whole page is selling.

     The flat value was the worse half of it. Body copy is clamped 16 to 18, so
     the two matched within half a pixel at 1440 and drifted to 2.5px apart at
     1920: the mismatch grew with the screen and only showed on a big monitor.
     Same clamp, same leading, one voice in the column. The list structure does
     the differentiating now, which is what it is for. */
  /* 14 on phone (Patrick, 15-09-26). The bold lead-ins and the green 30/30
     inherit this, so all three move together. */
  font-size: clamp(14px, 0.95vw, 16px);
  line-height: 1.72;
  color: var(--ink-soft);
}

/* THE MARKER IS THE APP'S GREEN DAY LEDGER CELL. Treatment 29, 14-09-26.

   Not white, deliberately, and Patrick made that call knowing it. Green is
   this brand's single yes / on / complete signal: it is the Green Day Count,
   the ticks, the toggles and every card stripe in the app. Spending it on the
   results list says these nine things are completed days rather than promises,
   which is the strongest available reading, and it is also the only place on
   this page that spends it.

   EVERY VALUE IS READ OUT OF THE APP, NOT REMEMBERED. From
   blvckos-app/src/lib/tokens.ts: greenTile (two white sheen passes over
   #01C66D), greenTileBorder #E6FFF9, greenTileGlow, tileRing 0.75px,
   tileRadius 0. The board version of this treatment carried glow numbers I
   had guessed, and they were wrong.

   THE LIGHT IS DERIVED, NOT GUESSED. The app's glow is authored for its
   SHIPPED 29px ledger block, so at 12px every radius is multiplied by 12/29 =
   0.4138: inset 5.44 -> 2.25, then 1.81 -> 0.75, 4.53 -> 1.87, 9.97 -> 4.13.
   Guessing instead of deriving is what made an earlier reuse of this block
   bloom about 30% hot and read as gamer RGB.

   THE RIM IS AN INSET RING, NOT A BORDER, for the app's own reason: 0.75px
   scaled to 12px is 0.31px, and box-shadow spread takes sub-pixel values
   where border-width does not. Chrome floors a 0.31px border to zero.

   Square corners per Jay's 20-08 lock, which tileRadius: 0 still carries. */
/* THE BARE TICK. Option 09 off ledger-ticks.html, Patrick 15-09-26.
   Replaces the filled ledger cell, which Jay called out on 14-09: "the green
   square reads as a square, not as a ledger day... I understand the logic but
   it just looks like a square."

   THE MARK IS THE APP'S, NOT A NEW ONE. The path, stroke weight and round caps
   below are copied from blvckos-app/src/components/ui/Badge.tsx, where the app
   draws a completed Directive and the Complete badge:

       viewBox 0 0 13 13   M3 7l2.5 2.5L10.5 4   stroke-width 1.8

   #02E8A3 is the app's on-black green, deliberately NOT the ledger block's
   #01C66D. The block colour is a FILL and this is a stroke on black, which is
   the same distinction FinalLedger.tsx makes: "the app has one green for
   everything that sits on black: the ticks, the toggles, the card stripes".

   THE GLOW IS A drop-shadow, NOT A box-shadow, and that is the whole reason
   this option works. A box-shadow draws around the element's BOX, so on a
   transparent box it paints a rectangular halo with a hole in the middle, the
   exact fault that made the light-only marker read as a hollow ring on 14-09.
   A drop-shadow follows the rendered alpha, so it traces the two strokes of
   the tick and nothing else.

   The SVG is inline as a data URI rather than a file so there is no second
   request and no chance of a missing asset leaving the list unmarked. */
.results li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.3em;
  width: 16px;
  height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 13' fill='none'%3E%3Cpath d='M3 7l2.5 2.5L10.5 4' stroke='%2302E8A3' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / contain;
  filter:
    drop-shadow(0 0 2px rgba(146, 254, 229, 0.85))
    drop-shadow(0 0 5px rgba(146, 254, 229, 0.35));
}

/* SMALLER ON A PHONE, 14-09-26. Patrick: the square looks bigger there.

   It was not bigger. Measured, the marker is 12px at EVERY width; what
   changes is the column it sits in. At 12px it is 1.96% of the line at 1440
   and 3.11% on a 430 phone, 3.47% on a 390, so it takes up around 60 to 77%
   more of the line on a phone while being the identical number of pixels.
   That is the whole effect, and the fix is proportional too: 12 to 9 brings
   it to 2.33% on a 430, which sits between the two desktop cases.

   THE LIGHT IS RE-DERIVED, not reused. Dropping the box and keeping the old
   halo is exactly the mistake the 12px version already corrected: the app's
   glow is authored for a 29px block, so at 9px the multiplier is 9/29 =
   0.3103 and every radius moves with it. Reusing the 12px numbers on a 9px
   tile would leave the halo a third too wide for its own face.

   AFTER the base rule, never with the other phone overrides higher up this
   file. The video bleed was written there and silently did nothing, because
   equal specificity plus later source order meant the base won. */
@media (max-width: 640px) {
  .results li {
    padding-left: 26px;
  }

  /* The tick does NOT shrink on a phone the way the filled cell did. A cell is
     a block of colour and reads at 9px; a two-stroke mark at 9px is a smudge.
     16px is the size it was judged at on the board, at 430 wide, against the
     same 14px copy. Only the glow comes in, because a phone is an OLED and a
     wide low-alpha spread lights pixels that are otherwise fully off. */
  .results li::before {
    width: 16px;
    height: 16px;
    top: 0.26em;
    filter:
      drop-shadow(0 0 1.5px rgba(146, 254, 229, 0.85))
      drop-shadow(0 0 4px rgba(146, 254, 229, 0.3));
  }
}/* Jay's numbers: emphasis via weight in the body face, single ink colour
   (Patrick 05-08, replacing the teal glowing mono which clashed mid-sentence.
   Teal stays reserved for actions and the hover spotlight). */
.results .n {
  font-weight: 800;
  font-size: 1.08em;
  color: var(--ink);
  letter-spacing: -0.01em;
}

/* The phrases Patrick called out, 11-09. Bold and white, nothing else: the
   size is deliberately left alone so a bolded phrase does not also become a
   different size mid-sentence. */
.results strong {
  font-weight: 700;
  color: var(--ink);
}

/* The only coloured words in the section, and it is the app's Green Day
   colour rather than the page accent: tokens.ts calls #02E8A3 the green
   behind "every piece of green text".

   Narrowed to the SCORE alone (Patrick, 11-09). "Green Day record" names the
   thing; "30/30" is the claim, and colouring the whole phrase spent the
   emphasis on the noun instead of the number. Nested inside the <strong> so
   the full phrase stays bold either way, which makes green-or-white a
   one-line change rather than a markup change. */
.results .gd {
  color: #02e8a3;
}

.tier {
  font-weight: 700;
  color: var(--ink);
}

.tier-vanta {
  font-weight: 700;
  color: var(--ink);
  text-shadow: 0 0 14px rgba(255, 255, 255, 0.5);
}

/* --------------------------------------------------------------------------
   Testimonials: two-row marquee, top row drifting left, bottom row drifting
   right, edge-faded (Patrick's reference, 05-08). The card content in here is
   FABRICATED PLACEHOLDER DATA generated by the script in index.html so
   Patrick can judge the layout. IT MUST NOT GO LIVE: swap in real
   testimonials before deploy. Because the cards are script-generated, the
   copy checker (which reads the static HTML) stays clean.
   -------------------------------------------------------------------------- */
.t-marquee {
  margin-top: clamp(26px, 2.8vw, 38px);
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}

.t-row {
  display: flex;
  width: max-content;
}

.t-row .t-card {
  margin-right: 14px;
}

.t-left {
  animation: tml 48s linear infinite;
}

.t-right {
  animation: tmr 56s linear infinite;
}

@keyframes tml {
  to {
    transform: translateX(-50%);
  }
}

@keyframes tmr {
  from {
    transform: translateX(-50%);
  }
  to {
    transform: translateX(0);
  }
}

.t-marquee:hover .t-row {
  animation-play-state: paused;
}

.t-card {
  flex: 0 0 auto;
  width: 320px;
  background: #0c0c0d;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 12px;
  padding: 15px 17px;
}

.t-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.t-id {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.t-ava {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 12px;
  color: #e6ebe9;
  flex: 0 0 auto;
}

.t-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.25;
}

.t-handle {
  font-size: 11px;
  color: var(--ink-dim);
  line-height: 1.3;
}

.t-rate {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  flex: 0 0 auto;
}

.t-rate svg {
  width: 14px;
  height: 14px;
  fill: #ffc83d;
}

.t-quote {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* --------------------------------------------------------------------------
   Decision (final)
   -------------------------------------------------------------------------- */
.decision {
  text-align: center;
  /* Was a teal radial wash rising from the bottom. Removed with the rest of
     the section colouring: pure black everywhere, and it was the last teal
     left behind a CTA that is now white. */
  background: var(--bg);
  padding-bottom: clamp(70px, 7vw, 120px);
}

.decision h2 {
  font-size: clamp(21px, 5.2vw, 30px);
}

/* Left aligned, Patrick 10-09. The section was centred, which on a five
   paragraph run makes every line start in a different place and gives the eye
   no edge to return to. Only the copy moves: .cta-block carries its own
   text-align: center, so the button and the free line under it stay centred
   without needing to be told again.

   The accent rule above the heading has to be un-centred separately. It is
   set to auto margins by the shared `.decision h2::before, .hero h2::before`
   rule earlier in this file; this overrides it at equal specificity on source
   order rather than editing that shared rule, so the hero is untouched. */
.decision {
  text-align: left;
}

.foot {
  /* LEFT, NOT CENTRED, and padded to the content column (Jay, 14-09-26: the
     footer logo "small and tucked away as opposed to a feature").

     This is the SECOND `.foot` rule in the file. An earlier one near the
     wordmark declarations set the same two properties and did nothing, because
     this block re-declares the `padding` SHORTHAND, which resets left and
     right to 0, and re-declares text-align, and wins on source order at equal
     specificity. The mark sat at x=0, hard against the screen edge, instead of
     on the 24px column. Same trap as the phone video bleed on 14-09.

     24px matches the hero column exactly, so the page opens and closes with
     the mark on the same line. */
  padding: 32px 24px 44px;
  text-align: left;
  /* RESTORED. This was removed this morning because the lifted ground above
     it marked the boundary; that ground is gone, and the footer is the one
     block on the page with no heading and therefore no rule of its own, so
     without this it simply runs on from the close. */
  border-top: 1px solid var(--hair);
}

.foot .wordmark {
  opacity: 0.45;
}

/* THE LEGAL ROW. Rebuilt 15-09-26 as option C: a copyright line with the two
   links inside it, rather than two links standing on their own.

   The first version was Space Mono caps at 12px with an underline under each
   link. Two things were wrong with it and both worked against the job.

   Mono caps is a DISPLAY treatment on this page: mono is the system-label
   voice, the ledger stamps and the timer, so setting the legal links in it
   made them read as something deliberate rather than as small print. And two
   underlined links sitting alone under the mark read as NAVIGATION, because
   nothing in that row tells you they are boilerplate.

   A copyright line fixes the second problem structurally rather than
   cosmetically. Once the links sit inside a legal string they stop being two
   items on their own and become part of the fine print, which is exactly what
   Patrick asked for: findable, not inviting.

   Everything else is the quiet end of every value on the page. Montserrat 400
   against the body's own face. 11px, under the smallest body size. Sentence
   case, because uppercase plus tracking is what made the old one shout.
   0.32 white, which is dimmer than the body copy's 0.82 and dimmer than the
   wordmark's 0.45 above it, so the eye reaches the mark first and stops. */
.foot-legal {
  margin: 20px 0 0;
  font-family: var(--sans);
  font-weight: 400;
  font-size: 11px;
  line-height: 1.8;
  color: rgba(255, 255, 255, 0.32);
  /* A WRAPPING FLEX LINE, not a run of inline text. The three items are
     written with no whitespace between them in the markup so the separator's
     own margins control the spacing instead of a stray word space, and no
     whitespace means inline layout has nowhere to break: at 320 the row ran
     43px past its own container rather than wrapping.

     Flex gives the break opportunity by structure, so it cannot be removed by
     someone tidying the HTML. The row-gap only shows on a narrow screen where
     the row actually takes two lines. */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  row-gap: 3px;
}

.foot-legal a {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s ease;
  /* THE TAP BOX, NOT THE TYPE. At 11px the hit area was 14px tall, which is
     a hard target on a phone. The padding grows it and the equal negative
     margin takes the layout cost back out, so the row looks identical and the
     box is twice the height. The type is meant to be quiet, not unreachable. */
  padding: 7px 0;
  margin: -7px 0;
}

/* The separator is drawn by CSS rather than typed into the markup, so a link
   can be added or removed without leaving a stray middot behind, and so the
   dot can be dimmer than the words it separates.

   AFTER, not before, and every item nowrap. At 360 the row ran out of width
   and broke inside "Terms of Use", leaving "Use" alone on a second line.
   nowrap means a break can now only fall BETWEEN items; putting the dot on
   the item before it means a wrapped line starts on a word rather than on a
   floating middot. Same dots on screen, different break behaviour. */
.foot-legal > * {
  white-space: nowrap;
}

.foot-legal > *:not(:last-child)::after {
  content: "·";
  margin: 0 9px;
  color: rgba(255, 255, 255, 0.18);
}

/* HOVER ONLY ON A REAL POINTER. A touch device synthesises hover on tap and
   then leaves it applied, so an underline here would stick on after a tap and
   read as a fault. Same guard the testimonial Show more button needed. */
@media (hover: hover) and (pointer: fine) {
  .foot-legal a:hover {
    color: rgba(255, 255, 255, 0.7);
  }
}

/* Keyboard focus is NOT a hover and must always show, on every device. */
.foot-legal a:focus-visible {
  color: rgba(255, 255, 255, 0.9);
  outline: 2px solid var(--teal);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .foot-legal a {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   Entrance motion: TQW spec (opacity + translateY(14px), ~.5s,
   cubic-bezier(.2,.7,.2,1)). Content entrance only, no layout animation.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.55s cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1);
  will-change: opacity, transform;
}

.reveal.in {
  opacity: 1;
  transform: none;
}

/* --------------------------------------------------------------------------
   Desktop
   -------------------------------------------------------------------------- */
@media (min-width: 760px) {
  body {
    font-size: 18px;
  }

  /* NO MULTI-COLUMN. A list reads top to bottom.

     This was two columns as cards and stayed two columns unboxed, but without
     boxes the reading order stops being obvious: the eye cannot tell whether
     item two is below item one or beside it. Nine outcomes in one column is
     longer and unambiguous, and it is what the rest of the page already does.

     NO max-width EITHER. A 62ch measure cap was tried here and it was wrong:
     at 1920 it held the list to 739px while the body copy above it ran 815,
     so every bullet broke 90px short of the paragraphs and the section looked
     truncated. It did not show up at 1440, where the cap is wider than the
     column and never bites, which is exactly why it shipped. The list matches
     the copy column at every width now. */
}


/* --------------------------------------------------------------------------
   One-screen hero (Patrick 05-08): on desktop the whole hero, wordmark down
   to the scarcity line, must fit 100dvh with no scrolling, exactly like the
   TQW landing. TQW achieves it by budgeting every vertical step in design
   pixels on its locked 2558x1304 canvas; same discipline here. The steps
   below sum to ~1286 design px, inside the 1304 canvas, so the hero fits at
   every desktop size by construction. Hero-scoped so the mid-page and
   closing CTA blocks keep their own rhythm.
   -------------------------------------------------------------------------- */
@media (min-width: 641px) {
  .hero {
    /* Bottom to zero: the divider below owns that air now. See the base rule. */
    padding: calc(14 * var(--u)) 0 0;
  }

  .wordmark-hero {
    width: calc(368 * var(--u));
    /* Desktop keeps the original glow exactly. Only the phone mark shrank. */
    filter:
      drop-shadow(0 0 16px rgba(255, 255, 255, 0.42))
      drop-shadow(0 0 44px rgba(255, 255, 255, 0.2));
  }

  h1 {
    font-size: calc(44 * var(--u));
    margin-top: calc(12 * var(--u));
  }

  .hero-sub {
    font-size: calc(20 * var(--u));
    margin-top: calc(16 * var(--u));
  }

  .hero-purpose {
    font-size: calc(19 * var(--u));
    margin-top: calc(16 * var(--u));
  }

  .hero .video {
    margin-top: calc(26 * var(--u));
  }

  .hero .cta-block {
    /* Was calc(56 * var(--u)), TQW's canvas gap. That made the hero the only
       CTA on the page whose spacing scaled with the canvas unit while the
       other two sat on the shared clamp, so it measured 32px against their
       40px on a 1440 laptop. Same clamp as the mid-page and closing CTAs now,
       so all three match at every width. */
    margin-top: clamp(24px, 2.8vw, 40px);
  }

  .hero .tagline {
    margin-top: calc(14 * var(--u));
  }

  .hero .scarcity {
    /* Vertical budget only. The font-size and max-width overrides that used
       to live here made the hero's free line a different size from the two
       below it: calc(16 * var(--u)) is 9px on a 1440 laptop, against the
       shared clamp's 16px. One sentence, one style, everywhere. */
    margin-top: calc(12 * var(--u));
  }
}


/* The h1 break is desktop-authored (Patrick 05-08). Phones wrap naturally. */
@media (max-width: 640px) {
  h1 br {
    display: none;
  }

  /* The hero's top padding is a clamp FLOOR, not a chosen phone value:
     clamp(42px, 5vw, 84px) only ever resolves to 42 below 840px wide, because
     5vw at 390px is 19.5. So the number a phone gets was picked by looking at
     a desktop window. It then lands UNDER Safari's 47px status bar, which put
     89px of a 664px screen above the wordmark before anything had been read.
     Measured 11-09; the hero is already 868px tall in that 664px viewport, so
     every pixel here is one the CTA needs. */
  .hero {
    padding-top: 14px;
  }

  /* THE PHONE REDUCTION SURVIVES, ITS STATED MECHANISM DOES NOT (17-09-26).

     The rule from 11-09 was that the radii come in and the alphas stay, because
     on an OLED it is the spread that boxes. That held while the glow was one
     wide low-alpha wash. It does not survive the near-field layer added above:
     radii at 0.75 / 0.65 / 0.55 / 0.45 of desktop with the alphas held all
     measured MORE total fog in the headline box than ships today
     (12.43 / 11.71 / 10.23 / 8.83 against 8.75) while the hottest 1 percent of
     pixels climbed 27 -> 43 -> 48 -> 52 -> 53. Radius alone cannot contain a
     bright tight layer, because its light lands in the counters and the gaps
     between letters, which is precisely where the box forms.

     So here the radii come to 0.70x AND the two outer alphas come down 25%.
     The 0.05em rim holds its 0.85 on both breakpoints: it is the layer Jay is
     asking for and it is the cheapest one there is in fog terms.

     THE NET IS LESS LIGHT THAN TODAY, mean 7.69 against 8.75, while the letter
     edge goes from 21.5 to 68.9. Brighter edge, dimmer page. That is why this
     is safe on the device that bloomed on 11-09, and it should still be looked
     at on the real phone rather than trusted from here. */
  h1 {
    /* DOUBLED with the desktop rule above, 17-09-26. The phone reduction still
       holds: these radii are 0.70x the desktop ones and the two outer alphas
       sit under them, same relationship as before. The h2 below is untouched,
       so the sub-headings are now half the headline rather than equal to it. */
    text-shadow:
      0 0 0.10em rgba(255, 255, 255, 1),
      0 0 0.44em rgba(255, 255, 255, 0.45),
      0 0 0.85em rgba(255, 255, 255, 0.24);
  }

  /* ---- the hero's vertical budget ---------------------------------------
     Every gap below was the FLOOR of a clamp whose middle term never engages
     on a phone, so each one was a number chosen while looking at a desktop
     window. Together they were 134px of air in a 745px viewport.

     Measured before this: the CTA's bottom edge landed at 744 against a fold
     at 745. One pixel. And the "100% free. No payment required. Ever." line
     under it ran to 807, so 62px of the risk reversal was cut off entirely.
     A button one pixel from the edge is not a margin, it is luck: anyone with
     slightly more browser chrome than Patrick loses the bottom of it.

     Nothing changes size here, only the space between things, which is why
     this was the lever to pull first. 44px comes out of the gaps:
       hero top   24 -> 14      purpose to video  24 -> 16
       mark to h1 22 -> 14      video to CTA      24 -> 16
       h1 to sub  14 -> 10      CTA to scarcity   12 -> 10
       sub to purpose 14 -> 10
     -------------------------------------------------------------------- */
  h1 {
    margin-top: 14px;
  }

  .hero-sub {
    margin-top: 10px;
  }

  .hero-purpose {
    margin-top: 10px;
  }

  .hero .video {
    margin-top: 16px;
  }

  .hero .cta-block {
    margin-top: 16px;
  }

  .cta-block .scarcity {
    margin-top: 10px;
    /* NARROWER THAN THE BUTTON, and scaled so it stays that way.

       At 15px the line rendered 385.5px wide against a 320px button, 120% of
       it, which is why it overhung. On desktop the same line is 411 against a
       394 button, 104%, close enough to read as matching, and that is the
       relationship Patrick was pointing at.

       calc(12 * --up) is what the TQW landing page uses for its own .below
       line, and it is also what the measurement lands on independently: 308px
       of text inside a 320px button, 96%. Both terms scale on the same unit,
       so the text stays 96% of the button at every phone width rather than
       only at 430. A flat 12px would go back to overhanging at 390, where the
       button is 290 and the text would still be 308.

       It also stays on ONE line, which is what keeps the risk reversal above
       the fold. */
    font-size: calc(12 * var(--up));
  }
}


/* --------------------------------------------------------------------------
   PHONE HERO, MATCHED TO JAY'S AFFINITY WIREFRAME (14-09-26)

   Source drawing: ECOSYSTEM/2 - BLVCKOS/2 - IMAGES/3 - MARKETING/2 - Landing Pages/BLVCKOS LANDING PAGE/BLVCKOS LANDING PAGE PHONE/BLVCKOS LANDING PAGE WIREFRAME PHONE.png

   It is drawn at 430 CSS px, which is exactly what --up normalises to, so the
   numbers below are read off the drawing rather than converted. Measured as
   ink bands, CSS px from the top of the page content:

     wordmark  ink top 4.7,  ink width 94.3, flush left
     h1        ink 70.7-97.0 and 102.7-129.3, so 32px apart, TWO lines
     hero-sub  ink 152.0 and 170.0, 18px apart
     purpose   ink 209.7 / 227.7 / 245.7, 18px apart, heavier
     video     top 288.7, 382 x 237
     CTA       band top 559, 314.3 x 45.3, centred
     scarcity  ink top 637.7, centred

   FONT SIZES ARE DERIVED, NOT GUESSED. The live page was measured first to get
   each element's ink-height-to-font-size ratio (h1 1.005, sub 0.953, purpose
   0.98, scarcity 0.975), then the wireframe's ink heights were divided back
   through it. That is why they are not round numbers.

   THE VIDEO IS THE SAME LOCKED SHAPE, NOT A NEW ONE. 382/237 is 1.612 and the
   current 410/254 is 1.614, so the drawing keeps TQW's box and simply insets
   it to the text column instead of bleeding it past the edges.

   THE HERO GOES LEFT-ALIGNED, except the CTA block which stays centred. Every
   section below the hero was already left, so this is the hero catching up.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .hero {
    text-align: left;
    padding-top: 0;

    /* THE HERO FILLS THE VISIBLE SCREEN, 15-09-26 (Patrick: "ideally we do not
       see the divider there on the hero section without having to scroll",
       and the space above and below should match).

       svh, NOT vh. On a phone 100vh is the LARGE viewport, the height with the
       browser chrome hidden, so it overshoots by however much chrome is on
       screen and pushes the CTA under the fold. 100svh is the SMALL viewport,
       the height while the chrome IS showing, which is the state the page
       loads in and therefore the only one the first impression happens in.
       Measured on Patrick's own 14 Pro Max in Chrome iOS: 109px of chrome on
       top, 78 underneath, 745 left over.

       justify-content does the spacing, not two hand-set paddings. The block
       is centred, so the gap above it and the gap below it are equal by
       construction and stay equal on every phone whatever its chrome costs.
       Before this the hero was 651 tall in that 745 band: zero above, 94
       below, and the divider landed at 711, inside the fold. */
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* Positioning context for the wordmark, which is absolute at top 5px.
       Without this it would resolve against the initial containing block and
       scroll away with the page. */
    position: relative;
  }

  /* 24px a side, not the 22 the rest of the page uses, because that is what is
     drawn. Scoped to the hero so no other section moves. It also lands three
     other targets at once: the wordmark and the copy start at 24, and the
     video becomes exactly the drawn 382 x 237. */
  .hero .wrap {
    width: min(var(--media-w), calc(100vw - 48px));
  }

  /* Block, not inline: an inline img sits on a text baseline and carries the
     line-box leading with it, which is invisible space above the mark. */
  .wordmark-hero {
    display: block;
    width: calc(100 * var(--up));
    /* OUT OF FLOW, 5px BELOW THE BROWSER CHROME (Patrick, 15-09-26).

       "Imagine that is not there when we take into account the spacing." The
       mark is parked against the top of the viewport and takes part in NO
       vertical maths: the hero is balanced on the heading-to-scarcity block
       alone, so moving the logo cannot push anything and cannot unbalance the
       gaps. It was in flow until now, which is why nudging it 3px moved the
       whole block.

       The left offset reproduces the wrap's own left edge rather than
       hardcoding 24px: the wrap is width min(--media-w, 100vw - 48px) centred,
       so its left edge is half the leftover. Hardcoding would drift the moment
       --media-w wins the min(), which it does above 458px wide. */
    position: absolute;
    /* 10px, down from 5 (Patrick, 15-09-26). Out of flow, so this moves the
       mark alone and the heading-to-scarcity balance is untouched. */
    top: 10px;
    left: calc((100% - min(var(--media-w), 100vw - 48px)) / 2);
    margin: 0;
  }

  /* --------------------------------------------------------------------
     THE FOLD CUE. Jay, 21-09-26: "in the empty space between the bottom
     text and the fold, a small down arrow to signal there is more below",
     for the least attentive visitor. Picked off arrow-styles.html, which
     carried thirty candidates; this is 08, ARROW PROPER.

     THE MIRROR OF THE WORDMARK ABOVE, and for the same reason. The hero is
     min-height:100svh with its block centred, so the gaps above and below
     are equal by construction (measured 84.1 and 84.1 on a 14 Pro Max).
     Anything placed IN that flow joins the centred block and destroys the
     symmetry. Absolute takes part in no vertical maths, exactly as the
     comment on .wordmark-hero says: "moving the logo cannot push anything
     and cannot unbalance the gaps."

     PHONE ONLY, and that is measured rather than assumed. At 1440x900 the
     next heading already sits 127px ABOVE the fold and at 1920x1080 it is
     88px, so a desktop visibly continues on its own and a cue there would
     answer a question nobody is asking. The element is turned OFF in the
     base stylesheet and switched on here; see the note on that rule for why
     leaving it unstyled is not the same thing.

     pointer-events:none because it is a hint and not a control. It must
     never swallow a tap meant for the CTA sitting above it.
     -------------------------------------------------------------------- */
  .fold-cue {
    display: flex;
    position: absolute;
    left: 0;
    right: 0;
    /* 10px off the bottom edge (Patrick, 22-09-26), clearing a home bar
       rather than hiding under one. On a 14 Pro Max that leaves 52px of air
       between the scarcity line and the arrow. */
    bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
    justify-content: center;
    pointer-events: none;
    color: rgba(255, 255, 255, 0.28);
    transition: opacity 0.3s ease-out;
  }

  /* IT LEAVES WHEN THE NEXT HEADING ARRIVES, AND NEVER COMES BACK.

     Not decoration: the cue is absolute inside the hero, so scrolling does
     NOT take it away. Measured on a 430x745 phone with the arrow in place,
     it stays on screen through 735px of scrolling and rides up over "Be
     honest, does this sound familiar?", pointing down at a section the
     reader is already inside. So hiding it is a correctness fix.

     The trigger is that heading entering the viewport (Patrick's call, and
     the observer is in index.html). Measured in WebKit on the live page:
     105px of scroll on a 430x745, 105 on a 393x660, 75 on a 414x715, so
     roughly a tenth to a sixth of a screen. A deliberate scroll fires it and
     a thumb twitch does not. One way only, because a cue that returned every
     time the page moved back up would flicker. */
  .hero.cue-gone .fold-cue { opacity: 0; }

  @media (prefers-reduced-motion: reduce) {
    .fold-cue { transition: none; }
  }

  /* NOT ON A SHORT PHONE. There is 19px of room between the scarcity line
     and the fold on a 375x553 SE, against the 84 a 14 Pro Max has, and the
     arrow is 22px tall: it would sit ON the text. Shrinking it does not
     rescue this, which was measured too, since even a 13px version is still
     4px over. A screen that short is already showing the CTA hard against
     the fold, which is the job this element exists to do, so it stands down
     instead of being squeezed. */
  @media (max-height: 620px) {
    .fold-cue { display: none; }
  }

  /* 25.1, not the 26.5 the ink-height ratio implied. "Stop breaking your word
     and" needs ~398px at 26.5 inside a 386px column, so "and" wrapped to its
     own line BEFORE the intended break could fire, giving three lines. The
     drawing has that line 377px wide, so width is the binding constraint and
     the size comes from it. Costs ~1px of ink height against the drawing,
     which is invisible; a wrapped headline is not. Tracking is left at the
     locked -0.02em rather than tightened to buy the difference back. */
  h1 {
    /* 27, up from 25.1 (Patrick, 17-09-26, off Jay's 16-09 note: the headline
       "just looks too flat", bigger and glowier). PHONE ONLY, desktop is not
       touched.

       THE LINE BREAK HAD TO MOVE WITH IT, see index.html. The comment below
       records that 26.5 was rejected in the wireframe pass because "Stop
       breaking your word and" no longer fitted and "and" wrapped to a line of
       its own. Measured at 27 before changing anything: three lines at EVERY
       phone width, with "and" alone on a 53px line at 430. Moving the phone
       break one word earlier, to after "word", puts it back to two clean lines
       from 360 up. Jay's words are untouched; only where the line turns moved.

       320px is the one exception and it goes to three lines there, breaking
       after "wasting". That is an iPhone SE 1 and the break is between whole
       words rather than stranding one, so it is left rather than special-cased.

       Leading holds the same 1.275 ratio 32/25.1 had. */
    font-size: calc(27 * var(--up));
    line-height: calc(34.4 * var(--up));
    /* ZERO, 15-09-26. This was 41px of clearance under the logo, which only
       made sense while the logo was in flow. It is now absolutely positioned,
       so this margin would sit at the TOP of the centred block and make the
       measured gap above the heading 41px larger than the gap below the
       scarcity line, which is exactly the balance being asked for. */
    margin-top: 0;
  }

  /* The drawing breaks after "and", not after "wasting". Desktop keeps its own
     break, so the two are separate elements toggled by width rather than one
     element moved. */
  h1 br.br-sm {
    display: inline;
  }

  h1 br.br-lg {
    display: none;
  }

  .hero-sub {
    font-size: calc(13.6 * var(--up));
    line-height: calc(18 * var(--up));
    margin-top: calc(18 * var(--up));
  }

  .hero-purpose {
    font-size: calc(11.5 * var(--up));
    line-height: calc(18 * var(--up));
    font-weight: 700;
    margin-top: calc(22 * var(--up));
  }

  /* Inset to the text column and cancel the bleed-out. Height follows the
     locked 1.6142 ratio from the width, so the shape cannot drift. */
  .hero .video {
    margin-left: 0;
    margin-right: 0;
    margin-top: calc(28 * var(--up));
    width: 100%;
    height: auto;
    aspect-ratio: 1113 / 690;
  }

  /* THE FIRST DIVIDER TAKES NO MARGIN OF ITS OWN (Patrick, 15-09-26: make the
     first divider match the others).

     Everywhere else the divider supplies both sides of its gap. After the hero
     it cannot, because the hero is min-height 100svh with its block centred,
     so it ALREADY ends in balance space. Measured on a 745 viewport: the
     scarcity line ends at 669, the hero box at 745, and the divider then added
     60 more and landed at 805. Gap above: 136, against 63 everywhere else.

     Zeroing the margin makes the hero trailing space the whole gap, 76px, so
     the spread drops from 73px out to 13px out.

     AND IT PARKS THE DIVIDER EXACTLY ON THE FOLD, on every phone rather than
     on Patrick's. The hero is 100svh, so its bottom edge IS the bottom of the
     visible area by definition; a divider sitting flush to that edge is the
     first row below the fold whatever the browser chrome costs. A fixed margin
     could only ever be right on one device.

     Desktop is untouched: the hero is not svh there and has no trailing space,
     so the divider still needs its full margin. */
  body.lp > section:first-of-type h2::before {
    /* TOP UP THE HERO'S TAIL TO A FULL GAP, 15-09-26 (Patrick: "more space
       below than above the divider" on the first one).

       --hero-tail is written by a measuring script at the end of index.html:
       the distance from the hero's last line to the hero's own bottom edge,
       which is the air this divider already has above it for free. This rule
       adds only what is missing, so the top gap equals --divider-space like
       every other divider, on any device height rather than on one.

       max() with 0 because a tall screen can leave MORE tail than a full gap
       (169px at 430x932). Taking the difference there would be negative, and
       a negative margin would lift the divider back above the fold, which is
       the one thing Patrick ruled out: "ideally we don't see the divider on
       the hero section without having to scroll".

       The fallback makes a no-JS visit behave exactly as it did before this
       change: var(--hero-tail, --divider-space) resolves to the full gap, the
       subtraction is 0, and the divider sits flush to the hero bottom. */
    margin-top: max(0px, calc(var(--divider-space) - var(--hero-tail, var(--divider-space))));
  }

  /* SECTION HEADINGS BECOME THE HERO HEADLINE (Patrick, 15-09-26: "be honest
     does this sound familiar needs to be the same sizing and have the same
     glow as the heading on the hero").

     Every value here is copied off the phone h1 rather than chosen:
       size        calc(25.1 * --up)   the drawing's width-constrained number
       leading     calc(32 * --up)
       glow        0 0 15px white .30 + 0 0 39px white .12

     The h1's glow is the SMALLER of its two declarations. The base phone rule
     sets 20px/52px and a later phone rule overrides it to 15px/39px, which is
     what actually paints. Copying the value that wins, not the first one in
     the file.

     This also drops the headings from 27px to 25.1px, giving up the Identity
     Surgeon match made this morning. That is the point: Jay's reference for
     heading treatment was the app, and Patrick's instruction now is that the
     hero headline is the reference for every heading.

     NOTE FOR THE OLED PASS: seven more glowing headings is seven more wide
     low-alpha spreads on a black ground, which is exactly the class of thing
     that bloomed into a grey box on the phone on 11-09. Worth a look on the
     device rather than here. */
  h2 {
    /* 22.6, one 1.111 step below the hero headline's 25.1 (Patrick, 15-09-26:
       "not identical to the hero headline, one size smaller"). The leading
       comes down with it to hold the hero's own 1.275 ratio rather than
       leaving 32px of line box around smaller type. */
    /* Follows the h1 to the measured glow, 17-09-26. Jay: "more glow on the
       sub-headings too", the same treatment as the main heading. In em, so at
       22px the rim is 1.10px rather than needing its own number.

       The size and leading here are SUPERSEDED by the later phone block (22 /
       28.05) and are left exactly as they were: this block still owns the
       text-shadow, which is why it has to be edited rather than skipped. */
    font-size: calc(22.6 * var(--up));
    line-height: calc(28.8 * var(--up));
    /* 80 percent of the phone h1, 17-09-26: same radii, alphas at 0.8x of its
       1 / 0.45 / 0.24. */
    text-shadow:
      0 0 0.10em rgba(255, 255, 255, 0.8),
      0 0 0.44em rgba(255, 255, 255, 0.36),
      0 0 0.85em rgba(255, 255, 255, 0.19);
  }


  .hero .cta-block {
    text-align: center;
    margin-top: calc(37.7 * var(--up));
  }

  /* MATCHED TO THE TQW LANDING PAGE (Patrick, 15-09-26: the CTA needs to be
     the same size as thequantumworld.co's on phone).

     MEASURED on both LIVE sites at three widths rather than read out of either
     stylesheet, because this file carried two contradicting claims about what
     the button had been matched to, one saying TQW and a later one saying the
     apps:

       430 wide   BLVCKOS 308 x 38   TQW 320 x 46
       390 wide   BLVCKOS 279 x 34   TQW 290 x 41
       375 wide   BLVCKOS 269 x 33   TQW 279 x 40

     Font 13px Montserrat 600, radius 10, 1px border, 20px side padding and
     0.13px tracking were already identical at every width. The entire gap was
     the 308 width and the 10px vertical padding, both taken off the Affinity
     drawing last night. These are TQW's own expressions, so the two landing
     pages now render the same button at every phone size. */
  .hero .cta {
    width: calc(320 * var(--up));
    padding-top: calc(14 * var(--up));
    padding-bottom: calc(14 * var(--up));
  }


  .hero .cta-block .scarcity {
    font-size: calc(11.3 * var(--up));
    margin-top: calc(32.7 * var(--up));
  }
}

/* SMALL PHONES KEEP THE TWO-LINE HEADLINE. The break point is arithmetic, not
   taste: the headline is 377px of a 382px column at 430, and the font scales on
   --up (w/430) while the column is a flat w - 48. Solving 377(w/430) < w - 48
   gives w > 389.3, so 390 holds and every width below it wraps to three lines.
   24.3 keeps it on two down to 320. Verified at 360 and 320, not reasoned. */
@media (max-width: 389px) {
  h1 {
    font-size: calc(24.3 * var(--up));
  }
}


/* Wide screens: three portrait columns (the column is ~1080px there, so two
   columns made wide landscape slabs). */
@media (min-width: 1900px) and (min-height: 960px) {
  /* Still one column above 1900, and matching the copy column, same as
     everywhere else. */
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .cta,
  .video,
  .results li {
    transition: none;
  }

}


/* --------------------------------------------------------------------------
   FAQ

   Accordion design taken from a 21st.dev component Patrick picked (11-09-26),
   ported to vanilla. The original is React + framer-motion + lucide + Tailwind
   on shadcn tokens; this page is static HTML with no build step, and a landing
   page is the last place to put a third-party runtime on the critical path
   (Build Lesson: third-party embeds). So the behaviour is reproduced rather
   than installed: no React, no motion library, no icon package.

   The category tabs were dropped. They need categories, and Jay's locked copy
   is six questions in one list with none; four tabs would be one or two
   questions each and hide most of the section behind a click.
   -------------------------------------------------------------------------- */
.faq {
  position: relative;
  margin-top: clamp(22px, 2.6vw, 34px);
  display: flex;
  flex-direction: column;
  /* 12 -> 18 (Jay, 14-09-26: FAQs "significantly smaller, more space between
     items"). The text came down earlier today; this is the spacing half. */
  gap: 18px;
}

/* The reference puts a large blurred radial behind the heading. Same idea,
   white rather than the accent, because on this page glow is white and action
   is teal. Behind everything, and cannot take pointer events. */
.faq::before {
  content: "";
  position: absolute;
  left: 50%;
  top: clamp(-300px, -22vw, -170px);
  width: min(620px, 120%);
  height: 380px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.055), transparent 70%);
  filter: blur(38px);
  pointer-events: none;
  z-index: -1;
}

/* The WHOLE CARD toggles, not just the heading (Patrick, 11-09), so the
   pointer has to read as clickable across all of it. */
.faq-item {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--card);
  cursor: pointer;
  /* box-shadow included so the glow fades in and out with the card rather
     than snapping on, matching the button's own 0.25s. */
  transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}

.faq-item:hover {
  border-color: #2a2c2f;
}

.faq-h {
  margin: 0;
  font: inherit;
}

/* ---- the question ---------------------------------------------------------
   WHOLE-PIXEL GEOMETRY, and it is not fussiness.

   This block used to size the question with clamp() on the font and a 1.4
   unitless line-height, which resolved to 23.19px lines and buttons 84.38px
   and 61.19px tall. Fractional, and different from each other. The plus is
   centred in that button, so each of the six landed on a different pixel
   fraction, measured at .75 / .53 / .31 / .69 / .06 / .84, and a hairline
   straddling a pixel boundary is rasterised across two rows at partial alpha.
   That is why the six icons did not look like the same icon.

   Fixed sizes here rather than clamp, so every button height is a whole even
   number (62 one-line, 86 two-line) and all six icons share one offset. They
   do not have to land ON a pixel, they have to land on the SAME one.
   --------------------------------------------------------------------------- */
.faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 20px;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--sans);
  font-weight: 700;
  letter-spacing: -0.01em;
  /* Always white. Patrick, 11-09: a question that dims at rest reads as
     disabled, and every one of these is worth reading. */
  color: var(--ink);
}

.faq-qt {
  /* 15 (Patrick, 15-09-26). */
  font-size: 15px;
  line-height: 24px;
}

@media (min-width: 1100px) {
  .faq-q { padding: 22px 22px; }
  .faq-qt { font-size: 18px; line-height: 26px; }
}

.faq-q:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -3px;
  border-radius: 14px;
}

/* Open state.

   WHITE, MATCHING THE RESULTS CARDS (Patrick, 11-09-26). This was the CTA's
   teal; it is now the same white light the results cards carry, so the two
   glowing things on the page agree. The border goes white with it, because a
   teal rim around a white glow reads as two different systems.

   A closed card is still untouched, so the light only ever exists as a
   response to a click. That is deliberate and predates this change: Patrick
   asked for the glow AS the click feedback, which is why it is not simply
   always on the way it is on the results cards.

   ONE DELIBERATE DIFFERENCE FROM THE RESULTS CARDS, kept from the teal
   version. The outer two layers stay pulled in at 22/42 rather than the
   results cards' 28/56. The button those numbers came from is 320 x 50 and an
   open FAQ card is 408 x roughly 300, so an identical blur radius throws
   several times the area of light and stops reading as an edge glow. That
   mattered in teal and it matters more in white, because white is brighter at
   the same alpha and this is the largest box on the page that lights up. The
   two INNER layers, which are what the eye actually reads as the edge
   igniting, are the results cards' values untouched. */
/* GREEN, 17-09-26. Jay: "I think I like the FAQ better as green as well."
   Same four layers, same alphas, on --green instead of --accent. */
.faq-item:not(.is-collapsed) {
  background: #0d0d0f;
  border-color: var(--green);
  box-shadow:
    0 0 4px rgba(var(--green-rgb), 0.5),
    0 0 12px rgba(var(--green-rgb), 0.4),
    0 0 22px rgba(var(--green-rgb), 0.24),
    0 0 42px rgba(var(--green-rgb), 0.12);
}

/* ---- the plus -------------------------------------------------------------
   Drawn, not imported: two bars that rotate into a cross, which is the whole
   reason the original pulled in lucide-react.

   Every number here is a whole even one, and the bars are placed with explicit
   offsets rather than translate(-50%, -50%), so nothing inside the icon can
   land on a half pixel of its own accord.
   --------------------------------------------------------------------------- */
.faq-plus {
  position: relative;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--ink-dim);
  transition: transform 0.32s cubic-bezier(0.2, 0.7, 0.2, 1), color 0.25s ease;
}

.faq-plus::before,
.faq-plus::after {
  content: "";
  position: absolute;
  background: currentColor;
  border-radius: 1px;
}
.faq-plus::before { left: 3px; top: 10px; width: 16px; height: 2px; }
.faq-plus::after  { left: 10px; top: 3px; width: 2px; height: 16px; }

.faq-item:hover .faq-plus { color: var(--ink-soft); }

/* NO COLOUR OVERRIDE HERE (Patrick, 11-09-26: the open X was teal and should
   be grey, the same as the plus). Rather than restating --ink-dim, the
   declaration is simply removed, so the icon inherits the plus's colour rules
   in every state: --ink-dim at rest, --ink-soft on hover. The open state now
   differs from the closed one by the rotation and nothing else, which is also
   why hovering an open card still lifts the icon the way it does on a closed
   one. Restating the colour here would have frozen it dim on hover, because
   this rule and `.faq-item:hover .faq-plus` have equal specificity and this
   one is later in the file. */
.faq-item:not(.is-collapsed) .faq-plus {
  transform: rotate(45deg);
}

/* ---- the answer -----------------------------------------------------------
   OPEN BY DEFAULT. The script closes them; if it never runs, all six answers
   are readable instead of being locked behind dead buttons.

   0fr to 1fr on a grid row is the only way to animate to a content-sized
   height without measuring it in JS, because `height: auto` is not animatable.
   --------------------------------------------------------------------------- */
.faq-a {
  display: grid;
  grid-template-rows: 1fr;
}

.faq-item.is-collapsed .faq-a {
  grid-template-rows: 0fr;
}

.faq-a-in {
  overflow: hidden;
}

/* The slide. The panel opens by height, and the text rides in behind it with
   its own small offset, which is what makes it read as sliding rather than as
   a box being stretched. Opening is delayed a fraction so the text follows the
   edge; closing is not, so it is out of the way before the panel shuts. */
.faq-a p {
  margin: 0;
  /* Whole EVEN padding and an explicit whole EVEN line box, for the same
     reason the question has them: an open panel whose height is fractional
     shifts every card below it onto a different pixel fraction, and then the
     plus icons under it rasterise differently again. 15 x 1.7 was 25.5px. */
  padding: 0 20px 20px;
  /* 14 (Patrick, 15-09-26). Line box left at a whole even 26px on purpose:
     the comment above explains that a fractional open panel shifts every card
     below it onto a different pixel fraction. */
  font-size: 14px;
  line-height: 26px;
  color: var(--ink-soft);
  opacity: 1;
  transform: translateY(0);
}

@media (min-width: 1100px) {
  .faq-a p { padding: 0 22px 22px; font-size: 16.5px; line-height: 28px; }
}

.faq-item.is-collapsed .faq-a p {
  opacity: 0;
  transform: translateY(-10px);
}

/* Transitions are switched on by the script AFTER it sets the opening state,
   or every closed item plays a collapse animation on page load. */
.faq-ready .faq-a {
  transition: grid-template-rows 0.36s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.faq-ready .faq-a p {
  transition:
    opacity 0.28s ease 0.1s,
    transform 0.34s cubic-bezier(0.2, 0.7, 0.2, 1) 0.08s;
}

.faq-ready .faq-item.is-collapsed .faq-a p {
  transition:
    opacity 0.16s ease,
    transform 0.2s cubic-bezier(0.2, 0.7, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  .faq-ready .faq-a,
  .faq-ready .faq-a p,
  .faq-ready .faq-item.is-collapsed .faq-a p,
  .faq-item,
  .faq-plus {
    transition: none;
  }
  .faq-item.is-collapsed .faq-a p { opacity: 1; transform: none; }
}


/* --------------------------------------------------------------------------
   PHONE TYPE, ONE STEP DOWN. Patrick, 15-09-26, after reviewing the measured
   type table: "can we make h2 section heading 20 for phone and the body
   paragraph 13 for phone please. actualy anything thats 14 make it 13 please
   for the phone ok"

   So: every 14px on a phone becomes 13, and the section headings go 22.6 -> 20.
   DESKTOP IS UNTOUCHED, which is the whole reason this is a separate block
   rather than eight edits to the base rules. The sizes involved are clamps
   whose floor IS the desktop value, so moving a floor would move both widths;
   and `.faq-a p` does not pick up its desktop size until 1100, so editing its
   base would drag every tablet width down with the phone.

   What was at 14 and is now 13, measured off the page rather than listed from
   memory: body paragraphs, the closing CTA line (it inherits .copy p), the
   three anchor lines, the outcome bullets with their bold lead-ins and the
   green 30/30 (all three inherit the li), the testimonial quotes, the FAQ
   answers and the Load more button. Left alone because they are not 14: the
   testimonial name at 14.5, the hero sub at 13.6 and both scarcity lines.

   ---------------------------------------------------------------------------
   REVERSED 17-09-26, and this block now does the opposite job. Jay reviewed the
   step-down on 16-09 and said it overshot ("I personally like it small, but
   it's just too small"), scoped to the recognition section. Patrick widened it
   to the page: section headings up TWO sizes, 20 -> 22, and everything that
   sat at 13 back up ONE, to 14.

   Since 14 is also the floor of every one of those clamps, these rules now PIN
   the phone to the desktop value rather than pull it under. They stay written
   out rather than deleted so the phone keeps an explicit number if a ceiling
   or a floor ever moves, and so the argument stays readable.

   EXCLUDED BY NAME, both Patrick's instruction: the CTA button, still 13, and
   the whole hero, which is where the other small values live (sub 13.6,
   purpose 11.5, both scarcity lines 11.3). Nothing in this block reaches into
   the header. Desktop is untouched, as always.
   ---------------------------------------------------------------------------
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  /* 22.6 -> 20 (15-09) -> 22 (17-09). TWO SIZES BACK UP, Patrick carrying out
     Jay's 16-09 call on the recognition section and widening it to every
     section: "I personally like it small, but it's just too small."

     Leading rides with it on the same 1.275 ratio the 22.6 had and the 20
     kept, so 22 x 1.275 = 28.05. The RATIO is the constant here, not the
     number: a heading that goes up two points against a line box left at 25.5
     tightens to 1.16, and the headings that wrap to two lines start to touch. */
  h2 {
    font-size: calc(22 * var(--up));
    line-height: calc(28.05 * var(--up));
    /* TRACKING -0.02em -> -0.04em, 17-09-26, and this is a SPACING change on
       purpose. Jay wanted "familiar" pulled onto one line in "Be honest, does
       this sound familiar?" and set his own limit on it: try to win it with
       spacing, and if it costs a size, leave it.

       Measured rather than guessed. At 430 the line WANTS 395.5px and the
       column gives 386, so it was 9.5px short. -0.03em leaves it 1.6px short
       and still wraps. -0.04em brings it to 379.6 and it fits, at 430 and at
       390, with 6.4px and 1.7px to spare. No size moved.

       It is on every section heading, not just that one, because one heading
       tracked differently from the other six is visible and a fault of its own.

       360 and 320 still wrap, and Jay closed that himself on the call: smaller
       phones will break it anyway and detecting the device is "just a waste of
       time really". DESKTOP IS NOT TOUCHED, where 31.5px already fits it. */
    letter-spacing: -0.04em;
  }

  /* The closing heading has its own size, `.decision h2` at (0,1,1), so it
     does NOT follow the rule above and has to be named. It was 22.36 against
     the others' 22.6; both land on 20 now, which also retires that 0.24px
     difference. */
  .decision h2 {
    font-size: calc(22 * var(--up));
    /* Follows the tracking above for the same reason it has to follow the
       size: .decision h2 is (0,1,1) and does not inherit a bare h2 rule. */
    letter-spacing: -0.04em;
  }

  /* Body copy. The closing CTA line rides on this, being .copy p.closing-line,
     so it moves with it and keeps its 700 weight. */
  .copy p {
    font-size: 14px;
  }

  /* The outcome bullets. The bold lead-ins and the green 30/30 are <strong>
     inside the li with no size of their own, so all three move together. */
  .results li {
    font-size: 14px;
  }

  /* !important because the base rule has it: `.copy p` is (0,1,1) and would
     otherwise beat `.anchor` at (0,1,0). Leading is a ratio there, 1.75, so it
     follows the size down on its own. */
  .anchor {
    font-size: 14px !important;
  }

  /* 26 -> 24 (15-09) -> 26 again (17-09), because the size it was cut to fit
     has gone back to 14. The leading here is a fixed pixel value on purpose
     and the base rule explains why: a panel whose open height is fractional
     shifts every card below it onto a different pixel fraction and the plus
     icons rasterise differently, so this stays a whole EVEN number. 26 is the
     1.857 ratio the answer had before the step-down; leaving it at 24 would
     put a 1.71 line box around 14px text.

     WORTH KNOWING: the question above is 14 as well now, set by Patrick's own
     instruction this session. The panel still separates them by weight and
     colour, 700 white against 400 grey, but they are the same size. */
  .faq-a p {
    font-size: 14px;
    line-height: 26px;
  }

  /* 15 -> 14 (Patrick, 15-09-26: "can we make the FAQ questions fourteen
     pixels"). Phone only, like everything else in this block: the base rule
     also serves 641-1099 and the 1100+ override stays at 18.

     Leading 24 -> 22, whole and EVEN for the same panel-height reason as the
     answer above. 22/14 is 1.57 against the 1.6 that 24/15 was, so the two
     line rhythms stay where they were; left at 24 it would be a 1.71 line box
     around a question that wraps to two lines on a phone. */
  .faq-qt {
    font-size: 14px;
    line-height: 22px;
  }
}


/* --------------------------------------------------------------------------
   THE CLOSING BLOCK SITS IN EQUAL AIR, ON PHONE. Patrick, 17-09-26, carrying
   out Jay's 16-09 rule: "whatever that top space is, say it's 13, you'll
   replicate 13 again and then you'll have the footer section." Patrick set the
   number at 45.

   PHONE ONLY. Desktop keeps 60 above and 115 below, deliberately: Jay gave the
   rule watching a phone, and the desktop hero is still on the 2558 canvas
   fault, so desktop spacing is not settled enough to change in the same pass.

   Measured before: 40 above, 100 below, which is the 1 : 2.5 Jay was looking
   at when he called it.

   NOTE THIS IS THE THIRD TIME THIS GAP HAS MOVED. It was built symmetric on
   15-09 at 100/100, Patrick reverted it the same day as "the incorrect way to
   go about it", and Jay then asked for symmetry from the other direction on
   16-09. The difference that makes this one right: the number is 45, not the
   divider rhythm, so the button comes UP off the line rather than the footer
   gap being forced down onto the whole page's spacing scale.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  /* 40 -> 45. Both in-page CTAs, because they were both on 40 and a rule that
     moved only the closing one would split a pair that has been identical by
     construction since the base rule was written. */
  section .cta-block {
    margin-top: 45px;
  }

  /* 100 -> 45, the same number, which is the whole point of the instruction.
     This is the last section's bottom padding, which is the only thing holding
     the footer off the "100% free" line, so it IS the gap Jay named. The
     selector matches the base rule exactly at (0,2,2) and wins on source
     order from the end of the file. */
  body.lp > section:last-of-type {
    padding-bottom: 45px;
  }
}


/* THE GREEN SWITCH IS GONE, 21-09-26. It lived here from 17-09 so Jay could
   compare white against green at the same scroll position. He settled the
   dividers, the FAQ and the lower buttons that night and they took --green
   directly, which left the switch flipping exactly one element, the hero CTA.
   Patrick has now called that green too, so the switch had nothing left to
   toggle and the page has no option to change colour.

   --accent and --accent-rgb are deliberately still DEFINED at the top of this
   file. Nothing on the live page reads them any more, but the option-catalogue
   pages in this repo load this stylesheet and do. */

/* The `section .cta` green override that used to live here is gone, 21-09-26.
   It was scoped by structure precisely BECAUSE the hero button had to stay
   white; now that all three are green, the base .cta rule covers them and this
   was a redundant duplicate of it. */
