/* ============================================================================
   Olex - design tokens
   Palette values come from the validated reference instance. The three series
   hues (blue / orange / aqua) passed all-pairs CVD + normal-vision checks
   against this surface; a fourth slot (yellow) failed beside orange, so the
   chart layer deliberately stops at three.
   ========================================================================= */

:root {
  color-scheme: dark;

  --page:            #0d0d0d;
  --surface-1:       #141414;
  --surface-2:       #1a1a19;
  --surface-3:       #212120;

  --text-primary:    #ffffff;
  --text-secondary:  #c3c2b7;
  --text-muted:      #898781;

  --grid:            #2c2c2a;
  --axis:            #383835;
  --border:          rgba(255, 255, 255, 0.10);
  --border-strong:   rgba(255, 255, 255, 0.16);

  --series-1:        #3987e5;
  --series-2:        #d95926;
  --series-3:        #199e70;

  --good:            #0ca30c;
  --warning:         #fab219;
  --critical:        #d03b3b;

  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 14px;

  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.24);

  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --wrap: 1140px;
}

:root[data-theme="light"] {
  color-scheme: light;

  --page:            #f9f9f7;
  --surface-1:       #fcfcfb;
  --surface-2:       #ffffff;
  --surface-3:       #f2f2ef;

  --text-primary:    #0b0b0b;
  --text-secondary:  #52514e;
  --text-muted:      #898781;

  --grid:            #e1e0d9;
  --axis:            #c3c2b7;
  --border:          rgba(11, 11, 11, 0.10);
  --border-strong:   rgba(11, 11, 11, 0.16);

  --series-1:        #2a78d6;
  --series-2:        #eb6834;
  --series-3:        #1baf7a;

  --good:            #006300;

  --shadow: 0 1px 2px rgba(11,11,11,.06), 0 8px 24px rgba(11,11,11,.06);
}

/* ============================================================================
   base
   ========================================================================= */

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

html { scroll-behavior: smooth; scroll-padding-top: 84px; }

body {
  margin: 0;
  background: var(--page);
  color: var(--text-primary);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

h1, h2, h3 { margin: 0; line-height: 1.15; letter-spacing: -0.02em; font-weight: 600; }
p { margin: 0; }
a { color: inherit; }

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

.ink-2 { color: var(--text-secondary); }
.ink-3 { color: var(--text-muted); }

.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ============================================================================
   top bar
   ========================================================================= */

.topbar {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--page) 88%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  /* notched phones in landscape */
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* color-mix is Baseline 2023; this fallback paints first for anything older. */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .topbar { background: var(--page); }
}

.topbar-inner {
  height: 64px;
  display: flex; align-items: center; gap: 24px;
}

.brand {
  display: flex; align-items: center; gap: 10px;
  text-decoration: none; font-weight: 600; letter-spacing: -0.02em;
  -webkit-tap-highlight-color: transparent;
}
.brand-mark { display: grid; place-items: center; }
.brand-text { font-size: 18px; }

.nav {
  display: flex; gap: 4px; margin-left: auto;
}
.nav a {
  padding: 7px 12px; border-radius: var(--radius-sm);
  color: var(--text-secondary); text-decoration: none;
  font-size: 14px; font-weight: 500;
  transition: background .15s ease, color .15s ease;
}
.nav a:hover { background: var(--surface-3); color: var(--text-primary); }

/* The nav spans five pages now, so "which page am I on" has to be answerable
   from the bar. Weight and colour carry it together - the underline is what
   survives a greyscale print, and aria-current carries it to a screen reader
   regardless. */
.nav a[aria-current="page"] {
  color: var(--text-primary);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--series-1);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.topbar-right { display: flex; align-items: center; gap: 10px; }

.conn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 12.5px; font-weight: 500; color: var(--text-secondary);
  white-space: nowrap;
}
.conn-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-muted); flex: none; }
.conn[data-state="live"] .conn-dot { background: var(--good); box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 22%, transparent); }
.conn[data-state="live"] { color: var(--text-primary); }
.conn[data-state="error"] .conn-dot { background: var(--critical); }

/* The network switch: two options, both always readable.
   A single toggle would show the active state but never name the alternative,
   and "which chain is this" is not a question to leave to inference. The active
   option carries a filled surface, a border and a weight change - hue is never
   the only thing marking it. */
