/* Fusion — visual foundation.
 *
 * Rebuilt against a premium-design pass. Three things were making it read as generic:
 * Inter everywhere, flat 1px grey borders, and motion on linear easing. All three are gone.
 *
 * Hairlines are white at low alpha rather than a grey hex, so a border catches the light of
 * whatever is behind it instead of sitting on top as a drawn line. Every raised surface gets
 * an inset top highlight, which is what makes a panel read as a physical object with an edge
 * rather than a coloured rectangle.
 */

:root {
  --bg:        #050509;
  --panel:     #0c0c14;
  --panel-2:   #101019;
  --raised:    #14141f;

  /* Hairlines and highlights, not borders. */
  --line:      rgba(255,255,255,.055);
  --line-2:    rgba(255,255,255,.10);
  --line-3:    rgba(255,255,255,.16);
  --sheen:     inset 0 1px 0 rgba(255,255,255,.06);
  --sheen-2:   inset 0 1px 0 rgba(255,255,255,.10);

  /* Washes: a surface lifted by tinting toward the light rather than by a new colour.
     Three steps — resting, hover, selected. Every one of these used to be a literal
     rgba(255,255,255,...) written inline, at eleven different alphas that were meant to be
     three. Naming them is what makes a light theme possible at all: on white the lift has
     to run the other way, toward the ink. */
  --wash-1:    rgba(255,255,255,.028);
  --wash-2:    rgba(255,255,255,.042);
  --wash-3:    rgba(255,255,255,.075);
  /* A white that has to stay white: the arrow's disc inside the primary CTA, which sits on
     the gradient in both themes and is not a surface. */
  --on-grad:   rgba(255,255,255,.16);
  --on-grad-2: rgba(255,255,255,.24);
  /* Marks drawn into the hero and how-it-works artwork. */
  --ink-soft:  rgba(255,255,255,.30);
  --ink-faint: rgba(255,255,255,.05);

  --glass:     rgba(12,12,20,.72);
  --shadow-nav:   0 12px 40px -18px rgba(0,0,0,.9);
  --shadow-card:  0 24px 60px -34px rgba(0,0,0,.95);
  --shadow-toast: 0 10px 40px rgba(0,0,0,.5);

  /* The two light sources behind the page, and how much grain sits over them. */
  --mesh-a:    rgba(124,92,255,.15);
  --mesh-b:    rgba(34,211,238,.075);
  --grain:     .16;

  --ring-accent: rgba(167,139,250,.28);

  /* Artwork. Held apart from the brand colours because these are read at 2px stroke widths
     over a full-bleed ground rather than as text or fills, and the two grounds want
     genuinely different values — not the same value at a different opacity. A halo tuned to
     bloom against #050509 is invisible against #f6f6fa, which is exactly what the first
     version did.

     --art-1/2/3 are the flow, left to right. --art-ink is structure, --art-ink-2 is the
     platform's own 20% line: deliberately the quietest thing on the page. */
  --art-1:      #8b6cff;
  --art-2:      #c558f0;
  --art-3:      #22d3ee;
  --art-glow-1: rgba(139,108,255,.50);
  --art-glow-2: rgba(124,92,255,.13);
  --art-ink:    rgba(255,255,255,.13);
  --art-ink-2:  rgba(255,255,255,.24);
  --art-face:   #0e0e18;
  /* Bodies. Two stops each, lit from up and to the left — the same direction the panels'
     inset sheen implies, so the artwork and the chrome agree about where the light is. */
  --art-body-1: #2a2158;
  --art-body-2: #0c0b18;
  --art-dead-1: #4a2333;
  --art-dead-2: #16101a;
  --art-face-1: #1a1a28;
  --art-face-2: #0d0d16;
  --art-cell-2: rgba(251,113,133,.55);

  --text:      #f2f2f7;
  --muted:     #8e8ea6;
  /* 4.5:1 on every surface here. The previous #5c5c74 measured 3.14:1 and was used
     exclusively on 10-13px text, so the large-text exemption never applied. */
  --muted-2:   #7d7d99;

  --violet:    #7c5cff;
  --magenta:   #c558f0;
  --cyan:      #22d3ee;
  --accent:    #a78bfa;

  --up:        #34d399;
  --down:      #fb7185;
  --warn:      #fbbf24;

  --grad: linear-gradient(100deg, var(--violet) 0%, var(--magenta) 48%, var(--cyan) 100%);
  /* The same arc, darkened until white text clears 4.5:1 across the whole run. The display
     gradient stays bright; only surfaces carrying text use this one. */
  --grad-btn: linear-gradient(100deg, #5b3fd6 0%, #9b3fc4 50%, #1c7f96 100%);
  --grad-soft: linear-gradient(100deg, rgba(124,92,255,.14), rgba(197,88,240,.10) 50%, rgba(34,211,238,.12));

  /* One easing for everything, with real mass to it. Nothing here is linear or ease-in-out. */
  --ease: cubic-bezier(.32,.72,0,1);
  --ease-soft: cubic-bezier(.4,.14,.3,1);

  --r-sm: 12px;
  --r:    18px;
  --r-lg: 26px;
  --maxw: 1240px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 14px/1.55 Geist, "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "ss01", "cv01";
  /* Every figure in this product sits in a column beside another figure. */
  font-variant-numeric: tabular-nums;
}

/* Two very large, very soft light sources. Fixed and non-interactive, so they never repaint
   with scroll. */
body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background:
    radial-gradient(1100px 620px at 76% -14%, var(--mesh-a), transparent 60%),
    radial-gradient(880px 540px at 8% 2%, var(--mesh-b), transparent 58%);
}
/* A trace of grain, so flat black surfaces have texture under the light. */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 1; opacity: var(--grain);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
h1,h2,h3,h4 { margin: 0; line-height: 1.08; letter-spacing: -.03em; font-weight: 650; }
.mono { font-family: "Geist Mono", ui-monospace, monospace; font-feature-settings: "zero"; }
.muted { color: var(--muted); }
.grow { flex: 1; }
.up { color: var(--up); }
.down { color: var(--down); }

/* An eyebrow, not a badge. Tiny, wide-tracked, quiet. */
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 10px; font-weight: 500; letter-spacing: .18em; text-transform: uppercase;
  color: var(--muted); background: var(--wash-1);
  border: 1px solid var(--line); box-shadow: var(--sheen);
  padding: 7px 14px; border-radius: 999px;
}
.pill .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--up); box-shadow: 0 0 10px var(--up); }

/* ---------- the nav island ----------
   Was a full-width bar with the brand pinned to one edge and the buttons to the other, which
   on a wide screen leaves them a metre apart. Now one detached pill, only as wide as its
   contents, floating clear of the top. */
.topbar { position: sticky; top: 0; z-index: 40; padding: 14px 20px 0; }
.topbar-inner {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 7px 7px 7px 16px; border-radius: 999px;
  background: var(--glass);
  backdrop-filter: blur(20px) saturate(150%);
  border: 1px solid var(--line);
  box-shadow: var(--sheen), var(--shadow-nav);
}

.brand { display: flex; align-items: center; gap: 9px; font-weight: 600; letter-spacing: -.02em; font-size: 15px; }
.brand-mark {
  width: 22px; height: 22px; border-radius: 50%; position: relative;
  background: conic-gradient(from 210deg, var(--violet), var(--magenta), var(--cyan), var(--violet));
  box-shadow: 0 0 18px -2px rgba(124,92,255,.7);
}
.brand-mark::after { content: ""; position: absolute; inset: 6px; border-radius: 50%; background: var(--bg); }
.brand-mark.small { width: 16px; height: 16px; }
.brand-mark.small::after { inset: 4.5px; }

