/* ==========================================================================
   Opusghost — the site, built around 0.5.0
   One stylesheet, no build step, no network. This is the project's own design
   token set, shared with the app so the page and the editor read as one
   product.

   Hard constraint carried from the deployment: the CSP is `style-src 'self'`,
   which forbids inline `style` attributes. Every bar width below is therefore
   a class, and the numeric label is always the authoritative value — the bar
   is a shape, not a measurement.

   A note on the motion, since this page leads with a performance release:
   every animation here animates `transform` or `opacity` only, on the
   compositor, and the scroll listeners in landing.js are passive and
   rAF-throttled. Animating a layout property on a page that argues for not
   doing that would be a poor advertisement for the argument.
   ========================================================================== */

:root {
  color-scheme: light dark;

  --ui: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI Variable Text",
    "Segoe UI", "Helvetica Neue", system-ui, sans-serif;
  --display: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display",
    "Segoe UI", system-ui, sans-serif;
  --page: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
    "Times New Roman", serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --bg: #eef0f4;
  --bg-deep: #e2e5eb;
  --surface-2: rgba(255, 255, 255, 0.72);
  --raised: #fff;
  --heading: #1c1914;
  --label: #1d1d1f;
  --secondary: rgba(60, 60, 67, 0.66);
  --tertiary: rgba(60, 60, 67, 0.4);
  --ghost: rgba(60, 60, 67, 0.09);
  --hairline: rgba(60, 60, 67, 0.16);
  --hairline-strong: rgba(60, 60, 67, 0.28);
  --accent: #007aff;
  --accent-2: #7c5cff;
  --accent-press: #0066d6;
  --on-accent: #fff;

  --paper: #fffefa;
  --paper-ink: #1c1914;
  --paper-edge: #f1f0eb;
  --desk: #e2e5eb;

  /* Wins are accent-filled; a regression would be outlined, so the two are
     never confused by hue alone. */
  --win: #007aff;
  --win-soft: rgba(0, 122, 255, 0.14);
  --warn: #b25000;

  --shadow-sm: 0 1px 2px rgba(32, 43, 65, 0.08), 0 6px 18px rgba(32, 43, 65, 0.08);
  --shadow-page: 0 1px 2px rgba(32, 43, 65, 0.08), 0 18px 44px rgba(32, 43, 65, 0.16);
  --shadow-lift: 0 2px 6px rgba(32, 43, 65, 0.08), 0 26px 60px rgba(32, 43, 65, 0.18);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
  --max: 1160px;

  /* Written by landing.js on scroll. All motion reads these rather than
     touching layout directly. */
  --scroll: 0;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0e0f12;
    --bg-deep: #08090b;
    --surface-2: rgba(32, 33, 38, 0.72);
    --raised: #2c2d33;
    --heading: #ece8e0;
    --label: #f5f5f7;
    --secondary: rgba(235, 235, 245, 0.62);
    --tertiary: rgba(235, 235, 245, 0.32);
    --ghost: rgba(235, 235, 245, 0.08);
    --hairline: rgba(235, 235, 245, 0.14);
    --hairline-strong: rgba(235, 235, 245, 0.26);
    --accent: #0a84ff;
    --accent-2: #a78bfa;
    --accent-press: #409cff;
    --desk: #0b0c0f;
    --win: #0a84ff;
    --win-soft: rgba(10, 132, 255, 0.2);
    --warn: #ff9f45;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 22px rgba(0, 0, 0, 0.4);
    --shadow-page: 0 1px 2px rgba(0, 0, 0, 0.5), 0 24px 60px rgba(0, 0, 0, 0.72);
    --shadow-lift: 0 2px 8px rgba(0, 0, 0, 0.5), 0 34px 80px rgba(0, 0, 0, 0.8);
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--label);
  font-family: var(--ui);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1,
h2,
h3 {
  font-family: var(--page);
  font-weight: 400;
  letter-spacing: -0.015em;
  line-height: 1.1;
  color: var(--heading);
  margin: 0;
  text-wrap: balance;
}

p {
  margin: 0;
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration: none;
}

svg {
  display: block;
}

code {
  font-family: var(--mono);
  font-size: 0.88em;
  padding: 0.1em 0.36em;
  border-radius: 5px;
  background: var(--ghost);
}

/* Keys and shortcuts are words the reader might go looking for, so they are
   set like code but never as a command they are expected to type into a shell. */
