/* tervo.health — the landing page's one skin, for all three directions.
   It reads the system's tokens (../tokens.css, ../tokens.project.css) and adds only
   what a web page has and a phone screen does not: a measure, a page rhythm, a nav.
   The law holds here as in the apps (design/PULSE-LANGUAGE.md): the word is the
   logo and the V is the symbol, never side by side (ADR-0004) — B's line draws the
   V as an event in a phrase and the word stands once, in the nav (ADR-0020); a
   phrase is one line, one colour; the stroke never varies; the platform's colour
   is a solid on the V alone (ADR-0020). */

:root { --train:#FF6A3D; --nutri:#46CF83; --body:#D9A93C; }
* { box-sizing:border-box; }
html, body { margin:0; background:var(--background, #0B0E13); color:var(--content, #EEF0F4); }
body { font:400 17px/1.55 "Onest", system-ui, sans-serif; -webkit-font-smoothing:antialiased; }
a { color:inherit; text-decoration:none; }


/* the nav: the word, small, at the top left — it introduces; the links say where */




/* the drawn word: the master, ink, never a product colour */


/* the platform's colour, ultramarine — tervo.health only (ADR-0020): --platform, a generated token */

.plat { color:var(--platform); }
.b-strip .phrase path.plat { stroke:var(--platform); }
.b-strip .phrase path.dot { stroke:var(--content-subtle); stroke-width:3; }

/* type: Golos Text heavy for the few words that carry weight, Onest for the rest */
h1, h2, h3 { font-family:"Golos Text", system-ui, sans-serif; margin:0; letter-spacing:-.01em; }
h1 { font-weight:800; font-size:clamp(40px, 6.2vw, 76px); line-height:1.04; }
h2 { font-weight:800; font-size:clamp(28px, 3.6vw, 44px); line-height:1.1; }
h3 { font-weight:700; font-size:22px; line-height:1.2; }
.lede { font-size:clamp(18px, 1.8vw, 21px); line-height:1.5; color:var(--content-muted); max-width:34em; }
.over { font:500 14px/1 "Onest"; color:var(--content-subtle); letter-spacing:.02em; }
.muted { color:var(--content-muted); }

/* a phrase on the page: one line, round, 2px — the line component's stroke, not
   a scaled icon. The colour is the product's when the phrase is the product's. */
.phrase { display:block; width:100%; height:auto; overflow:visible; }
.phrase path, .phrase line { fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round;
                             vector-effect:non-scaling-stroke; }
.phrase .rest { stroke:var(--outline, #2A313D); }
.phrase .dormant { stroke-dasharray:1 7; stroke:var(--content-subtle); }
.t-train { color:var(--train); } .t-nutri { color:var(--nutri); } .t-body { color:var(--body); }

/* a product's own mark, generated from the V — its stroke is the mark's */
.pmark { width:56px; height:auto; display:block; }

/* glass: the surface family (ADR-0007) — and inside it nothing is filled (ADR-0015) */
.glass { background:var(--glass, #FFFFFF0e); border:1px solid var(--glass-border, #FFFFFF17); border-radius:20px;
         backdrop-filter:blur(24px); }

/* the one act: honest about where the apps are — not in a store yet */



.sec { padding:112px 0; }
.sec + .sec { border-top:1px solid var(--border, #1F242E); }
.grid3 { display:grid; grid-template-columns:repeat(3, 1fr); gap:24px; }
@media (max-width: 760px) {


  .sec { padding:72px 0; }
  .grid3 { grid-template-columns:1fr; }
}

/* ── B · the line ─────────────────────────────────────────────────────────── */
/* top only: the sides are the wrap's, so the words align with the word */
.b-hero h1 { max-width:12em; }
.b-hero .lede { margin-top:22px; }
.b-strip .phrase { height:120px; color:var(--content); }
/* each word under the middle of its own stretch of the line (Kamen): the strip's
   x maps straight onto its width, so a stretch's middle is a percentage */
.b-labels { position:relative; height:44px; margin-top:16px; font:500 15px/1.3 "Onest"; color:var(--content-subtle); }
.b-labels .lab { position:absolute; top:0; transform:translateX(-50%); text-align:center; white-space:nowrap; }
.b-labels .lab.first { transform:none; text-align:left; }
.b-labels .lab.plat { white-space:normal; width:9.5em; }
.b-labels b { font:700 16px/1.2 "Golos Text"; color:var(--content-muted); }
.b-row { display:grid; grid-template-columns:1fr 1fr; gap:64px; align-items:center; }
.b-row .b-cell { width:88px; margin-bottom:22px; } .b-row .b-cell .pmark { width:88px; }
.b-row .points { margin:22px 0 0; padding:0; list-style:none; display:flex; flex-direction:column; gap:12px; }
.b-row .points li { display:flex; gap:12px; color:var(--content-muted); }
.b-row .points li::before { content:""; flex:none; width:14px; height:2px; margin-top:13px; background:currentColor;
                            border-radius:1px; opacity:.6; }
@media (max-width: 760px) {
  .b-labels { font-size:12px; height:52px; }
  .b-labels .lab { white-space:normal; width:6.5em; }
  .b-labels .lab.plat { width:7.5em; }
  .b-row { grid-template-columns:1fr; gap:28px; }
  .b-strip .phrase { height:72px; }
}

/* Intro and arrival states are part of the molecule, including its first frame. */
.b-strip .b-line path.b-flash { stroke-width:6; opacity:0; }
.b-strip .b-line path.b-flash.plat { stroke:var(--platform); }
.moving .b-line .b-flash.on { animation:b-bloom 480ms cubic-bezier(.2, 0, 0, 1) 1 both; }
@keyframes b-bloom { 0% { opacity:0 } 15% { opacity:.6 } 100% { opacity:0 } }
.moving .b-say > * { opacity:0; }
.moving.told .b-say > * { animation:b-in 320ms cubic-bezier(.2, 0, 0, 1) both; }
@keyframes b-in { from { opacity:0; transform:translateY(10px) } to { opacity:1; transform:none } }
.moving .b-labels .lab:not(.first) { opacity:0; }
.moving .b-labels .lab.lit { animation:b-lit 480ms cubic-bezier(.2, 0, 0, 1) both; }
@keyframes b-lit { 0% { opacity:0; text-shadow:0 0 0 transparent } 15% { opacity:1; text-shadow:0 0 14px currentColor } 100% { opacity:1; text-shadow:0 0 0 transparent } }
.moving .b-row .b-cell { clip-path:inset(0 100% 0 0); transition:clip-path 800ms cubic-bezier(.2, 0, 0, 1); }
.moving .b-row.here .b-cell { clip-path:inset(0 0 0 0); }
.settled .b-say > *, .settled .b-labels .lab { opacity:1; }
.moving:not(.told) body { overflow:hidden; }
.moving:not(.told) .sec, .moving:not(.told) .tw-footer { opacity:0; visibility:hidden; }
.moving:not(.told) .tw-site-header .links, .moving:not(.told) .tw-site-header .act, .moving:not(.told) .tw-site-header .tw-mobile-navigation { opacity:0; visibility:hidden; }
.moving:not(.told) .tw-site-header { background-size:0 1px; }
.moving.told .tw-site-header .links, .moving.told .tw-site-header .act { animation:b-in 320ms cubic-bezier(.2, 0, 0, 1) both; }
.tw-site-header { transition:background-size 480ms cubic-bezier(.2, 0, 0, 1); }
.moving .b-strip path.dot { opacity:0; transition:opacity 120ms linear; }
.moving .b-strip path.dot.on, .settled .b-strip path.dot { opacity:1; }

/* ── B, tightened (Kamen's reference, 4 Oct 2026) ────────────────────────────
   the header: the words left, the three apps' Днес fanned right; sections that
   end where their phone is cut by the next one; the end on one row */

.b-hero { padding-top:48px; }
.b-top { display:grid; grid-template-columns:1fr 1.15fr; gap:32px; align-items:center; }
.b-say { margin-top:0; }
.b-say h1 { font-size:clamp(44px, 5.4vw, 72px); }
.b-fan { position:relative; }
.b-fan .fan { position:absolute; width:196px; border-radius:26px; border:1px solid var(--glass-border, #FFFFFF17);
              box-shadow:0 30px 60px -20px #000; }
.b-strip { margin:36px 0 0; }

/* a section: kicker, headline, line, two points; the phone cut by the section's edge */
.b-sec { padding:0; overflow:hidden; }
.b-sec .b-row { grid-template-columns:1fr 1fr; gap:48px; align-items:center; }
.b-text .tw-kicker { margin:0 0 18px; }
.b-text h2 { font-size:clamp(32px, 3.4vw, 46px); line-height:1.06; }
.b-text .lede { margin-top:14px; }
.b-text .points { margin:24px 0 0; padding:0; list-style:none; display:flex; flex-direction:column; gap:14px; }
.b-text .points li { display:flex; align-items:center; gap:14px; color:var(--content-muted); }
.b-text .points li::before { content:none; }
.ring { flex:none; width:40px; height:40px; border-radius:999px; border:1px solid var(--glass-border, #FFFFFF17);
        display:grid; place-items:center; color:var(--content); }
.ring svg { width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:1.25; stroke-linecap:round; stroke-linejoin:round; }
.ring svg * { fill:none; }
.b-vis { justify-content:center; }
.chip { position:absolute; display:flex; align-items:center; gap:14px; padding:16px 20px; border-radius:18px; }
.chip .ring { border:0; width:32px; height:32px; color:var(--web-accent); }
.chip small { display:block; font:400 13px/1.2 "Onest"; color:var(--content-muted); }
.chip b { display:block; margin-top:4px; font:700 20px/1.1 "Golos Text"; }

/* the end: the sentence left, the act right */
.b-end { padding:72px 0; }
.b-endrow { display:grid; grid-template-columns:1fr 1fr; gap:40px; align-items:center; }

.b-endrow h2 { font-size:clamp(32px, 3.6vw, 46px); }

@media (max-width: 960px) {
  .b-top, .b-sec .b-row, .b-endrow { grid-template-columns:1fr; }
  .b-fan { display:none; }               /* on a phone the sections carry the phones */
  .b-sec .b-row { min-height:0; gap:0; }
  .b-text { padding:56px 0 24px; }
  .b-sec-1 .b-vis { order:2; }
  .chip { right:0; top:40px; padding:12px 14px; }

}

/* while the line is drawn the header's phones wait with everything else; then they rise in */
.moving:not(.told) .b-fan { opacity:0; }
.moving.told .b-fan .fan { animation:b-in 480ms cubic-bezier(.2, 0, 0, 1) both; }
.moving.told .b-fan .fan-1 { animation-delay:80ms; } .moving.told .b-fan .fan-2 { animation-delay:160ms; }
.settled .b-fan { opacity:1; }



/* the fan, as phones (Kamen): the outer two tilted toward the middle, behind it */
.b-fan .fan-1 { left:50%; z-index:2; }
.b-fan .fan-2 { left:auto; }
.moving.told .b-fan .fan-0 { animation:b-in-l 480ms cubic-bezier(.2, 0, 0, 1) both; }
.moving.told .b-fan .fan-2 { animation:b-in-r 480ms cubic-bezier(.2, 0, 0, 1) 160ms both; }

/* ── the scenes behind the products (Kamen's, 4 Oct 2026) ─────────────────────
   each darkened toward its words, so the words read and the scene stays a scene */
.b-scene { position:relative; background-color:#0B0E13; background-size:cover; background-position:center; }
.b-scene::before { content:""; position:absolute; inset:0; pointer-events:none; }
.b-scene > .wrap { position:relative; }





.b-sec + .b-sec { border-top:0; }

/* the phones larger, turned a little in space, cut by the section's edge */
/* placed beside each scene's own subject, so the bar, the plate and the scale stay seen */



@media (max-width: 960px) {

  .b-scene::before { background:linear-gradient(0deg, #0B0E13 0%, #0B0E13cc 40%, #0B0E1399 100%) !important; }
  .chip { left:auto; right:0; top:60px; }
}

/* the fan, a little in space (Kamen): the outer two turned toward the middle and set back */
.moving.told .b-fan .fan-1 { animation:b-in-c 480ms cubic-bezier(.2, 0, 0, 1) 80ms both; }

/* the header's rule (Kamen's reference): one hairline under the nav, the content's width */



/* ── the 3D as in Kamen's reference (5 Oct 2026) ──────────────────────────────
   the fan nearly upright — the outer two a few degrees off and set lower, behind
   a larger middle one; the sections' phones zoomed and turned a little, the
   section cutting them about half-way down */
.b-fan { height:520px; }
.b-fan .fan-0 { left:0; top:44px; }
.b-fan .fan-2 { right:0; top:44px; }
.b-fan .fan-1 { top:0; width:246px; margin-left:-123px; }
@keyframes b-in-c { from { opacity:0; transform:translateY(16px) } to { opacity:1; transform:none } }

.b-sec .b-row { min-height:420px; }
.b-text { padding:56px 0; }
.b-vis { align-self:stretch; display:block; }
.chip { z-index:2; }
@media (max-width: 960px) {
  .b-vis { display:flex; justify-content:center; height:300px; overflow:hidden; }
  .chip { right:0; top:24px; }
}

/* ── the sections as in Kamen's reference (5 Oct 2026) ────────────────────────
   the scenes mirrored and a little darker (in the files); the phones placed as
   the reference places them — large, a few degrees clockwise, flat to the eye,
   starting at the section's top and cut by its bottom */


.b-vis { position:static; perspective:none; }
@media (max-width: 960px) {
  .b-vis { position:relative; display:flex; justify-content:center; height:300px; overflow:hidden; }
  .chip { right:0; top:24px; }
}
.chip { left:83%; right:auto; top:104px; }
@media (max-width: 960px) { .chip { left:auto; right:0; top:24px; } }

/* ── the phones in 3D, read off Kamen's reference by their edges ──────────────
   the sections' phones lie back — wider at the bottom than at the top — with a
   breath of turn (Train and Body clockwise, Nutrition the other way); the fan's
   outer two turn their inner edge toward us, the middle one faces us */
.b-fan { perspective:1100px; perspective-origin:50% 45%; }
.b-fan .fan-0 { transform-origin:50% 50%; }
.b-fan .fan-2 { transform-origin:50% 50%; }
.b-fan .fan-1 { transform:none; }

/* the fan as the reference has it: the outer two turned to face the middle one,
   their outer edges near — and their sides showing */
.b-fan .fan-0 { transform:rotateY(22deg); }
.b-fan .fan-2 { transform:rotateY(-22deg); }
@keyframes b-in-l { from { opacity:0; transform:translateY(16px) rotateY(22deg) } to { opacity:1; transform:rotateY(22deg) } }
@keyframes b-in-r { from { opacity:0; transform:translateY(16px) rotateY(-22deg) } to { opacity:1; transform:rotateY(-22deg) } }

/* the ask for the scroll: a hairline mouse (a phone, on touch) and the word — a button; a tap plays
   the next phase, as a turn of the scroll does; gone once the line is told */
.b-hint { display:none; align-items:center; gap:8px; margin:28px 0 0; color:var(--content-muted);
          font:500 13px/1 "Onest"; }
.b-hint svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.25; stroke-linecap:round; stroke-linejoin:round; }

/* ── Kamen's frame (frames/compose.py): the phones are pictures now, their turn
   and their sides in the picture — no CSS 3D on them */
.phone3d { display:block; height:auto; filter:drop-shadow(0 40px 50px #000000b0); }
.b-vis img.phone3d { position:absolute; top:0; width:440px; transform:none; }



.b-fan img.phone3d.fan { position:absolute; transform:none !important; }
.b-fan img.fan-0 { left:-2%; } .b-fan img.fan-2 { right:-2%; left:auto; }
.moving.told .b-fan img.fan-0, .moving.told .b-fan img.fan-2 { animation:b-in 480ms cubic-bezier(.2, 0, 0, 1) both; }
.moving.told .b-fan img.fan-2 { animation-delay:160ms; }

.b-fan img.phone3d.fan { border:0; border-radius:0; box-shadow:none; padding:0; background:none; }
.b-fan img.phone3d.fan-1 { z-index:2; }
/* the fan sized by height — the frames differ in width (a turned phone shows its side) */
.b-fan img.phone3d.fan { width:auto; height:430px; top:56px; }
.b-fan img.phone3d.fan-1 { height:500px; top:0; width:auto; left:50%; margin-left:0; transform:translateX(-50%) !important; }
.b-fan img.phone3d.fan-0 { left:-4%; } .b-fan img.phone3d.fan-2 { right:-4%; left:auto; }
.moving.told .b-fan img.fan-1 { animation:b-in-c1 480ms cubic-bezier(.2, 0, 0, 1) 80ms both; }
@keyframes b-in-c1 { from { opacity:0; transform:translate(-50%, 16px) } to { opacity:1; transform:translate(-50%, 0) } }

/* ── the steps (Kamen; the default — ?intro=play is the board's): the stage held while the phases play
   the header pinned inside a tall wrap; the carousel of phases at the right; the
   ask for the scroll at the foot of the screen, its glyph moving until the page is told */
.b-phases { display:none; }
.intro-steps .b-phases { display:block; position:absolute; top:calc(50% - 10px); margin:0; padding:0; list-style:none; text-align:right; font:600 14px/1 "Onest"; color:var(--content-muted); }
.intro-steps .b-phases li { position:absolute; right:0; top:0; white-space:nowrap; transform-origin:100% 50%;
  transition:transform 320ms cubic-bezier(.2, 0, 0, 1), opacity 320ms cubic-bezier(.2, 0, 0, 1); }
.intro-steps .b-phases li.plat { color:var(--platform); }
.intro-steps .b-phases li.now { font-size:16px; }
.intro-steps .b-phases li.now::before { content:""; display:inline-block; height:2px; margin-right:10px; vertical-align:middle; border-radius:1px; background:currentColor; }
.intro-steps.told .b-phases { opacity:0; transition:opacity 480ms; }
.intro-steps .b-hero { position:relative; }
/* the ask, in the middle of the stage */
.intro-steps.ready:not(.playing):not(.told) .b-hint { display:flex; position:absolute; left:50%; transform:translateX(-50%); margin:0; flex-direction:column; }
.intro-steps.told .b-hint { display:none; }
/* the hint is a mouse, its wheel rolling — the gesture the page asks for (Kamen, 6 Oct 2026) */
.b-scroll-wheel { animation:b-scroll-wheel 1s ease-in-out infinite alternate; }
@keyframes b-scroll-wheel {
  from { transform:translateY(0); }
  to { transform:translateY(4px); }
}
/* on a touch screen the ask is the gesture the thumb makes: a phone, a stroke rising up it
   (Kamen, 6 Oct 2026) — decided by the pointer, not the width: a narrow window with a mouse keeps the mouse */
.b-hint .by-touch { display:none; }
@media (hover: none) and (pointer: coarse) { .b-hint .by-wheel { display:none; } .b-hint .by-touch { display:inline; } }
.b-swipe { animation:b-swipe 1.6s cubic-bezier(.2, 0, 0, 1) infinite; }
@keyframes b-swipe {
  0% { transform:translateY(3px); opacity:0; }
  20% { opacity:1; }
  70% { transform:translateY(-3px); opacity:1; }
  100% { transform:translateY(-3px); opacity:0; }
}
@media (prefers-reduced-motion:reduce) { .b-scroll-wheel, .b-swipe { animation:none; } }
/* it waits for the reader, so it pulses (§10): the glyph's stroke moves (the wheel rolls,
   the swipe rises), never a turn; the word stands still in --content, over 4.5:1 throughout */
@media (max-width: 960px) { .intro-steps .b-phases { right:0; font-size:12px; width:110px; } }
.intro-steps.ready:not(.playing):not(.told) .b-hint { font-size:15px; gap:10px; color:var(--content); }
.intro-steps .b-hint svg { width:28px; height:28px; }
/* the stage is the first screen: the page held at the top until the last phase */
/* while the stage is held the word keeps its place at the top, however the page stands (landing.js letGo) */
.held .nav { position:sticky; top:0; z-index:20; }
.intro-steps .b-hero { min-height:calc(100vh - var(--web-header-height)); min-height:calc(100svh - var(--web-header-height)); box-sizing:border-box; }   /* svh: the screen as it opens, URL bar and all (iOS Safari) */
/* the phases as marks only (Kamen): a short dash each; the one playing longer, in its colour */
.intro-steps .b-phases { width:40px; right:0; }
.intro-steps .b-phases li { width:40px; height:2px; text-align:right; }
.intro-steps .b-phases li::before, .intro-steps .b-phases li.now::before { content:""; display:block; margin:0 0 0 auto;
  width:14px; height:2px; border-radius:1px; background:currentColor; transition:width 320ms cubic-bezier(.2, 0, 0, 1); }
.intro-steps .b-phases li.now::before { width:36px; }
.intro-steps .b-phases li:not([class]), .intro-steps .b-phases li[class=""], .intro-steps .b-phases li.now:not(.plat):not(.t-train):not(.t-nutri):not(.t-body) { color:var(--content-muted); }
/* the ask for the scroll is a button (Kamen) — clickable, and drawn exactly as it was */
button.b-hint { background:none; border:0; padding:0; cursor:pointer; }
button.b-hint:focus-visible { outline:2px solid var(--focus-ring, #74A6FF); outline-offset:4px; border-radius:6px; }
button.b-hint:hover, .intro-steps.ready:not(.playing):not(.told) button.b-hint:hover { color:var(--platform); }

/* ── the phone, fixed (Kamen, 5 Oct 2026) ─────────────────────────────────────
   the carousel inside the wrap's margin, not on the glass's edge; the words under
   the line on two rows, so the beat's long name never lands on the pause; the
   sections' phones centred whole under their words, the chip on the phone's
   near corner instead of off the edge */
@media (max-width: 960px) {
  .intro-steps .b-phases { right:var(--web-page-inset); }

  .b-vis { height:340px; margin-bottom:40px; }   /* the phone a breath above the next section, not on its edge */
  .chip { left:0; right:auto; top:auto; bottom:48px; }
}
/* on a phone the email gets a row of its own, the button the row under it — room to type */

@media (max-width: 760px) {
  .intro-steps .b-phases { right:20px; }
  .b-labels { height:58px; }
  .b-labels .lab { width:auto; white-space:nowrap; }
  .b-labels .lab.plat, .b-labels .lab.t-nutri { top:20px; }
  .b-labels .lab.plat { white-space:normal; width:8.5em; }
  .b-labels .lab:last-child { transform:translateX(-62%); }
}

/* ── the stage (Kamen, 6 Oct 2026: D) ─────────────────────────────────────────
   While the line is told it is the whole first screen: drawn edge to edge
   through the middle, on the grid it is drawn on, under the name of the phase it
   is in, in that phase's colour. The stroke stays 2 px, at any size: the line is
   large, never heavier. One more turn of the scroll and the page is told: the name
   lifts away, the line travels down to its place under the words (landing.js
   flight), the headline rises in a word at a time, and the three phones rise in
   behind it, left to right, as the line reads. Without the script, and under
   reduced motion, none of this exists: the page stands as told. */
.b-stage { display:none; }
.moving .b-stage { display:block; }
.moving { --st-in:48px; --st-lh:200px; --st-ly:calc(50vh - 40px); }
@media (max-width: 960px) { .moving { --st-in:20px; --st-lh:120px; --st-ly:calc(50vh - 20px); } }
/* the grid the line is drawn on: a column every 20 of its units — every joint of
   the line lands on one — a heavier one every five; its baseline on a rule */
.b-paper { position:fixed; inset:0; z-index:0; pointer-events:none; --u:calc((100vw - 2 * var(--st-in)) / 56);
  background-image:linear-gradient(90deg, #FFFFFF0d 1px, transparent 1px), linear-gradient(0deg, #FFFFFF0d 1px, transparent 1px),
                   linear-gradient(90deg, #FFFFFF05 1px, transparent 1px), linear-gradient(0deg, #FFFFFF05 1px, transparent 1px);
  background-size:calc(var(--u) * 5) calc(var(--u) * 5), calc(var(--u) * 5) calc(var(--u) * 5), var(--u) var(--u), var(--u) var(--u);
  background-position:var(--st-in) calc(var(--st-ly) + var(--st-lh) * 70 / 120);
  -webkit-mask:radial-gradient(ellipse 72% 64% at 50% 55%, #000 25%, transparent 100%);
          mask:radial-gradient(ellipse 72% 64% at 50% 55%, #000 25%, transparent 100%); }
@media (max-width: 960px) {   /* on a phone, the heavier rules only: the finer would be a texture, not a grid */
  .b-paper { background-image:linear-gradient(90deg, #FFFFFF0b 1px, transparent 1px), linear-gradient(0deg, #FFFFFF0b 1px, transparent 1px);
             background-size:calc(var(--u) * 5) calc(var(--u) * 5); }
}
/* the light behind the name: one colour, the name's, barely there — it changes with the
   name, on the same beat, and goes with the stage (Kamen, 6 Oct 2026). A wash, not the V's
   gradient: one hue at a time, never two */
@property --tint { syntax:'<color>'; inherits:true; initial-value:#00000000; }
.b-stage { --tint:var(--content-subtle); transition:--tint 800ms cubic-bezier(.2, 0, 0, 1); }
.b-stage[data-at="beat"] { --tint:var(--platform); }
.b-stage[data-at="effort"] { --tint:var(--train); }
.b-stage[data-at="growth"] { --tint:var(--nutri); }
.b-stage[data-at="calm"] { --tint:var(--body); }
.b-stage::before { content:""; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:radial-gradient(ellipse 46% 34% at 50% calc(var(--st-ly) - 80px),
             color-mix(in srgb, var(--tint) 13%, transparent), transparent 100%); }
@media (max-width: 960px) {
  .b-stage::before { background:radial-gradient(ellipse 90% 26% at 50% calc(var(--st-ly) - 60px),
                     color-mix(in srgb, var(--tint) 14%, transparent), transparent 100%); }
}
@media (prefers-reduced-motion: reduce) { .b-stage { transition:none; } }
/* the phase's name: one at a time, changed on the beat, as the line lands (landing.js glow) */
.b-word { position:fixed; left:0; right:0; z-index:1; margin:0; pointer-events:none; text-align:center;
          top:calc(var(--st-ly) - 200px); height:150px; font:800 clamp(56px, 9vw, 136px)/150px "Golos Text", system-ui, sans-serif;
          letter-spacing:-.02em; }
.b-word span { position:absolute; left:0; right:0; opacity:0; transform:translateY(14px);
               transition:opacity 320ms cubic-bezier(.2, 0, 0, 1), transform 320ms cubic-bezier(.2, 0, 0, 1); }
.b-word span[data-at="pause"] { color:var(--content-subtle); }
.b-word span.now { opacity:1; transform:none; }
.moving.told .b-word span.now { opacity:0; transform:translateY(-24px); }
/* the longest name, «Постоянството.», is 7.7 times its size wide: 11vw holds it inside the
   wrap's own 20px down to 320, where 44px ran 10px past each edge */
@media (max-width: 960px) { .b-word { top:calc(var(--st-ly) - 132px); height:80px; line-height:80px; font-size:min(44px, 11vw); } }
.moving.told .b-stage { opacity:0; visibility:hidden; transition:opacity 480ms cubic-bezier(.2, 0, 0, 1), visibility 0s 480ms; }
/* the line on the stage; its names under it wait for the page, and arrive when it has landed */
.moving:not(.told) .b-strip { position:fixed; left:var(--st-in); right:var(--st-in); top:var(--st-ly); margin:0; z-index:1; }
.moving:not(.told) .b-strip .phrase { height:var(--st-lh); }
.moving:not(.told) .b-labels { visibility:hidden; }
.moving.told .b-labels { animation:b-in 320ms cubic-bezier(.2, 0, 0, 1) 800ms both; }
/* the ask for the scroll, under the line */
/* the hint stands clear of the line, at the foot of the screen — where the scroll will go */
.intro-steps.ready:not(.playing):not(.told) .b-hint { position:fixed; top:auto; bottom:calc(80px + env(safe-area-inset-bottom, 0px)); z-index:2; }
/* a short desktop screen (a laptop with its devtools docked): the stage takes the phone's
   proportions — a lower, shorter line, a smaller name — so the name clears the nav and the
   hint clears the line down to ~480px tall */
@media (min-width: 961px) and (max-height: 640px) {
  .moving { --st-lh:120px; --st-ly:calc(50vh - 20px); }
  .b-word { top:calc(var(--st-ly) - 132px); height:80px; line-height:80px; font-size:64px; }
  .intro-steps.ready:not(.playing):not(.told) .b-hint { bottom:calc(48px + env(safe-area-inset-bottom, 0px)); }
}
/* the headline rises in a word at a time, each from under its own edge; then the line under it, then the ask */
.b-say h1 .wd { display:inline-block; overflow:hidden; vertical-align:top; padding:.06em 0 .16em; margin:-.06em 0 -.16em; }
.b-say h1 .wd > span { display:inline-block; }
.moving.told .b-say > h1 { animation:none; opacity:1; }
.moving:not(.told) .b-say h1 .wd > span { transform:translateY(115%); }
.moving.told .b-say h1 .wd > span { animation:b-word 640ms cubic-bezier(.2, 0, 0, 1) both; animation-delay:calc(240ms + var(--i, 0) * 48ms); }
@keyframes b-word { from { transform:translateY(115%) } to { transform:none } }
.moving.told .b-say > :nth-child(2) { animation-delay:640ms; }
.moving.told .b-say > :nth-child(3) { animation-delay:760ms; }
/* the three phones rise in behind the words, left to right, as the line reads — a surface arriving */
.moving.told .b-fan img.fan-0, .moving.told .b-fan img.fan-1, .moving.told .b-fan img.fan-2 { animation:b-rise 800ms cubic-bezier(.2, 0, 0, 1) 360ms both; }
.moving.told .b-fan img.fan-1 { animation-delay:480ms; }
.moving.told .b-fan img.fan-2 { animation-delay:600ms; }
@keyframes b-rise { from { opacity:0; translate:0 96px; scale:.92 } to { opacity:1; translate:0 0; scale:1 } }
.moving.told .nav .links, .moving.told .nav .act { animation-delay:800ms; }
/* on a phone the three stand over the words, smaller — the first thing the page shows when it is told */
@media (max-width: 960px) {
  .b-fan { display:block; order:-1; height:250px; margin:-28px 0 12px; }
  .b-fan img.phone3d.fan { height:200px; top:40px; }
  .b-fan img.phone3d.fan-1 { height:244px; top:0; }
  /* the side phones reach into the wrap's own 20px, never past it: no sideways scroll at 320 */
  .b-fan img.phone3d.fan-0 { left:max(-20px, calc(50% - 172px)); }
  .b-fan img.phone3d.fan-2 { right:max(-20px, calc(50% - 172px)); left:auto; }
}
/* the carousel of phases off the line: at the height of the phase's name, at the
   stage's edge; on a phone, where the name is the screen's width, under the line */
.moving:not(.told) .b-phases { position:fixed; top:calc(var(--st-ly) - 125px); right:var(--st-in); z-index:2; }
@media (max-width: 960px) { .moving:not(.told) .b-phases { top:calc(var(--st-ly) + var(--st-lh) + 64px); right:var(--st-in); } }

/* the sections' phones (Kamen, 6 Oct 2026): as a product's row comes into view its phone
   swipes up into its place out of the dark — 96px, from the screen off to lit, once — and
   the chip it carries lands a beat after. The same verb as the fan: phones rise */
.moving .b-row .b-vis img.phone3d { opacity:0; translate:0 96px; filter:drop-shadow(0 40px 50px #000000b0) brightness(.35);
  transition:opacity 640ms cubic-bezier(.2, 0, 0, 1), translate 960ms cubic-bezier(.16, 1, .3, 1), filter 960ms cubic-bezier(.2, 0, 0, 1); }
.moving .b-row.here .b-vis img.phone3d { opacity:1; translate:0 0; filter:drop-shadow(0 40px 50px #000000b0) brightness(1); }
.moving .b-row .b-vis .chip { opacity:0; translate:0 16px; transition:opacity 480ms cubic-bezier(.2, 0, 0, 1) 480ms, translate 480ms cubic-bezier(.2, 0, 0, 1) 480ms; }
.moving .b-row.here .b-vis .chip { opacity:1; translate:0 0; }

/* the ask's beat (Kamen, 6 Oct 2026): arriving at the ask is an event, so the field
   beats once — its edge lights in the V's colour, 0 → 1 at 15% → 0 over 800 ms — the
   first time it comes into view, never again. A glow on the event, never a ring that spreads (§6) */



@keyframes b-beat { 0% { opacity:0 } 15% { opacity:1 } 100% { opacity:0 } }

/* Molecule configuration replaces archived inline placement and scene styles. */
.tw-glyph:not(.ring):not(.b-cell):not(.tw-icon){display:contents}.tw-glyph.b-cell{display:block}.tw-glyph[data-tone]{color:var(--web-accent)}
.tw-intro-form{margin-top:32px}.b-labels [data-at=pause]{left:0}.b-labels [data-at=beat]{left:21.43%}.b-labels [data-at=effort]{left:41.96%}.b-labels [data-at=growth]{left:65.18%}.b-labels [data-at=calm]{left:88.39%}
[data-tone=platform]{--web-accent:var(--platform)}[data-tone=Train]{--web-accent:var(--train)}[data-tone=Nutrition]{--web-accent:var(--nutri)}[data-tone=Body]{--web-accent:var(--body)}
.b-word [data-tone],.b-labels [data-tone],.b-phases [data-tone]{color:var(--web-accent)}
.b-labels [data-at=beat]{white-space:normal;width:9.5em}
.tw-product-scene{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.b-scene:before{z-index:1;background:linear-gradient(90deg,#0B0E13e0 0%,#0B0E13b3 45%,#0B0E1366 100%),linear-gradient(0deg,#0B0E13,transparent 18%)}
.b-scene[data-reverse=true]:before{background:linear-gradient(270deg,#0B0E13e0 0%,#0B0E13b3 45%,#0B0E1366 100%),linear-gradient(0deg,#0B0E13,transparent 18%)}
.b-scene>.tw-container{position:relative;z-index:2}
.b-scene[data-reverse=true] .b-text{order:2}.b-scene[data-reverse=true] .b-vis{order:1}
.b-scene .b-vis img.phone3d{left:50%}.b-scene[data-reverse=true] .b-vis img.phone3d{left:-10%;width:460px}
.chip .ring{color:var(--web-accent)}
.b-phones{min-width:0}.store-availability{margin:14px 0 0;text-align:center;line-height:1.5;letter-spacing:0}.store-availability-mobile{display:none}.moving:not(.told) .store-availability-desktop{visibility:hidden}
.intro-loading .b-phones,.intro-loading .b-strip [clip-path],.intro-loading .b-phases{visibility:hidden}.intro-loading .b-word span[data-at=pause]{opacity:1;transform:none}
@media(max-width:960px){.b-phones{display:none}.store-availability-mobile{display:block;margin:0 auto 40px}.b-scene .b-vis{margin-bottom:16px}.b-scene[data-reverse=true] .b-text{order:1}.b-scene[data-reverse=true] .b-vis{order:2}.b-scene .b-vis img.phone3d,.b-scene[data-reverse=true] .b-vis img.phone3d{position:relative;left:auto;width:290px;margin:0 auto}}
@media(max-width:760px){.b-labels [data-at=beat]{width:7.5em}}
