/* ==========================================================================
   BLOOMIFY V8 — "THE NIGHT GARDEN" core styles
   World rules encoded: W2 palette · W4 type roles · SC-C1 canvas visibility
   gates (inline in markup) · SC-C2 explicit solid backgrounds on big layers ·
   SC-C3 transparent wrappers · SC-C5 overflow-x:clip · W7 no-JS visible.
   Design tokens carried from the approved v7 system.
   ========================================================================== */

/* ---- fonts (self-hosted, reused from v7) -------------------------------- */
@font-face{
  font-family:"Switzer";font-style:normal;font-weight:300 800;font-display:swap;
  src:local("Switzer"),url("../v7/fonts/Switzer-Variable.woff2") format("woff2");
}

:root{
  color-scheme:dark;
  --canvas:#050807;
  --s1:#0a0e0c; --s2:#0f1512; --s3:#141b17;
  --ink:#f2f7f4; --ink-2:#b7c4bd; --ink-3:#79857f;
  --line:rgba(214,255,236,.08); --line-2:rgba(214,255,236,.14);
  --edge:rgba(255,255,255,.06);
  --mint:#6ef0c2; --sap:#34d39e; --spore:#eafff6;
  --mint-ink:#04120c;
  --mint-dim:rgba(110,240,194,.12); --mint-glow:rgba(110,240,194,.30);
  --display:"Switzer",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --text:"Switzer",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:"Fragment Mono","Geist Mono","JetBrains Mono",ui-monospace,Consolas,monospace;
  --step--1:clamp(.78rem,.74rem + .2vw,.86rem);
  --step-0:clamp(.95rem,.9rem + .25vw,1.05rem);
  --step-1:clamp(1.2rem,1.05rem + .6vw,1.5rem);
  --step-2:clamp(1.6rem,1.3rem + 1.4vw,2.4rem);
  --step-3:clamp(2.2rem,1.6rem + 3vw,4rem);
  --step-4:clamp(3rem,1.8rem + 6vw,7rem);
  --gutter:clamp(1.25rem,4vw,3rem);
  --container:1280px;
  --ease:cubic-bezier(.22,1,.36,1);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;background:var(--canvas);   /* SC-C2 */
  scrollbar-width:none;-ms-overflow-style:none}                /* Lenis drives scroll — hide native bar (breaks the canvas illusion in full-bleed portals) */
html::-webkit-scrollbar{width:0;height:0;display:none}
body.v8{
  margin:0;background:var(--canvas);color:var(--ink);          /* SC-C2 */
  font-family:var(--text);font-size:var(--step-0);line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:clip;                                             /* SC-C5 */
}
body.v8::-webkit-scrollbar{width:0;height:0;display:none}
.v8 h1,.v8 h2,.v8 h3,.v8 p,.v8 figure,.v8 blockquote{margin:0}
.v8 img,.v8 video,.v8 canvas{display:block;max-width:100%}
.v8 a{color:inherit;text-decoration:none}
.v8 ::selection{background:var(--mint);color:var(--mint-ink)}
.v8 :focus-visible{outline:2px solid var(--mint);outline-offset:3px;border-radius:2px}

/* type roles (W4) */
.v8 .display{font-family:var(--display);font-weight:600;text-transform:uppercase;
  line-height:.92;letter-spacing:-.04em}
.v8 .h-hero{font-size:clamp(3.4rem,1.2rem + 9vw,9.5rem)}
.v8 .h-xl{font-size:var(--step-4)}
.v8 .h-lg{font-size:var(--step-3)}
.v8 .lead{font-size:var(--step-1);line-height:1.4;color:var(--ink-2)}
.v8 .muted{color:var(--ink-2)}
.v8 .lab{font-family:var(--mono);font-size:var(--step--1);font-weight:400;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.v8 .lab--live{color:var(--mint)}
.v8 em{font-style:normal;color:var(--mint)}

/* layout helpers — wrappers stay TRANSPARENT (SC-C3) */
.v8 .container{width:100%;max-width:var(--container);margin-inline:auto;
  padding-inline:var(--gutter);background:transparent}

/* ---- L0 world canvas (fixed) — SC-C1 markup carries visibility:hidden --- */
.v8 #v8-world{
  position:fixed;inset:0;width:100vw;height:100vh;z-index:0;
  pointer-events:none;background:transparent;
}
/* both surfaces stack in-viewport; the controller picks which is visible */
.v8 #v8-world canvas{position:absolute;inset:0;width:100%;height:100%;max-width:none}