kbd {
  font-family: var(--mono);
  font-size: 0.82em;
  padding: 0.14em 0.42em;
  border-radius: 5px;
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  color: var(--heading);
  white-space: nowrap;
}

em {
  font-style: italic;
}

/* ----------------------------------------------------------------- ambience */

/* Paper grain. A fixed, non-interactive layer at very low opacity: it stops
   the large flat gradients from banding on wide gamut displays and gives the
   whole page a slightly printed texture. `pointer-events: none` so it can
   never eat a click. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

@media (prefers-color-scheme: dark) {
  .grain {
    opacity: 0.05;
  }
}

/* Two slow, blurred colour fields behind the hero. Transform-only keyframes,
   so they cost the compositor and never a layout. */
.aurora {
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 130%;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  filter: blur(70px);
  opacity: 0.5;
}

.aurora span {
  position: absolute;
  display: block;
  border-radius: 50%;
  mix-blend-mode: normal;
}

.aurora .a {
  width: 46vw;
  height: 46vw;
  min-width: 320px;
  min-height: 320px;
  left: 4%;
  top: 2%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 46%, transparent), transparent 68%);
  animation: drift-a 22s var(--ease-soft) infinite alternate;
}

.aurora .b {
  width: 40vw;
  height: 40vw;
  min-width: 280px;
  min-height: 280px;
  right: 2%;
  top: 16%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent-2) 38%, transparent), transparent 68%);
  animation: drift-b 27s var(--ease-soft) infinite alternate;
}

@media (prefers-color-scheme: dark) {
  .aurora {
    opacity: 0.34;
  }
}

@keyframes drift-a {
  from {
    transform: translate3d(0, 0, 0) scale(1);
  }
  to {
    transform: translate3d(7%, 9%, 0) scale(1.16);
  }
}

@keyframes drift-b {
  from {
    transform: translate3d(0, 0, 0) scale(1.1);
  }
  to {
    transform: translate3d(-8%, 6%, 0) scale(0.94);
  }
}

/* --------------------------------------------------------------- progress */

.progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 60;
  pointer-events: none;
  transform-origin: 0 50%;
  transform: scaleX(var(--scroll));
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 55%, transparent);
  will-change: transform;
}

/* ------------------------------------------------------------------ layout */

.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: 24px;
}

.section {
  position: relative;
  z-index: 2;
  padding-block: clamp(64px, 9vw, 116px);
  border-top: 1px solid var(--hairline);
}

.section-alt {
  background: var(--bg-deep);
}

.section-dark {
  background: #0a0b0e;
  color: rgba(255, 255, 255, 0.78);
}

.section-dark h2,
.section-dark h3 {
  color: #fff;
}

@media (prefers-color-scheme: dark) {
  .section-dark {
    background: #050608;
    color: rgba(235, 235, 245, 0.7);
  }
  .section-dark h2,
  .section-dark h3 {
    color: #f2efe8;
  }
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--raised);
  color: var(--label);
  padding: 12px 18px;
  border-radius: 0 0 10px 0;
  z-index: 100;
}

.skip:focus {
  left: 0;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.close-mark {
  width: 54px;
  height: 54px;
  margin: 0 auto 22px;
  fill: var(--heading);
  opacity: 0.85;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.eyebrow {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
}

.section-head {
  max-width: 64ch;
  margin-bottom: clamp(36px, 5vw, 60px);
}

.section-head h2 {
  font-size: clamp(30px, 4.4vw, 46px);
}

.section-lede {
  margin-top: 16px;
  font-size: clamp(17px, 1.6vw, 19px);
  color: var(--secondary);
  line-height: 1.6;
}

.section-dark .section-lede {
  color: rgba(255, 255, 245, 0.62);
}

/* --------------------------------------------------------------------- nav */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid var(--hairline);
}

.nav-inner {
  display: flex;
  align-items: center;
  gap: 20px;
  max-width: var(--max);
  margin-inline: auto;
  padding: 14px 24px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 16px;
  color: var(--heading);
  margin-right: auto;
}

.brand-mark {
  width: 26px;
  height: 26px;
  fill: var(--heading);
  transition: transform 0.5s var(--ease);
}

.brand-mark .eyes,
.brand-mark .text {
  stroke-linecap: round;
}

.brand:hover .brand-mark {
  transform: translateY(-2px) rotate(-5deg);
}

.nav-links {
  display: flex;
  gap: 22px;
  font-size: 14.5px;
  color: var(--secondary);
}

.nav-links a {
  position: relative;
  padding-block: 2px;
}

/* The underline grows from the centre on hover — a small, cheap flourish. */
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1.5px;
  border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform 0.32s var(--ease);
}