.net-switch {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 2px; border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  flex: none;
}
.net-opt {
  appearance: none;
  display: inline-grid; place-items: center;
  padding: 4px 11px; border-radius: 999px;
  border: 1px solid transparent;
  background: none; color: var(--text-secondary);
  font: inherit; font-size: 12.5px; font-weight: 500;
  white-space: nowrap; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.net-opt:hover { color: var(--text-primary); }
.net-opt.is-active {
  background: var(--surface-1);
  border-color: var(--border-strong);
  color: var(--text-primary);
  font-weight: 600;
}

.btn-ghost {
  display: inline-grid; place-items: center;
  min-height: 36px; padding: 0 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-secondary);
  font: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.btn-ghost:hover { background: var(--surface-3); color: var(--text-primary); border-color: var(--border-strong); }

/* Icon-only controls are square by construction rather than by padding a glyph
   out to size. The theme toggle used to reach 44px as a 16px mark centred in a
   box built for text, which on a phone read as a large empty tile. */
.icon-btn {
  display: inline-grid; place-items: center;
  width: 40px; height: 40px; padding: 0; flex: none;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-secondary);
  font: inherit; cursor: pointer; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.icon-btn:hover {
  background: var(--surface-3); color: var(--text-primary);
  border-color: var(--border-strong);
}
.icon-btn svg { width: 20px; height: 20px; display: block; }
.icon-btn[aria-pressed="true"] { color: var(--text-primary); }

/* Only rendered where the inline nav cannot fit; see the 960px breakpoint. */
#nav-toggle { display: none; }
#nav-toggle .bar-close { display: none; }
#nav-toggle.is-open .bar-open { display: none; }
#nav-toggle.is-open .bar-close { display: block; }

/* On touch devices every control clears the 44px recommendation. */
@media (pointer: coarse) {
  .btn-ghost { min-height: 44px; padding-inline: 14px; }
  .icon-btn { width: 44px; height: 44px; }

  /* The switch options are real buttons and have to clear 44px in both axes
     like every other control. The container gives up its 2px of padding so the
     group lands at 48px rather than 50px, keeping it close to the 44px icon
     buttons beside it instead of becoming the tallest thing in the bar. */
  .net-switch { padding: 1px; }
  .net-opt { min-height: 44px; min-width: 44px; padding-inline: 12px; }
}

/* ============================================================================
   hero
   ========================================================================= */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: 56px; align-items: center;
  padding-block: 72px 64px;
}

.eyebrow {
  font-size: 12.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--series-1); margin-bottom: 16px;
}

/* text-wrap: balance evens the ragged lines a hardcoded <br> used to force,
   and keeps doing so at every width instead of only the one it was tuned for. */
.hero h1 {
  font-size: clamp(30px, 4.2vw, 50px);
  margin-bottom: 20px;
  text-wrap: balance;
  max-width: 20ch;
}

.lede { color: var(--text-secondary); font-size: 17px; max-width: 54ch; }

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

.btn-primary, .btn-secondary {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 42px; padding: 0 20px;
  border-radius: var(--radius); font: inherit; font-size: 15px; font-weight: 600;
  text-decoration: none; cursor: pointer; border: 1px solid transparent;
  transition: filter .15s ease, background .15s ease, border-color .15s ease;
}
.btn-primary { background: var(--series-1); color: #fff; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-secondary { background: var(--surface-2); color: var(--text-primary); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--surface-3); }

.hero-note { margin-top: 22px; font-size: 13.5px; color: var(--text-muted); }

/* hero figure - exactly one per view */
.hero-figure {
  margin: 0; padding: 26px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.tile-label {
  font-size: 13px; font-weight: 500; color: var(--text-secondary);
  margin-bottom: 8px;
}

.hero-value {
  font-size: clamp(44px, 5.4vw, 60px);
  font-weight: 650; letter-spacing: -0.035em; line-height: 1;
  /* proportional figures, per the figure spec - tabular is for columns */
}

.hero-sub { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: 13.5px; }

.mark-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--series-3);
  box-shadow: 0 0 0 2px var(--surface-1);  /* surface ring */
  flex: none;
}

