/*  THE ORDER SITE'S STRUCTURE — layout, component shapes, states. No product.

    ⚠⚠ NOT ONE COLOUR, TYPEFACE, SHADOW OR RADIUS IS NAMED IN THIS FILE. Every
    value a designer would change reads a custom property, and the host's theme
    sheet — loaded AFTER this one, see Components/App.razor — sets them. That is
    the whole mechanism by which two products' order sites look like two products.

    ⚠ The :root block is the TOKEN CONTRACT and an unbranded fallback, so a new
    host renders legibly before anyone has drawn it. It is not a design. If a page
    looks like this in production, the host forgot its stylesheet.

    ⚠ Adding a rule that names #hex, a font family, a px radius or a shadow does
    not fail the build — it just quietly makes the next product look like this
    one. Add a token instead.                                                     */
:root {
    /*  Native UA chrome — select popups, caret, scrollbars, autofill — follows the
        theme instead of always painting light. A theme that adds a dark palette
        sets the dark counterpart alongside it; both must move together. */
    color-scheme: light;

    /* --- Ink and ground ------------------------------------------------- */
    --ink: #1d1f20;
    --ink-soft: #5d5d60;
    --ground: #f4f4f5;
    --sheet: #ffffff;
    --rule: #d9d9dc;

    /*  The canvas behind the cards. A theme that wants a plain ground leaves
        these alone; one with a paper texture sets both. */
    --canvas-image: none;
    --canvas-size: auto;

    /*  Chrome — the header band. A gradient token rather than a colour, because
        a flat fill is expressible as one and the reverse is not. */
    --chrome-bg: var(--sheet);
    --chrome-border: var(--rule);

    /* --- The one action colour, and what is legible on it ---------------- */
    --accent: #35618f;
    --accent-deep: #274a6d;
    --accent-wash: rgba(53, 97, 143, 0.08);
    --on-accent: #ffffff;

    /*  Status — meaning, not brand. A theme may retune these; it may not
        repurpose them, because a customer reads red as "this went wrong"
        whatever we do. */
    --ok: #2f6b52;
    --warn: #8a6d33;
    --bad: #8f4f43;
    --warn-wash: #f9f3e6;
    --bad-wash: #f9ebe8;

    /* --- Type ------------------------------------------------------------ */
    --font-body: system-ui, "Segoe UI", sans-serif;
    --font-heading: var(--font-body);
    --font-mono: ui-monospace, Consolas, monospace;

    /*  A scale, not a pile of magic numbers. Micro is the uppercase label;
        title is the page heading. */
    --fs-micro: 0.6875rem;
    --fs-small: 0.8125rem;
    --fs-body: 1rem;
    --fs-card-title: 0.9375rem;
    --fs-title: 1.375rem;

    --heading-weight: 700;
    --heading-tracking: normal;

    /*  How a micro-label is set — the eyebrow over a field, a pill, a table
        head. Some systems shout these in caps; some do not. */
    --micro-weight: 600;
    --micro-transform: none;
    --micro-tracking: normal;

    /* --- Shape and elevation --------------------------------------------- */
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-pill: 10px;
    --shadow-card: none;
    --focus-ring: 0 0 0 3px var(--accent-wash);

    /*  Artwork behind the checkout. No picture unless a host supplies one. */
    --page-backdrop: none;
    --page-backdrop-opacity: 0.16;
    --page-backdrop-filter: none;

    /*  Control geometry. One height for every button and field, so a row of
        them lines up without per-component nudging. */
    --control-height: 38px;
    --control-padding: 0 14px;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--font-body);
    font-size: var(--fs-body);
    color: var(--ink);
    background-color: var(--ground);
    background-image: var(--canvas-image);
    background-size: var(--canvas-size);
    line-height: 1.5;
}

main { max-width: 1040px; margin: 0 auto; padding: 24px 20px 80px; }

h1, h2, h3 {
    font-family: var(--font-heading);
    font-weight: var(--heading-weight);
    letter-spacing: var(--heading-tracking);
}
h1 { font-size: var(--fs-title); line-height: 1.2; margin: 0.6em 0 0.4em; }
h2 { font-size: var(--fs-title); margin: 1.6em 0 0.5em; }
h3 { font-size: var(--fs-card-title); }
a { color: var(--accent); }