.nav-links a:hover {
  color: var(--label);
}

.nav-links a:hover::after {
  transform: scaleX(1);
}

@media (max-width: 860px) {
  .nav-links {
    display: none;
  }
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 20px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 550;
  border: 1px solid transparent;
  transition: transform 0.22s var(--ease), background 0.22s var(--ease-soft),
    border-color 0.22s var(--ease-soft), box-shadow 0.22s var(--ease-soft);
  white-space: nowrap;
}

.btn:hover {
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(0) scale(0.97);
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 6px 20px color-mix(in srgb, var(--accent) 30%, transparent);
}

.btn-primary:hover {
  background: var(--accent-press);
  box-shadow: 0 10px 30px color-mix(in srgb, var(--accent) 40%, transparent);
}

.btn-ghost {
  border-color: var(--hairline-strong);
  color: var(--heading);
  background: var(--surface-2);
}

.btn-ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.btn-large {
  padding: 14px 28px;
  font-size: 16.5px;
}

/* -------------------------------------------------------------------- hero */

.hero {
  position: relative;
  isolation: isolate;
  padding-block: clamp(60px, 9vw, 108px) clamp(52px, 7vw, 92px);
  overflow: hidden;
}

.hero-grid {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  gap: clamp(34px, 5vw, 64px);
  align-items: center;
}

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

.kicker {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--secondary);
  margin-bottom: 18px;
}

.kicker svg {
  width: 20px;
  height: 20px;
  fill: var(--accent);
}

/* The version badge. Types itself in, because it is a writing app.
   `fit-content` keeps the pill hugging its own text while still claiming a
   block row of its own, so it never drifts up beside the kicker. */
.version {
  display: flex;
  width: fit-content;
  align-items: baseline;
  gap: 2px;
  margin-bottom: 20px;
  padding: 7px 8px 7px 16px;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 600;
  color: var(--heading);
  letter-spacing: 0.02em;
  box-shadow: var(--shadow-sm);
}

.version .from {
  color: var(--tertiary);
  font-weight: 500;
}

.version .arrow {
  color: var(--accent);
  padding-inline: 3px;
}

.version .to {
  color: var(--accent);
  font-weight: 700;
}

.version .caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 3px;
  background: var(--accent);
  transform: translateY(2px);
  animation: blink 1.05s steps(1, end) infinite;
}

/* Once typing has finished the caret stops blinking and fades, so it does not
   sit there twitching at a reader who has moved on. */
.version.is-typed .caret {
  animation: none;
  opacity: 0;
  transition: opacity 0.5s var(--ease-soft) 0.35s;
}

@keyframes blink {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

.hero h1 {
  font-size: clamp(34px, 5.8vw, 64px);
  line-height: 1.05;
}

/* A slow sheen across the headline. Background-clip only — no reflow. */
.hero h1 .sheen {
  background: linear-gradient(
    100deg,
    var(--heading) 0%,
    var(--heading) 38%,
    var(--accent) 50%,
    var(--heading) 62%,
    var(--heading) 100%
  );
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: sheen 9s var(--ease-soft) infinite;
}

@keyframes sheen {
  0%,
  100% {
    background-position: 130% 0;
  }
  50% {
    background-position: -30% 0;
  }
}

.lede {
  margin-top: 20px;
  font-size: clamp(17px, 1.8vw, 20px);
  line-height: 1.55;
  color: var(--secondary);
  max-width: 54ch;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 28px;
}

.hero-note {
  margin-top: 18px;
  font-size: 14.5px;
  color: var(--tertiary);
  max-width: 52ch;
}

/* The headline stat. */
.stat-card {
  position: relative;
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-radius: 22px;
  padding: clamp(26px, 3.4vw, 38px);
  box-shadow: var(--shadow-page);
  overflow: hidden;
}

/* A hairline of accent along the top edge, drawn in on reveal. */
.stat-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: transform 1.1s var(--ease) 0.15s;
}

.stat-card.is-in::before {
  transform: scaleX(1);
}

.stat-figure {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-family: var(--display);
  font-size: clamp(54px, 8.6vw, 88px);
  font-weight: 680;
  letter-spacing: -0.04em;
  line-height: 0.92;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.stat-unit {
  font-size: 0.36em;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--secondary);
}

