/* ============================================================================
   Auracle web design system — "The Ledger"
   Page-shell components. Authority: /DESIGN.md (2026-08-13).

   Loads AFTER css/tokens.css and consumes its custom properties. This file
   holds the components of the landing page shell only (the pill, the hero).
   Later slices append their section modules below.

   It is a separate sheet from css/index.css on purpose: index.css is the
   legacy dark chrome still shared by eight un-reskinned pages, and none of
   them should have to carry the new page's components.

   No glass, no glow, no gradients. Hairlines and material contrast only.
   Any edit here MUST bump the ?v= token on the stylesheet links.
   ========================================================================= */

/* ----------------------------------------------------------------------------
   1. Page frame.
-------------------------------------------------------------------------- */

/* Anchor targets clear the floating pill when jumped to. */
[id] {
    scroll-margin-top: 7rem;
}

/* Horizontal rhythm. One measure for every band on the page. */
.band {
    width: 100%;
    padding-inline: clamp(1.25rem, 0.6rem + 2.8vw, 4rem);
}

.band-in {
    width: 100%;
    max-width: 78rem;
    margin-inline: auto;
}

/* ----------------------------------------------------------------------------
   2. The Pill.

   Floating black capsule, top centre, perforated hairline. It carries the
   nav links, the one orange verb, and a factual ticker along its lower
   edge. Past ~120px of scroll js/ledger.js adds `.is-collapsed` and the
   capsule shrinks to "Menu +" of the same materials. Nothing here depends
   on script: with JS off the class is never added and the pill stays
   expanded, exactly as authored.
-------------------------------------------------------------------------- */

/* The dock is a rail, not a surface: it must not eat clicks across the
   full width of the viewport. */
.pill-dock {
    position: fixed;
    top: 0.875rem;
    left: 0;
    right: 0;
    z-index: 80;
    display: flex;
    justify-content: center;
    padding-inline: 0.75rem;
    pointer-events: none;
}

.pill {
    pointer-events: auto;
    max-width: 100%;
    background-color: var(--black);
    color: var(--on-black);
    border: 1px dotted rgba(255, 255, 255, 0.35);
    border-radius: 999px;
    overflow: hidden;
}

.pill-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 1.5rem;
    padding: 0.4375rem 0.4375rem 0.4375rem 0.9375rem;
}

.pill-mark {
    display: flex;
    align-items: center;
    flex: none;
}

.pill-mark img {
    width: 20px;
    height: 20px;
}

.pill-menu {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 1.5rem;
}

.pill-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 1.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.pill-link {
    display: inline-block;
    color: var(--on-black-muted);
    padding-block: 0.25rem;
    transition: color var(--dur-fast) var(--ease-out);
}

.pill-link:hover,
.pill-link:focus-visible {
    color: #fff;
}

/* The one verb. Orange marks the action, never decoration. */
.pill-cta {
    display: inline-flex;
    align-items: center;
    flex: none;
    background-color: var(--accent);
    color: var(--ink);
    border-radius: 999px;
    padding: 0.5625rem 0.9375rem;
}

/* Collapsed state. Hidden with display:none so the links leave the tab
   order entirely rather than staying reachable behind the capsule. */
.pill-toggle {
    display: none;
    align-items: center;
    gap: 0.375rem;
    background: none;
    border: 0;
    padding: 0.5rem 0.375rem;
    color: var(--on-black);
    cursor: pointer;
}

.pill.is-collapsed .pill-mark,
.pill.is-collapsed .pill-menu,
.pill.is-collapsed .pill-ticker {
    display: none;
}

.pill.is-collapsed .pill-row {
    padding: 0.4375rem 0.75rem;
}

.pill.is-collapsed .pill-toggle {
    display: inline-flex;
}

/* Collapsed it is a single short row, so it stays a stadium even at the
   widths where the expanded pill has to soften into a rounded panel. */
.pill.is-collapsed {
    border-radius: 999px;
}

/* Ticker. `width: 0; min-width: 100%` keeps the (very wide) marquee from
   deciding how wide the capsule is: the row decides, the ticker fills. */
.pill-ticker {
    width: 0;
    min-width: 100%;
    overflow: hidden;
    border-top: 1px dotted rgba(255, 255, 255, 0.18);
    padding: 0.3125rem 1.25rem 0.375rem;
}

.pill-ticker-track {
    display: flex;
    width: max-content;
    animation: pill-ticker 30s linear infinite;
}

/* Two identical runs, so translating the track by exactly half its width
   lands on a seam that is invisible. The separator is padding rather than
   a trailing space, which a flex item would strip. */
.pill-ticker-run {
    font-family: var(--font-mono);
    font-size: 10px;
    line-height: 1.2;
    font-weight: var(--weight-body);
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    color: var(--on-black-muted);
    white-space: nowrap;
    padding-right: 0.75em;
}

.pill-ticker-still {
    padding-right: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

@keyframes pill-ticker {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(-50%);
    }
}

/* The marquee is one of the cases that cannot simply be frozen, so the
   static rendering takes over. Belt and braces: kill the animation too. */
@media (prefers-reduced-motion: reduce) {
    .pill-ticker-track {
        animation: none;
    }
}

/* Sentinel for the collapse trigger. Created by js/ledger.js, so it does
   not exist at all without script. */
.pill-sentinel {
    position: absolute;
    top: 0;
    left: 0;
    width: 1px;
    height: 120px;
    opacity: 0;
    pointer-events: none;
}

/* Narrow viewports. The pill stays a real nav rather than turning into a
   script-only drawer, so it wraps instead of hiding: mark and links on one
   row, the verb below them. Tightened enough that a permanently floating
   element does not eat the top of a phone screen. */
@media (max-width: 40rem) {
    .pill-dock {
        padding-inline: 0.5rem;
    }

    .pill {
        border-radius: 1.375rem;
    }

    .pill-row {
        gap: 0.375rem 0.75rem;
        padding: 0.375rem 0.375rem 0.375rem 0.625rem;
    }

    /* Dissolve the menu's own box so the links and the verb wrap against
       the row directly. Without this the menu is one wide flex item and
       pushes the mark onto a line of its own. The collapsed rule still
       wins over this, being the more specific selector. */
    .pill-menu {
        display: contents;
    }

    .pill-links {
        gap: 0.375rem 0.75rem;
    }

    .pill-mark img {
        width: 16px;
        height: 16px;
    }

    .pill-link {
        padding-block: 0.125rem;
    }

    .pill-cta {
        padding: 0.4375rem 0.8125rem;
    }

    .pill-ticker {
        padding-inline: 0.875rem;
    }
}

/* ----------------------------------------------------------------------------
   3. The hero.

   Cream ground, one screen tall, one claim. No parallax, no glow, no
   gradient: the type and the empty space do the work.
-------------------------------------------------------------------------- */

.hero {
    display: flex;
    align-items: center;
    min-height: 100vh;
    min-height: 100svh;
    padding-block: 9rem 5rem;
}

/* .mono-label sets line-height 1, which is right for a single-line chip
   and wrong for these two, which wrap on narrow screens. */
.hero-eyebrow,
.hero-foot {
    line-height: 1.7;
}

.hero-eyebrow {
    color: var(--ink);
    margin-bottom: 1.75rem;
}

.hero-claim {
    /* ~44px..96px. Deliberately taller than the --size-h1 token: this is
       the one headline on the site that gets the full range. */
    font-size: clamp(2.75rem, 1.9rem + 4.2vw, 6rem);
    max-width: 16ch;
    margin-bottom: 2rem;
}

/* One mask per line so the intro can lift each line out of it. The
   padding/margin pair keeps descenders from being shaved by the mask. */
