
/* self-hosted faces, so the CSP does not have to be widened for a typeface.
     latin and latin-ext are complementary cuts: without the ranges the
     second rule of each pair would shadow the first. */
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/space-grotesk-latin-400-normal.woff2) format('woff2');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}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/space-grotesk-latin-ext-400-normal.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:500;font-display:swap;src:url(../fonts/space-grotesk-latin-500-normal.woff2) format('woff2');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}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:500;font-display:swap;src:url(../fonts/space-grotesk-latin-ext-500-normal.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:700;font-display:swap;src:url(../fonts/space-grotesk-latin-700-normal.woff2) format('woff2');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}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:700;font-display:swap;src:url(../fonts/space-grotesk-latin-ext-700-normal.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/noto-sans-latin-400-normal.woff2) format('woff2');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}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/noto-sans-latin-ext-400-normal.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:500;font-display:swap;src:url(../fonts/noto-sans-latin-500-normal.woff2) format('woff2');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}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:500;font-display:swap;src:url(../fonts/noto-sans-latin-ext-500-normal.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:600;font-display:swap;src:url(../fonts/noto-sans-latin-600-normal.woff2) format('woff2');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}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:600;font-display:swap;src:url(../fonts/noto-sans-latin-ext-600-normal.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

/* ============================================================
   TOKENS  brand layer from the Figma, structure from earlier scaffolds
   ============================================================ */
:root{
  --ws-ink:#15344B;
  --ws-teal:#03B8A5;
  --ws-aqua:rgba(0,255,229,.2);
  --ws-sky:#E2F5FF;
  --ws-sky-2:#D8F1FF;
  --ws-paper:#FFFFFF;
  --ws-body:#000000;
  --ws-line:rgba(21,52,75,.14);
  --ws-line-light:rgba(255,255,255,.2);
  --ws-duo:#1C5F91;               /* the blue every photograph is printed in */
  --ws-seam:clamp(64px,12vh,150px); /* how far the card rides up into the band */

  --ws-gutter:20px;
  --ws-maxw:1416px;
  --ws-radius:32px;
  --ws-header-h:104px;
  /* the sticky stack: where a card pins, and the sliver of the one underneath
     that stays visible below it */
  --ws-card-top:calc(var(--ws-header-h) + 12px);
  --ws-card-gap:24px;
  /* How long each card is held alone on screen before the next one starts to
     cover it. Without this, card one is eaten the moment it pins and is never
     seen at full height, which is what made it read as the shorter of the two. */
  --ws-card-hold:20vh;

  --ws-fs-mega:clamp(3.6rem,17.6vw,261px);
  --ws-fs-h1:clamp(2.9rem,8.1vw,120px);
  --ws-fs-h2:clamp(2.2rem,4.05vw,60px);
  --ws-fs-h3:clamp(1.9rem,3.1vw,46px);
  --ws-fs-h4:clamp(1.4rem,2.16vw,32px);
  --ws-fs-tile:clamp(1.9rem,4.3vw,64px);
  --ws-fs-lede:clamp(1.1rem,1.82vw,27px);
  --ws-fs-body:clamp(1rem,1.21vw,18px);
  --ws-fs-nav:16px;

  --ws-ease:cubic-bezier(.22,.61,.36,1);
  --ws-dur:800ms;
}
@media (min-width:1024px){ :root{ --ws-gutter:32px; } }

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--ws-paper);color:var(--ws-body);
  font-family:'Noto Sans',system-ui,sans-serif;font-weight:500;
  font-size:var(--ws-fs-body);line-height:1.33;letter-spacing:.02em;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4{margin:0}
p{margin:0}
:focus-visible{outline:3px solid var(--ws-teal);outline-offset:3px}

.d{font-family:'Space Grotesk',system-ui,sans-serif;font-weight:500;letter-spacing:-.05em;color:var(--ws-ink);text-wrap:balance}
.mega{font-size:var(--ws-fs-mega);line-height:.83}
.h1{font-size:var(--ws-fs-h1);line-height:1.09;color:var(--ws-body)}
.h2{font-size:var(--ws-fs-h2);line-height:1.17}
.h3{font-size:var(--ws-fs-h3);line-height:1.28;font-weight:700}
.h4{font-size:var(--ws-fs-h4);line-height:1.28}
.tile-t{font-size:var(--ws-fs-tile);line-height:1.14;font-weight:700}
.lede{font-size:var(--ws-fs-lede);line-height:1.55;letter-spacing:.02em}
.body{font-size:var(--ws-fs-body);line-height:1.33;letter-spacing:.02em}
.label{font-family:'Noto Sans',sans-serif;font-weight:500;font-size:var(--ws-fs-nav);line-height:1.375;text-transform:uppercase}

.wrap{max-width:var(--ws-maxw);margin-inline:auto;padding-inline:var(--ws-gutter)}

/* ============================================================
   BUTTONS  the angled edge, from the CTA shape study.

   A chamfer at the top left that runs the full height, so the button leans
   in the direction everything else on this site travels. Three things about
   the construction are deliberate.

   The fill lives on ::before rather than on the element. clip-path clips
   everything an element paints, its outline included, so a clipped button
   loses its focus ring. Clipping only the fill layer leaves the element's
   own box rectangular, and the ring is drawn on that.

   --ws-cut is registered with @property so it can transition. A plain custom
   property inside clip-path() jumps between values instead of animating.

   Padding compensates for the diagonal but never changes on hover. The label
   is fixed; only the notch moves.
   ============================================================ */
@property --ws-cut{syntax:'<length>';inherits:true;initial-value:12px}

.btn{
  --ws-cut:12px;                 /* 12 across 38 is 17.5 degrees off vertical */
  --ws-cut-hover:18px;
  --ws-btn-bg:var(--ws-paper);   /* what the outline variant fills itself with */
  position:relative;isolation:isolate;
  display:inline-flex;align-items:center;gap:12px;
  /* the extra 6px on the left is half the cut, so the label sits optically
     centred inside the visible shape rather than inside the box */
  padding:8px 16px 8px 22px;min-height:38px;border:0;border-radius:0;cursor:pointer;
  font-family:'Noto Sans',sans-serif;font-weight:600;font-size:var(--ws-fs-nav);
  line-height:1.375;text-transform:uppercase;letter-spacing:.02em;
  background:transparent;color:var(--ws-ink);white-space:nowrap;
  transition:--ws-cut 260ms var(--ws-ease),transform 220ms var(--ws-ease);
}
.btn::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:var(--ws-teal);
  clip-path:polygon(var(--ws-cut) 0,100% 0,100% 100%,0 100%);
  transition:background 220ms var(--ws-ease);
}
.btn:hover{--ws-cut:var(--ws-cut-hover);color:#fff}
.btn:hover::before{background:var(--ws-ink)}
.btn:active{transform:translateY(1px)}

/* Quiet stays a text control. Giving it the shape would contradict the
   decision that the secondary action is the one not asking for attention. */
.btn-quiet{background:transparent;color:var(--ws-body)}
.btn-quiet::before,.btn-quiet:hover::before{background:transparent}
.btn-quiet:hover{--ws-cut:12px;color:var(--ws-teal-deep)}

/* The large size keeps the angle rather than the inset: 18 across 56 is 17.8
   degrees, so it reads as the same cut at a different scale. */
.btn-lg{--ws-cut:18px;--ws-cut-hover:26px;padding:16px 28px 16px 37px;min-height:56px;font-size:18px}

/* ============================================================
   0  HEADER  Figma spec
   ============================================================ */
.hdr{
  position:fixed;top:0;left:0;right:0;z-index:80;height:var(--ws-header-h);
  background:var(--ws-paper);
  transition:box-shadow 320ms var(--ws-ease);
}
.hdr.solid{box-shadow:0 1px 0 var(--ws-line)}
.hdr > .wrap{height:100%;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:24px}
/* The horizontal lockup, mark v1.0 Ascent (2026-08-31, restored 2026-09-20
   after a stage_site.py run reverted it on every page). The mark is INLINE SVG
   rather than an <img>: it costs no second request, and fitNav below measures
   .brand on document.fonts.ready, which an image would not be laid out for. The
   word stays live Space Grotesk 500 at -0.05em, which is how this site has
   always set the brand.
   Cap height is 24.5px, just over the brand floor of 24px on white, and it no
   longer steps down with the breakpoints: the old 28/26/24px steps put the word
   at a 16.8px cap on a phone, well under the floor the teal "wise" needs. The
   whole lockup is about 170px wide, which still leaves room for the menu button
   at 375px. */
.brand{display:flex;align-items:center;gap:10px;text-decoration:none}
.brand-mark{height:38px;width:38px;flex:none;display:block}
.brand-mark path{fill:var(--ws-ink)}
.brand-mark path.a{fill:var(--ws-teal)}
.brand-word{font-family:'Space Grotesk',sans-serif;font-weight:500;font-size:35px;letter-spacing:-.05em;line-height:1}
.brand-word .t{color:var(--ws-ink)}
.brand-word .w{color:var(--ws-teal)}
/* six items now, so the gap tightens before the nav can reach either side */
.nav{position:relative;justify-self:center;display:flex;align-items:center;gap:clamp(18px,2.4vw,40px)}
.nav > a,.nav-trigger{position:relative;color:var(--ws-body);opacity:.6;transition:opacity 200ms var(--ws-ease)}
.nav > a:hover,.nav > a.active,.nav-trigger:hover,.nav-trigger.active,.nav-group.open .nav-trigger{opacity:1}

/* The three audience segments live under one trigger. Four top level items
   instead of six, and the group can grow without the bar growing with it. */
.nav-group{position:relative;display:flex;align-items:center}
.nav-trigger{
  display:inline-flex;align-items:center;gap:7px;
  border:0;background:transparent;cursor:pointer;padding:0;
  font-family:'Noto Sans',sans-serif;font-weight:500;font-size:var(--ws-fs-nav);
  line-height:1.375;letter-spacing:.02em;text-transform:uppercase;
}
.nav-trigger svg{transition:transform 240ms var(--ws-ease)}
.nav-group.open .nav-trigger svg{transform:rotate(180deg)}
.nav-drop{
  position:absolute;top:calc(100% + 22px);left:50%;transform:translateX(-50%);
  min-width:230px;display:flex;flex-direction:column;
  background:var(--ws-paper);padding:8px 0;
  box-shadow:0 0 0 1px var(--ws-line),0 22px 40px -24px rgba(21,52,75,.55);
}
/* an author display rule outranks the UA [hidden] rule, so state it explicitly
   or the panel renders open on load */
.nav-drop[hidden]{display:none}
/* keeps the pointer inside the group while it crosses the gap */
.nav-drop::before{content:"";position:absolute;left:0;right:0;top:-22px;height:22px}
.nav-drop a{
  padding:11px 22px;white-space:nowrap;color:var(--ws-body);opacity:.72;
  transition:opacity 160ms var(--ws-ease),color 160ms var(--ws-ease);
}
.nav-drop a:hover{opacity:1;color:var(--ws-teal)}
.nav-pill{
  position:absolute;top:-11px;height:4px;width:23px;border-radius:25px;background:var(--ws-body);opacity:0;
  transition:transform 420ms var(--ws-ease),opacity 260ms var(--ws-ease);pointer-events:none;
}
.nav:hover .nav-pill,.nav-pill.rest{opacity:1}
.actions{display:flex;align-items:center;gap:16px}

.menu-btn{
  display:none;border:0;background:transparent;cursor:pointer;padding:8px 4px;
  font-family:'Noto Sans',sans-serif;font-weight:600;font-size:var(--ws-fs-nav);
  line-height:1.375;letter-spacing:.02em;color:var(--ws-body);
}
.menu-btn:hover{color:var(--ws-teal)}
.menu-panel{
  position:absolute;top:var(--ws-header-h);left:0;right:0;
  background:var(--ws-paper);
  box-shadow:0 1px 0 var(--ws-line),0 24px 40px -28px rgba(21,52,75,.5);
  /* The panel is a child of a position:fixed header, so the page scrolling
     underneath it does not move it. Without a ceiling and a scrollbar of its
     own, every link past the bottom of the screen is unreachable rather than
     just out of sight, and the language list is the last block in here. svh,
     not vh: the small viewport is the one with the browser toolbars showing,
     which is the state the panel opens in. */
  max-height:calc(100svh - var(--ws-header-h));
  overflow-y:auto;overscroll-behavior:contain;
}
.menu-panel .wrap{display:flex;flex-direction:column;align-items:stretch;height:auto;padding-block:8px 24px}
.menu-panel a{
  padding:14px 0;font-family:'Noto Sans',sans-serif;font-weight:500;font-size:20px;
  text-transform:uppercase;letter-spacing:.02em;border-bottom:1px solid var(--ws-line);
}
.menu-panel a:last-child{border-bottom:0;opacity:.6}
.menu-group-label{
  padding:16px 0 6px;font-family:'Noto Sans',sans-serif;font-weight:600;
  font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--ws-teal);
}
.menu-panel a.sub{padding-left:18px;font-size:18px}
.menu-panel a:hover{color:var(--ws-teal)}