.spark-wrap { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border); }
.spark { width: 100%; height: 56px; display: block; overflow: visible; }
.spark-caption { font-size: 12px; margin-top: 10px; }

/* ============================================================================
   sections
   ========================================================================= */

/* A hairline between sections does the work the old 56px of dead space was
   attempting: it separates without leaving the page feeling unfinished. */
.section { padding-block: 64px; }
.section + .section { border-top: 1px solid var(--border); }
.section-head { margin-bottom: 28px; }
.section-head h2 { font-size: 26px; margin-bottom: 8px; letter-spacing: -0.025em; }
.section-head p { font-size: 15px; max-width: 68ch; }

/* stat tiles */
.tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px;
  margin-bottom: 24px;
}
.tile {
  padding: 20px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.tile-value { font-size: 30px; font-weight: 600; letter-spacing: -0.025em; line-height: 1.1; }
.tile-delta { font-size: 12.5px; margin-top: 6px; }

/* recent blocks */
.feed-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.feed-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
.feed-head h3 { font-size: 15px; font-weight: 600; }

.table-scroll { overflow-x: auto; }

.feed-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.feed-table th {
  text-align: left; font-weight: 500; font-size: 12px;
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-muted);
  padding: 10px 20px; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.feed-table th.num { text-align: right; }
.feed-table td {
  padding: 11px 20px; border-bottom: 1px solid var(--grid);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.feed-table tbody tr:last-child td { border-bottom: none; }
.feed-table tbody tr { transition: background .12s ease; }
.feed-table tbody tr:hover { background: var(--surface-3); }
/* Was set from script as two inline style properties on every row build. It is
   presentation and it never varies, so it belongs here. */
.feed-link { color: var(--series-1); text-decoration: none; }
.feed-link:hover { text-decoration: underline; }
.hash { font-family: var(--mono); font-size: 12.5px; color: var(--text-secondary); }
.skeleton-row td { color: var(--text-muted); text-align: center; padding-block: 28px; }

.row-new { animation: flashIn .9s ease; }
@keyframes flashIn {
  from { background: color-mix(in srgb, var(--series-1) 18%, transparent); }
  to   { background: transparent; }
}

/* ============================================================================
   playground
   ========================================================================= */

.play {
  display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 20px;
  align-items: start;
}

/* The tool list is ten rows tall and the form above the output is short, so the
   right column used to stop two-thirds of the way down and leave a rectangle of
   dead space beside the sidebar - the single thing that made this page read as
   a section that had been lifted out rather than a page. Let the output panel
   absorb the slack instead. Only above the stacking breakpoint: once the
   columns are on top of each other there is no sidebar to match and stretching
   would just be a tall empty box. */
@media (min-width: 961px) {
  .play { align-items: stretch; }
  .play-main { grid-template-rows: auto 1fr; }
  .play-output { display: flex; flex-direction: column; }
  .play-pre { flex: 1; }
}

/* The sidebar reads as one panel rather than seven loose buttons, which is
   what made the playground look unfinished next to the rest of the page. */
.play-tools {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.play-tool {
  position: relative;
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  padding: 10px 12px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: transparent;
  font: inherit; cursor: pointer; color: var(--text-secondary);
  transition: background .15s ease, color .15s ease;
}
.play-tool:hover { background: var(--surface-3); color: var(--text-primary); }
.play-tool.is-active {
  background: var(--surface-3); color: var(--text-primary);
}
/* An active marker that survives a monochrome print or CVD - position, not hue. */
.play-tool.is-active::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 2px; border-radius: 2px; background: var(--series-1);
}
.tool-name { font-family: var(--mono); font-size: 13px; font-weight: 500; }
.tool-hint { font-size: 11.5px; }

.play-main { display: grid; gap: 16px; min-width: 0; }

.play-form {
  padding: 20px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.play-inputs { display: grid; gap: 14px; }
.field { display: grid; gap: 6px; }
.field label { font-size: 13px; font-weight: 500; color: var(--text-secondary); }
.field input, .field select {
  width: 100%; min-height: 40px; padding: 0 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--page); color: var(--text-primary);
  font: inherit; font-size: 14px;
  font-family: var(--mono);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field input:focus, .field select:focus {
  outline: none; border-color: var(--series-1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--series-1) 24%, transparent);
}
.field .field-note { font-size: 12px; color: var(--text-muted); }
/* Stand-in for the form when the selected tool takes no arguments. */
.field-empty { font-size: 13.5px; }

.play-actions { display: flex; gap: 10px; margin-top: 18px; flex-wrap: wrap; }

.play-output {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.play-output-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px; border-bottom: 1px solid var(--border);
  font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
}
/* min-height reserves the result area before anything runs: it squares the
   right column up with the tool sidebar, and the panel no longer jumps a
   couple of hundred pixels the first time output lands. */
.play-pre {
  margin: 0; padding: 18px;
  font-family: var(--mono); font-size: 13px; line-height: 1.65;
  white-space: pre-wrap; word-break: break-word;
  color: var(--text-secondary);
  min-height: 168px;
  max-height: 460px; overflow: auto;
}
.play-pre strong { color: var(--text-primary); font-weight: 600; }
.play-pre.is-error { color: color-mix(in srgb, var(--critical) 80%, var(--text-primary)); }

/* status line with icon + label - status never carried by color alone */
.status-line { display: flex; align-items: center; gap: 8px; font-family: var(--font); font-size: 13.5px; }

/* ============================================================================
   tool cards
   ========================================================================= */

/* Flex rather than grid: with 7 cards a 3-column grid orphans the last one
   beside two empty tracks. Flex lets it grow to fill the row, so the odd
   count reads as intentional at any width. */
.cards { display: flex; flex-wrap: wrap; gap: 16px; }
.cards > .card { flex: 1 1 280px; }
.card {
  padding: 20px; background: var(--surface-1);
  border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color .15s ease, transform .15s ease;
}
.card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.card-name { font-family: var(--mono); font-size: 13.5px; font-weight: 600; margin-bottom: 8px; }
.card-desc { font-size: 13.5px; color: var(--text-secondary); }
.card-tag {
  display: inline-block; margin-top: 12px; padding: 3px 9px;
  border-radius: 999px; font-size: 11.5px; font-weight: 500;
  border: 1px solid var(--border); color: var(--text-muted);
}
/* View-key tools are not runnable in the browser by design; mark them so the
   catalog does not read as a list of things the playground can do. */
.card-tag.is-key {
  border-color: color-mix(in srgb, var(--series-2) 45%, transparent);
  color: var(--series-2);
}

/* ============================================================================
   install
   ========================================================================= */

/* One card per step, stacked; the middle card hosts the client tabs. */
.install-steps { display: grid; gap: 16px; }

/* The picker renders one snippet per client, because every client has its own
   config file and three of them use a different top-level key. */
.client-tabs {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 12px 16px 0;
}
.client-tab {
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--border); background: transparent;
  font: inherit; font-size: 12.5px; font-weight: 500;
  color: var(--text-secondary); cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.client-tab:hover { background: var(--surface-3); color: var(--text-primary); }
/* Active state is fill + a stronger border, never hue alone, so it survives a
   monochrome print and reads the same under any CVD. */
.client-tab.is-active {
  background: var(--surface-3); color: var(--text-primary);
  border-color: var(--text-muted); font-weight: 600;
}

.client-panel { padding: 12px 16px 16px; }
.client-where { font-size: 13px; color: var(--text-secondary); }
.client-note { font-size: 12.5px; margin-top: 10px; }
.install-foot { margin-top: 18px; font-size: 13.5px; line-height: 1.6; }
.install-foot code {
  font-family: var(--mono); font-size: 12px;
  background: var(--surface-2); padding: 2px 6px;
  border: 1px solid var(--border); border-radius: 4px;
}
.install-foot a { color: var(--series-1); }
.code-card {
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
}
.code-head {
  padding: 12px 16px; border-bottom: 1px solid var(--border);
  font-size: 12px; font-weight: 600; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: .05em;
}
/* Wrap instead of scroll. These are commands to copy, and a horizontal
   scroller hid the tail of the longest one (".../dist/i") with no affordance
   that anything was cut. */
.code { margin: 0; padding: 16px; white-space: pre-wrap; overflow-wrap: anywhere; }
.code code { font-family: var(--mono); font-size: 12.5px; line-height: 1.7; color: var(--text-secondary); }

/* ============================================================================
   footer
   ========================================================================= */

.footer { border-top: 1px solid var(--border); margin-top: 40px; }
.footer-inner {
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding-block: 24px; font-size: 13px;
}
/* Underlined, because this is the one link in the footer and a colour shift
   alone would be the only thing marking it - hue is never the sole signal. */
.foot-link { color: var(--text-secondary); text-decoration: underline; }
.foot-link:hover { color: var(--text-primary); }

/* ============================================================================
   multi-page chrome
   The playground, catalog and install guide became their own pages, so each
   needs a header of its own and a way back out at the bottom. These are the
   pieces the landing page's hero and sections do not cover.
   ========================================================================= */

/* A sub-page hero: same vertical rhythm as .hero, one column, no figure. */
.page-hero { padding-block: 56px 36px; border-bottom: 1px solid var(--border); }
.page-hero h1 {
  font-size: clamp(28px, 3.6vw, 40px);
  margin-bottom: 16px;
  text-wrap: balance;
}
.page-hero .lede { max-width: 66ch; }
.page-hero-note { margin-top: 16px; font-size: 13.5px; max-width: 66ch; }
.page-hero-note a { color: var(--series-1); }
.page-hero .doc-meta { margin-top: 20px; }

/* First section after a .page-hero. The hero already drew the separating rule,
   so this one must not draw a second one 40px below it. */
.section-flush { padding-block: 36px 0; }

/* The way onward from a leaf page. Not a nav - these are the two or three
   places someone actually goes after reading, named by destination. */
.next-row {
  display: flex; flex-wrap: wrap; gap: 12px 28px;
  padding-top: 4px;
}
.next-link {
  font-size: 14.5px; font-weight: 500;
  color: var(--series-1); text-decoration: none;
  display: inline-flex; align-items: center; min-height: 32px;
}
.next-link:hover { text-decoration: underline; }

/* ============================================================================
   landing: spec strip
   Four fixed facts directly under the hero. A <dl> because each one is a
   term and its value, which is also how a screen reader should read it.
   ========================================================================= */

.strip-wrap { padding-bottom: 8px; }

.strip {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px; margin: 0;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.strip-item { background: var(--surface-1); padding: 18px 20px; }
.strip dt {
  font-size: 11.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 6px;
}
.strip dd {
  margin: 0; font-size: 17px; font-weight: 600;
  letter-spacing: -0.02em; color: var(--text-primary);
}

/* ============================================================================
   landing: value props
   ========================================================================= */

.props {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}
.prop {
  padding: 24px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.prop h3 { font-size: 17px; margin-bottom: 10px; }
.prop p { font-size: 14.5px; }

/* A numbered mark rather than an icon: three abstract glyphs would have to be
   invented and would carry less meaning than the order already does. */
.prop-mark {
  display: grid; place-items: center;
  width: 30px; height: 30px; margin-bottom: 16px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--series-1) 16%, transparent);
  color: var(--series-1);
  font-size: 13px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.prop-mark::before { content: attr(data-mark); }

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .prop-mark { background: var(--surface-3); }
}

/* ============================================================================
   landing: route cards
   The three pages this one used to contain.
   ========================================================================= */

.routes {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}
.route {
  display: flex; flex-direction: column;
  padding: 24px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-decoration: none;
  transition: border-color .15s ease, transform .15s ease, background .15s ease;
}
.route:hover {
  border-color: var(--border-strong);
  background: var(--surface-2);
  transform: translateY(-2px);
}
.route-kicker {
  font-size: 11.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase;
}
.route-title {
  font-size: 20px; font-weight: 600; letter-spacing: -0.02em;
  margin: 8px 0 10px;
}
.route-desc { font-size: 14.5px; }
/* Pushed to the bottom so the arrow line sits flush across all three cards
   regardless of how long each description runs. */
.route-go {
  margin-top: auto; padding-top: 18px;
  font-size: 14px; font-weight: 600; color: var(--series-1);
}

/* ============================================================================
   catalog page: groups
   ========================================================================= */

.cat-group + .cat-group { margin-top: 44px; }
.cat-head {
  display: flex; align-items: baseline; gap: 12px;
  margin-bottom: 6px;
}
.cat-head h2 { font-size: 20px; letter-spacing: -0.02em; }
.cat-count { font-size: 12.5px; font-variant-numeric: tabular-nums; }
.cat-blurb { font-size: 14.5px; max-width: 72ch; margin-bottom: 18px; }

/* ============================================================================
   responsive
   ========================================================================= */

@media (max-width: 960px) {
  .strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .props, .routes { grid-template-columns: 1fr; gap: 14px; }
  .route-go { padding-top: 14px; }
  .hero { grid-template-columns: 1fr; gap: 40px; padding-block: 48px 40px; }
  .hero h1 { max-width: none; }
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .play { grid-template-columns: 1fr; }
  /* A 2-column grid instead of a horizontal scroller: the scroller clipped
     tool names mid-word and hid options behind an edge with no affordance. */
  .play-tools {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px; padding: 6px;
  }
  .play-tool { min-height: 44px; }
  .play-tool .tool-name { font-size: 12px; overflow-wrap: anywhere; }

  #nav-toggle { display: inline-grid; }
  .topbar-right { margin-left: auto; }

  /* The nav collapses into a panel rather than disappearing. It used to be
     display:none here, which left every section on the page unreachable from a
     phone. Positioned against .topbar (sticky, so it is the containing block)
     so the panel spans the full width instead of the centred wrap. */
  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    display: none; flex-direction: column; gap: 2px;
    margin: 0; padding: 8px;
    background: var(--surface-1);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow);
  }
  .nav.is-open { display: flex; }
  .nav a { padding: 12px 14px; font-size: 15px; }
}