/* ---- B0 loader ---------------------------------------------------------- */
.v8 #v8-loader{
  position:fixed;inset:0;z-index:200;background:var(--canvas);   /* SC-C2 */
  transition:opacity .8s var(--ease),visibility .8s;
}
.v8 #v8-loader.is-open{opacity:0;visibility:hidden}
/* counter + label vanish FAST at gate-open (the canvas glow fades slower) — the
   "100 GERMINATING" text must never linger readable under the arriving hero */
.v8 #v8-loader.is-open #v8-loader-count,
.v8 #v8-loader.is-open #v8-loader-label{opacity:0;transition:opacity .16s linear}
.v8 #v8-loader-canvas{position:absolute;inset:0;width:100%;height:100%}
.v8 #v8-loader-count{
  position:absolute;left:50%;bottom:9vh;transform:translateX(-50%);
  font-family:var(--mono);font-size:.8rem;letter-spacing:.3em;color:var(--mint);
}
.v8 #v8-loader-label{
  position:absolute;left:50%;bottom:6vh;transform:translateX(-50%);
  font-family:var(--mono);font-size:.62rem;letter-spacing:.24em;color:var(--ink-3);
  text-transform:uppercase;
}

/* ---- B1 hero DOM layer (L2) -------------------------------------------- */
.v8 .b1{position:relative;min-height:100svh;display:flex;align-items:flex-end;
  padding-block:6rem clamp(2.5rem,6vh,6rem);background:transparent}   /* SC-C3 */
