/* hero.css — 01 / Signal
 *
 * THE SCALING CONTRACT (locked — do not re-derive from screenshots)
 * Reference frame is 1600 x 900, per handoff-2 HERO-DESKTOP.md §1.
 * "Correct" at other window shapes is defined as:
 *
 *   1. The hero is a size container. Every hero length is cqw/cqh, never vw/vh —
 *      a vw includes the scrollbar, so it is wider than the hero box.
 *   2. Portrait scales on a pure height basis and is anchored by BODY CENTRE, which
 *      sits at 72.75% of the PNG's width (the file's left half is empty).
 *   3. Type, columns and watermark use one uniform contain scale: every reference px
 *      becomes min(px/16 cqw, px/9 cqh). Column measure and font size must share
 *      that one basis or they drift apart at non-16:9 shapes.
 *   4. JS reads the hero box, never window.innerWidth.
 *
 * THE FRAME MOVED FROM 1120x630 TO 1600x900 ON 2026-08-07 and the coefficients
 * did not have to change for it — the geometry tokens were already the approved
 * ones, only their px comments were quoted against the old frame. The TYPE was
 * genuinely wrong: M6 and M7 reduced eight sizes in the first handover and only
 * the headline and the watermark were ever applied. handoff-2 restates them as
 * final and they are now here.
 *
 * NO CAP AND NO FLOOR — HERO-DESKTOP.md §7.4 and §7.5, and this reverses a
 * decision this file used to carry. The supporting type was capped at roughly
 * 1.25x reference on the reasoning that a 1920 screen made it clumsy. That
 * reasoning applied to sizes that were 35-55% too large to begin with; at the
 * approved sizes the whole composition — type, columns, portrait — is meant to
 * grow as one image. A cap strands the portrait against the type.
 *
 * §7.5 flags the missing floor as a real exposure rather than an oversight: at
 * 1600x620 the chip and stat labels render at 6.0px. Fixing it means breaking the
 * uniform contain fit, so it is Zsolt's call, not a build decision.
 *
 * The tokens below are that formula applied once, with the reference px in a
 * comment. Add new lengths by running the same division — never by eyeballing.
 *
 * Below 1024px: hero.small.css. The banner and the two menus are chrome.css.
 */

.runway {
  /* 100vh of pinned hero + 210vh of scroll = the 2.1-viewport runway the choreography
     maps progress across. Changing this changes RUN in main.js. */
  height: 310vh;
  position: relative;
}