/* --- Chrome ------------------------------------------------------------- */
.site-header {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0 16px; height: 52px;
    background: var(--chrome-bg);
    border-bottom: 1px solid var(--chrome-border);
}
.site-header .brand { font-weight: 700; text-decoration: none; color: var(--ink); letter-spacing: var(--heading-tracking); }
.site-header nav { display: flex; gap: 18px; align-items: center; }
.site-header nav a:not(.btn) { font-size: var(--fs-small); text-decoration: none; }
.site-footer {
    display: flex; gap: 20px; justify-content: space-between; flex-wrap: wrap;
    padding: 18px 20px; border-top: 1px solid var(--rule);
    color: var(--ink-soft); font-size: var(--fs-small);
}

/* --- Controls ----------------------------------------------------------- */
/*  Height and inline-flex rather than padding alone: a button and a field in the
    same row have to agree on a baseline, and padding-sized controls never do. */
.btn {
    display: inline-flex; align-items: center; gap: 7px;
    height: var(--control-height); padding: var(--control-padding);
    border: 1px solid var(--rule); border-radius: var(--radius-sm);
    background: var(--sheet); color: var(--ink);
    font-family: inherit; font-size: var(--fs-small); font-weight: 600;
    text-decoration: none; white-space: nowrap; cursor: pointer;
    transition: background 0.12s, border-color 0.12s, box-shadow 0.12s;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); color: var(--on-accent); }
.btn-small { height: 32px; padding: 0 12px; font-size: var(--fs-small); }
.btn:disabled { opacity: 0.6; cursor: default; }
.btn:focus-visible, .order-form input:focus-visible, .invoice-actions input:focus-visible {
    outline: none; border-color: var(--accent); box-shadow: var(--focus-ring);
}
button.link {
    background: none; border: none; color: var(--accent); cursor: pointer;
    padding: 0; font-size: inherit; text-decoration: underline;
}

/* --- Small print and pills ----------------------------------------------- */
.fine { color: var(--ink-soft); font-size: var(--fs-small); }

.pill {
    display: inline-block; padding: 2px 8px;
    border: 1px solid var(--rule); border-radius: var(--radius-pill);
    color: var(--ink-soft);
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
}

/* --- Checkout ----------------------------------------------------------- */
/*  ⚠ GRID, NOT FLEX, AND THAT IS THE WHOLE TRICK. The three things wanted here —
    the form takes the slack, the summary drops below at a threshold, and it goes
    full width once it does — are one property each in grid and are not expressible
    in flex without fighting it: `flex-wrap` decides the drop point from content
    rather than from a threshold, and a wrapped flex item only fills its row if it
    is allowed to grow, which is the opposite of what it must do while beside the
    form.

    The summary column is a FIXED 250px and the form is minmax(0, 1fr), so every
    pixel the page gains goes to the form and none to the running total. At the
    1000px content width that is a 726px form. `minmax(0, …)` rather than plain
    `1fr` so a long unbroken string in the form cannot push the column wider than
    its share. */
.order-grid {
    display: grid;
    gap: 24px;
    grid-template-columns: minmax(0, 1fr) 250px;
    align-items: start;
}

/*  Below this the two columns stop being worth it: the form is down to ~430px
    beside a 250px total, which is barely a phone's width of form on a screen
    twice that. The summary is a running total, not a second column of work —
    below the form it reads fine, squeezed beside it neither one does.

    ⚠ Both children are then the only item in their row, so each is full width
    automatically. Nothing here needs to say 100%; saying it would be a second
    place for the layout to disagree with itself. */
@media (max-width: 1000px) { .order-grid { grid-template-columns: 1fr; } }

/*  ⚠ THE CHECKOUT OPTS INTO A WIDER SHELL THAN THE REST OF THE SITE. `main` is
    capped at 1040px because that is a comfortable measure for READING; this page
    is a form, and the form was asked to run to 1250px. `:has()` scopes the wider
    cap to the page that needs it without threading a class down from MainLayout,
    which would put a checkout detail into the shared chrome.

    The arithmetic, so the two numbers stay honest about each other:
        1250 form + 24 gap + 250 summary + 40 main padding = 1564.
    Change the form's max and this has to move with it, or the column can never
    reach the width the rule below claims for it. */
main:has(.order-grid) { max-width: 1564px; }
.order-form { max-width: 1250px; }
.order-form {
    display: flex; flex-direction: column; gap: 16px;
    background: var(--sheet); border: 1px solid var(--rule);
    border-radius: var(--radius-md); box-shadow: var(--shadow-card); padding: 20px;
}
/*  The field label is the system's micro-label: the theme decides whether that
    means small caps with tracking or ordinary bold text. */