.stat-label {
  margin-top: 14px;
  font-size: 17px;
  color: var(--heading);
  font-weight: 550;
}

.stat-sub {
  margin-top: 8px;
  font-size: 14.5px;
  color: var(--tertiary);
  line-height: 1.5;
}

.stat-split {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--hairline);
  font-family: var(--mono);
  font-size: 13px;
  color: var(--secondary);
  font-variant-numeric: tabular-nums;
}

.stat-split span:last-child {
  color: var(--heading);
  font-weight: 600;
}

/* A quiet scroll cue. Fades out as soon as the reader scrolls. */
.scroll-cue {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  margin-top: clamp(34px, 5vw, 58px);
  opacity: calc(1 - var(--scroll) * 6);
}

.scroll-cue span {
  display: block;
  width: 1px;
  height: 46px;
  background: linear-gradient(180deg, var(--hairline-strong), transparent);
  position: relative;
  overflow: hidden;
}

.scroll-cue span::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 16px;
  background: var(--accent);
  animation: cue 2.1s var(--ease-soft) infinite;
}

@keyframes cue {
  0% {
    transform: translateY(-18px);
    opacity: 0;
  }
  35% {
    opacity: 1;
  }
  100% {
    transform: translateY(48px);
    opacity: 0;
  }
}

/* --------------------------------------------------------------- ink rule */

/* A rule that draws itself across, the way a pen lays a line.
   This started as an SVG with `pathLength="1"` and a dash offset. That does not
   survive `vector-effect="non-scaling-stroke"`: the dash pattern is then
   measured in user units rather than in the normalised path length, so the line
   broke into segments. A transform on a pseudo-element is both simpler and
   immune to that interaction. */
.ink-rule {
  position: relative;
  height: 2px;
  margin-top: clamp(40px, 5vw, 64px);
  border-radius: 2px;
  background: var(--hairline);
  overflow: hidden;
}

.ink-rule::after {
  content: "";
  display: block;
  height: 100%;
  width: 100%;
  border-radius: inherit;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: transform 1.25s var(--ease);
}

.ink-rule.is-in::after {
  transform: scaleX(1);
}

/* ------------------------------------------------------------ at a glance */

.glance {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 14px;
}

.tile {
  position: relative;
  padding: 24px 22px;
  border-radius: 16px;
  background: var(--raised);
  border: 1px solid var(--hairline);
  overflow: hidden;
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease),
    border-color 0.4s var(--ease-soft);
}

/* Pointer-tracked highlight. The custom properties are written by
   landing.js; without scripting the tile simply has no highlight. */
.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s var(--ease-soft);
  background: radial-gradient(
    220px circle at var(--mx, 50%) var(--my, 0%),
    var(--win-soft),
    transparent 68%
  );
}

.tile:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
  border-color: color-mix(in srgb, var(--accent) 34%, var(--hairline));
}

.tile:hover::after {
  opacity: 1;
}

.tile-value {
  display: block;
  font-family: var(--display);
  font-size: clamp(30px, 3.6vw, 42px);
  font-weight: 680;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--heading);
  font-variant-numeric: tabular-nums;
}

/* A leading + or − is an operator on the figure, not a unit, so it sits closer
   to the number's own size. A trailing % is a unit and stays small — the same
   relationship the hero stat uses. */
.tile-value .sign {
  font-size: 0.62em;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0;
  margin-right: 0.03em;
}

.tile-value .u {
  font-size: 0.44em;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0;
  margin-left: 0.06em;
  vertical-align: 0.12em;
}

.tile-label {
  display: block;
  margin-top: 10px;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--secondary);
}

/* --------------------------------------------------------------- timeline */

.timeline {
  position: relative;
  display: grid;
  gap: 4px;
}

.phase {
  position: relative;
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: clamp(16px, 3vw, 34px);
  padding-bottom: 34px;
}

@media (max-width: 720px) {
  .phase {
    grid-template-columns: 1fr;
    gap: 8px;
  }
}

/* The connector draws downward as each phase arrives. */
.phase::before {
  content: "";
  position: absolute;
  left: 5px;
  top: 16px;
  bottom: -4px;
  width: 2px;
  border-radius: 2px;
  transform: scaleY(0);
  transform-origin: 50% 0;
  background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent-2) 60%, transparent));
  transition: transform 0.9s var(--ease) 0.1s;
}

