/* ==========================================================================
   exp33 . HERO v2 . the copy layer that sits over the living intent graph
   Loaded LAST on every exp33 page. Everything hero-specific is scoped to
   .hero33; the two rules that are not (the header's demo action and the
   headline weight split) are deliberately site-wide so the change is
   consistent across index / graph / method / onboarding / demo / prove.

   WHY THIS FILE EXISTS
   The founder's verdict on hero v1: "with the headline blurred out, somebody
   should be able to look at the animation and say: that's the Proof site."
   Getting there is not only a background change. It also needs
     - a headline with a split weight instead of one uniform display line,
     - ONE interactive object, built like an instrument rather than a pill,
     - a header action that stops competing with it,
     - and a lot more black space, so the hero gets deeper, not busier.
   ========================================================================== */

/* ==========================================================================
   1. THE COPY GUARD IS A DIMMER, NOT A PLATE
   exp33.css paints a masked wash of the page's own ground colour behind the copy
   column (.hero-film::after, strength --film-scrim). Two earlier passes both got
   it wrong, in opposite directions, and this is the middle they bracket.

   PASS ONE: A PLATE. --film-scrim .42-.68 per theme, over a mask with a wide
   opaque PLATEAU (solid to 34% of the ellipse before it began to feather) and a
   further 1.10-1.45x lift for the pull-back beat. It did its contrast job
   perfectly and it is exactly why the founder could see nothing behind the hero
   copy: the ground painted at half strength over the densest part of the frame
   does not protect the graph's neighbours, it deletes them, and it deletes them
   over an area large enough to read as a hole.

   PASS TWO: NOTHING AT ALL. --film-scrim 0 and content:none, so the graph ran
   under the copy at full tier. With the envelope raised at the same time, the
   type stopped sitting forward -- the founder's "protect a bit hero text".

   WHAT IS HERE NOW: about a THIRD of pass one's strength, and no plateau. The
   mask is a single continuous feather from the centre of the copy column out to
   nothing, so there is no edge anywhere for the eye to find, and the graph is
   never knocked out -- at the deepest point of the guard it still keeps roughly
   three quarters of its luminance, and the flanks and the whole periphery keep
   all of it. It reads as the copy having its own quiet air around it.

   THE ELLIPSE IS THE MEASURED GLYPH COLUMN, NOT THE COPY BOX. Swept at
   1440x900 (craft/glyphbox.mjs), the union of every text run in the headline,
   the machine line, the subhead, the CTA row and the facts line is
       terminal  x 13.2..65.5%  y 17.0..76.2%   centre 39.3% 46.6%
       centred   x 25.6..74.4%  y 18.2..75.2%   centre 50.0% 46.7%
   of the film box -- the tube left-aligns its copy, every other theme centres
   it, so the guard has two centres and no other per-theme geometry. The radii
   are ~1.75x the union's half-extent, which puts the outermost glyphs at ~.6 of
   full guard strength and lands the last stop outside anything the copy touches.

   PLACEMENT STILL DOES MOST OF THE WORK, and none of it is revoked: the copy's
   line boxes were swept across the whole viewport matrix (craft/lines.mjs), the
   horizontal bands that no viewport puts a glyph in are y 175..194, 215..246,
   506..515, 596..622, 757..826 and 867..899 in graph user space, and every
   LABELLED CARD above the fold sits in one of them. What passes behind the
   glyphs is edges, dots and ticks. The guard is the second half of that
   argument, not a replacement for it: craft/regress.mjs check D and
   craft/contrast4.mjs measure the result at the glyph boxes at every beat.
   ========================================================================== */
.hero33{--film-scrim:.26;}
.hero33 .hero-film::after{
  content:"";
  /* one continuous feather; no solid plateau at any radius */
  -webkit-mask-image:radial-gradient(44% 52% at 50% 47%,
      rgba(0,0,0,1) 0%,rgba(0,0,0,.94) 22%,rgba(0,0,0,.72) 46%,
      rgba(0,0,0,.40) 70%,rgba(0,0,0,.14) 87%,transparent 100%);
          mask-image:radial-gradient(44% 52% at 50% 47%,
      rgba(0,0,0,1) 0%,rgba(0,0,0,.94) 22%,rgba(0,0,0,.72) 46%,
      rgba(0,0,0,.40) 70%,rgba(0,0,0,.14) 87%,transparent 100%);
}
/* the tube left-aligns the hero copy, so the guard follows the copy, not the
   frame; the radius is a touch wider because the tube's glyph column is wider */