.hero {
  position: sticky;
  top: 0;
  height: 100vh;
  /* §1. It limits how far the height term can fall; it does NOT raise type —
     see the floor note in the contract above. */
  min-height: 560px;
  overflow: hidden;
  /* Above Clients (z-6), which is pulled up to overlap the hero's exit — see the
     margin-top note in clients.css. Still below all the fixed chrome. */
  z-index: 10;
  container-type: size;
  cursor: crosshair;
  color: var(--near-black);
  /* THE PAPER IS A FLAT --steel-mid (HERO-DESKTOP.md §6 called for a flat
     paper; the value is Zsolt's, 2026-08-14). It was the original steel
     gradient #f2f3f4 -> #e3e6e8 -> #cdd1d5, which is what M3 set out to fix in
     the first handover and what never got applied: red only reads vivid
     against a light, near-flat field. Wash and vignette are separate plates, and
     M24 marked that three-layer arrangement FINAL — a flat warm paper with
     neither was tried and rejected, so do not flatten this further.

     IT WAS #f4f6f7 UNTIL 2026-08-14. Zsolt read that as beige and picked a
     greyer paper from five rendered candidates; the chosen one was #E4E7EA,
     and this is --steel-mid at #e3e6e8 — two levels apart in blue, which is
     imperceptible, and it reuses a token the page already has rather than
     minting a sixth near-identical grey. The hero paper is now one step of the
     same steel scale as the page tiers instead of a value of its own. */
  background: var(--steel-mid);

  /* --- contain-scale tokens: min(px/16 cqw, px/9 cqh) at 1600x900 --------- */
  --inset:      min(3.93cqw,  6.98cqh);   /*  62.9px — frame inset / gutter  */
  --gap:        min(2.14cqw,  3.81cqh);   /*  34.3px — recurring column gap  */
  --pad-y:      min(1.96cqw,  3.49cqh);   /*  31.4px — top bar vertical pad  */
  --sq:         min(0.30cqw,  0.53cqh);   /*   4.8px — menu square           */
  --sq-gap:     min(0.18cqw,  0.32cqh);   /*   2.9px                         */
  --lang-gap:   min(0.63cqw,  1.11cqh);   /*  10.1px                         */
  --top-marker: min(7.50cqw, 13.33cqh);   /* 120.0px                         */
  --top-col:    min(11.79cqw, 20.95cqh);  /* 188.6px                         */
  --col-w:      min(30.36cqw, 53.97cqh);  /* 485.7px                         */
  --rule-w:     min(4.64cqw,  8.25cqh);   /*  74.3px — rule height stays 2px */
  --motto-mt:   min(0.54cqw,  0.95cqh);   /*   8.6px                         */
  --motto-py:   min(0.98cqw,  1.75cqh);   /*  15.7px                         */
  --motto-px:   min(1.16cqw,  2.06cqh);   /*  18.6px                         */
  --stats-gap:  min(2.50cqw,  4.44cqh);   /*  40.0px                         */
  --statl-mt:   min(0.63cqw,  1.11cqh);   /*  10.1px                         */
  --wm-top:     min(15.00cqw, 26.67cqh);  /* 240.0px                         */
  --band-h:     min(19.64cqw, 34.92cqh);  /* 314.2px                         */

  /* --- hero-local text tiers ----------------------------------------------
     Both differ from the site tokens ON PURPOSE, and only here. The hero's
     paper is --steel-mid, lighter than the #cdd1d5 the page tiers are measured
     against, so a value that fails there passes here. --grey-stat was moved off
     #565e67 site-wide precisely because it measures 4.28:1 on #cdd1d5; on this
     paper the same colour still clears AA and the handoff specifies it.

     Figures re-measured for the 2026-08-14 paper change. Both tiers lost about
     an eighth of their ratio and both still pass; the lighter one is the
     binding constraint and has 0.75 to spare. Do not darken the paper further
     without re-checking this pair. */
  --hero-body:  #3d454e;                  /*  7.76:1 on --steel-mid (was 8.97) */
  --hero-statl: #565e67;                  /*  5.25:1 on --steel-mid (was 6.07) */

  /* --- type ---------------------------------------------------------------
     NO CAPS — HERO-DESKTOP.md §7.4. Reference px is at 1600x900; multiply by
     S = min(w/1600, h/900). The rendered table in §5 is the acceptance test.

     FLOORS, added 2026-08-07 on Zsolt's instruction. §7.5 flags the missing
     floor as a real exposure and leaves the decision to him: at 1600x620 the
     chip and the stat labels render at 5.9px.

     THE FLOOR IS THE APPROVED REFERENCE SIZE, not an accessibility minimum, and
     that choice is the point. §7.5 suggests 11px, but the chip is APPROVED at
     8.6px — an 11px floor would make the hero larger than the design Zsolt
     signed off, on every screen below 1600x900. Flooring at the reference size
     instead means:

       · nothing changes at or above 1600x900 — the floor equals the value;
       · nothing ever renders SMALLER than it does on the approved screen;
       · the worst case goes from 5.9px to 8.6px.

     Only the small tiers are floored. The headline, the watermark and the stat
     figures keep a pure contain fit — they never approach an illegible size, and
     flooring display type would break the composition against the portrait,
     which is what §7.4 warns about.

     Body copy is floored at 12px rather than at its 13.6px reference: a partial
     floor, because it is a wrapping paragraph rather than a one-line label. Its
     measure is in `ch`, so it scales with the font and the wrap does not change.

     **THIS IS NOT AN ACCESSIBILITY FIX.** 8.6px uppercase mono at .16em is below
     every guideline, and it is the approved size. Getting the micro-type to 11px
     means raising the REFERENCE sizes, which is a decision for the designer, not
     a floor added in the build. */
  --fs-brand:  max(12.2px, min(0.76cqw,  1.35cqh));  /*  12.2px — logo            */
  --fs-hud:    max(10.7px, min(0.67cqw,  1.19cqh));  /*  10.7px — menu + EN/HU    */
  --fs-marker: max(10.1px, min(0.63cqw,  1.11cqh));  /*  10.1px — eyebrow, kicker */
  --fs-h1:              min(4.46cqw,  7.94cqh);      /*  71.4px — headline        */
  --fs-body:   max(12.0px, min(0.85cqw,  1.51cqh));  /*  13.6px — both lanes      */
  --fs-motto:  max( 8.6px, min(0.54cqw,  0.95cqh));  /*   8.6px — strapline chip  */
  --fs-stat:            min(1.79cqw,  3.17cqh);      /*  28.6px — stat figures    */
  --fs-statl:  max( 8.6px, min(0.54cqw,  0.95cqh));  /*   8.6px — stat labels     */
  --fs-wm:              min(14.11cqw, 25.08cqh);     /* 225.8px — watermark       */
}