.v8 .b1-poster{position:absolute;inset:0;z-index:0;pointer-events:none}
.v8 .b1-poster img{width:100%;height:100%;object-fit:cover;object-position:center;
  background-color:#070b09}                                     /* SC-C4 mean tone */
/* CENTRED (2026-09-08): with a two-line headline the left-set block left the
   upper-left empty and the lotus sits on the frame's centre line anyway */
.v8 .b1-inner{position:relative;z-index:2;width:100%;max-width:var(--container);margin-inline:auto;text-align:center}
.v8 .b1 .line-mask{display:block;overflow:hidden}
.v8 .b1 .line-mask > span{display:block;will-change:transform}  /* hidden ONLY by GSAP */
.v8 .b1-sub{max-width:52ch;margin:1.4rem auto 0}
.v8 .b1-actions{display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;margin-top:2.2rem}

/* L3 occluder (petal cutout over the headline) — pointer-events none */
.v8 .b1-occluder{position:absolute;z-index:3;pointer-events:none}

/* buttons (carried from v7 language) */
.v8 .btn{display:inline-flex;align-items:center;gap:.6em;padding:1.05em 1.6em;
  font-family:var(--mono);font-size:var(--step--1);letter-spacing:.08em;
  text-transform:uppercase;border-radius:999px;transition:transform .4s var(--ease),
  color .3s,background .3s,border-color .3s;will-change:transform}
.v8 .btn-primary{background:var(--sap);color:var(--mint-ink);font-weight:500;
  box-shadow:0 0 0 1px rgba(52,211,158,.4),0 0 40px -8px var(--mint-glow)}
.v8 .btn-ghost{color:var(--ink);border:1px solid var(--line-2);
  background:rgba(255,255,255,.015)}
.v8 .btn-ghost:hover{border-color:var(--mint);color:var(--mint)}

/* ---- minimal nav -------------------------------------------------------- */
.v8 .v8-nav{position:fixed;top:0;left:0;right:0;z-index:100;display:flex;
  align-items:center;justify-content:space-between;background:transparent;
  /* Full-bleed bar, container-aligned contents. The gutter alone left the logo
     and CTA on the viewport edge while every section sits in the centred
     --container box; this lands them on the same column. max() falls back to
     the plain gutter once the viewport is narrower than the container. */
  padding-block:1.1rem;
  padding-inline:max(var(--gutter),calc((100% - var(--container)) / 2 + var(--gutter)))}
.v8 .v8-logo{display:inline-flex;align-items:center;gap:.5em;font-family:var(--display);font-weight:600;font-size:1.15rem;
  letter-spacing:-.02em;color:var(--ink)}
.v8 .v8-nav-cta{padding:.6em 1.1em}

/* ---- B1 additions ------------------------------------------------------- */
.v8 .b1-scroll{position:absolute;bottom:2rem;right:var(--gutter);z-index:2}
/* S1 mint flood — declared flood event (W2 exception), driven only by progress */
/* a burst of light FROM the flower's throat — bright core, dark surround, not a
   flat green wall (edges fade to transparent so the void reads through).
   scale() is driven by JS: the core swells to cover the lotus at the S1 peak so
   the film->particles swap happens UNDER the light (measured delta-118 fix). */
/* S1 LIGHT — ONE light, born in the flower's throat, that RIDES the crown as the
   dive scrubs and then blooms out to engulf the frame.
   Two earlier attempts failed for structural reasons worth keeping written down:
   a full-screen wash at 50%/48% erased the flower it was meant to come from; and
   splitting it into a fixed crown "plume" plus a centre-anchored cover made the
   bright point visibly DETACH and slide back down to centre as the cover took
   over (measured: throat at y .257, cover at y .498). One element on one measured
   path is the only way it stays attached to the plant.
   Sized in vmax and positioned by TRANSFORM (composited, no per-frame repaint);
   its own centre is the anchor, so scale() blooms out of the throat. */
/* document lock while the gate is closed (set by v8-loader, lifted by v8-boot
   when Lenis starts): nothing scrolls the page under the loader */
html.v8-gate{overflow:hidden}
.v8 .s1-light{position:absolute;left:0;top:0;
  width:80vmax;height:80vmax;margin-left:-40vmax;margin-top:-40vmax;
  pointer-events:none;opacity:0;z-index:2;will-change:opacity,transform;
  background:radial-gradient(circle at 50% 50%, var(--spore) 0%, #b6f7de 16%,
             var(--mint) 34%, rgba(52,211,158,.30) 56%, rgba(5,8,7,0) 74%)}
/* SPORE LIFT — during the handoff the mote canvas rises ABOVE the light layers
   so the spores stream out IN FRONT of the lit flower. Without this they render
   beneath both the film and the flood and are simply invisible until everything
   above them has faded, so "light turning into dots" can never be seen. */
.v8 #v8-world-gl{z-index:0}
.v8 #v8-world-film{z-index:1}
/* SCREEN blend, not just a transparent clear: the EffectComposer's OutputPass
   writes alpha=1, so the lifted canvas stayed effectively OPAQUE and painted
   near-black over the entire lotus — the real reason the handoff kept reading as
   "a glowing orb on black" however the light itself was tuned. The spores are
   additive light, so screen-blending them over the film is also the physically
   right operation: black adds nothing, glow adds glow. */
.v8.s1-lift #v8-world-gl{z-index:4;mix-blend-mode:screen}

/* ---- B2 pollen void (placeholder scaffold) ------------------------------ */
/* 55vh, was 130vh: the section's own height becomes UNPINNED scroll after the pin
   releases, and it measured 991px = 1.3 viewports of gap in which the particle
   canvas was pixel-identical at every sample — a frozen screen you had to scroll
   through. Now ~0.55 viewport: a breath between beats, not a dead stretch.
   SC-C3: must reveal the fixed world canvas; body paints the black. */
.v8 .b2{position:relative;min-height:55vh;background:transparent}
/* .b2-soil gradient band REMOVED: anchored to the section, it scrolled up through
   the viewport after unpin as a hard-edged floating green stripe (the "this
   section looks weird" artifact). The GL mote soil bed owns the ground visual. */
.v8 .b2-soil{display:none}
.v8 .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---- B3 THE GROWN INDEX (services) --------------------------------------
   The services are the content here, not a caption on a picture of plants:
   four rows of display type filling the pinned frame, with the vine growing
   along each one on the canvas behind. Rows sit at fixed positions (no JS
   left/top) so the painter can read their rects and anchor growth to the type. */
.v8 .b3{position:relative;min-height:100vh;background:transparent}   /* SC-C3 */
.v8 .b3-labels{position:absolute;inset:0;display:flex;flex-direction:column;
  justify-content:center;gap:clamp(.7rem,2.4vh,2.1rem);      /* five rows now */
  padding:12vh var(--gutter) 15vh;pointer-events:none}
/* a dedicated column for the stems to climb out of the bed in. Without it all
   four crowd into the page gutter, bundle into one thick stalk and cross the
   row numbers on their way up. */
@media (min-width:641px){ .v8 .b3-labels{padding-left:calc(var(--gutter) + 5rem)} }
.v8 .b3-label{position:relative;display:flex;align-items:baseline;
  gap:clamp(.6rem,1.6vw,1.4rem);pointer-events:auto;text-decoration:none;
  padding:.1em 0}
/* the link to the services overview: the same ghost button the hero uses,
   out of flow so the rows stay where the painter measured them; inherits the
   rows' fade and pointer gating */
.v8 .b3-all{position:absolute;left:var(--gutter);bottom:8vh;pointer-events:auto}
@media (min-width:641px){ .v8 .b3-all{left:calc(var(--gutter) + 5rem)} }
.v8 .b3-label-num{flex:none;font-family:var(--mono);font-size:var(--step--1);
  letter-spacing:.14em;color:var(--ink-3);transition:color .45s var(--ease)}
/* One line per service where there is room for one. The painter measures the
   LAST line box, so a wrapped name (mobile) still gets its shoot under the line
   the name actually ends on. nowrap only where it cannot overflow. */
.v8 .b3-label-name{position:relative;display:inline-block;
  font-size:clamp(1.4rem,4.4vw,3.9rem);line-height:1.02}      /* five rows fit a 700px frame */

/* THE UNLIT GHOST. It was a 1px outline of the same bold cut, which at this size
   reads as thin wireframe lettering rather than a word waiting to be lit. It is a
   SOLID low-opacity fill in a far lighter weight of the family now: a visibly
   different cut, with no hairline to go ragged.
   Absolutely positioned so it can never affect the box — the LIT layer alone sets
   the width the shoot is anchored to — and scaleX-fitted by JS to that exact
   width so the two layers sit precisely on top of one another. */
.v8 .b3-name-dim{position:absolute;left:0;top:0;
  font-family:var(--display);font-weight:200;letter-spacing:-.005em;
  color:rgba(234,255,246,.15);
  transform-origin:left top;transform:scaleX(var(--dim-fit,1));
  transition:opacity .5s var(--ease);pointer-events:none}
.v8 .b3-name-lit{display:block;font-family:var(--display);font-weight:500;
  letter-spacing:-.02em;color:var(--spore);
  opacity:0;transform:translateY(.1em);
  transition:opacity .55s var(--ease),transform .55s var(--ease)}

/* grown: the ghost gives way and the word lights */
.v8 .b3-label.is-grown .b3-name-lit{opacity:1;transform:none}
.v8 .b3-label.is-grown .b3-name-dim{opacity:0}
.v8 .b3-label.is-grown .b3-label-num{color:var(--mint)}
.v8 .b3-label:hover .b3-name-lit,.v8 .b3-label:focus-visible .b3-name-lit{
  color:var(--mint);opacity:1;transform:none}
.v8 .b3-label:hover .b3-name-dim,.v8 .b3-label:focus-visible .b3-name-dim{opacity:0}
.v8 .b3-label:focus-visible{outline:2px solid var(--mint);outline-offset:.35rem;border-radius:4px}

@media (min-width:641px){ .v8 .b3-label-name,.v8 .b3-name-dim{white-space:nowrap} }
@media (max-width:640px){
  .v8 .b3-labels{gap:1.1rem;padding:14vh var(--gutter) 16vh}
  .v8 .b3-label{flex-direction:column;align-items:flex-start;gap:.1rem}
  .v8 .b3-label-name{font-size:clamp(1.35rem,7.2vw,2.6rem);line-height:1.06}
  /* A wrapped ghost cannot be scaleX-fitted to a single width, so it is dropped
     here and the LIT layer carries the unlit state itself. Without this second
     rule the words were invisible on a phone until their shoot arrived: the ghost
     was display:none and the lit layer still sat at opacity 0. */
  .v8 .b3-name-dim{display:none}
  .v8 .b3-name-lit{opacity:.22;transform:none}
  .v8 .b3-label.is-grown .b3-name-lit{opacity:1}
}
@media (prefers-reduced-motion:reduce){
  .v8 .b3-name-lit{opacity:1;transform:none}
  .v8 .b3-name-dim{opacity:0}
}

/* ---- reduced motion (W7): everything visible, zero scrub ---------------- */
@media (prefers-reduced-motion:reduce){
  .v8 *{animation:none!important;transition-duration:.001s!important}
  .v8 #v8-loader{display:none}
  .v8 #v8-world{display:none}
  .v8 .b1 .line-mask > span{transform:none!important}
  /* B4 reduced-motion: portal panels become a reachable static grid (W7) */
  .v8 #portal-layer{position:static;display:grid;grid-template-columns:1fr 1fr;
    gap:1.5rem;padding:var(--gutter);pointer-events:auto}
  .v8 #portal-layer .b4-panel{position:relative!important;display:block!important;
    left:auto!important;top:auto!important;width:auto!important;
    height:60vh!important;opacity:1!important;clip-path:none!important}
}