.hero-line {
    display: block;
    overflow: hidden;
    padding-bottom: 0.08em;
    margin-bottom: -0.08em;
}

.hero-line-in {
    display: block;
}

.hero-measure {
    max-width: 34rem;
    font-size: var(--size-lead);
    color: var(--grey-warm);
    margin-bottom: 2.75rem;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1.25rem 2rem;
    margin-bottom: 2rem;
}

.hero-secondary {
    color: var(--ink);
    text-underline-offset: 0.4em;
}

.hero-secondary:hover,
.hero-secondary:focus-visible {
    text-decoration: underline;
}

.hero-foot {
    color: var(--grey-warm);
}

/* ----------------------------------------------------------------------------
   4. The click-and-hold control.

   Black capsule, mono label, and a progress bar on its lower inside edge
   that js/ledger.js drives while the pointer is held. The bar is orange
   because it reports the state of a verb, which is exactly what the accent
   is for. It is a bar rather than a flood so the label keeps its contrast
   all the way to completion.
-------------------------------------------------------------------------- */

.hold {
    position: relative;
    display: inline-flex;
    align-items: baseline;
    gap: 0.875rem;
    overflow: hidden;
    background-color: var(--black);
    color: var(--on-black);
    border-radius: 999px;
    padding: 0.9375rem 1.5rem 1.125rem;
    cursor: pointer;
    /* A press-and-hold must not turn into a text selection, a callout
       menu, or a double-tap zoom. */
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

.hold-label {
    font-size: var(--size-micro);
    color: #fff;
}

.hold-hint {
    font-size: 10px;
    color: var(--on-black-muted);
}

.hold-fill {
    position: absolute;
    left: 1.5rem;
    right: 1.5rem;
    bottom: 0.5rem;
    height: 2px;
    background-color: var(--accent);
    transform: scaleX(0);
    transform-origin: left center;
}

/* While held, the rAF loop owns the transform. On release the class goes
   and the bar eases back to zero on its own. */
.hold:not(.is-holding) .hold-fill {
    transition: transform var(--dur-base) var(--ease-out);
}

/* ----------------------------------------------------------------------------
   5. Screen-reader-only text.

   Lives here rather than in tokens.css because tokens.css is the token
   layer and owns no components. The clip-path/1px pattern rather than
   `display: none`, which would take the text out of the accessibility tree
   along with the pixels.
-------------------------------------------------------------------------- */

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
    border: 0;
    clip-path: inset(50%);
}

/* ----------------------------------------------------------------------------
   6. The Ledger.

   Numbered mono rows, a Geist Sans label, a right-aligned mono quantity,
   hairlines between. The grammar is shared: the problems table here and the
   features index that lands beside it use the same `.ledger` component, so
   the two read as one instrument with two contents.

   It is a real <table>. The rows carry an index, a subject and a figure, and
   they sum: that is a table, and building it out of divs would only cost the
   reader the row/column semantics for nothing.
-------------------------------------------------------------------------- */

.ledger-band {
    padding-block: clamp(4.5rem, 3rem + 6vw, 9rem);
}

.ledger-intro {
    max-width: 34rem;
    margin-bottom: clamp(2.5rem, 1.8rem + 2.6vw, 4rem);
}

/* .mono-label sets line-height 1, right for a chip and wrong for a label
   that wraps on narrow screens. */
.ledger-eyebrow {
    line-height: 1.7;
    color: var(--grey-warm);
    margin-bottom: 1rem;
}

.ledger-lede {
    font-size: var(--size-lead);
    color: var(--ink);
    text-wrap: balance;
}

.ledger {
    width: 100%;
    /* Collapsed, so a single hairline sits between two rows instead of two
       hairlines meeting. */
    border-collapse: collapse;
    text-align: left;
}

/* The rule belongs to the top of each row, which puts one above the first
   row (closing the header block) and none below the last (the sum's own
   heavier rule closes the table). */
.ledger-row > * {
    border-top: var(--rule);
    padding-block: clamp(0.9rem, 0.65rem + 0.9vw, 1.35rem);
    vertical-align: baseline;
}

/* `width: 1%` on a nowrap cell is the table idiom for "as narrow as your
   content, and no narrower": the label column takes everything left over. */
.ledger-index {
    width: 1%;
    white-space: nowrap;
    padding-right: clamp(1rem, 0.5rem + 2vw, 2.5rem);
    font-size: var(--size-micro);
    color: var(--grey-warm);
}

.ledger-label {
    font-size: var(--size-lead);
    color: var(--ink);
    padding-right: 1.5rem;
}

.ledger-qty {
    width: 1%;
    white-space: nowrap;
    text-align: right;
    font-size: var(--size-micro);
    text-transform: uppercase;
    color: var(--grey-warm);
}

/* The sum. Heavier top rule in ink rather than hairline grey: the ledger
   convention for "everything above this line adds up to this". */
.ledger-sum-cell {
    border-top: 2px solid var(--ink);
    padding-top: clamp(1.25rem, 0.9rem + 1.4vw, 2rem);
    /* Up one step from the eyebrow size .mono-label ships, so the sum
       carries the same weight as the figures it is summing. */
    font-size: var(--size-micro);
    /* .mono-label's line-height 1 would clip a wrapped sum on narrow
       screens. */
    line-height: 1.6;
    color: var(--ink);
}

@media (max-width: 40rem) {
    .ledger-index {
        padding-right: 1rem;
    }

    .ledger-label {
        padding-right: 0.875rem;
        font-size: var(--size-body);
    }

    .ledger-index,
    .ledger-qty {
        font-size: 0.6875rem;
    }
}

/* ----------------------------------------------------------------------------
   7. The Narrative.

   One passage, ink on cream, held on one screen while it is read. Nothing
   here dims anything: the resting state below is the finished paragraph,
   and js/ledger.js applies the dim only when it takes the section over.
-------------------------------------------------------------------------- */

.narrative {
    display: flex;
    align-items: center;
    min-height: 100vh;
    min-height: 100svh;
    padding-block: 6rem;
}

.narrative-copy {
    /* The measure is the design constraint, and it also fixes the line
       count: characters-per-line at a ch-based max-width is the same at
       every size, so this passage is 13 lines whatever the type does. */
    max-width: 26ch;
    font-weight: var(--weight-display);
    /* Which is why the size answers to the viewport's HEIGHT as well as its
       width: those 13 lines have to finish inside the pinned screen, and
       they land at ~67% of it. The width term sets the ambition, the height
       term is the ceiling that keeps the passage whole. Measured landings:
       23px on a phone, 36px on a 1280x800 laptop, and the 52px ceiling on a
       display tall enough to ask for it. (13 line boxes of 1.14em are 14.8em,
       and 4.5vh x 14.8 is 67vh. Narrower than 26ch the phone runs to 16
       lines, but its type is smaller in the same proportion, so the passage
       still lands near half the screen.) */
    font-size: clamp(1.25rem, min(0.85rem + 2.6vw, 4.5vh), 3.25rem);
    line-height: 1.14;
    letter-spacing: var(--tracking-display);
    color: var(--ink);
}

/* The one accent moment of the section. It is orange in the markup's
   resting state too, so the reduced-motion rendering keeps the emphasis
   even though it never animates to it. */
.narrative-accent {
    color: var(--accent);
}