.nav { display: flex; gap: 2px; margin-left: 14px; }
.nav a {
  padding: 7px 13px; border-radius: 999px; color: var(--muted);
  font-weight: 500; font-size: 13.5px; white-space: nowrap;
  transition: color .4s var(--ease), background .4s var(--ease);
}
.nav a:hover { color: var(--text); background: var(--wash-2); }
.nav a.active { color: var(--text); background: var(--wash-3); box-shadow: var(--sheen); }

.topbar-right { display: flex; align-items: center; gap: 8px; margin-left: auto; }
/* The collapsed control. Wide enough to read as a search field rather than an icon button,
   because the shortcut badge is the only thing that teaches the shortcut. */
.searchbtn {
  display: flex; align-items: center; gap: 9px; padding: 7px 8px 7px 13px;
  border-radius: 999px; cursor: pointer;
  background: var(--wash-1); border: 1px solid var(--line); color: var(--muted-2);
  font-size: 13px; min-width: 216px;
  transition: border-color .4s var(--ease), background .4s var(--ease), color .4s var(--ease);
}
.searchbtn:hover { border-color: var(--line-3); background: var(--wash-2); color: var(--text); }
.searchbtn span { flex: 1; text-align: left; }
.kbd {
  font: 500 10.5px/1 "Geist Mono", ui-monospace, monospace; letter-spacing: .04em;
  color: var(--muted-2); background: var(--wash-2); border: 1px solid var(--line);
  border-radius: 6px; padding: 4px 6px; display: inline-flex; gap: 1px; align-items: center;
}

/* ---------- search palette ----------
   A dialog, not a dropdown: the filters and the pager need the room, and a list this long
   under a nav pill would be a scrolling tooltip. */
/* The `hidden` attribute is a UA style at [hidden] — one attribute, specificity 0,1,0 — so
   any class rule setting `display` silently outranks it and the element is never hidden at
   all. The palette shipped open across the whole page for exactly that reason. Stated for
   every element rather than just this one, because the next thing to use `hidden` will hit
   the same wall and there will be nothing to warn it. */
[hidden] { display: none !important; }

.palette { position: fixed; inset: 0; z-index: 100; display: grid; }
.palette-scrim {
  position: absolute; inset: 0; background: rgba(4,4,10,.62);
  backdrop-filter: blur(3px);
  animation: palFade .28s var(--ease) both;
}
.palette-box {
  position: relative; z-index: 1;
  width: min(680px, calc(100vw - 32px));
  /* Not centred. A palette pinned near the top keeps the result list in the same place as it
     grows and shrinks; centred, every keystroke moves the row under the cursor. */
  margin: min(11vh, 92px) auto auto;
  max-height: min(74vh, 720px); display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--r-lg);
  box-shadow: var(--sheen), var(--shadow-card);
  overflow: hidden;
  animation: palRise .34s var(--ease) both;
}
@keyframes palFade { from { opacity: 0 } to { opacity: 1 } }
@keyframes palRise { from { opacity: 0; transform: translateY(-10px) scale(.985) } to { opacity: 1; transform: none } }

.palette-head {
  display: flex; align-items: center; gap: 12px; padding: 16px 16px 14px 20px;
  border-bottom: 1px solid var(--line);
}
.palette-head .i { color: var(--muted-2); flex: none; }
.palette-head input {
  flex: 1; background: none; border: 0; color: var(--text); font-size: 16px; padding: 2px 0;
}
.palette-head input::placeholder { color: var(--muted-2); }
.palette-head input:focus { outline: none; }
.palette-x {
  width: 30px; height: 30px; border: 0; border-radius: 50%; background: none; cursor: pointer;
  color: var(--muted-2); display: grid; place-items: center; flex: none;
  transition: background .4s var(--ease), color .4s var(--ease);
}
.palette-x:hover { background: var(--wash-2); color: var(--text); }

.palette-filters { padding: 12px 18px; border-bottom: 1px solid var(--line); display: grid; gap: 7px; }
.pf-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pf-k { font-size: 11.5px; color: var(--muted-2); width: 62px; flex: none; }
.pf-row .chip { padding: 4px 11px; font-size: 12px; }

.palette-results { overflow-y: auto; padding: 8px; flex: 1; min-height: 120px; }
.pr {
  display: flex; align-items: center; gap: 12px; padding: 9px 11px; border-radius: var(--r-sm);
  border: 1px solid transparent; cursor: pointer;
}
.pr.on { background: var(--wash-2); border-color: var(--line-2); }
.pr-id { flex: 1; min-width: 0; }
.pr-name { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pr-sub { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 4px; }
.pr-go { color: var(--muted-2); opacity: 0; transition: opacity .3s var(--ease); flex: none; }
.pr.on .pr-go { opacity: 1; }
.pr-empty { padding: 34px 20px; text-align: center; }
.pr-empty p { margin: 0 0 6px; }

.palette-foot {
  display: flex; align-items: center; gap: 10px; padding: 11px 16px;
  border-top: 1px solid var(--line); font-size: 12.5px; background: var(--wash-1);
}
.palette-foot .chip { padding: 4px 12px; font-size: 12px; }

@media (max-width: 720px) {
  .searchbtn { min-width: 0; }
  .searchbtn span, .kbd { display: none; }
  .palette-box { margin-top: 6vh; max-height: 86vh; }
  .pf-k { width: 100%; }
}

/* ---------- buttons ----------
   Pills with real press physics. The primary CTA carries its arrow in its own nested circle
   flush to the inner edge, which moves independently on hover. */
.btn {
  border: 0; border-radius: 999px; padding: 9px 16px; cursor: pointer; white-space: nowrap;
  font-weight: 550; font-size: 13.5px; letter-spacing: -.01em;
  display: inline-flex; align-items: center; gap: 9px;
  transition: transform .45s var(--ease), filter .45s var(--ease), background .45s var(--ease), border-color .45s var(--ease);
}
.btn:active { transform: scale(.975); }
.btn-primary { background: var(--grad-btn); color: #fff; box-shadow: 0 8px 26px -10px rgba(124,92,255,.85), var(--sheen-2); padding-right: 7px; }
.btn-primary:hover { filter: brightness(1.08) saturate(1.05); }
.btn-primary .ico {
  width: 26px; height: 26px; border-radius: 50%; background: var(--on-grad);
  display: grid; place-items: center;
  transition: transform .45s var(--ease), background .45s var(--ease);
}
.btn-primary .ico .i { vertical-align: 0; }
.btn-primary:hover .ico { transform: translate(2px, -1px) scale(1.06); background: var(--on-grad-2); }
.btn-ghost { background: var(--wash-1); border: 1px solid var(--line-2); box-shadow: var(--sheen); }
.btn-ghost:hover { background: var(--wash-2); border-color: var(--line-3); }
.btn-sm { padding: 6px 13px; font-size: 12.5px; }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn:disabled:active { transform: none; }

/* ---------- layout ---------- */
.view { position: relative; z-index: 2; max-width: var(--maxw); margin: 0 auto; padding: 40px 20px 110px; }

/* Every raised surface: hairline, sheen, deep soft shadow. Never a flat grey box. */
.panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--sheen), var(--shadow-card);
}