/* six items need more room, so the centred nav gives way earlier than it used to */
@media (max-width:1024px){
  .nav{display:none}
  .menu-btn{display:inline-flex}
}
/* measured fallback: if the six items do not fit their column in whatever font
   actually loaded, collapse to the menu rather than crowding the buttons */
.hdr.compact .nav{display:none}
.hdr.compact .menu-btn{display:inline-flex}
@media (max-width:1080px){ :root{--ws-header-h:88px} }
@media (max-width:560px){ .actions .btn-quiet{display:none} }

/* ============================================================
   1  HERO  no video. Statement, then a bento of three USPs.
   ============================================================ */
.hero{
  position:relative;
  min-height:100svh;display:flex;flex-direction:column;
  padding-top:calc(var(--ws-header-h) + clamp(16px,4.5vh,72px));
  padding-bottom:clamp(16px,2.5vh,32px);
}
/* The hero dissolves into the page rather than sliding off it. A white veil over
   the whole section, opacity driven by scroll, so the duotone tiles wash out and
   the headline goes with them. Done as a veil rather than by fading the content,
   because the content's own entrance already animates opacity and the two would
   multiply against each other. It bleeds a gutter wide on each side so the veil
   covers the tiles' full width, not just the text column. */
.hero::after{
  content:"";position:absolute;z-index:6;pointer-events:none;
  top:0;bottom:0;left:calc(-1 * var(--ws-gutter));right:calc(-1 * var(--ws-gutter));
  background:var(--ws-paper);opacity:var(--ws-hero-fade,0);
  will-change:opacity;
}
.hero-top{
  display:grid;grid-template-columns:minmax(0,805fr) minmax(0,459fr);
  gap:clamp(32px,5vw,84px);align-items:start;
  margin-bottom:clamp(24px,4.5vh,72px);
}
/* the type is capped by viewport HEIGHT as well as width, so a short laptop
   screen does not get a headline that eats the fold */
.hero .h1{font-size:min(var(--ws-fs-h1),13vh)}
.hero-lede{font-size:min(var(--ws-fs-lede),2.6vh)}
.hero h1{width:fit-content;max-width:100%}
.hero .line{
  /* fit-content, so each line's box is its own text width and the marker hugs the
     words rather than running to the width of the longest line */
  display:block;width:fit-content;position:relative;z-index:0;white-space:nowrap;
  opacity:0;transform:translateY(18px);
  transition:opacity var(--ws-dur) var(--ws-ease),transform var(--ws-dur) var(--ws-ease);
}
.hero .line.on{opacity:1;transform:none}

/* SIGNATURE: the aqua marker, sized to each line's own words. */
.hero .line.mk::before{
  content:"";position:absolute;z-index:-1;
  left:-.05em;right:-.02em;top:.13em;height:.80em;
  background:var(--ws-aqua);
  transform:scaleX(0);transform-origin:left center;
  transition:transform 760ms cubic-bezier(.65,0,.35,1);
}
.hero .line.mk.swept::before{transform:scaleX(1)}

.hero-lede{display:flex;flex-direction:column;gap:1.2em;padding-top:.5em}

/* bento, 2x2 on a twenty-column grid, deliberately off the half AND out of
   line: the top row splits 11/9, the bottom row 12/8, so all four tiles are a
   different width and the vertical seam does not run through the middle. A
   50/50 grid reads as a table; this reads as arranged by hand. */
.bento{display:grid;grid-template-columns:repeat(20,minmax(0,1fr));grid-template-rows:minmax(0,54fr) minmax(0,46fr);gap:18px 20px;flex:1 1 0;min-height:min(46vh,540px)}
.tile.q1{grid-area:1/1/2/12}
.tile.q2{grid-area:1/12/2/21}
.tile.q3{grid-area:2/1/3/13}
.tile.q4{grid-area:2/13/3/21}
.tile{position:relative;border-radius:var(--ws-radius);overflow:hidden;isolation:isolate}
.tile-copy{
  position:absolute;left:clamp(18px,2vw,28px);bottom:clamp(16px,2vw,28px);right:clamp(18px,2vw,28px);
  z-index:2;color:#fff;
}
.tile-copy .d{color:#fff}
.feature .overlay .d{color:var(--ws-ink)}
/* one size per cell, tracking the cell's own area rather than a big/small pair */
.tile.q1 .tile-t{font-size:clamp(1.9rem,3.4vw,50px)}
.tile.q2 .tile-t{font-size:clamp(1.5rem,2.4vw,34px)}
.tile.q3 .tile-t{font-size:clamp(1.6rem,2.7vw,38px)}
.tile.q4 .tile-t{font-size:clamp(1.45rem,2.3vw,32px)}
.tile.fem .ph img{object-position:50% 78%}
.hero-foot{display:flex;justify-content:center;align-items:flex-end;margin-top:clamp(14px,2vh,24px)}
@media (max-width:900px){
  .hero{min-height:0;display:block}
  .hero .h1{font-size:var(--ws-fs-h1)}
  .hero-lede{font-size:var(--ws-fs-lede)}
  .hero-top{grid-template-columns:minmax(0,1fr);gap:28px}
  .bento{grid-template-columns:minmax(0,1fr);grid-template-rows:none;min-height:0}
  .bento .tile{grid-area:auto}
  .tile.q1{aspect-ratio:4/3}
  .tile.q2,.tile.q3,.tile.q4{aspect-ratio:16/10}
  .hero-foot{margin-top:24px}
  .cue{margin-top:8px}
}

/* scroll cue, from the Figma */
.cue{display:flex;flex-direction:column;align-items:center;gap:clamp(10px,1.6vh,20px)}
.cue span{font-size:var(--ws-fs-nav);line-height:1.375;opacity:.7}
.cue i{display:block;width:1px;height:clamp(24px,4vh,56px);background:var(--ws-body);opacity:.5}

/* ============================================================
   1c  EVERY WEARABLE WELCOME
   Proportioned off the Figma frame: 479 copy column, 698x1024 image,
   32px radius, and a flat rgba(0,174,255,.2) wash rather than a duotone.
   ============================================================ */
/* extra room below: the climbing line rises into this space, and it needs to be
   clear white rather than the tail of the photograph above it */
.ww{padding-top:clamp(64px,10vh,130px);padding-bottom:clamp(150px,33vh,380px)}
.ww-grid{
  max-width:1180px;margin-inline:auto;
  display:grid;grid-template-columns:minmax(0,479fr) minmax(0,698fr);
  gap:clamp(32px,5vw,72px);align-items:center;
}
.ww-copy{display:flex;flex-direction:column;gap:40px}
.ww-copy .h2{color:var(--ws-teal)}
.ww-copy p{max-width:34ch}

/* The platform wall. Two columns, three rows, every mark on the same optical
   height and desaturated to the same weight so no brand shouts louder than the
   others and none of them out-shouts the heading.
   Each cell holds an <img> and the brand name. The name is what shows until the
   image is PROVEN to have decoded, so a missing file degrades to type.
   This was an <object> and it looked right in a flagged test browser only:
   Chrome will not let an <object> pull a file:// subresource, so on a real
   double-clicked page all six fell back to text. An <img> has no such rule.
   The real marks still need each company's permission and their own files. */
.ww-logos{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(22px,3vh,34px) clamp(26px,3.4vw,48px);
  max-width:460px;align-items:center;
}
/* NOTHING HERE MAY TOUCH THE PIXELS OF A MARK, and that is not a style
   preference. This rule used to read `filter:grayscale(1);opacity:.52`, which
   is a colour alteration applied to eight trademarks. Strava ("never modify,
   alter or animate Strava logos"), Garmin ("please do not alter these
   images"), Fitbit ("do not alter, adapt, modify"), Oura ("do not change the
   color of the logo") and COROS (terms of service, section 6) each forbid it
   in writing, and WHOOP forbids anything that reduces the mark's legibility,
   which a .52 fade is. Every one of the eight publishes an approved BLACK
   file: that is where the row's coherence comes from now. Details, sources and
   the permission state of each brand: assets/logos/README.md. */
.ww-logo{
  display:flex;align-items:center;
  height:var(--mark-h,clamp(28px,2.8vw,38px));
}
.ww-logo img{max-height:100%;max-width:100%;width:auto;height:auto;pointer-events:none;display:none}
/* The name shows until the file is proven to have loaded, so a missing asset
   degrades to type rather than to a broken-image icon. */
.ww-logo.has-mark img{display:block}
.ww-logo.has-mark .fb{display:none}
.ww-logo .fb{
  font-family:'Space Grotesk',sans-serif;font-weight:700;
  font-size:clamp(18px,1.5vw,22px);letter-spacing:.02em;
  text-transform:uppercase;color:var(--ws-ink);white-space:nowrap;
}
.ww-more{
  grid-column:1 / -1;margin-top:clamp(12px,1.7vh,22px);
  font:inherit;font-size:var(--ws-fs-body);line-height:1.33;letter-spacing:.02em;
  color:inherit;
}

/* Per-brand heights, generated from BRANDS in integrations_wall.py so the two
   cannot drift. A brand with no height inherits --mark-h and, until its file is
   cleared, shows its name in type instead. */
.ww-logo[data-brand="garmin"]{--mark-h:21px}
.ww-logo[data-brand="strava"]{--mark-h:42px}
.ww-logo[data-brand="google-health"]{--mark-h:26px}
.ww-logo[data-brand="whoop"]{--mark-h:21px}
.ww-logo[data-brand="polar"]{--mark-h:21px}
.ww-logo[data-brand="oura"]{--mark-h:24px}
.ww-logo[data-brand="suunto"]{--mark-h:42px}
.ww-logo[data-brand="coros"]{--mark-h:30px}
.ww-more a{
  color:var(--ws-teal-deep);text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:1px;text-decoration-color:var(--ws-teal-deep);
}
.ww-more a:hover{text-decoration-thickness:2px}

/* ---- the integrations pane ---------------------------------------------
   Shell, close button and veil are the sign-up dialog's (.su-veil/.su/.su-x),
   so there is one modal look on the page rather than two. Only the list is
   new. The :target rules are the no-script path: the trigger is a real anchor
   to #wwVeil, so with the script dead the pane still opens and the close
   button still closes it. */
.ww-veil:target{display:grid;place-items:start center}
.ww-veil:target .su{opacity:1;transform:none}
/* .su.ww-all, not .ww-all: these rules sit ~530 lines ABOVE .su{width:...} in
   the sheet, so at equal specificity the sign-up card's width wins. */
.su.ww-all{width:min(920px,100%);padding:clamp(24px,3vw,40px)}
.ww-all .su-x{text-decoration:none;font-family:inherit}
/* Teal, matching the "Every wearable welcome" heading this pane opens over.
   Same value as .ww-copy .h2, deliberately: a second teal beside it would read
   as a mistake. */
.ww-all h2{
  font-size:clamp(1.6rem,3.2vw,40px);line-height:1.14;
  margin:0 44px 0 0;color:var(--ws-teal);
}
.ww-all .su-sub{margin-top:10px;max-width:60ch}

/* ONE ROW PER HEADING, and the row is a real box so its rule can run the full
   width. `display:contents` was the first attempt and it looked wrong: with no
   box of its own the group can only put the border on its two children, and
   the column gap then shows up as a break in the middle of every rule. SUBGRID
   instead: the row spans both parent columns, so it is one box that can carry
   one border, while `grid-template-columns:subgrid` keeps its heading and its
   names on the SAME two column tracks as every other row. That alignment is
   the whole reason the parent grid exists.
   The plain two-column value above it is the fallback a browser without
   subgrid keeps: rows still lay out, their heading columns just size
   independently. Caught by rendering it. */
.ww-cols{
  margin-top:26px;display:grid;
  grid-template-columns:minmax(0,auto) minmax(0,1fr);
  column-gap:clamp(20px,3vw,44px);
}
.ww-grp{
  grid-column:1 / -1;display:grid;align-items:baseline;
  grid-template-columns:minmax(0,auto) minmax(0,1fr);
  grid-template-columns:subgrid;
  padding:15px 0;border-top:1px solid var(--ws-line);
}
.ww-grp:first-child{border-top:0;padding-top:0}
.ww-grp h3{
  margin:0;font-family:'Space Grotesk',system-ui,sans-serif;
  font-size:12px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ws-ink);opacity:.55;white-space:nowrap;
}
/* padding:0 is load-bearing. Without it the UA's 40px padding-inline-start on
   a <ul> survives, and on a phone, where the heading sits directly above its
   names, the names are visibly indented from the heading they belong to. The
   earlier layout hid it: the rule that drew the row line also set the list's
   padding, so nobody saw the default. */