.order-form label {
    display: flex; flex-direction: column; gap: 4px;
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
    color: var(--ink-soft);
}
.order-form input[type=text], .order-form input:not([type]), .order-form input[type=email] {
    height: var(--control-height); padding: 0 10px;
    border: 1px solid var(--rule); border-radius: var(--radius-sm);
    background: var(--sheet); color: var(--ink);
    font-family: inherit; font-size: var(--fs-small);
    text-transform: none; letter-spacing: normal;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.order-form fieldset { border: 1px solid var(--rule); border-radius: var(--radius-md); padding: 10px 14px; }
.order-form legend {
    padding: 0 6px;
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
    color: var(--ink-soft);
}
/*  A radio row is prose, not a label — it must not inherit the micro treatment. */
/*  ⚠⚠ A BLOCK, NOT A FLEX ROW, AND THE REASON IS SUBTLE ENOUGH TO BE WORTH
    SPELLING OUT. A flex container turns every child into a flex item — including
    each BARE TEXT RUN between inline tags. So

        Annual — <b>$199/mo</b>, billed yearly at <b>$2,388</b>

    became five independent items sitting side by side, each wrapping inside its
    own column. Above ~470px there is room and it looks like a sentence; below it
    the columns wrap and the sentence comes apart on screen — the price rendering
    ABOVE the words that introduce it. It is not a wrapping-balance problem, it is
    five paragraphs pretending to be one.

    So the label is a block and its text is one ordinary inline flow, which wraps
    the way a sentence should. The control is lifted out of that flow and parked in
    the padding, which also buys the hanging indent flex was giving us: a wrapped
    second line stays clear of the radio instead of running under it.

    ⚠ The !importants are load-bearing: .order-form label sets the uppercase
    micro-label treatment, and a radio row is prose, not a label. */
.choice {
    /*  ⚠ !important because `.order-form label` (0,1,1) sets `display: flex;
        flex-direction: column` and outranks a bare `.choice` (0,1,0). Without this
        the label is STILL a flex container — just stacking instead of spreading, so
        every row breaks after its bold run. The four below are the same fight over
        the uppercase micro-label treatment. */
    display: block !important;
    position: relative;
    padding: 3px 0 3px 24px;
    font-size: var(--fs-body) !important;
    font-weight: 400 !important;
    text-transform: none !important;
    letter-spacing: normal !important;
    color: var(--ink) !important;
}

/*  Centred on the FIRST line rather than on the label, so a row that wraps to two
    lines keeps its control beside the line it belongs to. */
.choice > input { position: absolute; left: 8px; top: 0.62em; margin: 0; }

/*  THE ROW THE CUSTOMER PICKED SHOULD LOOK PICKED.

    A checkout whose only feedback is a 13px platform dot asks people to audit their
    own order from the summary panel. The row itself now carries the state.

    ⚠ accent-color, not a hand-drawn control. `appearance: none` plus a styled box is
    how a radio loses its platform behaviour — the arrow keys that move within a group,
    the Windows high-contrast treatment, the way a screen reader announces it. This
    recolours the real control and leaves all of that alone. */
.choice, .consent { --choice-hit: 34px; }
.choice > input, .consent > input { accent-color: var(--accent); width: 16px; height: 16px; }
.choice {
    padding: 7px 10px 7px var(--choice-hit) !important;
    border-radius: var(--radius);
    border: 1px solid transparent;
}
.choice:hover:not(:has(> input:disabled)) { background: var(--accent-wash); }
.choice:has(> input:checked) { background: var(--accent-wash); border-color: var(--accent); }

/*  A row that is checked because it is INCLUDED, not because anyone chose it — the
    always-on module, the free one. Same wash would tell the customer they had made a
    decision they cannot make; the eye should go to the rows that are still open. */
.choice:has(> input:disabled) { background: none; border-color: transparent; opacity: 0.75; }
/*  The row, not the 16px control, carries the focus ring: focus-within means Tab
    lands somewhere the eye can find at arm's length. */
.choice:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }

/*  The renewal-consent box. Same construction as .choice — prose with the control
    parked in the padding — and the same !important fight with the micro-label
    treatment. ⚠ Body-sized and full ink, not fine print: it is the one thing on the
    page the customer must actively do, and it must not read as a footnote. */