.section-head { display: flex; align-items: baseline; gap: 14px; margin: 76px 0 22px; }
.section-head h2 { font-size: 27px; letter-spacing: -.035em; }
.section-head .muted { font-size: 13px; }

@media (max-width: 1000px) {
  .topbar-inner { flex-wrap: wrap; border-radius: var(--r-lg); padding: 10px 12px; }
  .nav { order: 3; width: 100%; margin: 6px 0 0; overflow-x: auto; }
  .search { display: none; }
  .view { padding: 28px 16px 80px; }
  .section-head { margin: 52px 0 18px; }
}

/* ---------- hero ----------
   Slow, heavy, abstract. A 12-second cycle on custom easing; nothing animates a layout
   property. The stage timers are long on purpose — quick loops read as busy, and busy reads
   as cheap. */
.hero {
  display: grid; grid-template-columns: 1.04fr .96fr; gap: 56px; align-items: center;
  padding: 56px 0 26px; min-height: 460px;
}
.hero-copy > * { animation: heroRise .95s var(--ease) both; }
.hero-copy > .pill { animation-delay: .02s; }
.hero-copy > h1 { animation-delay: .09s; }
.hero-copy > p { animation-delay: .16s; }
.hero-copy > .hero-cta { animation-delay: .23s; }
.hero-copy > .hero-dots { animation-delay: .3s; }
.hero-stage { animation: heroFade 1.5s var(--ease-soft) both; }
@keyframes heroRise { from { opacity: 0; transform: translateY(20px); filter: blur(7px); } to { opacity: 1; transform: none; filter: none; } }
@keyframes heroFade { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }

.hero h1 {
  font-size: clamp(38px, 5.1vw, 66px); font-weight: 620; margin: 22px 0 0;
  letter-spacing: -.045em; line-height: 1.02;
}
.hero h1 .g {
  background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero p { color: var(--muted); font-size: 15.5px; line-height: 1.65; max-width: 50ch; margin: 22px 0 32px; }
.hero-cta { display: flex; gap: 11px; flex-wrap: wrap; }

.hero-dots { display: flex; gap: 10px; margin-top: 40px; }
.hero-dot { background: none; border: 0; padding: 6px 0; cursor: pointer; }
.hero-dot i { display: block; width: 34px; height: 2px; border-radius: 2px; background: var(--line-3); transition: all .7s var(--ease); }
.hero-dot:hover i { background: var(--ink-soft); }
.hero-dot.on i { width: 56px; background: var(--grad); box-shadow: 0 0 14px -2px rgba(124,92,255,.9); }

.hero-svg { width: 100%; max-width: 470px; display: block; margin-inline: auto; overflow: visible; }

/* --- 1. fuse: small dead coins are eaten, and the survivor grows ---
   The cells arrive on a schedule and the core steps up to meet each one. Both timings are
   written once in hero.js and mirrored in the keyframes below; if you move one, move both. */
.hf-cell {
  offset-rotate: 0deg;
  /* Infinite, not one-shot. The growth story finishes in the first nine seconds, but the
     stage is on screen for twelve and the survivor is supposed to look like it is still
     eating — a one-shot left a small ring sitting alone for the last three. */
  animation: hfFeed 2.6s var(--ease) infinite both;
  transform-box: fill-box; transform-origin: center;
}
.hf-cell-ring { fill: none; stroke: var(--art-cell-2); stroke-width: 1.4; }
@keyframes hfFeed {
  0%   { offset-distance: 0%;   opacity: 0; transform: scale(.7) }
  12%  { opacity: 1;            transform: scale(1) }
  /* Full size right up to the rim, then dissolving across the last third of the run. The
     dissolve is what reads as being engulfed; without it a cell simply slid under the body
     and stopped. */
  68%  { offset-distance: 76%;  opacity: 1; transform: scale(1) }
  100% { offset-distance: 100%; opacity: 0; transform: scale(.12) }
}

/* Nine steps, each a small overshoot that settles — the visual equivalent of a swallow.
   The percentages are the cell landing times over an 11s run: 1.0s = 9%, 1.9s = 17%, and
   so on. It never steps back down, because the whole claim is that the growth is kept. */
.hf-core { transform-box: fill-box; transform-origin: center; animation: hfGrow 11s both; }
@keyframes hfGrow {
  0%        { transform: scale(.30); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  9%        { transform: scale(.38); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  17%       { transform: scale(.46); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  25%       { transform: scale(.53); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  34%       { transform: scale(.61); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  41%       { transform: scale(.68); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  48%       { transform: scale(.75); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  56%       { transform: scale(.82); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  64%       { transform: scale(.88); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  72%       { transform: scale(.94); animation-timing-function: cubic-bezier(.2,1.6,.4,1) }
  80%, 100% { transform: scale(1) }
}
.hf-halo { transform-box: fill-box; transform-origin: center; animation: artBreathe 7s var(--ease-soft) infinite; }
@keyframes artBreathe { 0%,100% { opacity: .8; transform: scale(1) } 50% { opacity: 1; transform: scale(1.05) } }

/* --- 2. pair: a ring of anchors, seen at an angle --- */
.hp-track { stroke-width: 1; stroke-dasharray: 3 7; opacity: .8; }
.hp-sat {
  offset-rotate: 0deg;
  /* Linear is correct here and nowhere else in this file. Any easing on a continuous
     rotation produces a visible hitch at the loop point, every loop. */
  animation: hpOrbit 34s linear infinite;
}
@keyframes hpOrbit { to { offset-distance: 100% } }

/* Depth. Shares the orbit's phase, so a satellite is small and faint across the back of the
   sweep and large and solid across the front. This is the difference between a ring and a
   circle of dots. */
.hp-depth {
  transform-box: fill-box; transform-origin: center;
  animation: hpDepth 34s linear infinite;
}
@keyframes hpDepth {
  0%   { transform: scale(.66); opacity: .42 }
  50%  { transform: scale(1.06); opacity: 1 }
  100% { transform: scale(.66); opacity: .42 }
}
.hp-face { fill: var(--art-face); }
.hp-ring { fill: none; stroke: var(--art-ink-2); stroke-width: 1.3; }
.hp-t {
  fill: var(--muted); font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 10.5px; font-weight: 500; text-anchor: middle; letter-spacing: -.03em;
}
.hp-halo { transform-box: fill-box; transform-origin: center; animation: artBreathe 8s var(--ease-soft) infinite; }
/* One ring leaving the core on each pass — the coin the ring is around is the live one. */
.hp-ping { transform-box: fill-box; transform-origin: center; animation: hpPing 4.2s var(--ease-soft) infinite; }
@keyframes hpPing {
  0%   { transform: scale(1); opacity: .7 }
  70%, 100% { transform: scale(2.1); opacity: 0 }
}

/* --- 3. split: 80 one way, 20 the other --- */
.hs-draw { stroke-dasharray: 460; stroke-dashoffset: 460; animation: hsDraw 1.6s var(--ease) both; }
.hs-small { animation-delay: .3s; }
@keyframes hsDraw { to { stroke-dashoffset: 0 } }
.hs-dot { fill: var(--art-1); animation-name: hsRun; animation-timing-function: linear; animation-iteration-count: infinite; offset-rotate: 0deg; }
.hs-dim { fill: var(--art-ink-2); r: 2.4; }
@keyframes hsRun { 0% { offset-distance: 0%; opacity: 0 } 12% { opacity: 1 } 86% { opacity: 1 } 100% { offset-distance: 100%; opacity: 0 } }
.hs-src { animation: heroFade 1s var(--ease) both; }
.hs-end { animation: hsLand .9s var(--ease) both; }
.hs-end-big { animation-delay: 1.1s; }
.hs-end-small { animation-delay: 1.35s; }
@keyframes hsLand { from { opacity: 0; transform: scale(.7) } to { opacity: 1; transform: none } }
.hs-end { transform-box: fill-box; transform-origin: center; }
.hs-n {
  fill: var(--text); text-anchor: middle; font-weight: 700; font-size: 15px;
  letter-spacing: -.03em;
}
.hs-n-sm { font-size: 11px; fill: var(--muted); }

@media (max-width: 1000px) {
  .hero { grid-template-columns: 1fr; gap: 30px; padding: 28px 0 10px; min-height: 0; }
  .hero-svg { max-width: 330px; }
  .hero-dots { margin-top: 26px; }
}
@media (prefers-reduced-motion: reduce) {
  /* Everything settles at its finished state rather than its starting one: the core at full
     size, the lines drawn, the ring where it stands. A reduced-motion reader should get the
     final frame, not an empty stage. */
  .hero-copy > *, .hero-stage, .hf-cell, .hf-halo, .hp-sat, .hp-depth, .hp-halo, .hp-ping,
  .hs-draw, .hs-src, .hs-end, .hs-dot {
    animation: none !important; opacity: 1 !important; transform: none !important;
    stroke-dashoffset: 0 !important;
  }
  .hf-cell { opacity: 0 !important; }
  .hf-core { animation: none !important; transform: scale(1) !important; }
  .hp-depth { transform: scale(.9) !important; }
  .hp-ping { opacity: 0 !important; }
}

/* ---------- stat strip ---------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px,1fr)); gap: 12px; margin-top: 20px; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 15px 17px; }
.stat .k { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .07em; }
.stat .v { font-size: 22px; font-weight: 700; margin-top: 5px; letter-spacing: -.02em; }

/* ---------- fee flow ----------
   Static, deliberately. The animated version buried the numbers, and the numbers are the whole
   point here: this is a receipt, not a diagram. */
.flow { padding: 30px 32px; margin-top: 34px; }
.flow-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 26px; flex-wrap: wrap; gap: 8px; }
.flow-head strong { font-weight: 600; letter-spacing: -.02em; }
.flow-grid { display: grid; grid-template-columns: 236px 1fr 1.15fr; gap: 30px; align-items: center; }

.flow-total {
  background: var(--panel-2); border: 1px solid var(--line-2); border-radius: var(--r);
  padding: 22px; box-shadow: var(--sheen-2);
}
.flow-total .v { font-size: 32px; font-weight: 650; letter-spacing: -.04em; }
.flow-total .k { font-size: 10.5px; color: var(--muted-2); text-transform: uppercase; letter-spacing: .12em; margin-top: 7px; }

.flow-split { display: grid; gap: 9px; }
.flow-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: var(--wash-1); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 14px 16px; box-shadow: var(--sheen);
  transition: background .5s var(--ease), border-color .5s var(--ease);
}
.flow-row:hover { background: var(--wash-2); border-color: var(--line-2); }
.flow-row .lbl { display: flex; align-items: baseline; gap: 10px; font-size: 13.5px; }
.flow-row .bul { width: 6px; height: 6px; border-radius: 50%; flex: none; align-self: center; }
.flow-row .note { font-size: 11px; color: var(--muted-2); }
.flow-row .pct { font-size: 11px; color: var(--muted-2); font-weight: 500; margin-left: 6px; }
.flow-row b { font-weight: 600; letter-spacing: -.02em; }

@media (max-width: 1000px) {
  .flow { padding: 20px; }
  .flow-grid { grid-template-columns: 1fr; gap: 16px; }
}

/* ---------- coin grid ----------
   Four across, deliberately: StonkFun runs three, and the extra column is what lets us carry
   the full metric set without the grid feeling sparse. Steps down rather than reflowing by
   min-width, so the count is predictable at every size. */
.coin-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 13px; }
@media (max-width: 1240px) { .coin-grid { grid-template-columns: repeat(3, minmax(0,1fr)); } }
@media (max-width: 940px)  { .coin-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 620px)  { .coin-grid { grid-template-columns: 1fr; } }

.filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 16px; }
.chip { background: var(--panel); border: 1px solid var(--line); color: var(--muted); border-radius: 999px; padding: 7px 14px; font-size: 13px; font-weight: 500; cursor: pointer; }
.chip:hover { color: var(--text); }
/* Matches .nav a.active. A solid fill is reserved for the primary CTA; a filter chip
   must not outrank it. */
.chip.active { background: var(--wash-3); color: var(--text); border-color: var(--line-3); box-shadow: var(--sheen); font-weight: 600; }
.sortbar { display: flex; gap: 6px; align-items: center; margin-left: auto; font-size: 13px; }
.sortbar .chip { padding: 6px 12px; }

.coin-card {
  position: relative; overflow: hidden;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 17px 18px 16px; cursor: pointer; transition: .18s;
  display: flex; flex-direction: column;
}
.coin-card:hover { border-color: var(--line-2); transform: translateY(-2px); }

/* The pair's mark: large, half off the right edge, ringed. This is the one element that makes
   a card readable before you read any of it — you see what a coin trades against first. */
.pair-mark {
  position: absolute; right: -30px; top: -28px;
  width: 116px; height: 116px; border-radius: 50%;
  background: linear-gradient(150deg, var(--pm), var(--pm2));
  display: grid; place-items: center;
  opacity: .17; filter: blur(.2px);
  pointer-events: none; transition: opacity .5s var(--ease), transform .5s var(--ease);
}
/* The mark is a watermark, so it carries no text — the pair is named in the tag row where it
   can actually be read. */
.pair-mark span { display: none; }
.coin-card:hover .pair-mark { opacity: .26; transform: scale(1.05); }

.coin-top { display: flex; align-items: center; gap: 11px; position: relative; z-index: 1; }
.avatar { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; font-weight: 800; font-size: 13px; color: #fff; flex: none; }
.coin-id { min-width: 0; }
.coin-id .tick { font-weight: 700; font-size: 14px; color: var(--cyan); }
.coin-id .nm { color: var(--muted); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.coin-mc { font-size: 30px; font-weight: 800; letter-spacing: -.035em; margin: 15px 0 1px; position: relative; z-index: 1; }
.coin-mc-label { font-size: 11px; color: var(--muted-2); text-transform: uppercase; letter-spacing: .07em; margin-bottom: 13px; position: relative; z-index: 1; }

.tags { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; position: relative; z-index: 1; }
.tag { font-size: 11px; font-weight: 600; padding: 4px 9px; border-radius: 999px; border: 1px solid var(--line-2); color: var(--muted); background: var(--panel-2); }
.tag.pair { color: var(--text); border-color: var(--line-2); }
.tag.pair b { color: var(--cyan); }
.tag.mod { color: var(--accent); border-color: var(--ring-accent); }
.tag.grad { color: var(--up); border-color: rgba(52,211,153,.3); }

.coin-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 7px 14px; padding-top: 13px; border-top: 1px solid var(--line); font-size: 12.5px; position: relative; z-index: 1; }
.metric { display: flex; justify-content: space-between; gap: 8px; }
.metric .k { color: var(--muted); }
.metric .v { font-weight: 600; }
.coin-trade { margin-top: 14px; align-self: flex-start; position: relative; z-index: 1; }

/* ---------- graveyard ---------- */
.gy-hero { padding: 30px 32px; background: var(--grad-soft); border: 1px solid var(--line-2); border-radius: var(--r-lg); }
.gy-hero h1 { font-size: 38px; font-weight: 800; }
.gy-hero p { color: var(--muted); max-width: 68ch; margin: 14px 0 0; }
.gy-bar { display: flex; height: 12px; border-radius: 999px; overflow: hidden; margin: 22px 0 10px; background: var(--panel-2); }
.gy-bar i { display: block; height: 100%; }
.gy-legend { display: flex; gap: 20px; flex-wrap: wrap; font-size: 12.5px; color: var(--muted); }
.gy-legend b { color: var(--text); }
.gy-legend .sw { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 7px; }

.gy-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px,1fr)); gap: 13px; }
.gy-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 15px 16px; display: flex; flex-direction: column; gap: 11px; }
/* Not opacity: it took the 12px meta text to 2.62:1. The badge already carries the
   meaning, so the card just loses its accent instead. */
.gy-card.locked { border-color: var(--line); background: var(--panel); }
.gy-card.locked .gy-trapped { color: var(--muted); }
.gy-top { display: flex; align-items: center; gap: 10px; }
.gy-trapped { font-size: 23px; font-weight: 800; letter-spacing: -.02em; }
.gy-meta { display: grid; gap: 5px; font-size: 12px; }
.gy-meta .row { display: flex; justify-content: space-between; gap: 10px; }
.gy-meta .row .k { color: var(--muted); }
.badge { font-size: 10.5px; font-weight: 700; padding: 3px 8px; border-radius: 999px; letter-spacing: .03em; text-transform: uppercase; }
/* The one tier the graveyard never shows, because a coin too young to fuse is not in it.
   Quiet on purpose: "nobody can take this yet" is the resting state, not an alert. */
.badge.young { background: var(--wash-2); color: var(--muted); }
.badge.dead  { background: rgba(52,211,153,.14); color: var(--up); }
.badge.stale { background: rgba(251,191,36,.14); color: var(--warn); }
.badge.idle  { background: rgba(167,139,250,.14); color: var(--accent); }
.badge.lock  { background: rgba(251,113,133,.13); color: var(--down); }

/* ---------- launch studio ----------
   Progress across the top, form and live preview beneath. The preview is the real coin card,
   so what you watch while filling the form is exactly what lands on the board. */
.studio { display: block; }

.rail-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 18px; }
.rail-head h2 { font-size: 27px; font-weight: 800; }
.rail-head .muted { font-size: 13px; }

.rail-track {
  position: relative; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 6px; margin-bottom: 26px; padding-top: 22px;
}
/* The track itself, and the gradient that fills it as you advance.

   Both sit behind the steps. ::after is the last child of .rail-track, so with everything
   at the default z-index it painted last — the gradient ran straight across the face of
   every dot it had already reached, putting the line over the tick instead of the tick over
   the line. */
.rail-track::before, .rail-track::after {
  content: ""; position: absolute; top: 10px; height: 2px; border-radius: 2px;
  left: 6%; right: 6%; z-index: 0;
}
.rail-track::before { background: var(--line); }
.rail-track::after { right: auto; width: calc((100% - 12%) * var(--done, 0%) / 100%); background: var(--grad); transition: width .4s cubic-bezier(.2,.7,.3,1); }

.rail-step {
  position: relative; z-index: 1; background: none; border: 0; cursor: pointer; padding: 0;
  display: grid; justify-items: center; gap: 2px; text-align: center;
}
/* An opaque fill, not a translucent one. The track passes behind every dot, so anything
   see-through here puts a 2px line through the middle of the mark. */
.rail-step .dot {
  position: absolute; top: -22px; width: 22px; height: 22px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--line); color: var(--muted-2);
  display: grid; place-items: center; font-size: 11px; font-weight: 700;
  transition: background .25s, border-color .25s, color .25s, box-shadow .25s;
}
.rail-step .lbl { margin-top: 8px; font-size: 13.5px; font-weight: 600; color: var(--muted); transition: .2s; }
.rail-step .sub { font-size: 11px; color: var(--muted-2); }
.rail-step:hover .lbl { color: var(--text); }
/* Done is solid. A hollow outline reads as in-progress, which is the opposite of what it
   is trying to say. */
.rail-step.done .dot {
  background: var(--accent); border-color: transparent; color: #0b0a14;
  font-weight: 700; box-shadow: 0 0 18px -6px var(--accent), var(--sheen-2);
}
/* A tick drawn at 2.3 on a 24-grid, shrunk into a 22px dot, would otherwise sit on
   the text baseline rather than the centre of the circle. */
.rail-step.done .dot .i { vertical-align: 0; }
.rail-step.done .lbl { color: var(--muted); }
.rail-step.active .dot { background: var(--grad-btn); border-color: transparent; color: #fff; box-shadow: 0 0 0 5px rgba(124,92,255,.14); }
.rail-step.active .lbl { color: var(--text); }

.studio-body { display: grid; grid-template-columns: 1fr 372px; gap: 24px; align-items: start; }

/* The column is a layout, not a surface — the cards inside it are the surfaces.
   A bordered panel here wrapped a card of the same radius and produced a double frame. */
.preview { position: sticky; top: 82px; display: grid; gap: 14px; align-content: start; }
.preview-cap { font-size: 11px; color: var(--muted-2); text-transform: uppercase; letter-spacing: .08em; }
/* The preview card is the real component, so it must not behave like a clickable market card. */
.preview .coin-card { cursor: default; }
.preview .coin-card:hover { transform: none; border-color: var(--line); }
.preview .coin-trade { display: none; }

.preview-rows { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 14px 16px; display: grid; gap: 8px; font-size: 13px; }
.preview-rows .r { display: flex; justify-content: space-between; gap: 10px; }
.preview-rows .r .k { color: var(--muted); }
.preview-rows .r .v { font-weight: 600; }
.preview-rows .r.head { border-bottom: 1px solid var(--line); padding-bottom: 8px; margin-bottom: 2px; }
.preview-rows .r.head .k, .preview-rows .r.head .v { color: var(--text); font-weight: 700; }

@media (max-width: 1080px) {
  .studio-body { grid-template-columns: 1fr; }
  .preview { position: static; }
  .rail-track { grid-auto-flow: row; grid-auto-columns: auto; gap: 14px; padding-top: 0; }
  .rail-track::before, .rail-track::after { display: none; }
  .rail-step { grid-template-columns: 30px 1fr; justify-items: start; text-align: left; }
  .rail-step .dot { position: static; grid-row: span 2; }
  .rail-step .lbl { margin-top: 0; }
}

.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 26px 28px; }
.card h3 { font-size: 22px; font-weight: 700; }
.card > p.lead { color: var(--muted); margin: 10px 0 22px; }
.field { display: grid; gap: 7px; margin-bottom: 17px; }
.field label { font-size: 13px; font-weight: 600; }
.field .hint { font-size: 11.5px; color: var(--muted); }
input[type=text], input[type=number], textarea, select {
  background: var(--panel-2); border: 1px solid var(--line-2); border-radius: var(--r-sm);
  padding: 11px 13px; color: var(--text); width: 100%; font: inherit;
}
input:focus, textarea:focus, select:focus { border-color: var(--accent); }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.dropzone { border: 1px dashed var(--line-2); border-radius: var(--r); padding: 22px; display: flex; gap: 15px; align-items: center; cursor: pointer; }
.dropzone:hover { border-color: var(--accent); }
.dropzone.has { border-style: solid; border-color: var(--line-2); }
.dz-thumb { width: 46px; height: 46px; border-radius: 12px; object-fit: cover; flex: none; }
.dropzone > div:nth-child(2) { min-width: 0; flex: 1; }
.dropzone .hint { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Hidden from sight, not from the accessibility tree: display:none would take the input out
   of the tab order and its own label could no longer reach it. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.avatar img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; display: block; }
.dropzone .plus { width: 46px; height: 46px; border-radius: 12px; background: var(--panel-2); display: grid; place-items: center; font-size: 22px; color: var(--muted); }

.opts { display: grid; gap: 10px; }
.opt { border: 1px solid var(--line-2); border-radius: var(--r); padding: 14px 16px; cursor: pointer; display: flex; gap: 13px; align-items: center; background: var(--panel-2); }
.opt:hover { border-color: var(--line-2); }
.opt.sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--ring-accent); }
/* Shown, and not pickable. Dimming the whole row would hide the name, which is the
   thing worth showing — so the mark and the label fade and the text does not. */
