/* ============================================================
   BRAND TOKENS — edit only the palette below to rebrand
   ============================================================ */
:root {
    /* raw brand palette — single source of truth */
    --brand-void:    #0F0F0F;
    --brand-static:  #F7F7F5;
    --brand-hull:    #869392;
    --brand-pulse:   #D5EF65;
    --brand-violet:  #A188FC;
    --brand-flare:   #FA4321;

    /* Archivo Display = Extra Condensed cut (brand guide width spec: 62) */
    --font-display: 'Archivo Display', sans-serif;
    --font-body:    'Geist', ui-sans-serif, sans-serif;
    --font-mono:    'Geist Mono', ui-monospace, monospace;

    --nav-h:  60px;
    /* Lines on the content (from Albedo): each section has an edge line
       --frame-x in from the window, blocks reach out to meet it, and all
       text sits --pad inside any line. So the gutter is line + padding. */
    --frame-x: clamp(0.5rem, 1vw, 1rem);
    --pad:     clamp(1.25rem, 2vw, 2rem);
    --gutter:  calc(var(--frame-x) + var(--pad));
    /* Space round detached cards (pricing, FAQ), so the lines show between. */
    --card-gap: 1rem;
    --btn-h: clamp(3rem, 3.4vw, 3.75rem);
    /* Accent for the page frame: the nav action block and the hero rail.
       Fill only: Pulse can't carry text on Static, so accent text that
       used to follow it (About labels, active nav link) is Flare. */
    --frame-accent: var(--brand-pulse);
    /* Hero sizing. The rail is 240px, or half a grid column once that's
       wider (the 1025px block); its name fills the hero's height (padding
       takes 9rem; the two turned lines span 4.4em) unless the rail's width
       (1.75em + 5rem) caps it first.
       The nav's action block shares --rail-w, so the two stack into one
       column. */
    --hero-h:     clamp(560px, calc(100svh - var(--nav-h)), 1100px);
    --rail-w:     240px;
    --rail-title: min(calc((var(--hero-h) - 9rem) / 4.4), calc((var(--rail-w) - 5rem) / 1.75));
    /* Film grain tile — grey fractal noise, for the page grain layer and .screen */
    --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Semantic colour tokens — derive from the palette above, don't hardcode
   colours elsewhere. Brand guide 4.2 lets sections use different approved
   pairings, so there are two sets:
   - Static (light): the site. .theme-static restates it for the docs
     pages, whose ReDoc/JSDoc renderers carry their own light palette.
   - Void (dark): only on blocks marked .theme-void (the hero sits over a
     dark render).
   Pulse can't carry text or thin lines on Static (about 1.2:1), so the
   light set's accent is Void; Pulse shows as fills and on Void. */
:root,
.theme-static {
    color-scheme: light;
    --color-bg:          var(--brand-static);
    /* Opaque, so the background grid stops at cards and panels */
    --color-surface:     color-mix(in srgb, var(--brand-static) 92%, var(--brand-hull) 8%);
    --color-fg:          var(--brand-void);
    --color-fg-muted:    color-mix(in srgb, var(--brand-void) 70%, var(--brand-static)); /* ≈7:1 */
    --color-border:      color-mix(in srgb, var(--brand-void) 14%, transparent);
    --color-accent:      var(--brand-void);       /* primary action color */
    --color-accent-fg:   var(--brand-static);     /* text/icon on accent bg */
    --color-indicator:   var(--brand-violet);
    /* The one line colour: section edges, block borders. Tinted with Hull. */
    --block-line:        color-mix(in srgb, var(--brand-hull) 70%, transparent);

    --color-danger:         var(--brand-flare);
    --color-warning-bg:     color-mix(in srgb, var(--brand-pulse) 35%, var(--brand-static));
    --color-warning-border: var(--brand-void);
    --color-warning-text:   var(--brand-void);
    --color-nav-backdrop:   color-mix(in srgb, var(--brand-void) 85%, transparent);
    --color-modal-backdrop: color-mix(in srgb, var(--brand-void) 70%, transparent);
    color: var(--color-fg);
}

/* Pulse on Void: arrows and labels on Void buttons keep the brand accent. */
:root { --color-accent-fg: var(--brand-pulse); }

/* A dark block on a light page paints its own ground (the hero's pitch
   stacks under the render on phones, onto the page). Only the tokens that
   differ from the light set. */
.theme-void {
    color-scheme: dark;
    background-color: var(--color-bg);
    --color-bg:          var(--brand-void);
    --color-surface:     color-mix(in srgb, var(--brand-hull) 9%, var(--brand-void));
    --color-fg:          var(--brand-static);
    --color-fg-muted:    color-mix(in srgb, var(--brand-static) 68%, var(--brand-void)); /* ≈8:1 */
    --color-border:      color-mix(in srgb, var(--brand-static) 16%, transparent);
    --color-accent:      var(--brand-pulse);
    --color-accent-fg:   var(--brand-void);
    --block-line:        color-mix(in srgb, var(--brand-hull) 55%, transparent);
    --color-warning-bg:     color-mix(in srgb, var(--brand-pulse) 10%, var(--brand-void));
    --color-warning-border: var(--brand-pulse);
    --color-warning-text:   var(--brand-pulse);
    color: var(--color-fg);
}

/* ============================================================
   WEBFONTS — self-hosted, see static/fonts/
   ============================================================ */
@font-face {
    font-family: 'Archivo Display';
    src: url('/static/fonts/Archivo/static/Archivo_ExtraCondensed-Medium.ttf') format('truetype');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Archivo Display';
    src: url('/static/fonts/Archivo/static/Archivo_ExtraCondensed-Bold.ttf') format('truetype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist';
    src: url('/static/fonts/Geist/static/Geist-Regular.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist';
    src: url('/static/fonts/Geist/static/Geist-Medium.ttf') format('truetype');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist Mono';
    src: url('/static/fonts/Geist_Mono/static/GeistMono-Regular.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist Mono';
    src: url('/static/fonts/Geist_Mono/static/GeistMono-Medium.ttf') format('truetype');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist Mono';
    src: url('/static/fonts/Geist_Mono/static/GeistMono-Bold.ttf') format('truetype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* ============================================================
   RESET & BASE
   ============================================================ */
/* Anchor jumps stop below the fixed nav instead of under it. */
html {
    /* Short pages (dashboard) have no scrollbar; reserve its space anyway so
       the nav, sized off the viewport, doesn't shift between pages. */
    scrollbar-gutter: stable;
    scroll-behavior: smooth;
    scroll-padding-top: var(--nav-h);
}

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: var(--font-body);
    background-color: var(--color-bg);
    color: var(--color-fg);
    overflow-x: hidden;
    line-height: 1.5;
}

a {
    color: inherit;
    text-decoration: none;
    transition: opacity 0.2s ease;
}

a:hover {
    opacity: 0.6;
}

/* ============================================================
   TECHNICAL LABELS — Geist Mono (brand guide 5.3: labels, CTAs, data strings)
   ============================================================ */
.nav-links,
.nav-actions a,
.btn-primary,
.btn-secondary,
.btn-ghost,
.btn-danger,
.feature-tag,
.member-name,
.member-title,
.site-footer,
.token-header,
.token-cell,
.pricing-header h3,
.pricing-price span,
.pricing-faq summary,
.tab-logout,
.dialog-label,
.kernel-badge,
.scope-title {
    font-family: var(--font-mono);
}

/* ============================================================
   LAYOUT — edge to edge, no boxed column (Marathon runs every
   section to a small gutter off the window edge).
   ============================================================ */
.grid-container {
    display: flex;
    flex-direction: column;
    container-type: inline-size;
}

/* ============================================================
   NAVIGATION — a flush bar: Pulse logo square on the left, Pulse
   action block on the right, mono links between. No float, no blur.
   ============================================================ */
.top-nav {
    position: fixed;
    inset: 0 0 auto 0;
    height: var(--nav-h);
    display: flex;
    align-items: stretch;
    background-color: var(--color-bg);
    border-bottom: 1px solid var(--block-line);
    z-index: 100;
}

/* Void symbol on an accent square */
/* Void logo on a Static block: the full lockup, or the symbol alone in
   a square once the window is too narrow for it (1100px rule below).
   Padding clears the guide's 0.5X margin for the secondary logo. */
.nav-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: var(--nav-h);
    padding: 0 1.25rem;
    background-color: var(--brand-static);
}

/* Secondary logo is the horizontal lockup (6.2:1): ~162px wide at 26px. */
.brand-full {
    height: 26px;
    width: auto;
}

.brand-short {
    display: none;
    height: 22px;
    width: auto;
}

@media (max-width: 1100px) {
    .nav-brand { padding: 0; }
    .brand-full { display: none; }
    .brand-short { display: block; }
}

.nav-brand:hover { opacity: 1; }

.nav-links {
    display: flex;
    align-items: center;
    gap: 2.5rem;
    padding: 0 2.5rem;
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}

/* Pulse text on Static is about 1.2:1: Void link, Flare underline. */
.nav-link-active {
    color: var(--color-fg);
    text-decoration: underline 2px var(--brand-flare);
    text-underline-offset: 0.5em;
}

/* On the Pulse action block the underline is Void instead. */
.nav-actions .nav-link-active { text-decoration-color: var(--brand-void); }

/* Negative bottom margin: the action block runs over the nav's border, so
   nothing sits between it and the hero rail. */
.nav-actions {
    flex-shrink: 0;
    margin-left: auto;
    margin-bottom: -1px;
    display: flex;
    white-space: nowrap;
}

.nav-actions a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--rail-w);
    padding: 0 2rem;
    background-color: var(--frame-accent);
    color: var(--brand-void);
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    transition: background-color 0.2s ease;
}

.nav-actions a:hover {
    background-color: var(--brand-static);
    opacity: 1;
}

/* Exists only to be the mobile dropdown panel — display:contents keeps the
   links and actions as direct flex items of .top-nav everywhere else. */
.nav-menu {
    display: contents;
}

/* Mobile-only (shown in the 768px block) */
.nav-toggle {
    display: none;
    margin-left: auto;
    width: var(--nav-h);
    background: none;
    border: none;
    border-left: 1px solid var(--color-border);
    color: var(--color-fg);
    cursor: pointer;
}

.nav-toggle svg { display: block; margin: 0 auto; }

/* Burger ↔ X follows the state the script already writes for screen readers */
.nav-toggle .icon-close,
.nav-toggle[aria-expanded="true"] .icon-burger { display: none; }
.nav-toggle[aria-expanded="true"] .icon-close { display: block; }

/* ============================================================
   BUTTONS — solid blocks, no borders. Primary is the accent,
   secondary the foreground, and each hovers to the other.
   ============================================================ */
.btn-primary,
.btn-secondary,
.btn-ghost {
    display: inline-block;
    padding: 1rem 2rem;
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    text-align: center;
    border: none;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.btn-primary {
    background-color: var(--color-accent);
    color: var(--color-accent-fg);
}

.btn-secondary {
    background-color: var(--color-fg);
    color: var(--color-bg);
}

.btn-primary:hover {
    background-color: var(--color-fg);
    color: var(--color-bg);
    opacity: 1;
}

.btn-secondary:hover {
    background-color: var(--color-accent);
    color: var(--color-accent-fg);
    opacity: 1;
}

/* Third action in a row: an underlined text link. */
.btn-ghost {
    padding-inline: 0.5rem;
    background: none;
    color: var(--color-fg);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.35em;
}

/* Split button: a label cell and a square icon cell with a terminal prompt
   glyph (> inside the site, ↗ out of it), set in Geist Mono like the
   readouts (brand guide 5.3), one border round both. Primary carries the accent in its
   icon cell at rest; on hover the label tints and the icon fills. Built
   from the semantic tokens, so it follows the colour panels' swaps. */
.btn-split {
    display: inline-flex;
    align-items: center;
    gap: 2.5rem;
    height: var(--btn-h);
    padding: 0 0 0 1.5rem;
    border: 1px solid var(--block-line);
    background-color: color-mix(in srgb, var(--color-fg) 10%, var(--color-bg));
    color: var(--color-fg);
    text-align: left;
}

.btn-split .btn-icon {
    align-self: stretch;
    flex-shrink: 0;
    width: var(--btn-h);
    margin-left: auto;
    display: grid;
    place-items: center;
    border-left: 1px solid var(--block-line);
    font-size: 0;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.btn-split .btn-icon::before {
    content: '>';
    font-family: var(--font-mono);
    font-size: 1.1rem;
    font-weight: 500;
    line-height: 1;
}

.btn-split .btn-icon.is-ext::before { content: '\2197'; }

.btn-split.btn-primary .btn-icon,
.btn-split:hover .btn-icon {
    background-color: var(--color-accent);
    color: var(--color-accent-fg);
}

.btn-split:hover {
    background-color: color-mix(in srgb, var(--color-accent) 30%, var(--color-bg));
    color: var(--color-fg);
    opacity: 1;
}

.btn-split:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

/* The hero's second action hovers to Flare, so it doesn't echo the Pulse
   primary beside it. */
#hero .btn-secondary.btn-split {
    --color-accent:    var(--brand-flare);
    --color-accent-fg: var(--brand-void);
}

/* ============================================================
   SECTIONS
   ============================================================ */
/* Edge lines down the page and the footer, --frame-x in from the window.
   The hero is opaque, so they start under it. */
main,
.site-footer {
    background-image:
        linear-gradient(var(--block-line), var(--block-line)),
        linear-gradient(var(--block-line), var(--block-line));
    background-size: 1px 100%;
    background-position: left var(--frame-x) top 0, right var(--frame-x) top 0;
    background-repeat: no-repeat;
}

/* A rule across the footer's top, edge line to edge line, so the page's
   column lines end on something instead of stopping in mid-air. */
.site-footer {
    background-image:
        linear-gradient(var(--block-line), var(--block-line)),
        linear-gradient(var(--block-line), var(--block-line)),
        linear-gradient(var(--block-line), var(--block-line));
    background-size: 1px 100%, 1px 100%, calc(100% - 2 * var(--frame-x)) 1px;
    background-position: left var(--frame-x) top 0, right var(--frame-x) top 0, var(--frame-x) 0;
}

section {
    padding: 5rem var(--gutter);
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* ============================================================
   HERO — one frame: a grainy Star-Taker render with dim data
   strings over it, the name set vertically in a Void rail on the
   right, and a Pulse panel pinned bottom-left.
   ============================================================ */
.hero-title {
    font-family: var(--font-display);
    font-size: clamp(3rem, 8cqw, 10rem);
    font-weight: 700;
    line-height: 0.9;
    letter-spacing: -0.04em;
    margin-bottom: 2rem;
    text-transform: uppercase;
    max-width: 60cqw;
}

#hero {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--rail-w);
    height: var(--hero-h);
    margin-top: var(--nav-h);
    padding: 0;
}

.hero-visual {
    overflow: hidden;
}

/* pointer-events: none — the render is a backdrop, not something to drag
   off or right-click-save. */
.hero-visual > img {
    pointer-events: none;
    user-select: none;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 60% 45%;
    filter: contrast(1.15) saturate(1.3);
}

/* No top rule: the nav's action block runs straight into the rail, one
   Pulse column. */
.hero-rail {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 3.5rem 1rem;
    /* Same block as the nav's action above it, so the two read as one
       column. Void text: Static on Violet is under 3:1. */
    background-color: var(--frame-accent);
    color: var(--brand-void);
}

/* Reads top to bottom. Typeset text, not the logo, so turning it isn't
   the guide's "don't rotate the logo". */
#hero .hero-title {
    writing-mode: vertical-rl;
    font-size: var(--rail-title);
    line-height: 0.82;
    letter-spacing: -0.01em;
    color: inherit;
    max-width: none;
    margin: 0;
}

/* Under the title, in its turned frame: readouts, small marks and a
   barcode, in one line from the top. */
.rail-meta {
    writing-mode: vertical-rl;
    align-self: stretch;
    display: flex;
    align-items: center;
    gap: 0.9rem;
    overflow: hidden;
    color: inherit;
}

/* Thin-line marks from /static/assets/filler/small/, sized to the text so
   they carry the same weight. Void-only SVGs used as masks, so they take
   the accent. */
.rail-mark {
    flex-shrink: 0;
    width: 1.1rem;
    height: 1.1rem;
    background-color: currentColor;
    -webkit-mask: var(--g) center / contain no-repeat;
    mask: var(--g) center / contain no-repeat;
}

/* Bars run across the line, uneven like a real code. 48px of stops —
   the box height matches, so the pattern draws once. */
.rail-barcode {
    flex-shrink: 0;
    width: 0.9rem;
    height: 48px;
    background: linear-gradient(to bottom,
        currentColor 0 2px,   transparent 2px 4px,
        currentColor 4px 5px, transparent 5px 7px,
        currentColor 7px 10px, transparent 10px 11px,
        currentColor 11px 12px, transparent 12px 15px,
        currentColor 15px 17px, transparent 17px 18px,
        currentColor 18px 19px, transparent 19px 22px,
        currentColor 22px 25px, transparent 25px 26px,
        currentColor 26px 27px, transparent 27px 29px,
        currentColor 29px 31px, transparent 31px 33px,
        currentColor 33px 34px, transparent 34px 36px,
        currentColor 36px 39px, transparent 39px 40px,
        currentColor 40px 41px, transparent 41px 44px,
        currentColor 44px 46px, transparent 46px 47px,
        currentColor 47px 48px);
}

/* Readouts in the hero overlays' voice — mono, uppercase, tracked. */
.rail-text {
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* The pitch as plain type over the render, bottom-left. The scrim darkens
   that corner of the image so the type reads without a box. */
.hero-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(to top right,
        color-mix(in srgb, var(--brand-void) 90%, transparent) 0%,
        color-mix(in srgb, var(--brand-void) 55%, transparent) 35%,
        transparent 65%);
}

#hero .hero-pitch {
    position: absolute;
    left: var(--gutter);
    bottom: 3rem;
    z-index: 2;
    max-width: min(36rem, 50%);
}

.hero-pitch-title {
    font-family: var(--font-display);
    font-size: clamp(2.25rem, 3.2vw, 3.25rem);
    font-weight: 700;
    line-height: 0.9;
    text-transform: uppercase;
    margin-bottom: 1.25rem;
}

.hero-pitch-text {
    max-width: 30rem;
    margin-bottom: 1.75rem;
    color: var(--color-fg-muted);
    line-height: 1.6;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

/* Dim instrument readouts over a visual. Each string or block places
   itself with --x/--y (and --w/--h for blocks), in % of the visual. */
.data-noise {
    position: absolute;
    inset: 0;
    pointer-events: none;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    line-height: 1.6;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--brand-static) 40%, transparent);
}