.consent {
    display: block !important;
    position: relative;
    margin-top: 10px;
    padding: 3px 0 3px 26px;
    font-size: var(--fs-body) !important;
    font-weight: 600 !important;
    text-transform: none !important;
    letter-spacing: normal !important;
    color: var(--ink) !important;
}
.consent > input { position: absolute; left: 0; top: 0.3em; margin: 0; width: 16px; height: 16px; }
@media (pointer: coarse) {
    /* A 16px box is a miss on a phone; the whole label is the target, but the box
       itself should still be easy to see and hit. */
    .consent { padding-left: 32px; }
    .consent > input { width: 22px; height: 22px; top: 0.1em; }
}
.hint { color: var(--ink-soft); font-size: var(--fs-small); font-weight: 400; text-transform: none; letter-spacing: normal; }
.field-error { color: var(--bad); font-size: var(--fs-small); font-weight: 400; text-transform: none; letter-spacing: normal; }
.derived-host {
    background: var(--ground); border: 1px solid var(--rule); border-radius: var(--radius-sm);
    padding: 8px 12px; margin: 0; font-family: var(--font-mono); font-size: var(--fs-small);
}

.order-summary {
    background: var(--sheet); border: 1px solid var(--rule);
    border-radius: var(--radius-md); box-shadow: var(--shadow-card);
    padding: 16px 20px;
}
.order-summary dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 0; font-size: var(--fs-small); }
.order-summary dt { color: var(--ink-soft); }
.order-summary dd { margin: 0; }
.order-summary .total { font-size: var(--fs-title); font-weight: 700; font-variant-numeric: tabular-nums; }

/* --- States ------------------------------------------------------------- */
.banner { border-radius: var(--radius-md); padding: 12px 16px; border: 1px solid var(--rule); font-size: var(--fs-small); }
.banner p { margin: 0 0 6px; }
.banner p:last-child { margin: 0; }
.banner-warn { border-left: 4px solid var(--warn); background: var(--warn-wash); }
.banner-error { border-left: 4px solid var(--bad); background: var(--bad-wash); }

.status-card {
    background: var(--sheet); border: 1px solid var(--rule); border-left-width: 5px;
    border-radius: var(--radius-md); box-shadow: var(--shadow-card);
    padding: 20px; max-width: 640px;
}
.status-card dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; font-size: var(--fs-small); }
.status-card dd { margin: 0; }
.status-active { border-left-color: var(--ok); }
.status-rejected, .status-failed { border-left-color: var(--bad); }
.status-provisioning { border-left-color: var(--accent); }

/* --- Tables and readouts ------------------------------------------------ */
.tbl {
    width: 100%; border-collapse: collapse;
    background: var(--sheet); border: 1px solid var(--rule);
    font-size: var(--fs-small);
}
.tbl th, .tbl td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--rule); }
.tbl th {
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
    color: var(--ink-soft); background: var(--ground);
}
/*  On a phone the desk's tables are wider than the screen. They scroll inside
    themselves, as the legal pages' tables do, instead of pushing the whole page
    sideways (found 15 Sep 2026: /desk was 588px wide in a 538px viewport). On a
    wider screen they stay full-width tables. */
@media (max-width: 720px) {
    .tbl { display: block; overflow-x: auto; max-width: 100%; }
}
/*  Tabular numerals: a column of money whose digits shift width as it updates
    reads as a bug in the money, not in the font. */
.mono { font-family: var(--font-mono); font-size: var(--fs-small); font-variant-numeric: tabular-nums; }
.events { margin: 4px 0; padding-left: 18px; font-size: var(--fs-small); }

/*  The Stripe iframe's own box. Matched to a field so the card sits IN the form
    rather than on it. The min-height is Stripe's, not a choice. */
.card-element {
    border: 1px solid var(--rule); border-radius: var(--radius-sm);
    padding: 12px; background: var(--sheet); min-height: 48px;
}

.invoice-actions { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; padding: 8px 0; }
.invoice-actions label {
    display: flex; flex-direction: column; gap: 3px;
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
    color: var(--ink-soft);
}
.invoice-actions input {
    height: var(--control-height); padding: 0 8px;
    border: 1px solid var(--rule); border-radius: var(--radius-sm);
    font-family: inherit; font-size: var(--fs-small);
}
.pill-overdue { border-color: var(--bad); color: var(--bad); font-weight: 700; }