.opt.shut { cursor: not-allowed; border-style: dashed; }
.opt.shut .ico, .opt.shut .radio { opacity: .3; }
.opt.shut .d { opacity: .65; }
/* The module marks. Sized by the svg itself now; font-size did nothing here the
   moment these stopped being characters. The inset highlight is what stops a flat
   tinted square from reading as a coloured div. */
.opt .ico {
  width: 36px; height: 36px; border-radius: 11px; display: grid; place-items: center;
  flex: none; border: 1px solid currentColor; box-shadow: var(--sheen-2);
}
.opt .ico { border-color: color-mix(in srgb, currentColor 26%, transparent); }
.opt .t { font-weight: 600; }
.opt .d { font-size: 12px; color: var(--muted); }
.opt .radio { width: 17px; height: 17px; border-radius: 50%; border: 1px solid var(--line-2); flex: none; }
.opt.sel .radio { border-color: var(--accent); background: radial-gradient(circle, var(--accent) 42%, transparent 46%); }
.three { display: grid; grid-template-columns: repeat(3,1fr); gap: 11px; }
.tile { border: 1px solid var(--line-2); border-radius: var(--r); padding: 15px; cursor: pointer; background: var(--panel-2); text-align: left; }
.tile.sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--ring-accent); }
.tile .big { font-size: 19px; font-weight: 800; letter-spacing: -.02em; }
.tile .sub { font-size: 11.5px; color: var(--muted); margin-top: 3px; }