/* ----------------------------------------------------------------------------
   8. The features index.

   The same ledger grammar as section 6, opened out. A row here is not a line
   item with a figure on the end, it is a mono header line and a passage, so
   the row becomes two columns on a wide screen: the header in one, the
   measured body in the other, a hairline between entries and nothing else.
   That offset is the whole reason for the grid. Nine paragraphs in a single
   column would read as a wall no matter how quiet the type is.

   No cards, no icons, no border that is not a hairline. The section reuses
   .ledger-intro / .ledger-eyebrow / .ledger-lede unchanged, so its header
   block and the problems table's are literally the same component.
-------------------------------------------------------------------------- */

/* An <ol>, not a <table>: an ordered index of prose with nothing to sum.
   `list-style: none` costs the list its semantics in Safari, which is what
   the role="list" in the markup buys back. */
.features {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Mobile-first, one column. As in the table above the rule belongs to the TOP
   of each entry: that puts one under the section header, and none below the
   ninth, where the black band that follows closes the list on its own. */
.feature {
    border-top: var(--rule);
    padding-block: clamp(1.75rem, 1.15rem + 2.4vw, 2.75rem);
}

/* `001 / TITLE`. Mono, letter-spaced, and sized a step above the ledger's
   index cells because here it is the entry's title rather than its label. */
.feature-head {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: var(--weight-body);
    line-height: 1.5;
    letter-spacing: var(--tracking-mono);
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    margin-bottom: 0.875rem;
}

/* The number and its separator recede so the title carries the ink. */
.feature-index,
.feature-sep {
    color: var(--grey-warm);
}

.feature-body {
    /* Also the wide grid's second track. Repeated here because it is the
       measure that matters, and in one column there is no track to hold it. */
    max-width: 34rem;
    font-size: var(--size-lead);
    color: var(--grey-warm);
}

/* The sentence that states the claim takes the ink; the mechanism and the
   detail around it stay muted. Colour is the only difference between them,
   and it is emphasis rather than information: the entry says exactly the
   same thing read flat, so nothing depends on seeing the contrast. */
.feature-claim {
    color: var(--ink);
}

@media (max-width: 40rem) {
    /* Down a step so the longest header (`009 / SELF-HOSTED AND PRIVATE`)
       still sets on one line on a narrow phone. */
    .feature-head {
        font-size: 0.8125rem;
    }

    .feature-body {
        font-size: var(--size-body);
    }
}

/* Wide viewports: header column, body column, and a hairline that runs the
   full width of the band across both of them. The space to the right of the
   body is margin, not a third column. Nothing is ever placed in it.

   Baseline alignment rather than `start`: the mono header and the sans body
   are set at different sizes and leadings, so aligning the boxes would leave
   the header visibly riding above the line it belongs to. Aligning their
   first baselines is self-correcting at every step of both clamps. */
@media (min-width: 60rem) {
    .feature {
        display: grid;
        grid-template-columns: minmax(0, 22rem) minmax(0, 34rem);
        column-gap: clamp(2rem, 0.6rem + 3.2vw, 5rem);
        justify-content: start;
        align-items: baseline;
    }

    .feature-head {
        margin-bottom: 0;
    }
}

/* ----------------------------------------------------------------------------
   9. THE ACTUAL PLATFORM.

   The counter-material band, and the only section on the page that is a
   widget rather than a document. It is a master/detail browser: the stack on
   the left, the selected node's card on the right, stacked on a phone.

   Two renderings, one markup, and the difference is a single class:

     - Resting (this file's default, and what a blocked js/ledger.js leaves):
       nested lists with every node's image, role and sentence set inline
       after its name. Complete, readable, and claiming nothing it cannot do.
     - Live (`.is-live`, added by js/ledger.js when it upgrades the lists into
       an ARIA tree): the inline meta collapses, the panel and the key hint
       appear, and on a wide screen the two become columns.

   Mono throughout the tree, because every line of it is data. White at the
   opacity steps, hairlines at --line, and exactly one orange: the marker on
   the selected node, which is state.
-------------------------------------------------------------------------- */

.platform {
    padding-block: clamp(4.5rem, 3rem + 6vw, 9rem);

    /* A fourth step, local to this band. The detail sentence has to read as
       running prose against nine lines of mono data, and .55 is too quiet to
       carry a sentence while .9 makes it compete with the node names. Still
       white at an opacity, never a grey hex. */
    --on-black-soft: rgba(255, 255, 255, 0.75);
}

.platform-head {
    max-width: 34rem;
    margin-bottom: clamp(2.5rem, 1.8rem + 2.6vw, 4rem);
}

/* .mono-label sets line-height 1, right for a chip and wrong for a label
   that wraps on narrow screens. */
.platform-eyebrow {
    line-height: 1.7;
    color: var(--text-muted);
    margin-bottom: 1rem;
}

.platform-lede {
    font-size: var(--size-lead);
    color: var(--text);
    text-wrap: balance;
}

/* The tree ------------------------------------------------------------- */

.ptree,
.ptree-kids {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ptree-group + .ptree-group {
    margin-top: clamp(1.75rem, 1.2rem + 1.6vw, 2.75rem);
}

.ptree-group-name {
    line-height: 1.7;
    color: var(--text-muted);
    margin-bottom: 0.625rem;
}

/* A row is a marker, a name, and (at rest) the rest of the record trailing
   it. `flex-wrap` rather than a grid: the meta wraps by itself on a narrow
   screen, and the sentence claims a line of its own with flex-basis. */
.pnode {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 1rem;
    row-gap: 0.375rem;
    /* As in the ledger and the features index, the rule belongs to the TOP of
       each row: one under each group name, none below the last node. */
    border-top: var(--rule);
    padding-block: 0.8125rem;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    line-height: 1.5;
    letter-spacing: var(--tracking-mono-tight);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    overflow-wrap: break-word;
}

/* The marker. A square rather than a glyph: it is drawn, so it cannot fall
   back to another font's idea of a triangle, and it holds its place in every
   row whether or not that row is the selected one. At rest it is a hairline;
   selected, it is the one orange in the band. */
.pnode-mark {
    flex: none;
    width: 0.4375rem;
    height: 0.4375rem;
    background-color: var(--line);
}

/* The name is what the row IS, so it takes the top step and the rest of the
   record stays muted around it. This is the resting hierarchy, and it is the
   one a reader with no script gets: an identifier must not read quieter than
   the sentence describing it. */
.pnode-name {
    color: var(--text);
}

.pnode-role {
    text-transform: uppercase;
    letter-spacing: var(--tracking-mono);
}

/* The sentence takes a line of its own, indented to sit under the name
   rather than under the marker. */
.pnode-detail {
    flex-basis: 100%;
    margin-left: 1.4375rem;
    color: var(--on-black-soft);
}

/* Selection. Colour is emphasis here, not information: the panel says which
   node is open in words, and at rest nothing is selected at all. */
.pnode.is-selected .pnode-mark {
    background-color: var(--accent);
}

/* Hidden until js/ledger.js has actually made the tree walkable. */
.ptree-hint,
.pdetail {
    display: none;
}

/* The live widget ------------------------------------------------------ */

.platform.is-live .pnode-meta {
    display: none;
}

.platform.is-live .pnode {
    cursor: pointer;
}

/* Live, the column stops being the record and becomes a list of choices, so
   the names step back a tone and the open one takes the ink back. The tree
   then reads the way a master list should: one bright line, the rest quiet. */
.platform.is-live .pnode-name {
    color: var(--text-muted);
    transition: color var(--dur-fast) var(--ease-out);
}

.platform.is-live .pnode:hover .pnode-name,
.platform.is-live .pnode.is-selected .pnode-name {
    color: var(--text);
}

.platform.is-live .ptree-hint {
    display: block;
    line-height: 1.7;
    color: var(--on-black-faint);
    margin-top: 1.25rem;
}

.platform.is-live .pdetail {
    display: block;
    margin-top: clamp(2rem, 1.4rem + 2vw, 3rem);
    padding-top: clamp(1.5rem, 1.1rem + 1.4vw, 2rem);
    border-top: var(--rule);
}

.pdetail-name {
    font-size: 0.9375rem;
    color: var(--text);
}

.pdetail-image,
.pdetail-role {
    color: var(--text-muted);
}

.pdetail-image {
    font-size: 0.8125rem;
    margin-top: 0.375rem;
}

.pdetail-role {
    line-height: 1.7;
    margin-top: 1.125rem;
}

.pdetail-body {
    max-width: 30rem;
    font-size: var(--size-lead);
    color: var(--on-black-soft);
    margin-top: 0.875rem;
}

@media (max-width: 40rem) {
    /* Down a step so the longest name (`auracle-desktop 0.9`) and the longest
       image string still set inside a phone's measure. */
    .pnode,
    .pdetail-name {
        font-size: 0.8125rem;
    }
}

/* Wide viewports, live only: master and detail become columns. At rest the
   tree still runs full width, because at rest it is carrying the whole
   record and there is no panel beside it to make room for.

   The rule between them is the panel's own left border, and the grid's
   default `stretch` is what runs it the full height of the tree. */
@media (min-width: 60rem) {
    .platform.is-live .platform-browser {
        display: grid;
        grid-template-columns: minmax(0, 17rem) minmax(0, 32rem);
        column-gap: clamp(2rem, 0.6rem + 3.2vw, 5rem);
        justify-content: start;
    }

    .platform.is-live .pdetail {
        margin-top: 0;
        padding-top: 0;
        padding-left: clamp(1.5rem, 1rem + 1.6vw, 2.5rem);
        border-top: 0;
        border-left: var(--rule);
    }
}

/* ----------------------------------------------------------------------------
   10. Pricing: the band and Clerk's mount.

   The band's rhythm is the ledger band's, deliberately: pricing, problems
   and the features index are the same cream measure at the same cadence.

   The price list itself is module 17. This module holds only what belongs to
   the section and to Clerk Billing's mount target, both of which are
   independent of how the cards are drawn.
-------------------------------------------------------------------------- */

.pricing {
    padding-block: clamp(4.5rem, 3rem + 6vw, 9rem);
}

/* Clerk Billing's mount target. Empty at rest, and empty means zero-height:
   nothing here may give it a height of its own, or js/ledger.js could not
   tell a mounted plan list from a Billing outage. */
.plans-table {
    margin: 0;
}

/* Once Clerk has actually rendered plans, the table is the section's whole
   content and needs the air the cards were holding. */
.plans-table:not(:empty) {
    margin-top: 1rem;
}

/* ----------------------------------------------------------------------------
   11. FAQ.

   Six questions, hairlines between them, and the disclosure is the browser's
   own <details>. Mono for the question, because a question here reads as a
   label on the answer; sans at the standard measure for the answer, because
   it is prose.

   Nothing in this block animates the open/close. `details` has no height to
   transition to in the first place, and faking one would mean owning the
   open state in script and losing find-in-page inside closed answers, which
   is a real feature traded for a slide.

   The row class is `.faq-row` and not the obvious `.faq-item` because
   css/index.css, the legacy sheet still linked above this one, already owns
   `.faq-item summary` and `.faq-item summary::after` from the old page. Those
   are one element more specific than anything a single class here can say, so
   they would win from EARLIER in the cascade: the old sheet's "+" glyph would
   still be drawn, at its own size and position, and its "−" would still be
   painted with the accent. A different name simply does not match them.
   Check any new class on this page against index.css before using it.
-------------------------------------------------------------------------- */

.faq {
    /* The pricing band's rhythm, and the ledger's before it. */
    padding-block: clamp(4.5rem, 3rem + 6vw, 9rem);
}

/* The eyebrow is the whole header here, so it carries its own gap and does
   not also inherit the intro's. */
.faq-intro .ledger-eyebrow {
    margin-bottom: 0;
}

/* As everywhere else, the rule belongs to the TOP of the entry. */
.faq-row {
    border-top: var(--rule);
}

.faq-q {
    /* Two removals, because the marker is drawn below: `list-style` is what
       modern engines honour, the -webkit pseudo-element is what older Safari
       needs. */
    list-style: none;
    /* A block, and the marker is positioned rather than laid out beside the
       text. A flex row would put the marker in the same line box as the
       question, which is right until the question wraps or the engine boosts
       the type, and then the marker drifts off the line it is marking. Out
       of flow it always sits on the FIRST line, whatever happens to the
       rest. The padding is a custom property because the marker's offset is
       measured from it. */
    --faq-pad: clamp(1.125rem, 0.9rem + 0.9vw, 1.5rem);
    position: relative;
    display: block;
    cursor: pointer;
    padding-block: var(--faq-pad);
    /* Room for the marker, plus a gutter, so a long question never sets
       underneath it. */
    padding-right: 2rem;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    line-height: 1.5;
    letter-spacing: var(--tracking-mono);
    color: var(--ink);
}

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

/* The marker: a plus that loses its upright when the answer is open. Drawn
   from the same hairline the section is ruled with, and built out of
   backgrounds so no text enters the reading order. `details` already tells
   assistive technology whether it is expanded. */
.faq-q::after {
    content: "";
    position: absolute;
    right: 0;
    /* The centre of the first line: the padding, then half of one 1.5em line
       box. Its own height is then taken back off by the translate, so the
       marker is centred on the line at every step of the clamp and at any
       type size the engine decides to serve. */
    top: calc(var(--faq-pad) + 0.75em);
    transform: translateY(-50%);
    width: 0.625rem;
    height: 0.625rem;
    background-image: linear-gradient(var(--ink), var(--ink)),
        linear-gradient(var(--ink), var(--ink));
    background-size:
        100% 1px,
        1px 100%;
    background-position: center;
    background-repeat: no-repeat;
}

/* Open, the upright is taken away and the plus becomes a minus. The second
   size is written out rather than left to the list cycling back onto the
   first: two identical bars stacked on one another is a minus by accident,
   and this is a minus on purpose. */
.faq-row[open] .faq-q::after {
    background-size:
        100% 1px,
        0 0;
}

.faq-a {
    max-width: 34rem;
    font-size: var(--size-lead);
    color: var(--grey-warm);
    padding-bottom: clamp(1.25rem, 1rem + 1vw, 1.75rem);
}

@media (max-width: 40rem) {
    .faq-q {
        font-size: 0.8125rem;
    }

    .faq-a {
        font-size: var(--size-body);
    }
}

/* ----------------------------------------------------------------------------
   12. The colophon.

   The last band, and the quietest. Mono throughout, because a footer is an
   index: names of places, not prose. One hairline across the top to close the
   page, and no second rule anywhere inside it.

   No accent. The page spends its one orange on Community's DOWNLOAD, and a
   footer link is not a verb.
-------------------------------------------------------------------------- */

.colophon {
    border-top: var(--rule);
    padding-block: clamp(3rem, 2.2rem + 2.8vw, 4.5rem);
}

/* The mark. The source SVG ships hard-white for the old dark chrome, so it
   is used here as a mask and painted ink: one request, the exact token
   colour, and no second asset to keep in sync. Matches the secondary pages'
   idiom in css/reskin.css. */
.colophon-mark {
    display: block;
    width: 1.5rem;
    height: 1.5rem;
    background-color: var(--ink);
    -webkit-mask-image: url("/assets/logo/auracle-mark.svg?v=2");
    mask-image: url("/assets/logo/auracle-mark.svg?v=2");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.colophon-brand {
    margin-bottom: clamp(2.25rem, 1.8rem + 1.8vw, 3.25rem);
}

/* Three columns that wrap rather than collapse: at any width they stay side
   by side until they genuinely cannot, and there are only ever three short
   lists. */
.colophon-cols {
    display: flex;
    flex-wrap: wrap;
    gap: 2rem 4rem;
}

.colophon-k {
    line-height: 1.7;
    color: var(--grey-warm);
    margin-bottom: 1rem;
}

.colophon-links {
    list-style: none;
    margin: 0;
    padding: 0;
    font-family: var(--font-mono);
    font-size: var(--size-micro);
    letter-spacing: var(--tracking-mono-tight);
}

.colophon-links li + li {
    margin-top: 0.625rem;
}

.colophon-links a,
.colophon-contact a {
    color: var(--ink);
    text-decoration-color: var(--line);
    text-decoration-line: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.3em;
    transition: text-decoration-color var(--dur-fast) var(--ease-out);
}

.colophon-links a:hover,
.colophon-links a:focus-visible,
.colophon-contact a:hover,
.colophon-contact a:focus-visible {
    text-decoration-color: var(--ink);
}

.colophon-contact {
    margin-top: clamp(2.25rem, 1.8rem + 1.8vw, 3.25rem);
    font-family: var(--font-mono);
    font-size: var(--size-micro);
    letter-spacing: var(--tracking-mono-tight);
}

/* The closing line. Quiet, and last. */
.colophon-line {
    line-height: 1.7;
    color: var(--grey-warm);
    margin-top: 1.25rem;
}

@media (max-width: 40rem) {
    .colophon-cols {
        gap: 1.75rem 2.5rem;
    }
}

/* ----------------------------------------------------------------------------
   13. The features band: the dark staging, and the ASCII field.

   Section 8 above stays the features index's base — the list reset, the mono
   `001 / TITLE` header, the measure, the hairline at the top of every entry.
   This module stages it, and the staging is two moves of a piece.

   The band becomes black. THE WORKSPACE below it is back on cream, so the page
   runs black, cream, black through here and every colour in this band is white
   at one of the opacity steps, as on every dark band.

   Neither seam carries a hairline. A hairline says where one thing ends when
   both sides are the same material; here the material changes, which says it
   already, and a white .14 rule laid along the edge of the cream would only
   read as a smear.

   And the nine entries become a stepped ladder: 001 at the left edge, each
   entry a tread further right, three treads to a flight and three flights to
   the nine. That is layout, so it is here and not in the markup. Below 60rem
   there is no room for treads and the ladder is a plain single column, which
   is also section 8's own rendering.

   The rest of the band is the ASCII field. js/ledger.js builds it; everything
   about it here is one absolutely positioned box that catches nothing.
-------------------------------------------------------------------------- */

.features-band {
    position: relative;
    /* The field's canvas is inset to this box. The clip is belt and braces
       against a subpixel rounding of its right edge. */
    overflow: hidden;
    padding-block: clamp(4.5rem, 3rem + 6vw, 9rem);

    /* A fourth step, local to this band as in the platform band's: the claim
       sentence sits between the header at .9 and the body at .55. Still white
       at an opacity, never a grey hex. */
    --on-black-claim: rgba(255, 255, 255, 0.8);

    /* The tread. Two of them at the top of the flight, so the ladder is at
       most 26rem + 8rem wide and the field keeps the rest of the band. */
    --tread: clamp(1.25rem, 0.4rem + 3.4vw, 4rem);
}

/* The ladder reads over the field, never under it. */
.features-band > .band-in {
    position: relative;
    z-index: 1;
}

/* The header block is literally the problems table's component; only the
   surface under it changed. */
.features-band .ledger-eyebrow {
    color: var(--text-muted);
}

.features-band .ledger-lede {
    color: var(--text);
}

/* One measure for the whole ladder. The entry, its body and the hairline
   above it are all this wide, so the rules step with the treads instead of
   running the width of the band and flattening the staircase. */
.features-band .feature {
    max-width: 26rem;
}

.features-band .feature-head {
    color: var(--text);
}

.features-band .feature-index,
.features-band .feature-sep,
.features-band .feature-body {
    color: var(--text-muted);
}

.features-band .feature-claim {
    color: var(--on-black-claim);
}

/* The staircase. Section 8's wide-screen two-column grid is off here: a
   header column and a body column would want the same horizontal room the
   treads do, and on this band the treads are the point. */
@media (min-width: 60rem) {
    .features-band .feature {
        display: block;
    }

    .features-band .feature-head {
        margin-bottom: 0.875rem;
    }

    .features-band .feature:nth-child(3n + 2) {
        margin-left: var(--tread);
    }

    .features-band .feature:nth-child(3n) {
        margin-left: calc(var(--tread) * 2);
    }
}

/* The field. The canvas is created by js/ledger.js and is never authored
   into the page, so with the script blocked there is nothing here at all and
   the band is the ladder on black.

   It never takes a pointer event. The section listens; the canvas only ever
   draws. */
.ascii-field {
    position: absolute;
    top: 0;
    left: 0;
    /* Stated, not implied: a canvas is a replaced element, and a replaced
       element pinned on all four sides still takes its intrinsic 300x150
       rather than the box between them. */
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    /* Narrow, the field IS the band's background and the ladder reads on top
       of it, so it drops back a further step. */
    opacity: 0.5;
}

@media (min-width: 60rem) {
    .ascii-field {
        /* Wide, the field is the right of the band and the ladder has the
           left. They meet a little past the middle, which is where the
           longest tread of the ladder ends. */
        left: 52%;
        width: 48%;
        opacity: 1;
    }
}

/* ----------------------------------------------------------------------------
   14. THE WORKSPACE: the IDE window.

   A dark window on the cream ground, between the two black bands. It is the
   one object on this page that is a THING rather than a band, and everything
   here is in service of that: it has an edge, a radius, an interior of its
   own, and it stops well short of the viewport.

   Inside it the `.on-black` contract from tokens.css is in force, so every
   descendant keeps using --text / --text-muted / --line and gets the white
   opacity steps. Only the ground is different: the window's interior is
   #0d0d0c rather than the bands' pure black, which is what stops it reading
   as a hole punched through to the band above.

   Two things and only two things are drawn by js/ledger.js: the key chips
   (a promise, kept only once the keys work) and the minimap (decoration).
   Every document is authored markup, and the file the window opens on is
   already open before a line of script has run.

   The one accent in the window is the status bar's branch dot.
-------------------------------------------------------------------------- */

.ide {
    padding-block: clamp(4.5rem, 3rem + 6vw, 9rem);
}

.ide-head {
    max-width: 34rem;
    margin-bottom: clamp(2.25rem, 1.6rem + 2.4vw, 3.5rem);
}

/* .mono-label sets line-height 1, right for a chip and wrong for a label that
   wraps on a narrow screen. */
.ide-eyebrow {
    line-height: 1.7;
    color: var(--text-muted);
    margin-bottom: 1rem;
}

.ide-lede {
    font-size: var(--size-lead);
    text-wrap: balance;
}

/* The window ------------------------------------------------------------ */

.ide-window {
    /* Not the bands' pure black. See the module note above. */
    background-color: #0d0d0c;
    border: 1px solid rgba(35, 35, 35, 0.16);
    border-radius: 10px;

    /* The border is ink at 16%, and ink at 16% laid over a near-black
       interior is invisible. Clipping the background to the padding box
       leaves the border strip showing the cream underneath, tinted: a warm
       hairline hugging the window, which is the edge this system draws
       everywhere else. A ring shadow would have been a glow. */
    background-clip: padding-box;

    /* The interior rows are full-bleed inside the window, so they have to be
       clipped to the radius rather than each learning about the corners. */
    overflow: hidden;
}

/* The title bar --------------------------------------------------------- */

.ide-bar {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.625rem 0.75rem;
    border-bottom: var(--rule);
}

.ide-tabs {
    display: flex;
    flex: none;
    gap: 0.25rem;
}

/* Ink-on-paper, inverted: on this ground the ACTIVE shell is the light one
   and the two that are not rendered here stay at the faint step. They are
   spans, not buttons: there is nothing behind them to press. */
.ide-tab {
    line-height: 1;
    padding: 0.4375rem 0.625rem;
    border-radius: 5px;
    color: var(--on-black-faint);
    white-space: nowrap;
}

.ide-tab.is-active {
    background-color: var(--on-black);
    color: #0d0d0c;
}

.ide-bar-title {
    flex: 1 1 auto;
    line-height: 1;
    text-align: center;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Hidden until initIde() has bound the keys they advertise. */
.ide-keys {
    display: none;
    flex: none;
    gap: 0.3125rem;
}

.ide.is-live .ide-keys {
    display: flex;
}

.ide-key {
    font-size: var(--size-eyebrow);
    line-height: 1;
    padding: 0.375rem 0.4375rem;
    border: var(--rule);
    border-radius: 4px;
    color: var(--on-black-faint);
    white-space: nowrap;
}

/* The body: file list + editor ------------------------------------------ */

.ide-body {
    display: grid;
    /* Narrow, one column: the file list becomes a strip above the editor. */
    grid-template-columns: minmax(0, 1fr);
}

.ide-treecol {
    min-width: 0;
    padding: 0.875rem 0.75rem;
}

.ide-path {
    font-size: var(--size-eyebrow);
    letter-spacing: var(--tracking-mono);
    color: var(--on-black-faint);
    margin-bottom: 0.75rem;
    overflow-wrap: anywhere;
}

.ide-tree {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ide-file {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3125rem 0.4375rem;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    line-height: 1.4;
    letter-spacing: var(--tracking-mono-tight);
    color: var(--text-muted);
}

/* The ring is drawn inside the row: the window clips to its radius, and an
   outset ring on the first or last row would be clipped with it. */
.ide-file:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* Selection is a lift and the ink, never the accent: the accent in this
   window is the branch dot, and one view gets one verb. */
.ide-file.is-selected {
    background-color: rgba(255, 255, 255, 0.07);
    color: var(--text);
}

/* The file-type tag. A mark, so it takes the graphic secondaries. */
.ide-glyph {
    flex: none;
    width: 1.25rem;
    font-size: 0.5625rem;
    line-height: 1.4;
    letter-spacing: var(--tracking-mono);
    text-align: center;
    opacity: 0.7;
}

.ide-glyph-py {
    color: var(--tan);
}

.ide-glyph-md {
    color: var(--powder);
}

.ide-file-name {
    overflow-wrap: anywhere;
}

/* The editor ------------------------------------------------------------ */

.ide-editor {
    position: relative;
    min-width: 0;
    padding: 0.875rem 0.75rem;
    border-top: var(--rule);

    /* A floor, not a height: the eight documents are different lengths and
       the window must not jump between them. This is the tallest one, the
       24-line Python excerpt, at the narrow screen's size. Anything taller
       simply grows the pane. */
    min-height: 18rem;
}

.ide-doc-name {
    font-size: 0.75rem;
    letter-spacing: var(--tracking-mono);
    color: var(--text);
    padding-bottom: 0.75rem;
    margin-bottom: 0.875rem;
    border-bottom: var(--rule);
    overflow-wrap: anywhere;
}

/* Belt and braces: `[hidden]` is a single attribute selector and this file
   loads last, so any later `display` on .ide-doc would silently beat it. */
.ide-doc[hidden] {
    display: none;
}

.ide-doc-note {
    font-size: 0.75rem;
    color: var(--on-black-faint);
}

/* The numbered lines. `list-style: decimal` has to be restated because the
   Tailwind preflight strips it from every ol on the page, and `start` on the
   element carries the real offset into the file.

   The number is the marker rather than a span per line: it cannot drift out
   of step with its line, it holds its column for free, and a reader copying
   the code gets the code. */
.ide-lines {
    list-style: decimal;
    margin: 0;
    padding-left: 2.5rem;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    line-height: 1.6;
    font-variant-numeric: tabular-nums;
    /* The plain-code step: between the header at .9 and the muted step at
       .55, as the features band's claim sentence is. White at an opacity,
       never a grey hex. */
    color: rgba(255, 255, 255, 0.8);
}

.ide-lines > li {
    /* The excerpts are indented source: their leading spaces and their
       comment columns are content. They still wrap, because a phone is
       narrower than the code. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    /* A blank line is a line. Without this its box collapses and the
       numbering steps over a row that is not there. */
    min-height: 1.6em;
}

.ide-lines > li::marker {
    color: rgba(255, 255, 255, 0.25);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
}

/* Quiet tinting, three tones and no more: the comment drops back, the
   keyword and the literal take the two graphic secondaries, and everything
   else is the plain code step. */
.ide-c {
    color: rgba(255, 255, 255, 0.35);
}

.ide-k {
    color: var(--tan);
}

.ide-v {
    color: var(--powder);
}

/* The minimap. Drawn by js/ledger.js, so at rest there is nothing in it and
   nothing of it. It never takes a pointer event. */
.ide-minimap {
    display: none;
    pointer-events: none;
}

.ide-mini-bar {
    display: block;
    height: 2px;
    margin-bottom: 2px;
    background-color: rgba(255, 255, 255, 0.14);
}

/* The terminal ---------------------------------------------------------- */

.ide-term {
    padding: 0.875rem 0.75rem;
    border-top: var(--rule);
}

.ide-term-label {
    line-height: 1;
    color: var(--on-black-faint);
    margin-bottom: 0.75rem;
}

.ide-term-line {
    font-size: 0.6875rem;
    line-height: 1.7;
    color: var(--on-black-faint);
    overflow-wrap: anywhere;
}

/* The command is the one thing in the terminal that was typed, so it is the
   only thing in it that takes ink. */
.ide-cmd {
    color: rgba(255, 255, 255, 0.8);
}

/* The status bar -------------------------------------------------------- */

.ide-status {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0.75rem;
    border-top: var(--rule);
    font-size: var(--size-eyebrow);
    line-height: 1.4;
    letter-spacing: var(--tracking-mono);
    color: var(--on-black-faint);
}

.ide-status-left {
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ide-status-right {
    flex: none;
}

/* The one accent in the window. It reports which branch the workspace is on,
   which is state, which is what the accent is for. */
.ide-dot {
    flex: none;
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 50%;
    background-color: var(--accent);
    margin-right: 0.5rem;
}

/* Narrow ---------------------------------------------------------------- */

/* Below the two-column threshold the file list is a strip that scrolls
   sideways in its own box. Its own box matters: the page must never be the
   thing that scrolls sideways. */
@media (max-width: 59.999rem) {
    /* Three shells, two key chips and a sentence do not fit across a phone,
       and a sentence squeezed to an ellipsis is not a sentence. The bar
       wraps instead: chrome on the first row, the claim on its own. */
    .ide-bar {
        flex-wrap: wrap;
        row-gap: 0.625rem;
    }

    .ide-bar-title {
        order: 3;
        flex: 1 0 100%;
        text-align: left;
    }

    .ide-tree {
        display: flex;
        gap: 0.375rem;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        /* Room for the focus ring, which is drawn inside the row. */
        padding-block: 2px;
    }

    .ide-file {
        flex: none;
        white-space: nowrap;
    }

    .ide-file-name {
        overflow-wrap: normal;
    }
}

/* Wide ------------------------------------------------------------------ */

@media (min-width: 60rem) {
    /* The column is sized to the longest name in the folder
       (MOMENTUM_WITH_REGIME_FILTER.PY) so every file is one row, which is
       what makes it read as a file list rather than a paragraph. */
    .ide-body {
        grid-template-columns: minmax(0, 19rem) minmax(0, 1fr);
    }

    .ide-treecol {
        padding: 1.125rem 1rem;
    }

    .ide-path {
        margin-bottom: 1rem;
    }

    .ide-file {
        padding: 0.375rem 0.5rem;
    }

    /* The rule between the columns is the editor's own left border, and the
       grid's default `stretch` runs it the full height of the taller one. */
    .ide-editor {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        align-content: start;
        padding: 1.125rem 1.25rem;
        border-top: 0;
        border-left: var(--rule);
        /* The 24-line excerpt at this size, plus its filename row. */
        min-height: 34rem;
    }

    /* The minimap's column is opened only when there is a minimap to put in
       it. Reserving it at rest would leave a strip of nothing beside the
       code of a reader whose script never ran. */
    .ide.is-live .ide-editor {
        grid-template-columns: minmax(0, 1fr) 3.5rem;
        column-gap: 1.25rem;
    }

    /* The documents share the first column; the minimap holds the second for
       all of them, so swapping files cannot move it. */
    .ide-doc {
        grid-column: 1;
    }

    .ide.is-live .ide-minimap {
        display: block;
        grid-column: 2;
        grid-row: 1 / -1;
        align-self: start;
        /* Clear of the filename row, so it reads against the code. */
        margin-top: 2.75rem;
    }

    .ide-lines {
        font-size: 0.8125rem;
        padding-left: 3rem;
    }

    .ide-lines > li::marker {
        font-size: 0.75rem;
    }

    .ide-bar,
    .ide-term {
        padding-inline: 1.25rem;
    }

    .ide-status {
        padding-inline: 1.25rem;
    }

    .ide-term-line,
    .ide-doc-note {
        font-size: 0.8125rem;
    }
}

/* ----------------------------------------------------------------------------
   15. The hero split.

   The hero becomes two halves: the claim on the cream left, and a dark panel
   on the right carrying the ASCII field. Section 3 above stays the copy
   side's base — its type, its rhythm, its spacing are untouched. This module
   only re-seats it.

   Wide (>=60rem) it is a grid, roughly 55/45. The left column carries the
   page's own left margin so the eyebrow starts on the same vertical as every
   band below it; the right column runs from the split to the edge of the
   page with no gutter at all, because a dark panel that stopped a few rem
   short of the edge would read as a card rather than as the other half of
   the hero. The panel stretches, so it is exactly as tall as the hero.

   Narrow, there is no room for a column: the panel drops below the copy as a
   short full-bleed band, which is the same shape as every other band on the
   page. It stays live either way.

   The panel is empty markup. js/ledger.js builds a canvas into it; with the
   script blocked it is a plain dark surface, which is a rendering this
   system is happy to ship.
-------------------------------------------------------------------------- */

.hero {
    /* The band's own inline padding, named so the narrow panel can cancel it
       and bleed to both edges. Same value as .band's, deliberately: the
       panel's edge is the page's edge. */
    --hero-pad: clamp(1.25rem, 0.6rem + 2.8vw, 4rem);

    /* Section 3 centres a single child in a row. There are two children now
       and they stack, so the row becomes a column and the children keep
       their own width instead of being centred to their content. */
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;

    /* The panel closes the hero's bottom edge; the gap above it is the
       copy's, not the section's. */
    padding-block: 9rem 0;
}

.hero-panel {
    position: relative;
    overflow: hidden;
    background-color: var(--black);
    flex: none;
    min-height: 40vh;
    margin-top: 5rem;
    margin-inline: calc(-1 * var(--hero-pad));
}

/* The field, in the panel. The features band's rules put its canvas in the
   right half of that band and drop it back behind the ladder; here the panel
   IS the field's box and nothing is set over it, so it takes the whole box
   at full strength. Two classes deep, so this wins over section 13's rules
   at every width without either one having to know about the other. */
.hero-panel .ascii-field {
    left: 0;
    width: 100%;
    opacity: 1;
}

@media (min-width: 60rem) {
    .hero {
        display: grid;
        grid-template-columns: 55fr 45fr;
        align-items: stretch;

        /* The gutters move to the columns: the left one keeps the page
           margin, the right one has none. Percentage padding resolves
           against the hero's own width, so on a wide screen the copy lines
           up with the 78rem measure every band below it uses, and on a
           narrower one it falls back to the band margin. Not 100vw: that
           counts a scrollbar the content never gets. */
        padding-block: 0;
        padding-inline: max(var(--hero-pad), calc((100% - 78rem) / 2)) 0;
    }

    .hero-in {
        /* A column now, not a centred measure. */
        max-width: none;
        margin-inline: 0;
        align-self: center;
        padding-block: 9rem 5rem;
        padding-right: var(--hero-pad);
    }

    /* The claim's clamp in section 3 is measured against the window, and the
       window is no longer what it sets in: at 1440 it would ask for ~91px of
       type in a column that holds about 700px of line. Same shape of clamp,
       same 16ch measure, re-based on the column it actually occupies. */
    .hero-claim {
        font-size: clamp(2.5rem, 0.9rem + 3.1vw, 4.5rem);
    }

    .hero-panel {
        /* The grid gives it the full height of the hero and takes it to the
           right edge of the page. */
        min-height: 0;
        margin: 0;
    }
}

/* ----------------------------------------------------------------------------
   16. The pill at six links.

   Section 2's narrow-viewport block dissolves the menu's box so the links and
   the verb wrap against the capsule's row directly. With six links that is no
   longer enough: the list is still one flex item, it is wider than the row on
   a phone, and an item that cannot fit takes a line of its own and pushes
   both the mark above it and the verb below it onto lines of theirs. Four
   rows of capsule is a floating element eating the top of a phone screen,
   which is the one thing that block exists to prevent.

   So the list's own box goes too, and the links wrap one at a time like every
   other item in the row. Same two rows the pill had at five links, and the
   markup carries the role that keeps it a list where dissolving its box would
   otherwise cost it one.
-------------------------------------------------------------------------- */

@media (max-width: 40rem) {
    .pill-links {
        display: contents;
    }
}

/* ----------------------------------------------------------------------------
   17. Pricing: the card anatomy.

   The price list stops being a hairline table and becomes black cards on the
   cream, which is the one place on this page where the counter-material is
   an object rather than a full-bleed band.

   Each card is three slabs stacked with a 3px gap: the price, the numbered
   ledger of what the tier carries, and the action. The gap is not a border
   and not a divider colour, it is the card's own ground showing between the
   slabs, so the seams can never drift out of step with the page. The card
   clips them to its radius, so no slab has to know it is the top or bottom
   one.

   Type follows the system unchanged: the price is display sans, every label
   and every row is mono, and text on the slabs uses the white opacity steps
   (.9 for the line, .55 for the number and the quiet label), never a grey.

   The accent appears twice and both times as state: the live availability
   dot, and a capsule under the pointer or the focus ring. At rest the
   capsules are cream on black, so the page's one orange verb is still the
   hero's DOWNLOAD.
-------------------------------------------------------------------------- */

.pricing {
    /* A hair off --black. The bands on this page are #000; a card sitting on
       the cream is a different object and reads a shade softer at its
       edges. Nothing else in the system uses it. */
    --slab: #0d0d0c;
}

/* The header ------------------------------------------------------------ */

.price-head {
    margin-bottom: clamp(2.25rem, 1.5rem + 2.4vw, 3.5rem);
}

/* The H1 tier, not the hero's extended range: this is the loudest headline
   below the fold and it should not out-shout the one at the top. */
.price-claim {
    font-size: var(--size-h1);
    color: var(--ink);
}

.price-claim-line {
    display: block;
}

/* A fact, set as a label. .mono-label's line-height 1 is wrong here because
   this wraps to two lines between the stacked and side-by-side layouts. */
.price-chip {
    line-height: 1.7;
    color: var(--grey-warm);
    margin-top: 1.25rem;
}

@media (min-width: 60rem) {
    .price-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: start;
        column-gap: 2.5rem;
    }

    .price-chip {
        /* Optically on the first line of the headline rather than its box:
           the cap height of a 5rem line starts well below its top. */
        margin-top: 0.75rem;
        text-align: right;
    }
}

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

.tiers {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
}

.tier {
    display: flex;
    flex-direction: column;
    /* The cream seams between the slabs. */
    gap: 3px;
    border-radius: 12px;
    /* So the corner slabs are cut to the card, not the other way round. */
    overflow: hidden;
    /* The price is measured against the card, not the window: see below. */
    container-type: inline-size;
}

.tier-slab {
    background-color: var(--slab);
    padding: clamp(1.25rem, 0.9rem + 1.4vw, 1.75rem);
}

/* The ledger takes the slack, so the action slabs sit on one line across a
   row of cards however uneven the lists above them are. */
.tier-rows {
    flex: 1 1 auto;
}

.tier-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    line-height: 1.6;
}

.tier-name {
    color: var(--on-black-muted);
}

.tier-status {
    display: inline-flex;
    align-items: center;
    color: var(--on-black);
}

/* Drawn, not typed: a bullet glyph would fall back to another font's idea of
   a dot and would be read out as one. */
.tier-dot {
    flex: none;
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 50%;
    background-color: var(--accent);
    margin-right: 0.5rem;
}

/* Enterprise is not a thing you can start today, and the accent only marks
   state that is live. */
.tier-dot.is-quiet {
    background-color: var(--on-black-muted);
}

/* Sized against the CARD, not the window. A window-based clamp has to be set
   for the widest layout and then breaks the narrowest one: at three cards
   across, a viewport-sized 88px turns CUSTOM into CUSTO/M. In container
   units the price is the same proportion of its card at every count, which
   is also the only reading of "the same display scale" that survives the
   card changing width. ~56px..96px in practice. */
.tier-price {
    font-size: 3.5rem;
    font-size: clamp(3.5rem, 20cqw, 6rem);
    font-weight: var(--weight-display);
    line-height: 1;
    letter-spacing: var(--tracking-display);
    color: var(--on-black);
    margin-top: 1.75rem;
}

/* On the baseline of the number, not floated beside its box. */
.tier-per {
    font-size: var(--size-eyebrow);
    font-weight: var(--weight-body);
    letter-spacing: var(--tracking-mono);
    color: var(--on-black-muted);
    margin-left: 0.625rem;
}

/* The rows -------------------------------------------------------------- */

/* .tier-rows takes its padding from .tier-slab, which it also is. */
.tier-rows,
.includes-list {
    list-style: none;
    margin: 0;
}

.includes-list {
    padding: 0;
}

.tier-row {
    /* Two columns rather than an inline pair, so a line that wraps on a
       phone still hangs off its number. */
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 0.75rem;
    align-items: start;
}

.tier-row + .tier-row {
    margin-top: 0.625rem;
}

.tier-num {
    font-size: var(--size-eyebrow);
    line-height: 1.5;
    color: var(--on-black-muted);
}

/* The site's mono label size, tracking and case, but not .mono-label itself:
   its line-height 1 clips these where they wrap. */
.tier-line {
    font-family: var(--font-mono);
    font-size: var(--size-eyebrow);
    line-height: 1.5;
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    color: var(--on-black);
}

/* The split capsule ----------------------------------------------------- */

/* One link. The notch down the middle is the slab showing through a 3px gap
   between two segments, so there is a single control, a single tab stop and
   a single focus ring, which the radius here keeps capsule-shaped. */
.capsule {
    display: flex;
    width: 100%;
    gap: 3px;
    border-radius: 999px;
}

.capsule-seg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    padding: 0.875rem 1.25rem;
    background-color: var(--cream);
    color: var(--ink);
    font-family: var(--font-mono);
    font-size: var(--size-eyebrow);
    line-height: 1;
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    transition: background-color var(--dur-fast) var(--ease-out);
}

/* The verb takes only the width of its word; the object holds the rest. */
.capsule-verb {
    flex: none;
}

.capsule-seg:first-child {
    border-radius: 999px 0.25rem 0.25rem 999px;
}

.capsule-seg:last-child {
    border-radius: 0.25rem 999px 999px 0.25rem;
}

/* State, which is what the accent is for. */
.capsule:hover .capsule-seg,
.capsule:focus-visible .capsule-seg {
    background-color: var(--accent);
}

/* The includes card ----------------------------------------------------- */

.includes {
    background-color: var(--slab);
    border-radius: 12px;
    padding: clamp(1.5rem, 1rem + 1.8vw, 2.25rem);
    margin-top: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
}

.includes-label {
    line-height: 1.6;
    color: var(--on-black-muted);
    margin-bottom: 1.5rem;
}

/* Padding, not an adjacent-sibling margin: at a column break the margin
   above the first row of the second column is either dropped or kept
   depending on the engine, and either way one column starts 10px off the
   other. Padding is inside the row, so both columns start on the same
   line. */
.includes-list .tier-row {
    margin-top: 0;
    padding-block: 0.3125rem;
}

/* Two columns from the same width the cards take two, and not before: at
   768px a column is barely wider than the longest line in it. */
@media (min-width: 60rem) {
    /* Multicolumn, not a grid: a ledger reads down its column and then over,
       so 001..004 stand together on the left. */
    .includes-list {
        columns: 2;
        column-gap: clamp(1.5rem, 0.8rem + 2.4vw, 3rem);
    }

    .includes-list .tier-row {
        break-inside: avoid;
    }
}

/* Two up, then three ---------------------------------------------------- */

@media (min-width: 60rem) {
    .tiers {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Enterprise takes the second row whole rather than leaving half of it
       empty. It is the tier with the fewest lines, so it is also the one
       that survives being wide. */
    .tier:last-child {
        grid-column: 1 / -1;
    }

    .tier:last-child .capsule {
        width: auto;
        align-self: flex-start;
    }

    .tier:last-child .tier-footslab {
        display: flex;
    }
}

@media (min-width: 80rem) {
    .tiers {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .tier:last-child {
        grid-column: auto;
    }

    .tier:last-child .capsule {
        width: 100%;
    }
}

/* Narrow ---------------------------------------------------------------- */

@media (max-width: 40rem) {
    /* The longest lines (INTERACTIVE BROKERS PAPER WIRING, LIVE ROUTING
       BEHIND AN EXPLICIT GATE) run about 10px past a 360px card. The
       tracking is what gives, not the size: these are still labels and
       still read as the ledger rows they are at 0.02em. */
    .tier-line {
        letter-spacing: var(--tracking-mono-tight);
    }
}