/* --- Theme toggle -------------------------------------------------------- */
/*  A square control at the end of the header. Square because it holds a glyph,
    not a word — its label is present but visually hidden, and screen-reader-only
    text in a pill-shaped button pushes the header layout around for nobody. */
.theme-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: var(--control-height); height: var(--control-height); padding: 0;
    border: 1px solid var(--rule); border-radius: var(--radius-sm);
    background: var(--sheet); color: var(--ink-soft);
    font-family: inherit; font-size: var(--fs-small); line-height: 1;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s, box-shadow 0.12s;
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent); }
.theme-toggle:focus-visible { outline: none; border-color: var(--accent); box-shadow: var(--focus-ring); }

/*  The glyph is CSS, not markup, so it cannot fall out of step with the theme
    when Blazor re-renders the header. A moon offers the dark theme; a sun offers
    the way back. Text characters rather than SVG: they inherit colour, and there
    is no icon set in this library to be consistent with. */
.theme-toggle__icon::before { content: "\263E"; font-size: 15px; }          /* ☾ */
:root[data-theme="dark"] .theme-toggle__icon::before { content: "\2600"; }  /* ☀ */

/*  Clipped, not `display: none` — a hidden label is still the button's accessible
    name, and display:none would remove it from the tree along with the name. */
.theme-toggle__label {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
/*  ⚠ Exactly one label is in the tree at a time, and THIS is the display:none
    that is meant to remove one — the announced name must be the action the button
    will perform, never both actions read one after the other. */
.theme-toggle__label[data-when="dark"] { display: none; }
:root[data-theme="dark"] .theme-toggle__label[data-when="light"] { display: none; }
:root[data-theme="dark"] .theme-toggle__label[data-when="dark"] { display: inline; }

/* ========================================================================== */
/*  PAGE SHAPES — the section rhythm the terms, the legal pages and the       */
/*  not-found page share.                                                     */
/*                                                                            */
/*  The storefront that used to live here — hero, product shots, feature      */
/*  rows, plans, module cards, the lightbox — moved to the company site with  */
/*  the pages that used it, on 15 Oct 2026 (DiscoverySystemsWeb, Software).   */
/* ========================================================================== */

/* --- Section rhythm ------------------------------------------------------ */
/*  Text for a screen reader and nobody else — a table's caption, a heading that
    would be noise on screen. Clip rather than display:none, which would take it out
    of the accessibility tree along with the pixels. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/*  The first thing Tab reaches, and invisible until it does. A keyboard visitor
    would otherwise walk the whole header on every page to reach the content. */
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  padding: 10px 16px; border-radius: var(--radius); border: 1px solid var(--rule);
  background: var(--sheet); color: var(--ink); text-decoration: none;
  transition: top 120ms ease-out;
}
.skip-link:focus { top: 12px; }
main:focus { outline: none; }

.band { padding: 56px 0; }
.band + .band { border-top: 1px solid var(--rule); }
.band__head { max-width: 640px; margin-bottom: 28px; }
.band__head h2 { margin-top: 0; }
.band__head p { color: var(--ink-soft); margin: 0; }

/*  The eyebrow over a section title — the same micro-label the rest of the
    system uses, so a section head and a field label are visibly one family. */
.eyebrow {
    display: block; margin: 0 0 6px;
    color: var(--accent);
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
}

/*  A row of buttons — the not-found page's way out. */
.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }

/* --- Pages that open on a section head ------------------------------------- */
/*  The head carries the h1, so it loses the top margin a following-band h2 would want. */
.band--lead { padding-top: 32px; }
.band--lead .band__head h1 { margin: 0 0 8px; }

/*  The way back to the index, above a legal document's title. Quiet on purpose — it is
    for the visitor who wants it. */
.crumb {
    display: inline-block; margin-bottom: 14px;
    color: var(--ink-soft); font-size: var(--fs-small); text-decoration: none;
}
.crumb::before { content: "\2190\00a0"; }          /* ← */
.crumb:hover { color: var(--accent); }

/*  The header's links again, in the footer — on a phone, the only copy of them. */
.site-footer nav { display: flex; gap: 16px; flex-wrap: wrap; }
.site-footer nav a { color: var(--ink-soft); text-decoration: none; }
.site-footer nav a:hover { color: var(--accent); }