.phase.is-in::before {
  transform: scaleY(1);
}

.phase:last-child::before {
  display: none;
}

.phase-when {
  position: relative;
  padding-left: 26px;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--tertiary);
  letter-spacing: 0.02em;
  padding-top: 2px;
}

/* The node on the connector. Scales and glows in on arrival. */
.phase-when::before {
  content: "";
  position: absolute;
  left: 0;
  top: 5px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--accent);
  transform: scale(0);
  transition: transform 0.55s var(--ease) 0.15s, box-shadow 0.55s var(--ease-soft) 0.15s;
}

.phase.is-in .phase-when::before {
  transform: scale(1);
  box-shadow: 0 0 0 5px var(--win-soft);
}

.phase-body {
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  padding: 22px 24px;
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}

.phase-body:hover {
  transform: translateX(4px);
  box-shadow: var(--shadow-sm);
}

.phase-body h3 {
  font-size: 20px;
  margin-bottom: 8px;
}

.phase-body p {
  font-size: 15px;
  line-height: 1.6;
  color: var(--secondary);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 14px;
}

.chip {
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--ghost);
  font-size: 12.5px;
  color: var(--secondary);
  white-space: nowrap;
}

.chip.accent {
  background: var(--win-soft);
  color: var(--accent);
  font-weight: 550;
}

/* -------------------------------------------------------------- win panels */

.wins {
  display: grid;
  gap: 20px;
}

.win {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.86fr);
  gap: clamp(24px, 4vw, 52px);
  align-items: start;
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-radius: 20px;
  padding: clamp(24px, 3.2vw, 40px);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.45s var(--ease), border-color 0.45s var(--ease-soft);
}

.win:hover {
  box-shadow: var(--shadow-lift);
  border-color: color-mix(in srgb, var(--accent) 28%, var(--hairline));
}

@media (max-width: 860px) {
  .win {
    grid-template-columns: 1fr;
  }
}

.win-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.win-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--win-soft);
  color: var(--win);
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 700;
  flex: none;
}

.win h3 {
  font-size: clamp(21px, 2.3vw, 26px);
}

.win-body p {
  margin-top: 12px;
  color: var(--secondary);
  line-height: 1.62;
}

.win-body code {
  color: var(--heading);
}

/* -------------------------------------------------------------- the meters */

.meters {
  display: grid;
  gap: 18px;
  align-content: start;
  padding: 20px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  border: 1px solid var(--hairline);
}

.meter + .meter {
  padding-top: 18px;
  border-top: 1px solid var(--hairline);
}

.meter-row {
  display: grid;
  /* The value column is a FIXED width on purpose. It used to be `auto`, which
     meant a row reading "3,813,453 B" got a wider label column, a narrower
     track, and therefore a visibly shorter 100% "before" bar than the "after"
     row below it sitting on a wider track. On a page whose entire argument is
     that these two bars are comparable, that is the one bug that must not
     survive. Every track is now the same width, so `w-100` really is 100%. */
  grid-template-columns: 58px minmax(0, 1fr) 106px;
  align-items: center;
  gap: 12px;
}

.meter-row + .meter-row {
  margin-top: 10px;
}

.meter-tag {
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tertiary);
}

.meter-track {
  height: 22px;
  border-radius: 6px;
  background: var(--ghost);
  overflow: hidden;
}

/* `min-width` keeps a sub-1% result visible at all. It is a visibility floor,
   NOT a rounded value: the label beside the bar is always the real number, and
   a floor that ever misled a reader would be a lie told by a picture. */
.bar {
  position: relative;
  display: block;
  height: 100%;
  width: 0;
  min-width: 3px;
  border-radius: 6px;
  background: var(--hairline-strong);
  transition: width 1s var(--ease);
}

.is-in .bar {
  width: var(--w);
}

.meter-row--before .bar {
  background: var(--hairline-strong);
}

.meter-row--after .bar {
  background: linear-gradient(90deg, var(--win), color-mix(in srgb, var(--accent-2) 55%, var(--win)));
  box-shadow: 0 0 0 0 transparent;
}

/* One brightness pulse as the bar lands, then still. Scale independent, so it
   reads on a 3px bar as well as a full-width one. */
.meter-row--after .is-in .bar,
.is-in .meter-row--after .bar {
  animation: land 1.1s var(--ease-soft) 0.85s;
}