html[data-theme="terminal"] .hero33 .hero-film::after{
  -webkit-mask-image:radial-gradient(46% 52% at 39% 47%,
      rgba(0,0,0,1) 0%,rgba(0,0,0,.94) 22%,rgba(0,0,0,.72) 46%,
      rgba(0,0,0,.40) 70%,rgba(0,0,0,.14) 87%,transparent 100%);
          mask-image:radial-gradient(46% 52% at 39% 47%,
      rgba(0,0,0,1) 0%,rgba(0,0,0,.94) 22%,rgba(0,0,0,.72) 46%,
      rgba(0,0,0,.40) 70%,rgba(0,0,0,.14) 87%,transparent 100%);
}
/* brutal keeps hard geometry: a flat wash at half strength, never a soft
   ellipse, which on that theme would read as a smudge. exp33.css states the
   rule; it is restated here only because this file loads later. */
html[data-theme="brutal"] .hero33 .hero-film::after{
  -webkit-mask-image:linear-gradient(#000,#000);mask-image:linear-gradient(#000,#000);
}
/* light grounds show a wash of their own ground sooner than a dark one does,
   and they carry less graph to knock down in the first place */
html[data-theme="paper"] .hero33,html[data-theme="riso"] .hero33,
html[data-theme="brutal"] .hero33,html[data-theme="olo"] .hero33,
html:not([data-theme]) .hero33{--film-scrim:.19;}
/* the pull-back multiplier is NOT coming back: the guard is the same strength
   at every beat, including the wide one, so no beat can be the one that hides
   the graph behind the copy */
.hero33{--film-wide:1;}

/* ==========================================================================
   2. TYPOGRAPHY: one face, two weights
   Line 1 is the subject, line 2 is the claim. Splitting the weight rather than
   the size or the colour is what gives the headline a character of its own
   without adding a second voice. The claim is forced onto its own line so the
   break is deterministic at every width.
   NO GREEN IN THE HEADLINE: green means verified, and a headline is not a
   verdict. Every theme that painted .h1-em in its accent is overridden to the
   plain ink token. The single exception, and the reason it is an exception, is
   documented in section 6.
   ========================================================================== */
.hero33 .hero-copy h1{
  font-weight:500;
  letter-spacing:-.03em;
  max-width:22ch;
  text-wrap:normal;
}
.hero33 .hero-copy h1 .h1-em{
  display:block;
  font-weight:680;
  letter-spacing:-.038em;
  color:var(--ink);
  text-shadow:none;
}
html[data-theme="night"] .hero33 .hero-copy h1 .h1-em,
html[data-theme="brutal"] .hero33 .hero-copy h1 .h1-em,
html[data-theme="olo"] .hero33 .hero-copy h1 .h1-em{color:var(--ink);text-shadow:none;}
/* acid fills its display with a violet-cyan-CHARTREUSE gradient. In the hero
   that is both a second voice and a green claim, so the hero headline drops
   back to the plain ink token. Section H2s keep the gradient. */
html[data-theme="acid"] .hero33 .hero-copy h1{
  background:none;
  -webkit-background-clip:border-box;background-clip:border-box;
  color:var(--ink);
}
/* riso prints its display in klein blue with a deliberately misregistered pink
   pass. Forcing line 2 to black ink read as a broken print, so both lines keep
   the theme's own ink and the weight split alone carries the split. */
html[data-theme="riso"] .hero33 .hero-copy h1 .h1-em{
  color:var(--signal);text-shadow:.055em .05em 0 rgba(255,61,154,.75);
}

/* the machine annotation under line 2. Brand texture, not copy: ~9.5px, very
   low contrast, aria-hidden, never a sentence. */
.hero-mach{
  margin:clamp(1.1rem,1.8vw,1.5rem) auto 0;
  font-family:var(--mono);font-size:9.5px;font-weight:500;
  letter-spacing:.34em;text-transform:uppercase;
  color:var(--muted);opacity:.55;
  white-space:nowrap;
}
.hero-mach i{font-style:normal;opacity:.7;padding:0 .1em;}
html[data-theme="terminal"] .hero-mach{margin-left:0;margin-right:0;}

.hero33 .hero-sub{
  margin-top:clamp(1.2rem,2vw,1.7rem);
  font-size:clamp(1.08rem,1.35vw,1.22rem);
  max-width:52ch;
  /* MEASURED, not eyeballed: --ink-60 lands at 5.1:1 on the paper ground, and
     the brief asks for 7:1 minimum behind the graph. .78 of the ink token
     clears 8.7:1 on paper and 10.5:1 on the near-black grounds. */
  color:rgba(var(--ink-rgb),.78);
}
/* riso's ink is a print blue-black on cream: .78 of it lands at 6.7:1, so this
   one theme needs a heavier pass to clear the bar. */
html[data-theme="riso"] .hero33 .hero-sub{color:rgba(var(--ink-rgb),.88);}

/* ==========================================================================
   3. THE ONE INTERACTIVE OBJECT
   A Proof machine control, not a CTA pill: 2px corners, a hairline border in
   the site's own line colour, a mono label, and a small state lamp on the
   left. The lamp is var(--signal) -- an affordance, never a state -- because
   in this theme green would read as "verified" and a button is not a verdict.
   ========================================================================== */
.pctl{
  display:inline-flex;align-items:center;gap:.85rem;
  min-height:46px;padding:0 1.15rem 0 .95rem;
  appearance:none;
  background:transparent;
  border:1px solid var(--hair-strong);
  border-radius:2px;
  font-family:var(--mono);font-size:.72rem;font-weight:500;
  letter-spacing:.19em;text-transform:uppercase;
  color:var(--ink);text-decoration:none;white-space:nowrap;cursor:pointer;
  transition:border-color .16s ease,color .16s ease,background-color .16s ease;
}
.pctl-lamp{
  position:relative;
  flex:0 0 auto;width:5px;height:5px;border-radius:50%;
  background:var(--signal);opacity:.85;
}
/* one hairline tick either side of the lamp: the control reads as wired into
   something rather than floating on the page */
.pctl-lamp::before,.pctl-lamp::after{
  content:"";position:absolute;top:50%;width:7px;height:1px;
  background:var(--hair-strong);
}
.pctl-lamp::before{right:100%;margin-right:3px;}
.pctl-lamp::after{left:100%;margin-left:3px;}
.pctl-key{
  flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:19px;height:19px;
  border:1px solid var(--hair-strong);border-radius:1px;
  font-size:.62rem;line-height:1;letter-spacing:0;
  color:var(--ink);
}
.pctl:hover{border-color:var(--signal);color:var(--signal);}
.pctl:hover .pctl-key{border-color:var(--signal);color:var(--signal);}
.pctl:focus-visible{outline:2px solid var(--signal);outline-offset:3px;}
/* hard-edged themes take square corners from --radius like everything else */
html[data-theme="riso"] .pctl,
html[data-theme="brutal"] .pctl,
html[data-theme="terminal"] .pctl,
html[data-theme="verified"] .pctl{border-radius:0;}
html[data-theme="brutal"] .pctl{border-width:2px;}

.hero33 .cta-row{
  margin-top:clamp(2.1rem,3.2vw,2.7rem);
  justify-content:center;gap:1.4rem 2rem;align-items:center;
}
html[data-theme="terminal"] .hero33 .cta-row{justify-content:flex-start;}

/* the hero's secondary action gets the same treatment as the header's: label
   and destination untouched, box gone. One control per screen. */
.hero33 .cta-row .hero-act{
  min-height:0;padding:0;
  background:transparent;border:0;border-radius:0;
  color:rgba(var(--ink-rgb),.76);          /* 7.9:1 on paper, 9.6:1 on black */
  font-family:var(--mono);font-size:.7rem;font-weight:500;
  letter-spacing:.16em;text-transform:uppercase;
  transition:color .16s ease;
}
.hero33 .cta-row .hero-act:hover{background:transparent;border:0;color:var(--signal);}

/* the facts line drops back: it is provenance, not a claim, and the hero now
   has exactly one thing to look at. Quieted by SIZE and tracking, not by colour.

   THE COLOUR IS SET IN THE HERO BECAUSE THE HERO HAS A CONTRAST FLOOR.
   The brief's four -- headline, subhead, control label, facts line -- carry a
   7:1 minimum measured at their own glyph boxes. Measured that way, the shell's
   inherited fine-print token lands at 5.16:1 on paper and 5.26:1 on verified.
   That is not the graph: with .hg-svg forced to zero opacity the same glyph
   boxes measure 5.19 and 5.28, i.e. the animation costs the facts line 0.03 of
   contrast ratio. It is the token, and it is under the bar wherever the token is
   used. Scoped to .hero33 so the fine print everywhere else on the site is
   untouched: .78 of the ink token is the same figure the subhead above already
   uses and measures, and it clears the floor on every theme. */
.hero33 .facts{
  margin-top:clamp(1.5rem,2.2vw,1.9rem);
  font-size:.7rem;letter-spacing:.02em;
  color:rgba(var(--ink-rgb),.78);
}
.hero33 .facts span{color:rgba(var(--ink-rgb),.78);}
.hero33 .facts a{color:rgba(var(--ink-rgb),.84);border-bottom-color:var(--hair-strong);}
.hero33 .facts a:hover{color:var(--ink);border-bottom-color:var(--ink);}
.hero33 .facts b{font-weight:500;color:rgba(var(--ink-rgb),.92);}

/* ==========================================================================
   4. THE HEADER'S DEMO ACTION, QUIETED
   Site-wide on purpose. The label set and the destination are untouched: only
   the chrome goes, and the arrow + caps come from CSS, so the hero has exactly
   one boxed control on it.
   ========================================================================== */
.site-header .nav > .btn-primary{
  min-height:0;padding:0;
  background:transparent;border:0;border-radius:0;
  color:var(--ink);
  font-family:var(--mono);font-size:.7rem;font-weight:500;
  letter-spacing:.16em;text-transform:uppercase;
  transition:color .16s ease,opacity .16s ease;
}
.site-header .nav > .btn-primary::after{
  content:"\2192";margin-left:.55em;letter-spacing:0;opacity:.7;
}
.site-header .nav > .btn-primary:hover{background:transparent;border:0;color:var(--signal);}
html[data-theme="verified"] .site-header .nav > .btn-primary,
html[data-theme="verified"] .site-header .nav > .btn-primary:hover{background:transparent;border-color:transparent;}
html[data-theme="verified"] .site-header .nav > .btn-primary{color:var(--ink);}
html[data-theme="verified"] .site-header .nav > .btn-primary:hover{color:var(--signal);}
html[data-theme="terminal"] .site-header .nav > .btn-primary,
html[data-theme="brutal"] .site-header .nav > .btn-primary,
html[data-theme="riso"] .site-header .nav > .btn-primary{
  background:transparent;border:0;box-shadow:none;
}
/* TERMINAL: THE CLOSING BRACKET WAS BEING EATEN.
   themes.css draws every .btn on the tube as a bracketed command -- ::before is
   "[" and ::after is "]" -- and the rule above replaced ::after with the arrow,
   so the header read `[ REQUEST A DEMO →` with no closing bracket while the
   hero's own secondary (whose arrow is in the label text, not in CSS) correctly
   read `[ REQUEST A DEMO → ]`. The arrow and the bracket now share the one
   pseudo-element the tube leaves free, in the bracket's own chrome green, so the
   pair is complete and the two actions match. One box, no extra glyph width to
   clip: verified at 1440 / 1280 / 1024 / 390. */
html[data-theme="terminal"] .site-header .nav > .btn-primary::after{
  content:"\2192\00A0]";
  margin-left:.5em;
  letter-spacing:0;
  color:rgba(43,255,111,.62);
  opacity:1;
}
html[data-theme="terminal"] .site-header .nav > .btn-primary:hover::after{color:var(--signal);}

/* ==========================================================================
   5. THE BAND
   More air, and the scroll cue loses its glowing hairline: the graph's own
   hairline crossing into section 2 is the real cue now, and two vertical
   hairlines at the fold was one too many.
   ========================================================================== */
.hero33{min-height:clamp(600px,86vh,940px);}
html[data-theme="terminal"] .hero33{min-height:clamp(560px,82vh,900px);}
/* THE GLOWING HAIRLINE UNDER THE CUE IS GONE. The graph's own hairline
   crossing into section 2 is the real cue now, and two vertical hairlines at
   the fold was one too many. The label moves to the bottom-left corner: it
   reads as a frame annotation, it breaks the last piece of symmetry, and it
   clears the artifact row that sits on the frame's bottom edge. */
.hero-cue i{display:none;}
.hero33 .hero-cue{
  margin-top:clamp(1.6rem,3vw,2.6rem);
  text-align:left;
  font-size:.66rem;letter-spacing:.2em;
  color:var(--muted);                     /* was --ink-40: 2.6:1 on paper */
}
.hero33 .hero-cue:hover{color:var(--ink);}

@media (max-width:760px){
  /* a phone hero has no free flank, so the copy is top-weighted and the band
     grows: that buys a real graph band under the facts line instead of a
     whisper behind the headline. */
  .hero33{min-height:clamp(560px,88vh,880px);}
  .hero33 > .hero-main{margin-top:0;margin-bottom:auto;}
  /* Line 2 must stay on ONE line or the weight split reads as an accident
     rather than as a decision. exp33.css and theme-verified.css both set the
     hero H1 scale from an attribute selector, so the override has to match
     that specificity to win; it loads last, so a tie goes to this file. */
  html[data-theme] .hero33 .hero-copy h1,
  html:not([data-theme]) .hero33 .hero-copy h1{
    max-width:none;
    font-size:clamp(2rem,9.3vw,2.9rem);
    line-height:1.02;
  }
  .hero33 .hero-sub{font-size:1.05rem;}
  .hero-mach{font-size:9px;letter-spacing:.22em;}
  .hero33 .cta-row{gap:1rem 1.2rem;}
  .pctl{width:auto;}
}

/* nothing in this layer animates; the graph driver holds its own final frame
   under reduced motion. */

/* ==========================================================================
   6. TERMINAL: the one theme where the headline stays in its own ink
   Green means verified everywhere else on the site, which is why nothing in
   the headline is green. On the tube green IS the ink -- the whole page is
   phosphor -- so forcing a pale headline there would read as a broken theme
   rather than as a rule. What DID read as broken was line 2 inheriting a
   different colour from .h1-em, and the theme's block cursor being pushed onto
   a line of its own by the forced break. Both are fixed here.
   ========================================================================== */
html[data-theme="terminal"] .hero33 .hero-copy h1 .h1-em{
  color:var(--signal);
  text-shadow:0 0 14px rgba(43,255,111,.4);
}
html[data-theme="terminal"] .hero33 .hero-copy h1::after{display:none;}
html[data-theme="terminal"] .hero33 .hero-copy h1 .h1-em::after{
  content:"";display:inline-block;width:.5em;height:.85em;margin-left:.18em;
  background:var(--signal);vertical-align:baseline;transform:translateY(.1em);
  animation:t-blink 1.1s steps(1) infinite;
}
@media (prefers-reduced-motion: reduce){
  html[data-theme="terminal"] .hero33 .hero-copy h1 .h1-em::after{animation:none;}
}

/* ==========================================================================
   7. TERMINAL: THE `>` PROMPT HANGS. THE TEXT COLUMN IS FLUSH.
   --------------------------------------------------------------------------
   WHAT WAS WRONG
   themes.css draws the prompt as an IN-FLOW ::before (content:"> ") on every
   h1. In the hero that puts it inside the first line box, and section 2 of this
   file forces line 2 onto its own line with .h1-em{display:block}. So the two
   lines did not share a column: measured at 1440, line 1 began at x=213.91 and
   line 2 at x=130.00 -- an 83.91 px step, which is exactly the prompt glyph's
   own advance. Every headline line except the first started under the prompt
   instead of beside it.

   THE FIX, AND WHY IT IS NOT A PADDING ON LINE 2
   Indenting line 2 would only paper over the first line's inflation, and it
   would break again the moment the headline wrapped to three lines. The prompt
   is taken OUT OF FLOW instead:

     .hero-copy    carries the prompt column as its own padding-left, so the
                   headline, the machine stamp, the subhead, the CTA row, the
                   facts line and the cue all begin on ONE column
     h1            is the containing block (position:relative) and keeps the
                   scale that drives the column width, so there is one source
                   of truth for both
     h1::before    is absolutely positioned at right:100% -- entirely outside
                   the text column, hanging in the padding the copy block just
                   opened for it, and no longer part of any line box

   Because the pseudo-element is not sized here it still shrink-wraps to the
   glyph, which is what assets/hdr-event.css section 2 needs: its HDR raster is
   background-clip:text over that box, so the emitting pixels stay exactly the
   shape of the character. No bloom or geometry retune was required.

   The column is .82em of the headline -- a `>` advance in IBM Plex Mono is .6em
   and .22em is the gap -- so the glyph never reaches past .hero-copy into the
   page gutter, at any width down to 390.
   ========================================================================== */
html[data-theme="terminal"] .hero33 .hero-copy{
  --t-h1:clamp(2.2rem,5.4vw,4.6rem);
  --t-pw:calc(var(--t-h1) * .82);
  padding-left:var(--t-pw);
}
html[data-theme="terminal"] .hero33 .hero-copy h1{
  font-size:var(--t-h1);
  position:relative;
}
html[data-theme="terminal"] .hero33 .hero-copy h1::before{
  content:">";
  position:absolute;
  top:0; right:100%;
  margin-right:.22em;
  /* font-size, line-height, weight and colour are all inherited from the h1, so
     the glyph sits on line 1's own baseline and cannot drift when the headline
     scale changes. */
  text-shadow:none;
  pointer-events:none;
}
/* the phone keeps the same construction on its own type scale. This block is
   last in the file, so it wins the specificity tie with section 5's narrow
   headline rule. */
@media (max-width:760px){
  html[data-theme="terminal"] .hero33 .hero-copy{
    --t-h1:clamp(2rem,9.3vw,2.9rem);
  }
  html[data-theme="terminal"] .hero33 .hero-copy h1{
    max-width:none;
    font-size:var(--t-h1);
    line-height:1.02;
  }
}

/* --------------------------------------------------------------------------
   ... AND ON EVERY OTHER HERO ON THE SITE.
   The tube is now the default theme, so the prompt is what a first-time visitor
   sees on all six pages -- and graph.html, method.html, demo.html and prove.html
   all carry a headline that wraps. Measured at 1440 before this rule: graph and
   method stepped 88.33 px between line 1 and line 2, demo and prove 72.97 px.
   Same defect, same cause.

   Those four heroes are not .hero33 and their headline wrappers all differ
   (.hero-copy, .dm-left, .pv-left), so this variant is self-contained: the h1
   carries the prompt column as its own padding and the prompt hangs at the
   column's left edge. Every line of the headline therefore starts on one column
   and the prompt sits outside it, exactly as in the hero above, without this
   rule needing to know what the headline is wrapped in.

   box-sizing is content-box for the duration: every one of these h1s is sized by
   a `max-width` in ch, and under the site's border-box default the new padding
   would eat that measure and could force an extra wrap.
   -------------------------------------------------------------------------- */
html[data-theme="terminal"] .hero:not(.hero33) h1{
  --t-pw:.82em;
  position:relative;
  box-sizing:content-box;
  padding-left:var(--t-pw);
}
html[data-theme="terminal"] .hero:not(.hero33) h1::before{
  content:">";
  position:absolute;
  top:0; left:0;
  text-shadow:none;
  pointer-events:none;
}
