/* Runix — international SaaS stylesheet (light, flagship) */

/* Archivo, served from our own origin rather than a font CDN: one less pair of
   DNS+TLS round trips in front of first paint, and no visitor IP handed to a
   third party on a site that sells to EU buyers. That is why the face is
   self-hosted; it is not a reason to keep any particular face.

   Replaced Inter on 2026-09-04. Inter is the face every AI-generated interface
   reaches for — legible, and anonymous with it. Archivo is a variable grotesque
   from Omnibus-Type: tighter apertures and a squarer, more editorial skeleton,
   so headlines set denser and hold their colour at 800 where Inter goes soft.
   SIL Open Font License. 68 KB across both subsets against Inter's 133 KB, and
   one file per subset covers the whole 400-800 range this type scale uses, so
   nothing here changes weight.

   Instrument Sans was tried first and reverted the same day: it sits on the
   same overused-font list as Inter, one wave later. Archivo does not. */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/archivo-latin.woff2?v=2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/archivo-latin-ext.woff2?v=2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bg: #ffffff;
  --bg-alt: #f5f5f7;
  --ink: #0d1117;
  --ink-2: #48505e;
  --ink-3: #676f7b;
  --line: rgba(13, 17, 23, 0.07);
  --line-2: rgba(13, 17, 23, 0.11);
  --on-accent: #ffffff;
  --indigo: #4a5bd6;
  --cyan: #0b96b8;
  /* Same hue, dark enough to pass AA as text on the tinted panels too (5.4:1 on white).
     --cyan itself stays put: it carries the gradient and the borders. */
  --cyan-text: #08748d;
  /* --indigo is 5.59:1 on paper but 4.4:1 once it sits on its own tint, which
     is where the chips and badges put it. This is the same hue for text on
     those tinted surfaces. */
  --indigo-ink: #3c49ad;
  /* Same hues as --indigo/--cyan: the light theme needs stops that stay legible
     as text on white, which the brighter dark-theme gradient did not. */
  /* The cyan end was #0b96b8, against which white text measures 3.46:1 — under
     AA, on every primary button, step number, "Most teams" flag and "Save 25%"
     chip the gradient fills. Measured 2026-09-04 across 57 pages. #08748d is
     the same hue already in the palette as --cyan-text and takes white to
     5.39:1; the indigo end was always fine at 5.59:1, so the ramp now passes
     end to end instead of only at one end. */
  --grad: #4a5bd6;
  /* 2026-09-29 flagship pass: a wider canvas, a tighter corner and a quieter
     shadow. 18px corners and a 34px blur read as a consumer app; the pages
     this site is measured against (cloud and infrastructure vendors) use
     10-14px corners and let hairlines, not shadows, carry the structure. */
  --radius: 14px;
  --radius-sm: 10px;
  --maxw: 1200px;
  --mono: "SF Mono", ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;
  --shadow: 0 1px 2px rgba(13, 17, 23, 0.04), 0 12px 32px -16px rgba(13, 17, 23, 0.14);
  /* Display type. One weight for every headline so the page reads as one
     voice; 640 sits between the 600 that looked soft at 72px and the 700-800
     that made every section shout. */
  --display-weight: 640;
  --ink-4: #8a919c;
  --panel: #0b0e14;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
  line-height: 1.7;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; transition: all 0.18s; }
.container { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
h1, h2, h3 { letter-spacing: -0.025em; line-height: 1.2; }
/* Headings without a deliberate .line break get balanced instead of
   leaving one orphaned word on the last line. */
/* h1 was missing from this list, so article titles could drop a one-word
   last line while every h2 below them balanced correctly. Most titles
   happen to break evenly, which is why it showed on one page and the
   gap was in the rule for all of them. */
h1, h2, h3, .section-head h2 { text-wrap: balance; }
/* A headline broken across lines without gluing the words together
   when the text is extracted. */
.line { display: block; }

.badge {
  display: inline-flex; align-items: center; gap: 8px;
  /* Sentence case, not tracked caps. Every surviving badge is a phrase, not a
     label — "For small teams buying 30–50 seats" is 34 characters, and caps
     strip the ascender/descender shapes a reader recognises words by. Caps
     stay where a label is two or three words (.layer-state, .cat, .flag). */
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.01em;
  color: var(--indigo-ink); background: rgba(107, 149, 255, 0.10);
  border: 1px solid rgba(107, 149, 255, 0.24);
  padding: 6px 14px; border-radius: 999px; margin-bottom: 20px;
}
/* The seven surviving badges name a product and its availability stage
   ("Runix Router · Early access"). They now sit *under* their h1 rather than
   above it — a status chip attached to the headline instead of a kicker
   introducing it — so the margin flips to the top. The decorative ones that
   only restated the page title ("Legal" over "Privacy Policy") are gone. */
h1 + .badge, h3 + .badge { margin: 14px 0 0; }
/* The home page headline reads "AI, / made effortless." — the second line used
   to be filled with the brand gradient via background-clip. Gradient text is
   decoration doing the job weight and colour already do, and it forces the
   word through a stop that measures 3.4:1 at the cyan end. One solid indigo
   at 5.59:1 carries the same emphasis and survives selection, high-contrast
   mode, and print, none of which render clipped backgrounds. */
.grad-text { color: var(--indigo); }

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: saturate(1.6) blur(16px);
  border-bottom: 1px solid var(--line);
}
.nav {
  display: flex; align-items: center; gap: 36px;
  height: 64px; max-width: var(--maxw); margin: 0 auto; padding: 0 24px;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 18.5px; letter-spacing: -0.025em; }
.brand .mark {
  width: 28px; height: 28px; flex: none; display: inline-block;
  background: url("logo.svg?v=3") center / contain no-repeat;
  font-size: 0; color: transparent; /* hide the fallback letter */
}
.nav-links { display: flex; gap: 28px; align-items: center; margin-left: auto; }
.nav-links a { color: var(--ink-2); font-size: 14.5px; font-weight: 500; }
.nav-links a:hover, .nav-links a.active { color: var(--ink); }
.nav-cta {
  background: var(--ink); color: var(--on-accent) !important; padding: 9px 18px;
  border-radius: 980px; font-weight: 600; font-size: 14px !important;
}
/* Colour change, not a lift. A header button that jumps on hover is the
   motion of a landing-page template; the fill deepening is enough to say
   "this is live" and it does not move the bar under the pointer. */
.nav-cta:hover { background: #262b36; }
.nav-toggle { display: none; margin-left: auto; background: none; border: none; color: var(--ink); cursor: pointer; padding: 6px; align-items: center; }

/* Products menu. Opens on hover and on keyboard focus with CSS alone, so it
   needs no script on a desktop; "Products" itself stays a real link to the
   product index, which is where a touch or no-script visitor lands. The panel
   is display:none until opened rather than visibility-hidden: a laid-out but
   invisible panel still has boxes, and the render checks would read five
   covered links under the header on every page. */
.nav-menu { position: relative; display: flex; align-items: center; }
.nav-menu-top { display: inline-flex; align-items: center; gap: 6px; }
.nav-menu-top::after {
  content: ""; width: 6px; height: 6px; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); opacity: 0.55;
}
.nav-panel {
  display: none; position: absolute; top: 100%; left: -28px; z-index: 110;
  width: 560px; padding: 10px; margin-top: 14px;
  grid-template-columns: 1fr 1fr; gap: 2px;
  background: #fff; border: 1px solid var(--line-2); border-radius: var(--radius);
  box-shadow: 0 24px 60px -24px rgba(13, 17, 23, 0.28), 0 2px 6px rgba(13, 17, 23, 0.04);
}
/* A hover bridge: the panel sits 14px below the link, and without this strip
   the pointer crosses a gap that closes the menu on its way down. */
.nav-panel::before { content: ""; position: absolute; left: 0; right: 0; top: -16px; height: 16px; }
.nav-menu:hover .nav-panel, .nav-menu:focus-within .nav-panel { display: grid; }
.nav-links .nav-prod {
  display: grid; gap: 2px; padding: 12px 14px; border-radius: var(--radius-sm);
  color: var(--ink); font-size: 14px;
  /* Without this a short entry is stretched to its row-mate's height and its
     title drifts down, so two titles in one row stop sharing a baseline. */
  align-content: start;
}
.nav-links .nav-prod:hover, .nav-links .nav-prod:focus-visible { background: var(--bg-alt); }
.nav-prod b { font-weight: 650; font-size: 14.5px; display: flex; align-items: center; gap: 8px; }
.nav-prod span { color: var(--ink-3); font-size: 13px; line-height: 1.45; }
.nav-prod i {
  font: 600 12px/1 var(--mono); font-style: normal; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--indigo-ink); background: rgba(74, 91, 214, 0.08);
  border: 1px solid rgba(74, 91, 214, 0.3); border-radius: 999px; padding: 2px 6px;
}

/* ---------- Hero ---------- */
.hero { position: relative; padding: 132px 0 116px; overflow: hidden; }
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(820px 420px at 12% -8%, rgba(91, 140, 255, 0.07), transparent 64%),
    radial-gradient(720px 380px at 90% 4%, rgba(34, 211, 238, 0.05), transparent 64%);
}
.hero .container { position: relative; }
.hero h1 { font-size: 62px; font-weight: var(--display-weight); max-width: 820px; letter-spacing: -0.04em; }
.hero .sub { margin-top: 26px; font-size: 20px; line-height: 1.6; color: var(--ink-2); max-width: 640px; }
.hero .actions { margin-top: 38px; display: flex; gap: 12px; flex-wrap: wrap; }
.btn {
  display: inline-block; padding: 13px 26px; border-radius: 980px;
  font-size: 15px; font-weight: 600; transition: background-color 0.18s, border-color 0.18s, color 0.18s;
  border: 1px solid transparent; letter-spacing: -0.005em;
}
/* No lift on hover (2026-09-29). Every button on the site jumped 2px and
   grew a shadow; on a page with three of them that is motion competing with
   the copy. The fill shifts instead, which is what a pressed material does. */