.data-noise > * {
    position: absolute;
    left: var(--x);
    top: var(--y);
    white-space: pre;
}

.data-noise .hot { color: color-mix(in srgb, var(--brand-flare) 85%, transparent); }

/* ============================================================
   PANELS — solid colour blocks pinned to the edge of a visual.
   Text on Pulse stays Void: the guide's Static-on-Pulse pairing is
   about 1.2:1 and can't carry text.
   ============================================================ */
.panel-pulse {
    background-color: var(--brand-pulse);
    color: var(--brand-void);
}

/* ============================================================
   STATEMENT — one huge line, then short mono copy.
   ============================================================ */
.statement-title {
    font-family: var(--font-display);
    font-size: clamp(2.5rem, 4.4vw, 4.5rem);
    font-weight: 700;
    line-height: 0.85;
    letter-spacing: -0.01em;
    text-transform: uppercase;
    margin: 1rem 0 2.5rem;
}

/* Reading text: Geist, sentence case (brand guide 5.3 keeps mono for
   labels, CTAs and data strings). */
.body-copy {
    font-family: var(--font-body);
    font-size: clamp(1rem, 1.05vw, 1.125rem);
    line-height: 1.5;
    max-width: 40rem;
}

/* A solid block on the background grid: opaque, so the lines stop at it. */
.text-block {
    background-color: var(--color-bg);
    border: 1px solid var(--block-line);
    padding: var(--pad);
}

/* Visual that runs off the section's right edge. */
.bleed-right { margin-right: calc(-1 * var(--pad)); }
.bleed-right .demo-shot { outline: none; }

/* ============================================================
   GRAIN — the grit lives in the imagery; type stays crisp. A faint
   layer over the whole page, under the nav (100) so the logo never
   gets an effect (brand guide 3.6), and a heavy one on .screen.
   ============================================================ */
body::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 99;
    pointer-events: none;
    opacity: 0.06;
    background: var(--noise);
}

/* Screen capture shown as footage: grain blended into the picture, plus
   scanlines and darkened edges. In a wrapper because an <img> can't take
   pseudo-elements; isolation keeps the blend inside the wrapper. */
.screen {
    position: relative;
    isolation: isolate;
}

.screen::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: var(--noise);
    mix-blend-mode: screen;
    opacity: 0.18;
}

.screen::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        repeating-linear-gradient(to bottom, transparent 0 2px, rgb(0 0 0 / 0.22) 2px 3px),
        radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.5));
}