/* Below this the bar runs out of room for brand + status + two controls, so the
   pill keeps its dot and drops its text. setConn mirrors the label into
   aria-label, so the state stays available to a screen reader either way. */
@media (max-width: 480px) {
  .conn {
    width: 36px; height: 36px; min-height: 36px;
    padding: 0; justify-content: center;
  }
  .conn #conn-label { display: none; }
  /* Same reason, one control further: the repo link is the most droppable
     thing in the bar because the footer carries it as text on every page.
     Collapsing the pill alone no longer buys back enough width here. */
  .gh-link { display: none; }

  /* The switch stays - it is the only place the network can be changed, and the
     footer names the active one but cannot change it. It gives up padding
     instead, which is enough because the pill and the repo link above have
     already freed the width. */
  .net-opt { padding: 4px 8px; font-size: 12px; }
}

/* Under ~400px even the shortened switch competes with the brand, so drop the
   inactive option and keep the active one as a tappable pill. The alternative
   name is lost, so the group gets an explicit accessible name here - "Testnet"
   alone would otherwise read as a label rather than a control.

   This was 380px and was 20px too generous. At 390px - iPhone 12/13/14 Pro,
   one of the most common viewports there is - both options still rendered and
   .topbar-right measured 280px against a 390px viewport, pushing the page 6px
   wider than the screen. 375px passed (below the old breakpoint) and 430px
   passed (enough room for both), so the defect sat in a ~16px window that
   happened to contain a very popular phone. Measured at 400px the bar has
   8px of slack. theme.js runs the matching matchMedia query and both have to
   move together. */
