/* ==========================================================================
   Tall Order — rebuild. All values measured from tallorder.vc @1440px.
   Display font (was Cabinet Grotesk) -> GC Vank
   Body font    (was Geist)           -> Neue Haas Grotesk
   ========================================================================== */

@font-face { font-family:"GC Vank"; src:url("fonts/GCVank.woff2") format("woff2"), url("fonts/GCVank.otf") format("opentype"); font-weight:400 800; font-display:swap; }
@font-face { font-family:"Neue Haas Grotesk"; src:url("fonts/NHGText-Roman.woff2") format("woff2"), url("fonts/NHGText-Roman.otf") format("opentype");  font-weight:400; font-display:swap; }
@font-face { font-family:"Neue Haas Grotesk"; src:url("fonts/NHGText-Medium.woff2") format("woff2"), url("fonts/NHGText-Medium.otf") format("opentype"); font-weight:500; font-display:swap; }
@font-face { font-family:"Neue Haas Grotesk"; src:url("fonts/NHGText-Medium.woff2") format("woff2"), url("fonts/NHGText-Medium.otf") format("opentype"); font-weight:600; font-display:swap; }
@font-face { font-family:"Neue Haas Grotesk"; src:url("fonts/NHGText-Bold.woff2") format("woff2"), url("fonts/NHGText-Bold.otf") format("opentype");   font-weight:700; font-display:swap; }
/* Mono. Self-hosted, same as the other two families — it used to arrive from the
   Google Fonts CDN via a <link> pasted into individual pages, which is why only 21
   of them had it and every other page fell back to SF Mono. Declared here it cannot
   drift: every page already loads this file. 400 and 500 are the only weights used. */
@font-face { font-family:"IBM Plex Mono"; src:url("fonts/IBMPlexMono-Regular.woff2") format("woff2"); font-weight:400; font-display:swap; }
@font-face { font-family:"IBM Plex Mono"; src:url("fonts/IBMPlexMono-Medium.woff2") format("woff2");  font-weight:500; font-display:swap; }

:root{
  --bg:#110f0d;              /* rgb(17,15,13)    */
  --ground:#090705;          /* base under the grain; composites back to --bg */
  --surface:#1c1917;         /* rgb(28,25,23)    */
  --chip:#141210;            /* rgb(20,18,16)    */
  /* Was #16130f. Now the same value as --chip, deliberately — the two card and
     chip surfaces are one colour. Both names stay because --card has 20-odd
     call sites across nine stylesheets; collapsing them is a rename, not a
     palette change. Keep them equal, or change both. */
  --card:#141210;
  --white:#f5f5f4;           /* rgb(245,245,244) */
  --text:#fafaf9;            /* rgb(250,250,249) */
  --muted:#a6a09b;           /* rgb(166,160,155) */
  --muted-2:#78716c;
  --faint:#57534e;

  --border:rgba(250,250,249,.09);
  --border-2:rgba(250,250,249,.14);
  --hairline:rgba(250,250,249,.06);

  --font-head:"GC Vank","Neue Haas Grotesk",sans-serif;
  --font-body:"Neue Haas Grotesk",-apple-system,BlinkMacSystemFont,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,"SF Mono",Menlo,monospace;

  --gutter:64px;             /* frame margin each side  */
  --frame-max:1400px;        /* frame cap               */
  --pad:40px;                /* inner content padding   */
  --nav-h:68px;
  /* Was .25, before the dot rails were switched on site-wide. Grain and dots are
     both fine noise at a similar scale, so they compete: at .25 the grid reads as
     more grain, at .12 the grain has all but gone. .18 keeps the texture and lets
     the dots read as a grid. */
  --grain-opacity:.18;       /* noise ground strength */
  /* The dot grids, declared once. Both are the pattern defs from the source,
     tiled: bands are an 8px grid with a 1.5px dot at (4,4), cards a 12px grid
     with a 2px dot at (6,6), both #1c1917. Rails set their own width — some are
     a fixed 96px gutter, some flex — but the pattern comes from here, because
     when it lived in a page file four others pasted the URI instead. */
  --dots-band:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Crect x='4' y='4' width='1.5' height='1.5' fill='%231c1917'/%3E%3C/svg%3E");
  --dots-card:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Crect x='6' y='6' width='2' height='2' fill='%231c1917'/%3E%3C/svg%3E");
  /* One noise tile, shared by the body ground and the sticky header. */
  --grain-url:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22160%22%20height%3D%22160%22%3E%3Cfilter%20id%3D%22g%22%20x%3D%220%22%20y%3D%220%22%20width%3D%22100%25%22%20height%3D%22100%25%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%220.9%22%20numOctaves%3D%224%22%20stitchTiles%3D%22stitch%22%20result%3D%22t%22%2F%3E%3CfeColorMatrix%20in%3D%22t%22%20type%3D%22matrix%22%20values%3D%220%200%200%200%201%20%200%200%200%200%201%20%200%200%200%200%201%20%201%200%200%200%200%22%2F%3E%3CfeComponentTransfer%3E%3CfeFuncA%20type%3D%22gamma%22%20amplitude%3D%221%22%20exponent%3D%223.2%22%20offset%3D%220%22%2F%3E%3C%2FfeComponentTransfer%3E%3C%2Ffilter%3E%3Crect%20width%3D%22160%22%20height%3D%22160%22%20filter%3D%22url%28%23g%29%22%2F%3E%3C%2Fsvg%3E");
}

*,*::before,*::after{box-sizing:border-box}
*{margin:0;padding:0}
html{-webkit-text-size-adjust:100%;overflow-x:clip}
html{background:var(--ground)}
body{
  background:transparent; color:var(--text);
  font-family:var(--font-body); font-size:16px; line-height:24px; font-weight:400;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  overflow-x:clip;
}

/* Code-ish elements pick up the mono face from the element, not just from a
   scope. Every scoped rule (.prose code, .k-code code, .cx code, …) already sets
   this same family; the ones nobody scoped were falling through to the browser's
   default monospace, which after the Plex switch was the last place on the site
   where a second mono was still visible. Family only — size, colour and the code
   block's chrome stay with the scoped rules. */
code,pre,kbd,samp{font-family:var(--font-mono)}

/* ---- Noise ground -------------------------------------------------------
   Fractal noise drives the ALPHA of a white tile, so the layer is sparse bright
   speckle rather than a grey wash. <html> carries a deliberately darker base
   (--ground) and the grain lifts it back to --bg, which is why panels, the header
   and code blocks still match the ground exactly. Fixed, so it reads as grain in
   the surface rather than a texture that scrolls.
   The ground colour lives on <html> and body is transparent — a z-index:-1
   pseudo-element paints BELOW its own element's background, so if body kept a
   background the grain would be invisible. Ignores pointer events. --------- */
body::before{
  content:"";
  position:fixed; inset:-180px; z-index:-1; pointer-events:none;
  will-change:transform;
  background-image:var(--grain-url);
  background-repeat:repeat;
  background-size:160px 160px;
  opacity:var(--grain-opacity,.25);
}

/* ---- Dot rails, in the gutters ------------------------------------------
   Outside the page box, not inside it. The vertical rules stay the site's only
   edge and no content moves — which is the whole point, and the reason the
   .shell-rail version in vc.css stays off.

   One fixed layer of dots masked to the two bands outside the box, rather than
   two elements sized to guess where the box is. The band is --gutter wide until
   the viewport outgrows --frame-max, and half the overflow after that, which is
   exactly how the page box computes its own margins — so the dots meet the rule
   at every width without a breakpoint per step.

   Off below 1100, like every other rail on the site: --gutter is down to 24px by
   then, and a 24px strip of dots is litter rather than a rail. ------------- */