/* =========================================================================
   Background plates — z-0 / z-1 / z-2
   ========================================================================= */

.hero__plate { position: absolute; inset: 0; will-change: transform; }
/* THE CENTRE WASH — one soft white radial, HERO-DESKTOP.md §6. It was two
   plates: a harder white at .96/.52 and a blue-grey pool bottom-right. Both
   graded the paper, and a graded field is what costs the red bar its bite. */
.hero__plate--key  { z-index: 0;
  background: radial-gradient(46% 52% at 42% 26%, rgba(255,255,255,.85) 0%, rgba(255,255,255,0) 72%);
}
.hero__plate--far  { z-index: 0; }
.hero__plate--near { z-index: 2; }

.hero__watermark {
  position: absolute;
  left: 0; right: 0;
  top: var(--wm-top);
  z-index: 1;
  text-align: center;
  font-family: var(--display);
  font-weight: 900;
  font-size: var(--fs-wm);
  line-height: .82;
  letter-spacing: -.05em;
  text-transform: uppercase;
  color: rgba(96, 112, 130, .15);
  filter: blur(2.6px);
  white-space: nowrap;
  will-change: transform;
  animation: omIn 2400ms ease 560ms both;
}


/* =========================================================================
   Figure FX — z-4. Contact shadows are pure cqh and centred, per the contract.
   ========================================================================= */

.figfx {
  position: absolute; inset: 0; z-index: 4;
  pointer-events: none;
  will-change: transform, opacity;
}
.figfx__contact {
  position: absolute; left: 50%;
  border-radius: 50%;
}
.figfx__contact--wide {
  bottom: 10.48cqh; width: 68.25cqh; height: 3.81cqh; margin-left: -34.13cqh;
  background: radial-gradient(ellipse at 50% 50%, rgba(20,28,40,.26), transparent 72%);
}
.figfx__contact--tight {
  bottom: 11.11cqh; width: 30.16cqh; height: 1.90cqh; margin-left: -17.46cqh;
  background: radial-gradient(ellipse at 50% 50%, rgba(14,20,30,.4), transparent 74%);
  filter: blur(3px);
}
.figfx__cast, .figfx__bloom {
  position: absolute;
  left: calc(52.2cqw - 103.93cqh);
  bottom: 0;
  width: 142.86cqh;
  height: auto;
  /* The portrait scales on a PURE HEIGHT basis and is deliberately wider than the
     frame at aspect ratios taller than 16:9. The global img{max-width:100%} would
     clamp it to the frame width and drag his body centre off the 52.2% anchor. */
  max-width: none;
}
.figfx__cast {
  transform-origin: 38% 100%;
  transform: skewX(34deg) scaleY(.3);
  filter: brightness(0) blur(15px);
  opacity: .12;
}
.figfx__bloom {
  filter: brightness(0) invert(1) blur(26px);
  opacity: .3;
}


/* =========================================================================
   z-5 — vignette, motto plates, red bar.
   DOM order in index.html decides paint order here; z-index does not.
   ========================================================================= */

.vignette {
  position: absolute; inset: 0; z-index: 5;
  pointer-events: none;
  will-change: opacity;
}
.vignette > * { position: absolute; inset: 0; }
/* THE EDGE VIGNETTE — ONE gradient, and a tenth of what was here.
   HERO-DESKTOP.md §6 specifies a single edge vignette reaching .075 at the
   corners. This layer carried four plates: a radial to .3, a .14 top band, a
   .34 diagonal sheen and a .13 bottom band — roughly three times the shading,
   darkening the paper exactly where the bar sits, which is what M3 diagnosed as
   making the red read pale.

   The other three keep their elements and simply stop painting: the markup is
   frozen, and `background: none` is the whole of the change. Restoring any of
   them is one line, so nothing is lost. */
.vignette__radial { background: radial-gradient(118% 112% at 48% 44%, rgba(18,28,40,0) 64%, rgba(18,28,40,.035) 86%, rgba(18,28,40,.075) 100%); }
.vignette__top    { background: none; }
.vignette__sheen  { background: none; }
.vignette__band   { inset: auto 0 0 0; height: var(--band-h); background: none; }