@media (max-width: 400px) {
  .net-opt { display: none; }
  .net-opt.is-active { display: inline-grid; }
}

@media (max-width: 560px) {
  /* Two tiles per row, not one - one column made the page needlessly long. */
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .tile { padding: 14px; }
  .tile-value { font-size: 21px; }
  .tile-label { font-size: 11.5px; }
  .tile-delta { font-size: 11px; }
  .play-tools { grid-template-columns: 1fr; }
  .wrap {
    padding-inline: max(18px, env(safe-area-inset-left)) max(18px, env(safe-area-inset-right));
  }
  .hero h1 { font-size: clamp(26px, 7.6vw, 34px); }
  .lede { font-size: 15.5px; }
  .section { padding-block: 40px; }
  .hero-figure { padding: 20px; }
  /* Table cells shed side padding before they force a page-level scroll. */
  .feed-table th, .feed-table td { padding-inline: 14px; }
  /* The hash was clipped mid-string at this width and unreadable anyway.
     Drop the column outright rather than showing a truncated fragment;
     height, time and tx count all stay, and each row still links out. */
  .feed-table th:nth-child(4), .feed-table td:nth-child(4) { display: none; }
  /* No sidebar to line up with once the columns stack, so drop the reserved
     height rather than pad the page with an empty box. */
  .play-pre { font-size: 12.5px; padding: 14px; min-height: 0; }
  .footer-inner { flex-direction: column; gap: 6px; }
}