.btn-primary { background: var(--ink); color: var(--on-accent); }
.btn-primary:hover { background: #262b36; }
.btn-grad { background: var(--grad); color: var(--on-accent); }
.btn-grad:hover { background: var(--indigo-ink); }
.btn-ghost { border-color: var(--line-2); color: var(--ink); background: #fff; }
.btn-ghost:hover { border-color: var(--ink-3); background: rgba(13, 17, 23, 0.03); }

/* ---------- Code card ---------- */
.code-card {
  margin-top: 64px; background: #05080f; border-radius: var(--radius);
  border: 1px solid var(--line-2); box-shadow: var(--shadow);
  overflow: hidden; max-width: 860px;
}
.code-card .bar {
  display: flex; align-items: center; gap: 6px;
  padding: 12px 18px; border-bottom: 1px solid var(--line);
}
.code-card .dot { width: 11px; height: 11px; border-radius: 50%; background: #2a3441; }
.code-card .bar span { margin-left: 10px; color: #8b95a1; font-size: 12.5px; font-family: "SF Mono", Menlo, monospace; }
.code-card pre {
  /* 18px matches .bar above, so the first character of the code lines up
     with the filename. They were 24 and 18 -- which read as a slip, and
     also left the sample 5px too narrow for the real endpoint URL. */
  padding: 22px 18px; overflow-x: auto;
  font-family: "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.5px; line-height: 1.9; color: #c9d1d9;
}
.code-card .c { color: #78828f; } .code-card .k { color: #79b8ff; } .code-card .s { color: #7ee2a8; }

/* ---------- Logos / stats strip ---------- */
.strip { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--bg-alt); }
.strip .row {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px;
  max-width: var(--maxw); margin: 0 auto; padding: 34px 24px;
}
.strip .cell { text-align: center; }
.strip b { display: block; font-size: 26px; font-weight: 800; letter-spacing: -0.02em; }
.strip span { color: var(--ink-3); font-size: 13px; }

/* ---------- Sections ---------- */
.section { padding: 128px 0; }
.section.alt { background: var(--bg-alt); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.section.alt + .section.alt { border-top: 0; }
.section-head { max-width: 680px; margin-bottom: 64px; }
.section-head.center { text-align: center; margin-left: auto; margin-right: auto; }
.section-head h2 { font-size: 44px; font-weight: var(--display-weight); letter-spacing: -0.035em; line-height: 1.1; }
/* The deck under a section heading rendered 640px / 85 characters a line at
   16.5px. The heading keeps the full 640px -- it is short and wants the room
   for a balanced two-line break -- and the deck is held to 585px / 78. */
.section-head p { margin-top: 18px; color: var(--ink-2); font-size: 17.5px; line-height: 1.7; max-width: 600px; }
.section-head.center p { margin-left: auto; margin-right: auto; }

/* ---------- Product cards ---------- */
.grid { display: grid; gap: 28px; }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
.cols-2 { grid-template-columns: repeat(2, 1fr); }
.card {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 34px 32px; transition: all 0.2s;
}
/* Hairline, not lift: the border darkens to say the card is live. */
.card:hover { border-color: var(--line-2); }
/* The icon sits in the margin beside the title, not in a tinted rounded square
   stacked on top of it (2026-09-04). A 44px tile above a heading is the
   feature-card shape every UI generator emits; forty of them across seven
   pages is the shape a reader recognises before they read a word. Absolute
   placement keeps this working for a card with any number of children — the
   title indents to clear the icon, the body copy starts at the full measure. */
.card { position: relative; }
.card .icon {
  position: absolute; left: 30px; top: 31px;
  width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
}
.card .icon svg { width: 24px; height: 24px; stroke: var(--indigo); }
.card h3 { font-size: 19px; font-weight: 650; margin-bottom: 10px; padding-left: 38px; min-height: 26px; letter-spacing: -0.02em; }
/* The icon is positioned against the top of the card, so on the four product
   cards — the only ones carrying a layer label above the title — it landed on
   that label and sat on top of its first letter. The label clears it the same
   way the title does. */
.card:has(.card-layer) h3 { min-height: 0; }
/* A job description is the longest prose on the site outside the blog, and its
   card spans the full container: measured on the deployed /careers at 1010px,
   122 characters a line. The card keeps its width -- it holds a title row and
   a meta row that want the room -- and the copy inside it is held to 72ch. */
.card > p, .card > ul { max-width: 60ch; }  /* 498px, 78 characters a line */
/* Links in body copy.
   Third attempt at this selector, and the first that is not a list of places a
   link might live. Enumerating containers missed <li>, then .facts, then three
   inline style= overrides, then <span> — each time the fix looked complete.
   So: every link in the main content is a body link by default, and the
   exceptions are named. The exception set is small and stable; the container
   set is neither. */
main a:not(.btn) { color: var(--indigo); font-weight: 600; }

/* Colour alone does not mark a link (WCAG 1.4.1): --indigo on --ink-2 body copy
   measures 1.45:1, against the 3:1 the criterion wants when colour is the only
   cue — and no usable indigo reaches 3:1 without wrecking the brand colour.
   Underline is the non-colour cue it actually asks for. */
main a:not(.btn) {
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 2px; text-decoration-color: rgba(74, 91, 214, 0.4);
}
main a:not(.btn):hover { text-decoration-color: currentColor; }

/* Exceptions: surfaces where the whole element is the affordance, so an
   underline would be noise rather than a cue. */
/* Exceptions: surfaces where the whole element is the affordance.
   Every selector here carries :not(.btn) so it out-specifies the body-link
   rule above — which is (0,1,2). `main .read-more` alone is (0,1,1) and loses,
   and `main nav a` is (0,0,3) and loses badly; both were written that way
   first and silently did nothing. Measured, not assumed. */
main a.card:not(.btn), main a[class*="card-clickable"]:not(.btn),
main nav a:not(.btn), main .chips a:not(.btn),
main .doc-toc a:not(.btn), main .doc-next a:not(.btn),
main .layer a:not(.btn), main .compat a:not(.btn), main .facts-head a:not(.btn),
/* A link that is an entire heading, and a card's own "Read post →" affordance,
   are not links inside a sentence — underlining every card title turns an index
   into a wall of rules. The arrow is read-more's non-colour cue. */
main :is(h1, h2, h3, h4) > a:not(.btn), main .read-more:not(.btn) {
  text-decoration: none;
}
main a.card, main a[class*="card-clickable"] { color: inherit; font-weight: inherit; }
main .doc-toc a { color: var(--muted); font-weight: 400; }
main .doc-next a { color: var(--indigo); font-weight: 500; }

.card a:not(.btn):hover, .section-head p a:hover, .feature a:not(.btn):hover,
.pillar a:not(.btn):hover, .plan a:not(.btn):hover,
.card a:not(.btn):focus-visible, .feature a:not(.btn):focus-visible,
.pillar a:not(.btn):focus-visible { text-decoration: underline; }
.card p a:hover, .section-head p a:hover, .feature p a:hover { text-decoration: underline; }
.card p { color: var(--ink-2); font-size: 14.5px; }
.card ul { list-style: none; margin-top: 16px; }
.card ul li { padding: 7px 0 7px 24px; position: relative; color: var(--ink-2); font-size: 14px; }
/* One tick mark, used everywhere except .feature, which keeps the circled
   variant as its deliberate emphasis. */
.card ul li::before, .plan ul li::before, .pillar ul li::before {
  content: "✓"; position: absolute; left: 0; color: var(--cyan); font-weight: 700;
}

/* ---------- Feature rows ---------- */
.feature { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; padding: 40px 0; }
.feature > * { min-width: 0; }
.feature h3 { font-size: 30px; font-weight: var(--display-weight); letter-spacing: -0.03em; margin-bottom: 14px; }
.feature p { color: var(--ink-2); }
.feature ul { list-style: none; margin-top: 18px; }
.feature ul li { padding: 8px 0 8px 30px; position: relative; color: var(--ink-2); }
.feature ul li::before {
  content: "✓"; position: absolute; left: 0; top: 10px; width: 18px; height: 18px;
  border-radius: 50%; background: rgba(34, 211, 238, 0.14);
  box-shadow: inset 0 0 0 1.5px var(--cyan);
  display: flex; align-items: center; justify-content: center;
  color: var(--cyan); font-size: 10.5px; font-weight: 700; line-height: 1;
}

/* ---------- Pricing ---------- */
.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; align-items: stretch; }
.plan {
  background: var(--bg); border: 1px solid var(--line); border-radius: 20px; padding: 34px 30px;
  transition: all 0.2s; position: relative;
}
.plan:hover { border-color: var(--line-2); }
.plan.featured { border: 2px solid transparent; background:
  linear-gradient(var(--bg), var(--bg)) padding-box, var(--grad) border-box; }
.plan .flag {
  position: absolute; top: -13px; left: 28px; background: var(--grad); color: var(--on-accent);
  font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 4px 12px; border-radius: 999px;
}
.plan h3 { font-size: 17px; font-weight: 700; }

/* ---- Top-up picker (pricing) ------------------------------------------
   Same surface treatment as .plan so the page reads as one system: --bg on
   --line, 20px radius, gradient border for the selected state. Chosen over a
   third card variant because a top-up is one choice repeated, not four
   products. */
.topup { max-width: 760px; margin: 0 auto; }
.topup-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.topup-opt {
  position: relative; text-align: left; cursor: pointer; font: inherit; color: inherit;
  background: var(--bg); border: 1px solid var(--line); border-radius: 20px;
  padding: 22px 24px; display: grid; gap: 2px; transition: all 0.2s;
}
.topup-opt:hover { border-color: var(--line-2); box-shadow: var(--shadow); }
.topup-opt:focus-visible { outline: 2px solid var(--indigo); outline-offset: 3px; }
.topup-opt.is-selected {
  border: 2px solid transparent; padding: 21px 23px;
  background: linear-gradient(var(--bg), var(--bg)) padding-box, var(--grad) border-box;
}
.topup-name { font-size: 14px; font-weight: 700; color: var(--ink-2); letter-spacing: 0.02em; }
.topup-usd { font-size: 30px; font-weight: 800; letter-spacing: -0.02em; color: var(--ink); }
.topup-sub { font-size: 13px; color: var(--ink-3); }
.topup-flag {
  position: absolute; top: -13px; left: 22px; background: var(--grad); color: var(--on-accent);
  /* 12px is the site's floor for readable text; .plan .flag uses the same. */
  font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 4px 12px; border-radius: 999px;
}
.topup-custom {
  display: grid; gap: 10px; margin-top: 22px; font-size: 14px; color: var(--ink-2);
}
.topup-custom small { color: var(--ink-3); font-size: 12px; }
/* Validation message for the custom amount. Empty until something is wrong, so
   it takes no space in the normal case. Colour is the site's danger ink at a
   size visual_qa will accept (>=12px). */
/* Selector carries the element too: .topup-custom small sets 12px and would
   otherwise win on specificity, which is exactly what happened the first time. */
.topup-custom small.topup-amount-error:empty { display: none; }
.topup-custom small.topup-amount-error { color: #b3261e; font-size: 13px; font-weight: 600; }
/* The message alone was a 12px line sitting directly under another 12px line of
   grey helper text, which is easy to miss while typing. The field itself now
   carries the state too, so the feedback is where the eyes already are.
   :has() lets the wrapper react to its own input; browsers without it still get
   the message and the input's own red border. */
.topup-input:has(input[aria-invalid="true"]) { border-color: #b3261e; }
.topup-input input[aria-invalid="true"] { color: #b3261e; }
.topup-input {
  display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--line-2); border-radius: 12px; padding: 0 14px; background: var(--bg);
}
.topup-input:focus-within { border-color: var(--indigo); }
.topup-input i { font-style: normal; color: var(--ink-3); font-weight: 600; }
.topup-input input {
  flex: 1; border: 0; outline: 0; background: transparent; font: inherit; color: var(--ink);
  padding: 13px 0;
}
.topup-equiv {
  margin-top: 22px; padding: 20px 22px; border-radius: 16px;
  background: var(--bg-alt); border: 1px solid var(--line); font-size: 14px; color: var(--ink-2);
}
/* The measure is held on the copy, not on the card: shrinking the card would
   pull it out of line with the payment block beside it. 714px at 14px is 89
   characters a line, measured on the live page. */
.topup-equiv p { max-width: 68ch; }
.topup-equiv-head {
  font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--cyan-text); margin-bottom: 8px;
}
.topup-equiv b { color: var(--ink); }
/* 714px at 13px is 96 characters a line, measured on the live page -- long for
   a footnote under a number. */
.topup-equiv-note { margin-top: 10px; font-size: 13px; color: var(--ink-3); max-width: 68ch; }
/* Stripe Buy Button block. Mirrors .topup-equiv so the card reads as one
   surface. Stripe renders its button inside an iframe it sizes itself, so this
   only sets the surround; do not try to style stripe-buy-button internals. */
.topup-pay {
  margin-top: 22px; padding: 20px 22px; border-radius: 16px;
  background: var(--bg-alt); border: 1px solid var(--line);
}
.topup-pay[hidden] { display: none; }
.topup-pay-head {
  font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--cyan-text); margin-bottom: 12px;
}
.topup-pay-note { margin-top: 12px; font-size: 13px; color: var(--ink-3); max-width: 68ch; }
/* Payment-method choice. Two links, not a JS-driven radio with one shared
   button: the amount is typed on the provider's own page either way, so there
   is no state on this page worth keeping, and a plain link still works with
   scripting off — which the payment-provider review requires of the pricing.
   The two are visually equal because neither is the recommended one; they
   differ by which methods they accept, and that is what the copy says. */
.paygrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.payopt {
  display: grid; gap: 3px; padding: 16px 18px; border-radius: 14px;
  background: var(--bg); border: 1px solid var(--line-2); color: inherit;
  text-decoration: none; transition: all 0.2s;
  /* One tile is a link and the other is a button. Without this the button falls
     back to the UA's form font — Arial 13.3px next to Inter 16px — and the two
     halves of one control group stop looking like one control group.
     text-align matters for the same reason: buttons centre by default.
     cursor likewise: an <a> is a pointer for free, a <button> is not, and the
     tile that did not change the cursor read as "not clickable" — reported as
     "hovering does nothing, clicking does nothing" when it was in fact live. */
  font: inherit; text-align: left; cursor: pointer;
}
/* Pressed state. The tile is large, so without this a click on a slow network
   looks like nothing happened at all. */
.payopt:active { transform: translateY(1px); border-color: var(--indigo); }
/* Working: the checkout SDK is loading or the intent is being minted. Both take
   a visible moment, and a 12px line of grey text changing at the bottom of the
   card was not enough to tell anyone their click registered. */
.payopt.is-busy {
  border-color: var(--indigo); background: var(--bg-alt); cursor: progress;
  box-shadow: var(--shadow);
}
.payopt.is-busy .payopt-by { color: var(--indigo); font-weight: 700; }
/* Scripting off, or the provider unreachable: the tile must not look clickable.
   Left visible rather than hidden so the option is still discoverable, and the
   text colours are untouched so it stays above the AA threshold visual_qa
   enforces — dimming with opacity would drag every label under it. */
.payopt:disabled {
  cursor: not-allowed; border-style: dashed; background: var(--bg-alt);
  box-shadow: none;
}
.payopt:disabled:hover { border-color: var(--line-2); box-shadow: none; }
.payopt:hover { border-color: var(--indigo); box-shadow: var(--shadow); }
.payopt:focus-visible { outline: 2px solid var(--indigo); outline-offset: 3px; }
.payopt-name { font-size: 15px; font-weight: 700; color: var(--ink); }
.payopt-sub { font-size: 13px; color: var(--ink-2); }
.payopt-by { font-size: 12px; color: var(--ink-3); }
/* Not yet linked. Dashed border and the alt surface, but the same text colours:
   dimming it with opacity would drag every label under the AA threshold that
   visual_qa enforces, and an unavailable option still has to be readable. */
.payopt.is-pending { border-style: dashed; background: var(--bg-alt); }
@media (max-width: 640px) { .paygrid { grid-template-columns: 1fr; } }
.topup-cta { margin-top: 22px; }
.topup-foot { margin-top: 12px; text-align: center; font-size: 13px; color: var(--ink-3); }

@media (max-width: 640px) {
  .topup-grid { grid-template-columns: 1fr; }
  .topup-usd { font-size: 26px; }
}

.plan .price { font-size: 34px; font-weight: 800; margin: 14px 0 2px; letter-spacing: -0.03em; }
.plan .price small { font-size: 13.5px; font-weight: 500; color: var(--ink-3); }
.plan .for { color: var(--ink-3); font-size: 13.5px; }
/* The two lines under a price that turn it into a rate rather than a number:
   what the money buys, and what that works out to per unit. Shared by
   /pricing and /code-plans, which is why they are not page-level rules. */
.plan .credits { margin: 12px 0 4px; font-size: 15px; color: var(--ink); font-weight: 600; white-space: nowrap; }
/* Solid indigo, not gradient-clipped text (2026-09-04). Gradient text is
   decoration where weight and size already carry the emphasis, and it puts
   the glyphs through a ramp whose far end measured 3.46:1. It also breaks
   in high-contrast mode, in print, and under text selection. These four
   were the credit figure, the multiplier, and two diagram headings — the
   numbers a buyer reads off the pricing page. */
.plan .credits b { color: var(--indigo); }
.plan .save { display: block; width: fit-content; margin: 8px 0 0; font: 700 12px/1 var(--mono); letter-spacing: .04em;
  color: var(--on-accent); background: var(--grad); padding: 4px 10px; border-radius: 999px; }
.plan .rate { color: var(--ink-3); font-size: 12.5px; margin: 2px 0 0; }
.plan ul { list-style: none; margin: 22px 0 0; }
.plan ul li { padding: 8px 0 8px 24px; position: relative; color: var(--ink-2); font-size: 14px; border-bottom: 1px solid var(--line); }
/* Cards stretch to the tallest in the row, so the CTA is pinned to the bottom
   instead of floating wherever that card's feature list happens to end. */
.plan { display: flex; flex-direction: column; }
.plan ul { flex: 1 0 auto; }
/* The last row's rule separated the last feature from empty space. Every other
   ruled list on the site (.contact-card .row, .facts .frow) already drops it;
   the plan cards were the one that did not. */
.plan ul li:last-child { border-bottom: none; }
.plan .btn { width: 100%; text-align: center; margin-top: auto; }

/* ---------- CTA band ---------- */
.cta-band {
  position: relative; overflow: hidden; text-align: center;
  background: var(--bg-alt); color: var(--ink); border: 1px solid var(--line); border-radius: 24px; padding: 78px 28px;
}
.cta-band::before {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(560px 280px at 22% 100%, rgba(79, 108, 255, 0.12), transparent 66%),
    radial-gradient(560px 280px at 78% 0%, rgba(34, 211, 238, 0.10), transparent 66%);
}
.cta-band h2 { position: relative; font-size: 40px; font-weight: var(--display-weight); letter-spacing: -0.035em; }
/* Measured on the live page at 1280px: 1014px, 111 characters a line. It is
   one centred sentence under a heading, so it was running the full band width
   for no reason. 60ch is the measure the rest of the page's body copy uses. */
.cta-band p { position: relative; color: var(--ink-2); margin-top: 12px; max-width: 60ch; margin-left: auto; margin-right: auto; }
.cta-band .btn { position: relative; margin-top: 32px; }

/* ---------- Page hero / legal ---------- */
/* The off-centre radial wash is gone (2026-09-04). A saturated-centre glow
   fading to transparent behind a heading is decoration standing in for depth,
   and at 700x300 it stopped well short of a 1280px viewport, so it read as a
   smudge in the top-left rather than as lighting. A flat tinted band that
   resolves into paper grounds the hero without pretending to have a light
   source. */
.page-hero { padding: 104px 0 80px; border-bottom: 1px solid var(--line); background: var(--bg); }
.page-hero h1 { font-size: 52px; font-weight: var(--display-weight); letter-spacing: -0.04em; line-height: 1.08; overflow-wrap: break-word; }
/* 620px rendered 88 characters a line, counted off the line boxes on the
   deployed page. 550px lands at 78. */
.page-hero p { color: var(--ink-2); margin-top: 18px; max-width: 550px; font-size: 18px; line-height: 1.6; }
/* Bare paragraphs sitting straight in a .container inherit no measure at all
   and ran to 96 characters on /comic. Scoped to :not([class]) so the notes
   that carry their own class and centring (.model-note and friends) keep it. */
.container > p:not([class]) { max-width: 550px; }
/* Sized by counting rendered line boxes, not by ch. The ch unit is the width
   of "0", which in a narrow face like Archivo is about a fifth wider than the
   average lowercase letter, so sizing by ch under-counts real prose: 680px
   measured "75ch" and rendered 91 characters a line. 590px gives 542px of
   copy and 78 characters, and still clears the 560px the widest table inside
   an article needs (that table scrolls in its own frame). */
.article { max-width: var(--maxw); margin: 0 auto; padding: 56px 24px 96px; }
/* The measure lives on the children, not on the column. Centring a 590px
   column under a hero whose title starts at the container's left edge left a
   265px step between the headline and the first line of body copy — the page
   read as two documents. Now the title and the copy share a left edge, and
   the things that genuinely want width (tables, code, figures) keep it. */
.article > * { max-width: 542px; }
/* Wider than the prose measure, but not unbounded: letting the table have the
   full 1120px container put 124 characters on one line inside a cell,
   measured on /delivery. 780px is enough for the widest comparison table on
   the site (its own min-width is 560px) and keeps a cell's longest line near
   the prose measure. */
.article > .table-scroll,
.article > pre,
.article > figure,
.article > .diagram { max-width: 780px; }
.article h2 { font-size: 22px; font-weight: 700; margin: 38px 0 12px; }
.article h3 { font-size: 17px; font-weight: 600; margin: 24px 0 8px; }
.article p, .article li { color: var(--ink-2); font-size: 15.5px; }
.article p { margin-bottom: 15px; }
.article h2 + p, .article h3 + p { margin-top: 0; }
.article ul, .article ol { margin: 10px 0 10px 22px; }
.article li { margin-bottom: 7px; }
.article table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 14.5px; }
.article th, .article td { border: 1px solid var(--line); padding: 11px 14px; text-align: left; color: var(--ink-2); }
.article th { background: var(--bg-alt); color: var(--ink); font-weight: 600; }
.article .updated { color: var(--ink-3); font-size: 14px; margin-bottom: 26px; }
/* Even 1px border and a tinted fill instead of a 3px side stripe. The wash
   already says "this is an aside"; the stripe said it a second time, louder,
   and forced the asymmetric 0/10px radius that made the block look clipped. */
.article .notice {
  background: rgba(107, 149, 255, 0.08); border: 1px solid rgba(107, 149, 255, 0.28);
  border-radius: 10px; padding: 16px 20px; margin: 20px 0;
}
.article a { color: var(--indigo); }
.article a:hover { text-decoration: underline; }

/* ---------- Contact ---------- */
.contact-card {
  background: var(--bg); border: 1px solid var(--line); border-radius: 20px; padding: 40px;
  box-shadow: var(--shadow);
}
.contact-card .row { display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 15px; }
.contact-card .row:last-child { border-bottom: none; }
.contact-card .row > * { min-width: 0; overflow-wrap: anywhere; }
.contact-card .k { color: var(--ink-3); min-width: 110px; }
.contact-card a { color: var(--indigo); font-weight: 500; }

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--line); background: var(--bg-alt); padding: 60px 0 32px; }
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; }
.site-footer h4, .site-footer .footer-heading { font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 16px; }
.site-footer a { display: block; color: var(--ink-2); font-size: 14px; margin-bottom: 10px; }
.site-footer a:hover { color: var(--ink); }
/* the link rule above outranks .brand, which would break the lockup onto two lines */
.site-footer .brand {
  display: flex; align-items: center; gap: 10px;
  color: var(--ink); font-size: 19px; margin-bottom: 0;
}
.site-footer .desc { color: var(--ink-2); font-size: 13.5px; max-width: 300px; margin-top: 14px; }
/* The divider between the footer grid and the legal block is drawn by
   .footer-identity's own border-top. This rule used to draw a second one and
   then have it cancelled further down by `.footer-identity + .footer-bottom`
   — dead declarations on all 57 pages, since every page renders the identity
   block (checked 2026-09-04, 57/57). Removed rather than waived: a border
   that is always overridden is a border that reads as real to every static
   reader, human or otherwise. */