.ww-grp ul{
  margin:0;padding:0;list-style:none;
  display:flex;flex-wrap:wrap;gap:10px clamp(14px,1.9vw,26px);
}
.ww-grp li{
  font-family:'Space Grotesk',system-ui,sans-serif;font-weight:700;
  font-size:clamp(14px,1.15vw,16px);letter-spacing:.01em;color:var(--ws-ink);
}
.ww-foot{
  margin:14px 0 0;padding-top:14px;border-top:1px solid var(--ws-line);
  font-size:12px;line-height:1.5;color:var(--ws-body);opacity:.5;
}
@media (max-width:640px){
  /* One column, so the heading stacks above its names. The row line moves to
     the heading alone: left on the list it would draw between a heading and
     the names it belongs to. */
  .ww-cols{grid-template-columns:minmax(0,1fr)}
  .ww-grp{grid-template-columns:minmax(0,1fr);grid-template-columns:subgrid;row-gap:9px}
  .ww-grp h3{white-space:normal}
}
.ww-media{
  position:relative;border-radius:var(--ws-radius);overflow:hidden;
  aspect-ratio:698/1024;background:var(--ws-sky-2);
}
.ww-media img{width:100%;height:100%;object-fit:cover}
.ww-media::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:rgba(0,174,255,.2);
}
@media (max-width:900px){
  .ww-grid{grid-template-columns:minmax(0,1fr);gap:36px}
  .ww-media{aspect-ratio:4/5;order:-1}
  .ww-copy{gap:28px}
}

/* ============================================================
   1b  PHONE STAGE  scroll-driven product walkthrough
   All classes are prefixed pm- because the incoming markup used .card,
   .screen and .step, which already mean something else on this page.
   ============================================================ */