@media (min-width:1101px){
  body::after{
    content:"";
    position:fixed; inset:0; z-index:-1; pointer-events:none;
    --edge:max(var(--gutter),(100% - var(--frame-max)) / 2);
    background-image:var(--dots-band);
    background-repeat:repeat;
    -webkit-mask-image:linear-gradient(90deg,#000 0 var(--edge),
      transparent var(--edge) calc(100% - var(--edge)),#000 calc(100% - var(--edge)));
    mask-image:linear-gradient(90deg,#000 0 var(--edge),
      transparent var(--edge) calc(100% - var(--edge)),#000 calc(100% - var(--edge)));
  }
}

/* ---- Animated grain -----------------------------------------------------
   The layer is oversized by 180px and jumps around inside that slack on a
   steps() timeline, so the grain flickers like film. Animating `transform`
   keeps it on the compositor — no repaint per frame, unlike animating
   background-position. ~8fps: fast enough to shimmer, slow enough to stay
   cheap. Held still for anyone who asked for reduced motion. -------------- */
@keyframes grain-drift{
  0%,100%{transform:translate3d(0,0,0)}
  12.5%  {transform:translate3d(-42px,26px,0)}
  25%    {transform:translate3d(31px,-38px,0)}
  37.5%  {transform:translate3d(-19px,-47px,0)}
  50%    {transform:translate3d(48px,17px,0)}
  62.5%  {transform:translate3d(-36px,44px,0)}
  75%    {transform:translate3d(23px,-25px,0)}
  87.5%  {transform:translate3d(-47px,-14px,0)}
}
@media (prefers-reduced-motion:no-preference){
  body::before{animation:grain-drift 1s steps(1,end) infinite}
}

/* The header, the notice bar and the ascent hero's main all paint their own
   grain rather than showing the body's, because each one has an opaque ground
   that covers a z-index:-1 layer. Left alone they sat perfectly still while the
   field around them flickered — the nav read as a printed strip laid over moving
   film. They cannot borrow grain-drift: a transform makes the element the
   containing block for its own background-attachment:fixed, which unpins the
   tile from the viewport and pulls the layer out of register with the body's.
   Same eight offsets, applied to background-position instead. That repaints
   where the transform did not, but only across a 68px band at ~8fps. */
@keyframes grain-drift-bg{
  0%,100%{background-position:0 0}
  12.5%  {background-position:-42px 26px}
  25%    {background-position:31px -38px}
  37.5%  {background-position:-19px -47px}
  50%    {background-position:48px 17px}
  62.5%  {background-position:-36px 44px}
  75%    {background-position:23px -25px}
  87.5%  {background-position:-47px -14px}
}
@media (prefers-reduced-motion:no-preference){
  .notice-bar::before,
  .header::before,
  .ascent-page main::before{animation:grain-drift-bg 1s steps(1,end) infinite}
}
/* decorative motion does not run while the tab is in the background */

/* ---- Page transition -----------------------------------------------------
   A cross-document view transition: the browser snapshots the outgoing page,
   fetches the next one, and crossfades the two. Native, so there is no script
   in the navigation path and no way for a failed script to strand a page at
   opacity 0. The default root animation is already a crossfade, so all this
   sets is its pace.

   Every page carries the same --ground and the same fixed grain, so the two
   snapshots sit on an identical field and only the content appears to move.
   The header is sticky and identical page to page, so it crossfades against
   itself and reads as static — the same effect Framer gets by keeping the nav
   mounted across a soft navigation.

   Pace is the reference's: 200ms on cubic-bezier(.12,.23,.5,1), measured off
   the previous site, which crossfades opacity only. 320ms on the old curve
   was slow enough to read as a transition rather than as the page arriving.

   Firefox has no cross-document view transitions yet; main.js adds .pt-js
   there and fades the document out on the way to the next page instead. It
   fades to --ground, which is <html>'s own background, so the ground never
   flashes. -------------------------------------------------------------- */
@view-transition{navigation:auto}

/* Our own keyframes, not the UA's. Chrome's default pair is
   `-ua-view-transition-fade-out, -ua-mix-blend-mode-plus-lighter` — the blend
   mode arrives as an ANIMATION, so a plain `mix-blend-mode:normal` here loses to
   it in the cascade and only !important or replacing animation-name gets rid of
   it. Replacing it is the honest version, and it has to supply the fade too,
   since naming our own drops both of the UA's animations.

   Why bother: plus-lighter ADDS the two snapshots. Chrome does that to avoid a
   luminance dip mid-crossfade, and it is the wrong trade here — where both pages
   carry light pixels in the same place, the sum clips. Leaving an interior page
   for index.html put white body copy over a lit hero and a white headline, and
   the transition flashed white. Normal alpha compositing instead: the dip
   plus-lighter exists to prevent costs nothing when every page crossfades
   against the same --ground, because the luminance it is missing is a colour
   both snapshots already share. ---------------------------------------------- */
@keyframes pt-fade-out{to{opacity:0}}
@keyframes pt-fade-in{from{opacity:0}}
::view-transition-old(root),
::view-transition-new(root){
  animation-duration:.2s;
  animation-timing-function:cubic-bezier(.12,.23,.5,1);
  animation-fill-mode:both;
  mix-blend-mode:normal;
}
::view-transition-old(root){animation-name:pt-fade-out}
::view-transition-new(root){animation-name:pt-fade-in}
html.pt-js body{transition:opacity .2s cubic-bezier(.12,.23,.5,1)}
html.pt-js.pt-leaving body{opacity:0}

@media (prefers-reduced-motion:reduce){
  @view-transition{navigation:none}
  html.pt-js body{transition:none}
  html.pt-js.pt-leaving body{opacity:1}
}

a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
::selection{background:var(--text);color:var(--bg)}

/* ---- Type scale (measured) ---- */
h1{
  font-family:var(--font-head); font-weight:700;
  font-size:72px; line-height:64px; letter-spacing:0;
  text-transform:uppercase;
}
/* section headings use the BODY font at 32/34 600 */
h2,h3{
  font-family:var(--font-body); font-weight:600;
  font-size:32px; line-height:34px; letter-spacing:-.01em;
}
/* display slots that used Cabinet Grotesk */
.display{
  font-family:var(--font-head); font-weight:700;
  font-size:60px; line-height:52px; letter-spacing:0;
  text-transform:uppercase;
}
.display-sm{
  font-family:var(--font-head); font-weight:700;
  font-size:48px; line-height:40px; letter-spacing:0;
  text-transform:uppercase;
}

/* ---- The page box ----
   One box, and everything that draws a page edge sits in it: the notice bar,
   the header, main, and the footer. That is what makes the two vertical rules
   run unbroken from the first pixel of the page to the last, rather than
   starting under the header and stopping above the footer.

   Inside the box there is one inset — --pad — and it is the site's only left
   edge. Nav, breadcrumb, body copy and footer columns all land on it. Anything
   that introduces a second inset (an inner rail, a wrap with its own gutter)
   breaks the alignment and should use .page-box instead. */
.page-box,
.notice-bar,
.header,
.frame,
.footer{
  width:calc(100% - (var(--gutter) * 2));
  max-width:var(--frame-max);
  margin-inline:auto;
  border-left:1px solid var(--border);
  border-right:1px solid var(--border);
}

/* The notice bar is chrome — setchrome.py stamps it into every page, so its
   styling has to live in a stylesheet every page loads. It sat in vc.css, which
   left it unstyled on the pages that do not load vc.css (contact, careers,
   careers-role). Every other piece of chrome is already here. */
/* ==========================================================================
   Notification bar — sits ABOVE the sticky nav, scrolls away with the page.
   ========================================================================== */
/* The same trick the header plays below. On --surface the bar was a lighter
   band sitting on top of the page instead of part of it, and it was the one
   piece of chrome with no texture at all. It paints the darker --ground and
   carries its own grain layer, which composites back to --bg — so the bar, the
   nav and the page are one field, and the hairline and the News chip are what
   separate them. background-attachment:fixed locks the tile to the viewport, so
   it drifts with the other two rather than reading as a third pattern. */
.notice-bar{position:relative;z-index:101;background:var(--ground);isolation:isolate;
  border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:center;
  gap:12px;padding:9px 20px;font-size:13px;line-height:18px;color:var(--muted)}
.notice-bar::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:var(--grain-url);
  background-repeat:repeat;background-size:160px 160px;background-attachment:fixed;
  opacity:var(--grain-opacity,.25);
}
.notice-bar > *{position:relative;z-index:1}
.notice-bar .tag{font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;background:var(--to-first-light,#fff695);color:#17130d;padding:3px 8px;font-weight:500;flex:none}
.notice-bar a{color:var(--text);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--faint)}
.notice-bar a:hover{text-decoration-color:var(--text)}
.notice-bar .close{margin-left:8px;color:var(--muted-2);font-size:15px;line-height:1;flex:none}
.notice-bar .close:hover{color:var(--text)}
.notice-bar[hidden]{display:none}

/* Dismissal fades and settles rather than vanishing. The inline script stamped
   with the bar adds .is-dismissed, waits for the transition, then sets [hidden]
   so it leaves the layout cleanly. The choice is remembered in a cookie, so the
   bar stays gone across pages and across sessions. */
.notice-bar{transition:opacity .28s ease,transform .28s ease}
.notice-bar.is-dismissed{opacity:0;transform:translateY(-6px);pointer-events:none}
@media (prefers-reduced-motion:reduce){
  .notice-bar{transition:none}
}

/* The hidden attribute must beat component display rules. The UA sheet only
   gives [hidden] a bare display:none, so any class that sets display — and most
   component classes do — silently overrides it and the element stays on screen.
   This is the standard author-level fix, and it is why .notice-bar[hidden] above
   had to exist at all. */
[hidden]{display:none !important}

/* ---------- Breadcrumb ----------
   setcrumb.py stamps this into every interior page, so — like the notice bar —
   its styling has to live where every page loads it, not in vc.css.
   team/careers.html does not load vc.css and its crumb rendered unstyled. */
.crumb{display:flex;align-items:center;gap:10px;padding:20px var(--pad);border-bottom:1px solid var(--border);
  font-size:14px;line-height:20px;color:var(--muted-2)}
.crumb a{color:var(--text)}
.crumb a:hover{opacity:.8}

/* Above a full-bleed band — the founders and investors heroes — the crumb is a
   body-level element, so there is no frame above it to take the box from. It
   draws its own, the same four properties .page-box uses, and its border-bottom
   becomes the rule the band sits under. Scoped to a direct child of body so the
   crumb inside main.frame, which already has a box, is untouched. */
body > .crumb{
  width:calc(100% - (var(--gutter) * 2));
  max-width:var(--frame-max);
  margin-inline:auto;
  border-left:1px solid var(--border);
  border-right:1px solid var(--border);
}

/* This used to carry the page box itself, because on the legal and long-form
   writing pages <main> was bare and a direct-child crumb spanned the full
   viewport. Those pages are main.frame now, so the box came from two places at
   once and the crumb sat 65px right of the wordmark instead of under it. The
   frame is the only box; the crumb just fills it and pads to --pad. */
@media (max-width:620px){ .notice-bar{font-size:12px;padding:8px 14px;text-align:left} }

/* About half the pages close the footer inside main rather than after it. There
   the frame already draws the two rules, so the footer fills its column instead
   of insetting a second box within it. Either markup gives the same edges. */
.frame .footer{
  width:auto;max-width:none;margin-inline:0;
  border-left:0;border-right:0;
}
.section{border-bottom:1px solid var(--border)}
.pad{padding-left:var(--pad);padding-right:var(--pad)}

/* ==========================================================================
   Header
   ========================================================================== */
/* The header was flat --bg: the right colour, but no texture, because the grain
   lives on a body::before at z-index:-1 and any opaque background covers it. It
   is sticky so it cannot simply go transparent — content would scroll through.
   So it paints the darker --ground and carries its own grain layer on top, which
   composites back to --bg exactly like the body does. background-attachment:fixed
   locks the tile to the viewport so it lines up with the body's own grain. */
.header{position:sticky;top:0;z-index:100;background:var(--ground);
  border-bottom:1px solid var(--border);isolation:isolate}
.header::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:var(--grain-url);
  background-repeat:repeat;background-size:160px 160px;background-attachment:fixed;
  opacity:var(--grain-opacity,.25);
}
.header > *{position:relative;z-index:1}
.nav{height:var(--nav-h);display:flex;align-items:center;gap:16px;padding:0 var(--pad);max-width:none}
.brand{display:flex;align-items:center;gap:8px;font-family:var(--font-head);font-size:22px;font-weight:700;letter-spacing:0;text-transform:uppercase;margin-right:16px}
.brand svg{width:22px;height:22px}

.nav-links{display:flex;align-items:center;gap:0}
.nav-item{position:relative}
.nav-link{display:inline-flex;align-items:center;gap:4px;padding:8px 14px;border-radius:0;font-size:14px;line-height:20px;font-weight:500;color:var(--white);transition:background .18s}
.nav-link:hover,.nav-item.open .nav-link{background:rgba(250,250,249,.06)}
.nav-link .chev{transition:transform .2s;opacity:.7}
.nav-item.open .nav-link .chev{transform:rotate(180deg)}
.nav-spacer{flex:1}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;font-size:14px;line-height:20px;font-weight:500;border-radius:0;padding:10px 16px;transition:opacity .18s,background .18s;white-space:nowrap}
.btn-white{background:var(--white);color:var(--surface)}
.btn-white:hover{opacity:.88}
.btn-ghost{background:var(--surface);color:var(--white)}
.btn-ghost:hover{background:#262220}
.btn-nav{padding:8px 14px}

/* Dropdowns */
.dropdown{position:absolute;top:calc(100% + 8px);left:0;background:#171310;border:1px solid var(--border-2);border-radius:0;padding:12px;box-shadow:0 24px 60px rgba(0,0,0,.5);opacity:0;visibility:hidden;transform:translateY(-6px);transition:opacity .18s,transform .18s,visibility .18s;z-index:120}
.nav-item.open .dropdown{opacity:1;visibility:visible;transform:translateY(0)}
.dd-features{display:flex;gap:4px;width:534px}
.dd-feature{flex:1;padding:12px;border-radius:0;transition:background .18s;display:flex;flex-direction:column;gap:12px;width:173px}
.dd-feature:hover{background:rgba(250,250,249,.05)}
.dd-icon{width:40px;height:40px;display:flex;align-items:center;justify-content:center;color:var(--text);margin-bottom:16px}
.dd-feature h4{font-family:var(--font-body);font-weight:500;font-size:14px;line-height:20px;letter-spacing:0;margin-bottom:4px}
.dd-feature p{color:var(--muted);font-size:14px;line-height:20px}
.dd-resources{display:grid;grid-template-columns:1.35fr 1fr;width:560px;gap:8px}
.dd-col-label{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted-2);padding:6px 12px 10px}
.dd-link-rich{display:flex;gap:12px;padding:10px 12px;border-radius:0;transition:background .18s}
.dd-link-rich:hover{background:rgba(250,250,249,.05)}
.dd-link-rich .ic{width:36px;height:36px;flex:none;border:1px solid var(--border-2);border-radius:0;display:flex;align-items:center;justify-content:center}
.dd-link-rich h4{font-family:var(--font-body);font-weight:500;font-size:14px;line-height:20px;letter-spacing:0;margin-bottom:2px}
.dd-link-rich p{color:var(--muted);font-size:14px;line-height:20px}
.dd-resources .col-right{border-left:1px solid var(--border);padding-left:8px}
.dd-simple{display:block;padding:10px 12px;border-radius:0;font-size:14px;line-height:20px;transition:background .18s}
.dd-simple:hover{background:rgba(250,250,249,.05)}

.hamburger{display:none;margin-left:auto;width:36px;height:36px;border-radius:0;border:1px solid var(--border-2);align-items:center;justify-content:center}
.mobile-menu{display:none}

/* ==========================================================================
   Hero
   ========================================================================== */
.hero{position:relative}
.badge-row{padding:22px var(--pad);border-bottom:1px solid var(--border)}
.badge{display:inline-flex;align-items:center;gap:16px;font-size:14px;line-height:20px;color:var(--text)}
.badge .tag{font-size:12px;line-height:16px;font-weight:500;background:var(--surface);border-radius:0;padding:4px 8px;color:var(--text)}
.badge .dots{color:var(--muted-2)}

.hero-body{padding:120px var(--pad) 0;position:relative;z-index:2}
.hero h1{max-width:9ch}
.hero-lead{margin-top:24px;max-width:576px;color:var(--muted);font-size:16px;line-height:24px}
.hero-cta{display:flex;gap:12px;margin-top:32px}
.hero-art{position:absolute;top:0;right:0;width:58%;max-width:760px;pointer-events:none;z-index:1;opacity:.9}
.hero-art img{width:100%;height:auto}

.steps{display:grid;grid-template-columns:repeat(3,221px);gap:32px;padding:120px var(--pad) 64px;position:relative;z-index:2}
.step-h{font-size:16px;line-height:24px;font-weight:600;margin-bottom:8px}
.step-h .n{color:var(--muted-2);font-weight:500}
.step p{color:var(--muted);font-size:14px;line-height:20px}

.trusted{padding:24px var(--pad) 0}
.trusted p{color:var(--muted);font-size:14px;line-height:20px;font-weight:500}
.marquee{margin-top:24px;padding:28px 0 32px;overflow:hidden;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
/* will-change promotes the track to its own compositor layer, so the marks are
   rasterised once and the animation just moves that texture. Without it the
   logos are SVG, and almost every one comes out a fractional number of pixels
   wide — the browser re-rasterises them at a new sub-pixel offset every frame
   and they shimmer. Taller marks make the fractions bigger, which is why the
   flicker showed up when the height went from 22px to 30px.
   The marks are also NOT lazy in the markup: the track is width:max-content, so
   an image arriving late grows it and translateX(-50%) lands somewhere new. */
.marquee-track{display:flex;gap:64px;width:max-content;animation:scroll-x 48s linear infinite;
  will-change:transform;backface-visibility:hidden}
.logo-item{display:flex;align-items:center;gap:10px;color:#d8d4cf;font-size:22px;font-weight:600;white-space:nowrap;letter-spacing:-.01em}
.logo-item svg{width:24px;height:24px;flex:none}
.logo-item img{height:30px;width:auto;max-width:150px;object-fit:contain;flex:none;
  filter:brightness(0) invert(1);opacity:.75}
@keyframes scroll-x{to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.marquee-track{animation:none}}
/* Linked logos: a moving target needs to stop before it can be clicked.
   With JS, main.js ramps playbackRate so it eases to a stop instead. */
html:not(.js) .marquee:hover .marquee-track,
html:not(.js) .marquee:focus-within .marquee-track{animation-play-state:paused}
a.logo-item img{transition:opacity .2s}
a.logo-item:hover img,a.logo-item:focus-visible img{opacity:1}
a.logo-item:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
/* ==========================================================================
   Marquee with a lede — a label holds the left, the logos run past it.
   Extends .marquee / .marquee-track / .logo-item in styles.css. The left
   edge fade is dropped so the run reads as starting from the text.
   ========================================================================== */
.marquee-row{display:flex;align-items:center;gap:48px;padding:28px 0 32px}
.marquee-row .marquee-lede{flex:none;max-width:270px}
.marquee-row .marquee-lede h4{margin:0 0 6px;letter-spacing:0}
.marquee-row .marquee-lede p{margin:0;color:var(--muted);font-size:14px;line-height:20px}
.marquee-row .marquee{flex:1 1 auto;min-width:0;margin-top:0;padding:0;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 3%,#000 86%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 3%,#000 86%,transparent)}
@media (max-width:700px){
  .marquee-row{display:block;padding:24px 0 28px}
  .marquee-row .marquee-lede{max-width:none;margin-bottom:18px}
  .marquee-row .marquee{-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
    mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
}


/* ==========================================================================
   Statement + conversation
   ========================================================================== */
.statement{padding:96px var(--pad)}
.statement h2{max-width:616px;color:var(--muted)}
.statement h2 .hl{color:var(--text)}

.convo-wrap{display:flex;flex-direction:column;align-items:center;padding:40px var(--pad) 120px}
.convo-card{width:100%;max-width:560px;background:var(--card);border:1px solid var(--border-2);border-radius:0;padding:20px}
.convo-q{font-size:16px;line-height:24px;min-height:72px}
.convo-q .caret{color:var(--muted-2)}
.convo-bar{display:flex;align-items:center;justify-content:space-between;margin-top:16px}
.convo-bar .plus{color:var(--muted);font-size:18px}
.convo-send{width:32px;height:32px;border-radius:0;background:var(--surface);display:flex;align-items:center;justify-content:center}
.convo-chips{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:16px}
.chip{display:inline-flex;align-items:center;gap:8px;padding:8px;border-radius:0;background:var(--chip);color:var(--muted);font-size:14px;line-height:16px}
.chip svg{width:14px;height:14px}

/* ==========================================================================
   Feature showcase
   ========================================================================== */
.showcase{display:grid;grid-template-columns:1fr 1fr}
.showcase-left{border-right:1px solid var(--border)}
.feature-block{min-height:640px;padding:96px var(--pad);display:flex;flex-direction:column;justify-content:center;border-bottom:1px solid var(--border)}
.feature-block:last-child{border-bottom:none}
.feature-block h2{margin-bottom:16px}
.feature-block>p{color:var(--muted);font-size:16px;line-height:24px;max-width:576px}
.feat-points{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:40px}
.feat-point .fp-ic{color:var(--text);margin-bottom:12px}
.feat-point p{font-size:14px;line-height:20px;font-weight:500}
.explore{display:inline-flex;align-items:center;gap:12px;margin-top:40px;color:var(--muted);font-size:14px;line-height:20px;font-weight:500;transition:color .18s}
.explore:hover{color:var(--text)}
.explore .round{width:26px;height:26px;border-radius:0;background:var(--surface);display:flex;align-items:center;justify-content:center}

.showcase-right{position:relative}
.sticky-panel{position:sticky;top:var(--nav-h);height:calc(100vh - var(--nav-h));display:flex;align-items:center;justify-content:center;padding:40px}
.panel-visual{width:100%;max-width:420px}
.panel-stage{position:relative}
.panel-view{position:absolute;inset:0;opacity:0;transition:opacity .5s,transform .5s;transform:translateY(12px);pointer-events:none}
.panel-view.active{position:relative;opacity:1;transform:none;pointer-events:auto}

/* ---------- Feature rail ----------
   The strip is taller than its window and slides inside it; the needle stays
   put. Both ends of the window are masked so a step fades out rather than being
   guillotined at the edge, which is what makes the travel read as one long
   scale rather than a short list moving. main.js writes the transform and fills
   .tick-marks; with no JS the strip parks with step 01 on the needle, which is
   what the rail used to say before anything scrolled.

   The strip is not transitioned — it tracks the scroll position frame by frame,
   and easing a scroll-linked transform only makes it lag the finger. Only the
   colour and width changes ease. */
.ticks{position:absolute;right:16px;top:50%;transform:translateY(-50%);
  display:flex;align-items:center;gap:4px;pointer-events:none}
.ticks-window{
  position:relative;width:24px;height:300px;overflow:hidden;
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 12%,#000 88%,transparent);
  mask-image:linear-gradient(180deg,transparent,#000 12%,#000 88%,transparent);
}
.ticks-strip{position:absolute;top:0;right:0;display:flex;flex-direction:column;
  align-items:flex-end;will-change:transform}
/* The spacing is doing a job. A number's own first mark has to sit closer to it
   than the previous step's last mark does, or the mark that lights when a number
   reaches the needle belongs to the step above it — and step 03's marks never
   light at all, because nothing follows them. So: tight under the number, wide
   under the marks. */
.tick-step{display:flex;flex-direction:column;align-items:flex-end;gap:6px}
.tick-marks{display:flex;flex-direction:column;align-items:flex-end;gap:10px;padding:0 0 26px}
.tick{width:10px;height:1px;background:var(--faint);transition:background .3s,width .3s}
.tick.on{width:18px;background:var(--text)}
.tick-num{font-family:var(--font-mono);font-size:11px;line-height:16px;color:var(--faint);
  transition:color .3s}
.tick-num.on{color:var(--text)}
/* The marker the strip is wound past. Same 5px the reference uses. */
.ticks-needle{width:5px;height:1px;background:var(--text);flex:none}

.src-row{display:flex;align-items:center;justify-content:space-between;background:var(--card);border:1px solid var(--border);border-radius:0;padding:16px;margin-bottom:12px}
.src-row .name{font-size:16px;line-height:24px}
.src-row .sub{font-family:var(--font-mono);font-size:12px;color:var(--muted-2);margin-top:2px}
.status{display:inline-flex;align-items:center;gap:8px;font-size:14px}
.status .dot{width:8px;height:8px;border-radius:0}
.status.live{color:var(--accent)} .status.live .dot{background:var(--accent);box-shadow:0 0 0 3px rgba(255,246,149,.18)}
.status.sync{color:var(--muted)} .status.sync .dot{background:var(--muted)}
.status.pend{color:var(--to-grey-300)} .status.pend .dot{background:var(--to-grey-300)}

.ask-card,.pulse-card{background:var(--card);border:1px solid var(--border-2);border-radius:0;padding:20px}
.ask-head{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:14px;margin-bottom:16px}
.ask-q{font-size:16px;line-height:24px;margin-bottom:16px}
.ask-think{font-family:var(--font-mono);font-size:12px;color:var(--accent);letter-spacing:.06em;margin-bottom:14px}
.ask-chips{display:flex;gap:8px;flex-wrap:wrap}
.pulse-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.sev{display:inline-flex;align-items:center;gap:8px;color:var(--accent);font-size:14px;font-weight:500}
.sev .dot{width:8px;height:8px;border-radius:0;background:var(--accent)}
.pulse-time{font-family:var(--font-mono);font-size:12px;color:var(--muted-2)}
.pulse-card h4{font-family:var(--font-body);font-weight:600;font-size:16px;line-height:24px;margin-bottom:6px}
.pulse-card p{color:var(--muted);font-size:14px;line-height:20px}
.spark{height:56px;margin:16px 0}
.pulse-sent{display:flex;align-items:center;justify-content:space-between;font-family:var(--font-mono);font-size:12px;color:var(--muted-2);border-top:1px solid var(--border);padding-top:12px}
.pulse-sent .ok{color:var(--accent)}

/* ==========================================================================
   Connect your stack
   ========================================================================== */
.stack{display:grid;grid-template-columns:1fr 1fr}
.stack-left{padding:120px var(--pad);border-right:1px solid var(--border);display:flex;flex-direction:column;justify-content:center}
.stack-left h2{margin-bottom:16px}
.stack-left p{color:var(--muted);max-width:445px;font-size:16px;line-height:24px}
.stack-right{padding:48px 40px;display:flex;align-items:center}
.stack-card{width:100%;background:var(--card);border:1px solid var(--border-2);border-radius:0;overflow:hidden}
.stack-card-head{padding:14px 16px;border-bottom:1px solid var(--border);font-size:14px;color:var(--muted-2)}
.stack-grid{display:grid;grid-template-columns:1.15fr .85fr}
.stack-sources{border-right:1px solid var(--border)}
.si-row{display:flex;align-items:center;gap:12px;padding:14px 16px;border-bottom:1px solid var(--hairline)}
.si-row:last-child{border-bottom:none}
.si-logo{width:32px;height:32px;border-radius:0;display:flex;align-items:center;justify-content:center;flex:none}
.si-row .nm{font-size:14px;line-height:20px}
.si-row .meta{font-family:var(--font-mono);font-size:11px;color:var(--muted-2);margin-top:2px}
.si-row .meta b{color:var(--accent);font-weight:400}
.stack-logos{display:grid;grid-template-columns:repeat(3,1fr)}
.sl-cell{aspect-ratio:1;display:flex;align-items:center;justify-content:center;border-bottom:1px solid var(--hairline);border-right:1px solid var(--hairline);color:var(--faint)}
.sl-cell svg{width:24px;height:24px;opacity:.55}
.stack-card-foot{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-top:1px solid var(--border);font-family:var(--font-mono);font-size:12px;color:var(--muted-2)}
.stack-card-foot .add{display:inline-flex;align-items:center;gap:8px}

/* ==========================================================================
   Testimonial
   ========================================================================== */
.testi{display:grid;grid-template-columns:1fr .78fr}
.testi-left{padding:80px var(--pad);border-right:1px solid var(--border);display:flex;flex-direction:column}
.testi-num{font-family:var(--font-head);font-weight:700;font-size:60px;line-height:52px;letter-spacing:0;text-transform:uppercase}
.testi-num-sub{color:var(--muted);font-size:20px;line-height:28px;margin-top:8px}
.testi-rule{height:1px;background:var(--border);margin:32px 0}
.testi-quote{font-size:20px;line-height:28px;text-align:right;margin-left:auto;max-width:541px}
.testi-attr{text-align:right;margin-top:24px}
.testi-attr .nm{font-size:16px;line-height:24px}
.testi-attr .role{color:var(--muted-2);font-size:14px;line-height:20px;margin-top:2px}
.testi-arrows{display:flex;gap:8px;margin-top:auto;padding-top:32px}
.arrow-btn{width:26px;height:26px;border-radius:0;background:var(--surface);display:flex;align-items:center;justify-content:center;color:var(--muted);transition:color .18s,background .18s,opacity .18s}
.arrow-btn:hover:not(:disabled){color:var(--text);background:#262220}
.arrow-btn:disabled{opacity:.35;cursor:default}
.testi-right{position:relative;overflow:hidden;min-height:460px}
.testi-right img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 25%;opacity:0;transition:opacity .5s}
.testi-right img.active{opacity:1}

/* ==========================================================================
   Stats / FAQ / CTA
   ========================================================================== */
.stats-head{padding:96px var(--pad) 56px}
.stats-head h2{max-width:472px;color:var(--muted)}
.stats-head h2 .hl{color:var(--text)}
.stats-grid{display:grid;grid-template-columns:repeat(4,1fr);padding:0 var(--pad) 96px;gap:24px}
.stat .ic{color:var(--faint);margin-bottom:40px;height:40px}
.stat .big{font-family:var(--font-head);font-weight:700;font-size:48px;line-height:40px;letter-spacing:0;text-transform:uppercase}
.stat .lbl{color:var(--muted);font-size:16px;line-height:24px;margin-top:8px}

.faq{display:grid;grid-template-columns:1fr 1fr;padding:96px var(--pad);gap:40px}
.faq-head p{color:var(--muted);font-size:16px;line-height:24px;margin-top:12px;max-width:32ch}
.faq-list{display:flex;flex-direction:column}
.faq-item{border-bottom:1px solid var(--border)}
.faq-item:first-child{border-top:1px solid var(--border)}
.faq-q{display:flex;align-items:center;justify-content:space-between;gap:20px;width:100%;text-align:left;padding:18px 0;font-size:18px;line-height:24px;font-weight:600;color:var(--text)}
.faq-q .ico{flex:none;width:20px;height:20px;position:relative}
.faq-q .ico::before,.faq-q .ico::after{content:"";position:absolute;background:var(--muted);border-radius:0;transition:transform .25s,opacity .25s}
.faq-q .ico::before{top:9px;left:2px;width:16px;height:2px}
.faq-q .ico::after{left:9px;top:2px;width:2px;height:16px}
.faq-item.open .faq-q .ico::after{transform:rotate(90deg);opacity:0}
.faq-a{max-height:0;overflow:hidden;transition:max-height .35s}
.faq-a p{color:var(--muted);font-size:16px;line-height:24px;padding:0 40px 20px 0}

.cta{padding:140px var(--pad);text-align:center}
.cta h2{font-family:var(--font-head);font-weight:700;font-size:60px;line-height:52px;letter-spacing:0;text-transform:uppercase;margin-bottom:28px}

/* ==========================================================================
   Footer
   ========================================================================== */
/* --wordmark-w is the one place the footer wordmark's width is decided, and
   everything else here reads it: the mark itself, and the min-height that keeps
   the footer tall enough to show it whole.

   It is measured off the VIEWPORT, not off the footer, because the footer is
   not the same width on every page — it is the page box on framed pages (1310
   at 1440) and full bleed on the ascent page (1440). Sizing off the footer gave
   the same mark two widths, 1230 on investors.html against 1360 on index.html.

   Taking one gutter off the viewport lands exactly halfway between those two:
   at 1440 that is 1440 - 64 - 80 = 1296. The mark is then identical on both,
   and centred, so it sits at the same place on screen either way.

   Height follows from the SVG's own 544:149, plus --wordmark-clear.

   That clearance is not decoration. Without it min-height equals the mark's
   height exactly, so the mark spans the footer top to bottom and its top edge
   lands on the footer's own top edge — which reads as a crop even though the
   whole glyph is there. The clearance is the gap the eye needs to see it
   sitting inside the footer rather than running out of it. */
/* Flow sits at the BOTTOM of the footer box, not the top. min-height still sets
   how tall the footer is; the column just decides where the legal lines, the
   chip and the social mark land inside it — flush to the base of the wordmark
   rather than floating above it with dead space underneath. On the v2 pages the
   link columns make the footer taller than min-height, so justify-content has
   nothing to distribute and this is a no-op there. */
.footer{position:relative;overflow:hidden;padding:40px 0 0;
  display:flex;flex-direction:column;justify-content:flex-end;
  --wordmark-w:calc(
    min(100vw, var(--frame-max) + var(--gutter) * 2)
    - var(--gutter) - var(--pad) * 2);
  --wordmark-clear:calc(var(--pad) * 1.5);
  /* The 340px floor is about the news notice, not the wordmark. Above 900 the
     notice is pinned to the footer's bottom-right corner — the same corner the
     status chip sits above now that it is right-aligned — and its top lands at
     footerHeight - 86 (58 tall, 28 up from the bottom). Let the footer get
     shorter than about 340 and that walks the notice straight up into the chip,
     which is what happened between roughly 900 and 1150 where the wordmark is
     small enough that content, not the mark, sets the height. */
  min-height:max(
    calc((var(--wordmark-w) / 3.651) + var(--wordmark-clear)),
    340px)}
.footer-cols{display:grid;grid-template-columns:repeat(4,1fr);padding:56px var(--pad) 36px;gap:24px;position:relative;z-index:2}
.footer-col h5{font-family:var(--font-body);font-weight:500;font-size:14px;line-height:20px;margin-bottom:16px}
.footer-col a{display:flex;align-items:center;gap:4px;color:var(--muted);font-size:14px;line-height:20px;padding:6px 0;transition:color .18s}
.footer-col a:hover{color:var(--text)}
.footer-bar{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;padding:38px var(--pad);border-top:1px solid var(--border)}
.status-pill{display:inline-flex;align-items:center;gap:8px;padding:12px 16px;border-radius:0;border:1px solid var(--border-2);font-size:12px;line-height:16px}
.status-pill .dot{width:8px;height:8px;border-radius:0;background:var(--accent);box-shadow:0 0 0 3px rgba(255,246,149,.16)}
.status-pill .up{font-family:var(--font-mono);color:var(--muted-2);font-size:11px}
.status-pill .sep{color:var(--faint)}
.subscribe{display:flex;align-items:center;gap:12px}
.subscribe .lbl{color:var(--muted-2);font-size:14px;line-height:20px}
.sub-field{display:flex;align-items:center;background:var(--surface);border-radius:0;padding:4px 4px 4px 12px;gap:8px}
.sub-field input{background:none;border:none;color:var(--text);font-family:var(--font-body);font-size:14px;width:140px;outline:none}
.sub-field input::placeholder{color:var(--muted-2)}
.sub-field .redsq{width:20px;height:20px;border-radius:0;background:var(--accent);display:flex;align-items:center;justify-content:center}
.sub-btn{background:var(--white);color:var(--surface);border-radius:0;padding:8px 14px;font-size:14px;line-height:20px;font-weight:500}

.footer-watermark{
  font-family:var(--font-head);font-weight:700;text-transform:uppercase;
  font-size:clamp(130px,30vw,440px);line-height:.84;
  color:transparent;padding:32px var(--pad) 0;
  background:linear-gradient(180deg,rgba(250,250,249,.05),rgba(250,250,249,0));
  -webkit-background-clip:text;background-clip:text;
  letter-spacing:0;user-select:none;pointer-events:none;white-space:nowrap;overflow:hidden;
}
/* 12px, not 40. The copyright line, the status chip and the general-advice
   disclaimer are one legal block — 40px between each read as three unrelated
   rows stacked with air. */
.footer-legal{display:flex;justify-content:space-between;padding:0 var(--pad) 12px;position:relative;z-index:2}
.footer-legal,.footer-legal a{color:var(--muted-2);font-size:12px;line-height:16px;font-weight:500}

/* ==========================================================================
   About  —  920px centred column (measured)
   ========================================================================== */
.about-col{
  width:920px; max-width:100%;
  margin:0 auto;
  border-left:1px solid var(--border);
  border-right:1px solid var(--border);
}
.about-title{padding:32px var(--pad);border-bottom:1px solid var(--border)}
.about-title h1{font-size:48px;line-height:48px}
.about-block{padding:32px var(--pad);border-bottom:1px solid var(--border)}
.about-label{font-size:14px;line-height:20px;color:var(--muted-2);margin-bottom:28px}
.about-body p{font-size:16px;line-height:24px;max-width:560px}
.about-body p+p{margin-top:20px}
.about-meta{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;margin-top:56px;flex-wrap:wrap}
.about-fund .big{font-family:var(--font-head);font-weight:700;font-size:48px;line-height:40px;letter-spacing:0;text-transform:uppercase}
.about-fund .sub{color:var(--muted);font-size:16px;line-height:24px;margin-top:6px}
.about-facts .row{display:flex;justify-content:flex-end;gap:8px;font-size:14px;line-height:20px;padding:3px 0}
.about-facts .row .k{color:var(--muted-2)}
.about-facts .row .v{color:var(--text);min-width:110px;text-align:left}

.milestones{padding:32px var(--pad) 48px;border-bottom:1px solid var(--border);overflow:hidden}
.ms-viewport{position:relative;overflow:hidden}
.ms-track{position:relative;transition:transform .6s cubic-bezier(.22,.61,.36,1);will-change:transform}
.ms-ruler{display:flex;align-items:center;gap:10px;height:32px}
.ms-tick{width:1px;height:10px;background:var(--faint);flex:none;transition:background .4s,height .4s}
.ms-tick.major{height:24px;background:var(--muted-2)}
.ms-tick.active{background:var(--text);height:28px}
.ms-labels{position:relative;height:52px;margin-top:18px}
.ms-item{position:absolute;top:0;transition:opacity .5s}
.ms-item .when{color:var(--muted-2);font-size:14px;line-height:20px}
.ms-item .what{font-size:16px;line-height:24px;margin-top:2px;white-space:nowrap}
.ms-item.dim{opacity:.55}
.ms-arrows{display:flex;gap:8px;margin-top:24px}

.team{padding:32px var(--pad) 72px}
.team-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:16px}
.member img,.member .placeholder{width:100%;aspect-ratio:1;object-fit:cover;border-radius:0;background:var(--card)}
.member .placeholder{background:linear-gradient(180deg,#1c1814,#100e0c);display:flex;align-items:flex-end;justify-content:center}
.member .nm{text-align:center;font-size:14px;line-height:20px;margin-top:12px}
.member .role{text-align:center;color:var(--muted-2);font-size:12px;line-height:16px;margin-top:2px}

/* ==========================================================================
   Appear-on-enter. Measured from the source:
     initial  opacity:.001 + transform:translateY(10px)  (or none)
     easing   cubic-bezier(.12,.23,.5,1)   duration .4s   staggered delays
   ========================================================================== */
.js .appear{
  opacity:.001;
  transform:translateY(10px);
  transition:opacity .4s cubic-bezier(.12,.23,.5,1),
             transform .4s cubic-bezier(.12,.23,.5,1);
}
.js .appear.flat{transform:none}          /* fade only, no rise */
.js .appear.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .js .appear{opacity:1;transform:none;transition:none}
}

/* ==========================================================================
   Chromatic dispersion (scroll-linked). JS sets --gx per element.
   ========================================================================== */

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width:1100px){
  :root{--gutter:24px;--pad:28px}
  .nav-links{display:none}
  .header .btn-white{display:none}
  .hamburger{display:flex}
  .hero-art{display:none}
  .showcase,.stack,.testi,.faq{grid-template-columns:1fr}
  .showcase-left,.stack-left,.testi-left{border-right:none}
  .showcase-right{display:none}
  .feature-block{min-height:auto;padding:64px var(--pad)}
  .steps{grid-template-columns:1fr 1fr}
  .feat-points,.stats-grid,.footer-cols{grid-template-columns:1fr 1fr}
  .stack-left{padding:64px var(--pad) 32px}
  .stack-right{padding:0 var(--pad) 64px}
  .testi-right{min-height:340px}
  .testi-quote,.testi-attr{text-align:left;margin-left:0}
  .team-grid{grid-template-columns:1fr 1fr}
  h1{font-size:clamp(40px,7vw,72px);line-height:.92}
  .cta h2,.testi-num{font-size:clamp(36px,6vw,60px);line-height:.9}
  /* ---- Mobile menu: accordion, matching the source site ---- */
  .mobile-menu{display:block;position:fixed;inset:var(--nav-h) 0 0;z-index:95;background:var(--bg);
    transform:translateX(100%);visibility:hidden;transition:transform .3s cubic-bezier(.2,0,0,1),visibility .3s;
    overflow-y:auto;-webkit-overflow-scrolling:touch}
  .mobile-menu.open{transform:translateX(0);visibility:visible}
  .mm-panel{display:flex;flex-direction:column;min-height:100%;padding:8px 24px 32px}

  .mm-acc{border-bottom:1px solid var(--border)}
  .mm-row{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
    padding:20px 4px;background:none;border:0;text-align:left;color:var(--text);
    font-family:var(--font-body);font-size:19px;font-weight:500;line-height:1.2;cursor:pointer}
  a.mm-row{border-bottom:1px solid var(--border)}
  .mm-row .mm-chev{flex:none;color:var(--muted);transition:transform .24s cubic-bezier(.2,0,0,1)}
  .mm-acc.open > .mm-row .mm-chev{transform:rotate(180deg)}
  /* focus ring like the source: the open row is outlined */
  .mm-acc.open > .mm-row{outline:1px solid var(--border-2);outline-offset:-1px}

  .mm-drawer{display:grid;grid-template-rows:0fr;transition:grid-template-rows .3s cubic-bezier(.2,0,0,1)}
  .mm-acc.open > .mm-drawer{grid-template-rows:1fr}
  .mm-drawer-in{overflow:hidden;min-height:0}
  .mm-acc.open > .mm-drawer > .mm-drawer-in{padding-bottom:14px}

  .mm-col-label{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted-2);
    padding:14px 4px 8px}
  .mm-rich{display:flex;gap:14px;padding:12px 4px;align-items:flex-start}
  .mm-rich .ic{width:40px;height:40px;flex:none;border:1px solid var(--border-2);
    display:flex;align-items:center;justify-content:center;color:var(--text)}
  .mm-rich h4{font-family:var(--font-body);font-weight:500;font-size:15px;line-height:20px;
    letter-spacing:0;margin-bottom:2px;color:var(--text)}
  .mm-rich p{color:var(--muted);font-size:14px;line-height:20px}
  .mm-simple{display:block;padding:12px 4px;font-size:15px;color:var(--text)}
  .mm-simple:active,.mm-rich:active{background:rgba(250,250,249,.05)}

  .mm-cta{display:flex;align-items:center;justify-content:center;margin-top:28px;width:100%;height:52px;
    background:var(--white);color:#17130d;font-family:var(--font-body);font-weight:500;font-size:15px}
}
@media (max-width:620px){
  :root{--gutter:16px;--pad:20px}
  .steps,.feat-points,.stats-grid,.footer-cols,.team-grid{grid-template-columns:1fr}
  .stat .ic{margin-bottom:16px}
  .hero-body{padding-top:64px}
  .hero-cta{flex-direction:column;align-items:stretch}
  .statement{padding:64px var(--pad)}
  h2,h3{font-size:26px;line-height:29px}
  .subscribe{flex-direction:column;align-items:flex-start}
  .footer-legal{flex-direction:column;gap:8px}
}

/* Footer wordmark is now the Tall Order SVG, not clipped text */
/* The wordmark is a ground layer, not a block in the flow: pinned flush to the
   bottom of the footer, with the legal lines reading over it. The footer's
   overflow:hidden crops it to the footer box.

   Width comes from --wordmark-w on .footer, which is measured off the viewport
   so the mark is the same on the ascent page and on framed pages — see the note
   up there. It is centred rather than padded to an edge for the same reason:
   the two footers have different edges, the viewport does not. max-width is the
   guard for any container narrower than the target.

   Natural height, never contained or scaled: the footer's min-height is what
   keeps it from cropping. It used to have no min-height and got away with it
   only because the four link columns made the footer tall. With those out the
   footer fell to 293px against a 373px mark and the top 80px was cut off. Do
   not "fix" a recurrence here by shrinking the mark — make the footer taller. */
.footer-watermark{
  position:absolute;left:0;right:0;bottom:0;z-index:0;
  padding:0;margin:0;line-height:0;
  display:flex;justify-content:center;
  background:none;-webkit-text-fill-color:initial;
}
.footer-watermark img{
  width:var(--wordmark-w);max-width:100%;height:auto;display:block;
  opacity:.07;filter:brightness(0) invert(1);
}

/* ===== Consolidated Tall Order nav ===================================== */
.brand-to{display:inline-flex;align-items:center;gap:0;padding:0}
.brand-to img{height:30px;width:auto;display:block;filter:brightness(0) invert(1)}

/* Feature-card grid + a rail of plain links beneath it. Same atoms as the
   Features/Resources dropdowns, stacked so a menu can carry both. */
.dd-stack{display:flex;flex-direction:column;width:560px}
.dd-stack .dd-features{width:auto}
.dd-rail{margin-top:8px;padding-top:10px;border-top:1px solid var(--border)}
.dd-rail-links{display:grid;grid-template-columns:1fr 1fr;gap:0}

/* ==========================================================================
   IMAGE STROKE

   Every content image carries a 1px hairline. box-sizing is border-box, so the
   element keeps its size and the picture insets by a pixel — no reflow.

   Not included, deliberately: company marks and logo walls (their cell already
   has the line), the wordmark treatments (the picture reads through the type),
   and the global img reset.
   ========================================================================== */

/* portraits and people */
.tm-ph img, .pf-photo img, .tb-ph img,
.person img, .person .ph,
.member img, .member .placeholder,
.ta-id img, .ta-id .ph,
.byline img, .authorbox img, .author-row img,
.crow .au img, .entry .who img, .m-card .byline img,
.post .byline img, .b-author img, .quote .by img,
.who img, .contact-card img, .talent img,
.fdr-grid .person img.av, .fdr-why img,
.testi-right img, .cr-faces img,
/* figures, covers and thumbnails */
.psp-panel .fig img,
.hvc .fig img, .hvb-hero img, .hve-panel img,
.nw-card .ph img, .nw-row .ph img, .nw-feature img,
.wr-card .ph img, .rel-shot img, .plate img,
.ti figure img, .ti-overlay > img, .ti-band > img,
.hero-art img, .cr-hero img, .lf-hero > img,
.int-tile img, .det-art img.bg, .det-side-tile img, .int-cta .cta-art img,
.f-hero-art img,
/* the library's own */
.k-band > img, .k-cta-photo > img, .k-fig img, .k-gallery img,
.k-video img, .k-case .vis img, .k-fq .p img, .k-cta-call img,
.k-byline img, .k-author img, .k-adv img.p, .k-quote .attr img
{border:1px solid var(--border)}

/* A circular portrait takes the hairline as a ring. */
.k-cta-call img, .k-byline img, .k-author img, .k-adv img.p,
.k-quote .attr img{border-radius:0}

/* On a light ground the hairline has to be the light rule, not the dark one. */
.k-invert img, .bare-light img{border-color:var(--rule-light)}

/* One social mark in the global footer, on the site's own left edge. */
/* z-index:2 like .footer-legal. It now sits last in the flow, directly over the
   densest part of the wordmark, and a static element has no reliable paint
   order against the watermark's positioned z-index:0 layer. */
.footer-social{position:relative;z-index:2;padding:0 var(--pad) 32px}
.footer-social a{display:inline-flex;color:var(--muted-2);transition:color .18s}
.footer-social a:hover{color:var(--text)}
.footer-social svg{width:18px;height:18px;display:block}

/* ---------- News, in the footer corner ----------
   The alternative to the bar above the nav. Pinned bottom-right inside .footer
   (already position:relative for the wordmark), above the wordmark's ground
   layer. Solid surface behind it so the giant letterforms do not run through the
   text. Below 900px a pinned corner is too cramped, so it drops into the flow
   above the legal lines and goes full width. */
.footer-notice{
  position:absolute;right:var(--pad);bottom:28px;z-index:3;
  display:flex;align-items:center;gap:10px;
  max-width:min(46ch,calc(100% - (var(--pad) * 2)));
  padding:10px 12px;
  background:var(--surface);border:1px solid var(--border);
  font-size:13px;line-height:18px;color:var(--muted);
}
.footer-notice .tag{
  font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  background:var(--to-first-light,#fff695);color:#17130d;padding:3px 8px;font-weight:500;flex:none;
}
.footer-notice a{color:var(--text);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--faint)}
.footer-notice a:hover{text-decoration-color:var(--text)}
.footer-notice .close{margin-left:2px;color:var(--muted-2);font-size:15px;line-height:1;flex:none}
.footer-notice .close:hover{color:var(--text)}

/* Dismissal fades and settles rather than vanishing. The script stamped with the
   notice adds .is-dismissed, waits for the transition, then sets [hidden] so it
   leaves the layout cleanly. */
.footer-notice{transition:opacity .28s ease,transform .28s ease}
.footer-notice.is-dismissed{opacity:0;transform:translateY(8px);pointer-events:none}
@media (prefers-reduced-motion:reduce){
  .footer-notice{transition:none}
}

/* The legal stack now sits at the BOTTOM of the footer (see .footer), which
   walks the disclaimer line straight into the pinned notice's corner — at around
   1000px the notice's solid ground covered its last line. Keep the measure clear
   of the corner rather than unpinning the notice: 420px is the notice's own
   ~46ch cap plus a gap. Above roughly 1300px the 80ch measure ends well short of
   the notice anyway, so this only bites in the middle of the range. */
@media (min-width:901px){
  /* Two selectors for one row: the disclaimer follows the status chip on the v2
     pages, which still carry it, and follows the copyright line everywhere else
     now that the chip is out of chrome/footer.html. */
  .footer-status + .footer-legal,
  .footer-legal + .footer-legal{padding-right:calc(var(--pad) + 420px)}
}

@media (max-width:900px){
  /* In the flow above the legal lines, but still hugging its contents — the tag,
     the headline and the dismiss button. Stretched to the full footer column it
     read as a band rather than a notice. No 46ch measure here, unlike the pinned
     desktop corner: the point is to sit on one line where there is room for one,
     and the column is the only cap it needs. */
  .footer-notice{
    position:static;right:auto;bottom:auto;
    margin:0 var(--pad) 24px;
    width:fit-content;
    max-width:calc(100% - (var(--pad) * 2));
  }
}

/* ---------- Status chip, in the footer ----------
   The pattern taken from the reference: a small chip carrying a live dot and a
   label, sat on the site's own left edge above the legal lines.

   Two deliberate departures. The chip has square corners where the reference
   pill is fully rounded, because this site does not do radius; and the dot is
   First Light, not a status green, because one colour is the whole palette. That
   makes the dot the only round thing in the footer — at 6px a square mark reads
   as a swatch rather than a light, so it earns the exception.

   The pulse is a ring, not a throb: the dot's ::after starts sat exactly on top
   of it and scales out while it fades, so the dot itself never moves and one
   keyframe sets the whole pace. Same curve as the page transition. Held still
   under prefers-reduced-motion, like the grain and the notice dismissal. */
/* Right-aligned, so it lands under the legal-link group in the legal row above
   rather than under the copyright line. Same --pad inset, so its right edge and
   the "Privacy" link's right edge are the same edge.

   z-index:2 for the same reason as .footer-social: it sits under the legal lines
   now, over the wordmark, and a static element has no reliable paint order
   against the watermark's positioned z-index:0 layer. */
.footer-status{position:relative;z-index:2;padding:0 var(--pad) 10px;
  display:flex;justify-content:flex-end}
.fs-pill{
  display:inline-flex;align-items:center;gap:10px;
  padding:9px 12px;
  background:var(--surface);border:1px solid var(--border);
  font-size:12px;line-height:16px;font-weight:500;color:var(--text);
}
.fs-dot{
  position:relative;flex:none;width:6px;height:6px;
  border-radius:50%;background:var(--accent);
}
.fs-dot::after{
  content:"";position:absolute;inset:0;
  border-radius:50%;background:var(--accent);
  animation:fs-pulse 2s cubic-bezier(.12,.23,.5,1) infinite;
}
@keyframes fs-pulse{
  0%      {transform:scale(1);opacity:.5}
  70%,100%{transform:scale(2.8);opacity:0}
}
@media (prefers-reduced-motion:reduce){
  .fs-dot::after{animation:none;opacity:0}
}