@media (prefers-contrast: more) {
    body::after,
    .screen::before,
    .screen::after,
    .data-noise { display: none; }
}

/* ============================================================
   ASSET CARD DEVICES — eyebrow tags, readouts
   (brand guide 6.6: eyebrow codes, terminal readouts, wayfinding
   strips borrowed from the asset-card mockups)
   ============================================================ */
.card-frame {
    position: relative;
}

/* The nav is fixed over the top of every page, so whatever section opens
   the page starts below it. */
main > section:first-child {
    padding-top: calc(var(--nav-h) + 4rem);
}

.eyebrow-code {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
    margin-bottom: 0.75rem;
}

/* Block, not flex: a flex container makes every child its own item, which
   tore the inline <span> highlights out of the preformatted text. */
.terminal-readout {
    position: relative;
    display: block;
    min-height: 300px;
    padding: 2rem;
    border: 1px solid var(--color-border);
    text-align: left;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    line-height: 1.9;
    letter-spacing: 0.05em;
    text-transform: none;
    color: var(--color-fg-muted);
}

.terminal-readout .readout-active {
    color: var(--color-fg);
}

/* Bare screenshot — no frame, no wrapper. The image scales to the column
   and sets its own height, so nothing can gap or crop around it.
   The offset box is an outline, not a border: outline-offset pushes it
   clear of the image without taking up layout space. */
.demo-shot {
    display: block;
    width: 100%;
    height: auto;
    outline: 1px solid var(--color-border);
    outline-offset: 12px;
}

/* ============================================================
   DECORATIVE FILLER ASSETS — static, randomly assigned on load
   (see the placement script at the bottom of home.html)
   ============================================================ */
.decor-slot {
    position: relative;
}

.decor-asset {
    position: absolute;
    top: 50%;
    left: 50%;
    pointer-events: none;
}

/* Corner-pinned slots (inside a readout panel or placeholder box) sit
   in a fixed corner instead of centering, so they never land over text. */
.decor-corner {
    position: absolute;
    bottom: 1rem;
    right: 1rem;
    width: 90px;
    height: 90px;
}

.decor-corner .decor-asset {
    top: auto;
    left: auto;
    bottom: 0;
    right: 0;
    width: 80px;
    height: auto;
}

.decor-scatter {
    min-height: 80px;
}

.decor-scatter .decor-asset {
    width: 70px;
    height: auto;
}

/* cover crops the pattern's wide edges to fill the box — clipped to the
   border-box automatically, no overflow:hidden needed. The pattern is
   Void-only, so it sits on an approved Hull ground (Void on Hull). */
.about-pattern {
    min-height: 340px;
    border: 1px solid var(--color-border);
    background: url('/static/assets/pattern/Pattern-1.svg') center / cover no-repeat var(--brand-hull);
}

/* The mark sits in the right-hand cell of a .feature-grid on both the 404 and
   error pages, so it centres itself within that cell. The grid's gap provides
   the spacing, and its collapse to one column at 768px handles the stacked
   layout — no separate rules needed for either page.
   Change the width here and both pages follow. */
.notfound-mark {
    align-self: center;
    justify-self: center;
    width: min(100%, 300px);
    height: auto;
}

/* Small filler marks sized to sit inside an existing text row rather than
   float over the layout like the JS-placed .decor-slot assets. */
#pricing {
    position: relative;
}

/* ============================================================
   LEGAL — prose column, wider than .feature-desc's 40rem
   ============================================================ */
.legal-body {
    max-width: 760px;
    color: var(--color-fg-muted);
    line-height: 1.8;
}

.legal-meta {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    margin-bottom: 3rem;
}

.legal-body h2 {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-fg);
    margin: 2.5rem 0 0.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--color-border);
}

.legal-body p {
    margin-bottom: 1rem;
}

.legal-body ul {
    margin: 0 0 1.5rem 1.25rem;
    padding: 0;
}

.legal-body li {
    margin-bottom: 0.5rem;
}

.legal-body strong {
    color: var(--color-fg);
    font-weight: 500;
}

.legal-body code {
    font-family: var(--font-mono);
    font-size: 0.85em;
    color: var(--color-fg);
}

.legal-body a {
    color: var(--color-fg);
    text-decoration: underline;
}

/* Pulled-out notice — reuses the pulse-based warning tokens. */
.legal-callout {
    margin: 0 0 1.5rem;
    padding: 1.25rem 1.5rem;
    background-color: var(--color-warning-bg);
    border-left: 2px solid var(--color-warning-border);
}

.legal-callout p:last-child {
    margin-bottom: 0;
}

/* Black mono tag — the cursor-following "[ TRY CLICKING ]" nudge and the
   sticker switch's hover label share this look. */
.sticker-hint,
.sticker-toggle::before {
    padding: 0.4rem 0.7rem;
    background-color: var(--color-accent);
    color: var(--color-accent-fg);
    font-family: var(--font-mono);
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s ease;
}

/* Cursor-following nudge toward the click-to-sticker easter egg. Positioned
   at the origin and moved with transform, so it never affects layout.
   z-index sits under .top-nav (100) and over the sticker layer (50). */
.sticker-hint {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 90;
}

.sticker-hint.is-visible {
    opacity: 1;
}

/* No cursor to follow — it would sit frozen in the corner. */
@media (hover: none) {
    .sticker-hint { display: none; }
}

/* Sticker on/off switch, pinned bottom-right — injected by stickers.js.
   Ruler-ticked track (as .bd-track), square thumb whose glyph morphs:
   bar = off, circle = on. Native checkbox underneath, so keyboard and
   screen readers work. z-index over the sticker layer (50) and hint (90),
   under .top-nav (100). */
.sticker-toggle {
    position: fixed;
    right: 1.5rem;
    bottom: 1.5rem;
    z-index: 95;
    display: flex;
    cursor: pointer;
}

/* Hover/keyboard-focus label, in the hint's look, sitting above the switch. */
.sticker-toggle::before {
    content: '[ TOGGLE STICKERS ]';
    position: absolute;
    right: 0;
    bottom: calc(100% + 0.5rem);
}

.sticker-toggle:hover::before,
.sticker-toggle:has(:focus-visible)::before {
    opacity: 1;
}

.sticker-toggle input {
    --w: 6rem;
    --h: 3rem;
    --pad: 4px;
    --s: calc(var(--h) - 2px - 2 * var(--pad)); /* thumb side */
    --x: 0px;                                     /* thumb travel */
    appearance: none;
    position: relative;
    flex-shrink: 0;
    width: var(--w);
    height: var(--h);
    margin: 0;
    box-sizing: border-box;
    border: 1px solid var(--color-fg);
    /* Ruler ticks scroll with the thumb. Travel (--w - --h = 3rem) is a whole
       number of 8px tiles, so the pattern lands back where it started. */
    background: linear-gradient(to right, transparent 7px, var(--color-fg-muted) 7px)
        var(--x) 50% / 8px 30% repeat-x var(--color-bg);
    cursor: pointer;
    transition: background-position 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.sticker-toggle input:checked { --x: calc(var(--w) - var(--h)); }

/* Thumb */
.sticker-toggle input::before {
    content: '';
    position: absolute;
    top: var(--pad);
    left: var(--pad);
    width: var(--s);
    height: var(--s);
    box-sizing: border-box;
    border: 1px solid var(--color-fg);
    background-color: var(--color-bg);
    transform: translateX(var(--x));
    transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.25s ease;
}

/* Glyph: a bar when off, morphing into a ring when on. */
.sticker-toggle input::after {
    content: '';
    position: absolute;
    top: calc(var(--pad) + var(--s) / 2);
    left: calc(var(--pad) + var(--s) / 2);
    width: 16px;
    height: 2px;
    box-sizing: border-box;
    border: 1px solid var(--color-fg);
    border-radius: 0;
    background-color: var(--color-fg);
    transform: translate(calc(-50% + var(--x)), -50%);
    transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1),
                width 0.25s ease, height 0.25s ease, border-radius 0.25s ease,
                border-width 0.25s ease, background-color 0.25s ease;
}

.sticker-toggle input:checked::before { background-color: var(--color-indicator); }

.sticker-toggle input:checked::after {
    width: 16px;
    height: 16px;
    border-width: 2px;
    border-radius: 50%;
    background-color: transparent;
}

.sticker-toggle input:focus-visible {
    outline: 2px solid var(--color-fg);
    outline-offset: 3px;
}

@media (max-width: 768px) {
    .sticker-toggle { right: 1rem; bottom: 1rem; }
}

/* Section flags — shared look, per-section placement below. Each host
   section is already positioned (.card-frame, or #pricing's own rule). */
.decor-flag {
    position: absolute;
    width: 175px;
    height: auto;
    pointer-events: none;
}

/* Flags sit below the nav, which covers the section's top ~6rem. */
#storytelling .decor-flag {
    top: 8rem;
    right: 12%;
    transform: rotate(-8deg);
}

#star-taker .decor-flag,
#barycenter .decor-flag {
    top: 8rem;
    right: 12%;
    transform: rotate(10deg);
}

/* Side stickers — margin art for the storytelling page's empty right
   column. Every knob is an inline custom property on the <img>, so the
   art and its placement are edited in the template, not here:
   --top (from the section top), --side (distance from the page edge),
   --size, --rotate. Hidden on narrow screens, where there is no margin
   left to put them in. */
.side-sticker {
    position: absolute;
    top: var(--top, 4rem);
    width: var(--size, 120px);
    height: auto;
    transform: rotate(var(--rotate, 0deg));
    pointer-events: none;
}

.side-sticker.side-left  { left: var(--side, 2rem); }
.side-sticker.side-right { right: var(--side, 4rem); }

/* Narrow screens have no free margin, so every fixed-position sticker would
   land on text. */
@media (max-width: 1024px) {
    .side-sticker,
    .decor-flag,
    .divider-sticker,
    .sticker-cluster,
    .decor-slot { display: none; }
}

/* Sticker bomb — permanent stickers piled on a visual. Every knob is an
   inline custom property on the <img> (see the comment in home.html), all in
   % of the host box so the pile keeps its shape at any width. Kept on narrow
   screens: the box stacks below the text there, so nothing gets covered.
   Same shadow as the click-placed stickers in stickers.js. */
.sticker-bomb {
    position: relative;
}

.sticker-bomb img {
    position: absolute;
    left: var(--x, 50%);
    top: var(--y, 50%);
    width: var(--size, 25%);
    height: auto;
    transform: translate(-50%, -50%) rotate(var(--rotate, 0deg));
    filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25));
    pointer-events: none;
}

/* Click-placed stickers (stickers.js) — same shadow as the bomb. */
.sticker {
    filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25));
}

