
  @font-face{
    font-family:'Lexend';
    src:url('lexend-latin.woff2') format('woff2');
    font-weight:100 900; font-style:normal; font-display:swap;
    unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
  }

  /* ── design unit: 1u === 1px on the 1600 × 880 reference frame ───────── */
  .mh{
    --mh-top: 112px;      /* header + utility strip; JS re-measures */
    --u: min(calc(100vw / 1600), calc((100svh - var(--mh-top)) / 880));

    --ink:            #ffffff;
    --ink-soft:       rgba(255,255,255,.62);
    --ink-faint:      rgba(255,255,255,.44);
    --rule:           rgba(255,255,255,.055);

    --card:           #f0f1f2;
    --card-ink:       #212224;
    --card-label:     #5f6165;

    --ease: cubic-bezier(.22,.61,.36,1);
    --ease-out: cubic-bezier(.16,1,.3,1);
  }
  @media (min-width:1900px){ .mh{ --u: min(calc(1900px / 1600), calc((100svh - var(--mh-top)) / 880)); } }

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

  .mh{ background:#0c0f13; }
  .mh{
    font-family:'Lexend',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
    font-weight:300;
    color:var(--ink);
    background:#0c0f13;
    overflow-x:hidden;
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
  }

  /* ── hero shell ──────────────────────────────────────────────────────── */
  .mh{
    position:relative;
    width:100%;
    height:calc(100svh - var(--mh-top));
    min-height:calc(880 * var(--u));
    overflow:hidden;
    isolation:isolate;
    /* the reference screen reads a near-flat #47484a corner to corner —
       all the modelling comes from the light pool the root sits in */
    background:
      radial-gradient(64% 52% at 27% 84%, rgba(184,196,214,.055) 0%, rgba(184,196,214,0) 72%),
      radial-gradient(70% 60% at 92% 8%,  rgba(22,24,26,.10) 0%, rgba(22,24,26,0) 68%),
      #14171b;
  }
  /* The floor of light the root stands in. Sampled off the reference: the
     background climbs from 73 luma at the nav to ~128 at y 850, brightest
     around the middle of the bottom edge. */
  .mh::after{
    content:'';
    position:absolute; inset:0;
    background:
      radial-gradient(72% 44% at 50% 117%, rgba(198,210,226,.30) 0%, rgba(198,210,226,.12) 42%, rgba(198,210,226,.025) 72%, rgba(198,210,226,0) 88%),
      linear-gradient(180deg, rgba(235,237,239,0) 54%, rgba(235,237,239,.03) 78%, rgba(235,237,239,.085) 100%);
    pointer-events:none; z-index:0;
  }

  /* The whole composition lives on a centred 1600 × 880 stage.
     Centred with margins rather than a transform on purpose: a transform would
     open a stacking context and trap every child below #scene. */
  .mh .stage{
    position:absolute; left:50%; top:50%;
    margin-left:calc(-800 * var(--u));
    margin-top:calc(-408 * var(--u));
    width:calc(1600 * var(--u));
    height:calc(880 * var(--u));
  }

  /* ── column guides (z 1) ─────────────────────────────────────────────── */
  .mh .guides{ position:absolute; inset:calc(-40 * var(--u)) 0; z-index:1; pointer-events:none; }
  .mh .guides i{
    position:absolute; top:0; bottom:0; width:1px;
    background:linear-gradient(180deg, rgba(255,255,255,0) 0%, var(--rule) 12%, var(--rule) 78%, rgba(255,255,255,0) 100%);
  }

  /* ── ghost wordmark (z 1) ────────────────────────────────────────────── */
  .mh .ghost{
    position:absolute; z-index:1;
    left:calc(6 * var(--u)); bottom:calc(-64 * var(--u));
    font-size:calc(310 * var(--u));
    line-height:.78;
    font-weight:400;
    letter-spacing:calc(30 * var(--u));
    color:rgba(255,255,255,.055);
    white-space:nowrap; user-select:none; pointer-events:none;
  }

  /* ── three.js canvas (z 3 — above card 1, below everything else) ─────── */
  .mh #scene{
    position:absolute; inset:0; z-index:3;
    width:100%; height:100%;
    pointer-events:none;
    opacity:0; transition:opacity .7s var(--ease);
  }
  .mh.scene-ready #scene{ opacity:1; }

  /* ── nav: a floating dock (z 5) ──────────────────────────────────────
     A centred capsule of pills that magnify as the pointer nears them, over
     a rim highlight that tracks where the pointer is — the dock idiom from
     ascii-page-transition, in this page's palette and unit system.
     The wrapper does the centring so the capsule itself is free to carry the
     pointer-parallax transform; putting both on one element means whichever
     is written last wins and the dock jumps out of centre. */
  .mh .dock-wrap{
    position:absolute; z-index:5;
    top:calc(38 * var(--u)); left:0; right:0;
    display:flex; justify-content:center;
    pointer-events:none;
  }
  .mh .dock{
    pointer-events:auto;
    display:flex; align-items:flex-start; gap:calc(3 * var(--u));
    height:calc(46 * var(--u));
    padding:calc(5 * var(--u));
    border-radius:calc(14 * var(--u));
    border:1px solid rgba(255,255,255,.11);
    /* No backdrop-filter. It sits over a canvas that repaints every frame,
       so the backdrop has to be re-sampled and re-blurred every frame too —
       measured at ~20 fps off the whole page, and the radius made no
       difference because the cost is the extra pass, not the blur. A
       translucent panel with a lit top edge reads the same at this size. */
    background:
      linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,0) 42%),
      rgba(34,35,37,.74);
    box-shadow:0 calc(8 * var(--u)) calc(22 * var(--u)) rgba(10,11,12,.30),
               inset 0 1px rgba(255,255,255,.06);
    isolation:isolate;
  }
  /* Anchored at the top so growth runs downward, out of the headline's way —
     a dock that grew from its centre would push into the nav's own row. */
  .mh .dock-item{
    position:relative; z-index:6;
    display:inline-flex; align-items:center; justify-content:center;
    flex:none;
    height:calc(36 * var(--u));
    gap:calc(8 * var(--u));
    padding:0 calc(13 * var(--u));
    transform-origin:50% 0;
    border:1px solid transparent;
    border-radius:calc(10 * var(--u));
    background:rgba(255,255,255,.04);
    color:var(--ink-faint);
    text-decoration:none; cursor:pointer;
    font-family:inherit;
    font-size:calc(11 * var(--u)); font-weight:500;
    letter-spacing:calc(1.5 * var(--u)); text-transform:uppercase;
    white-space:nowrap;
    will-change:width,height,transform;
    transition:color .18s var(--ease), border-color .2s var(--ease), background .2s var(--ease);
  }
  /* A magnified pill hangs below the capsule, so it needs to be its own
     opaque tile — a translucent white wash at that size reads as a milky
     rectangle stuck to the bar rather than as a key lifting off it. */
  .mh .dock-item[data-near="true"]{
    z-index:7;
    color:var(--ink);
    border-color:rgba(255,255,255,.19);
    background:rgba(31,32,34,.94);
    box-shadow:0 calc(7 * var(--u)) calc(16 * var(--u)) rgba(10,11,12,.30);
  }
  .mh .dock-item .glyph{
    width:calc(14 * var(--u)); height:calc(14 * var(--u)); flex:none;
    opacity:.66; transition:opacity .18s var(--ease);
  }
  .mh .dock-item .glyph svg{
    display:block; width:100%; height:100%;
    fill:none; stroke:currentColor; stroke-width:1.25;
    stroke-linecap:round; stroke-linejoin:round;
  }
  .mh .dock-item[data-near="true"] .glyph{ opacity:1; }

  /* the mark is the dock's anchor: a solid pale tile, the one opaque thing
     in a bar made of glass */
  .mh .dock-mark{
    width:calc(36 * var(--u)); padding:0;
    background:#eaecee; border-color:#eaecee; color:#212224;
    overflow:hidden;
  }
  .mh .dock-mark svg{ width:58%; height:58%; display:block; fill:currentColor; }
  /* the near state paints .dock-item white, which on the pale mark tile
     would be a white glyph on a white ground */
  .mh .dock-mark[data-near="true"]{ background:#fff; border-color:#fff; color:#1a1b1c; }

  /* the current section wears the cards' paper, so the nav and the cards
     read as the same material */
  .mh .dock-item.is-active{
    background:var(--card); border-color:var(--card); color:var(--card-ink);
    box-shadow:0 calc(6 * var(--u)) calc(16 * var(--u)) rgba(12,13,14,.24);
  }
  .mh .dock-item.is-active .glyph{ opacity:.8; }
  .mh .dock-item--enter{ color:var(--ink); background:rgba(255,255,255,.075); }

  /* ── specular rim ────────────────────────────────────────────────────
     A conic gradient masked down to the border, whose start angle points at
     the pointer and whose opacity falls off with distance. It is the reason
     the glass reads as a lit edge rather than as a flat translucent box. */
  .mh [data-spec]{ --spec-angle:2.4rad; --spec-bright:0; }
  .mh [data-spec]::after{
    content:''; position:absolute; inset:-1px; z-index:5;
    padding:1px; border-radius:inherit; pointer-events:none;
    opacity:var(--spec-bright);
    background:conic-gradient(from var(--spec-angle) at 50% 50%,
      rgba(237,239,241,0) 0deg, rgba(237,239,241,.08) 14deg, rgba(237,239,241,.95) 28deg,
      rgba(237,239,241,.16) 46deg, rgba(237,239,241,0) 68deg, rgba(237,239,241,0) 180deg,
      rgba(237,239,241,.08) 194deg, rgba(237,239,241,.95) 208deg, rgba(237,239,241,.16) 226deg,
      rgba(237,239,241,0) 248deg, rgba(237,239,241,0) 360deg);
    -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite:xor; mask-composite:exclude;
  }
  .mh .dock{ position:relative; }

  /* ── hero copy (z 4) ─────────────────────────────────────────────────── */
  .mh .headline{
    position:absolute; z-index:4;
    left:calc(64 * var(--u)); top:calc(214 * var(--u));
    font-size:calc(63 * var(--u)); line-height:calc(65 * var(--u));
    font-weight:300; letter-spacing:calc(-0.4 * var(--u));
    color:var(--ink);
  }
  /* No overflow clip: cropping a 63u face to wipe it in cuts the descenders
     of "Step" and "living" at the moment they land. The padding stays even
     though the clip is gone — it set the two lines' metrics, and removing it
     would shift line two. */
  .mh .headline span{ display:block; padding-bottom:.04em; }
  .mh .headline span i{ display:inline-block; font-style:normal; }

  .mh .mhlede{
    position:absolute; z-index:4;
    left:calc(66 * var(--u)); top:calc(402 * var(--u));
    width:calc(408 * var(--u));
    font-size:calc(16.5 * var(--u)); line-height:calc(22 * var(--u));
    font-weight:300; color:var(--ink-soft);
  }

  /* ── liquid-metal controls ──────────────────────────────────────────
     The original five-pass WebGL2 renderer now mounts directly in this
     document. Its canvas, sizing, glass plate, shader constants and input
     model are unchanged; only the iframe boundary has been removed. */
  .mh .mhpill-clip{
    position:absolute; z-index:4;
    left:calc(272 * var(--u)); top:calc(556 * var(--u));
    width:calc(410 * var(--u)); height:calc(270 * var(--u));
    margin:calc(-135 * var(--u)) 0 0 calc(-205 * var(--u));
    clip-path:inset(calc(72 * var(--u)) calc(60 * var(--u))
                    calc(26 * var(--u)) calc(60 * var(--u)) round calc(62 * var(--u)));
  }
  .mh .mhpill{
    position:absolute; inset:0; --mr:calc(150 * var(--u));
    display:grid; place-items:center;
  }

  .mh .liquid-stage{
    --lu:calc(var(--h) / 516);
    --bh:var(--h);
    --pad:calc(900 * var(--lu));
    position:relative;
    width:max-content; height:max-content;
    padding:var(--pad);
    display:grid; place-items:center;
    touch-action:manipulation;
    font-family:'Lexend','Inter',-apple-system,BlinkMacSystemFont,'Helvetica Neue',Arial,sans-serif;
    font-optical-sizing:auto;
    -webkit-font-smoothing:antialiased;
  }
  .mh .liquid-stage--explore{ --h:calc(60.156 * var(--u)); }
  .mh .liquid-stage--play{ --h:calc(88.2288 * var(--u)); }

  .mh .liquid-plate{
    position:absolute;
    inset:var(--pad);
    border-radius:999px;
    background:
      linear-gradient(180deg, rgba(255,255,255,.085), rgba(255,255,255,.014) 44%, rgba(255,255,255,0) 64%),
      rgba(11,11,11,.42);
    box-shadow:
      0 calc(var(--h) * 0.08) calc(var(--h) * 0.18) rgba(0,0,0,.38),
      0 calc(var(--h) * 0.24) calc(var(--h) * 0.50) rgba(0,0,0,.28),
      0 calc(var(--h) * 0.48) calc(var(--h) * 0.96) rgba(0,0,0,.16),
      inset 0 1px 0 rgba(255,255,255,.13),
      inset 0 calc(var(--h) * -0.02) calc(var(--h) * 0.05) rgba(255,255,255,.05);
    transition:box-shadow .38s cubic-bezier(.22,.61,.36,1),
               background .38s cubic-bezier(.22,.61,.36,1);
  }
  .mh .liquid-stage.hot .liquid-plate{
    background:
      linear-gradient(180deg, rgba(255,255,255,.105), rgba(255,255,255,.02) 44%, rgba(255,255,255,0) 64%),
      rgba(9,9,9,.50);
    box-shadow:
      0 calc(var(--h) * 0.10) calc(var(--h) * 0.22) rgba(0,0,0,.44),
      0 calc(var(--h) * 0.32) calc(var(--h) * 0.66) rgba(0,0,0,.34),
      0 calc(var(--h) * 0.66) calc(var(--h) * 1.32) rgba(0,0,0,.20),
      inset 0 1px 0 rgba(255,255,255,.17),
      inset 0 calc(var(--h) * -0.02) calc(var(--h) * 0.05) rgba(255,255,255,.06);
  }
  .mh .liquid-fx{ position:absolute; inset:0; width:100%; height:100%; display:block; }

  .mh .liquid-button{
    position:relative;
    height:var(--bh);
    border:0; background:none;
    border-radius:999px;
    display:flex; align-items:center; justify-content:center;
    color:#fff;
    font-family:inherit; font-weight:500; line-height:1; letter-spacing:0;
    cursor:pointer; -webkit-tap-highlight-color:transparent; outline:none;
  }
  .mh .liquid-button:focus-visible{
    outline:calc(4 * var(--lu)) solid rgba(255,255,255,.55);
    outline-offset:calc(10 * var(--lu));
  }
  .mh .liquid-button .ico{ display:block; flex:none; overflow:visible; }
  .mh .liquid-button .lbl{ display:block; transform:translateY(calc(2 * var(--lu))); }
  .mh .liquid-button--explore{
    padding:0 calc(224 * var(--lu)) 0 calc(95 * var(--lu));
    gap:calc(112 * var(--lu));
    font-size:calc(140 * var(--lu));
  }
  .mh .liquid-button--explore .ico{
    width:calc(150 * var(--lu)); height:calc(150 * var(--lu));
  }
  .mh .liquid-button--play{
    width:var(--bh); height:var(--bh); padding:0;
  }
  .mh .liquid-button--play .ico{
    width:calc(176 * var(--lu)); height:calc(176 * var(--lu));
    margin-left:calc(14 * var(--lu));
  }
  .mh .liquid-button--play .lbl{ display:none; }
  .mh .liquid-stage.press .liquid-plate{
    background:
      linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.01) 44%, rgba(255,255,255,0) 64%),
      rgba(8,8,8,.55);
    box-shadow:
      0 calc(var(--h) * 0.04) calc(var(--h) * 0.11) rgba(0,0,0,.46),
      0 calc(var(--h) * 0.13) calc(var(--h) * 0.32) rgba(0,0,0,.36),
      0 calc(var(--h) * 0.27) calc(var(--h) * 0.62) rgba(0,0,0,.22),
      inset 0 1px 0 rgba(255,255,255,.10);
    transition-duration:.10s;
  }

  /* ── play button (z 4) ─────────────────────────────────────────────── */
  .mh .play-wrap{
    position:absolute; z-index:4; pointer-events:none;
    left:calc(187 * var(--u)); top:calc(431 * var(--u));
    width:calc(170 * var(--u)); height:calc(170 * var(--u));
  }
  .mh .play-wrap > *{ pointer-events:auto; }
  .mh .play-clip{
    position:absolute; left:50%; top:50%;
    width:calc(396 * var(--u)); height:calc(396 * var(--u));
    margin:calc(-198 * var(--u)) 0 0 calc(-198 * var(--u));
    clip-path:inset(calc(131 * var(--u)) calc(106 * var(--u))
                    calc(73 * var(--u)) calc(106 * var(--u)) round calc(92 * var(--u)));
  }
  .mh .play-glass{ position:absolute; inset:0; display:grid; place-items:center; }
  .mh .play-ring{
    position:absolute; inset:0; pointer-events:none;
    border:1px solid rgba(255,255,255,.17); border-radius:50%;
  }
  .mh .play-ring::after{
    content:''; position:absolute; inset:calc(-1 * var(--u));
    border:1px solid rgba(255,255,255,.32); border-radius:50%;
    opacity:0; transform:scale(.86);
    transition:opacity .7s var(--ease), transform .9s var(--ease-out);
  }
  .mh .play-clip:hover ~ .play-ring::after, .mh .play-clip:focus-within ~ .play-ring::after{ opacity:1; transform:scale(1.06); }

  /* ── stats (z 4) ─────────────────────────────────────────────────────── */
  .mh .stat{ position:absolute; z-index:4; display:flex; align-items:flex-start; gap:calc(9 * var(--u)); }
  .mh .stat--a{ left:calc(68 * var(--u)); top:calc(672 * var(--u)); }
  .mh .stat--b{ left:calc(288 * var(--u)); top:calc(672 * var(--u)); }
  .mh .stat .mark{ width:calc(32 * var(--u)); height:calc(32 * var(--u)); flex:none; margin-top:calc(2 * var(--u)); color:rgba(255,255,255,.34); }
  .mh .stat .mark svg{ width:100%; height:100%; display:block; }
  .mh .stat dt{ font-size:calc(13.5 * var(--u)); font-weight:300; color:var(--ink-soft); line-height:calc(19 * var(--u)); }
  .mh .stat dt, .mh .stat dd{ text-shadow:0 calc(2 * var(--u)) calc(16 * var(--u)) rgba(10,11,12,.6); }
  .mh .stat .mark svg{ filter:drop-shadow(0 calc(2 * var(--u)) calc(10 * var(--u)) rgba(10,11,12,.6)); }
  .mh .stat dd{ font-size:calc(13.5 * var(--u)); font-weight:600; color:var(--ink); line-height:calc(21 * var(--u)); }

  /* ── cards ───────────────────────────────────────────────────────────── */
  .mh .mhcard{
    position:absolute;
    background:var(--card); border-radius:calc(46 * var(--u));
    box-shadow:0 calc(30 * var(--u)) calc(70 * var(--u)) rgba(15,17,19,.30);
    transition:box-shadow .8s var(--ease);
  }
  /* The source left this at z-index:auto on purpose, so #scene painted over
     the card's shoulder. That reads well when what drapes across it is a
     thin root; the re-traced beam is as wide as the card and buried the
     heading, so the card is lifted clear. .mhcard--stove already sits at z 4. */
  .mh .mhcard--about{
    z-index:4;
    left:calc(1146 * var(--u)); top:calc(150 * var(--u));
    width:calc(330 * var(--u)); height:calc(305 * var(--u));
  }
  .mh .mhcard--stove{
    z-index:4; will-change:transform;
    left:calc(1148 * var(--u)); top:calc(492 * var(--u));
    width:calc(328 * var(--u)); height:calc(310 * var(--u));
  }
  .mh .mhcard .label{
    position:absolute; left:calc(38 * var(--u));
    font-size:calc(15.5 * var(--u)); font-weight:300; color:var(--card-label);
  }
  .mh .mhcard h2{
    position:absolute; left:calc(38 * var(--u));
    font-size:calc(26.2 * var(--u)); line-height:calc(27 * var(--u));
    font-weight:400; letter-spacing:calc(-0.5 * var(--u)); color:var(--card-ink);
  }
  .mh .mhcard--about .label{ top:calc(152 * var(--u)); }
  .mh .mhcard--about h2{ top:calc(177 * var(--u)); width:calc(142 * var(--u)); }
  .mh .mhcard--stove .label{ top:calc(45 * var(--u)); }
  .mh .mhcard--stove h2{ top:calc(70 * var(--u)); }
  /* Both cards carry a plate. The Field Note reads downward — label, title,
     then the photograph — so its window sits at the foot of the card; the
     Ethos card reads the other way up, so its window is at the head and the
     copy sits under it. Same frame, mirrored. */
  .mh .mhcard figure{
    position:absolute; left:calc(14 * var(--u)); right:calc(14 * var(--u));
    border-radius:calc(34 * var(--u)); overflow:hidden;
    isolation:isolate; background:#282a2d;
  }
  .mh .mhcard--stove figure{ bottom:calc(14 * var(--u)); height:calc(158 * var(--u)); }
  .mh .mhcard--about figure{ top:calc(14 * var(--u)); height:calc(122 * var(--u)); }
  /* The plate is its own depth plane. It travels against the card and the
     mass, so the photograph reads as a small window onto the yard
     rather than as an image glued to the card. */
  .mh .portal-media{
    position:absolute; inset:calc(-9 * var(--u)); z-index:1; display:block;
    will-change:transform,clip-path;
    transform:
      perspective(900px)
      translate3d(calc(var(--px,0) * -11px),calc(var(--py,0) * -7px),0)
      rotateY(calc(var(--px,0) * -1.4deg))
      rotateX(calc(var(--py,0) * .9deg));
    transform-origin:50% 50%;
  }
  .mh .portal-media img{
    width:100%; height:100%; object-fit:cover; display:block;
    transform:scale(1.08);
    filter:saturate(.92) contrast(1.03);
    transition:transform 1.25s var(--ease-out),filter .8s var(--ease);
  }
  .mh .mhcard:hover .portal-media img{ transform:scale(1.13); filter:saturate(1.04) contrast(1.04); }
  .mh .pixel-reveal{
    position:absolute; inset:0; z-index:3; width:100%; height:100%;
    pointer-events:none; opacity:0; mix-blend-mode:screen;
  }
  /* The white scan rides the clip edge, so its centre has to travel the
     media element's box, not the figure's — .portal-media is overscanned by
     9u on every side to give the parallax rotation somewhere to go. Offsetting
     by that 9u in calc() rather than by a translate percentage keeps the
     glow on the edge at every breakpoint, whatever size the plate is. */
  .mh .mhcard figure::after{
    content:''; position:absolute; z-index:2;
    filter:blur(calc(2 * var(--u))); opacity:0; pointer-events:none;
    top:0; bottom:0; width:26%; left:calc(-13% - 9 * var(--u));
    background:linear-gradient(90deg,transparent,rgba(224,226,229,.2) 42%,rgba(250,250,251,.72) 54%,transparent);
  }

  .mh .knob-float{
    position:absolute; z-index:4; pointer-events:none;
    left:calc(1398 * var(--u)); top:calc(377 * var(--u));
    width:calc(58 * var(--u)); height:calc(58 * var(--u));
  }
  .mh .knob-float > *{ pointer-events:auto; }
  .mh .knob--about{ left:0; top:0; }
  .mh .mhcard .knob, .mh .knob--about{
    position:absolute; z-index:4; right:calc(20 * var(--u)); bottom:calc(20 * var(--u));
    width:calc(58 * var(--u)); height:calc(58 * var(--u));
    border:0; border-radius:50%; cursor:pointer;
    background:#fafafb; display:grid; place-items:center;
    box-shadow:0 calc(6 * var(--u)) calc(16 * var(--u)) rgba(15,17,19,.18);
    transition:transform .5s var(--ease-out), background .4s var(--ease);
  }
  .mh .knob--about{ right:auto; bottom:auto; width:calc(58 * var(--u)); height:calc(58 * var(--u)); }
  .mh .mhcard--stove .knob{ width:calc(54 * var(--u)); height:calc(54 * var(--u)); right:calc(26 * var(--u)); bottom:calc(26 * var(--u)); }
  .mh .mhcard .knob svg, .mh .knob--about svg{ width:calc(19 * var(--u)); height:calc(19 * var(--u)); display:block; color:#3d3f42; }
  .mh .mhcard .knob:hover, .mh .knob--about:hover{ transform:scale(1.1) rotate(8deg); background:#fff; }
  .mh .mhcard:hover{ box-shadow:0 calc(38 * var(--u)) calc(84 * var(--u)) rgba(15,17,19,.36); }

  /* ── scroll cue (z 4) ────────────────────────────────────────────────── */
  .mh .scroll{
    position:absolute; z-index:4;
    left:calc(806 * var(--u)); top:calc(706 * var(--u));
    display:flex; align-items:center; gap:calc(12 * var(--u));
    writing-mode:vertical-rl;
    font-size:calc(11 * var(--u)); font-weight:400;
    letter-spacing:calc(4.4 * var(--u));
    color:rgba(255,255,255,.5);
    text-transform:uppercase; text-decoration:none;
  }
  .mh .scroll .track{ position:relative; width:1px; height:calc(56 * var(--u)); background:rgba(255,255,255,.18); overflow:hidden; }
  .mh .scroll .track::after{
    content:''; position:absolute; inset:0 0 auto; height:40%;
    background:rgba(255,255,255,.75);
    animation:trickle 2.6s var(--ease) infinite;
  }
  @keyframes trickle{
    0%   { transform:translateY(-105%); opacity:0; }
    22%  { opacity:1; }
    78%  { opacity:1; }
    100% { transform:translateY(255%); opacity:0; }
  }

  /* ── entrance: everything is wiped in behind a mask ───────────────────
     Transform is reserved for the pointer parallax, so the reveal is done
     with clip-path. Once the intro has run, .intro-done drops the clip
     entirely — a live clip-path would open a stacking context on the About
     card and trap its knob behind the scene. */
  .mh.js .mask{ clip-path:inset(100% 0 0 0 round var(--mr,0px)); }
  .mh.is-ready .mask{
    clip-path:inset(0 0 0 0 round var(--mr,0px));
    transition:clip-path 1.05s var(--ease-out) var(--d,0ms);
  }
  .mh.js .mask-circle{ clip-path:circle(0% at 50% 50%); }
  .mh.is-ready .mask-circle{
    clip-path:circle(76% at 50% 50%);
    transition:clip-path 1.1s var(--ease-out) var(--d,0ms);
  }
  .mh.js .fade{ opacity:0; }
  .mh.is-ready .fade{ opacity:1; transition:opacity 1.3s var(--ease) var(--d,0ms); }

  .mh.intro-done .mask, .mh.intro-done .mask-circle{ clip-path:none; transition:none; }

  .mh .mhcard{ --mr:calc(46 * var(--u)); }

  /* the dock drops in tile by tile; the capsule itself only fades, because
     a clip on it would cut the pills off as they magnify past its edge */
  .mh.js .dock{ opacity:0; }
  .mh.is-ready .dock{ opacity:1; transition:opacity .8s var(--ease) 80ms; }
  .mh.js .dock-item{ clip-path:inset(0 0 105% 0); }
  .mh.is-ready .dock-item{
    clip-path:inset(0 0 -30% 0);
    transition:clip-path .9s var(--ease-out) var(--d,0ms),
               color .18s var(--ease), border-color .2s var(--ease), background .2s var(--ease);
  }
  .mh.intro-done .dock-item{ clip-path:none; }

  /* A short rise under a fade rather than a full-height wipe: with nothing
     cropping it, a 105% travel would start line one sitting on top of line
     two. .headline itself carries the pointer parallax, so the transform has
     to go on the inner <i>. */
  .mh.js .headline span i{ opacity:0; transform:translateY(calc(16 * var(--u))); }
  .mh.is-ready .headline span i{
    opacity:1; transform:none;
    transition:opacity 1.05s var(--ease) var(--d,0ms),
               transform 1.25s var(--ease-out) var(--d,0ms);
  }

  /* Each plate resolves like a low-bandwidth botanical transmission: a
     stepped clip exposes the photograph while sampled pixel-dots gather along
     the advancing edge (the dots themselves are painted by canvas).
     Both plates scan across, the Ethos one a beat ahead of the Field Note. */
  .mh.js .portal-media{ clip-path:inset(0 100% 0 0 round calc(25 * var(--u))); }
  .mh.is-ready .mhcard--about .portal-media{ animation:portal-cut 1.45s steps(12,end) .92s both; }
  .mh.is-ready .mhcard--stove .portal-media{ animation:portal-cut 1.45s steps(12,end) 1.08s both; }
  .mh.is-ready .mhcard--about figure::after{ animation:portal-scan 1.45s steps(12,end) .92s both; }
  .mh.is-ready .mhcard--stove figure::after{ animation:portal-scan 1.45s steps(12,end) 1.08s both; }
  .mh.intro-done .portal-media{ clip-path:none; animation:none; }
  @keyframes portal-cut{
    from{ clip-path:inset(0 100% 0 0 round calc(25 * var(--u))); }
    to{ clip-path:inset(0 0 0 0 round calc(25 * var(--u))); }
  }
  /* The glow travels by animating its own offset, not by a translate
     percentage. A translate is a percentage of the glow's width, so the
     distance it covers depends on the plate's proportions — it overshot by
     a quarter of the card here and rode ahead of the edge the whole way.
     In calc() the travel is exactly the media box: 100% of the plate plus
     the 9u of overscan at each end, at every breakpoint. */
  @keyframes portal-scan{
    0%{ left:calc(-13% - 9 * var(--u)); opacity:0; }
    10%{ opacity:.75; }
    88%{ opacity:.55; }
    100%{ left:calc(87% + 9 * var(--u)); opacity:0; }
  }

  /* No clip on the canvas: the root draws itself in behind the survey pulse,
     and a CSS wipe on top of that would be two reveals fighting each other.
     The fade is only here to cover the first compiled frame. */
  .mh.scene-ready #scene{ transition:opacity .45s var(--ease); }

  /* ── pointer parallax ────────────────────────────────────────────────
     --px / --py are written on .hero once per frame (-1…1). Each layer
     declares how far it rides (--pd, px at full deflection) and how much
     it turns (--pr, degrees), which is what gives the plane its depth. */
  .mh .par{
    transform:
      perspective(1400px)
      translate3d(calc(var(--px,0) * var(--pd,0) * -1px),
                  calc(var(--py,0) * var(--pd,0) * -0.62px),
                  0)
      rotateY(calc(var(--px,0) * var(--pr,0) * 1deg))
      rotateX(calc(var(--py,0) * var(--pr,0) * -0.7deg));
  }
  /* the floating knob turns about the About card's centre, not its own,
     so it stays glued to the corner it belongs to */
  .mh .knob-float{ transform-origin:calc(-87 * var(--u)) calc(-74.5 * var(--u)); }
  .mh .mhcard--about{ transform-origin:50% 50%; }

  /* ── keyboard focus ──────────────────────────────────────────────────── */
  .mh a:focus-visible, .mh button:focus-visible{
    outline:2px solid rgba(255,255,255,.85);
    outline-offset:calc(4 * var(--u));
    border-radius:calc(6 * var(--u));
  }
  .mh .mhcard .knob:focus-visible, .mh .knob--about:focus-visible, .mh .play:focus-visible{ outline-color:rgba(25,28,31,.9); }

  @media (prefers-reduced-motion:reduce){
    .mh .mask, .mh .mask-circle, .mh .fade, .mh #scene, .mh .dock, .mh .dock-item, .mh .headline span i{ opacity:1 !important; clip-path:none !important; transform:none !important; transition:none !important; }
    .mh .par{ transform:none !important; }
    .mh .portal-media{ clip-path:none !important; animation:none !important; transform:none !important; }
    .mh .pixel-reveal, .mh .mhcard figure::after{ display:none !important; }
    .mh .portal-media img{ transform:none !important; transition:none !important; }
    .mh .scroll .track::after{ animation:none; }
    .mh #scene{ transition:none; }
  }

  /* ── narrow screens: one column, the scrap mass becomes a band between
        the copy and the cards (760 design units wide) ──────────────────── */
  @media (max-width:900px){
    .mh{ --u: calc(100vw / 760); }
    .mh{ height:auto; min-height:calc(100svh - var(--mh-top)); }
    .mh .stage{
      position:relative; left:auto; top:auto; margin:0;
      width:100%; height:calc(1625 * var(--u));
    }
    .mh::after{
      background:
        radial-gradient(96% 34% at 50% 78%, rgba(150,170,196,.10) 0%, rgba(140,158,182,.045) 46%, rgba(140,158,182,0) 82%),
        linear-gradient(180deg, rgba(235,237,239,0) 62%, rgba(235,237,239,.05) 100%);
    }
    .mh .guides i:nth-child(3){ display:none; }
    .mh .guides i:nth-child(1){ left:calc(253 * var(--u)) !important; }
    .mh .guides i:nth-child(2){ left:calc(506 * var(--u)) !important; }

    /* one column: the labels come off and the dock keeps only its glyphs,
       because at this scale the type would be four pixels tall */
    /* Floored with max(), not left on the design unit alone: this breakpoint
       runs from 900px down to 320px, so a pure --u dock is a 24px bar with
       12px targets on a phone. The floor only bites at the small end. */
    .mh .dock-wrap{ top:calc(30 * var(--u)); }
    .mh .dock{
      height:max(56px, calc(58 * var(--u)));
      padding:max(6px, calc(6 * var(--u)));
      gap:max(4px, calc(4 * var(--u)));
      border-radius:max(17px, calc(18 * var(--u)));
    }
    .mh .dock-item{
      height:max(44px, calc(46 * var(--u)));
      width:max(44px, calc(46 * var(--u)));
      padding:0; border-radius:max(12px, calc(13 * var(--u)));
    }
    .mh .dock-item span:not(.glyph){ display:none; }
    .mh .dock-item .glyph{ width:max(19px, calc(20 * var(--u))); height:max(19px, calc(20 * var(--u))); }
    .mh .dock-mark svg{ width:52%; height:52%; }
    .mh .knob-float{ left:calc(644 * var(--u)); top:calc(1218 * var(--u)); transform-origin:calc(-264 * var(--u)) calc(-43 * var(--u)); }
    .mh .headline{ left:calc(34 * var(--u)); top:calc(128 * var(--u)); font-size:calc(62 * var(--u)); line-height:calc(66 * var(--u)); }
    .mh .mhlede{ left:calc(34 * var(--u)); top:calc(288 * var(--u)); width:calc(400 * var(--u)); font-size:calc(19 * var(--u)); line-height:calc(27 * var(--u)); }
    /* one column: the frame keeps its aspect, re-anchored to the left rail */
    .mh .mhpill-clip{
      left:calc(34 * var(--u)); top:calc(430 * var(--u));
      width:calc(506 * var(--u)); height:calc(334 * var(--u));
      margin:calc(-167 * var(--u)) 0 0 calc(-79 * var(--u));
      clip-path:inset(calc(93 * var(--u)) calc(74 * var(--u)) calc(1 * var(--u)) calc(74 * var(--u)) round calc(76 * var(--u)));
    }
    .mh .liquid-stage--explore{ --h:calc(74.4152 * var(--u)); }
    .mh .play-wrap{ display:none; }

    .mh .stat{ gap:calc(11 * var(--u)); }
    .mh .stat .mark{ width:calc(36 * var(--u)); height:calc(36 * var(--u)); }
    .mh .stat dt{ font-size:calc(16 * var(--u)); line-height:calc(22 * var(--u)); }
    .mh .stat dd{ font-size:calc(16.5 * var(--u)); line-height:calc(24 * var(--u)); }
    .mh .stat--a{ left:calc(34 * var(--u));  top:calc(540 * var(--u)); }
    .mh .stat--b{ left:calc(396 * var(--u)); top:calc(540 * var(--u)); }

    .mh .mhcard{ border-radius:calc(40 * var(--u)); }
    .mh .mhcard--about{ left:calc(34 * var(--u)); top:calc(1050 * var(--u)); width:calc(692 * var(--u)); height:calc(250 * var(--u)); }
    .mh .mhcard--about .label{ top:calc(96 * var(--u)); }
    .mh .mhcard--about h2{ top:calc(124 * var(--u)); width:calc(400 * var(--u)); font-size:calc(32 * var(--u)); line-height:calc(36 * var(--u)); }
    .mh .mhcard--stove{ left:calc(34 * var(--u)); top:calc(1324 * var(--u)); width:calc(692 * var(--u)); height:calc(268 * var(--u)); }
    .mh .mhcard--stove h2{ font-size:calc(32 * var(--u)); }
    /* one column: both plates become a thumbnail on the card's outer edge,
       the Ethos one still anchored to the top */
    .mh .mhcard--stove figure{ left:auto; right:calc(16 * var(--u)); bottom:calc(16 * var(--u)); width:calc(300 * var(--u)); height:calc(150 * var(--u)); }
    .mh .mhcard--about figure{ left:auto; right:calc(16 * var(--u)); top:calc(16 * var(--u)); width:calc(224 * var(--u)); height:calc(218 * var(--u)); }
    .mh .mhcard .knob{ right:calc(24 * var(--u)); bottom:calc(24 * var(--u)); }
    .mh .mhcard--stove .knob{ right:calc(30 * var(--u)); bottom:calc(30 * var(--u)); }

    .mh .scroll{ left:calc(702 * var(--u)); top:calc(470 * var(--u)); }
    .mh .ghost{ font-size:calc(184 * var(--u)); letter-spacing:calc(14 * var(--u)); bottom:calc(660 * var(--u)); left:calc(-10 * var(--u)); }
  }



  /* ---- keep the site stylesheet out of the hero --------------------
     Scoping stops the hero's rules reaching the page. This is the other
     direction, and renaming classes does not help with it: the site
     stylesheet styles BARE ELEMENTS -- h1 to h5, p, a, img, svg, ul, li
     -- and a bare element selector applies inside the hero exactly as
     happily as outside it. Every property the hero does not set for
     itself then arrives from the site. Three of those were visible:

       h1..h5  font-family: var(--font-display)   the site's display
               face landed on the headline and both card headings in
               place of Lexend;
       h1..h5  text-wrap: balance                 which broke "Drained
               and graded." into three balanced lines inside a card
               that had room for two;
       h1..h5  margin: 0 0 0.6em                  under the hero's own
               absolute positioning.

     :where() carries no specificity of its own, so each of these is a
     plain class-level rule: enough to beat a bare element selector,
     never enough to beat a rule the hero writes for itself. */
  .mh :where(h1,h2,h3,h4,h5,h6){
    font-family:inherit; font-size:inherit; font-weight:inherit;
    line-height:inherit; letter-spacing:inherit;
    text-wrap:wrap; text-transform:none; margin:0;
  }
  .mh :where(p,ul,ol,li,dl,dt,dd,figure,blockquote){ margin:0; padding:0; }
  .mh :where(img,svg,video,canvas){ max-width:none; }
  .mh :where(a){ text-decoration:none; color:inherit; }

  /* ---- no WebGL2 --------------------------------------------------
     The scene drops its canvas and adds .nogl rather than replacing the
     hero's contents, because the page's only <h1> lives inside it. All
     that is needed then is a ground for the copy to sit on. */
  .mh.nogl{
    background:
      radial-gradient(120% 76% at 50% 116%, rgba(198,210,226,.10) 0%, rgba(198,210,226,0) 70%),
      linear-gradient(180deg,#191d24 0%,#0f1217 100%);
  }
  .mh.nogl .ghost{ opacity:.22; }

  /* ---- pieces the embedded hero adds ------------------------------
     The demo had no trust row and only one call to action. The home
     page needs both, so a chip row sits above the headline and a
     second, quieter link sits beside the pill. Both are placed in the
     same 1600-unit stage space as everything else, and both ride the
     pointer parallax on the same --pd/--pr contract as the copy. */
  .mh .chips{
    position:absolute; z-index:4;
    left:calc(66 * var(--u)); top:calc(148 * var(--u));
    display:flex; flex-wrap:wrap;
    gap:calc(9 * var(--u)) calc(10 * var(--u));
  }
  /* The site's own .chip is sized in rem, which is right everywhere else
     on the page and wrong here: nothing else in the hero is, so the pills
     kept their desktop weight while the type around them scaled down with
     --u and they read as three heavy black lozenges. Re-declared in the
     hero's unit so they hold their proportions, with the border taken
     down to a hairline and the fill to almost nothing — they are a
     credential line, not buttons. */
  .mh .chips .chip{
    display:inline-flex; align-items:center; gap:calc(8 * var(--u));
    padding:calc(8 * var(--u)) calc(17 * var(--u)) calc(9 * var(--u));
    font-size:calc(14.5 * var(--u)); font-weight:400; line-height:1;
    letter-spacing:.005em; white-space:nowrap;
    color:rgba(236,240,246,.84);
    background:rgba(255,255,255,.028);
    border:1px solid rgba(255,255,255,.115);
    border-radius:calc(100 * var(--u));
    -webkit-backdrop-filter:blur(calc(6 * var(--u)));
    backdrop-filter:blur(calc(6 * var(--u)));
  }
  .mh .chips .chip__dot{
    width:calc(5.5 * var(--u)); height:calc(5.5 * var(--u));
    border-radius:50%; background:#5cc86f; flex:none;
  }
  .mh .cta2{
    position:absolute; z-index:4;
    left:calc(424 * var(--u)); top:calc(564 * var(--u));
    display:inline-flex; align-items:center; gap:calc(9 * var(--u));
    font-size:calc(17 * var(--u)); font-weight:400; letter-spacing:.01em;
    color:rgba(255,255,255,.78); text-decoration:none;
    padding-bottom:calc(3 * var(--u));
    border-bottom:1px solid rgba(255,255,255,.26);
    transition:color .2s var(--ease), border-color .2s var(--ease);
  }
  .mh .cta2:hover{ color:#fff; border-bottom-color:rgba(255,255,255,.7); }
  .mh .cta2 svg{ width:calc(17 * var(--u)); height:calc(17 * var(--u)); }

  /* Three lines of a real headline, not two of a demo one: the face
     comes down from 63u so "and refined lead," clears the first card,
     and starts 10u higher than the source's 214u to pay for the third
     line at the size below. */
  .mh .headline{
    top:calc(204 * var(--u));
    font-size:calc(55 * var(--u)); line-height:calc(59 * var(--u));
  }

  /* ---- the copy is set one step up from the demo's -------------------
     The scene is authored on a 1600 x 880 frame and --u is pinned to
     whichever of width and height runs out first. On a laptop that is
     the height: 1536 x 695 leaves --u at about 0.67, so every size in
     the composition renders at two thirds of the number written here.
     The headline was the only piece with enough size to survive that;
     everything supporting it landed between 8 and 11 real pixels -- the
     lede at 11px, the credential chips at 8px, the two figures at 9px.

     So the supporting copy goes up a step and the pieces underneath it
     move to keep the composition. The stage coordinates of the block as
     a whole are unchanged: still 66u in from the left, still the chips
     above the headline and the figures at 672u.

     Two of these are ratios, not free numbers:

       .mhlede     408u at 16.5u is 24.7 : 1, and that ratio is what makes
                 the paragraph break over four lines. The width moves
                 with the size to hold it -- widen the type without
                 widening the box and a fifth line drops onto the
                 button below.
       .mhcard--about h2  142u at 26.2u is what breaks "Drained and
                 graded." after "and". Same ratio, same break.

     The button is not sized here at all: --h is its own unit base and
     --lu = --h/516 drives its label, icon, padding and shadow together,
     so it grows from the one number and stays the control it was. */
  .mh .mhlede{
    width:calc(472 * var(--u));
    font-size:calc(22 * var(--u)); line-height:calc(30 * var(--u));
  }
  /* --h is the button's whole size, and .mhpill-clip is the window it is
     posted through: a 410 x 270 box whose padding, inset and radius were
     all derived from the 60.156u button that used to sit in it -- the
     stage is 4.49 x --h tall, which is where 270 came from. Grow one
     without the other and the stage stops fitting the box, the browser
     clamps the overflow to the top-left instead of centring it, and the
     button drops 20u down the page. So both scale by the same 69/60.156
     about the same centre, and the composition is the one it was. */
  .mh .liquid-stage--explore{ --h:calc(69 * var(--u)); }
  .mh .mhpill-clip{
    top:calc(580 * var(--u));
    width:calc(470.3 * var(--u)); height:calc(309.7 * var(--u));
    margin:calc(-154.85 * var(--u)) 0 0 calc(-235.15 * var(--u));
    clip-path:inset(calc(82.6 * var(--u)) calc(68.8 * var(--u))
                    calc(29.8 * var(--u)) calc(68.8 * var(--u)) round calc(71.1 * var(--u)));
  }
  .mh .stat{ gap:calc(11 * var(--u)); }
  .mh .stat .mark{ width:calc(38 * var(--u)); height:calc(38 * var(--u)); }
  .mh .stat dt{ font-size:calc(17 * var(--u)); line-height:calc(23 * var(--u)); }
  .mh .stat dd{ font-size:calc(17.5 * var(--u)); line-height:calc(24 * var(--u)); }
  .mh .mhcard .label{ font-size:calc(17.5 * var(--u)); }
  .mh .mhcard h2{ font-size:calc(29.5 * var(--u)); line-height:calc(31 * var(--u)); }
  .mh .mhcard--about .label{ top:calc(149 * var(--u)); }
  .mh .mhcard--about h2{ top:calc(178 * var(--u)); width:calc(160 * var(--u)); }
  .mh .mhcard--stove .label{ top:calc(43 * var(--u)); }
  .mh .mhcard--stove h2{ top:calc(69 * var(--u)); }
  .mh .scroll{ font-size:calc(13.5 * var(--u)); letter-spacing:calc(4.8 * var(--u)); }

  /* ---- narrow screens ---------------------------------------------
     The source does NOT switch to flow layout below 900px: it keeps
     every child absolutely positioned and re-places it inside a taller
     760 x 1625 stage. So these are coordinates in that space, not
     margins — the headline sits at 128u, the lede at 288u, the pill at
     430u and the figures at 540u, and the two new pieces have to be
     given room between them rather than pushed into the flow.

     The headline also comes down again: three lines at the source's
     62u would run from 128u to 314u and collide with the lede. */
  @media (max-width:900px){
    .mh .chips{
      left:calc(34 * var(--u)); top:calc(44 * var(--u));
      width:calc(692 * var(--u)); gap:calc(8 * var(--u)) calc(10 * var(--u));
    }
    .mh .chips .chip{
      font-size:calc(21 * var(--u));
      padding:calc(10 * var(--u)) calc(20 * var(--u)) calc(11 * var(--u));
      gap:calc(9 * var(--u));
    }
    .mh .chips .chip__dot{ width:calc(7 * var(--u)); height:calc(7 * var(--u)); }
    /* The chip row takes two lines on a phone — three chips will not sit on
       390px — so the headline starts below the deepest that row gets (137u at
       the size above) rather than at the source's 128u, and everything under
       it moves down to match. The row is shorter than it once was and still
       wraps at this width, so the offset stands. */
    .mh .headline{
      left:calc(34 * var(--u)); top:calc(152 * var(--u));
      font-size:calc(56 * var(--u)); line-height:calc(60 * var(--u));
    }
    /* The narrow stage is 760u across, so --u is vw/760 and a phone reads
       it at about 0.51: the same divide as the laptop, one notch deeper.
       These are the desktop step again, re-derived against that unit --
       the lede at 29u is 15px on a 390px screen, the chips 11px, the
       figures 11px. Every one of them has to be written twice, because
       the desktop rules above are later in the file than the source's
       own narrow block and reach it. */
    .mh .mhlede{
      top:calc(352 * var(--u)); width:calc(676 * var(--u));
      font-size:calc(29 * var(--u)); line-height:calc(38 * var(--u));
    }
    /* .mhpill-clip is centre-anchored on its `top`, so the button sits at
       580 +/- 50u and the window scales with it, 100/74.4152 on every
       number the source wrote for the smaller one. */
    .mh .liquid-stage--explore{ --h:calc(100 * var(--u)); }
    .mh .mhpill-clip{
      top:calc(580 * var(--u));
      width:calc(679.9 * var(--u)); height:calc(448.8 * var(--u));
      margin:calc(-224.4 * var(--u)) 0 0 calc(-106.2 * var(--u));
      clip-path:inset(calc(125 * var(--u)) calc(99.4 * var(--u))
                      calc(1.3 * var(--u)) calc(99.4 * var(--u)) round calc(102.1 * var(--u)));
    }
    /* the button is wider at 100u than it was at 74u: the quote link
       clears its right edge at 480, not the source's 430 */
    .mh .cta2{
      left:calc(480 * var(--u)); top:calc(560 * var(--u));
      font-size:calc(22 * var(--u));
    }
    .mh .cta2 svg{ width:calc(22 * var(--u)); height:calc(22 * var(--u)); }
    .mh .stat{ gap:calc(13 * var(--u)); }
    .mh .stat .mark{ width:calc(44 * var(--u)); height:calc(44 * var(--u)); }
    .mh .stat dt{ font-size:calc(21 * var(--u)); line-height:calc(28 * var(--u)); }
    .mh .stat dd{ font-size:calc(22 * var(--u)); line-height:calc(30 * var(--u)); }
    .mh .stat--a, .mh .stat--b{ top:calc(672 * var(--u)); }
    .mh .mhcard .label{ font-size:calc(21 * var(--u)); }
    .mh .mhcard h2{ font-size:calc(38 * var(--u)); line-height:calc(42 * var(--u)); }
    .mh .mhcard--about .label{ top:calc(94 * var(--u)); }
    .mh .mhcard--about h2{ top:calc(126 * var(--u)); width:calc(400 * var(--u)); }
    .mh .mhcard--stove .label{ top:calc(40 * var(--u)); }
    .mh .mhcard--stove h2{ top:calc(72 * var(--u)); }
    .mh .scroll{ font-size:calc(16 * var(--u)); letter-spacing:calc(5.4 * var(--u)); }
  }

  /* ---- fitting the real lede -------------------------------------
     The scene places everything on a fixed 1600 x 880 unit stage, so a
     slot holds the number of lines it was drawn for and not one more.
     The demo's lede was two sentences; this one is the site's, and it
     runs to five lines in both regimes -- far enough that the button's
     top edge cut through the last line ("...actually holds.") on every
     width from 320px to 1920px.

     The two regimes need different answers, because only one of them
     has room to widen into:

     WIDE: the lede column is 472u inside a copy area that runs to the
     cards at 1146u, so it is simply narrower than it needs to be. At
     600u the same words set in four lines and finish at 522u, clear of
     the button at 546u -- and a 27em measure reads better than the
     cramped 21em one did.

     NARROW: the column is the full 692u already, so there is nothing to
     widen into and the five lines stay. The button moves down instead.
     Its window is centre-anchored on `top`, so one number moves the
     whole control: 580u -> 616u puts its top at 566u, 24u below the
     lede. The stage is 1625u tall here and the cards do not start until
     1050u, so nothing below it has to move.

     Both numbers are checked by tools/tests/hero-layout.test.js rather
     than by eye, because this is the kind of thing that breaks silently
     the next time somebody edits one sentence of copy. */
  .mh .mhlede{ width:calc(600 * var(--u)); }

  @media (max-width:900px){
    .mh .mhpill-clip{ top:calc(616 * var(--u)); }

    /* ---- the two figures, readable ------------------------------
       --u on a phone is viewport/760, so 0.51 at 390px wide and 0.42
       at 320px. The figures were written at 21u and 22u, which lands
       them at 10.8px and 8.8px of real type -- under the hero image,
       in a light weight, at a size nobody reads. 26u/27u puts them at
       13.3px on a 390px screen and 11px on a 320px one, which is the
       same step the rest of the site's supporting copy sits at.

       There is room for it: stat--a starts at 34u and stat--b at
       396u, so the longer of the two labels ("Converters recycled")
       has 362u to set in and needs about 230u at this size. */
    .mh .stat dt{ font-size:calc(26 * var(--u)); line-height:calc(33 * var(--u)); }
    .mh .stat dd{ font-size:calc(27 * var(--u)); line-height:calc(35 * var(--u)); }
    .mh .stat .mark{ width:calc(48 * var(--u)); height:calc(48 * var(--u)); }
  }

  /* ---- the header height, known before any script runs --------------
     --mh-top used to start at 0 and only be measured once hero.js ran.
     Since the scene loads after the page, that measurement arrived seconds
     late: the whole hero re-laid out at a new design unit, the lede
     repainted at its new size, and that repaint -- queued behind the scene's
     shader compile -- became the Largest Contentful Paint. The stylesheet
     now carries the real values (utility strip + header at 941px and up,
     the one-row header below), so the late measurement changes nothing. */
  @media (max-width:940px){ .mh{ --mh-top:65px; } }

  /* ---- no replayed entrance on the card photographs -----------------
     is-ready is set from the first frame now (see JS_HEAD), and the two
     portal scans are keyed on it at a higher specificity than the
     intro-done rule that switches them off -- so without this they would
     wipe the photographs out and back in on every load. Same weight,
     later in the file, so this wins. */
  .mh.intro-done .mhcard--about .portal-media, .mh.intro-done .mhcard--stove .portal-media, .mh.intro-done .mhcard--about figure::after, .mh.intro-done .mhcard--stove figure::after{ animation:none; }