@keyframes land {
  0% {
    filter: brightness(1);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--win) 55%, transparent);
  }
  35% {
    filter: brightness(1.32);
    box-shadow: 0 0 16px 2px color-mix(in srgb, var(--win) 42%, transparent);
  }
  100% {
    filter: brightness(1);
    box-shadow: 0 0 0 0 transparent;
  }
}

.meter-val {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
}

.meter-row--after .meter-val {
  color: var(--heading);
  font-weight: 650;
}

.meter-ratio {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.meter-ratio b {
  font-family: var(--display);
  font-size: 26px;
  font-weight: 680;
  letter-spacing: -0.02em;
  color: var(--win);
  font-variant-numeric: tabular-nums;
}

.meter-ratio span {
  font-size: 13px;
  color: var(--tertiary);
  text-align: right;
}

/* Bar widths. Every one is a true fraction of its own "before" bar, which is
   always 100%, so the pairs are directly comparable within a meter and two
   meters are never compared against each other. */
.w-100 { --w: 100%; }
.w-72  { --w: 72%; }
.w-48  { --w: 47.6%; }
.w-20  { --w: 19.7%; }
.w-12  { --w: 11.9%; }
.w-08  { --w: 7.7%; }

.basis {
  display: inline-block;
  margin-top: 16px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--tertiary);
}

.note {
  margin-top: 16px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--tertiary);
  padding-left: 14px;
  border-left: 2px solid var(--hairline);
}

.note b {
  color: var(--secondary);
  font-weight: 650;
}

/* ------------------------------------------------------------------- table */

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--hairline);
  border-radius: 16px;
  background: var(--raised);
}

table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: 15px;
}

thead th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tertiary);
  padding: 14px 18px;
  border-bottom: 1px solid var(--hairline);
  white-space: nowrap;
}

tbody td {
  padding: 15px 18px;
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
  color: var(--secondary);
}

tbody tr {
  transition: background 0.3s var(--ease-soft);
}

tbody tr:hover {
  background: color-mix(in srgb, var(--accent) 4%, transparent);
}

tbody tr:last-child td {
  border-bottom: 0;
}

td.change {
  color: var(--heading);
  font-weight: 500;
}

td.num {
  font-family: var(--mono);
  font-size: 13.5px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

td.after {
  color: var(--heading);
  font-weight: 650;
}

td.gain {
  color: var(--win);
  font-weight: 650;
  white-space: nowrap;
}

.tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--ghost);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.03em;
  color: var(--secondary);
  white-space: nowrap;
}

/* A quiet sub-heading between two card grids, so a long release section can be
   scanned without reading every card. Set in the UI face and small on purpose:
   it is a label, not another headline competing with the section title. */
.group-title {
  font-family: var(--ui);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--tertiary);
  margin: 38px 0 16px;
}

.group-title:first-of-type {
  margin-top: 0;
}

/* ------------------------------------------------------------------ cards */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  gap: 16px;
}

.card {
  position: relative;
  padding: 24px;
  border-radius: 16px;
  background: var(--raised);
  border: 1px solid var(--hairline);
  overflow: hidden;
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease),
    border-color 0.4s var(--ease-soft);
}

.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s var(--ease-soft);
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 0%),
    var(--win-soft),
    transparent 70%
  );
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--hairline));
}

.card:hover::after {
  opacity: 1;
}

.card-icon {
  width: 24px;
  height: 24px;
  margin-bottom: 14px;
  color: var(--accent);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.45s var(--ease);
}

.card:hover .card-icon {
  transform: scale(1.12) rotate(-4deg);
}

.card h3 {
  font-size: 19px;
  margin-bottom: 9px;
}

.card p {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--secondary);
}

.card code {
  color: var(--heading);
}

/* ----------------------------------------------------------------- method */

.method {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
}

.method-card {
  padding: 24px;
  border-radius: 16px;
  background: var(--raised);
  border: 1px solid var(--hairline);
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}

.method-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-sm);
}

.method-card h3 {
  font-size: 19px;
  margin-bottom: 10px;
}

.method-card p {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--secondary);
}

.method-card .trust {
  display: inline-block;
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--win);
}

.repro {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--secondary);
}

.repro code {
  background: var(--raised);
  border: 1px solid var(--hairline);
  padding: 7px 12px;
  font-size: 13px;
  color: var(--heading);
  transition: border-color 0.3s var(--ease-soft), transform 0.3s var(--ease);
}