/* Free-floating bomb: an invisible box placed in the section, the stickers
   positioned inside it as above. Must come after .sticker-bomb to win the
   position. Hidden with the other margin stickers at 1024px. */
.sticker-cluster {
    position: absolute;
    pointer-events: none;
}

.cluster-pricing {
    top: 1.5rem;
    right: 4rem;
    width: 210px;
    height: 230px;
}

/* margin-left:auto pins it to the far end of the summary's flex row,
   past the title, without disturbing the ::before "+" marker. */
.faq-mark {
    margin-left: auto;
    height: 20px;
    width: auto;
}

.about-shapes {
    position: absolute;
    bottom: -1.5rem;
    left: var(--gutter);
    display: flex;
    align-items: center;
    gap: 0.6rem;
    pointer-events: none;
}

.about-shapes .shape-circle {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background-color: var(--color-fg);
}

.about-shapes .shape-square {
    width: 14px;
    height: 14px;
    background-color: var(--color-fg);
}

.about-shapes .shape-triangle {
    width: 0;
    height: 0;
    border-left: 7px solid transparent;
    border-right: 7px solid transparent;
    border-bottom: 14px solid var(--color-fg);
}

.decor-team-mark {
    position: absolute;
    bottom: 1rem;
    right: 1rem;
    width: 50px;
    height: auto;
    transform: rotate(-10deg);
    pointer-events: none;
}

.section-strip {
    margin-top: 3rem;
    padding-top: 1rem;
    width: 100%;
    display: flex;
    justify-content: space-between;
    border-top: 1px solid var(--color-border);
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
}

/* Ruled break between the last section and the footer — margin-top clears
   the .about-shapes row, which hangs 1.5rem past the section's bottom edge. */
.page-divider {
    position: relative;
    height: 76px;
    /* No bottom margin: the footer's top rule sits right under the divider
       and is its fifth line. */
    margin: 3rem 0 0;
    /* Four rules between the edge lines, in the grid's line colour, the gap
       widening on the way down (10/16/22, then 28 to the footer rule). The
       position list IS the spacing spec; height is where the footer rule
       lands. */
    background-image:
        linear-gradient(var(--block-line) 0 0),
        linear-gradient(var(--block-line) 0 0),
        linear-gradient(var(--block-line) 0 0),
        linear-gradient(var(--block-line) 0 0);
    background-size: calc(100% - 2 * var(--frame-x)) 1px;
    background-position: var(--frame-x) 0, var(--frame-x) 10px, var(--frame-x) 26px, var(--frame-x) 48px;
    background-repeat: no-repeat;
}

/* Permanent sticker, unlike the click-spawned ones — pointer-events:none so
   it never swallows a click meant for the sticker layer underneath. */
.divider-sticker {
    position: absolute;
    top: 50%;
    right: 8%;
    width: 200px;
    height: auto;
    transform: translateY(-80%) rotate(10deg);
    pointer-events: none;
}

/* Binary symbol standing in for the URL — align-self stops the flex row
   from stretching it to the full strip height. */
.section-strip img {
    align-self: center;
    height: 10px;
    width: auto;
}

/* ============================================================
   FEATURE SECTIONS
   ============================================================ */
.feature-section {
    align-items: flex-start;
}

.feature-grid {
    display: grid;
    /* minmax(0, …) so a long unbreakable line can't widen a column and push
       the other one off-screen. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4rem;
    width: 100%;
}

.feature-tag {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.25em;
    color: var(--color-fg-muted);
    margin-bottom: 1rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.feature-tag::before {
    content: '';
    display: block;
    width: 8px;
    height: 8px;
    background-color: var(--color-accent);
    flex-shrink: 0;
}

#star-taker .feature-tag::before {
    background-color: var(--brand-flare);
}

#barycenter .feature-tag::before {
    background-color: var(--brand-violet);
}

.feature-title {
    font-family: var(--font-display);
    font-size: clamp(2.5rem, 4.4vw, 4.5rem);
    font-weight: 700;
    line-height: 0.9;
    margin-bottom: 1.5rem;
    letter-spacing: -0.02em;
    text-transform: uppercase;
}

.feature-desc {
    font-size: clamp(1rem, 1.05vw, 1.125rem);
    color: var(--color-fg-muted);
    line-height: 1.5;
    max-width: 40rem;
    margin-bottom: 3rem;
}

/* ============================================================
   TEAM GRID
   ============================================================ */
.team-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    width: 100%;
    margin: 0 auto;
    max-width: 1400px;
}

.team-cell {
    border-bottom: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    padding: 3rem;
}

.team-cell:nth-child(3n) {
    border-right: none;
}

.team-title {
    font-family: var(--font-display);
    font-size: 3rem;
    font-weight: 500;
    color: var(--color-fg-muted);
}

.member-cell {
    display: flex;
    gap: 1.5rem;
    align-items: center;
}

.member-photo {
    width: 80px;
    height: 80px;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    filter: grayscale(100%);
    flex-shrink: 0;
}

.member-name {
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.member-title {
    font-size: 0.75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--color-fg-muted);
    margin-top: 0.25rem;
}

/* ============================================================
   FOOTER
   ============================================================ */
.site-footer {
    /* Closes the grid-container's left/right rules, which otherwise just end. */
    border-bottom: 1px solid var(--color-border);
    padding: 2rem var(--gutter);
    text-align: left;
    font-size: 0.7rem;
    color: var(--color-fg-muted);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    display: flex;
    /* .grid-container also applies here and sets column — override it or the
       copyright and links stack instead of sitting on one row. */
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
}

.footer-links {
    display: flex;
    gap: 2rem;
}

/* ============================================================
   DASHBOARD — LAYOUT HELPERS
   ============================================================ */
.tokens-header-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 2rem;
}

.billing-cards {
    grid-template-columns: 1fr 1fr;
}

/* ============================================================
   DASHBOARD — TOKEN TABLE
   ============================================================ */
.token-container {
    border: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
}

/* Each row is its own grid, so columns must size from the track list alone:
   minmax(0, …) and fixed tracks never consult cell content, which keeps every
   row's columns in line. STATUS/ACTION are fixed to fit "[ REVOKED ]" and the
   REVOKE button without wrapping. */
.token-row {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1.5fr) minmax(0, 1.5fr) 10rem 8.5rem;
    border-bottom: 1px solid var(--color-border);
    align-items: center;
}

.token-row:last-child {
    border-bottom: none;
}

.token-header {
    background-color: var(--color-surface);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--color-fg-muted);
}

.token-cell {
    padding: 1.5rem;
    font-size: 0.85rem;
    letter-spacing: 0.1em;
    color: var(--color-fg-muted);
    /* Long aliases/prefixes wrap inside their column instead of spilling
       into the next one. */
    overflow-wrap: anywhere;
}

.btn-danger {
    display: inline-block;
    padding: 0.5rem 1rem;
    background-color: transparent;
    color: var(--color-danger);
    border: 1px solid color-mix(in srgb, var(--color-danger) 30%, transparent);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    cursor: pointer;
    transition: all 0.2s ease;
}

.revoke-icon { display: none; }
.action-revoked { display: none; }

.btn-danger:hover {
    background-color: color-mix(in srgb, var(--color-danger) 6%, transparent);
    border-color: var(--color-danger);
    opacity: 1;
}

/* ============================================================
   PRICING
   ============================================================ */
.pricing-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    width: 100%;
    gap: 2rem;
    margin-top: 3rem;
}

.pricing-card {
    padding: 2.5rem;
    display: flex;
    flex-direction: column;
    background-color: var(--color-surface);
    transition: transform 0.3s ease;
}

.pricing-card:hover {
    transform: translateY(-4px);
}

/* One accent per tier, carried on the card and read by its CTA's hover state.
   Cards with no tier class (the dashboard panels) simply have no accent. */
.tier-stargazer  { --card-accent: var(--brand-violet); }
.tier-pro        { --card-accent: var(--brand-pulse); }
.tier-commercial { --card-accent: var(--brand-flare); }

#pricing .pricing-card .btn-primary {
    transition: background-color 0.2s ease, color 0.2s ease;
}

/* opacity:1 defeats the global a:hover fade, which would otherwise mute the
   accent to 60%. Void text — Static fails contrast on every accent. */
#pricing .pricing-card .btn-primary:not(.btn-split):hover {
    background-color: var(--card-accent);
    color: var(--brand-void);
    opacity: 1;
}

.pricing-header {
    border-bottom: 1px solid var(--color-border);
    padding-bottom: 1.5rem;
    margin-bottom: 1.5rem;
}

.pricing-header h3 {
    font-size: 0.8rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
    margin: 0 0 1rem 0;
}

.pricing-price {
    font-family: var(--font-display);
    font-size: 2.5rem;
    font-weight: 700;
}

.pricing-price span {
    font-size: 0.85rem;
    letter-spacing: 0.15em;
    color: var(--color-fg-muted);
    font-weight: 400;
}

.pricing-features {
    list-style: none;
    padding: 0;
    margin: 0 0 3rem 0;
    flex-grow: 1;
}

.pricing-features li {
    font-size: 0.85rem;
    letter-spacing: 0.05em;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--color-border);
}

.pricing-features li.disabled {
    color: var(--color-fg-muted);
    text-decoration: line-through;
}

.pricing-card .btn-primary {
    text-align: center;
    width: 100%;
}

/* ============================================================
   WHY STAR-TAKER — reason cards reuse .pricing-card; the tier-*
   class on each card supplies its one accent
   ============================================================ */
.why-grid { width: 100%; }

/* Four steps in a row, two when that gets tight. */
.why-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 1200px) {
    .why-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Consecutive paragraphs read as one passage, not separate blocks. */
.feature-desc + .feature-desc { margin-top: -1.5rem; }

/* Storytelling's sticker bomb: an in-flow box (unlike the home pricing
   cluster), so it can sit in a grid column. */
.story-bomb {
    align-self: stretch;
    min-height: 22rem;
}

.why-head .feature-desc:last-child { margin-bottom: 0; }
.why-head + .why-grid { margin-top: 4rem; }

.why-card h3 {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 400;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
    margin: 0 0 1.25rem;
}

.why-card h3::before {
    content: '';
    width: 8px;
    height: 8px;
    flex-shrink: 0;
    background-color: var(--card-accent);
}

.why-line {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.05;
    text-transform: uppercase;
    margin-bottom: 1rem;
}

.why-card p {
    font-size: 0.9rem;
    line-height: 1.7;
    color: var(--color-fg-muted);
    margin: 0;
}

/* Card rows on the grid pages, at every width: cells, borders drawn by
   the 1px gap. */
.has-grid .why-grid {
    gap: 1px;
    background-color: var(--block-line);
    border: 1px solid var(--block-line);
}

.has-grid .why-grid > .why-card {
    padding: var(--pad);
    background-color: var(--color-bg);
}

.has-grid .why-grid > .why-card:hover { transform: none; }

/* Stacked (no column grid), the intro and How We Work need room between
   them and the stickers. */
@media (max-width: 1024px) {
    .why-head,
    .why-head > * + * { margin-top: 2.5rem; }
}

.why-start { margin-top: 5rem; }

/* Storytelling's call to action, out to the edge lines when stacked. */
.story-cta { margin: 3rem calc(-1 * var(--pad)) 0; }

/* Ruled list set in the display face, like the cards' headlines. */
.why-list {
    list-style: none;
    margin: 0 0 1.75rem;
    border-top: 1px solid var(--color-border);
}

.why-list li {
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--color-border);
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 2.2vw, 2rem);
    font-weight: 700;
    line-height: 1;
    text-transform: uppercase;
}