/* ---- B4 website blooms + DOM portal ------------------------------------- */
/* garden mist plate (seam cover) — dark mint fog, opaque bg so it truly hides */
.v8 #s3-mist{position:fixed;inset:0;z-index:5;pointer-events:none;opacity:0;
  background:radial-gradient(135% 95% at 50% 60%,rgba(52,211,158,.13),rgba(5,8,7,.9) 50%,#050807 86%)}

.v8 .b4{position:relative;min-height:100vh;background:transparent}   /* SC-C3 */
/* fade our nav during the full-bleed portal so it never collides with the client's nav */
.v8 .v8-nav{transition:opacity .3s var(--ease,ease)}
.v8-portal .v8-nav{opacity:0;pointer-events:none}

/* the power-on's runway: transparent scroll where the fixed world shows through */
.v8 .b4-runway{height:100vh;background:transparent;pointer-events:none}

/* ---- B3.5 BLOOMIFY SIGNAL (product / lead magnet) -----------------------
   Opaque and above the fixed world (SC-C2): this section also covers the frozen
   B3 canvas between b3's pin end and B4's power-on. The demo panel is real DOM +
   SVG, not a screenshot, so it can assemble on entry and stay crisp at any DPR. */
/* TRANSPARENT and pinned. It was an opaque box that scrolled past between two
   pinned canvas beats, which is exactly why it read as a different website and
   had no transition to speak of. The painter owns the ground now (SC-C3). */
.v8 .b35{position:relative;z-index:3;background:transparent;
  min-height:100vh;display:grid;align-items:center;
  padding-block:clamp(4.5rem,11vh,7rem) clamp(2rem,5vh,4rem)}
.v8 .b35-inner{position:relative;display:grid;gap:clamp(2.5rem,5vw,4rem);
  grid-template-columns:1fr;align-items:center}
@media (min-width:980px){
  .v8 .b35-inner{grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);
    gap:clamp(2.5rem,4.5vw,4.5rem)}
}
.v8 .b35-eyebrow{display:flex;align-items:center;gap:.55rem;color:var(--mint);
  margin-bottom:1rem}