.repro code:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}

.honesty {
  margin-top: 20px;
  padding: 22px 24px;
  border-radius: 14px;
  background: var(--win-soft);
  font-size: 15.5px;
  line-height: 1.62;
  color: var(--heading);
}

.honesty b {
  font-weight: 650;
}

.commit-ref {
  display: inline-block;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--tertiary);
  padding: 2px 7px;
  border-radius: 5px;
  background: var(--ghost);
  margin-left: 6px;
  white-space: nowrap;
}

/* ------------------------------------------------------------------ close */

.close {
  position: relative;
  z-index: 2;
  text-align: center;
  padding-block: clamp(64px, 9vw, 116px);
  border-top: 1px solid var(--hairline);
}

.close h2 {
  font-size: clamp(28px, 4.2vw, 44px);
}

.close p {
  margin-top: 16px;
  color: var(--secondary);
  max-width: 48ch;
  margin-inline: auto;
}

.close .hero-actions {
  justify-content: center;
}

/* ----------------------------------------------------------------- footer */

.footer {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--hairline);
  padding-block: 40px;
}

.footer-inner {
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: 24px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 28px;
}

.footer-line {
  font-size: 14.5px;
  color: var(--tertiary);
}

.footer-links {
  display: flex;
  gap: 20px;
  margin-left: auto;
  font-size: 14.5px;
  color: var(--secondary);
}

.footer-links a:hover {
  color: var(--accent);
}

.footer-fine {
  width: 100%;
  font-size: 13px;
  color: var(--tertiary);
  padding-top: 18px;
  border-top: 1px solid var(--hairline);
}

/* ---------------------------------------------------------------- reveals */

/* Everything that waits on an entrance starts hidden; `.no-js` is removed by
   landing.js before anything animates, so a scripted-less visit is simply
   visible rather than blank. */
.no-js [data-reveal] {
  opacity: 1;
  transform: none;
}

/* The bars are the exception that proves the rule above. They are authored at
   `width: 0` and only reach their real width via `.is-in`, which JavaScript
   adds. Without this rule a reader with scripting off would see a column of
   empty 3px slivers next to perfectly legible labels — a page whose pictures
   contradict its own numbers. `no-js` is only ever present when the script did
   not run, so this can never fight the animated state. */
.no-js .bar {
  width: var(--w);
  transition: none;
}

/* Same reasoning for the timeline node, which is authored collapsed. */
.no-js .phase-when::before {
  transform: scale(1);
  transition: none;
}

[data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s var(--ease-soft), transform 0.7s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}

[data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* A clip-based reveal for the big headings: the text rises into place from
   behind a mask rather than sliding as a whole block. */
.reveal-mask {
  display: block;
  overflow: hidden;
}

.reveal-mask > span {
  display: block;
  transform: translateY(105%);
  transition: transform 0.85s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal-mask.is-in > span {
  transform: translateY(0);
}

.no-js .reveal-mask > span {
  transform: none;
}

/* ------------------------------------------------------------ reduced motion */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  [data-reveal],
  .reveal-mask > span {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .bar,
  .stat-card::before,
  .ink-rule::after,
  .phase::before,
  .phase-when::before {
    transition: none;
  }

  /* Land everything at its final state rather than freezing it mid-animation.
     These are separate rules on purpose: a single `transform` declaration
     listing both scaleX and scaleY would let the last one win, leaving the
     horizontal rules collapsed at zero width. */
  .bar {
    width: var(--w);
  }

  .stat-card::before,
  .ink-rule::after {
    transform: scaleX(1);
  }

  .phase::before {
    transform: scaleY(1);
  }

  .phase-when::before {
    transform: scale(1);
  }

  .phase-when::before {
    transform: scale(1);
  }

  .btn,
  .tile,
  .card,
  .win,
  .method-card,
  .phase-body,
  .repro code,
  .nav-links a::after,
  .version .caret {
    transition: none;
  }

  .aurora,
  .aurora .a,
  .aurora .b,
  .hero h1 .sheen,
  .scroll-cue span::after,
  .meter-row--after .is-in .bar,
  .is-in .meter-row--after .bar {
    animation: none;
  }

  .tile:hover,
  .card:hover,
  .btn:hover,
  .phase-body:hover,
  .repro code:hover {
    transform: none;
  }

  .scroll-cue {
    display: none;
  }
}