.mottolayer {
  position: absolute; inset: 0; z-index: 5;
  pointer-events: none;
  will-change: transform, opacity;
}
.mottolayer--knockout {
  color: #fff;
  will-change: clip-path, transform, opacity;
  clip-path: inset(0 50% 0 50%);  /* overwritten every frame by main.js */
}

.motto {
  box-sizing: border-box;
  white-space: nowrap;
  font-family: var(--hud);
  font-weight: 500;
  font-size: var(--fs-motto);
  line-height: 1.5;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--hero-body);
  background: rgba(255, 255, 255, .82);
  border: 1px solid var(--hair-on-light);
  padding: var(--motto-py) var(--motto-px);
}
/* The two visible plates are absolutely positioned; main.js mirrors them onto the
   hidden in-flow spacer's layout offsets. */
.mottolayer .motto {
  position: absolute; left: 0; top: 0;
  animation: omRise 1350ms var(--ease-out) 1180ms both;
}
.motto--knockout {
  background: none;
  border-color: rgba(255, 255, 255, .5);
  color: #fff;
}
/* In-flow spacer: occupies the column so the plates have a position to mirror,
   but never paints. */
.motto--spacer {
  visibility: hidden;
  /* CONTENT WIDTH, not the full lane. main.js mirrors this spacer's box onto the
     two painted plates, so its width IS the chip's width — at `100%` the chip
     ran the whole 485.7px copy lane with the text ending a third of the way in.
     The prototype's chip is 331px at 1600x900: the strapline plus its padding
     and nothing more. `nowrap` on .motto is what makes max-content meaningful.

     NO `max-width: 100%`. Once the chip's type is floored (see --fs-motto) its
     text stops shrinking while the lane keeps going, so at 1024x640 the two met
     exactly and the clamp started cutting a nowrap line. The lane governs the
     PARAGRAPH's measure; the chip is a one-line label that is allowed to be
     wider than it. Verified it stays inside the hero at every frame down to the
     768px desktop edge. */
  width: max-content;
  margin-top: var(--motto-mt);
}

.bar {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 100%;
  z-index: 5;
  /* background: declared once in main.css, with the display-p3 uplift beside
     it. Repainting it here would win on source order and kill the uplift. */
  pointer-events: none;
  transform-origin: 0 50%;
  will-change: transform;
  transform: translateX(50cqw) scaleX(.002);
}


/* =========================================================================
   Portrait — z-6
   ========================================================================= */

.fig {
  position: absolute; inset: 0; z-index: 6;
  will-change: transform, opacity;
}
.fig img {
  position: absolute;
  left: calc(52.2cqw - 103.93cqh);
  bottom: 0;
  width: 142.86cqh;   /* = 95% of frame height at any aspect */
  height: auto;
  max-width: none;    /* see .figfx__cast — the height basis must not be clamped */
  animation: omFig 1800ms var(--ease-out) 80ms both;
}


/* =========================================================================
   Type layer — z-7, and its white knockout clone at z-8
   ========================================================================= */

.lift {
  position: absolute; inset: 0; z-index: 7;
  will-change: transform, opacity;
}

.topbar {
  position: absolute; left: 0; right: 0; top: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--pad-y) var(--inset);
  animation: omIn 1200ms ease 220ms both;
}
.topbar__brand {
  font-family: var(--hud); font-weight: 800;
  font-size: var(--fs-brand); line-height: 1;
  letter-spacing: .22em; text-transform: uppercase;
}
.topbar__dot { color: var(--red); }
.topbar__right { display: flex; align-items: center; gap: var(--gap); }

.langsel {
  display: flex; align-items: center; gap: var(--lang-gap);
  font-family: var(--hud); font-weight: 500;
  font-size: var(--fs-hud); line-height: 1;
  letter-spacing: .14em; text-transform: uppercase;
}
.lang { cursor: pointer; color: var(--lang-off); transition: color 160ms ease; }
.lang.is-active { color: var(--near-black); }
.lang:hover { color: var(--red); }
.langsel__sep { color: var(--lang-sep); }

.menubtn {
  display: flex; align-items: center; gap: 10px;
  cursor: pointer;
  font-family: var(--hud); font-weight: 500;
  font-size: var(--fs-hud); line-height: 1;
  letter-spacing: .14em; text-transform: uppercase;
}
.menubtn__grid {
  display: grid;
  grid-template-columns: var(--sq) var(--sq);
  grid-template-rows: var(--sq) var(--sq);
  gap: var(--sq-gap);
}
.menubtn__grid i { background: var(--red); }