.v8 .b35-dot{width:.45rem;height:.45rem;border-radius:50%;background:var(--mint);
  animation:b35pulse 2.6s ease-out infinite}
@keyframes b35pulse{
  0%{box-shadow:0 0 0 0 rgba(110,240,194,.5)}
  70%{box-shadow:0 0 0 .55rem rgba(110,240,194,0)}
  100%{box-shadow:0 0 0 0 rgba(110,240,194,0)}}
.v8 .b35-h{font-size:clamp(1.5rem,min(2.9vw,5.2vh),3.5rem);text-transform:none;
  letter-spacing:-.03em;line-height:1.03;text-wrap:balance;max-width:15ch}
.v8 .b35-lead{margin-top:clamp(.6rem,1.4vh,1.1rem);max-width:44ch;
  font-size:clamp(.95rem,min(1.15vw,2.4vh),1.5rem)}

/* the offer card sits under the copy, in the same column */
.v8 .b35-card{margin-top:clamp(.9rem,2.4vh,2.2rem);will-change:transform,opacity;
  background:rgba(10,14,12,.86);border:1px solid var(--line-2);border-radius:14px;
  padding:clamp(1rem,2.2vh,1.7rem);
  box-shadow:0 40px 90px -50px rgba(0,0,0,.9),0 0 70px -45px var(--mint-glow)}
.v8 .b35-card-h{font-family:var(--display);font-weight:600;
  font-size:clamp(1.05rem,min(1.6vw,2.9vh),1.5rem);
  letter-spacing:-.02em;color:var(--ink)}
.v8 .b35-card-sub{margin-top:.3rem;color:var(--mint);font-family:var(--mono);
  font-size:var(--step--1);letter-spacing:.04em}