/* Long unbroken strings - addresses, hashes, program source - must wrap or
   scroll inside their own box, never widen the page. */
.play-pre, .code, .hash { overflow-wrap: anywhere; }
.code { -webkit-overflow-scrolling: touch; }

/* focus visibility everywhere */
:focus-visible {
  outline: 2px solid var(--series-1);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ============================================================================
   touch sizing
   Every interactive element clears 44x44 on a coarse pointer. Inline links
   inside table rows grow into the cell's padding with a negative margin, so
   the hit area reaches 44px without inflating row height.
   ========================================================================= */

@media (pointer: coarse) {
  .brand { min-height: 44px; }

  .btn-primary, .btn-secondary { min-height: 46px; padding-inline: 22px; }

  .nav a { min-height: 44px; display: flex; align-items: center; }

  /* The footer's repo link measured 102x17 - the one target under 44px in every
     audit run since the footer was written. It is a real link on every page, so
     it gets a real hit area; the row is already a flex column on a phone, so
     growing it costs no layout. .next-link is new and would have landed in the
     same place. */
  .foot-link, .next-link {
    display: inline-flex; align-items: center; min-height: 44px;
  }

  /* The docs table of contents: ten full-width rows at 33px. Width was never
     the problem, so this only buys back height. */
  .doc-toc a { min-height: 44px; display: flex; align-items: center; }

  .feed-table td { padding-block: 12px; }
  .feed-table td a {
    display: inline-flex; align-items: center;
    min-height: 44px; margin-block: -12px;
    padding-inline: 2px;
  }

  .field input, .field select { min-height: 46px; }

  .play-tool { min-height: 48px; justify-content: center; }

  /* Pills are short strings, so height alone is not enough to clear 44px in
     both axes - the narrow ones ("Zed", "Cursor") need the width too. */
  .client-tab { min-height: 44px; min-width: 44px; padding-inline: 16px; }

  /* The inline "docs" link grows into the paragraph's leading rather than
     forcing the line taller, same trick as the links in the block feed. */
  .install-foot a {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; min-width: 44px; margin-block: -12px; padding-inline: 2px;
  }

  .conn { min-height: 36px; }
}

/* ============================================================================
   docs page
   ========================================================================= */

.doc-hero { padding-block: 56px 32px; border-bottom: 1px solid var(--border); }
.doc-hero h1 {
  font-size: clamp(30px, 4vw, 42px); margin-bottom: 14px; text-wrap: balance;
}
.doc-hero .lede { max-width: 62ch; }

.doc-meta {
  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px;
}
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface-2);
  font-size: 12.5px; font-weight: 500; color: var(--text-secondary);
}
.badge code { font-family: var(--mono); font-size: 12px; color: var(--text-primary); }