.wizard-nav { display: flex; justify-content: space-between; margin-top: 22px; }

/* ---------- fuse flow ---------- */
.fuse-grid { display: grid; grid-template-columns: 1fr 46px 1fr; gap: 16px; align-items: stretch; }
.fuse-slot { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 20px; min-height: 200px; }
.fuse-slot h4 { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }
.fuse-arrow { display: grid; place-items: center; font-size: 22px; color: var(--accent); }
.picker { max-height: 260px; overflow-y: auto; display: grid; gap: 7px; margin-top: 13px; }
.pick { display: flex; gap: 10px; align-items: center; padding: 9px 11px; border-radius: var(--r-sm); border: 1px solid transparent; cursor: pointer; }
.pick:hover { background: var(--panel-2); }
.pick.sel { border-color: var(--accent); background: var(--panel-2); }
.receipt { display: grid; gap: 10px; margin-top: 16px; }
.receipt .r { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; }
.receipt .r .k { color: var(--muted); }
.receipt .r.total { border-top: 1px solid var(--line); padding-top: 11px; font-size: 15px; font-weight: 700; }
.note { background: var(--panel-2); border: 1px solid var(--line); border-left: 2px solid var(--accent); border-radius: var(--r-sm); padding: 12px 14px; font-size: 12.5px; color: var(--muted); }
.note b { color: var(--text); }

/* ---------- how it works ----------
   A sequence, not a feature grid: a coin's whole life in order, with its drawing beside each
   beat. The opening claim is a measurement, so it gets the space a measurement deserves. */
.how-open { padding: 46px 0 10px; max-width: 62ch; }
.how-open h1 { font-size: 60px; font-weight: 800; letter-spacing: -.04em; line-height: 1.02; margin: 20px 0 0; }
.how-open h1 .g { background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.how-open p { color: var(--muted); font-size: 16px; margin: 20px 0 0; }
.how-open p b { color: var(--text); }
.how-open-kicker { color: var(--text) !important; font-size: 17px !important; font-weight: 600; }

.how-line { list-style: none; margin: 0; padding: 0; position: relative; }
/* One continuous line down the numbers, so the beats read as a sequence rather than as cards
   that happen to be stacked. */
.how-line::before {
  content: ""; position: absolute; left: 21px; top: 26px; bottom: 26px; width: 2px;
  background: linear-gradient(var(--violet), var(--magenta), var(--cyan));
  opacity: .3;
}
.how-beat {
  display: grid; grid-template-columns: 44px 1fr 210px; gap: 22px; align-items: center;
  padding: 24px 0; border-bottom: 1px solid var(--line);
}
.how-beat:last-child { border-bottom: 0; }
.how-rail { display: flex; justify-content: center; }
.how-n {
  width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
  background: var(--panel); border: 1px solid var(--line-2);
  font-size: 12px; font-weight: 800; color: var(--accent); letter-spacing: .04em;
  position: relative; z-index: 1;
}
.how-copy h3 { font-size: 18px; font-weight: 700; }
.how-copy p { color: var(--muted); font-size: 14px; margin: 8px 0 0; max-width: 62ch; }
.how-copy p b { color: var(--text); }

.how-art { display: flex; justify-content: flex-end; }
.how-svg { width: 100%; max-width: 210px; overflow: visible; }
.how-svg text { text-anchor: middle; font-family: Geist, "Plus Jakarta Sans", sans-serif; }
.hw-t { font-size: 9.5px; fill: var(--muted); font-weight: 600; }
.hw-good { fill: var(--up); }
.hw-n { font-size: 17px; font-weight: 800; fill: var(--text); }
.hw-draw { stroke-dasharray: 260; stroke-dashoffset: 260; animation: hwDraw 1.4s ease-out both; }
@keyframes hwDraw { to { stroke-dashoffset: 0 } }
.hw-pulse { animation: hwPulse 2.4s ease-in-out infinite; transform-origin: 180px 20px; }
@keyframes hwPulse { 0%,100% { transform: scale(1); opacity: 1 } 50% { transform: scale(1.35); opacity: .55 } }
.hw-clock { transform-origin: 100px 58px; transform: rotate(-90deg); animation: hwTick 4s linear infinite; }
@keyframes hwTick { from { stroke-dashoffset: 214 } to { stroke-dashoffset: 0 } }
.hw-fade { animation: hwFade 3.2s ease-in-out infinite; }
@keyframes hwFade { 0%,30% { opacity: 1 } 70%,100% { opacity: .35 } }
.hw-dot { offset-path: path('M 78 58 L 120 58'); animation: hwRun 1.6s linear infinite; }
@keyframes hwRun { 0% { offset-distance: 0%; opacity: 0 } 15% { opacity: 1 } 85% { opacity: 1 } 100% { offset-distance: 100%; opacity: 0 } }
.hw-holder { animation: hwPop .5s cubic-bezier(.2,1.5,.4,1) both; }
@keyframes hwPop { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }

.how-why { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 14px; }
.why-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 20px; }
.why-icon {
  width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
  background: var(--grad-soft); border: 1px solid var(--line-2); color: var(--accent);
  box-shadow: var(--sheen);
}
.why-card h4 { margin: 13px 0 8px; font-size: 15.5px; }
.why-card p { color: var(--muted); font-size: 13px; margin: 0; }