.v8 .b35-form{display:grid;gap:clamp(.5rem,1.1vh,.85rem);margin-top:clamp(.7rem,1.6vh,1.1rem)}
.v8 .b35-row{display:grid;gap:clamp(.5rem,1.1vh,.85rem);grid-template-columns:1fr 1fr 1fr}
@media (max-width:1180px){ .v8 .b35-row{grid-template-columns:1fr 1fr} }
@media (max-width:520px){ .v8 .b35-row{grid-template-columns:1fr} }
.v8 .b35-field{display:grid;gap:clamp(.2rem,.6vh,.35rem);min-width:0}
.v8 .b35-field > span{font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}
.v8 .b35-field input{width:100%;min-width:0;padding:clamp(.5em,1.1vh,.8em) .85em;border-radius:8px;
  background:rgba(255,255,255,.03);border:1px solid var(--line-2);
  color:var(--ink);font-family:var(--text);font-size:var(--step-0);
  transition:border-color .25s var(--ease),background .25s var(--ease)}
.v8 .b35-field input::placeholder{color:var(--ink-3)}
.v8 .b35-field input:focus{outline:none;border-color:var(--mint);
  background:rgba(110,240,194,.05)}
.v8 .b35-field input:focus-visible{outline:2px solid var(--mint);outline-offset:2px}
.v8 .bf-hp{position:absolute!important;left:-9999px;width:1px;height:1px;opacity:0}
.v8 .b35-submit{justify-content:center;margin-top:.25rem}
.v8 .b35-submit[disabled]{opacity:.55;cursor:wait}
.v8 .b35-status{min-height:1.2em;font-family:var(--mono);
  font-size:var(--step--1);color:var(--ink-2)}