.marker {
  position: absolute;
  top: var(--top-marker);
  font-family: var(--hud); font-weight: 500;
  font-size: var(--fs-marker); line-height: 1;
  letter-spacing: .18em; text-transform: uppercase;
}
.marker--left {
  left: var(--inset);
  display: flex; align-items: center; gap: 10px;
  animation: omSlideL 1200ms var(--ease-out) 520ms both;
}
.marker--right {
  right: var(--inset);
  color: var(--red);
  animation: omSlideR 1200ms var(--ease-out) 700ms both;
}
.marker__num { color: var(--red); }
.marker__slash, .marker__label { color: var(--grey-marker); }

.col {
  position: absolute;
  top: var(--top-col);
  width: var(--col-w);
  display: flex; flex-direction: column;
  gap: var(--gap);
}
.col--left  { left: var(--inset); align-items: flex-start; }
.col--right { right: var(--inset); align-items: flex-end; text-align: right;
              animation: omSlideR 1350ms var(--ease-out) 1460ms both; }
.col__group {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: var(--gap);
  align-self: stretch;
  animation: omRise 1350ms var(--ease-out) 1180ms both;
}

.h1 {
  margin: 0;
  font-family: var(--display); font-weight: 900;
  font-size: var(--fs-h1);
  line-height: .92;
  letter-spacing: -.034em;
  text-transform: uppercase;
  text-wrap: pretty;
  color: var(--near-black);
  animation: omRise 1350ms var(--ease-out) 900ms both;
}
.h1__grey { color: var(--grey-accent); }
/* inline-block so the rotator can transform it without disturbing the line */
.h1__verb { display: inline-block; will-change: transform, opacity, filter; }

.rule { width: var(--rule-w); height: 2px; background: var(--red); flex: none; }

.sub, .proof {
  margin: 0;
  font-family: var(--body); font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--hero-body);
}
.sub   { max-width: 31ch; }
.proof { max-width: 30ch; }

.stats { display: flex; justify-content: flex-end; gap: var(--stats-gap); }
.stat__v {
  font-family: var(--display); font-weight: 900;
  font-size: var(--fs-stat); line-height: 1;
  color: var(--red);
}
.stat__l {
  font-family: var(--hud); font-weight: 500;
  font-size: var(--fs-statl); line-height: 1.3;
  letter-spacing: .14em;
  color: var(--hero-statl);
  margin-top: var(--statl-mt);
}

/* --- the knockout clone -------------------------------------------------
   The whole type layer again in white, clipped to the bar's exact span, so type
   reads white wherever the bar is behind it. main.js writes the bar transform and
   this clip-path in the same frame — never put a CSS transition on either. */
.lift--knockout {
  z-index: 8;
  color: #fff;
  pointer-events: none;
  will-change: clip-path, transform, opacity;
  clip-path: inset(0 50% 0 50%);
}
.lift--knockout .topbar__dot,
.lift--knockout .marker__num,
.lift--knockout .marker__slash,
.lift--knockout .marker__label,
.lift--knockout .marker--right,
.lift--knockout .h1,
.lift--knockout .h1__grey,   /* "solid" is not greyed in the knockout */
.lift--knockout .sub,
.lift--knockout .proof,
.lift--knockout .stat__v,
.lift--knockout .stat__l     { color: #fff; }
.lift--knockout .rule,
.lift--knockout .menubtn__grid i { background: #fff; }
.lift--knockout .lang            { color: rgba(255, 255, 255, .5); }
.lift--knockout .lang.is-active  { color: #fff; }
.lift--knockout .langsel__sep    { color: rgba(255, 255, 255, .4); }


/* =========================================================================
   Reveal layer (z-7) and edge rails (z-9)
   ========================================================================= */

.revclip {
  position: absolute; inset: 0; z-index: 7;
  color: #fff; pointer-events: none;
  will-change: clip-path;
  clip-path: inset(0 50% 0 50%);
}
.reveal {
  position: absolute; inset: 0;
  opacity: 0;
  will-change: transform, opacity;
}

.rail {
  position: absolute; left: 0; right: 0;
  height: 4px; z-index: 9;
  /* background: declared once in main.css, with the display-p3 uplift beside
     it. Repainting it here would win on source order and kill the uplift. */
  pointer-events: none;
  opacity: 0;
  transition: opacity 260ms ease;
}
.rail--top    { top: 0; }
.rail--bottom { bottom: 0; }