.doc-shell {
  display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 48px;
  align-items: start; padding-block: 44px 72px;
}

/* Sticky so the reader never loses their place in a long reference. */
.doc-toc {
  position: sticky; top: 88px;
  max-height: calc(100vh - 120px); overflow-y: auto;
}
.doc-toc-title {
  font-size: 11.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--text-muted); margin-bottom: 10px;
}
.doc-toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.doc-toc a {
  display: block; padding: 7px 12px; border-radius: var(--radius-sm);
  border-left: 2px solid transparent;
  color: var(--text-secondary); text-decoration: none;
  font-size: 13.5px; line-height: 1.4;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.doc-toc a:hover { background: var(--surface-3); color: var(--text-primary); }
/* Position and weight, not hue alone, so the marker survives CVD and print. */
.doc-toc a.is-current {
  background: var(--surface-3); color: var(--text-primary);
  border-left-color: var(--series-1); font-weight: 600;
}

.doc-body { min-width: 0; max-width: 74ch; }
.doc-section { scroll-margin-top: 92px; }
.doc-section + .doc-section { margin-top: 52px; }
.doc-section > h2 {
  font-size: 24px; letter-spacing: -0.02em;
  padding-bottom: 10px; border-bottom: 1px solid var(--border);
  margin-bottom: 18px;
}
.doc-section h3 {
  font-size: 16px; margin-top: 30px; margin-bottom: 10px;
  font-family: var(--mono); font-weight: 600; letter-spacing: 0;
}
.doc-body p { margin-bottom: 14px; color: var(--text-secondary); font-size: 15px; }
.doc-body p strong { color: var(--text-primary); font-weight: 600; }
.doc-body > .doc-section > p:last-child { margin-bottom: 0; }

.doc-body ul { margin: 0 0 16px; padding-left: 22px; }
.doc-body li { color: var(--text-secondary); font-size: 15px; margin-bottom: 7px; }
.doc-body li strong { color: var(--text-primary); font-weight: 600; }

.doc-body code {
  font-family: var(--mono); font-size: 13px;
  padding: 1.5px 5px; border-radius: 4px;
  background: var(--surface-3); color: var(--text-primary);
  overflow-wrap: anywhere;
}
.doc-body a:not(.badge) {
  color: var(--series-1); text-decoration: underline;
  text-underline-offset: 2px; text-decoration-thickness: 1px;
}

/* Reference tables scroll inside their own box, never widening the page. */
.doc-table-wrap {
  overflow-x: auto; margin-bottom: 18px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1);
}
.doc-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.doc-table th {
  text-align: left; font-weight: 500; font-size: 11.5px;
  text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted);
  padding: 11px 16px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.doc-table td {
  padding: 12px 16px; border-bottom: 1px solid var(--grid);
  color: var(--text-secondary); vertical-align: top;
}
.doc-table tbody tr:last-child td { border-bottom: none; }
.doc-table td:first-child { white-space: nowrap; }
.doc-table td code { white-space: nowrap; }