.v8 .b35-status.ok{color:var(--mint)}
.v8 .b35-status.err{color:#ff9a9a}

/* ---- the demo panel ---------------------------------------------------- */
/* No fill, no border, no shadow: the world canvas paints this plate underneath
   so the panel can DRAW ITSELF into existence. The DOM is content only. */
.v8 .sig-panel{position:relative;border-radius:16px;background:transparent}
.v8 .sig-chrome{display:flex;align-items:center;gap:.6rem;
  padding:clamp(.5rem,1.2vh,.75rem) 1.1rem;border-bottom:1px solid var(--line)}
.v8 .sig-live{width:.4rem;height:.4rem;border-radius:50%;background:var(--mint);
  box-shadow:0 0 10px var(--mint)}
.v8 .sig-title{font-family:var(--display);font-weight:600;font-size:.92rem;
  letter-spacing:-.01em;color:var(--ink)}
.v8 .sig-range{margin-left:auto;font-family:var(--mono);font-size:.68rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.v8 .sig-body{padding:clamp(.85rem,2vh,1.5rem)}
.v8 .sig-label{font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}
.v8 .sig-figure{display:flex;align-items:baseline;gap:.7rem;margin-top:.3rem}
.v8 .sig-value{font-family:var(--display);font-weight:600;
  font-size:clamp(1.6rem,min(2.4vw,4.6vh),3rem);letter-spacing:-.03em;color:var(--ink);
  font-variant-numeric:tabular-nums}
.v8 .sig-delta{font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;
  color:var(--mint);background:rgba(110,240,194,.10);
  border:1px solid rgba(110,240,194,.28);border-radius:999px;padding:.2rem .5rem}
.v8 .sig-chart{display:block;width:100%;height:clamp(74px,13vh,150px);
  margin-top:clamp(.5rem,1.4vh,.9rem);overflow:visible}
.v8 .sig-grid line{stroke:rgba(214,255,236,.06);stroke-width:1}
.v8 .sig-area{fill:url(#sigFill)}
.v8 .sig-line{fill:none;stroke:#6ef0c2;stroke-width:2;
  stroke-linejoin:round;stroke-linecap:round}
.v8 .sig-tip{fill:#eafff6}

.v8 .sig-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(.5rem,1.1vh,.75rem);
  margin:clamp(.7rem,1.7vh,1.1rem) 0 0;padding:0;list-style:none}
.v8 .sig-tiles li{background:rgba(255,255,255,.025);border:1px solid var(--line);
  border-radius:10px;padding:clamp(.45rem,1.1vh,.7rem) .8rem}
.v8 .sig-tile-n{display:block;font-family:var(--display);font-weight:600;
  font-size:var(--step-1);letter-spacing:-.02em;color:var(--ink);
  font-variant-numeric:tabular-nums}
.v8 .sig-tile-l{display:block;margin-top:.1rem;font-family:var(--mono);
  font-size:.63rem;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}

.v8 .sig-feed{margin:clamp(.6rem,1.5vh,1rem) 0 0;padding:0;list-style:none;display:grid;gap:clamp(.35rem,.8vh,.5rem)}
.v8 .sig-event{display:grid;grid-template-columns:auto 1fr auto;align-items:center;
  gap:.7rem;padding:clamp(.4rem,.95vh,.6rem) .75rem;border-radius:9px;
  background:rgba(255,255,255,.02);border:1px solid var(--line);
  border-left:2px solid var(--sap)}
.v8 .sig-event--alert{border-left-color:#ffb454}
.v8 .sig-when{font-family:var(--mono);font-size:.65rem;letter-spacing:.08em;
  color:var(--ink-3);white-space:nowrap}
.v8 .sig-what{font-size:var(--step--1);color:var(--ink-2);min-width:0}
.v8 .sig-result{font-family:var(--mono);font-size:.65rem;letter-spacing:.04em;
  color:var(--mint);white-space:nowrap}
.v8 .sig-event--alert .sig-result{color:#ffcf8a}
.v8 .sig-foot{padding:0 clamp(.85rem,2vh,1.5rem) clamp(.6rem,1.4vh,1rem);
  font-family:var(--mono);font-size:.62rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-3)}
@media (max-width:560px){
  .v8 .sig-event{grid-template-columns:auto 1fr;row-gap:.15rem}
  .v8 .sig-result{grid-column:2}
}

/* Progress drives every opacity/transform inline from the painter (W5), so there
   is nothing to hide here. With no JS the panel simply renders finished (W7). */
@media (prefers-reduced-motion:reduce){ .v8 .b35-dot{animation:none} }

/* The way out of the strip to everything. The section shows four projects; this
   is the only click target that reaches the rest, so it is a REAL anchor over the
   canvas, not something painted into it. Gated on .v8-b4-live like the audio
   toggle, and it steps aside for the full-bleed portal. */
.v8 .b4-all{position:fixed;left:50%;bottom:1.6rem;transform:translateX(-50%);z-index:20;
  opacity:0;pointer-events:none;transition:opacity .45s var(--ease)}
.v8.v8-b4-live .b4-all{opacity:1;pointer-events:auto}
/* must out-specify .v8.v8-b4-live (0,3,0) or the live rule keeps it on screen
   right through the full-bleed project */
.v8-portal .v8.v8-b4-live .b4-all{opacity:0;pointer-events:none}
@media (prefers-reduced-motion:reduce){.v8 .b4-all{transition:none}}

/* Catalogue audio toggle. Was amber — the arcade second-accent that appears
   nowhere else on this site; now the same mint as everything around it. Hidden
   and inert unless the section is on screen. */
.v8 .v8-sound{position:fixed;right:var(--gutter);bottom:2.2rem;z-index:20;
  display:inline-flex;align-items:center;gap:.5rem;
  font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);background:rgba(8,20,16,.6);border:1px solid var(--line-2);
  border-radius:999px;padding:.5rem .85rem;cursor:pointer;
  opacity:0;pointer-events:none;transition:opacity .4s ease,border-color .2s ease,color .2s ease}
.v8.v8-b4-live .v8-sound{opacity:.7;pointer-events:auto}
.v8.v8-b4-live .v8-sound:hover,
.v8 .v8-sound:focus-visible{opacity:1;border-color:var(--mint);color:var(--mint)}
.v8 .v8-sound[aria-pressed="true"]{color:var(--mint);border-color:rgba(110,240,194,.55)}
.v8 .v8-sound-ico{font-size:.85rem;line-height:1}
.v8-portal .v8.v8-b4-live .v8-sound{opacity:0;pointer-events:none}
@media (prefers-reduced-motion:reduce){.v8 .v8-sound{transition:none}}
/* on a narrow frame the two controls would collide; stack the CTA above */
@media (max-width:640px){
  .v8 .b4-all{bottom:5.2rem}
}

.v8 #portal-layer{position:fixed;inset:0;z-index:15;pointer-events:none}
.v8 .b4-panel{position:absolute;overflow:hidden;background:#050807;
  border:1px solid var(--line);box-shadow:0 50px 130px -50px rgba(0,0,0,.95);
  will-change:left,top,width,height,opacity,clip-path;pointer-events:auto}
.v8 .b4-panel-frame{position:absolute;inset:0}
.v8 .b4-panel-frame img{width:100%;height:100%;object-fit:cover;object-position:top center}
.v8 .b4-panel-meta{position:absolute;left:0;right:0;bottom:0;z-index:1;
  display:flex;flex-direction:column;gap:.35rem;padding:clamp(1.2rem,4vw,3rem);
  background:linear-gradient(0deg,rgba(5,8,7,.94),rgba(5,8,7,.55) 55%,transparent)}
.v8 .b4-panel-name{font-size:var(--step-3);font-weight:600;letter-spacing:-.03em;line-height:1}
.v8 .b4-panel-sector{color:var(--ink-3)}
.v8 .b4-panel-link{align-self:flex-start;margin-top:.5rem}

/* phones + PORTRAIT TABLETS: the portal is a centred BROWSER-FRAMED CARD (JS sizes
   it to the site's 16:10 + this 34px chrome) so a landscape site shows in full,
   framed, over the garden — never a portrait side-crop. Wide/landscape stays
   full-bleed. Query MUST match the JS `card` condition in v8-b4.js. */
@media (max-width:640px), (max-width:1024px) and (orientation:portrait){
  .v8 .b4-panel{border-radius:14px;border-color:var(--line-2)}
  .v8 .b4-panel::before{
    content:"";position:absolute;top:0;left:0;right:0;height:34px;z-index:3;
    border-bottom:1px solid var(--line);border-radius:14px 14px 0 0;
    background:
      radial-gradient(circle 3.5px at 18px 17px,rgba(110,240,194,.6) 96%,transparent),
      radial-gradient(circle 3.5px at 36px 17px,rgba(214,255,236,.3) 96%,transparent),
      radial-gradient(circle 3.5px at 54px 17px,rgba(214,255,236,.3) 96%,transparent),
      #0b1310}
  .v8 .b4-panel-frame{top:34px}                         /* site sits below the chrome bar */
  .v8 .b4-panel-meta{padding:1rem 1.1rem}
  .v8 .b4-panel-name{font-size:var(--step-2)}
}

/* ---- B5 "the seed returns" — the closing CTA as a world beat ------------
   Transparent like every other beat: the painter draws the ground, the section
   only carries the type. Height-bounded (a pin shows exactly ONE viewport, and
   a stack that overflows it puts the button out of reach), so every step of the
   vertical rhythm is a clamp against BOTH vw and vh. */
.v8 .b5{position:relative;z-index:2;min-height:100vh;background:transparent;
  display:flex;align-items:center;pointer-events:none}
.v8 .b5-inner{width:100%;max-width:var(--container);margin-inline:auto;
  padding-inline:var(--gutter);pointer-events:none}
.v8 .b5-eyebrow{color:var(--mint);margin:0 0 clamp(.8rem,2vh,1.4rem)}
.v8 .b5-head{font-family:var(--display);font-weight:600;letter-spacing:-.035em;
  line-height:1.02;color:var(--ink);margin:0;
  font-size:clamp(2.2rem,min(7vw,9vh),5rem);text-wrap:balance;max-width:18ch}
.v8 .b5-head em{font-style:normal;color:var(--mint)}
.v8 .b5-cta{margin-top:clamp(1.6rem,4vh,2.8rem);pointer-events:auto}
/* W7: finished with no JS. v8-boot adds .b5-armed only once it owns the beat,
   and only then may anything be hidden. */
.v8.b5-armed .b5-eyebrow,
.v8.b5-armed .b5-head,
.v8.b5-armed .b5-cta{opacity:0;transform:translateY(18px);will-change:opacity,transform}
@media (prefers-reduced-motion:reduce){
  .v8.b5-armed .b5-eyebrow,.v8.b5-armed .b5-head,.v8.b5-armed .b5-cta{
    opacity:1;transform:none}
}
/* the shoot grows up the right on a wide frame and stands beside the type;
   once it is centred the type must not sit on top of it */
@media (max-width:900px){
  .v8 .b5{align-items:flex-start;padding-top:12vh}
  .v8 .b5-head{max-width:none}
}


/* ---- brand lock-up: the lotus mark + the wordmark ----------------------- */
.v8 .v8-logo-mark{width:auto;height:1.35em;display:block;flex:none}
.v8 .v8-logo-word{display:block;line-height:1}