/* --- Legal pages ------------------------------------------------------------ */
/*  Set for reading, not scanning: a measure a person can follow line to line, and
    body-coloured text rather than the storefront's softer grey, because every word
    here is one a customer may be held to. */
.legal { max-width: 70ch; padding-block: 24px 8px; }
.legal h1 { margin: 0 0 4px; }
.legal h2 { font-size: var(--fs-card-title); margin: 30px 0 8px; }
.legal p, .legal li { color: var(--ink); }
.legal ul { padding-left: 20px; }
.legal li { margin: 4px 0; }
.legal .banner { margin: 18px 0 8px; }

/*  A rendered legal document (LegalDocumentPage). Clause numbers live in the text
    ("3.1 **Terms of Sale.**"), so paragraphs stay plain paragraphs — the numbering is
    the lawyer's, not the stylesheet's. */
.legal-doc h2 { font-size: var(--fs-card-title); margin: 34px 0 10px; }
.legal-doc h3 { font-size: var(--fs-body); margin: 22px 0 6px; }
.legal-doc p { margin: 0 0 12px; }
.legal-doc hr { border: 0; border-top: 1px solid var(--rule); margin: 26px 0; }
.legal-doc em { color: var(--ink-soft); }
.legal-doc table {
    display: block; overflow-x: auto; max-width: 100%;
    border-collapse: collapse; font-size: var(--fs-small); margin: 8px 0 16px;
}
.legal-doc th, .legal-doc td {
    text-align: left; vertical-align: top;
    padding: 8px 10px; border-bottom: 1px solid var(--rule);
}
.legal-doc th {
    font-size: var(--fs-micro); font-weight: var(--micro-weight);
    text-transform: var(--micro-transform); letter-spacing: var(--micro-tracking);
    color: var(--ink-soft); white-space: nowrap;
}
.legal .crumb { margin-bottom: 10px; }

.legal-list { list-style: none; padding: 0; margin: 18px 0 0; display: flex; flex-direction: column; }
.legal-list li { display: flex; flex-direction: column; gap: 2px; padding: 12px 0; border-top: 1px solid var(--rule); }
.legal-list li:last-child { border-bottom: 1px solid var(--rule); }
.legal-list a { font-weight: 600; }
.legal-list span { color: var(--ink-soft); font-size: var(--fs-small); }

/*  A fact the business has not supplied. ⚠ Meant to be impossible to miss, on screen
    and in a proof-read — see Fact.razor. Never style it down. */
.tbc {
    background: var(--warn-wash); color: var(--warn);
    border: 1px dashed var(--warn); border-radius: 4px;
    padding: 0 4px; font-weight: 600;
}

/* ========================================================================== */
/*  SMALL SCREENS AND TOUCH                                                   */
/*                                                                            */
/*  ⚠ TWO SEPARATE CONCERNS, TWO SEPARATE QUERIES, DELIBERATELY.              */
/*    `max-width` is about LAYOUT — how much room there is.                   */
/*    `pointer: coarse` is about THE HAND — how accurately it can be hit.     */
/*  A 600px-wide desktop window is narrow but not touched; a tablet is wide   */
/*  but is. Collapsing both into one breakpoint gets one of them wrong.       */
/*                                                                            */
/*  ⚠ All of this is STRUCTURE, not brand. A 44px touch target and iOS's      */
/*  16px zoom threshold are platform facts — the next product inherits them   */
/*  whether or not anyone remembers to ask.                                   */
/* ========================================================================== */

@media (max-width: 640px) {
    main { padding: 16px 16px 56px; }

    /*  The header stops being a fixed 52px band and becomes a box that fits its
        contents. It was clipping: the brand had been squeezed to 78px and wrapped
        onto three lines inside a 52px header. */
    .site-header { height: auto; min-height: 56px; padding: 10px 14px; gap: 10px; }
    .site-header .brand { white-space: nowrap; flex: 0 0 auto; }
    .site-header nav { gap: 10px; flex: 0 1 auto; }
    /*  The section links go to the company site, and the footer repeats them, so
        losing them here costs the visitor nothing and buys the brand its room. The
        call to action is a .btn and stays. */
    .site-header nav a:not(.btn) { display: none; }

    /* Vertical rhythm: desktop's air is a very long scroll on a phone. */
    .band { padding: 32px 0; }
    .band__head { margin-bottom: 20px; }

    .hero__actions .btn { flex: 1 1 auto; justify-content: center; }

    .order-grid { gap: 18px; }
    .order-form { padding: 16px; gap: 14px; }

}