/* A callout carries an icon and a heading, so the meaning never rests on the
   left border's hue alone. */
.callout {
  display: grid; grid-template-columns: 20px minmax(0, 1fr);
  gap: 12px; align-items: start;
  padding: 15px 17px; margin-bottom: 18px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-muted);
  border-radius: var(--radius);
  background: var(--surface-1);
}
.callout svg { width: 20px; height: 20px; margin-top: 1px; color: var(--text-muted); }
.callout-title { font-size: 14px; font-weight: 600; margin-bottom: 4px; }
.callout p { margin: 0; font-size: 14px; }
.callout p + p { margin-top: 8px; }
.callout.is-warn { border-left-color: var(--warning); }
.callout.is-warn svg { color: var(--warning); }
.callout.is-key { border-left-color: var(--series-2); }
.callout.is-key svg { color: var(--series-2); }

/* Steps are numbered by counter so inserting one never renumbers by hand. */
.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
.steps > li {
  position: relative; counter-increment: step;
  padding-left: 40px; margin-bottom: 24px;
}
.steps > li::before {
  content: counter(step);
  position: absolute; left: 0; top: 0;
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--surface-3); border: 1px solid var(--border);
  color: var(--text-primary); font-size: 12.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.step-title { font-size: 15px; font-weight: 600; margin-bottom: 8px; }

.doc-body .code-card { margin-bottom: 14px; }
.doc-body .code-card:last-child { margin-bottom: 0; }

@media (max-width: 960px) {
  .doc-shell { grid-template-columns: 1fr; gap: 28px; padding-block: 32px 56px; }
  /* Sticky is wrong once it is a full-width block at the top of the flow. */
  .doc-toc {
    position: static; max-height: none;
    padding: 12px; border: 1px solid var(--border);
    border-radius: var(--radius); background: var(--surface-1);
  }
  .doc-toc ol { grid-template-columns: repeat(2, minmax(0, 1fr)); display: grid; }
}

@media (max-width: 560px) {
  .doc-hero { padding-block: 36px 26px; }
  .doc-shell { padding-block: 26px 44px; }
  .doc-section + .doc-section { margin-top: 40px; }
  .doc-section > h2 { font-size: 21px; }
  .doc-toc ol { grid-template-columns: 1fr; }
  .doc-body p, .doc-body li { font-size: 14.5px; }
  .steps > li { padding-left: 34px; }
  .steps > li::before { width: 23px; height: 23px; font-size: 12px; }
}