.why-licence {
    font-size: 0.85rem;
    letter-spacing: 0.05em;
    color: var(--color-fg-muted);
    margin: 3rem 0 0;
}

.why-licence a { color: var(--color-fg); }

/* ============================================================
   BLOCK DIAGRAM — barycenter.html. Each track draws its own block
   edges with a repeating gradient (--n blocks per row); the hit
   block (--i) and the playhead (--t, set on the figure) are placed
   in %, so the figure keeps its shape at any width.
   ============================================================ */
.bd-section { width: 100%; }

.bd-title {
    font-size: 2rem;
    margin-bottom: 2rem;
}

.block-diagram {
    display: grid;
    gap: 1.25rem;
    margin: 0 0 3rem;
    padding: 2.5rem;
    border: 1px solid var(--color-border);
}

.bd-row {
    display: grid;
    grid-template-columns: 14rem minmax(0, 1fr);
    gap: 1.5rem;
    align-items: center;
}

.bd-label {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    line-height: 1.6;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
}

.bd-label strong {
    display: block;
    font-weight: 400;
    color: var(--color-fg);
}

.bd-row.is-active .bd-label strong::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 0.5rem;
    background-color: var(--brand-violet);
}

.bd-track {
    position: relative;
    height: 2.75rem;
    border: 1px solid var(--color-fg);
    background-image: repeating-linear-gradient(to right,
        transparent 0 calc(100% / var(--n) - 1px),
        var(--color-fg) 0 calc(100% / var(--n)));
}

.bd-hit {
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(100% * var(--i) / var(--n));
    width: calc(100% / var(--n));
    outline: 2px solid var(--brand-violet);
    outline-offset: -2px;
}

.bd-row.is-active .bd-hit { background-color: var(--brand-violet); }

/* Playhead: one segment per track, overlapping the row gap so they read as
   a single line. */
.bd-track::after {
    content: '';
    position: absolute;
    top: -0.7rem;
    bottom: -0.7rem;
    left: var(--t);
    width: 2px;
    background-color: var(--color-fg);
}

.bd-ruler .bd-label {
    position: relative;
    display: flex;
    justify-content: space-between;
}

.bd-ruler .bd-label span:nth-child(2) {
    position: absolute;
    left: var(--t);
    transform: translateX(-50%);
    color: var(--color-fg);
}

.block-diagram figcaption {
    margin-top: 0.5rem;
    text-transform: none;
    letter-spacing: 0.05em;
}

.bd-notes { margin-top: 0; }

@media (max-width: 768px) {
    .block-diagram { padding: 1.25rem; }
    .bd-row { grid-template-columns: 1fr; gap: 0.5rem; }
    .bd-head .bd-label:first-child { display: none; }
    /* Labels now sit directly above each track — keep the playhead off them. */
    .bd-track::after { top: 0; bottom: 0; }
    .bd-title { font-size: 2rem; }
}

/* ============================================================
   PACKET SPEC — barycenter-format.html. A .byte-map is one row of
   field cells; each cell prints its start byte (data-off) under its
   left edge, and the map prints data-end under its right edge.
   ============================================================ */
.byte-map {
    position: relative;
    display: grid;
    grid-template-columns: repeat(var(--n), minmax(0, 1fr));
    margin-bottom: 1.75rem;   /* room for the offsets */
}

.byte-map span {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 3.25rem;
    margin-left: -1px;        /* shared borders */
    border: 1px solid var(--color-fg);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    letter-spacing: 0.05em;
    color: var(--color-fg);
}

.byte-map span::after,
.byte-map[data-end]::after {
    position: absolute;
    top: 100%;
    padding-top: 0.4rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--color-fg-muted);
}

.byte-map span::after {
    content: attr(data-off);
    left: 0;
    transform: translateX(-50%);
}

.byte-map[data-end]::after {
    content: attr(data-end);
    right: 0;
    transform: translateX(50%);
}

.byte-map span:first-child { margin-left: 0; }

/* Header's records run on past the map — open on the right. */
.byte-map .is-open {
    grid-column: span 2;
    justify-content: flex-start;
    padding-left: 1rem;
    border-right: none;
    border-style: solid none solid solid;
    color: var(--color-fg-muted);
}

.byte-map .is-optional {
    border-style: dashed;
    background-color: color-mix(in srgb, var(--brand-violet) 20%, transparent);
}

.spec-formats .why-card p { font-family: var(--font-mono); font-size: 0.8rem; }

.spec-desc { max-width: 760px; margin-bottom: 2rem; }
.spec-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.spec-table th,
.spec-table td {
    padding: 0.75rem 1rem 0.75rem 0;
    border-bottom: 1px solid var(--color-border);
    text-align: left;
    vertical-align: top;
}

.spec-table th {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 400;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
}

/* First two columns are field names and units — mono, kept on one line. */
.spec-table td:nth-child(-n+2) {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    white-space: nowrap;
}

.spec-table td:last-child { color: var(--color-fg-muted); }

#barycenter code,
#star-taker code {
    font-family: var(--font-mono);
    font-size: 0.85em;
    color: var(--color-fg);
}

.spec-callout { margin-top: 2rem; }

.spec-snippet { min-height: 0; }

@media (max-width: 768px) {
    .byte-map span { font-size: 0.7rem; }
    .spec-table td:nth-child(-n+2) { white-space: normal; }
}


/* ============================================================
   PRICING FAQ
   ============================================================ */
.pricing-faq {
    margin-top: 4rem;
    width: 100%;
    border: 1px solid var(--block-line);
    background-color: var(--color-bg);
}

.pricing-faq + .pricing-faq {
    margin-top: calc(2 * var(--card-gap));
}

.pricing-faq summary {
    padding: 1.5rem var(--pad);
    cursor: pointer;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 1rem;
}

.pricing-faq summary::-webkit-details-marker {
    display: none;
}

.pricing-faq summary::before {
    content: '+';
    font-size: 1.25rem;
    font-weight: 400;
    line-height: 1;
    color: var(--color-fg-muted);
    transition: transform 0.2s ease;
}

.pricing-faq[open] summary::before {
    transform: rotate(45deg);
}

.pricing-faq[open] summary {
    border-bottom: 1px solid var(--color-border);
}

.pricing-faq .faq-content {
    padding: var(--pad);
    color: var(--color-fg-muted);
    font-size: 0.9rem;
    line-height: 1.7;
}

.pricing-faq .faq-content p {
    margin: 0 0 1rem 0;
}

/* Same ruled rows as .pricing-features, so the tier cards and every FAQ list
   read as one system. Applied by selector rather than by adding the class to
   the licence templates — /legal shares those and wants plain prose bullets. */
.pricing-faq .faq-content ul {
    list-style: none;
    margin: 0 0 1rem 0;
    padding: 0;
}

.pricing-faq .faq-content li {
    font-size: 0.85rem;
    letter-spacing: 0.05em;
    padding: 0.75rem 0;
    margin-bottom: 0;
    border-bottom: 1px solid var(--color-border);
}

/* ============================================================
   DASHBOARD TABS
   ============================================================ */
.dashboard-nav {
    display: flex;
    gap: 2rem;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 3rem;
}

.tab-btn {
    background: transparent;
    border: none;
    color: var(--color-fg-muted);
    font-family: var(--font-mono);
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 1rem 0;
    cursor: pointer;
    position: relative;
    transition: color 0.2s ease;
}

.tab-btn:hover {
    color: var(--color-fg);
}

.tab-btn.active {
    color: var(--color-accent);
}

.tab-btn.active::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    width: 100%;
    height: 2px;
    background-color: var(--color-accent);
}

.tab-logout {
    margin-left: auto;
    align-self: center;
    padding: 0.4rem 0.9rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-danger);
    border: 1px solid color-mix(in srgb, var(--color-danger) 35%, transparent);
    transition: all 0.2s ease;
}

.tab-logout:hover {
    background-color: color-mix(in srgb, var(--color-danger) 6%, transparent);
    border-color: var(--color-danger);
    opacity: 1;
}

/* ============================================================
   USAGE BAR
   ============================================================ */
.usage-bar-container {
    width: 100%;
    height: 4px;
    /* Its own tint, not --color-surface: the bar sits on surface cards. */
    background-color: color-mix(in srgb, var(--color-fg) 14%, transparent);
    overflow: hidden;
}

.usage-bar-fill {
    height: 100%;
    background-color: var(--color-accent);
}

/* ============================================================
   TOKEN FLASH — one-time new token reveal
   ============================================================ */
.token-flash {
    background-color: var(--color-warning-bg);
    border: 1px solid var(--color-warning-border);
    padding: 1.5rem;
    margin-bottom: 2rem;
}

.token-flash-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 0.5rem;
}

.token-flash-code {
    font-family: var(--font-mono);
    font-size: 0.9rem;
    word-break: break-all;
    flex: 1;
    color: var(--color-fg);
}

/* ============================================================
   GENERATE TOKEN DIALOG
   ============================================================ */
.token-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border: 1px solid var(--color-border);
    padding: 2.5rem;
    max-width: 480px;
    width: 90%;
    background: var(--color-bg);
    margin: 0;
}

.token-dialog::backdrop {
    background: var(--color-modal-backdrop);
}

.dialog-label {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
    margin-bottom: 0.5rem;
}

.dialog-input {
    width: 100%;
    padding: 0.8rem 1rem;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--color-fg);
    margin-bottom: 1.5rem;
    outline: none;
}

.dialog-input:focus {
    border-color: var(--color-accent);
}

/* File input needs its own box model — .dialog-input's text padding leaves the
   native button clipped */
input[type="file"].dialog-input {
    padding: 0.65rem 0.75rem;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    cursor: pointer;
}