.footer-bottom {
  margin-top: 6px;
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px;
  color: var(--ink-3); font-size: 13px;
  /* two literal email links wrap on phones; without this their tap targets
     stack 7px apart and visual_qa (rightly) blocks the deploy */
  line-height: 2;
}
.footer-bottom a { display: inline; margin-left: 18px; color: var(--ink-2); }
/* Who you are actually contracting with: name, registration, and a reachable
   address, phone and email. Card acquirers check for it on every page, so it
   is rendered into the static markup by tools/render_identity.py rather than
   injected at runtime. <address> is italic by default, which reads as a quote
   rather than as the legal footer it is. */
.footer-identity {
  border-top: 1px solid var(--line); margin-top: 44px; padding-top: 24px;
  font-style: normal; color: var(--ink-3); font-size: 13px; line-height: 2;
}
.footer-identity strong { color: var(--ink-2); font-weight: 600; }
.footer-identity a { display: inline; margin: 0; color: var(--ink-2); }


/* ---------- Blog ---------- */
/* --ink-3 reads 4.40:1 on the tinted card these sit on, against 5.08:1 on
   paper — under AA by a tenth, on 99 spans across 33 posts. #5b636f is the
   same neutral one step down and measures 5.26:1 there. Measured, not
   eyeballed: the gap only opens up on the tinted surface. */
