/* ============================================================
   system.css - marketing design system

   Sits ON TOP of global.css, which stays the single source of
   truth for the palette. The product surfaces (dashboard, admin,
   configure) read global.css directly and are deliberately not
   touched by anything in this file: a subscriber's daily tool
   should not shift under them because the marketing site did.

   What this adds that global.css does not have:
     - a display typeface, for headlines only
     - a fluid type scale
     - motion tokens, so easing and duration are decided once
     - depth tokens for the 3D surfaces

   The palette, radii and spacing come from global.css unchanged.
   ============================================================ */

:root {
    /* ── Type ───────────────────────────────────────────────
       Geist for display, Inter for everything else. The product
       is built in Inter and shares global.css with this page, so
       swapping the body face would split the brand in two. A
       display face on headlines is the part that carries weight.
       Geist Mono for figures: a trading page prints a lot of
       numbers and they have to align in a column. */
    --font-display: 'Instrument Serif', 'Iowan Old Style', 'Times New Roman', serif;
    --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
    --font-num: 'Geist Mono', 'SF Mono', 'Fira Code', monospace;

    /* Fluid scale. clamp() means no breakpoint jumps between the
       phone and the 1400px cap, and the middle term is in vw so it
       tracks the viewport rather than stepping at arbitrary widths. */
    /* The small ends of steps 1-6 were sized for a tablet and left a
       phone reading a 40px headline three words to the line. Only the
       minimums moved; the desktop caps are unchanged, so nothing above
       ~900px shifts. --step-0 holds at 1rem because that is the floor
       for body copy and going under it is an accessibility problem,
       not a density one. */
    --step--1: clamp(0.80rem, 0.77rem + 0.15vw, 0.92rem);
    --step-0:  clamp(1.00rem, 0.95rem + 0.25vw, 1.13rem);
    --step-1:  clamp(1.09rem, 1.01rem + 0.40vw, 1.44rem);
    --step-2:  clamp(1.26rem, 1.13rem + 0.65vw, 1.84rem);
    --step-3:  clamp(1.44rem, 1.25rem + 0.95vw, 2.35rem);
    --step-4:  clamp(1.66rem, 1.38rem + 1.40vw, 3.00rem);
    --step-5:  clamp(1.94rem, 1.54rem + 2.00vw, 3.83rem);
    --step-6:  clamp(2.24rem, 1.72rem + 2.60vw, 4.89rem);

    /* --text-subtle from global.css is #6f7a95, which measures 4.08:1
       on --bg-base, 3.83:1 on --bg-surface and 3.55:1 on
       --bg-elevated: it fails AA for body-size text on all three.
       This is the smallest lift that clears 4.5:1 on the darkest of
       them (4.63:1 on --bg-elevated, 5.30:1 on --bg-base).

       Defined here rather than corrected in global.css on purpose:
       global.css is shared with the dashboard and the admin console,
       and a subscriber's daily tool should not change colour because
       the marketing page did. */
    --text-quiet: #8592b0;

    /* ── A second accent ────────────────────────────────────
       The page was blue on near-black top to bottom and read cold.
       Amber is the counterweight, and it is governed by a rule so it
       stays a system rather than a sprinkle:

         blue  = anything the reader can act on, plus primary emphasis
         amber = enumeration and labels - the things that NAME a part
                 rather than invite a click

       So section eyebrows, the 01/02 indices and the small captions
       under a figure are amber; every link, button and headline
       emphasis stays blue. Nothing is ever both.

       #8aa4e8 on --bg-base is about 11:1, so it clears AA at the small
       sizes it is used at with room to spare. */
    --accent-warm: #b9a67c;   /* muted gold: names a part, never invites a click */

    --tracking-display: -0.012em;  /* a serif needs far less negative tracking than Geist did */   /* display type needs negative tracking */
    --tracking-eyebrow: 0.14em;
    --leading-display: 1.02;
    --leading-body: 1.65;

    /* ── Motion ─────────────────────────────────────────────
       One easing family. The expo-out curve is what makes a
       transition read as "settling" rather than "stopping". */
    --ease-out: cubic-bezier(0.16, 1, 0.30, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --dur-fast: 160ms;
    --dur-base: 320ms;
    --dur-slow: 640ms;

    /* ── Depth ──────────────────────────────────────────────
       Used by the WebGL hero and the CSS-3D cards so both read as
       the same space rather than two unrelated effects. */
    --depth-perspective: 1200px;
    --surface-line: rgba(138, 164, 232, 0.55);
    --surface-line-dim: rgba(163, 173, 196, 0.16);
    --scrim: linear-gradient(180deg,
                rgba(10, 15, 30, 0) 0%,
                rgba(10, 15, 30, 0.72) 62%,
                rgba(10, 15, 30, 1) 100%);
}

/* ── Reduced motion ─────────────────────────────────────────
   MOTION_INTENSITY is 7 here, so this is mandatory rather than a
   courtesy. Everything below collapses to its end state: the page
   still reads, it just stops moving. The WebGL hero checks this
   flag in JS as well and renders one static frame instead of a
   loop, which also saves the GPU on machines that asked for calm. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ════════════════════════════════════════════════════════════
   TYPOGRAPHY
   ════════════════════════════════════════════════════════════ */

.display {
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: var(--tracking-display);
    line-height: var(--leading-display);
    color: var(--text-primary);
    margin: 0;
    /* Reserve for descenders. A display line at leading 1.04 will
       clip a 'g' or a 'y' without this. */
    padding-bottom: 0.06em;
}

.display-xl { font-size: var(--step-6); }
.display-lg { font-size: var(--step-5); }
.display-md { font-size: var(--step-4); }
.display-sm { font-size: var(--step-3); }

/* Emphasis inside a headline stays in the same family. A serif word
   dropped into a sans headline is the tell this avoids. */
.display em {
    font-style: italic;
    color: var(--accent);
}

.lede {
    font-family: var(--font-body);
    font-size: var(--step-1);
    line-height: var(--leading-body);
    color: var(--text-muted);
    max-width: 58ch;
    margin: 0;
}

.eyebrow {
    font-family: var(--font-body);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
    color: var(--accent-warm);
    margin: 0;
}

/* Figures. Tabular so a column of numbers lines up on the decimal. */
.num {
    font-family: var(--font-num);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

/* ════════════════════════════════════════════════════════════
   LAYOUT
   ════════════════════════════════════════════════════════════ */

.shell {
    width: 100%;
    max-width: var(--page-max, 1400px);
    margin-inline: auto;
    padding-inline: clamp(1.25rem, 4vw, 3.5rem);
}

/* Sections carry their own rhythm so a page is assembled by
   stacking them rather than by hand-tuning margins between them. */
.band {
    padding-block: clamp(4rem, 9vw, 8.5rem);
    position: relative;
}
.band-tight { padding-block: clamp(2.5rem, 5vw, 4.5rem); }

/* ════════════════════════════════════════════════════════════
   REVEAL
   Entry motion for anything below the fold. Driven by
   IntersectionObserver rather than a scroll listener - a scroll
   handler runs on every frame and is the usual reason a page
   janks on a phone.
   ════════════════════════════════════════════════════════════ */

[data-reveal] {
    opacity: 0;
    /* Shorter throw, longer settle. 18px over 640ms is a shove; 12px
       over 820ms on the expo curve is something arriving. The distance
       is what reads as "pop", not the duration. */
    /* A whole section is a big object, so it moves a little further and
       takes a little longer than a single element would - a 12px shift
       that a paragraph reads as arrival, a full section reads as a
       twitch. */
    transform: translateY(22px);
    transition: opacity 900ms var(--ease-out),
                transform 900ms var(--ease-out);
    transition-delay: var(--reveal-delay, 0ms);
    will-change: opacity, transform;
}
[data-reveal].is-in {
    opacity: 1;
    transform: none;
    will-change: auto;
}
@media (prefers-reduced-motion: reduce) {
    [data-reveal] { opacity: 1; transform: none; }
}


/* ════════════════════════════════════════════════════════════
   LEDGER  (2026-09)
   The serif carries the headlines everywhere on the marketing
   site, not only where a page remembered to add .display. Brass
   is the single accent and it means "act here": links, buttons,
   the italic word in a headline. Labels stay quiet.
   ════════════════════════════════════════════════════════════ */
h1, h2 {
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: var(--tracking-display);
    line-height: 1.08;
}
h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
/* h3 and below stay in the sans: they are card titles and list heads
   more often than headlines, and a serif under 1.2rem reads as a
   footnote. Pages that want a serif h3 opt in with .display. */
h3 { font-family: var(--font-body); font-size: var(--step-1); font-weight: 600; letter-spacing: -0.01em; }
h4, h5, h6 { font-weight: 600; letter-spacing: -0.01em; }
h1 em, h2 em { font-style: italic; color: var(--accent); }

.lede { color: var(--text-muted); }

/* Buttons. One solid, one outlined; both square-shouldered. The
   pill was the SaaS tell. */
body .btn-solid, body .btn-ghost,
body .btn-primary, body .btn-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    padding: 0.85rem 1.55rem;
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: 0.92rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background var(--dur-base) var(--ease-out),
                color var(--dur-base) var(--ease-out),
                border-color var(--dur-base) var(--ease-out),
                transform var(--dur-base) var(--ease-out),
                box-shadow var(--dur-base) var(--ease-out);
}
/* A pale lavender slab with dark text and a glow around it read as a
   default UI button dropped on the page. This is the same family several
   stops darker, with white type and no glow, so it sits in the palette
   instead of floating over it. */
body .btn-solid, body .btn-primary {
    background: linear-gradient(180deg, #4a63a8 0%, #3d5290 100%);
    color: #ffffff;
    border-color: rgba(169, 189, 240, 0.28);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
body .btn-solid:hover, body .btn-primary:hover {
    background: linear-gradient(180deg, #5b78c8 0%, #4a63a8 100%);
    color: #ffffff;
    border-color: rgba(201, 169, 98, 0.55);
    transform: translateY(-1px);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 10px 24px -16px rgba(0, 0, 0, 0.9);
}
body .btn-ghost, body .btn-secondary {
    background: transparent;
    color: var(--text-primary);
    border-color: rgba(238, 241, 248, 0.18);
}
body .btn-ghost:hover, body .btn-secondary:hover {
    border-color: var(--accent);
    color: var(--accent-lt);
    transform: translateY(-1px);
    background: rgba(138, 164, 232, 0.06);
}
body .btn-solid:focus-visible, body .btn-ghost:focus-visible,
body .btn-primary:focus-visible, body .btn-secondary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* A hairline rule with a short brass tick at its start. Used above
   section heads so every section opens the same way. */
.rule {
    position: relative;
    height: 1px;
    background: var(--border);
    margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}
.rule::before {
    content: '';
    position: absolute;
    left: 0; top: -0.5px;
    width: 2.6rem; height: 2px;
    background: var(--gold);
}

/* Quiet caps label, used for eyebrows, table heads, figure keys. */
.caps {
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Selection in brass, so even the highlight belongs to the palette. */
::selection { background: rgba(138, 164, 232, 0.32); color: var(--text-primary); }


/* A button that reads as a link. It lives here rather than in ledger.css
   because the index does not load ledger, and its finder link was
   rendering as a raw browser button. */
.linkish {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--accent);
    cursor: pointer;
    border-bottom: 1px solid rgba(138, 164, 232, 0.35);
    transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.linkish:hover { color: var(--accent-lt); border-bottom-color: var(--accent-lt); }
.linkish:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