@media (max-width: 900px) {
  .how-open h1 { font-size: 38px; }
  .how-beat { grid-template-columns: 44px 1fr; }
  .how-art { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hw-draw, .hw-pulse, .hw-clock, .hw-fade, .hw-dot, .hw-holder {
    animation: none !important; stroke-dashoffset: 0 !important; opacity: 1 !important;
  }
}

/* ---------- icons ----------
   Every mark on the page comes from icons.js as an inline <svg> carrying class .i. It
   inherits colour from its parent, so a call site tints an icon by setting `color` and
   nothing else, and it never needs a fill declared here.

   The default is inline-block with an optical baseline nudge, because most of these sit in
   running text — a pair mark inside "$4.2M · ◈ SOL". Anywhere the parent is already a flex
   row the browser blockifies it and the nudge stops applying, which is the behaviour we
   want in both places. `flex: none` keeps a 12px mark from being squeezed to 9px by a long
   coin name beside it. */
.i { display: inline-block; vertical-align: -.14em; flex: none; }

/* Containers that hold text next to a mark. These were inline-block with a plain space
   between icon and label, which left the two on different baselines at every size. */
.tag, .chip { display: inline-flex; align-items: center; gap: 5px; }
.chip { gap: 6px; }
.tag.pair .i, .tag.mod .i { opacity: .85; }
/* The pair's own artwork, where the chip used to carry a generic mark. Circular because every
   token logo is drawn for a circle, and ringed so a white logo still has an edge on a light
   panel. */
.tag.pair .pl { width: 14px; height: 14px; border-radius: 50%; object-fit: cover; box-shadow: 0 0 0 1px var(--line-2); }
/* The studio's pair rows. The square keeps its radius and sheen; the logo fills it. */
.opt .ico.logo { border: 0; overflow: hidden; background: var(--panel); }
.opt .ico.logo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* A mark alone in a large empty state. Ringed rather than floating, so it reads as a
   deliberate placeholder and not a loading failure. */
.empty-mark {
  width: 62px; height: 62px; margin: 0 auto 16px; border-radius: 18px;
  display: grid; place-items: center; color: var(--muted);
  background: var(--grad-soft); border: 1px solid var(--line-2); box-shadow: var(--sheen);
}


/* ---------- light ----------
   Dark is the default and stays the default: this is a dark-first product and following
   prefers-color-scheme would land most visitors — whose OS is light — somewhere the brand
   is not. Light is opt-in, remembered, and set before first paint by a script in <head> so
   the page never flashes the other theme.

   Only tokens are redefined here. If a rule below this block needs a colour literal, that
   is the signal it should have been a token in the first place.

   Two things invert and two things do not. The washes invert: on black a surface lifts by
   tinting toward the light, on white it lifts by tinting toward the ink. The sheen does
   not: a white top edge is what a physical object catches from above, and that is true on
   either ground. Neither does --on-grad — the CTA's arrow disc sits on the gradient, not on
   the page, so it stays white in both.

   The semantic colours darken rather than staying put, because each is used as text
   somewhere. #a78bfa on white measures 2.2:1 and #34d399 measures 1.9:1; both would have
   failed on the tags and badges that carry them. */
:root[data-theme="light"] {
  --bg:        #f6f6fa;
  --panel:     #ffffff;
  --panel-2:   #f1f1f7;
  --raised:    #ffffff;

  --line:      rgba(17,17,40,.09);
  --line-2:    rgba(17,17,40,.14);
  --line-3:    rgba(17,17,40,.24);
  --sheen:     inset 0 1px 0 rgba(255,255,255,.85);
  --sheen-2:   inset 0 1px 0 rgba(255,255,255,1);

  --wash-1:    rgba(17,17,40,.032);
  --wash-2:    rgba(17,17,40,.055);
  --wash-3:    rgba(17,17,40,.085);
  --ink-soft:  rgba(17,17,40,.30);
  --ink-faint: rgba(17,17,40,.07);

  --glass:     rgba(255,255,255,.74);
  --shadow-nav:   0 12px 34px -20px rgba(17,17,60,.35);
  --shadow-card:  0 22px 54px -34px rgba(17,17,60,.32);
  --shadow-toast: 0 10px 36px rgba(17,17,60,.20);

  --mesh-a:    rgba(124,92,255,.10);
  --mesh-b:    rgba(34,211,238,.07);
  --grain:     .05;

  --text:      #14141f;
  --muted:     #56566e;
  --muted-2:   #6a6a86;

  /* Each of these is used as text somewhere — the tags, the badges, the up/down column — so
     each is picked to clear 4.5:1 against the worst of the three surfaces rather than
     against white. web/contrast.mjs measures every pair, and is the reason two of them are
     darker than they first were: --up and --down both looked fine and both sat under 4.5.
     The bright originals survive only as glows and fills, never as a mark. */
  --accent:    #6b46e5;
  --cyan:      #0e7490;
  --up:        #067a4c;
  --down:      #c62c48;
  --warn:      #9a6206;

  --ring-accent: rgba(107,70,229,.30);

  /* The artwork on white. Every one of these is darker and more saturated than its dark
     counterpart rather than merely re-alpha'd: on a light ground a glow has to be a tint
     you can see, and a hairline has to be ink rather than an absence of it. */
  --art-1:      #6d4df0;
  --art-2:      #a935d8;
  --art-3:      #0e9dbb;
  --art-glow-1: rgba(109,77,240,.20);
  --art-glow-2: rgba(109,77,240,.06);
  --art-ink:    rgba(17,17,40,.14);
  --art-ink-2:  rgba(17,17,40,.30);
  --art-face:   #ffffff;
  --art-body-1: #ffffff;
  --art-body-2: #ded7fb;
  --art-dead-1: #fff3f5;
  --art-dead-2: #f3ced5;
  --art-face-1: #ffffff;
  --art-face-2: #eeeef6;
  --art-cell-2: rgba(207,52,80,.52);
  --grad-soft: linear-gradient(100deg, rgba(124,92,255,.10), rgba(197,88,240,.07) 50%, rgba(34,211,238,.09));
}

/* The rail's pending dots punch a hole in the track, so they take the page ground rather
   than a panel. Stated once here because --bg is the only token whose role changes. */
:root[data-theme="light"] .badge.dead  { background: rgba(13,143,95,.13); }
:root[data-theme="light"] .badge.stale { background: rgba(154,98,6,.13); }
:root[data-theme="light"] .badge.idle  { background: rgba(107,70,229,.12); }
:root[data-theme="light"] .badge.lock  { background: rgba(207,52,80,.12); }

/* The theme switch. Two marks in one track, the active one lit — a state you can read at a
   glance rather than a single icon that shows either where you are or where you would go
   and never says which. */
.themer {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  border-radius: 999px; background: var(--wash-1); border: 1px solid var(--line);
}
.themer button {
  width: 26px; height: 26px; border: 0; border-radius: 50%; padding: 0; cursor: pointer;
  background: none; color: var(--muted-2); display: grid; place-items: center;
  transition: color .4s var(--ease), background .4s var(--ease);
}
.themer button:hover { color: var(--text); }
.themer button[aria-pressed="true"] {
  background: var(--wash-3); color: var(--text); box-shadow: var(--sheen);
}

/* ---------- wallet ---------- */
.wallet-on { border-color: var(--line-3); font-family: "Geist Mono", ui-monospace, monospace; font-size: 12px; }

.wallet-sheet { position: fixed; inset: 0; z-index: 110; display: grid; place-items: center; }
.wallet-scrim { position: absolute; inset: 0; background: rgba(4,4,10,.62); backdrop-filter: blur(3px); animation: palFade .28s var(--ease) both; }
.wallet-box {
  position: relative; z-index: 1; width: min(380px, calc(100vw - 32px));
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--r-lg);
  box-shadow: var(--sheen), var(--shadow-card); padding: 20px;
  display: grid; gap: 9px; animation: palRise .34s var(--ease) both;
}
.wallet-box h3 { font-size: 16px; margin-bottom: 6px; }
.wallet-box .opt { cursor: pointer; }
.wallet-box .opt:hover { border-color: var(--line-3); background: var(--wash-2); }
.wallet-box .opt .pr-go { opacity: .6; }