.post-meta { display: flex; gap: 10px; align-items: center; color: #5b636f; font-size: 13.5px; margin-bottom: 14px; flex-wrap: wrap; }
.post-meta .cat {
  font-size: 12px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  /* --indigo on its own 12% tint is 4.39:1. The tint is the point of the
     chip, so the ink moves instead: --indigo-ink is the same hue two steps
     darker, 6.97:1 here and still unmistakably the brand blue. */
  color: var(--indigo-ink); background: rgba(107, 149, 255, 0.12); padding: 3px 10px; border-radius: 999px;
}
.blog-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px; }
/* These titles wrap to two lines at this width and 1.2 is display leading —
   fine for a 42px hero, tight for a 20px sentence the eye tracks back across.
   1.4 measured against the 33 real titles, none of which reflow. */
.blog-list .card h3 { font-size: 20px; line-height: 1.4; }
/* The title's text lives in the <a>, not the <h3>. It inherits 1.4 in a
   browser, but a static reader that does not walk inheritance sees an
   unstyled anchor and falls back to `normal` — which is how 11 of the 29
   titles read as 1.12x leading to a tool and 1.4x to a person. Declared
   explicitly so both agree. */
.blog-list .card h3 a { line-height: 1.4; }
.blog-list .card h3 a:hover { color: var(--indigo); }
.blog-list .card .excerpt { margin-top: 8px; }
.blog-list .card .read-more { display: inline-block; margin-top: 16px; font-size: 14px; font-weight: 600; color: var(--indigo); }
.article .post-meta { margin-bottom: 0; }
/* A pull quote earns an indent and a rule, not a coloured tab. 1px in the
   line colour reads as a quotation mark's worth of emphasis; 3px of indigo
   read as an alert box. */
.article blockquote {
  border-left: 1px solid var(--line-2); background: var(--bg-alt);
  padding: 14px 24px; margin: 18px 0; border-radius: 0 10px 10px 0; color: var(--ink-2);
}
.article code {
  font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 0.9em;
  background: var(--bg-alt); border: 1px solid var(--line); border-radius: 6px; padding: 1px 6px;
}
.article pre {
  background: #05080f; color: #c9d1d9; border: 1px solid var(--line); border-radius: 12px; padding: 18px 20px;
  overflow-x: auto; font-family: "SF Mono", Menlo, Consolas, monospace;
  font-size: 13.5px; line-height: 1.8; margin: 18px 0;
}
.article pre code { background: none; border: none; padding: 0; color: inherit; }

/* ---------- Careers ---------- */
.job { display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.job .tags { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.job .tag {
  font-size: 12px; font-weight: 600; color: var(--ink-2); background: var(--bg-alt);
  border: 1px solid var(--line); padding: 3px 12px; border-radius: 999px;
}

/* ---------- Responsive ---------- */
@media (max-width: 920px) {
  .hero h1 { font-size: 38px; }
  .section-head h2 { font-size: 30px; }
  .cols-3, .plans { grid-template-columns: 1fr; }
  .cols-2, .feature, .blog-list { grid-template-columns: 1fr; }
  .feature { gap: 28px; }
  .strip .row { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .nav-links {
    display: none; position: absolute; top: 64px; left: 0; right: 0;
    background: var(--bg-alt); flex-direction: column; align-items: flex-start;
    padding: 20px 24px; gap: 16px; border-bottom: 1px solid var(--line);
  }
  .nav-links.open { display: flex; }
  .nav-toggle { display: flex; }
}
@media (max-width: 560px) {
  .hero { padding: 72px 0 60px; }
  .hero h1 { font-size: 31px; }
  .page-hero h1 { font-size: 32px; }
  /* Buttons inside the plan cards are already full-width on a phone; hero
     buttons sized to their own text look ragged next to that. Match them. */
  .hero .actions, .page-hero .actions { flex-direction: column; align-items: stretch; }
  /* Explicit line breaks in a headline are composed for a wide measure. On a
     phone they strand words ("endpoint" alone on its own line); let the text
     wrap naturally instead. The source has whitespace between the spans, so
     going inline keeps the word gap. Scoped to .page-hero: the homepage
     headline is a deliberate two-part composition ("AI," then the gradient
     phrase whole) and must keep its breaks. */
  .page-hero h1 .line { display: inline; }
  /* .btn is inline-block, so the label centres with text-align, not flexbox. */
  .hero .actions .btn, .page-hero .actions .btn { width: 100%; text-align: center; }
}

/* ---------- Gateway pillars ---------- */
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.pillar {
  position: relative; overflow: hidden;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 34px 30px; transition: all 0.2s;
}
/* The 3px gradient bar across the top of every pillar is gone (2026-09-04). A
   thick coloured stripe on one edge of a card is the single most recognisable
   tell of a generated interface, and it appeared on 57 pages because .pillar
   is the site's default card. The card is now separated by its border and by
   the hover lift, and the brand gradient stays where it means something. */
.pillar:hover { border-color: var(--line-2); }
.pillar .k { font-size: 12px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--indigo); }
.pillar h3 { font-size: 21px; font-weight: 650; letter-spacing: -0.02em; margin: 10px 0 8px; }
.pillar > p { color: var(--ink-2); font-size: 14.5px; }
.pillar ul { list-style: none; margin-top: 18px; }
.pillar ul li { position: relative; padding: 10px 0 10px 26px; color: var(--ink); font-size: 14px; border-top: 1px solid var(--line); }
.pillar ul li:first-child { border-top: none; }
.pillar ul li::before { top: 10px; }
.pillar ul li b { font-weight: 600; }

/* ---------- Conversion paths ---------- */
.paths { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
/* Icon beside the heading, copy at full measure, button on its own row — laid
   out by named grid areas rather than by centring everything and stacking a
   46px icon tile on top (2026-09-04). Centred icon-over-heading-over-text is
   the generated feature card; these are three different actions and reading
   them left-aligned is faster than reading three centred columns. */
.path {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 30px 28px; transition: all 0.2s;
  display: grid; grid-template-columns: auto 1fr;
  grid-template-areas: "ico title" "body body" "cta cta";
  column-gap: 13px; align-items: center;
}
.path:hover { border-color: var(--line-2); }
.path .pico { grid-area: ico; display: flex; align-items: center; justify-content: center; }
.path .pico svg { width: 26px; height: 26px; stroke: var(--indigo); }
.path h3 { grid-area: title; font-size: 18px; font-weight: 700; }
.path p { grid-area: body; color: var(--ink-2); font-size: 14px; margin: 12px 0 18px; }
.path .btn { grid-area: cta; width: 100%; }

/* ---------- Integration steps ---------- */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; counter-reset: st; }
.stepc { background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px 26px; }
.stepc .n { width: 34px; height: 34px; border-radius: 10px; background: var(--grad); color: var(--on-accent); font-weight: 800; display: flex; align-items: center; justify-content: center; margin-bottom: 16px; }
.stepc h3 { font-size: 16.5px; font-weight: 700; margin-bottom: 6px; }
.stepc p { color: var(--ink-2); font-size: 14px; }

/* accessibility: skip link + visible focus */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--on-accent); padding: 10px 16px; border-radius: 0 0 10px 0; font-weight: 600;
}
.skip-link:focus { left: 0; }
a:focus-visible, button:focus-visible, .btn:focus-visible {
  outline: 2px solid var(--indigo); outline-offset: 2px; border-radius: 6px;
}
.footer-grid-4 { grid-template-columns: 2fr 1fr 1fr 1.2fr; }
.card-meta { margin-top: 14px; color: var(--ink-3); font-size: 12.5px; }
.card .read-more { display: inline-block; margin-top: 14px; font-size: 14px; font-weight: 600; color: var(--indigo); }
.card .read-more:hover { text-decoration: underline; }

.pillars.two { grid-template-columns: repeat(2, 1fr); }
.pillar .lead-line { color: var(--ink-2); font-size: 15px; margin-top: 4px; }

/* provider chips */
.prov-row { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 18px; }
.prov-row span {
  font-size: 13px; font-weight: 600; color: var(--ink-2);
  background: var(--bg-alt); border: 1px solid var(--line);
  padding: 7px 14px; border-radius: 999px;
}
.prov-row .best { color: var(--indigo); border-color: rgba(107, 149, 255, 0.35); background: rgba(107, 149, 255, 0.10); }

/* compliance callout / contracts */
.callout {
  display: flex; gap: 14px; align-items: flex-start;
  background: rgba(107, 149, 255, 0.07); border: 1px solid rgba(107, 149, 255, 0.22);
  border-radius: var(--radius); padding: 18px 22px; margin-top: 22px; color: var(--ink-2); font-size: 14.5px;
}
.callout svg { width: 22px; height: 22px; stroke: var(--indigo); flex: none; margin-top: 1px; }