:root{ --pm-radius:52px; --pm-frame:12px; --pm-muted:#5C7488; }

/* the wash moves up to a band wrapper so the headline can bleed above the stage
   without joining the stage's own scroll maths */
.sky-band{
  background:var(--ws-sky);position:relative;
  /* seam + clearance, so the phone lands in colour instead of being cut by the edge */
  padding-bottom:calc(var(--ws-seam) + 40px);
}
.pm-stage{height:330vh;position:relative}

/* SIGNATURE 2: the headline straddles the colour boundary. One position, two
   stacked copies. The base is navy; a teal copy sits exactly on top of it and is
   clipped to everything below the band edge, so the letters change colour at the
   join rather than at a glyph. --ms-bleed is in em, so it holds at any size. */
.ms{
  --ms-bleed:.27em;                  /* 70 of 261.71 in the Figma frame */
  will-change:transform;
  position:relative;display:flow-root;   /* flow-root, or the negative margin
                                            collapses out and drags the band up */
  padding-bottom:clamp(20px,4vh,56px);
}
/* both copies carry the same pull, so they cannot drift apart */
.ms .mega{margin:calc(-1 * var(--ms-bleed)) 0 0;color:var(--ws-ink);text-align:center}
/* fit-content, not plain block: a block-level line fills its parent, so measuring
   it returns the container width and the fitter never grows the type */
.ms .mline{display:block;width:fit-content;margin-inline:auto;white-space:nowrap}
.ms .ms-teal{
  /* an absolute child is placed against the PADDING BOX, so it has to carry the
     wrap's gutter itself or it sits 32px left of the copy underneath it */
  position:absolute;top:0;left:0;right:0;padding-inline:var(--ws-gutter);
  color:var(--ws-teal);
  clip-path:inset(var(--ms-bleed) 0 0 0);
  pointer-events:none;
}
@media (max-width:900px){ .ms{--ms-bleed:.20em} }
.pm-sticky{
  position:sticky;top:0;height:100svh;
  padding-top:var(--ws-header-h);
  display:grid;grid-template-columns:auto minmax(0,560px);
  justify-content:center;gap:clamp(28px,7vw,110px);align-items:center;
  max-width:var(--ws-maxw);margin-inline:auto;padding-inline:var(--ws-gutter);
}

/* the phone is sized off the viewport so it never outgrows the pinned screen.
   9/18 rather than 9/19.5, and a lower ceiling, so it reads as a phone rather
   than a strip of one. */
.pm-phone{
  position:relative;justify-self:center;
  height:min(690px,calc(100svh - var(--ws-header-h) - 128px));
  aspect-ratio:9/18;width:auto;
  background:#1C2B36;border-radius:var(--pm-radius);padding:var(--pm-frame);
  box-shadow:0 30px 60px rgba(21,52,75,.22),inset 0 0 0 2px #3B4B58;
}
.pm-screen{
  position:relative;height:100%;overflow:hidden;   /* the mask */
  border-radius:calc(var(--pm-radius) - var(--pm-frame));background:var(--ws-paper);
}
/* flex-basis 100% makes every panel exactly one screen tall, so the shift is
   always a whole number of screens whatever the content does */
.pm-strip{height:100%;display:flex;flex-direction:column;will-change:transform,opacity}
.pm-app{flex:0 0 100%;padding:46px 20px 26px;display:flex;flex-direction:column}
/* The eyebrow and title stay pinned under the notch where an app would put them,
   and the free space is then split above and below the body instead of pooling
   at the foot of the screen. Two auto margins, no extra markup. */
.pm-app h3 + *{margin-top:auto}
.pm-app > *:last-child{margin-bottom:auto}
.pm-notch{
  position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:44%;height:26px;background:#1C2B36;border-radius:0 0 16px 16px;z-index:2;
}

.pm-eyebrow{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--pm-muted);margin-bottom:6px}
.pm-app h3{font-family:'Space Grotesk',sans-serif;font-weight:700;letter-spacing:-.02em;font-size:19px;margin-bottom:14px;color:var(--ws-ink)}
.pm-card{background:#F3F9FC;border-radius:16px;padding:14px;margin-bottom:10px}
.pm-card b{display:block;font-size:14px;color:var(--ws-ink)}
.pm-card span{font-size:11px;color:var(--pm-muted);line-height:1.45;display:block}
.pm-ring{
  width:112px;height:112px;border-radius:50%;margin:18px auto 14px;display:grid;place-items:center;
  background:conic-gradient(var(--ws-teal) 0 78%,#E3EEF4 78% 100%);
}
.pm-ring i{background:#fff;width:88px;height:88px;border-radius:50%;display:grid;place-items:center;
  font-style:normal;font-family:'Space Grotesk',sans-serif;font-weight:700;font-size:26px;color:var(--ws-teal-deep)}
.pm-big{font-family:'Space Grotesk',sans-serif;font-size:44px;font-weight:700;color:var(--ws-teal-deep);letter-spacing:-.03em;margin-bottom:14px}

.pm-copy h2{margin-bottom:28px;color:var(--ws-ink)}
.pm-step{
  padding:12px 0 12px 16px;border-left:2px solid transparent;opacity:.8;
  transition:opacity .35s var(--ws-ease),border-color .35s var(--ws-ease);
}
.pm-step[data-active="true"]{opacity:1;border-left-color:var(--ws-teal)}
.pm-step h3{font-family:'Space Grotesk',sans-serif;font-weight:700;letter-spacing:-.02em;font-size:20px;margin-bottom:4px;color:var(--ws-ink)}
.pm-step p{font-size:15px;line-height:1.5;color:var(--ws-ink);max-width:44ch}

/* Mobile keeps the pinned behaviour. Going static there left the phone stuck on
   screen one, so two thirds of the walkthrough never rendered. Shorter runway,
   smaller phone, tighter steps instead. */
@media (max-width:900px){
  .pm-stage{height:290vh}
  .pm-sticky{grid-template-columns:minmax(0,1fr);align-content:center;gap:clamp(18px,3vh,28px)}
  .pm-phone{height:min(430px,48svh)}
  .pm-copy h2{font-size:clamp(1.7rem,6.4vw,2.2rem);margin-bottom:14px}
  .pm-step{padding:8px 0 8px 14px}
  .pm-step h3{font-size:17px}
  .pm-step p{font-size:13px}
}
@media (prefers-reduced-motion:reduce){
  .pm-stage{height:auto}
  .pm-sticky{position:static;height:auto;padding-block:8vh}
  .pm-step{opacity:1;border-left-color:rgba(21,52,75,.18)}
}

/* ============================================================
   2  STICKY CARD STACK
   ============================================================ */
/* The headline crosses into the band at the top; the card crosses out of it at the
   bottom. Same device at both ends, so the band reads as bracketed rather than as
   two hard edges. */
.stack{padding-block:0;display:flow-root;margin-top:calc(-1 * var(--ws-seam));position:relative;z-index:2}
/* The reference site's stack, measured: every card is its own sticky, pinned just
   under the fixed header, sized to the screen minus that header, separated by one
   small margin. The next card scrolls up over the pinned one and takes its place.
   No JS, no scroll listener. Because every card is the same viewport-derived
   height, they cannot disagree about how tall they are. */
.card{
  position:sticky;top:var(--ws-card-top);
  background:var(--ws-paper);border-radius:var(--ws-radius);overflow:hidden;
  box-shadow:0 40px 80px -44px rgba(21,52,75,.5),0 0 0 1px var(--ws-line);
  display:grid;grid-template-columns:1fr 1fr;
  min-height:calc(100svh - var(--ws-card-top) - var(--ws-card-gap));
  margin-bottom:calc(var(--ws-card-gap) + var(--ws-card-hold));
}
.stack .card:last-child{margin-bottom:0}
.stack-tail{height:calc(var(--ws-card-hold) + var(--ws-card-gap))}
.card .txt{display:flex;flex-direction:column;justify-content:center;gap:28px;padding:clamp(28px,4vw,64px)}
.card .media{position:relative;overflow:hidden;isolation:isolate}
.card.flip .txt{order:2}
.card.flip .media{order:1}
.card.tint{background:var(--ws-sky-2)}
.card.tealtype .h2{color:var(--ws-teal)}
@media (max-width:900px){
  /* No stacking below this width, so no hold and no tail. */
  .card{grid-template-columns:minmax(0,1fr);position:static;min-height:0;margin-bottom:clamp(36px,6vh,84px)}
  .stack{padding-bottom:clamp(36px,6vh,84px)}
  .stack-tail{display:none}
  .card .media{aspect-ratio:4/3}
  .card.flip .txt{order:2}.card.flip .media{order:1}
}

/* ============================================================
   4  SKY SECTION
   ============================================================ */
.sky{background:var(--ws-sky);padding-block:clamp(72px,11vh,140px);color:var(--ws-ink)}
.sky .body,.sky .lede{color:var(--ws-ink)}
.sky-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(32px,5vw,80px);align-items:center}
.band{position:relative;border-radius:var(--ws-radius);overflow:hidden;aspect-ratio:3/4;isolation:isolate}
.specs{display:flex;flex-direction:column;gap:40px}
.spec-list{display:flex;flex-direction:column}
.spec{display:flex;flex-direction:column;gap:8px;padding-block:24px;border-top:1px solid rgba(21,52,75,.2)}
.spec:last-child{border-bottom:1px solid rgba(21,52,75,.2)}
@media (max-width:900px){.sky-grid{grid-template-columns:minmax(0,1fr)}.band{aspect-ratio:4/3}}

/* ============================================================
   5  FIELD NOTES
   ============================================================ */
.notes{padding-block:clamp(80px,12vh,150px)}
.notes-head{display:flex;justify-content:space-between;align-items:flex-end;gap:24px;flex-wrap:wrap;margin-bottom:clamp(28px,4vh,56px)}
.feature{position:relative;border-radius:var(--ws-radius);overflow:hidden;min-height:min(70vh,640px);isolation:isolate}
.feature .overlay{
  position:absolute;left:clamp(16px,2.6vw,40px);bottom:clamp(16px,2.6vw,40px);z-index:2;
  width:min(430px,84%);background:var(--ws-paper);border-radius:24px;
  padding:clamp(22px,2.2vw,32px);display:flex;flex-direction:column;gap:14px;
}
.two-up{display:grid;grid-template-columns:1fr 1fr;gap:28px;margin-top:28px}
.note{border-radius:var(--ws-radius);overflow:hidden;background:var(--ws-sky);display:flex;flex-direction:column}
.note .media{aspect-ratio:16/10;position:relative;isolation:isolate}
.note .nbody{padding:clamp(20px,2.2vw,32px);display:flex;flex-direction:column;gap:12px;color:var(--ws-ink)}
.read{font-weight:600;font-size:var(--ws-fs-nav);text-transform:uppercase;color:var(--ws-teal)}
@media (max-width:760px){.two-up{grid-template-columns:minmax(0,1fr)}}

/* ============================================================
   6  CLOSER
   ============================================================ */
/* The fan. The words are the only thing that never moves; everything else starts
   piled on top of them and travels outward as you scroll, so the sentence is
   uncovered rather than faded in. Each satellite carries its own destination
   (--x/--y/--r) and its own share of the runway (--d), and JS writes one number
   per satellite per frame. */
.closer{
  background:var(--ws-sky);color:var(--ws-ink);height:var(--ws-fan-runway,130vh);
  /* one percent of the stage, not of the viewport, so nothing is ever parked
     underneath the fixed header or below the fold */
  --vy:calc((100svh - var(--ws-header-h)) / 100);
}
.fan-stage{
  position:sticky;top:var(--ws-header-h);height:calc(100svh - var(--ws-header-h));
  overflow:hidden;display:grid;place-items:center;text-align:center;
}
/* The text block is deliberately proportional, min(620px,44vw), so the clear
   centre and the ring of satellites keep the same relationship at every width
   instead of the words swallowing the room the satellites need. */
.fan-core{position:relative;z-index:1;padding-inline:var(--ws-gutter);width:min(620px,44vw)}
.fan-core .h1{color:var(--ws-teal);font-size:clamp(2.1rem,4.6vw,72px);line-height:.98}
.fan-core .lede{margin:clamp(18px,2.4vh,32px) auto 0;color:var(--ws-ink)}
.fan-core .btn{margin-top:clamp(22px,2.8vh,38px)}

.fan-item{
  --p:0;
  position:absolute;top:50%;left:50%;z-index:2;
  width:var(--w);border-radius:20px;overflow:hidden;
  box-shadow:0 26px 50px -30px rgba(21,52,75,.55);
  /* Two progress values, not one. --py lifts the satellite from its start in the
     clump below the fold; --px, which runs eighteen percent later, throws it
     outward. So the pile rises over the sentence first and only then opens. */
  --px:0;--py:0;
  transform:
    translate3d(
      calc(-50% + var(--sx) + (var(--x) - var(--sx)) * var(--px)),
      calc(-50% + var(--sy) + (var(--y) - var(--sy)) * var(--py)), 0)
    rotate(calc(var(--sr) + (var(--r) - var(--sr)) * var(--px)))
    scale(calc(.88 + .12 * var(--py)));
  will-change:transform;
}
.fan-item .ph{position:relative;inset:auto;aspect-ratio:var(--ar,4/5)}

/* the visual cards. Marks are teal on navy, where teal clears contrast comfortably;
   labels and values wear text colours, never the mark colour. */
.viz{background:var(--ws-ink);color:#fff;padding:18px 20px 20px;display:flex;flex-direction:column;gap:14px}
.viz.light{background:var(--ws-paper);color:var(--ws-ink)}
.viz .k{font-size:11px;letter-spacing:.16em;text-transform:uppercase;opacity:.62;font-weight:600}
.viz .v{font-family:'Space Grotesk',system-ui,sans-serif;font-weight:500;font-size:38px;line-height:1;letter-spacing:-.03em}
.viz .u{font-size:12px;opacity:.62;white-space:nowrap}
.viz .k{white-space:nowrap}
.viz svg{display:block;width:100%;height:auto}
.chip{
  background:var(--ws-teal);color:#fff;border-radius:999px;
  padding:clamp(9px,1vw,12px) clamp(14px,1.5vw,20px);
  font-size:clamp(11px,.95vw,13px);font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;white-space:nowrap;
}

/* Destinations. The read-outs hold the outer edges, where there is horizontal
   room for them, and the photographs sit above and below the sentence, which is
   why they are landscape rather than portrait. Nothing is on a grid: the eight
   sit as four loose pairs, each pair offset from its partner in both axes, so
   the arrangement reads as things that fell into place rather than slots.
   Width is capped against the viewport HEIGHT as well as its width, or a short
   wide window keeps full size cards while the destinations collapse. */
.fan-item{--sr:0deg}

/* photographs, above and below */
.fan-item.p1{--ar:3/2;--w:clamp(180px,min(23vw,29 * var(--vy)),330px);--x:-12vw;--y:calc(-35 * var(--vy));--r:-3.4deg;--d:0}
.fan-item.p2{--ar:4/3;--w:clamp(130px,min(16vw,22 * var(--vy)),240px);--x:  8vw;--y:calc(-38 * var(--vy));--r: 2.4deg;--d:.1}
.fan-item.p3{--ar:3/2;--w:clamp(180px,min(22vw,28 * var(--vy)),320px);--x:  9vw;--y:calc( 35 * var(--vy));--r: 3deg;--d:.06}
.fan-item.p4{--ar:4/3;--w:clamp(130px,min(15vw,21 * var(--vy)),225px);--x:-14vw;--y:calc( 38 * var(--vy));--r:-2.2deg;--d:.18}

/* read-outs, on the outside */
.fan-item.v1{--w:clamp(150px,min(19vw,30 * var(--vy)),280px);--x:-35vw;--y:calc(-20 * var(--vy));--r:-2.4deg;--d:.26}
.fan-item.v2{--w:clamp(150px,min(18vw,28 * var(--vy)),262px);--x:-33.5vw;--y:calc( 18 * var(--vy));--r: 2.6deg;--d:.34}
.fan-item.v3{--w:clamp(120px,min(14vw,24 * var(--vy)),210px);--x: 36vw;--y:calc(-19 * var(--vy));--r: 2.2deg;--d:.3}
.fan-item.c1{--w:auto;--x: 34.5vw;--y:calc( 14 * var(--vy));--r:-3deg;--d:.44}

/* Start: one loose clump held high in the stage, overlapping itself, rotations
   scattered. High in the STAGE is what puts it low on the SCREEN, because until
   the stage pins the section is still rising, so the clump crosses the bottom
   edge of the window first and the sentence arrives underneath it. Not a single
   point, which reads as a magic trick, and not a tidy row either. */
.fan-item.p1{--sx:-12vw;--sy:calc(-22 * var(--vy));--sr:-5.5deg}
.fan-item.p2{--sx: -1vw;--sy:calc(-30 * var(--vy));--sr: 4deg}
.fan-item.p3{--sx:  7vw;--sy:calc(-17 * var(--vy));--sr: 6deg}
.fan-item.p4{--sx: 15vw;--sy:calc(-27 * var(--vy));--sr:-4deg}
.fan-item.v1{--sx:-20vw;--sy:calc(-34 * var(--vy));--sr:-3deg}
.fan-item.v2{--sx: -6vw;--sy:calc(-13 * var(--vy));--sr: 5deg}
.fan-item.v3{--sx: 17vw;--sy:calc(-29 * var(--vy));--sr: 3deg}
.fan-item.c1{--sx:  2vw;--sy:calc(-20 * var(--vy));--sr:-6.5deg}

/* A short window also tightens the read-outs, since the ring has no room to
   move further out and the cards are what has to give. */
@media (min-width:901px) and (max-height:830px){
  .viz{padding:13px 15px 15px;gap:9px}
  .viz .v{font-size:30px}
}

/* A short window shrinks the words rather than the ring, because the ring has
   nowhere left to go once it is near the top and bottom edges. */
@media (max-height:860px) and (min-width:901px){
  .fan-core .h1{font-size:clamp(2rem,3.9vw,54px)}
  .fan-core .lede{font-size:clamp(1rem,1.28vw,19px)}
  .fan-core .lede{margin-top:16px}
  .fan-core .btn{margin-top:20px}
}

@media (max-width:900px){
  /* No room for a ring on a phone, so the fan runs vertically instead: two above
     the words, two below, and the rest stand down. */
  .closer{--ws-fan-runway:135vh}
  .fan-core{width:min(88vw,520px)}
  .fan-item{border-radius:16px}
  .fan-item.p2,.fan-item.p4,.fan-item.v2,.fan-item.c1{display:none}
  .fan-item.p1{--ar:3/2;--w:clamp(110px,min(40vw,22 * var(--vy)),200px);--x:-23vw;--y:calc(-40 * var(--vy))}
  .fan-item.p3{--ar:3/2;--w:clamp(105px,min(36vw,20 * var(--vy)),185px);--x:-20vw;--y:calc( 40 * var(--vy))}
  .fan-item.v1{--w:clamp(120px,min(38vw,30 * var(--vy)),210px);--x: 25vw;--y:calc(-32 * var(--vy))}
  .fan-item.v3{--w:clamp(100px,min(30vw,20 * var(--vy)),170px);--x: 27vw;--y:calc( 34 * var(--vy))}
  .fan-item.p1{--sx:-14vw;--sy:calc(-24 * var(--vy))}
  .fan-item.p3{--sx:  6vw;--sy:calc(-16 * var(--vy))}
  .fan-item.v1{--sx: 14vw;--sy:calc(-30 * var(--vy))}
  .fan-item.v3{--sx: -6vw;--sy:calc(-12 * var(--vy))}
}
/* Without motion the fan has nothing to say, so the section becomes what the fan
   was always describing: the sentence, then the evidence, laid out flat. */
@media (prefers-reduced-motion:reduce){
  .closer{height:auto;padding-block:clamp(72px,11vh,140px);--vy:1px}
  .fan-stage{
    position:static;height:auto;overflow:visible;
    display:flex;flex-direction:column;align-items:center;gap:clamp(28px,4vh,52px);
  }
  .fan-core{width:min(620px,88vw)}
  .fan-item{
    position:static;transform:none!important;width:auto;max-width:min(300px,42vw);
  }
  .fan-item.p1,.fan-item.p2,.fan-item.p3,.fan-item.p4,.fan-item.c1{display:none}
  .fan-stage{padding-inline:var(--ws-gutter)}
}

/* ============================================================
   7  FOOTER
   ============================================================ */
.ftr{background:var(--ws-ink);color:#fff;padding-block:clamp(56px,8vh,96px) 28px}
.ftr .brand-mark path{fill:#fff}
.ftr .brand-word .t{color:#fff}
.ftr-groups{display:grid;grid-template-columns:repeat(3,1fr);gap:40px;margin-top:clamp(40px,6vh,72px)}
.ftr-groups :is(h2,h4){font-family:'Noto Sans',sans-serif;font-weight:600;font-size:var(--ws-fs-nav);line-height:1.375;text-transform:uppercase;color:var(--ws-teal);margin-bottom:18px;letter-spacing:.02em}
.ftr-groups ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.ftr-groups a{color:rgba(255,255,255,.78)}
.ftr-groups a:hover{color:#fff}
/* One disclaimer, in the footer, so it is on every page rather than on the
   three that happened to have an honest-limits block. */
.ftr-disclaimer{
  max-width:78ch;margin:clamp(32px,5vh,56px) 0 0;
  font-size:14px;line-height:1.7;color:#fff;opacity:.62;
}
.ftr-bottom{
  margin-top:clamp(40px,6vh,72px);padding-top:24px;border-top:1px solid var(--ws-line-light);
  display:flex;justify-content:space-between;align-items:center;gap:18px;flex-wrap:wrap;
  font-size:var(--ws-fs-nav);color:rgba(255,255,255,.6);
}
.locale{border:1px solid var(--ws-line-light);padding:9px 16px}
@media (max-width:760px){.ftr-groups{grid-template-columns:minmax(0,1fr);gap:32px}.ftr-bottom{justify-content:center;text-align:center}}

/* ============================================================
   PHOTOGRAPHY  every image is printed in one blue.
   The image contributes luminance only, the blue underneath supplies the hue,
   so a misty forest and an athletics track end up in the same world.
   ============================================================ */
.ph{position:absolute;inset:0;overflow:hidden;background:var(--ws-sky-2);isolation:isolate}
.ph.rel{position:relative;inset:auto;width:100%;height:100%}
.ph img{width:100%;height:100%;object-fit:cover;filter:saturate(.94) contrast(1.02)}

/* The duotone is now a HERO-ONLY device. Printing the three USP tiles in one blue
   makes them read as a set and separates the pitch from the evidence below it,
   where the photography keeps its own colour. */
.ph.duo{background:var(--ws-duo)}
.ph.duo img{mix-blend-mode:luminosity;filter:contrast(1.08)}
.ph.scrim::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to top,rgba(6,28,46,.78),rgba(6,28,46,.14) 52%,transparent 78%);
}
.tag{
  position:absolute;right:20px;bottom:20px;z-index:3;
  font-size:13px;text-transform:uppercase;letter-spacing:.06em;
  color:rgba(255,255,255,.8);border:1px solid rgba(255,255,255,.35);padding:7px 12px;
}

[data-reveal]{opacity:0;transform:translateY(24px);transition:opacity var(--ws-dur) var(--ws-ease),transform var(--ws-dur) var(--ws-ease)}
[data-reveal].on{opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .card{position:static}
  .hero .line,[data-reveal],.tinted .w{opacity:1!important;transform:none!important}
  .hero .line.mk::before{transform:scaleX(1)!important}
  *{transition:none!important}
}

/* ============================================================
   9  THE COACH LINE
   One row between the closer and the footer. Deliberately the
   quietest section on the page: a coach is a different buyer with a
   different argument, and that argument belongs on its own page. This
   is a door, not a pitch, and it is placed after the runner has been
   asked to start, so it costs the main conversion nothing.
   ============================================================ */
.coachbar{border-top:1px solid var(--ws-line);background:var(--ws-paper)}
.coachbar .wrap{
  display:flex;align-items:center;justify-content:space-between;gap:clamp(24px,4vw,64px);
  padding-block:clamp(40px,6vh,72px);
}
.coachbar .kick{
  font-family:'Noto Sans',sans-serif;font-weight:600;font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ws-teal-deep);margin:0 0 10px;
}
.coachbar p.line{
  margin:0;max-width:56ch;font-size:clamp(1.05rem,1.5vw,22px);line-height:1.4;color:var(--ws-ink);
}
.coachbar a.go{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:10px;
  font-family:'Noto Sans',sans-serif;font-weight:600;font-size:var(--ws-fs-nav);
  color:var(--ws-ink);text-decoration:none;
  border-bottom:2px solid var(--ws-teal);padding-bottom:4px;
  transition:color 220ms var(--ws-ease),gap 220ms var(--ws-ease);
}
.coachbar a.go:hover{color:var(--ws-teal-deep);gap:16px}
.coachbar a.go svg{display:block}
@media (max-width:760px){
  .coachbar .wrap{flex-direction:column;align-items:flex-start;gap:24px}
}

/* Tokens the block forgot, defined once at the root before anything asks.

   The deep teal is in the brand book and in the button hover state, but it was
   never written into the token block, so every rule that asked for it resolved
   to nothing and the declaration was thrown away. That is why the spots bar had
   no fill: an invalid colour inside linear-gradient invalidates the whole
   background.

   The other four arrived with the v2 segmented control, which is their only
   consumer today and will not be their last:

     --ws-muted        idle UI label. The designer specified #6A7F8E, which is
                       4.17:1 on white and misses AA for text below 18.66px
                       bold. This is the same hue and saturation three shades
                       down, at 4.53:1. On a control the muted label is the
                       affordance that says which option is NOT chosen, so it
                       has to be readable.
     --ws-line-strong  a hairline with presence, for a boundary that carries
                       state. Twice --ws-line, still a hairline.
     --ws-fs-ui        control labels. One step below --ws-fs-nav.
     --ws-dur-micro    a colour change on hover. Short enough not to lag the
                       pointer, long enough not to snap. */
:root{
  --ws-teal-deep:#00786C;
  --ws-muted:#657987;
  --ws-line-strong:rgba(21,52,75,.32);
  --ws-fs-ui:15px;
  --ws-dur-micro:220ms;
}

/* ============================================================
   LANGUAGE PICKER
   Seven locales in the header, next to the sign-in and join
   buttons, because that is the corner people already look in
   for account-shaped controls. The names are endonyms and stay
   in their own language on every page.
   ============================================================ */
.lang{position:relative;flex:none}
.lang-btn{
  display:inline-flex;align-items:center;gap:7px;appearance:none;border:0;cursor:pointer;
  background:none;padding:9px 10px;color:var(--ws-body);opacity:.62;
  font-family:'Noto Sans',sans-serif;font-weight:600;font-size:var(--ws-fs-nav);letter-spacing:.02em;
  transition:opacity 200ms var(--ws-ease);
}
.lang-btn:hover,.lang.open .lang-btn{opacity:1;color:var(--ws-teal-deep)}
.lang-btn:focus-visible{outline:3px solid var(--ws-ink);outline-offset:2px}
.lang-btn svg{flex:none}
.lang-btn .chev{transition:transform 260ms var(--ws-ease)}
.lang.open .lang-btn .chev{transform:rotate(180deg)}
.lang-drop{
  position:absolute;top:calc(100% + 6px);right:0;z-index:90;min-width:184px;
  background:var(--ws-paper);box-shadow:0 1px 0 var(--ws-line),0 18px 40px rgba(21,52,75,.14);
  padding:8px;display:grid;gap:2px;
}
/* The `hidden` attribute is a UA rule, and any author rule that sets display
   beats it. Without this line the panel has display:grid and sits open on every
   page from the moment it loads, attribute or no attribute. The nav dropdowns
   above already carry the same line; this one was missed. */
.lang-drop[hidden]{display:none}
.lang-drop a{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:11px 12px;color:var(--ws-body);opacity:.78;
  font-family:'Noto Sans',sans-serif;font-weight:500;font-size:16px;
  transition:background 180ms var(--ws-ease),opacity 180ms var(--ws-ease);
}
.lang-drop a:hover{background:var(--ws-sky);opacity:1}
.lang-drop a[aria-current="true"]{font-weight:700;opacity:1;color:var(--ws-teal-deep)}

/* The header runs out of room before the nav does, so below the breakpoint the
   picker lives in the menu panel instead of beside it. */
.menu-langs{display:flex;flex-wrap:wrap;gap:8px;margin-top:26px;padding-top:22px;
  border-top:1px solid var(--ws-line)}
.menu-langs a{
  padding:8px 12px;font-size:15px;font-weight:600;color:var(--ws-body);opacity:.7;
  box-shadow:inset 0 0 0 1px var(--ws-line);
}
.menu-langs a[aria-current="true"]{opacity:1;color:#fff;background:var(--ws-ink);box-shadow:none}
@media (max-width:1024px){ .actions .lang{display:none} }
@media (min-width:1025px){ .menu-langs{display:none} }

/* German and Dutch compounds are longer than the English they replace, and a
   fixed-width card stays a fixed-width card. Let a long word break rather than
   push the page wider than the screen. Zero specificity, so nothing else has to
   move out of its way. */
:where(p,li,dd,dt,td,th,figcaption,label,button,a,h1,h2,h3,h4,.d){overflow-wrap:break-word}
:where(:lang(de),:lang(nl)) :where(p,li,dd,dt,td){hyphens:auto}

/* ============================================================
   SIGN-UP
   Opened by every "Start 30 days free" button. Two steps: who you
   are, then how the trial ends. The second step is the whole point
   of the design, so it is a real choice on one screen rather than a
   card field with a skip link hidden under it.
   ============================================================ */
.su-veil{
  position:fixed;inset:0;z-index:200;display:none;
  background:rgba(21,52,75,.55);backdrop-filter:blur(3px);
  padding:clamp(16px,4vh,56px) var(--ws-gutter);overflow:auto;
}
.su-veil.on{display:grid;place-items:start center}
.su{
  position:relative;width:min(660px,100%);background:var(--ws-paper);
  border-radius:var(--ws-radius);padding:clamp(28px,4vw,52px);
  box-shadow:0 60px 120px -50px rgba(21,52,75,.7);
  opacity:0;transform:translateY(20px) scale(.98);
  transition:opacity 420ms var(--ws-ease),transform 420ms var(--ws-ease);
}
.su-veil.on .su{opacity:1;transform:none}
.su-x{
  position:absolute;top:18px;right:18px;width:40px;height:40px;
  display:grid;place-items:center;border:0;background:none;cursor:pointer;
  color:var(--ws-ink);opacity:.5;font-size:26px;line-height:1;
}
.su-x:hover{opacity:1}
.su h2{font-size:clamp(1.2rem,2.5vw,34px);line-height:1.14;margin:0}
.su-sub{margin:0;font-size:17px;line-height:1.45;color:var(--ws-body);opacity:.72}

/* Two dots rather than "step 1 of 2", so the form reads as short. */
.su-dots{display:flex;gap:8px;margin-top:26px}
.su-dots i{width:26px;height:3px;background:var(--ws-line);display:block}
.su-dots i.on{background:var(--ws-teal)}

.su-step{display:none;margin-top:26px}
.su-step .su-card{margin-top:0}
.su-step.on{display:block}
.su-field{margin-top:18px}
.su-field label{display:block;font-family:'Noto Sans',sans-serif;font-weight:600;
  font-size:13px;letter-spacing:.06em;text-transform:uppercase;color:var(--ws-ink);margin-bottom:8px}
.su-field input{
  width:100%;font-family:'Noto Sans',sans-serif;font-size:17px;color:var(--ws-body);
  background:var(--ws-paper);border:1px solid var(--ws-line);border-radius:0;
  padding:14px 16px;min-height:54px;
}
.su-field input:focus{outline:3px solid var(--ws-teal);outline-offset:1px;border-color:transparent}
.su-field .hint{margin:8px 0 0;font-size:14px;color:var(--ws-body);opacity:.6}
.su-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media (max-width:560px){.su-row{grid-template-columns:minmax(0,1fr)}}

/* Inline, not a panel: inside step two it is one of three things stacked in a
   column and a tinted box around it read as a second dialog. */
.su-plan{margin:22px 0 26px;display:flex;flex-direction:column;gap:5px}
.su-plan .k{
  font-family:'Noto Sans',sans-serif;font-weight:600;font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ws-teal);
}
.su-plan b{font-family:'Space Grotesk',sans-serif;font-weight:700;letter-spacing:-.02em;
  font-size:19px;color:var(--ws-ink)}
.su-plan .p{font-size:15.5px;line-height:1.4;color:var(--ws-body);opacity:.75}

.su-login{margin:0 0 0 auto;text-align:right;font-size:16px;color:var(--ws-body);opacity:.7}
/* Side by side there is no room for both on a phone, so it drops under the
   button and goes back to reading left to right with everything else. */
@media (max-width:560px){
  .su-login{margin:4px 0 0;width:100%;text-align:left}
}
.su-login a{color:var(--ws-teal);font-weight:600;text-decoration:underline;text-underline-offset:3px}
.su-login a:hover{color:var(--ws-ink)}
/* The way out, quiet by default and teal only when it is being used. A full
   width outlined button competed with the primary one it sits under; a plain
   line does the same job without arguing for itself. */
.su-later{margin-top:6px}
.su-later .btn{
  width:auto;min-height:0;padding:8px 0;background:transparent;
  /* sentence case, because uppercase is the kit's emphasis and this is the one
     control on the screen that should not be asking for attention */
  text-transform:none;letter-spacing:.02em;font-weight:500;
  color:var(--ws-body);opacity:.55;text-decoration:underline;text-underline-offset:4px;
  transition:color 220ms var(--ws-ease),opacity 220ms var(--ws-ease);
}
.su-later .btn:hover,.su-later .btn:focus-visible{color:var(--ws-teal);opacity:1;background:transparent}
.su-later .btn::before,.su-later .btn:hover::before{background:transparent}
/* The first sentence holds one line, which is why the title's lower bound is
   1.2rem rather than 1.5: at 390px a 24px setting of it is wider than the panel
   and a line that cannot wrap has nowhere to go but sideways. */
.su h2 .nb{white-space:nowrap}
.su-card{margin-top:4px}

.su-actions{display:flex;align-items:center;gap:18px;margin-top:28px;flex-wrap:wrap}
.su-actions .btn{flex:0 0 auto}
.su-back{background:none;border:0;cursor:pointer;font-family:'Noto Sans',sans-serif;
  font-weight:600;font-size:16px;color:var(--ws-body);opacity:.6;padding:8px 0}
.su-back:hover{opacity:1;color:var(--ws-teal)}
.su-fine{margin:18px 0 0;font-size:14px;line-height:1.55;color:var(--ws-body);opacity:.6}

@media (prefers-reduced-motion:reduce){ .su{transition:none} }

/* Tokens the block forgot, defined once at the root before anything asks.

   The deep teal is in the brand book and in the button hover state, but it was
   never written into the token block, so every rule that asked for it resolved
   to nothing and the declaration was thrown away. That is why the spots bar had
   no fill: an invalid colour inside linear-gradient invalidates the whole
   background.

   The other four arrived with the v2 segmented control, which is their only
   consumer today and will not be their last:

     --ws-muted        idle UI label. The designer specified #6A7F8E, which is
                       4.17:1 on white and misses AA for text below 18.66px
                       bold. This is the same hue and saturation three shades
                       down, at 4.53:1. On a control the muted label is the
                       affordance that says which option is NOT chosen, so it
                       has to be readable.
     --ws-line-strong  a hairline with presence, for a boundary that carries
                       state. Twice --ws-line, still a hairline.
     --ws-fs-ui        control labels. One step below --ws-fs-nav.
     --ws-dur-micro    a colour change on hover. Short enough not to lag the
                       pointer, long enough not to snap. */
:root{
  --ws-teal-deep:#00786C;
  --ws-muted:#657987;
  --ws-line-strong:rgba(21,52,75,.32);
  --ws-fs-ui:15px;
  --ws-dur-micro:220ms;
}

/* ============================================================
   BETA SIGNUP 2026-10-03
   The owner-approved redesign: ink rail with one moving highlight, sky
   title panel, angled teal action, full screen on a phone. Written by
   build/beta_signup_2026_10_03.py; the app's /beta page carries the same
   design on its tokens (apps/web/app/beta/_signup/beta-signup.css).
   Everything is scoped to #btVeil and namespaced .bsu-, so the trial dialog's
   .su- shell above is untouched.
   ============================================================ */
#btVeil{
  --bs-ink:var(--ws-ink);--bs-teal:var(--ws-teal);--bs-deep:var(--ws-teal-deep,#00786C);
  --bs-sky:var(--ws-sky);--bs-paper:var(--ws-paper);--bs-muted:var(--ws-muted,#6A7F8E);
  --bs-quiet:#486173;--bs-line:rgba(21,52,75,.14);--bs-field:rgba(21,52,75,.32);
  --bs-selected:#E8F8F6;--bs-mint:#EDF9F7;--bs-mint-line:#B8D9D6;--bs-seq2:#A9E4DC;
  --bs-on-ink:#E2F5FF;--bs-ink-wash:rgba(226,245,255,.14);--bs-line-light:rgba(255,255,255,.2);
  --bs-error:#A32B2B;--bs-error-fill:#FCF3F3;--bs-error-line:#F5D4D4;--bs-sky-lift:#F4FBFF;
  position:fixed;inset:0;z-index:200;display:grid;place-items:center;padding:32px;
  background:rgba(23,59,82,.42);backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
  color:var(--bs-ink);font-family:'Noto Sans',system-ui,sans-serif;font-size:14px;line-height:1.6;font-weight:400;letter-spacing:0;
  -webkit-hyphens:manual;hyphens:manual;
}
#btVeil[hidden]{display:none}
#btVeil *,#btVeil *::before,#btVeil *::after{box-sizing:border-box}
#btVeil :is(h2,h3){font-family:'Space Grotesk',system-ui,sans-serif;font-weight:500;margin:0}
#btVeil :is(button,input,select){font:inherit;color:inherit}
#btVeil button{cursor:pointer}
#btVeil button:disabled{cursor:wait;opacity:.6}
#btVeil :is(a,button,input,select):focus-visible{outline:3px solid var(--bs-deep);outline-offset:4px}
#btVeil [hidden]{display:none!important}
#btVeil .bsu-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
#btVeil svg{width:18px;height:18px;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
#btVeil .bsu-shell{width:min(1120px,100%);height:min(810px,calc(100dvh - 64px));display:grid;grid-template-columns:278px minmax(0,1fr);grid-template-rows:minmax(0,1fr);overflow:hidden;border-radius:28px;background:var(--bs-paper);box-shadow:0 35px 100px rgba(7,31,53,.27)}
/* rail */
#btVeil .bsu-rail{min-height:0;overflow-y:auto;scrollbar-width:none;padding:36px 27px 27px;display:flex;flex-direction:column;background:var(--bs-ink);color:var(--bs-paper)}
#btVeil .bsu-brand{display:flex;align-items:center;gap:9px;height:36px;width:fit-content;color:#fff;text-decoration:none}
#btVeil .bsu-brand-mark{width:35px;height:35px;stroke:none}
#btVeil .bsu-brand-mark path{fill:#fff}
#btVeil .bsu-brand-mark path.a{fill:var(--bs-teal)}
#btVeil .bsu-brand-word{font-family:'Space Grotesk',system-ui,sans-serif;font-size:30px;line-height:1;letter-spacing:-.06em;color:#fff}
#btVeil .bsu-brand-word .w{color:var(--bs-teal)}
#btVeil .bsu-rail-intro{margin:52px 0 31px}
#btVeil .bsu-kicker{font-size:10px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--bs-seq2)}
#btVeil .bsu-rail-title{margin:12px 0 0;font-family:'Space Grotesk',system-ui,sans-serif;font-size:31px;line-height:1.18;letter-spacing:-.045em;font-weight:500}
#btVeil .bsu-rail-title span{display:block}
#btVeil .bsu-progress{position:relative;margin-inline:-11px;--step:0}
#btVeil .bsu-progress-highlight{position:absolute;inset:0 0 auto;height:68px;border-radius:15px;background:var(--bs-ink-wash);transform:translateY(calc(var(--step)*80px));transition:transform 320ms cubic-bezier(0,0,.38,.9)}
#btVeil .bsu-progress ol{position:relative;display:grid;gap:12px;margin:0;padding:0;list-style:none}
#btVeil .bsu-progress li{min-height:68px;display:flex;align-items:center;gap:14px;padding:10px 13px;color:var(--bs-on-ink)}
#btVeil .bsu-step-name{display:grid;gap:1px;font-size:13px}
#btVeil .bsu-step-name small{font-size:10px;opacity:.8}
#btVeil .bsu-step-marker{width:36px;height:36px;flex:0 0 auto;display:grid;place-items:center;border:1px solid var(--bs-line-light);border-radius:50%;font-family:'Space Grotesk',system-ui,sans-serif;font-size:13px}
#btVeil .bsu-step-marker svg{width:17px;height:17px;display:none}
#btVeil .bsu-step-done{display:none}
#btVeil .bsu-progress li[data-state="current"]{color:#fff}
#btVeil .bsu-progress li[data-state="current"] .bsu-step-marker{background:var(--bs-teal);border-color:var(--bs-teal);color:var(--bs-ink)}
#btVeil .bsu-progress li[data-state="done"] .bsu-step-marker{color:var(--bs-teal);border-color:#3E827F}
#btVeil .bsu-progress li[data-state="done"] .bsu-step-n{display:none}
#btVeil .bsu-progress li[data-state="done"] .bsu-step-marker svg{display:block}
#btVeil .bsu-rail-bottom{margin-top:auto;padding-top:34px}
#btVeil .bsu-rail-line{display:block;width:36px;height:3px;background:var(--bs-teal);transform:skewX(-18deg)}
#btVeil .bsu-rail-bottom p{margin:18px 0 12px;font-family:'Space Grotesk',system-ui,sans-serif;font-size:27px;line-height:1.16;letter-spacing:-.04em;font-weight:500}
#btVeil .bsu-rail-bottom p span,#btVeil .bsu-rail-bottom p strong{display:block}
#btVeil .bsu-rail-bottom strong{font-weight:500;color:var(--bs-seq2)}
/* panel */
#btVeil .bsu-panel{min-width:0;min-height:0;display:flex;flex-direction:column;position:relative}
#btVeil .bsu-topbar{min-height:70px;padding:12px 28px 12px 32px;display:flex;align-items:center;justify-content:space-between;flex:0 0 auto}
#btVeil .bsu-topbar-label{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:var(--bs-quiet)}
#btVeil .bsu-topbar-label i{width:6px;height:6px;border-radius:50%;background:var(--bs-deep)}
#btVeil .bsu-close{display:grid;place-items:center;width:32px;height:32px;padding:0;border:1px solid var(--bs-line);border-radius:50%;background:var(--bs-paper);color:var(--bs-quiet)}
#btVeil .bsu-close:hover{background:var(--bs-sky);color:var(--bs-ink)}
#btVeil .bsu-scroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-gutter:stable;padding:0 32px 26px}
#btVeil .bsu-sky{border-radius:24px;background:linear-gradient(145deg,var(--bs-sky) 0%,var(--bs-sky-lift) 58%,#D8F1FF 100%);padding:26px 29px 27px}
#btVeil .bsu-title{margin:0 0 13px;font-size:43px;line-height:1.08;letter-spacing:-.05em;color:var(--bs-ink);overflow-wrap:anywhere;outline:none}
#btVeil .bsu-title span{display:block}
#btVeil [data-stage="join"] .bsu-title span{display:inline}
#btVeil .bsu-intro{margin:0;max-width:560px;font-size:13px;line-height:1.75;color:var(--bs-quiet)}
#btVeil .bsu-offer{display:flex;flex-wrap:wrap;gap:3px 8px;margin:16px 0 0;font-size:11px;color:var(--bs-quiet)}
#btVeil .bsu-offer strong{font-weight:500;color:var(--bs-deep)}
/* signing up joins the waiting list (owner feedback 2026-10-14); an organisation talks to us instead */
#btVeil .bsu-how{max-width:560px;margin:18px 0 0;padding:14px 0 0;border-top:1px solid var(--bs-mint-line)}
#btVeil .bsu-how-title{margin:0 0 8px;font-size:11px;font-weight:500;color:var(--bs-ink)}
#btVeil .bsu-how ol{display:grid;gap:5px;margin:0;padding:0;list-style:none}
#btVeil .bsu-how li{display:flex;gap:10px;align-items:baseline;font-size:12px;line-height:1.6;color:var(--bs-quiet)}
#btVeil .bsu-how li > span{flex:none;font-family:'Space Grotesk',system-ui,sans-serif;font-size:11px;color:var(--bs-deep)}
#btVeil .bsu-shell[data-aud="org"] .bsu-how{display:none!important}
/* forms */
#btVeil .bsu-form{padding:25px 4px 0}
#btVeil .bsu-fieldset{min-width:0;margin:0;padding:0;border:0}
#btVeil .bsu-fieldset legend{width:100%;margin:0 0 11px;padding:0;font-size:13px;font-weight:500;color:var(--bs-ink)}
#btVeil .bsu-tag{margin-left:7px;font-size:10px;font-weight:400;color:var(--bs-quiet)}
#btVeil .bsu-field{display:grid;gap:9px;align-content:start}
#btVeil .bsu-field > label{font-size:13px;font-weight:500;color:var(--bs-ink)}
#btVeil .bsu-field :is(input,select){width:100%;min-width:0;height:51px;padding:12px 15px;border:1px solid var(--bs-field);border-radius:11px;background:var(--bs-paper);color:var(--bs-ink);font-size:15px;-webkit-appearance:none;appearance:none}
#btVeil .bsu-field select{padding-right:34px;background-image:linear-gradient(45deg,transparent 50%,var(--bs-quiet) 50%),linear-gradient(135deg,var(--bs-quiet) 50%,transparent 50%);background-position:calc(100% - 20px) 50%,calc(100% - 15px) 50%;background-size:5px 5px;background-repeat:no-repeat}
#btVeil .bsu-field :is(input,select):hover{border-color:var(--bs-muted)}
#btVeil .bsu-field input::placeholder{color:#758995}
#btVeil .bsu-field input[aria-invalid="true"]{border-color:var(--bs-error)}
#btVeil .bsu-hint{margin:0;font-size:11px;color:var(--bs-quiet)}
#btVeil .bsu-error{margin:0;font-size:12px;color:var(--bs-error)}
#btVeil .bsu-error-box{margin-top:16px;padding:12px 14px;border:1px solid var(--bs-error-line);border-radius:10px;background:var(--bs-error-fill)}
#btVeil .bsu-error-box:focus{outline:2px solid var(--bs-error);outline-offset:2px}
#btVeil .hp-field{position:absolute!important;left:-9999px!important;width:1px;height:1px;overflow:hidden}
#btVeil .bsu-audiences{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
#btVeil :is(.bsu-audience,.bsu-choice,.bsu-platform){position:relative;display:flex;align-items:center;gap:10px;border:1px solid var(--bs-field);border-radius:12px;background:var(--bs-paper);color:var(--bs-ink);cursor:pointer;transition:background-color 200ms cubic-bezier(.2,0,.38,.9),border-color 200ms cubic-bezier(.2,0,.38,.9)}
#btVeil .bsu-audience{align-items:flex-start;min-height:78px;padding:16px 13px}
#btVeil .bsu-audience-text strong{display:block;font-size:13px;font-weight:500}
#btVeil .bsu-audience-text small{display:block;margin-top:2px;font-size:10px;color:var(--bs-quiet)}
#btVeil :is(.bsu-audience,.bsu-choice,.bsu-platform) input{position:absolute;opacity:0;width:1px;height:1px;margin:0}
#btVeil :is(.bsu-audience,.bsu-choice,.bsu-platform):hover{border-color:var(--bs-deep)}
#btVeil :is(.bsu-audience,.bsu-choice):has(input:checked){border-color:var(--bs-deep);background:var(--bs-selected);box-shadow:inset 0 0 0 .5px var(--bs-deep)}
#btVeil :is(.bsu-audience,.bsu-choice,.bsu-platform,.bsu-consent):has(input:focus-visible){outline:3px solid var(--bs-deep);outline-offset:3px}
#btVeil :is(.bsu-audience,.bsu-choice,.bsu-platform,.bsu-consent):has(input:disabled){opacity:.65;cursor:wait}
#btVeil .bsu-dot{display:block;width:15px;height:15px;flex:0 0 15px;border:1px solid #829EAE;border-radius:50%;background:var(--bs-paper)}
#btVeil .bsu-audience .bsu-dot{margin-top:3px}
#btVeil :has(> input:checked) > .bsu-dot{border:5px solid var(--bs-deep)}
#btVeil .bsu-name-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin:20px 0 18px}
/* preferences */
#btVeil .bsu-preferences{display:grid;gap:24px}
#btVeil .bsu-question{display:grid;gap:14px}
#btVeil .bsu-sent{display:flex;gap:11px;align-items:flex-start;padding-bottom:21px;border-bottom:1px solid var(--bs-line);font-size:12px}
#btVeil .bsu-sent strong{font-weight:500}
#btVeil .bsu-sent p{margin:3px 0 0;font-size:11px;color:var(--bs-quiet);overflow-wrap:anywhere}
#btVeil .bsu-sent-check{width:25px;height:25px;flex:0 0 auto;display:grid;place-items:center;border-radius:50%;background:var(--bs-selected);color:var(--bs-deep)}
#btVeil .bsu-sent-check svg{width:16px;height:16px}
#btVeil .bsu-address{font-weight:500;color:var(--bs-ink);overflow-wrap:anywhere}
#btVeil .bsu-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}
#btVeil .bsu-choice{min-height:50px;padding:10px 13px;font-size:12px}
#btVeil .bsu-clear{margin-top:6px;padding:0;border:0;background:none;font-size:10px;color:var(--bs-deep);text-decoration:underline;text-underline-offset:3px}
#btVeil .bsu-legend-hint{margin:-4px 0 12px}
#btVeil .bsu-platforms{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}
#btVeil .bsu-platform{min-height:49px;padding:12px 14px;gap:11px;font-size:12px}
#btVeil .bsu-platform-none{grid-column:1/-1;background:var(--bs-sky-lift)}
#btVeil .bsu-platform:has(input:checked){border-color:var(--bs-deep);background:var(--bs-selected)}
#btVeil .bsu-mark{display:grid;place-items:center;width:16px;height:16px;flex:0 0 16px;border:1px solid #9AAFBB;border-radius:4px;color:#fff}
#btVeil .bsu-mark svg{width:12px;height:12px;stroke-width:3;visibility:hidden}
#btVeil .bsu-platform:has(input:checked) .bsu-mark{border-color:var(--bs-deep);background:var(--bs-deep)}
#btVeil .bsu-platform:has(input:checked) .bsu-mark svg{visibility:visible}
#btVeil .bsu-updates{padding:23px;border:1px solid var(--bs-mint-line);border-radius:19px;background:var(--bs-mint)}
#btVeil .bsu-updates-heading{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px}
#btVeil .bsu-updates-heading h3{font-size:24px;line-height:1.2;letter-spacing:-.035em;color:var(--bs-ink)}
#btVeil .bsu-updates-heading span{font-size:10px;color:var(--bs-deep)}
#btVeil .bsu-updates > p{max-width:590px;margin:10px 0 18px;font-size:12px;line-height:1.8;color:var(--bs-quiet)}
#btVeil .bsu-updates > .bsu-updates-note{margin:10px 0 0;font-size:11px}
#btVeil .bsu-consent{display:flex;gap:13px;align-items:flex-start;padding:15px 16px;border:1px solid var(--bs-mint-line);border-radius:11px;background:var(--bs-paper);cursor:pointer}
#btVeil .bsu-consent:hover,#btVeil .bsu-consent:has(input:checked){border-color:var(--bs-deep)}
#btVeil .bsu-consent input{width:21px;height:21px;flex:0 0 auto;margin:2px 0 0;accent-color:var(--bs-deep)}
#btVeil .bsu-consent input:focus-visible{outline:none}
#btVeil .bsu-consent > span{display:grid;gap:3px}
#btVeil .bsu-consent strong{font-size:13px;font-weight:600;color:var(--bs-ink)}
#btVeil .bsu-consent > span > span{font-size:11px;color:var(--bs-quiet)}
/* finish */
#btVeil .bsu-finish{padding:30px 16px 10px}
#btVeil .bsu-finish h3{margin:0 0 9px;font-size:25px;letter-spacing:-.035em;color:var(--bs-ink)}
#btVeil .bsu-finish > p{max-width:520px;margin:0;font-size:13px;line-height:1.9;color:var(--bs-quiet)}
#btVeil .bsu-next-steps{display:grid;gap:18px;margin:25px 0 0;padding:23px 0 0;border-top:1px solid var(--bs-line);list-style:none}
#btVeil .bsu-next-steps li{display:flex;gap:14px;align-items:flex-start}
#btVeil .bsu-next-steps li > span{padding-top:3px;font-family:'Space Grotesk',system-ui,sans-serif;font-size:13px;color:var(--bs-deep)}
#btVeil .bsu-next-steps p{display:grid;gap:3px;margin:0}
#btVeil .bsu-next-steps strong{font-size:12px;font-weight:500}
#btVeil .bsu-next-steps small{font-size:11px;color:var(--bs-quiet)}
#btVeil .bsu-finish > .bsu-saved{display:flex;gap:7px;align-items:center;margin:24px 0 0;font-size:11px;color:var(--bs-deep)}
#btVeil .bsu-saved svg{width:15px;height:15px}
/* dock */
#btVeil .bsu-dock{flex:0 0 auto;display:grid;gap:12px;padding:20px 36px 21px;border-top:1px solid var(--bs-line);background:var(--bs-paper)}
#btVeil .bsu-dock-row{display:flex;align-items:center;justify-content:space-between;gap:16px}
#btVeil .bsu-privacy{font-size:11px;line-height:1.75;color:var(--bs-deep);text-decoration:underline;text-underline-offset:3px}
#btVeil .bsu-back{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:10px 0;border:0;background:none;color:var(--bs-quiet);font-size:13px;font-weight:500}
#btVeil .bsu-back:hover{color:var(--bs-ink)}
#btVeil .bsu-back svg{width:17px;height:17px}
#btVeil .bsu-primary{position:relative;isolation:isolate;display:inline-flex;align-items:center;justify-content:center;gap:28px;min-height:50px;padding:13px 24px 13px 32px;border:0;background:none;color:var(--bs-ink);font-size:13px;font-weight:600;white-space:nowrap}
#btVeil .bsu-primary::before{content:"";position:absolute;z-index:-1;inset:0;background:var(--bs-teal);clip-path:polygon(16px 0,100% 0,100% 100%,0 100%);transition:background-color 200ms cubic-bezier(.2,0,.38,.9)}
#btVeil .bsu-primary:hover::before{background:#31C7B5}
#btVeil .bsu-primary svg{transition:transform 200ms cubic-bezier(.2,0,.38,.9)}
#btVeil .bsu-primary:hover svg{transform:translateX(3px)}
#btVeil .bsu-primary:focus-visible{outline:3px solid var(--bs-ink);outline-offset:4px}
#btVeil .bsu-skip{padding:2px 0;border:0;background:none;font-size:11px;color:var(--bs-quiet);text-decoration:underline;text-underline-offset:4px}
#btVeil .bsu-skip:hover{color:var(--bs-ink)}
#btVeil .bsu-thanks{margin:0;font-size:11px;color:var(--bs-quiet)}
/* which parts show at which stage */
#btVeil [data-stage="join"] [data-when="later"],
#btVeil .bsu-shell:not([data-stage="join"]) [data-when="join"],
#btVeil .bsu-shell:not([data-stage="preferences"]) [data-when="preferences"],
#btVeil .bsu-shell:not([data-stage="done"]):not([data-stage="already"]) [data-when="finish"],
#btVeil .bsu-shell:not([data-stage="done"]) .bsu-finish [data-when="done"],
#btVeil .bsu-shell:not([data-stage="already"]) .bsu-finish [data-when="already"]{display:none!important}
#btVeil .bsu-shell[data-aud="runner"] .bsu-preferences [data-aud]:not([data-aud="runner"]),
#btVeil .bsu-shell[data-aud="coach"] .bsu-preferences [data-aud]:not([data-aud="coach"]),
#btVeil .bsu-shell[data-aud="org"] .bsu-preferences [data-aud]:not([data-aud="org"]){display:none!important}
@media (min-width:721px) and (max-height:790px){
  #btVeil .bsu-rail-intro{margin:35px 0 20px}
  #btVeil .bsu-rail-bottom{padding-top:20px}
  #btVeil .bsu-rail-bottom p{font-size:23px}
  #btVeil .bsu-sky{padding-block:21px}
  #btVeil .bsu-title{font-size:36px}
  #btVeil .bsu-topbar{min-height:60px}
  #btVeil .bsu-form{padding-top:19px}
  #btVeil .bsu-audience{min-height:68px;padding-block:11px}
}
@media (min-width:721px) and (max-width:1000px){
  #btVeil{padding:18px}
  #btVeil .bsu-shell{height:calc(100dvh - 36px);grid-template-columns:224px minmax(0,1fr)}
  #btVeil .bsu-rail{padding-inline:22px}
  #btVeil .bsu-rail-title{font-size:28px}
  #btVeil .bsu-brand-word{font-size:27px}
  #btVeil .bsu-scroll,#btVeil .bsu-topbar{padding-inline:24px}
  #btVeil .bsu-audiences{gap:7px}
  #btVeil .bsu-audience{padding:13px 10px;gap:7px}
  #btVeil .bsu-audience-text strong{font-size:12px}
  #btVeil .bsu-audience-text small{font-size:9px}
  #btVeil .bsu-platforms{grid-template-columns:repeat(3,minmax(0,1fr))}
  #btVeil .bsu-sky{padding-inline:23px}
  #btVeil .bsu-title{font-size:36px}
  #btVeil .bsu-dock{padding-inline:28px}
  #btVeil .bsu-thanks{display:none}
}
@media (max-width:720px){
  #btVeil{display:block;padding:0}
  #btVeil .bsu-shell{width:100%;height:100dvh;display:flex;flex-direction:column;border-radius:0;box-shadow:none}
  #btVeil .bsu-rail{display:block;flex:0 0 auto;padding:max(18px,env(safe-area-inset-top)) 21px 14px}
  #btVeil .bsu-brand-word{font-size:25px}
  #btVeil .bsu-brand-mark{width:29px;height:29px}
  #btVeil .bsu-rail-intro,#btVeil .bsu-rail-bottom{display:none}
  #btVeil .bsu-progress{margin:16px -8px 0}
  #btVeil .bsu-progress ol{grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}
  #btVeil .bsu-progress li{flex-direction:column;align-items:flex-start;min-height:76px;gap:7px;padding:9px 8px}
  #btVeil .bsu-step-marker{width:25px;height:25px;font-size:10px}
  #btVeil .bsu-step-marker svg{width:14px;height:14px}
  #btVeil .bsu-step-name{display:block;font-size:10px;line-height:1.4}
  #btVeil .bsu-step-name small{display:none}
  #btVeil .bsu-progress-highlight{height:76px;width:calc((100% - 10px)/3);border-radius:9px;transform:translateX(calc(var(--step)*(100% + 5px)))}
  #btVeil .bsu-panel{flex:1}
  #btVeil .bsu-topbar{min-height:49px;padding:7px 19px}
  #btVeil .bsu-topbar-label{font-size:10px}
  #btVeil .bsu-scroll{padding:0 18px 24px;scrollbar-gutter:auto}
  #btVeil .bsu-sky{padding:23px;border-radius:20px}
  #btVeil .bsu-title{font-size:34px}
  #btVeil [data-stage="join"] .bsu-title span{display:block}
  #btVeil .bsu-intro{font-size:12px}
  #btVeil .bsu-how li{font-size:11px}
  #btVeil .bsu-form{padding:22px 1px 0}
  #btVeil .bsu-audiences{gap:7px}
  #btVeil .bsu-audience{flex-direction:column;gap:7px;min-height:100px;padding:11px 10px}
  #btVeil .bsu-audience-text strong{font-size:11px}
  #btVeil .bsu-audience-text small{font-size:9px;line-height:1.5}
  #btVeil .bsu-audience .bsu-dot{margin-top:0}
  #btVeil .bsu-name-fields{gap:10px}
  #btVeil .bsu-field :is(input,select){font-size:16px}
  #btVeil .bsu-choices{gap:7px}
  #btVeil .bsu-choice{min-height:60px;gap:7px;padding:10px;font-size:11px}
  #btVeil .bsu-platforms{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  #btVeil .bsu-platform{padding:12px;gap:10px}
  #btVeil .bsu-updates{padding:19px 16px;border-radius:16px}
  #btVeil .bsu-updates-heading h3{font-size:22px}
  #btVeil .bsu-consent{padding:14px 12px;gap:11px}
  #btVeil .bsu-dock{padding:14px 20px max(17px,env(safe-area-inset-bottom));gap:10px}
  #btVeil .bsu-primary{min-height:46px;padding:12px 17px 12px 25px;gap:18px;font-size:12px}
  #btVeil .bsu-back{font-size:12px}
  #btVeil .bsu-finish{padding:25px 8px 10px}
  #btVeil .bsu-finish > p{font-size:12px}
  #btVeil .bsu-thanks{display:none}
}
@media (prefers-reduced-motion:reduce){
  #btVeil *,#btVeil *::before,#btVeil *::after{transition:none!important;animation:none!important}
}
/* end beta signup 2026-10-03 */
/* render fixes 2026-10-02 (TRA-209) */
.hero::after{left:0;right:0}
.hc-head h1{min-width:0}
:where(:lang(de),:lang(nl)) .hc-head h1{hyphens:auto}
@media (max-width:899px){.closer .mega{font-size:clamp(2.6rem,13vw,261px)}}
@media (max-width:600px){.viz .u,.viz .k{white-space:normal}}
@media (max-width:560px){.tue-close .btn,.pr-foot .btn,.hc-pad .acts .btn{white-space:normal;text-align:center;max-width:100%;line-height:1.25}.hc-pad .acts{flex-wrap:wrap}}
@media (max-width:480px){.hdr .brand{gap:7px}.hdr .brand-mark{height:30px;width:30px}.hdr .brand-word{font-size:27px}.actions{gap:10px}.actions .btn{padding-left:14px;padding-right:14px}}
/* end render fixes 2026-10-02 */
.viz.light .k,.viz.light .u{opacity:.72}