/*  --- The hand, not the screen ------------------------------------------- */
@media (pointer: coarse) {
    /*  ⚠ min-height, NOT height — so it raises the theme's density without
        fighting it. A theme is free to set --control-height to 32px for the
        desk; it is not free to make a 32px tap target on a phone, and this is
        where that is decided rather than left to each host to remember. */
    .btn, .theme-toggle, button.link,
    .order-form input[type=text], .order-form input:not([type]), .order-form input[type=email],
    .invoice-actions input { min-height: 44px; }

    /* The toggle is square: raising only its height would make it a tall sliver. */
    .theme-toggle { min-width: 44px; }

    /*  ⚠⚠ 16px IS NOT A DESIGN CHOICE, IT IS THE iOS THRESHOLD. Safari zooms the
        whole page in when a focused field's text is smaller than 16px, and it
        does not zoom back out — so a 13px field on a checkout leaves the customer
        entering their card into a page they now have to pan sideways to read.
        The rest of the type scale is untouched; this is the fields only. */
    .order-form input[type=text], .order-form input:not([type]), .order-form input[type=email],
    .invoice-actions input { font-size: 16px; }

    /*  Field labels stop being micro-type. 11px uppercase is a desk affordance —
        on a phone, at arm's length, over a form that takes payment details, it is
        the wrong place to be economical with legibility. */
    .order-form label, .order-form legend { font-size: var(--fs-small); }
}

/*  ⚠ Blazor's FocusOnNavigate moves focus to each page's h1 on every navigation,
    which is right for a screen reader and wrong on screen: the browser then paints
    its focus ring around the heading of every page the visitor lands on.

    Suppressing it here is safe precisely because tabindex="-1" means the element
    is reachable ONLY programmatically — never by keyboard — so no real keyboard
    focus indicator is being hidden from anyone. Do not widen this selector to
    :focus generally; on an actual control that would be an accessibility defect. */
[tabindex="-1"]:focus { outline: none; }

/*  The comparison line under the summary's charge. Block so it sits beneath the
    figure rather than trailing it at title size, and it resets the weight the
    .total rule sets — a comparison must not read as loud as the amount. */
.order-summary .total .hint { display: block; margin-top: 3px; font-weight: 400; }

/*  ── The page backdrop ────────────────────────────────────────────────────
    Artwork behind the checkout, the one page here that is shopfront rather than
    utility (the storefront it shared this with moved to the company site, 15 Oct
    2026). The order tracker, the subscription manager and the operator desk are
    places people go to get something done, and a picture behind those is noise.

    ⚠⚠ `isolation: isolate` IS LOAD-BEARING, NOT TIDINESS. The layer sits at
    z-index -1 so it paints under the content. Without an isolating ancestor
    that puts it behind the BODY's background too — the ground colour and the
    drafting grid — and it vanishes completely, with no error and nothing in the
    inspector to suggest why. Isolating main confines the -1 to main's own
    stacking context.

    ⚠ position: fixed, not background-attachment: fixed. These pages run to
    thousands of pixels; a backdrop that scrolls with them is off screen for most
    of the page, and one stretched to cover that height is unrecognisable.

    ⚠ FULL VIEWPORT, AND `cover`. It is deliberately NOT bounded by main's
    max-width or padding — a backdrop that stops where the text column stops
    reads as a panel behind the content rather than as the ground it is standing
    on. `inset: 0` takes the layer off the document flow and onto the viewport,
    so main's measure has no say in it. Nothing here may gain a transform,
    filter or `will-change`: any of those on this ELEMENT's ancestors would make
    them the containing block and re-introduce exactly the clipping this avoids.

    ⚠ It must never compete with the page. The checkout is somewhere people type
    payment details — the artwork is atmosphere, and the opacity token is the
    dial that keeps it there. */
main:has(.order-grid) { position: relative; isolation: isolate; }

main:has(.order-grid)::before {
    content: "";
    position: fixed;
    inset: 0;
    background: var(--page-backdrop) no-repeat center center / cover;
    opacity: var(--page-backdrop-opacity);
    /*  Artwork drawn for one theme rarely suits the other. A light-on-dark plate
        inverts cleanly to dark-on-light, which is cheaper and stays in step than
        maintaining two exports of the same drawing. */
    filter: var(--page-backdrop-filter);
    pointer-events: none;
    z-index: -1;
}