/* ---------- coin page ---------- */
/* .section-head carries a 76px top margin, which is right between page sections and absurd
   as the first thing inside a card. */
.card > .section-head:first-child { margin-top: 0; }
.card > .section-head h3 { font-size: 17px; letter-spacing: -.02em; }
.coin-cols .stats { margin-top: 0; }

.coin-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 8px 0 20px; }
.coin-head .avatar { width: 54px; height: 54px; border-radius: 16px; font-size: 18px; }

.coin-cols { display: grid; grid-template-columns: 1.15fr .85fr; gap: 20px; align-items: start; margin-top: 20px; }
.coin-cols > div { display: grid; gap: 20px; align-content: start; }

/* The idle ladder. A bar rather than a number because the thing worth seeing is how close
   the next tier is, not how many days have passed. */
.life-bar {
  position: relative; height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--panel-2); border: 1px solid var(--line); margin-top: 6px;
}
.life-bar i { display: block; height: 100%; background: var(--grad); }
.life-bar b {
  position: absolute; top: -1px; width: 2px; height: calc(100% + 2px);
  background: var(--bg); opacity: .9;
}
.life-scale {
  display: flex; justify-content: space-between; font-size: 11px; color: var(--muted-2);
  margin-top: 6px;
}
/* The marks sit at 7 and 30 of 90, so the first two crowd the left edge. Spacing the labels
   evenly is a lie about where they are; these are positioned to match. */
.life-scale span:nth-child(2) { margin-left: -3%; }
.life-scale span:nth-child(3) { margin-right: 26%; }

@media (max-width: 900px) {
  .coin-cols { grid-template-columns: 1fr; }
}

/* ---------- misc ---------- */
.empty { text-align: center; padding: 60px 20px; color: var(--muted); }
/* The board before its first coin. Spans the grid, and says what the page is for rather
   than that something is missing. */
.empty-board { grid-column: 1 / -1; padding: 72px 20px; display: grid; justify-items: center; gap: 6px; }
.empty-board h3 { color: var(--text); font-size: 20px; letter-spacing: -.02em; margin: 6px 0 0; }
.empty-board p { max-width: 460px; margin: 0 0 18px; }
.toast { position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%); background: var(--panel-2); border: 1px solid var(--line-2); border-radius: var(--r); padding: 13px 20px; z-index: 90; box-shadow: var(--shadow-toast); }
.footer { position: relative; z-index: 1; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; max-width: var(--maxw); margin: 0 auto; padding: 24px 22px 40px; border-top: 1px solid var(--line); color: var(--muted); font-size: 12.5px; }
.footer a:hover { color: var(--text); }
.footer .sep { color: var(--muted-2); }

@media (max-width: 1080px) {
  .studio, .hero { grid-template-columns: 1fr; }
  .preview, .steps { position: static; }
  .flow-grid { grid-template-columns: 1fr; }
  .hero h1 { font-size: 40px; }
  .nav { order: 3; width: 100%; overflow-x: auto; }
}
@media (max-width: 640px) {
  .fuse-grid { grid-template-columns: 1fr; }
  .fuse-arrow { transform: rotate(90deg); }
  .three { grid-template-columns: 1fr; }
  .search { display: none; }
}

/* custom trading tax + Backstop controls */
.taxpresets .chip { padding: 5px 12px; font-size: 12px; }
input[type=range] { accent-color: var(--accent); }

/* ---------- trading tax tiles ----------
   Four tiles in one row: three presets and a custom rate. The custom one is a tile that
   happens to contain an input, rather than a field bolted on underneath, so picking it is the
   same gesture as picking any other rate. */
.tax-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.tile-custom { display: block; cursor: text; position: relative; }
.tile-custom .big { display: flex; align-items: baseline; gap: 3px; }
.tile-custom input {
  width: 3.1ch; min-width: 3.1ch; padding: 0; border: 0; background: none;
  font: inherit; font-size: 19px; font-weight: 650; letter-spacing: -.02em;
  color: var(--text); outline: 0;
  /* No spinner: it is a rate, not a stepper, and the arrows crowd a 3-character field. */
  -moz-appearance: textfield; appearance: textfield;
}
.tile-custom input::-webkit-outer-spin-button,
.tile-custom input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tile-custom input::placeholder { color: var(--muted-2); }
.tile-custom .pc { font-size: 19px; font-weight: 650; color: var(--muted-2); letter-spacing: -.02em; }
.tile-custom.sel .pc { color: var(--text); }
.tile-custom:focus-within { border-color: var(--accent); box-shadow: 0 0 0 1px var(--ring-accent); }

@media (max-width: 720px) {
  .tax-tiles { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- focus, keyboard, and the things the reviews found ----------
   There was no :focus-visible rule anywhere in this file, and two `outline: 0` declarations
   whose only replacement was a 1px hairline at 1.53:1 — invisible. One rule covers everything. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* A skip link, visible only when tabbed to. */
.skip {
  position: fixed; top: 10px; left: 10px; z-index: 60;
  transform: translateY(-200%);
  background: var(--raised); color: var(--text);
  border: 1px solid var(--line-3); border-radius: 999px;
  padding: 9px 16px; font-size: 13px; font-weight: 550;
  transition: transform .35s var(--ease);
}
.skip:focus { transform: none; }
#view:focus { outline: none; }

/* The pair and module options are real buttons now, so they need the button reset. */
.opt, .pick { font: inherit; text-align: left; width: 100%; color: inherit; }
.opt { border: 1px solid var(--line-2); }

/* The radio dot was the only rendering of a radio until selected, at 1.26:1 — below the 3:1
   floor for a control boundary. */
.opt .radio { border-color: var(--line-3); }

/* The toast stays in the accessibility tree and toggles by class, so a role="status" mutation
   is actually announced. `hidden` removed the node and swallowed it. */
.toast {
  opacity: 0; pointer-events: none;
  transform: translate(-50%, 10px);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

/* Name the properties. `transition: .18s` with no list is `transition: all`, which on a grid
   of sixteen cards animates every animatable property on every mutation. */
.coin-card { transition: transform .35s var(--ease), border-color .35s var(--ease); }