.dialog-actions {
    display: flex;
    gap: 1rem;
    justify-content: flex-end;
}

/* ============================================================
   TOKEN SCOPE — public data vs. private kernel access
   Both options render at once; the choice is immutable after
   creation, so it has to be readable before it's made.
   ============================================================ */
.scope-option {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    border: 1px solid var(--color-border);
    padding: 1rem;
    margin-bottom: 0.75rem;
    cursor: pointer;
}

.scope-option:last-of-type {
    margin-bottom: 1.5rem;
}

.scope-option:has(input:checked) {
    border-color: var(--color-accent);
}

.scope-option-warn:has(input:checked) {
    background-color: var(--color-warning-bg);
    border-color: var(--color-warning-border);
}

.scope-option input[type="radio"] {
    margin-top: 0.15rem;
    accent-color: var(--color-accent);
    flex-shrink: 0;
}

.scope-title {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--color-fg);
    margin-bottom: 0.4rem;
}

.scope-desc {
    display: block;
    font-size: 0.8rem;
    line-height: 1.6;
    color: var(--color-fg-muted);
}

.scope-desc + .scope-desc {
    margin-top: 0.5rem;
}

/* Marks a token that can read the owner's uploaded kernels — never safe to
   embed client-side, so it's called out in the list, not just at creation */
.kernel-badge {
    display: inline-block;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    padding: 0.15rem 0.4rem;
    background-color: var(--color-warning-bg);
    border: 1px solid var(--color-warning-border);
    color: var(--color-warning-text);
    vertical-align: middle;
    white-space: nowrap;
}

/* Allowed URLs — the rows only matter for "Selected URLs", so they stay
   hidden until it's checked. No JS: the handler ignores them otherwise. */
.origins-list {
    display: none;
    margin-bottom: 1.5rem;
}

form:has([name="origins_mode"][value="selected"]:checked) .origins-list {
    display: block;
}

.origin-row {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.origin-row .dialog-input {
    margin-bottom: 0;
    font-family: var(--font-mono);
}

.origin-row .btn-secondary {
    flex-shrink: 0;
}

.origins-error {
    font-size: 0.8rem;
    line-height: 1.6;
    color: var(--color-danger);
    margin-top: 0.75rem;
}

.origins-error:empty {
    display: none;
}

/* Under the alias in the key list — same cell as the badge, because the mobile
   collapse hides cells by position */
.token-origins {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 400;
    color: var(--color-fg-muted);
    margin-top: 0.25rem;
    overflow-wrap: anywhere;
}

/* ============================================================
   HOME FEATURE SECTIONS — the lower half of the home page, built
   from separate chunks on open Void: a giant name, short mono copy,
   a visual run off the page edge, and a panel flush to the other
   edge, and the section's corner brackets. No ornament beyond that.
   Classes, not ids: the ids are shared with product pages.
   ============================================================ */
.mx-sec { position: relative; }

/* Plain Void, overriding the shared striping on these two ids. */
#star-taker.mx-sec,
#pricing.mx-sec { background-color: transparent; }

.mx-head .statement-title { margin: 0.5rem 0 0; }

.statement-title em {
    font-style: normal;
    color: var(--brand-violet);
}

/* Short numbered rows: Geist text, mono counters. */
.mono-list {
    list-style: none;
    counter-reset: n;
    margin: 1.75rem 0 1.5rem;
    font-size: 0.95rem;
    line-height: 1.45;
}

.mono-list li {
    counter-increment: n;
    display: grid;
    grid-template-columns: 2.5rem minmax(0, 1fr);
    padding: 0.55rem 0;
    border-top: 1px solid var(--color-border);
}

.mono-list li::before {
    content: counter(n, decimal-leading-zero);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    line-height: 1.8;
    color: var(--color-accent);
}

/* Text links lined up with the copy above them. */
.mx-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-left: -0.5rem;
}

/* A filled button in the row: undo the row's text offset so its edge
   lines up with the copy too. */
.mx-links > .btn-split { margin: 0 0.5rem; }
.mx-links { align-items: center; }

/* ---- Blocks (from Inversion and Albedo): copy, panel and visual as
   solid cells inside one border, half and half. The 1px gap shows the
   container's line colour between the opaque cells, which draws every
   shared border. */
.mx-split,
.mx-duo,
.mx-cols {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px;
    margin-top: 3.5rem;
    background-color: var(--block-line);
    border: 1px solid var(--block-line);
}

/* Blocks reach out by --pad so their borders sit on the section's edge
   lines and their padded text lines up with the loose text. stretch:
   .feature-section aligns children to the start. */
.mx-split,
.mx-duo,
.mx-cols,
#pricing .pricing-grid,
.pricing-faq {
    align-self: stretch;
    width: auto;
    margin-inline: calc(-1 * var(--pad));
}

/* Detached cards sit --card-gap inside the edge lines instead. */
#pricing .pricing-grid,
.pricing-faq { margin-inline: calc(var(--card-gap) - var(--pad)); }

#statement .text-block { margin-left: calc(-1 * var(--pad)); }
#pricing > .body-copy { margin-top: 2rem; }

.mx-copy {
    position: relative;
    grid-column: 1;
    grid-row: 1;
    padding: var(--pad);
    background-color: var(--color-bg);
}

/* Split: copy over its panel on one side, the visual down the other. */
.mx-split { grid-template-rows: 1fr auto; }

.mx-visual {
    grid-column: 2;
    grid-row: 1 / -1;
    position: relative;
    min-height: 24rem;
    overflow: hidden;
    border: 0;
}

.mx-panel { grid-column: 1; grid-row: 2; }

.is-mirror .mx-copy,
.is-mirror .mx-panel  { grid-column: 2; }
.is-mirror .mx-visual { grid-column: 1; }

/* Photo visuals only — a sticker box places its own images. */
.mx-visual:not(.sticker-bomb) > img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 50%;
    filter: contrast(1.15) saturate(1.3);
    pointer-events: none;
    user-select: none;
}

/* ---- Flush panel: body text, then the CTA cut into the bottom corner
   on the side away from the page edge. Text starts on the page gutter. */
.flush-panel {
    display: flex;
    flex-direction: column;
    background-color: var(--color-bg);
    color: var(--color-fg);
}

.flush-body { padding: var(--pad); }

.flush-title {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 2.4vw, 2.5rem);
    font-weight: 700;
    line-height: 0.9;
    text-transform: uppercase;
    margin: 0.25rem 0 0.9rem;
}

.flush-text {
    max-width: 34rem;
    color: var(--color-fg-muted);
    line-height: 1.6;
}

/* Pinned to the panel's foot, inset so panel colour surrounds it. */
.flush-panel > .btn-split {
    align-self: flex-start;
    margin: auto var(--pad) var(--pad);
}

/* Pulse panel: swaps the tokens, so buttons and text inside follow. Void
   for text and accents — Static on Pulse is about 1.2:1, and the guide
   keeps one accent per asset. */
.flush-panel.panel-pulse {
    --color-bg:        var(--brand-pulse);
    --color-fg:        var(--brand-void);
    --color-fg-muted:  color-mix(in srgb, var(--brand-void) 75%, var(--brand-pulse));
    --color-border:    color-mix(in srgb, var(--brand-void) 20%, transparent);
    --block-line:      color-mix(in srgb, var(--brand-void) 35%, transparent);
    --color-accent:    var(--brand-void);
    --color-accent-fg: var(--brand-pulse);
}

/* Buttons inside a panel's body, in a row. */
.flush-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 1.75rem 0 0.75rem;
}

/* Violet panel, Void text and accents (Static on Violet is under 3:1). */
.flush-panel.panel-violet {
    --color-bg:        var(--brand-violet);
    --color-fg:        var(--brand-void);
    --color-fg-muted:  color-mix(in srgb, var(--brand-void) 78%, var(--brand-violet));
    --color-border:    color-mix(in srgb, var(--brand-void) 20%, transparent);
    --block-line:      color-mix(in srgb, var(--brand-void) 35%, transparent);
    --color-accent:    var(--brand-void);
    --color-accent-fg: var(--brand-violet);
    background-color: var(--brand-violet);
}

#barycenter .panel-violet .feature-tag::before { background-color: var(--color-accent); }

/* Beats the #star-taker Flare tag square, which would put a second
   accent on the panel. */
#star-taker :is(.panel-pulse, .panel-flare) .feature-tag::before { background-color: var(--color-accent); }

/* Flare panel, Void text (Static on Flare is under 3:1). */
.panel-flare {
    --color-bg:        var(--brand-flare);
    --color-fg:        var(--brand-void);
    --color-fg-muted:  color-mix(in srgb, var(--brand-void) 82%, var(--brand-flare));
    --color-border:    color-mix(in srgb, var(--brand-void) 25%, transparent);
    --block-line:      color-mix(in srgb, var(--brand-void) 35%, transparent);
    --color-accent:    var(--brand-void);
    --color-accent-fg: var(--brand-flare);
}

/* Section accents for buttons and tag squares. */
.mx-flare {
    --color-accent:    var(--brand-flare);
    --color-accent-fg: var(--brand-void);
}

/* ---- Duo: copy and a panel side by side, same height. .is-mirror puts
   the panel on the left. */
.mx-duo .mx-panel           { grid-column: 2; grid-row: 1; }
.mx-duo.is-mirror .mx-panel { grid-column: 1; }

/* One request, in the panel: Void box, Static text, Violet status. */
.panel-code {
    margin: 1.5rem 0 0;
    padding: 1rem 1.25rem;
    overflow-x: auto;
    background-color: var(--brand-void);
    color: var(--brand-static);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    line-height: 1.8;
}

.panel-code b { font-weight: 400; color: var(--brand-violet); }

/* The badge on the Violet panel's top-right corner, mostly above it so it
   clears the headline. */
#barycenter .flush-panel { position: relative; }
#barycenter .flush-panel .decor-corner {
    top: -125px;
    bottom: auto;
    right: 1.5rem;
    width: 140px;
    height: 140px;
}
#barycenter .flush-panel .decor-corner .decor-asset { width: 130px; }

/* Label / text rows, ruled — the specs without boxes. */
.spec-rows {
    margin: 1.75rem 0 1.5rem;
    border-top: 1px solid var(--color-border);
}

.spec-rows > div {
    display: grid;
    grid-template-columns: 6rem minmax(0, 1fr);
    gap: 1rem;
    padding: 0.7rem 0;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.95rem;
    line-height: 1.5;
}

.spec-rows dt {
    padding-top: 0.15em;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    /* Not Violet: on Static it's under 3:1. */
    color: var(--color-fg-muted);
}