/* ---------- Split hero: copy beside a live-looking request ---------- */
.hero-split { display: grid; grid-template-columns: 1.04fr 0.96fr; gap: 54px; align-items: center; }
.hero-split > * { min-width: 0; }
.hero-split h1 { font-size: 52px; max-width: none; }
.hero-split .sub { font-size: 18px; }
.hero-split .code-card { margin-top: 0; max-width: none; border-radius: var(--radius) var(--radius) 0 0; }
.hero-metrics {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--line); border: 1px solid var(--line-2); border-top: none;
  border-radius: 0 0 var(--radius) var(--radius); overflow: hidden;
}
.hero-metrics div { background: #05080f; padding: 13px 16px; }
.hero-metrics b { display: block; font-family: var(--mono); font-size: 16px; color: #e9edf6; }
.hero-metrics span { font-size: 12px; color: #8b95a9; letter-spacing: 0.05em; text-transform: uppercase; }

/* works-with row */
.compat { display: flex; gap: 14px 26px; flex-wrap: wrap; align-items: center;
  font-family: var(--mono); font-size: 13px; color: var(--ink-3); padding: 18px 24px;
  max-width: var(--maxw); margin: 0 auto; }
.compat b { color: var(--ink-2); font-weight: 500; font-size: 13px; letter-spacing: 0.02em; }

/* ---------- Company facts (what procurement asks for) ---------- */
.facts { border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-alt); overflow: hidden; }
.facts .facts-head { font-size: 16px; font-weight: 700; padding: 18px 24px; border-bottom: 1px solid var(--line); }
/* Grid, not wrapping flex: a long value has to wrap inside its own column
   rather than dropping underneath the label and breaking the row rhythm. */
.facts .frow { display: grid; grid-template-columns: 148px 1fr; gap: 4px 18px; padding: 13px 24px; border-bottom: 1px solid var(--line); font-size: 14.5px; }
.facts .frow:last-child { border-bottom: none; }
.facts .frow > * { min-width: 0; overflow-wrap: anywhere; }
.facts .k { color: var(--ink-3); min-width: 148px; }
.facts .v { color: var(--ink); font-weight: 500; }
.facts .v small { display: block; color: var(--ink-3); font-weight: 400; font-size: 13px; }

@media (max-width: 920px) {
  .pillars, .pillars.two, .paths, .steps { grid-template-columns: 1fr; }
  .footer-grid-4 { grid-template-columns: 1fr 1fr; }
  .hero-split { grid-template-columns: 1fr; gap: 38px; }
  .hero-split h1 { font-size: 38px; }
  .hero-metrics { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .footer-grid-4 { grid-template-columns: 1fr; }
}

/* Product cards are links, not just the "Explore" line — a visitor clicking
   anywhere on the card lands on that product's page. */
.card-clickable { display: block; text-decoration: none; color: inherit; cursor: pointer; }
.card-clickable .read-more { color: var(--indigo); font-weight: 600; display: inline-block; margin-top: 4px; }
.card-clickable:hover .read-more { text-decoration: underline; }

/* ---------- Platform stack (macro layered view) ---------- */
.stack { display: flex; flex-direction: column; gap: 0; max-width: 920px; margin: 0 auto; }
.layer { border: 1px solid var(--line); border-radius: var(--radius); padding: 26px 30px;
  background: var(--bg-alt); }
/* .layer-tag is gone (2026-09-04): "Access" over "Gateway & routing",
   "More" over "Capabilities that ride along". Four tracked-caps labels naming
   what the heading beneath them already named. */
.layer-body h3 { font-size: 21px; font-weight: 650; letter-spacing: -0.02em; margin-bottom: 8px; }
.layer-body p { color: var(--ink-2); font-size: 15px; max-width: 68ch; }
.layer .chips { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 16px; }
.layer .chips a, .layer .chips span {
  font-size: 13.5px; padding: 7px 14px; border-radius: 999px;
  border: 1px solid var(--line-2); background: #fff; color: var(--ink-2); }
.layer .chips a { color: var(--indigo); font-weight: 600; }
.layer .chips a:hover { border-color: var(--indigo); background: rgba(107,149,255,0.10); }
/* the middle layer is the hero of the diagram */
.layer-mid { border-color: rgba(107,149,255,0.5);
  background: linear-gradient(180deg, rgba(107,149,255,0.10), rgba(34,211,238,0.05));
  box-shadow: 0 0 0 1px rgba(107,149,255,0.25), var(--shadow); }
.layer-mid .layer-body h3 { color: var(--indigo); }
.layer-flow { display: flex; justify-content: center; gap: 40px; padding: 8px 0;
  font: 500 12px/1 var(--mono); color: var(--ink-3); letter-spacing: 0.06em; }
@media (max-width: 640px) {
  .layer { padding: 22px; }
  .layer-flow { gap: 20px; }
}

/* nav "Sign in" reads like a text link next to the primary CTA (OpenAI/Google pattern) */
.nav-links a.nav-signin { font-weight: 600; }

/* ---------- Related reading (end of an article) ---------- */
.article .related {
  margin-top: 48px; padding: 26px 28px;
  background: var(--bg-alt); border: 1px solid var(--line); border-radius: var(--radius);
}
.article .related h2 {
  font-size: 13px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 14px;
}
.article .related ul { list-style: none; margin: 0; }
.article .related li { margin: 0; padding: 9px 0; border-top: 1px solid var(--line); }
.article .related li:first-child { border-top: none; }
.article .related a { color: var(--indigo); font-weight: 600; }
.article .related a:hover { text-decoration: underline; }

/* ---------- Copy button on code blocks ---------- */
.copy-btn {
  margin-left: auto; font: 600 12px/1 var(--mono); letter-spacing: .02em;
  color: #8b95a1; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.14);
  padding: 5px 11px; border-radius: 999px; cursor: pointer; transition: all .15s;
}
.copy-btn:hover { color: #e9edf6; background: rgba(255,255,255,.12); }
.copy-btn.done { color: #7ee2a8; border-color: rgba(126,226,168,.4); }
.article pre { position: relative; }
.article pre .copy-btn { position: absolute; top: 10px; right: 12px; margin: 0; }

/* Sticky header is 68px; without this every in-page anchor lands with its
   heading hidden underneath it. */
:where(h1, h2, h3, h4, [id]) { scroll-margin-top: 88px; }

/* Documentation: contents rail + sibling nav */
.doc-wrap { max-width: 820px; margin: 0 auto; }
.doc-wrap .article { margin: 0; }
.doc-toc {
  padding: 40px 24px 0;
}
.toc-title {
  font-size: 12px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 12px;
}
.doc-toc ul { list-style: none; margin: 0; padding: 0; }
.doc-toc li { margin: 0 0 8px; }
.doc-toc a {
  color: var(--muted); text-decoration: none; font-size: 14px; line-height: 1.45;
  display: block; border-left: 2px solid var(--line); padding: 2px 0 2px 12px;
}
.doc-toc a:hover { color: var(--ink); border-left-color: var(--indigo); }
.doc-next {
  border-top: 1px solid var(--line); margin-top: 56px; padding-top: 32px;
}
.doc-next .toc-title {
  font-size: 13px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 16px;
}
.doc-next ul {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.doc-next a { color: var(--indigo); text-decoration: none; font-weight: 500; }
.doc-next a:hover { text-decoration: underline; }

@media (min-width: 1200px) {
  .doc-wrap {
    /* Same container token as the header and hero, so the contents rail lines
       up with the logo and the h1 instead of sitting 20px to their left.
       212 + 40 + 820 exactly fills the 1072px content box. */
    max-width: var(--maxw);
    display: grid; grid-template-columns: 212px minmax(0, 820px); gap: 40px;
    padding: 0 24px;
  }
  .doc-toc {
    position: sticky; top: 92px; align-self: start;
    padding: 56px 0 0; max-height: calc(100vh - 120px); overflow-y: auto;
  }
}

/* ---------- Failover diagram (/router) ---------- */
.diagram { margin: 0; max-width: 940px; margin-inline: auto; }
.diagram-svg {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg); padding: 20px 12px;
}
.diagram-svg .d-node rect { fill: var(--bg); stroke: var(--line-2); stroke-width: 1.25; }
.diagram-svg .d-gw rect { fill: var(--bg-alt); stroke: var(--indigo); }
.diagram-svg .d-title {
  font-weight: 700; font-size: 15px; fill: var(--ink); text-anchor: middle;
}
.diagram-svg .d-sub {
  font-weight: 400; font-size: 13px; fill: var(--ink-3); text-anchor: middle;
}
.diagram-svg .d-left { text-anchor: start; }
.diagram-svg .d-chip rect { fill: var(--bg); stroke: var(--line-2); stroke-width: 1; }
.diagram-svg .d-chip text {
  font: 600 13px/1 var(--mono); fill: var(--ink-2); text-anchor: middle;
  letter-spacing: 0.02em;
}
.diagram-svg .d-flow { color: var(--ink-3); }
.diagram-svg .d-flow line, .diagram-svg .d-flow path {
  stroke: currentColor; stroke-width: 1.5;
}
.diagram-svg .d-edge {
  font: 600 12px/1 var(--mono); fill: var(--ink-3); text-anchor: middle;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.diagram-svg .d-ok { color: var(--cyan-text); }
.diagram-svg .d-ok .d-edge { fill: var(--cyan-text); }
.diagram-svg .d-down, .diagram-svg .d-idle { color: var(--ink-4, #9aa3af); }
.diagram-svg .d-x line { stroke: #c2410c; stroke-width: 2; stroke-linecap: round; }
.diagram-svg .d-prov-down rect { stroke-dasharray: 5 4; }
.diagram-svg .d-prov-idle rect, .diagram-svg .d-prov-idle text { opacity: 0.62; }

.diagram-steps {
  display: none; margin: 0; padding-left: 22px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg); padding: 22px 22px 22px 42px;
}
.diagram-steps li { margin: 0 0 12px; color: var(--ink-2); line-height: 1.6; }
.diagram-steps li:last-child { margin-bottom: 0; }
.diagram-steps b { color: var(--ink); font-weight: 600; }

.diagram figcaption {
  margin-top: 16px; color: var(--ink-3); font-size: 14.5px; line-height: 1.6;
  text-align: center; max-width: 640px; margin-inline: auto;
}

/* A 880-wide drawing on a phone puts its labels at about 6px. Below that, the
   ordered list says the same thing at a readable size. */
@media (max-width: 719px) {
  .diagram-svg { display: none; }
  .diagram-steps { display: block; }
  .diagram figcaption { text-align: left; }
}

/* A page's hero follows the alignment of its own body: centred on the product
   and pricing pages, left on anything you read as an article. */
.page-hero.center { text-align: center; }
/* 680px rendered 96 characters a line on /comic, counted off the line boxes.
   Centred text is harder to track back across than left-aligned, not easier,
   so the centred variant wants the same measure as the rest -- not a wider
   one. 550px lands at 78. */
.page-hero.center p { margin-inline: auto; max-width: 550px; }
.page-hero.center .actions { justify-content: center; }

/* The hero already separates itself with a rule and a colour change; the first
   section does not need a full section's worth of padding on top of that. */
main > .section:first-child { padding-top: 64px; }

/* This used to re-centre the radial glow for centred heroes. The glow itself is
   gone (see .page-hero), and a flat band has no side to be on, so the centred
   variant no longer needs a background of its own. */
/* Stops the lede stranding a single word on its own last line. */
.page-hero p { text-wrap: pretty; }

/* Wide tables scroll inside their own region rather than pushing the page
   sideways. tabindex makes the region keyboard-scrollable. */
/* impeccable-disable-next-line cramped-padding -- the container is a scroll
   frame, and its inset comes from the table inside it: cells carry
   padding 11px 14px and the one visible <caption> on the site now carries
   12px 14px 10px (see below). Measured on /delivery 2026-09-04. */
.article .table-scroll {
  overflow-x: auto; margin: 18px 0;
  border: 1px solid var(--line); border-radius: var(--radius);
}
.article .table-scroll table { margin: 0; min-width: 560px; border: none; }
/* A visible <caption> carries no padding by default, so it rendered 4px under
   the container's border while every cell below it sat on 11px. Measured on
   /delivery, which is the one table on the site with a visible caption. */
.article .table-scroll caption { padding: 12px 14px 10px; text-align: left; font-weight: 600; color: var(--ink-2); }
.article .table-scroll:focus-visible { outline: 2px solid var(--indigo); outline-offset: 2px; }

/* A tick means "included". Two of the four products on /about are not
   available yet, so a tick beside them would be a claim, not a bullet. */
.feature ul.status-list li { padding-left: 0; }
.feature ul.status-list li::before { content: none; }
.feature ul.status-list li em { color: var(--ink-3); font-style: normal; }

/* Without JavaScript the mobile nav cannot open: .nav-links is display:none
   under the breakpoint and only .open shows it, and .open is added by script.
   A <noscript> block on every page turns this on, so a visitor with JS off —
   or with the script blocked or failed — still has navigation instead of only
   the footer. */
.no-js-nav .nav-links {
  display: flex !important; position: static; flex-direction: row;
  flex-wrap: wrap; background: none; padding: 0; border: none; gap: 14px 18px;
}
.no-js-nav .nav-toggle { display: none !important; }


/* .model-note carried its styling inline on every page, which is why a media
   query could not left-align it -- an inline style beats any selector without
   !important. Moved here so the responsive rule below can actually win. */
/* Measured on the live page at 1280px: 1072px wide, 133 characters a line --
   the widest measure on the site, on a centred one-line note where the ragged
   left edge makes a long line worse, not better. */
.model-note {
  text-align: center; margin-top: 24px;
  color: var(--ink-3); font-size: 14px;
  max-width: 72ch; margin-left: auto; margin-right: auto;
}

/* ---------- Centred body copy is a phone-width readability problem ---------- */
/* Centred text is fine for a line or two -- a label, a short deck. Past that the
   ragged left edge makes the reader hunt for the start of every line, and at
   375px a paragraph that sits on two lines on a desktop runs to five, seven or
   nine. Measured: 35 centred paragraphs of three lines or more across eight
   pages, the longest at nine.

   Headings stay centred, because that is the site's convention everywhere
   (twenty-seven centred section heads across ten pages) and a heading is short
   enough that centring costs nothing. Only the prose under them changes, and
   only below the phone breakpoint. */
@media (max-width: 560px) {
  .section-head.center p,
  .page-hero.center p,
  .cta-band p,
  /* .model-note is the "here is the caveat" paragraph under several sections;
     it is the longest centred copy on the site -- eleven lines at 375px on
     /code-plans. .path is the two-column "adopt the stack or start with one"
     block, which stacks on a phone. */
  p.model-note,
  .path p {
    text-align: left;
    margin-inline: 0;
  }
}


/* ---------- numbered product system -------------------------------------
   The page used to carry two taxonomies for one set of products: a
   three-band stack and a four-card grid, grouped differently, counts
   disagreeing. Numbering is what joins them now -- band 01 and the card
   stamped 01 are the same thing -- so the reader never has to map between
   two schemes. The bands lost their chips and flow arrows in the process:
   the chips duplicated the cards, and the arrows described a data flow the
   numbered sequence no longer claims. */
.layer {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 0 4px;
  align-items: start;
}
.layer + .layer { margin-top: 14px; }
.layer-num {
  font: 800 26px/1 var(--mono);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--line-2);
  padding-top: 2px;
}
/* 01 is the only layer a visitor can buy today, so it is the one that gets
   the brand weight -- the same treatment the old .layer-mid gave the Router. */
.layer-lead {
  border-color: rgba(107, 149, 255, 0.5);
  background: linear-gradient(180deg, rgba(107, 149, 255, 0.10), rgba(34, 211, 238, 0.05));
}
.layer-lead .layer-num { color: var(--cyan); }
.layer-lead .layer-body h3 { color: var(--indigo); }
.layer-prod {
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  font-size: 15px;
}
.layer-prod a { color: var(--indigo); font-weight: 700; }
.layer-prod a:hover { color: var(--cyan-text); text-decoration: underline; }
.layer-side { color: var(--ink-3); font-size: 13.5px; }
/* Status reads as a fact, not a badge to be proud of: "in development" must
   not look like a feature. Only the shipping one gets colour. */
/* line-height 1 was safe only because "Running traffic today" happens to fit
   on one line at every width tested. It is a chip whose text is content, and
   a longer state string or a wider translation would set two lines directly
   on top of each other. 1.3 costs 4px of chip height and removes the trap. */
.layer-state {
  font: 600 12px/1.3 var(--mono);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  color: var(--ink-3);
}
.layer-state.on {
  color: var(--cyan-text);
  border-color: rgba(11, 150, 184, 0.45);
  background: rgba(11, 150, 184, 0.08);
}

/* The card stamp is the other half of the join. Monospace and muted so it
   reads as an index, not as a label competing with the product name. */
.card-layer {
  /* The icon is positioned against the top of the card, where the title used
     to start; the four product cards put this label there instead, so it has
     to clear the icon the same way the title does. Kept in one rule: the
     `font` shorthand below resets line-height, which silently undid an
     earlier attempt that set it in a separate block above. */
  padding-left: 38px;
  min-height: 26px;
  font: 700 12px/26px var(--mono);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.card-layer b { color: var(--cyan-text); font-weight: 800; }

@media (max-width: 920px) {
  .layer { grid-template-columns: 44px 1fr; }
  .layer-num { font-size: 20px; }
}
@media (max-width: 560px) {
  /* The number column costs a third of the width on a phone, so it goes
     above the tag instead of beside it. */
  .layer { grid-template-columns: 1fr; }
  .layer-num { padding-top: 0; margin-bottom: 6px; }
}


/* ---------- /plans -----------------------------------------------------
   Rebuilt after the owner's note that it was "too cramped". The previous version packed four cards, a band and
   three cards into roughly one screen; the complaint was about air, so the
   rhythm here is deliberately slower: sections breathe, rows have height, and
   a horizontal rule separates each movement instead of a colour change.

   Structure follows the standalone reference supplied with the handover —
   mono eyebrows over display headings, a numbered run sequence, a datasheet
   table, a two-column FAQ. Its typefaces are not carried over: they load from
   Google Fonts, and this site self-hosts its face on purpose (font-src is
   'self', and the reason recorded at the top of this file is one less DNS+TLS
   round trip plus not handing an EU visitor's IP to a third party). The
   existing Inter and the system mono stack do the same job here. */

.plan-hero { padding: 88px 0 76px; }
.plan-hero .container { display: grid; grid-template-columns: 1.02fr .98fr; gap: 56px; align-items: start; }
/* Grid items default to min-width:auto, so the terminal's white-space:pre gave
   the track a min-content width of the longest line and pushed the whole hero
   26px past the viewport at 375px — the text column widened with it, which is
   why the overflow reported against the headline rather than the terminal. */
.plan-hero .container > * { min-width: 0; }
.plan-hero h1 { font-size: clamp(40px, 5vw, 60px); font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; margin: 18px 0 24px; }
.plan-hero h1 em { font-style: normal; color: var(--cyan-text); }
.plan-hero .sub { color: var(--ink-2); font-size: 17.5px; max-width: 46ch; }
.plan-hero .cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.plan-hero .note { font-family: var(--mono); font-size: 12px; color: var(--ink-3); margin-top: 18px; letter-spacing: .02em; }
@media (max-width: 940px) { .plan-hero { padding: 60px 0 52px; } .plan-hero .container { grid-template-columns: 1fr; gap: 40px; } }

/* .eyebrow is gone (2026-09-04): eight tracked-caps section labels
   ("Plans", "Top-up", "Datasheet", "FAQ") and two hero chips, all sitting
   above a heading that said the same thing in words a reader can use. */

/* A worked example, labelled as one. Terminal greys are set from a measured
   contrast ratio against #0b1018, not by eye: the first pass used #63707f,
   which is 3.77:1 and fails AA. #7d8a99 is 5.42:1. Nothing here drops below
   12px either — the site's floor, and the check enforces it. */
.term { background: #0b1018; border: 1px solid var(--line-2); border-radius: 10px; overflow: hidden;
        box-shadow: 0 18px 44px -28px rgba(11,16,24,.55); }
.term-bar { display: flex; align-items: center; gap: 8px; padding: 10px 15px;
            border-bottom: 1px solid rgba(255,255,255,.07);
            font-family: var(--mono); font-size: 12px; color: #7d8a99; letter-spacing: .05em; }
.term-bar i { width: 8px; height: 8px; border-radius: 50%; background: #2c3846; flex: none; }
.term-bar b { font-weight: 400; margin-left: 6px; }
.term pre { margin: 0; padding: 20px 18px 22px; overflow-x: auto;
            font-family: var(--mono); font-size: 12.5px; line-height: 1.8; color: #c9d3e0; white-space: pre; }
.term .c { color: #7d8a99; } .term .a { color: #22d3ee; } .term .g { color: #5fb98b; }
.term-cap { font-family: var(--mono); font-size: 12px; color: var(--ink-3); margin-top: 10px; letter-spacing: .02em; }

/* Section rhythm. 78px is the number that answers the complaint. */
.psec { padding: 78px 0; }
.psec-head { display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap; margin-bottom: 40px; }
.psec-head h2 { font-size: clamp(26px, 3vw, 34px); font-weight: 700; }
.prule { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* Numbered run sequence. Named .prun, not .steps: .steps already exists above
   as a three-column grid, and a later single-class rule cannot undo an earlier
   display and grid-template — the rows laid out sideways until this was
   renamed. Checked every class introduced in this block against the rules
   above it; this was the only real collision.
   Numbered run sequence. Rows are tall on purpose: this is the part that used
   to be a wall of bullets inside a card. */
.prun { border-top: 1px solid var(--line); }
/* Two columns now, not three: the step number moved inside its own <h3> (it
   numbers that heading, so it belongs to it) and the 58px column it used to
   occupy went with it. 278px = the old 58 + 220 so the paragraph starts on the
   same vertical line as before. */
/* Asymmetric padding so each step's heading leads its own row rather than
   trailing the one above: 34px of air before it, 24px after. */
.pstep { display: grid; grid-template-columns: 278px 1fr; gap: 28px; align-items: baseline;
         padding: 34px 0 24px; border-bottom: 1px solid var(--line); }
.pstep-n { font-family: var(--mono); font-size: 12.5px; color: var(--cyan-text); letter-spacing: .08em; font-weight: 600; }
/* The number keeps its own optical column inside the heading, so the four
   steps still line up down the left edge — it just is not a separate block
   sitting above the words it belongs to. */
.pstep h3 { font-size: 19.5px; font-weight: 700; display: flex; align-items: baseline; gap: 16px; }
.pstep h3 .pstep-n { flex: none; min-width: 26px; }
.pstep p { color: var(--ink-2); font-size: 15.5px; max-width: 64ch; }
@media (max-width: 820px) {
  /* One column on a phone: 278px of heading track next to the paragraph leaves
     the copy about 90px wide. The heading stacks above its own paragraph. */
  .pstep { grid-template-columns: 1fr; gap: 10px; }
  .pstep p { grid-column: 1; }
}

/* Explicit three, not auto-fit: six items on an auto-fit track landed 4+2 and
   left a hole in the bottom-right that read as a missing card. */
.incs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 44px; }
@media (max-width: 900px) { .incs { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .incs { grid-template-columns: 1fr; } }
.inc { padding: 24px 22px; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); }
.inc h3 { font-size: 15px; font-weight: 700; margin-bottom: 7px; }
.inc p { font-size: 13.5px; color: var(--ink-3); line-height: 1.65; }

/* Cards: the multiplier still leads, but with room around it. */
.plans-4 { grid-template-columns: repeat(4, 1fr); gap: 18px; }
.plans-4 .plan { padding: 34px 26px 30px; display: flex; flex-direction: column; }
.plans-4 .price { font-size: 33px; margin: 12px 0 0; }
.plans-4 .price .cur { font-size: 20px; font-weight: 700; vertical-align: 6px; margin-right: 1px; color: var(--ink-2); }
.plans-4 .price small { font-size: 14px; font-weight: 500; color: var(--ink-3); letter-spacing: 0; }
.plan-for { color: var(--ink-3); font-size: 13.5px; min-height: 40px; margin-top: 4px; }
.plan-rate { font-size: 12.5px; color: var(--ink-3); margin: 6px 0 0; font-family: var(--mono); }
.mult { margin: 24px 0 18px; padding: 18px 0 16px;
        border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
        display: flex; align-items: baseline; gap: 9px; }
.mult b { font-size: 34px; font-weight: 800; letter-spacing: -.03em; line-height: 1;
          color: var(--indigo); }
.mult span { font-size: 13px; color: var(--ink-3); font-weight: 500; }
.plan-diff { font-size: 13.5px; color: var(--ink-2); line-height: 1.7; flex: 1 0 auto; margin-bottom: 26px; }
.plan-diff b { color: var(--ink); }
.btn-block { display: block; width: 100%; text-align: center; }
.plans-4 .btn { padding: 12px 20px; font-size: 15px; }

/* Datasheet. Every cell here is traceable to the product description a buyer
   sees at Stripe checkout — see the comment in the markup. */
/* impeccable-disable-next-line cramped-padding -- the only child touching the
   top border is a .visually-hidden <caption>; the first painted row is a
   thead cell on padding 14px 18px. Measured 2026-09-04 on /plans. */
.dsheet { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg); }
.dsheet table { border-collapse: collapse; width: 100%; min-width: 720px; font-size: 14.5px; }
.dsheet th, .dsheet td { text-align: left; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.dsheet thead th { background: var(--bg-alt); font-family: var(--mono); font-size: 12px; font-weight: 600;
                   letter-spacing: .07em; text-transform: uppercase; color: var(--ink-2); white-space: nowrap; }
.dsheet tbody th { font-weight: 500; color: var(--ink); width: 36%; }
.dsheet td { font-family: var(--mono); font-size: 13px; color: var(--ink-2); white-space: nowrap; }
.dsheet tbody tr:last-child th, .dsheet tbody tr:last-child td { border-bottom: 0; }
.dsheet .yes { color: var(--cyan-text); font-weight: 700; }
.dsheet .no { color: var(--ink-3); }
.dsheet .grp th { background: var(--bg-alt); font-family: var(--mono); font-size: 12px; letter-spacing: .14em;
                  text-transform: uppercase; color: var(--ink-3); font-weight: 600; }

.qas { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 48px; border-top: 1px solid var(--line); }
.qa { padding: 26px 0; border-bottom: 1px solid var(--line); }
.qa h3 { font-size: 17px; font-weight: 700; margin-bottom: 8px; }
.qa p { color: var(--ink-2); font-size: 14.5px; max-width: 58ch; line-height: 1.7; }
@media (max-width: 820px) { .qas { grid-template-columns: 1fr; } }

.pclose { border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-alt);
          padding: 44px 40px; display: flex; flex-wrap: wrap; gap: 26px;
          align-items: center; justify-content: space-between; }
.pclose h2 { font-size: clamp(23px, 2.6vw, 30px); font-weight: 700; max-width: 22ch; }
.pclose .cta { display: flex; flex-wrap: wrap; gap: 12px; }

@media (max-width: 1080px) { .plans-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .plans-4 { grid-template-columns: 1fr; } .psec { padding: 56px 0; } }

/* Accessible name for the datasheet without printing a heading nobody needs to
   see; the section already carries a visible h2. */
.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; border: 0;
}

/* /thanks — one column, no terminal beside it, so the hero grid collapses. */
.thanks-hero .container { grid-template-columns: 1fr; }
.thanks-hero .sub { max-width: 56ch; }


/* ======================================================================
   Flagship pass (2026-09-29)
   ----------------------------------------------------------------------
   The brief was "grander, more premium, more professional, simpler". Read
   against the pages this site is compared with, the gap was not colour or
   copy -- it was structure: every section was a centred heading over three
   floating cards, so nothing on a page outranked anything else. The rules
   below give the page a spine: one statement per screen, hairlines instead
   of shadows, headings that sit on a left edge, and a closing band dark
   enough to end the page rather than fade it out.
   ====================================================================== */

/* Section heads: title on the left, the deck in a second column. Centred
   heading-over-paragraph is the shape every generated page repeats; a split
   head reads as editorial and lets the heading be set large without the deck
   wrapping into a narrow centred column under it. Phones keep the stacked,
   left-aligned version from the rules above. */
@media (min-width: 921px) {
  .section-head.center {
    max-width: none; text-align: left;
    display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    column-gap: 72px; align-items: end;
  }
  .section-head.center h2 { grid-column: 1; grid-row: 1 / span 4; }
  .section-head.center > :not(h2) { grid-column: 2; margin-left: 0; margin-right: 0; }
  .section-head.center > p:first-of-type { margin-top: 0; }
  .section-head.center p { font-size: 17.5px; max-width: 520px; }
}

/* ---------- Home hero ---------- */
.hero-flagship { padding: 112px 0 96px; text-align: center; }
/* A drafting grid that fades out before the copy ends: structure without a
   light source, which is what the old radial glows pretended to be. */
.hero-flagship::before {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 46%, #fff 82%),
    repeating-linear-gradient(90deg, rgba(13, 17, 23, 0.05) 0 1px, transparent 1px 80px),
    repeating-linear-gradient(0deg, rgba(13, 17, 23, 0.05) 0 1px, transparent 1px 80px);
  background-position: center top;
}
.hero-flagship h1 {
  font-size: clamp(42px, 5.8vw, 80px); line-height: 1.03; letter-spacing: -0.048em;
  max-width: none; margin: 28px auto 0;
}
.hero-flagship .sub { margin: 28px auto 0; max-width: 640px; font-size: 20px; }
.hero-flagship .actions { justify-content: center; }
.hero-kicker-row { margin: 0; }
main a.hero-kicker:not(.btn) {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 14px 6px 6px; border: 1px solid var(--line-2); border-radius: 999px;
  background: #fff; color: var(--ink-2); font-size: 14px; font-weight: 500;
  text-decoration: none;
}
main a.hero-kicker:not(.btn):hover { border-color: var(--ink-3); color: var(--ink); }
.kicker-tag {
  font: 600 12px/1 var(--mono); letter-spacing: 0.06em; text-transform: uppercase;
  color: #fff; background: var(--indigo-ink); border-radius: 999px; padding: 5px 9px;
}

/* ---------- Platform map ----------
   The product system as one drawing: layers top to bottom in the order a
   request travels, each product sitting in its layer with its literal status.
   It replaces the curl card that used to fill the hero -- that sample was
   about one product, and it now lives on that product's tile. */
.pmap {
  margin: 76px auto 0; max-width: 1040px; text-align: left;
  background: #fff; border: 1px solid var(--line-2); border-radius: 18px;
  box-shadow: 0 1px 2px rgba(13, 17, 23, 0.04), 0 40px 80px -48px rgba(13, 17, 23, 0.28);
  overflow: hidden;
}
.pmap-row { display: grid; grid-template-columns: 176px minmax(0, 1fr); }
.pmap-row + .pmap-row { border-top: 1px solid var(--line); }
.pmap-layer {
  display: flex; align-items: center; padding: 0 22px;
  font: 600 12px/1.3 var(--mono); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3); background: var(--bg-alt); border-right: 1px solid var(--line);
}
.pmap-cells { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 12px; padding: 14px; list-style: none; margin: 0; }
.pmap-cells li { display: grid; min-width: 0; }
main a.pmap-cell:not(.btn) {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 16px; align-items: baseline;
  padding: 15px 18px; border: 1px solid var(--line); border-radius: 12px;
  color: var(--ink); font-weight: 400; text-decoration: none; background: #fff;
  transition: border-color 0.18s, background-color 0.18s;
}
main a.pmap-cell:not(.btn):hover { border-color: var(--ink-3); background: var(--bg-alt); }
.pmap-cell b { font-size: 15.5px; font-weight: 650; letter-spacing: -0.015em; display: flex; align-items: center; gap: 8px; }
.pmap-cell span { grid-column: 1 / -1; color: var(--ink-3); font-size: 13.5px; line-height: 1.45; }
.pmap-cell i, .card-new {
  font: 600 12px/1 var(--mono); font-style: normal; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--indigo-ink); background: rgba(74, 91, 214, 0.08);
  border: 1px solid rgba(74, 91, 214, 0.3); border-radius: 999px; padding: 3px 7px;
}
.pmap-st {
  grid-column: 2; grid-row: 1; font: 600 12px/1 var(--mono); font-style: normal;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap;
}
.pmap-live .pmap-st { color: var(--cyan-text); }
.pmap-live .pmap-st::before {
  content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 7px;
  border-radius: 50%; background: var(--cyan-text); vertical-align: 1px;
}
.pmap-ground { padding: 18px 22px; color: var(--ink-3); font-size: 14px; }
.pmap-base .pmap-layer { background: var(--bg-alt); }

/* ---------- Product bento ---------- */
.bento { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 20px; }
.bento > .card { grid-column: span 2; display: flex; flex-direction: column; padding: 32px 30px 28px; }
.bento > .bento-lg { grid-column: span 3; }
.bento .card > p:not(.card-meta):not(.card-layer) { font-size: 15px; }
.bento .card-meta { margin-top: auto; padding-top: 18px; }
.bento .read-more { margin-top: 10px; }
.bento .card-layer { display: flex; align-items: center; gap: 10px; }
.bento .code-card { margin-top: 22px; max-width: none; box-shadow: none; border-radius: 12px; }
.bento .code-card pre { padding: 16px 18px 18px; font-size: 12.5px; line-height: 1.75; }
.bento .card ul { margin-top: 12px; }

/* The FS tile's drawing: the same four layers as the product page's
   architecture figure, small enough to sit under three bullets. */
.mini-arch {
  margin-top: 22px; padding: 14px; display: grid; gap: 8px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--bg-alt);
}
.ma-row { display: flex; gap: 8px; }
.ma-row span, .ma-row b {
  flex: 1; text-align: center; padding: 10px 6px; border-radius: 8px;
  font: 500 12.5px/1.2 var(--mono); color: var(--ink-2);
  background: #fff; border: 1px solid var(--line);
}
.ma-if span { color: var(--indigo-ink); }
.ma-core b { flex: 1.5; background: var(--panel); border-color: var(--panel); color: #fff; font-weight: 650; }
.ma-store span { background: transparent; border-style: dashed; border-color: var(--line-2); }

/* ---------- Procurement ---------- */
.assure { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: 56px; align-items: start; }
.assure-grid { display: grid; grid-template-columns: 1fr 1fr; column-gap: 40px; border-top: 1px solid var(--line); }
.assure-item { padding: 28px 0; border-bottom: 1px solid var(--line); }
.assure-item:nth-last-child(-n+2) { border-bottom: 0; }
.assure-item h3 { font-size: 17.5px; font-weight: 650; letter-spacing: -0.015em; margin-bottom: 8px; }
.assure-item p { color: var(--ink-2); font-size: 15px; }

/* ---------- Closing band ----------
   Dark, so the page ends on a decision instead of fading into the footer's
   grey. Every band on the site is heading + sentence + one button, which is
   why a single rule can carry them all. */
.cta-band {
  background: var(--panel); color: #fff; border: 0; border-radius: 22px; padding: 88px 32px;
}
.cta-band::before {
  background:
    radial-gradient(700px 320px at 50% 120%, rgba(74, 91, 214, 0.35), transparent 70%),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.045) 0 1px, transparent 1px 72px);
}
.cta-band h2 { color: #fff; max-width: 22ch; margin-left: auto; margin-right: auto; }
.cta-band p { color: #b9c1cd; }
.cta-band .btn-grad, .cta-band .btn-primary { background: #fff; color: var(--ink); }
.cta-band .btn-grad:hover, .cta-band .btn-primary:hover { background: #e6e9ef; }
.cta-band .btn-ghost { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.3); }
.cta-band .btn-ghost:hover { border-color: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.06); }
.cta-actions { position: relative; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 32px; }
.cta-actions .btn { margin-top: 0; }
.cta-foot { position: relative; margin-top: 22px; font-size: 14px; }
.cta-band a:not(.btn) { color: #d4dbff; text-decoration-color: rgba(212, 219, 255, 0.5); }
.section-end { padding: 96px 0 104px; }

/* ---------- Footer ---------- */
.site-footer { background: #fff; padding: 72px 0 36px; }

/* ---------- Responsive ---------- */
@media (max-width: 920px) {
  .bento > .card, .bento > .bento-lg { grid-column: 1 / -1; }
  .assure { grid-template-columns: 1fr; gap: 36px; }
  .pmap-row { grid-template-columns: 1fr; }
  .pmap-layer { padding: 12px 18px; border-right: 0; border-bottom: 1px solid var(--line); }
  .pmap-cells { grid-auto-flow: row; grid-auto-columns: auto; }
  /* The products menu has no hover on a phone: inside the open hamburger the
     five products are listed under their heading instead. */
  .nav-menu { flex-direction: column; align-items: flex-start; width: 100%; }
  .nav-menu-top::after { display: none; }
  .nav-panel, .nav-menu:hover .nav-panel, .nav-menu:focus-within .nav-panel {
    display: grid; position: static; width: 100%; margin: 6px 0 0; padding: 0 0 0 12px;
    grid-template-columns: 1fr; gap: 0; border: 0; box-shadow: none; background: none;
  }
  .nav-panel::before { display: none; }
  .nav-links .nav-prod { padding: 8px 0; }
  .nav-prod span, .nav-prod i { display: none; }
  /* Sub-items under "Products" read lighter than it, not heavier. */
  .nav-prod b { font-weight: 500; font-size: 14.5px; color: var(--ink-2); }
}
@media (max-width: 560px) {
  .hero-flagship { padding: 72px 0 64px; }
  /* The two-line break is composed for a wide measure; on a phone "layer"
     was stranded on a line of its own. Let the headline wrap and balance. */
  .hero-flagship h1 .line, .split-hero h1 .line { display: inline; }
  .split-hero .actions { flex-direction: column; align-items: stretch; }
  .split-hero .actions .btn { width: 100%; text-align: center; }
  .hero-flagship .sub { font-size: 17.5px; }
  .pmap { margin-top: 48px; border-radius: 14px; }
  .assure-grid { grid-template-columns: 1fr; }
  .assure-item:nth-last-child(2) { border-bottom: 1px solid var(--line); }
  .cta-band { padding: 64px 22px; border-radius: 18px; }
  .section-head h2 { font-size: 31px; }
}

/* ---------- Product page parts (first used by /fs) ---------- */
/* Split hero: the claim on the left, the thing itself on the right. Used where
   a product can be shown working in a few lines, which a centred hero with
   three buttons under it cannot do. */
.split-hero { padding: 96px 0 88px; border-bottom: 1px solid var(--line); position: relative; overflow: hidden; }
.split-hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(90deg, #fff 30%, rgba(255, 255, 255, 0.4) 70%, rgba(255, 255, 255, 0.75)),
    repeating-linear-gradient(90deg, rgba(13, 17, 23, 0.045) 0 1px, transparent 1px 80px),
    repeating-linear-gradient(0deg, rgba(13, 17, 23, 0.045) 0 1px, transparent 1px 80px);
}
.split-hero .container {
  position: relative; display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
  gap: 64px; align-items: center;
}
/* Grid items default to min-width:auto, and a terminal's pre lines are
   unbreakable, so the column would take the width of the longest command and
   push the page sideways on a phone. Same trap as .plan-hero, same fix. */
.split-hero .container > * { min-width: 0; }
.split-hero h1 {
  font-size: clamp(40px, 5vw, 62px); font-weight: var(--display-weight);
  letter-spacing: -0.045em; line-height: 1.04;
}
.split-hero .badge { margin-bottom: 26px; }
.split-hero .sub { margin-top: 24px; font-size: 19px; line-height: 1.6; color: var(--ink-2); max-width: 36em; }
.split-hero .actions { margin-top: 34px; display: flex; gap: 12px; flex-wrap: wrap; }
.hero-note { margin-top: 22px; font-size: 14px; color: var(--ink-3); }
.split-hero .term { box-shadow: 0 40px 80px -44px rgba(11, 16, 24, 0.55); }

/* "Built on" strip: the provenance line, set as a ruled band rather than a
   badge, because it is a fact about the product, not a decoration on it. */
.oss-strip { border-bottom: 1px solid var(--line); background: var(--bg-alt); }
.oss-strip .container { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 32px; padding-top: 20px; padding-bottom: 20px; }
.oss-strip b { font-size: 14.5px; font-weight: 650; }
.oss-strip span { font: 500 13px/1.4 var(--mono); color: var(--ink-2); }
.oss-strip a { margin-left: auto; font-size: 14px; }

/* Capability grid: one hairline frame, six cells. The frame is drawn once and
   the cells share edges, which is what makes a set of six read as one system
   instead of six cards that happen to be neighbours. */
.fgrid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--line); gap: 1px;
}
.fcell { background: #fff; padding: 34px 32px 36px; }
.fcell .fno { display: block; font: 600 12px/1 var(--mono); letter-spacing: 0.08em; color: var(--cyan-text); margin-bottom: 18px; }
.fcell h3 { font-size: 19px; font-weight: 650; letter-spacing: -0.02em; margin-bottom: 10px; }
.fcell p { color: var(--ink-2); font-size: 15px; line-height: 1.65; }

/* Architecture figure, drawn in HTML so it reflows on a phone instead of
   shrinking a fixed-width drawing to unreadable labels. */
.arch { margin: 0; max-width: 1000px; margin-inline: auto; }
.arch-stack {
  display: grid; gap: 0; border: 1px solid var(--line-2); border-radius: 18px; overflow: hidden; background: #fff;
}
.arch-row { display: grid; grid-template-columns: 170px minmax(0, 1fr); border-top: 1px solid var(--line); }
.arch-row:first-child { border-top: 0; }
.arch-label {
  display: flex; align-items: center; padding: 0 20px; background: var(--bg-alt); border-right: 1px solid var(--line);
  font: 600 12px/1.3 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3);
}
.arch-cells { display: flex; flex-wrap: wrap; gap: 10px; padding: 16px; }
.arch-cells span {
  flex: 1 1 0; min-width: 120px; text-align: center; padding: 13px 10px; border-radius: 10px;
  border: 1px solid var(--line); background: #fff; font-size: 14px; font-weight: 550; color: var(--ink);
}
.arch-cells span small { display: block; margin-top: 3px; font-size: 12.5px; font-weight: 400; color: var(--ink-3); }
.arch-core .arch-cells { background: var(--panel); }
.arch-core .arch-label { background: #151a23; color: #b9c1cd; border-right-color: rgba(255, 255, 255, 0.08); }
.arch-core .arch-cells span { background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.14); color: #fff; }
.arch-core .arch-cells span small { color: #b9c1cd; }
.arch-store .arch-cells span { border-style: dashed; border-color: var(--line-2); background: transparent; }
.arch figcaption { margin: 18px auto 0; max-width: 700px; text-align: center; color: var(--ink-3); font-size: 14.5px; line-height: 1.6; }

/* Four code samples, each a worked example against the same namespace. */
.codegrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.codegrid > * { min-width: 0; }
.codegrid .codecell h3 { font-size: 17px; font-weight: 650; letter-spacing: -0.015em; margin-bottom: 4px; }
.codegrid .codecell > p { color: var(--ink-3); font-size: 14.5px; margin-bottom: 14px; }
.codegrid .term { box-shadow: none; }
.codegrid .term pre { font-size: 12.5px; }
/* A comparison in words, not figures: sans, and allowed to wrap. */
.dsheet.plain td { font-family: inherit; font-size: 14.5px; white-space: normal; color: var(--ink-2); }

/* Workloads: ruled rows, each with its evidence linked where there is some. */
.uses { border-top: 1px solid var(--line); }
.use {
  display: grid; grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); gap: 12px 48px;
  padding: 30px 0; border-bottom: 1px solid var(--line);
}
.use:last-child { border-bottom: 0; }
.use h3 { font-size: 20px; font-weight: 650; letter-spacing: -0.02em; }
.use p { color: var(--ink-2); font-size: 15.5px; }
.use .evidence { margin-top: 10px; font-size: 14px; color: var(--ink-3); }

/* A figure with a source, not a claim. */
.src-note { margin-top: 16px; font-size: 14px; color: var(--ink-3); max-width: 760px; }

@media (max-width: 920px) {
  .split-hero .container { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .fgrid { grid-template-columns: 1fr 1fr; }
  .codegrid { grid-template-columns: minmax(0, 1fr); }
  .use { grid-template-columns: 1fr; }
  .arch-row { grid-template-columns: 1fr; }
  .arch-label { padding: 12px 16px; border-right: 0; border-bottom: 1px solid var(--line); }
  .oss-strip a { margin-left: 0; }
}
@media (max-width: 560px) {
  .split-hero { padding: 64px 0 56px; }
  .fgrid { grid-template-columns: 1fr; }
  .fcell { padding: 28px 22px; }
  .arch-cells span { min-width: 100%; }
}

/* ---------- Inner pages, flagship pass ---------- */
/* Cards without an icon kept the 38px indent that clears one: every blog and
   docs card title started to the right of its own meta line and excerpt. The
   indent now exists only where the icon does. */
.card:not(:has(.icon)) h3, .card:not(:has(.icon)) .card-layer { padding-left: 0; }
.blog-list .card h3 a { color: var(--ink); }
.blog-list .card h3 a:hover { color: var(--indigo); }

/* One primary button. The site had two: near-black in the header and every
   hero, brand indigo on the pricing and product bands. Two primaries on one
   site means neither reads as the primary. Indigo stays the link colour. */
.btn-grad { background: var(--ink); }
.btn-grad:hover { background: #262b36; }

/* Notes and caveats: a neutral panel, not a blue alert box. The copy in them
   is a statement of status, and tinting it the brand colour made the least
   promotional sentence on each page look like the most promotional one. */
.callout { background: var(--bg-alt); border-color: var(--line); color: var(--ink-2); border-radius: var(--radius); }
.callout svg { stroke: var(--ink-3); }

/* Centred product heroes: the status chip leads the headline, as on /fs and
   the home page, and the drafting grid gives the band the same ground. The
   chip stays after the h1 in the markup, so the document outline is unchanged. */
.page-hero.center { position: relative; overflow: hidden; padding: 112px 0 96px; }
.page-hero.center::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.7) 55%, #fff 92%),
    repeating-linear-gradient(90deg, rgba(13, 17, 23, 0.045) 0 1px, transparent 1px 80px),
    repeating-linear-gradient(0deg, rgba(13, 17, 23, 0.045) 0 1px, transparent 1px 80px);
  background-position: center top;
}
.page-hero.center .container { position: relative; display: flex; flex-direction: column; align-items: center; }
.page-hero.center .badge { order: -1; margin: 0 0 24px; }
.page-hero.center h1 { font-size: 60px; line-height: 1.05; letter-spacing: -0.045em; }
.page-hero.center p { font-size: 19px; max-width: 600px; }

/* Long-form reading: 17px on a 640px measure (about 76 characters), up from
   15.5px on 542px. The old size was set for a denser layout; next to 52px
   titles and a 1200px canvas it read as a footnote. */
.article > * { max-width: 640px; }
.article p, .article li { font-size: 17px; line-height: 1.75; }
.article h2 { font-size: 26px; font-weight: 650; letter-spacing: -0.025em; margin: 48px 0 14px; }
.article h3 { font-size: 19px; font-weight: 650; letter-spacing: -0.015em; margin: 30px 0 10px; }
.article > .table-scroll, .article > pre, .article > figure, .article > .diagram { max-width: 820px; }

@media (max-width: 560px) {
  /* A phone reads the centred hero as mixed alignment: the prose under it is
     already left-aligned at this width for readability, so the chip and the
     headline follow it rather than sitting centred above it. */
  .page-hero.center { padding: 72px 0 60px; text-align: left; }
  .page-hero.center h1 { font-size: 34px; }
  .page-hero.center .container { align-items: stretch; }
  .page-hero.center .badge { align-self: flex-start; }
  .article p, .article li { font-size: 16.5px; }
  /* The FS tile's drawing: four cells in a row leave "Runix FS" clipped at
     phone width, so the core gets a row of its own above its tiers. */
  .ma-core { flex-wrap: wrap; }
  .ma-core b { flex: 1 0 100%; }
  .ma-row span, .ma-row b { font-size: 12px; padding: 9px 4px; }
  /* Label above value: a 148px label column leaves the value a third of a
     phone, and every value wrapped to two or three lines. */
  .facts .frow { grid-template-columns: 1fr; gap: 2px; }
  .facts .k { min-width: 0; font-size: 13px; }
}
@media (max-width: 920px) and (min-width: 561px) {
  .page-hero h1 { font-size: 42px; }
  .page-hero.center h1 { font-size: 46px; }
}

/* Published figures, set large. Each carries its source in the caption under
   it, because a number without a source on this site would be the first one. */
.stats-band { border-bottom: 1px solid var(--line); }
.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; }
.stats > div { padding: 44px 28px 40px 0; }
.stats > div + div { padding-left: 28px; border-left: 1px solid var(--line); }
.stats dt { font-size: 44px; font-weight: var(--display-weight); letter-spacing: -0.04em; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.stats dd { margin: 12px 0 0; color: var(--ink-3); font-size: 14px; line-height: 1.5; max-width: 26ch; }
.stats-src { padding: 0 0 22px; margin: 0; color: var(--ink-3); font-size: 13px; }
@media (max-width: 920px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats > div:nth-child(3) { padding-left: 0; border-left: 0; }
  .stats > div:nth-child(n+3) { border-top: 1px solid var(--line); }
}
@media (max-width: 560px) {
  .stats { grid-template-columns: 1fr; }
  .stats > div, .stats > div + div { padding: 28px 0; border-left: 0; }
  .stats > div + div { border-top: 1px solid var(--line); }
  .stats dt { font-size: 38px; }
}