/* ---- Pricing: Pulse is the only accent. Big prices, the CTA cut into
   each card's bottom-right corner, the featured tier outlined in Pulse. */
#pricing .pricing-price {
    font-size: clamp(2.5rem, 3.4vw, 3.5rem);
    line-height: 0.9;
}

.manifest {
    flex-grow: 1;
    list-style: none;
    margin: 0 0 2.5rem;
}

.manifest li {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.65rem 0;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.85rem;
}

.manifest span {
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-fg-muted);
}

.manifest b {
    font-weight: 500;
    text-align: right;
}

/* ---- About: the mission in three cells on the grid. */
.mx-cols { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.mx-cols > div {
    padding: var(--pad);
    background-color: var(--color-bg);
}

.mx-cols h3 {
    margin-bottom: 0.9rem;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 400;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--brand-flare);
}

@media (max-width: 1024px) {
    .mx-cols { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 768px) {
    /* One column, in source order: copy, visual, panel. */
    .mx-split,
    .mx-duo { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; margin-top: 2.5rem; }
    .mx-sec .mx-copy,
    .mx-sec .mx-visual,
    .mx-sec .mx-panel,
    .mx-sec .is-mirror .mx-copy,
    .mx-sec .is-mirror .mx-visual,
    .mx-sec .is-mirror .mx-panel,
    .mx-sec .mx-duo.is-mirror .mx-panel { grid-column: 1; grid-row: auto; }
    .mx-visual { min-height: 45svh; }
}

/* ---- Pricing: the three tiers as detached cards (from Inversion), the
   lines showing in the gaps between, each CTA a split button across the
   card's foot. */
#pricing .pricing-grid { gap: calc(2 * var(--card-gap)); }

#pricing .pricing-card {
    border: 1px solid var(--block-line);
    padding: var(--pad) var(--pad) 0;
    background-color: var(--color-bg);
    color: var(--color-fg);
}

#pricing .pricing-card:hover { transform: none; }

#pricing .pricing-card .btn-split {
    align-self: stretch;
    width: auto;
    margin: 0 calc(-1 * var(--pad));
    border-width: 1px 0 0;
}

#pricing .pricing-featured {
    outline: 2px solid var(--brand-void);
    outline-offset: -2px;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */

/* Narrow desktop / tablet: drop the second column (KEY PREFIX / SIZE) */
@media (max-width: 1200px) {
    .token-row {
        grid-template-columns: minmax(0, 2fr) minmax(0, 1.5fr) 10rem 8.5rem;
    }
    .token-row .token-cell:nth-child(2) {
        display: none;
    }
}

@media (max-width: 1024px) {
    .nav-links { gap: 1.75rem; padding: 0 1.5rem; }
}

/* Last step before the phone menu: tighter links so the bar never runs
   past the window and pushes the action block off the rail below it. */
@media (max-width: 900px) {
    .nav-links { gap: 1.25rem; padding: 0 1rem; }
}

@media (max-width: 768px) {
    /* Links collapse into a dropdown panel under the bar, every option kept. */
    .nav-toggle { display: block; }
    .nav-menu {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        padding: 0 var(--gutter) var(--gutter);
        background-color: var(--color-bg);
        border-bottom: 1px solid var(--color-border);
    }
    .top-nav.menu-open .nav-menu { display: flex; }
    .nav-menu .nav-links {
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: 0;
    }
    .nav-menu .nav-links a {
        padding: 1.1rem 0;
        border-bottom: 1px solid var(--color-border);
    }
    .nav-menu .nav-actions { margin: 1rem 0 0; }
    .nav-menu .nav-actions a {
        flex: 1;
        padding: 1rem;
    }

    /* Display titles scale with the screen (capped at their old size) so a
       long word like STORYTELLING can't spill past a phone's edge. */
    .hero-title {
        font-size: min(3.5rem, 15cqw);
        max-width: none;
    }
    .feature-title {
        font-size: min(3.5rem, 11cqw);
    }

    /* Stacked: the name runs across the top, then the render, then the
       panel. The rail turns into a width container for the sizing. */
    #hero {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto 50svh auto;
        height: auto;
    }
    .hero-rail {
        order: -1;
        container-type: inline-size;
        justify-content: flex-start;
        padding: 1.5rem var(--gutter) 1rem;
    }
    .rail-meta { display: none; }
    #hero .hero-title {
        writing-mode: horizontal-tb;
        font-size: calc(100cqw * 0.23);
    }
    #hero .hero-pitch {
        position: relative;
        left: auto;
        bottom: auto;
        max-width: none;
        padding: 2rem var(--gutter) 2.5rem;
    }
    /* Too narrow for the readout strings to clear each other — keep the blocks. */
    .data-noise span { display: none; }


    .feature-grid {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
    }

    .team-grid,
    .pricing-grid {
        grid-template-columns: 1fr;
    }

    /* Hide empty spacer cells that stack as blank rows on mobile */
    .team-cell:empty {
        display: none;
    }

    .team-cell {
        border-right: none;
    }

    section {
        padding: 4rem var(--gutter);
    }

    /* Token table: name + action only */
    .token-row {
        /* auto is safe here: alias hugs the left, action the right, so a
           per-row action width never shows as misalignment. */
        grid-template-columns: minmax(0, 1fr) auto;
    }
    .token-row .token-cell:nth-child(2),
    .token-row .token-cell:nth-child(3),
    .token-row .token-cell:nth-child(4) {
        display: none;
    }
    .action-dash { display: none; }
    .action-revoked {
        display: inline;
        white-space: nowrap;
        font-size: 0.8rem;
        letter-spacing: 0.1em;
        color: var(--color-fg-muted);
    }
    .token-cell {
        padding: 1rem 0.75rem;
    }
    .revoke-label { display: none; }
    .revoke-icon { display: inline; }

    /* Copyright and links overrun each other on one row — let the links
       drop to their own line instead of squashing both. */
    .site-footer {
        flex-wrap: wrap;
        gap: 1rem;
        padding: 2rem;
    }

    /* Stacked, the box would go wide and short and squash the pile — hold
       the desktop proportions so the % positions keep their shape.
       min-height off: through the ratio, .about-pattern's 340px floor would
       turn into a 388px minimum width and push past a phone screen. */
    .sticker-bomb {
        aspect-ratio: 8 / 7;
        min-height: 0;
    }

    /* Billing cards: stack vertically */
    .billing-cards {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   HOME COLUMN GRID (from Albedo) — three columns between the edge
   lines, with the two interior lines drawn too. Every home section is
   laid out on the same three columns: loose text sits inside one
   column, padded off its lines, and blocks span whole columns so their
   seams land on the lines. Below 1025px only the edge lines remain.
   ============================================================ */
/* Registered so it computes to a length on #hero (against main's width)
   and inherits as that, instead of re-resolving cqw inside the render. */
@property --frame-w {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}

@media (min-width: 1025px) {
    /* Nav on the same frame: inset to the edge lines, its action block
       half a column wide, so it stacks on the hero rail below. */
    .top-nav {
        padding-inline: var(--frame-x);
        container-type: inline-size;
    }
    .nav-actions a { width: max(var(--rail-w), 100cqw / 6); }

    /* Hero framed like a block: inside the edge lines, the rail half a
       column wide on the right (never under --rail-w, its width below this
       breakpoint, so it doesn't shrink then jump), the render the rest.
       The rail's title sizes off the rail itself (a container).
       --frame-w is the width between the edge lines, resolved here against
       main (see @property) so the render can place the grid lines without
       assuming the rail is exactly 1/6. */
    .has-grid > #hero {
        --frame-w: calc(100cqw - 2 * var(--frame-x));
        margin-inline: var(--frame-x);
        grid-template-columns: minmax(0, 1fr) max(var(--rail-w), var(--frame-w) / 6);
    }
    .has-grid > #hero .hero-rail  { container-type: inline-size; }
    .has-grid > #hero .hero-title {
        font-size: min(calc((var(--hero-h) - 9rem) / 4.4), calc((100cqw - 3rem) / 1.75));
    }
    /* The pitch stays inside the first column, padded off its lines. */
    .has-grid > #hero .hero-pitch {
        left: var(--pad);
        max-width: calc(100% / 3 - 2 * var(--pad));
    }
    /* The render (1920x800) covers the box by height, so it is 2.4 x
       --hero-h wide. This puts the image's gap between the EARTH and MARS
       labels (55.6% across it, 1.334 x --hero-h in) on the first grid
       line, a third of the frame in, at any size. */
    .has-grid > #hero .hero-visual { container-type: inline-size; }
    .has-grid > #hero .hero-visual > img {
        object-position: calc(var(--frame-w) / 3 - 1.334 * var(--hero-h)) 45%;
    }

    /* Both interior grid lines carry on through the render (a third and
       two thirds of the frame), faint, like a reticle over the footage. */
    .has-grid > #hero .data-noise::before {
        content: '';
        position: absolute;
        inset: 0;
        --l: color-mix(in srgb, var(--brand-static) 18%, transparent);
        background:
            linear-gradient(var(--l), var(--l)) calc(var(--frame-w) / 3) 0 / 1px 100% no-repeat,
            linear-gradient(var(--l), var(--l)) calc(var(--frame-w) * 2 / 3) 0 / 1px 100% no-repeat;
    }

    main.has-grid {
        background-image:
            linear-gradient(var(--block-line), var(--block-line)),
            linear-gradient(var(--block-line), var(--block-line)),
            linear-gradient(var(--block-line), var(--block-line)),
            linear-gradient(var(--block-line), var(--block-line));
        background-position:
            left var(--frame-x) top 0,
            calc(var(--frame-x) + (100% - 2 * var(--frame-x)) / 3) 0,
            calc(var(--frame-x) + 2 * (100% - 2 * var(--frame-x)) / 3) 0,
            right var(--frame-x) top 0;
    }

    .has-grid > section:not(#hero) {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        align-content: start;
        align-items: start;
        padding-inline: var(--frame-x);
    }

    .has-grid > section:not(#hero) > * {
        grid-column: 1;
        padding-inline: var(--pad);
    }

    /* Blocks span the three columns; their cells carry the padding. */
    .has-grid > section:not(#hero) > :is(.mx-duo, .mx-split, .mx-cols) {
        grid-column: 1 / -1;
        padding-inline: 0;
        margin-inline: 0;
    }

    /* Duo: copy takes one column, the panel the other two. */
    .has-grid .mx-duo            { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
    .has-grid .mx-duo.is-mirror  { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }

    /* Split: one row, a column each for copy, panel and visual (mirrored:
       visual, copy, panel), so the sticker box stays one column wide. */
    .has-grid .mx-split { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: auto; }
    .has-grid .mx-split > .mx-copy             { grid-column: 1; grid-row: 1; }
    .has-grid .mx-split > .mx-panel            { grid-column: 2; grid-row: 1; }
    .has-grid .mx-split > .mx-visual           { grid-column: 3; grid-row: 1; }
    .has-grid .mx-split.is-mirror > .mx-visual { grid-column: 1; }
    .has-grid .mx-split.is-mirror > .mx-copy   { grid-column: 2; }
    .has-grid .mx-split.is-mirror > .mx-panel  { grid-column: 3; }

    /* Heading in the first column, its paragraph beside it in the second. */
    .has-grid > #statement > .eyebrow-code    { grid-row: 1; }
    .has-grid > #statement > .statement-title { grid-row: 2; margin-bottom: 0; }
    .has-grid > #statement > .text-block      { grid-column: 2; grid-row: 2; margin: 0; max-width: none; }
    .has-grid > #pricing > .body-copy         { grid-column: 2; grid-row: 1; align-self: end; margin: 0; }
    /* Detached cards: the grid's padding plus half its gap puts each
       column line in the middle of the gap between two cards. */
    .has-grid > #pricing > .pricing-grid {
        grid-column: 1 / -1;
        margin: 4rem 0 0;
        padding-inline: var(--card-gap);
    }
    /* Absolute, so it takes no cell padding: it lines up with the text. */
    .has-grid > section:not(#hero) > .about-shapes { padding-inline: 0; }

    .has-grid > #pricing > .pricing-faq {
        grid-column: 1 / -1;
        padding-inline: 0;
        margin-inline: var(--card-gap);
    }

    /* ---- Product pages (Star-Taker, Barycenter), same columns. */

    /* Intro paragraph beside the title, like the home statement. */
    .has-grid > section:not(#hero) > .feature-title + .feature-desc {
        grid-column: 2;
        grid-row: 1 / span 2;
        align-self: end;
        margin: 0;
    }

    .has-grid > section:not(#hero) > :is(.why-grid, .feature-grid, .bd-section, .section-strip) {
        grid-column: 1 / -1;
        margin-inline: 0;
    }

    .has-grid > section:not(#hero) > :is(.why-grid, .feature-grid, .bd-section, .section-strip) { padding-inline: 0; }

    /* Rows that hold their own content: three columns again, each cell
       padded off its lines. Copy in the first, a list in the second, a
       readout (a solid block) in the second, or across the second and
       third when a column is too narrow for its lines. */
    .has-grid :is(.feature-grid, .bd-section) {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 0;
        align-items: start;
    }

    .has-grid :is(.feature-grid, .bd-section) > * {
        grid-column: 1;
        padding-inline: var(--pad);
    }

    .has-grid .feature-grid > .pricing-features { grid-column: 2; }

    .has-grid .feature-grid > :is(.feature-visual, .terminal-readout),
    .has-grid .bd-section > .block-diagram {
        background-color: var(--color-bg);
        border-color: var(--block-line);
        padding: var(--pad);
    }

    /* One column if it holds the longest line (47 characters, Star-Taker's
       install sample; measured in the readout's own font, letter-spacing and
       padding), else both. The x1000 snaps the width to exactly one (50%)
       or two (100%) columns, nothing between. */
    .has-grid .feature-grid > :is(.feature-visual, .terminal-readout) {
        grid-column: 2 / -1;
        width: clamp(50%, (47 * (1ch + 0.05em) + 2 * var(--pad) - 50%) * 1000, 100%);
    }

    .has-grid .bd-section > :is(.why-grid, .block-diagram) { grid-column: 1 / -1; }
    .has-grid .bd-section > .why-grid { padding-inline: 0; }

    /* ---- Packet spec (/barycenter/format). */

    /* Two format cards: the first two columns, seam on the first line. */
    .has-grid > section:not(#hero) > .spec-formats {
        grid-column: 1 / 3;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Each spec section: tag, title and text in the first column, then
       the byte map and its table as one block across all three (the table
       closes the map's box), then the callout. */
    .has-grid .bd-section > .block-diagram:has(+ .spec-table) { margin-bottom: 0; }
    .has-grid .bd-section > .spec-table {
        grid-column: 1 / -1;
        width: 100%;
        margin: 0 0 2rem;
        padding: 0;
        background-color: var(--color-bg);
        border: 1px solid var(--block-line);
        border-top: 0;
    }
    /* Fixed columns, so every table lines up: name and unit share the
       first grid column, the meaning starts on the second line. */
    .has-grid .bd-section > .spec-table { table-layout: fixed; }
    .has-grid .bd-section > .spec-table th:nth-child(-n+2) { width: calc(100% / 6); }
    .has-grid .bd-section > .spec-table :is(th, td):nth-child(3) { padding-left: var(--pad); }
    /* Text beside the title, like the page intro. */
    .has-grid .bd-section:has(> .block-diagram) > .spec-desc {
        grid-column: 2;
        grid-row: 1 / span 2;
        align-self: end;
        margin: 0 0 2rem;
    }
    .has-grid .bd-section > .spec-table :is(th, td):first-child { padding-left: var(--pad); }
    .has-grid .bd-section > .spec-table :is(th, td):last-child  { padding-right: var(--pad); }
    .has-grid .bd-section > .spec-table tr:last-child td        { border-bottom: 0; }
    .has-grid .bd-section > .spec-callout {
        margin: 0 var(--pad) 2rem;
        padding: 1.25rem 1.5rem;
    }

    /* The readers sit beside the text; a 1fr fourth row soaks up their
       height so the text rows stay their own size. */
    .has-grid .bd-section { grid-template-rows: auto auto auto 1fr; }

    /* Contact: copy in the first column, the form across the other two as a
       solid block, like the readouts, so the middle line doesn't cut it. */
    /* No strip on this page, so the section fills main and its bottom edge
       closes the grid above the footer. Margin instead of padding keeps the
       columns where they were but stops the rule at the frame lines. */
    .has-grid > section#contact {
        flex-grow: 1;
        margin-inline: var(--frame-x);
        padding-inline: 0;
        border-bottom: 1px solid var(--block-line);
    }
    .has-grid .feature-grid > .contact-form {
        grid-column: 2 / -1;
        background-color: var(--color-bg);
        border: 1px solid var(--block-line);
        padding: var(--pad);
    }

    /* Time and Rotation side by side. */
    .has-grid .feature-grid > .feature-content + .feature-content { grid-column: 2; }

    /* ---- Storytelling. Title in the first column, intro and How We Work
       under it in the first and second, the sticker bomb in the third
       beside both; then the call to action and the four steps under them. */
    .has-grid > #storytelling > .story-bomb {
        grid-column: 3;
        grid-row: 1 / span 4;
    }
    .has-grid > #storytelling > .why-head {
        grid-column: 1 / 3;
        grid-row: 4;
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        margin-top: 2.5rem;
        padding-inline: 0;
    }
    .has-grid > #storytelling > .why-head > * { padding-inline: var(--pad); }

    /* The four steps 2x2 in the second and third columns, one column per
       card, so their seams land on the grid lines. Row set on both, since
       the panel comes after the steps in the markup. */
    .has-grid > section#storytelling > .why-grid.why-grid-4 {
        grid-column: 2 / -1;
        grid-row: 5;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    /* The Pulse panel fills the first column beside the steps. */
    .has-grid > section#storytelling > .story-cta {
        grid-column: 1;
        grid-row: 5;
        align-self: stretch;
        margin: 4rem 0 0;
        padding-inline: 0;
    }

    /* Two readers beside the text, across the second and third columns:
       side by side once each holds the longest line (50 characters),
       stacked before.
       The readout font is set here so ch measures its characters. Borders
       drawn by the 1px gap, like the card rows, so they work either way. */
    .has-grid .bd-section > .feature-grid {
        grid-column: 2 / -1;
        grid-row: 1 / span 4;
        grid-template-columns: repeat(auto-fit, minmax(min(100%, 50 * (1ch + 0.05em) + 2 * var(--pad)), 1fr));
        align-items: stretch;
        gap: 1px;
        padding-inline: 0;
        font-family: var(--font-mono);
        font-size: 0.8rem;
        background-color: var(--block-line);
        border: 1px solid var(--block-line);
    }
    /* Code keeps its lines; a narrow column scrolls instead of wrapping. */
    .has-grid .bd-section > .feature-grid > .terminal-readout {
        grid-column: auto;
        width: auto;
        border: 0;
        min-height: 0;
        white-space: pre;
        overflow-wrap: normal;
        overflow-x: auto;
    }

    /* Strip: its readout wraps inside the first column, the mark sits at
       the end of the third. */
    .has-grid .section-strip {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
    .has-grid .section-strip > span { grid-column: 1; padding-inline: var(--pad); }
    .has-grid .section-strip > img  { grid-column: 3; justify-self: end; margin-right: var(--pad); }
}

/* ============================================================
   COMING SOON — pre-launch deploy. One wide line laid over a product
   section's duo, which stays in place but blurred and inert. Both take
   grid row 2, so the line sits over the duo at any width; below 1025px
   the section becomes a one-column grid for it. The status tag keeps
   the section's square (Flare / Violet).
   ============================================================ */
.is-coming-soon {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}

.is-coming-soon > :is(.mx-duo, .coming-soon) { grid-row: 2; grid-column: 1 / -1; }
.is-coming-soon > .mx-duo { filter: blur(10px); opacity: 0.6; }

.coming-soon {
    /* The width the line fills: the section's content box below 1025px,
       two grid columns above. */
    --cs-w: calc(100cqw - 2 * var(--gutter));
    z-index: 2;
    align-self: center;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* 5.0 is "COMING SOON"'s width in ems in Archivo Display;
   tune it if the copy or font changes. */
.coming-soon-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: calc(var(--cs-w) / 5.0);
    font-weight: 700;
    line-height: 0.85;
    letter-spacing: -0.01em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--color-fg);
}

.coming-soon .feature-tag { margin: 0; color: var(--color-fg); }

/* On the grid: two columns wide, padded off their lines like every other
   cell. Star-Taker runs left to right from its copy column; .is-mirror
   (Barycenter) runs right to left from its copy column. The selector
   repeats the grid's section:not(#hero) prefix, whose ID would otherwise
   win. */
@media (min-width: 1025px) {
    .has-grid > section:not(#hero) > .coming-soon {
        --cs-w: calc((100cqw - 2 * var(--frame-x)) * 2 / 3 - 2 * var(--pad));
        grid-column: 1 / 3;
    }
    .has-grid > section:not(#hero) > .coming-soon.is-mirror {
        grid-column: 2 / 4;
        align-items: flex-end;
    }
}
