/* =============================================
   Framework
   ---------------------------------------------
   Component + utility layer. Depends on a theme stylesheet (e.g.
   theme-04-brightside.css) for colour tokens. Theme MUST be linked first.

   Four tokens are newer than the older themes in this directory —
   --color-focus, --color-outline-strong and the --color-surface-inset
   pair — so every reference to them carries a fallback. A theme that
   does not define them still renders; one that does gets the intended
   value. Do not drop the fallbacks without checking every theme file.

   This layer is derived from the Brightside Voices prototype stylesheet,
   and four decisions in it explain nearly every rule below:

   1. THE PAGE IS WARM, THE PANELS ARE WHITE. The ground is cream
      (#faf8f2). That is what lets a card separate with a hairline and a
      2%-black shadow instead of a heavy one — on a white page the same
      card would need real elevation to be visible at all.

   2. SERIF FOR FIGURES AND TITLES, SANS FOR EVERYTHING ELSE. Georgia
      carries the page title, the big numbers on the stat tiles, and the
      pull quote. Nothing else. A serif heading over sans body is the
      product's voice; a serif label inside a form is a costume.

      The wordmark is set in neither, because it is not type on this page
      at all — it is part of the supplied logo image. Which is why nothing
      here loads a webfont: every character the browser draws is either the
      platform UI face or Georgia, and both are already on the machine.

   3. ONE ACTION COLOUR. Emphasis is FILL vs OUTLINE — a solid blue button
      against a white-and-hairline one — never a second hue. This is why
      there are no coloured category tiles and no per-section accents.

   4. FOCUS IS GOLD AND ALWAYS VISIBLE. 3px, offset 3px, on every control.
      It is the one place the design spends a colour no component may
      otherwise use, because a focus ring that matches the action colour
      disappears exactly where it is needed.

   Sizes are not arbitrary either: controls are 47px tall, cards are padded
   30px, and body text is 16px/1.6. Pick from the tokens rather than
   inventing a value — a 40px control next to a 47px one is the fastest
   way to make a careful page look assembled from parts.
   ============================================= */


/* =============================================
   Non-colour tokens
   ============================================= */
:root {
    /* No webfont. The reference design uses the system UI stack for body
       copy and Georgia for display, both of which every target platform
       already has — which also removes a render-blocking request to a
       third-party font host from every page load. */
    /* Both stacks are the reference stylesheet's, character for character.
       They had picked up extra fallbacks (Roboto/Helvetica/Arial on the
       body, Iowan Old Style/Times New Roman on the display face) which look
       harmless and are not: they change which font a machine actually
       resolves. A box without Georgia used to land on Times New Roman —
       which fontconfig aliases to Liberation Serif, a Times clone with
       LINING figures — where the reference lands on the platform's generic
       serif. Different letterforms, different numerals, same CSS intent.
       Do not extend these stacks. */
    --font-body:    -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --font-display: Georgia, serif;
    --font-mono:    ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

    /* Four radii, each with a job. They step DOWN as the thing gets
       smaller and more interactive: a card is soft, a button less so, an
       input least — except the badge, which is a pill because it is a
       label rather than a surface. */
    --radius:         12px;   /* cards, modals */
    --radius-panel:    9px;   /* stat tiles, panels inset in a card */
    --radius-control:  7px;   /* buttons, tabs */
    --radius-input:    6px;   /* inputs, selects, textareas */
    --radius-pill:    30px;   /* badges */

    /* The reading column. ONE width and ONE gutter, shared by the header,
       the content and the footer — so the mark, the page title and the
       copyright all sit on a single left edge down the whole page. (The
       reference gives its header a wider box and a bigger gutter, which
       works there because its logo is an image with its own internal
       margin; with a mark-plus-wordmark lockup the 28px difference reads
       as a mistake.) */
    --shell-max: 1130px;
    --shell-pad:   28px;

    --control-h: 47px;        /* inputs, selects and full-size buttons */

    --focus-width:  3px;
    --focus-offset: 3px;

    /* Elevation, in three steps and used sparingly. --shadow-card is
       deliberately almost nothing: the hairline does the work. */
    --shadow-card: 0 5px 25px rgba(var(--shadow-tint, 36, 60, 75), 0.02);
    --shadow-pop:  0 6px 35px rgba(var(--shadow-tint, 36, 60, 75), 0.19);
    --shadow-deep: 0 14px 50px rgba(var(--shadow-tint, 36, 60, 75), 0.26);
}


/* =============================================
   Reset + Base
   ============================================= */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html, body {
    margin: 0;
    padding: 0;
}

/* The HTML `hidden` attribute is the standards-compliant way to hide an
   element, but our component CSS sets explicit `display:` values that win
   over the user-agent default. Restore the intended semantics globally so
   `<button hidden>` actually hides — otherwise every component that uses
   the attribute has to ship its own toggle class. */
[hidden] { display: none !important; }

/* NO font-smoothing overrides here, deliberately.

   ``-webkit-font-smoothing: antialiased`` (with its Firefox counterpart
   ``-moz-osx-font-smoothing: grayscale``) switches macOS from subpixel
   rendering to greyscale, which STRIPS WEIGHT from every glyph on the
   page. It is widely pasted into resets as a polish step; what it
   actually does is make body copy thinner and less legible, and the
   effect is strongest exactly where it hurts most — small text like the
   12px label under a stat figure.

   The reference stylesheet does not touch font smoothing, so neither does
   this one: the same stack rendered two different ways is the same font
   and a visibly different page. Do not add it back. */
body {
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    color: var(--color-on-background);
    background: var(--color-background);
}

input, textarea, select, button { font: inherit; color: inherit; }

img { max-width: 100%; }

::selection {
    background: var(--color-primary-150, var(--color-primary-200));
    color: var(--color-primary-800);
}


/* =============================================
   Focus
   ---------------------------------------------
   One rule, applied everywhere, in a colour nothing else may use. On
   inputs and selects it is bound to :focus rather than :focus-visible
   deliberately — a text field that has the caret is focused whether you
   arrived by keyboard or by click, and the ring is the only thing saying
   so once the caret stops blinking.
   ============================================= */
input:focus,
select:focus,
textarea:focus,
button:focus-visible,
a:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
    outline: var(--focus-width) solid var(--color-focus, var(--color-warning-600));
    outline-offset: var(--focus-offset);
}

/* Visible to a screen reader, to nobody else. For the text a control needs
   in order to be announced but the sighted layout already makes obvious — a
   table's actions column, an icon-only button.

   Not display:none and not visibility:hidden: both remove the element from
   the accessibility tree as well, which is the opposite of the point. This is
   the standard clip-rect technique, which leaves it readable and unpainted. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}


/* Skip link — parked off-screen until it takes focus. */
.skip {
    position: absolute;
    top: -70px;
    left: 0;
    z-index: 100;
    background: var(--color-surface);
    padding: 10px 16px;
}
.skip:focus { top: 0; }


/* =============================================
   Typography
   ---------------------------------------------
   Element defaults first, so an <h2> dropped into a card is already
   right, then utilities for the cases that need to opt out.

     Display (Georgia, weight 400 — a serif at 400 is already
     emphatic; bolding it makes it shout):
       h1 / .text-display   46px  the largest title on a page
       .page-title          38px  in-app screen title
       .layout__aside h1    35px  the title beside a form
       .stat strong         36px  a figure

     Body (system sans):
       h2 / .section-title  23px
       h3                   16px, weight 700
       .text-body-lg        17px
       (default)            16px
       .text-body-sm        14px
       .text-caption        13px
       .text-micro          12px
   ============================================= */
h1, h2, h3, h4, p { margin-top: 0; }

h1, .text-display {
    font-family: var(--font-display);
    font-size: 46px;
    line-height: 1.14;
    font-weight: 400;
    letter-spacing: -1.3px;
    margin-bottom: 22px;
    color: var(--color-on-surface);
}
/* Weight and margin are stated rather than inherited from the user agent,
   but the VALUES are the UA's — 700 and 0.83em/1em — because that is what
   the reference leaves in place by declaring neither. Stating them means
   ``.section-title`` on a <div> renders identically to an <h2>. */
h2, .section-title {
    font-size: 23px;
    line-height: 1.3;
    font-weight: 700;
    margin-bottom: 0.83em;
    color: var(--color-on-surface);
}
h3 {
    font-size: 16px;
    font-weight: 700;
    margin-bottom: 1em;
}
p { margin-bottom: 20px; }

.text-body-lg { font-size: 17px; line-height: 1.8; }
.text-body    { font-size: 16px; }
.text-body-sm { font-size: 14px; }
.text-caption { font-size: 13px; }

small, .muted, .text-muted { color: var(--color-on-surface-variant); }
.text-primary      { color: var(--color-primary); }
.text-warning-tone { color: var(--color-warning-700); }
.text-italic       { font-style: italic; }
.text-medium       { font-weight: 500; }
.text-semibold     { font-weight: 600; }
.text-bold         { font-weight: 700; }

/* Eyebrow — the small tracked-out blue line above a title. It names the
   AREA you are in ("PANEL CENTRAL · ADMIN"); the title below it names the
   screen. Weight 750 is not a typo: at 11px with 2px of tracking, 700
   looks thin and 800 closes up the counters. */
.eyebrow {
    font-size: 11px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--color-primary);
    font-weight: 750;
    margin-bottom: 20px;
}

/* Section label — the divider WITH a name on it, between groups of fields
   inside one card. The rule above it is the component; the text is the
   caption for what follows. */
/* Capitals and tracking, but body weight and full-strength ink — the
   rule above it is what separates the groups, so the label does not also
   have to be bold to be found. */
.section-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.6px;
    border-top: 1px solid var(--color-outline-variant);
    padding-top: 24px;
    margin: 28px 0 20px;
}
.section-label:first-child { border-top: 0; padding-top: 0; margin-top: 0; }

/* Fixed-format identifiers (an order number, a short code) in a mono face
   so they line up down a column. ``nowrap`` keeps them on one line — they
   are inherently short, and an id broken mid-token is never the intended
   rendering. */
.id-mono {
    font-family: var(--font-mono);
    font-size: 0.92em;
    letter-spacing: 0.01em;
    white-space: nowrap;
}


/* =============================================
   Prose — for content-heavy pages (docs, help)
   ============================================= */
.prose {
    max-width: 68ch;
    font-size: 17px;
    line-height: 1.8;
    color: var(--color-on-surface);
}
.prose h2 { margin-top: 36px; }
.prose h3 { margin-top: 26px; }
.prose code {
    font-family: var(--font-mono);
    font-size: 0.88em;
    padding: 2px 6px;
    background: var(--color-neutral-100);
    border-radius: var(--radius-input);
}


/* =============================================
   Links
   ============================================= */
a {
    color: var(--color-primary);
    text-underline-offset: 4px;
}
a:hover { color: var(--color-primary-600); }

.link,
.link-strong {
    color: var(--color-primary);
    text-decoration: underline;
}
.link-strong { font-weight: 650; }
.link-plain  { color: inherit; text-decoration: none; }
.link-plain:hover { color: var(--color-primary); text-decoration: underline; }


/* =============================================
   Page chrome
   ---------------------------------------------
   Every screen is the same three bands: a cream header carrying the mark
   and the navigation, a centred column of content, and a footer. No
   sidebar and no bar above the header — one band of chrome, so the full
   width AND the top of the page belong to the work.
   ============================================= */
.page {
    min-height: 100vh;
    /* dvh tracks the viewport as mobile browser chrome slides away; the vh
       above stays as the fallback for anything that does not know it. */
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}

/* --- 1. Header ------------------------------------------------------
   Three parts on one line: the mark, the navigation, and who is signed
   in. Everything the chrome has to say fits here, which is the point —
   a second band above it would spend 40px of every screen restating it. */
.site-header {
    max-width: var(--shell-max);
    margin: 0 auto;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 24px var(--shell-pad);
    border-bottom: 1px solid var(--color-outline-variant);
    flex-wrap: wrap;
}
.site-header__brand {
    display: flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
    color: inherit;
    flex: 0 0 auto;
}

/* Navigation. Set in the body face at body weight — it is a list of
   places, not a row of buttons, and the design already spends its one
   loud shape on the things you press. The current screen is the only
   blue word on the line, with a rule under it: in a product with a
   single action colour, "where am I" and "what can I press" have to be
   told apart by SHAPE, and a marker attached to the word is not a
   button. */
.site-nav {
    display: flex;
    align-items: center;
    gap: 28px;
    flex-wrap: wrap;
    min-width: 0;
}
.site-nav__link {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-on-surface);
    text-decoration: none;
    padding-bottom: 3px;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    transition: color 120ms, border-color 120ms;
}
.site-nav__link:hover {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary-200);
}
.site-nav__link[aria-current="page"] {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

/* Signed out, the header carries the mark and nothing else — centred,
   with no rule under it. There is no navigation to offer someone who is
   not signed in, and a chrome bar with one item in it and a border under
   it makes an auth screen look like a page that lost its content. */
.site-header--auth {
    justify-content: center;
    border-bottom: none;
    padding-bottom: 8px;
}
/* ...and because it is the only thing in that header, it is drawn larger
   here than anywhere else. Elsewhere the mark shares the bar with the nav
   and the account, and has to stay out of their way; on a sign-in screen
   there is nothing to stay out of the way OF. The breakpoints below carry
   this override with them — a mark sized for a desktop sign-in screen is
   the first thing to cost a cramped one its fold. */
.site-header--auth .logo { width: 200px; }

/* Who is signed in, and the one action that ends the session. */
.site-header__account {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 0 0 auto;
}
.site-header__logout { display: flex; }
.header-note {
    margin: 0;
    font-size: 13px;
    color: var(--color-on-surface-variant);
    text-align: right;
}

/* The right-hand end of the header on a PUBLIC page: the brand line.
   Signed-in screens put the account block here instead. */
.site-header__aside {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* --- 2. Main + footer ----------------------------------------------- */
.site-main {
    /* No min-height. .page is a 100vh flex column and this is its flexible
       child, so it already grows to fill a short page — a min-height on top
       of that can only ever make it TALLER than the space available. At
       605px of viewport, header + footer exceed 35vh, and a `min-height:
       65vh` then guaranteed a scrollbar on a page with nothing in it. */
    flex: 1;
    width: 100%;
    max-width: var(--shell-max);
    margin: 0 auto;
    padding: 48px var(--shell-pad) 60px;
}
.site-footer {
    width: 100%;
    max-width: var(--shell-max);
    margin: 0 auto;
    border-top: 1px solid var(--color-outline-variant);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding: 25px var(--shell-pad);
    font-size: 12px;
    color: var(--color-on-surface-variant);
}
.site-footer a { color: var(--color-primary); }
.site-footer__links { display: flex; gap: 24px; }


/* =============================================
   Page head — title row at the top of a screen
   ============================================= */
.page-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    /* 24px, the same step ``.tabs`` uses above and below itself, so a page
       with tabs and a page without keep one rhythm. */
    margin-bottom: 24px;
}
.page-head__text { min-width: 0; }
/* The action beside a page title is the SMALL button (13px, 34.8px tall),
   not the full-size one — measured off the reference's "Back to
   registration". A 51.6px button up here competes with the 38px serif
   title it sits next to; the small one reads as an action attached to the
   heading. */
.page-head__actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
}
.page-head__actions > .btn {
    padding: 7px 12px;
    font-size: 13px;
    gap: 6px;
}
.page-head__actions > .btn > svg { width: 14px; height: 14px; }
/* 38px, and otherwise exactly h1 — which is how the reference gets it:
   ``.admin-head h1{font-size:38px}`` overrides the size and nothing else.
   The tracking in particular is an ABSOLUTE -1.3px at every display size
   (46, 44, 38, 35), not a ratio that scales down. */
.page-title {
    font-family: var(--font-display);
    font-size: 38px;
    line-height: 1.14;
    font-weight: 400;
    letter-spacing: -1.3px;
    margin: 0;
    color: var(--color-on-surface);
}
/* The line under the title: what this screen is, or who is looking at
   it. Small and muted — the title has already been read. */
.page-sub {
    margin: 10px 0 0;
    font-size: 14px;
    color: var(--color-on-surface-variant);
}


/* =============================================
   Two-column layout — a title column beside a panel
   ---------------------------------------------
   For a screen that is ONE form. The narrow column carries the heading
   and the explanation, the wide one carries the card, and the two scroll
   together — so the instructions stay beside the fields they describe
   instead of above a form long enough to push them off-screen.
   ============================================= */
.layout {
    display: grid;
    grid-template-columns: 235px minmax(0, 1fr);
    gap: 50px;
}
.layout__aside { padding-top: 10px; }
.layout__aside h1,
.layout__aside .page-title { font-size: 35px; margin-bottom: 18px; }
.layout__aside p { font-size: 14px; }
.layout__body { min-width: 0; }


/* =============================================
   Steps — where you are in a flow that has an end
   ---------------------------------------------
   A row of equal segments, each capped by a rule that colours in as the
   flow advances. Equal widths are the point: the segments are a measure of
   how much is left, so a long step name must not make its segment look
   bigger than the others.

   POSITION, NOT NAVIGATION. These are <li>, never links — you cannot jump
   to step 4, and a step that looks clickable and is not is worse than one
   that never offered. The current step carries aria-current="step"; the
   colour and weight are for everyone else.

   NOT .tabs, which is the other row of things at the top of a screen. Tabs
   are lateral — three views of one set of data, any of them reachable at
   any time, and the one you are on is a choice. Steps are sequential, and
   the one you are on is a consequence.
   ============================================= */
.steps {
    display: flex;
    list-style: none;
    padding: 0;
    margin: 0 0 40px;
    gap: 8px;
}
.steps li {
    /* Equal segments regardless of label length. */
    flex: 1;
    border-top: 3px solid var(--color-outline-variant);
    padding-top: 11px;
    font-size: 12px;
    color: var(--color-on-surface-variant);
}
/* Done is green and receded; current is the action blue and the only bold
   thing in the row. Two different colours rather than two weights of one,
   so "finished" and "here" are told apart at a glance and not by reading. */
.steps li.is-done    { border-color: var(--color-tertiary-300); }
.steps li.is-current {
    border-color: var(--color-primary);
    color: var(--color-primary);
    font-weight: 700;
}
@media (max-width: 760px) {
    .steps { gap: 6px; margin-bottom: 25px; }
    .steps li { font-size: 10px; }
}


/* =============================================
   Medallion — the one mark on a screen that reports an outcome
   ---------------------------------------------
   A circle with a single glyph in it, centred above the heading of a page
   that exists to say one thing: you are confirmed, check your email, this
   is done. Sized to be seen before the heading is read, which is the whole
   job — the reader already knows what they did, and wants to know how it
   went before they read a word.

   ONE PER SCREEN, and only on a screen whose entire purpose is the report.
   A medallion beside anything else is decoration, and a page with two is a
   page that has not decided what it is telling you.

   The default is the confirmation green. --info is the blue of a step that
   went fine but is not the end — "we have sent it", not "you are in" — and
   the distinction is worth a variant rather than a second green, because a
   green circle on a screen that still needs an action from you reads as
   finished when it is not.
   ============================================= */
.medallion {
    width: 64px;
    height: 64px;
    margin: 0 auto 25px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 30px;
    background: var(--color-tertiary-50);
    color: var(--color-success-600);
}
.medallion--info {
    background: var(--color-primary-75);
    color: var(--color-primary);
}


/* =============================================
   Demo help — what this build does that the real one will not
   ---------------------------------------------
   The one component that talks about the INSTALLATION rather than to the
   person using it: "no email was really sent", "this data is synthetic",
   "sign in with these test credentials".

   It is yellow because it must not be mistaken for the page's own content,
   and it says so in the first few words so a reader can skip it. Every
   block wearing this class is a thing to delete before the software meets
   the public, which is exactly why they all wear the same one — they are
   findable with a single grep.
   ============================================= */
.demo-help {
    background: var(--color-accent-50);
    border: 1px solid var(--color-accent-200);
    border-radius: var(--radius-input);
    padding: 12px 16px;
    margin: 18px 0;
    font-size: 12px;
}
.demo-help > :last-child { margin-bottom: 0; }


/* =============================================
   Scroll region — long text you are asked to read
   ---------------------------------------------
   A bounded, scrollable box for a document that has to be shown in full
   inside a page that is not about the document: terms, a consent notice,
   a licence, a long log.

   THE HEIGHT IS FIXED, NOT max-height, and that is the whole point. When a
   page gates an action on "you have reached the end of this", the end has
   to be somewhere the reader can actually get to, and the layout must not
   move while they get there. A max-height box collapses to its content, so
   short text silently removes the scroll — and with it any evidence the
   text was put in front of anyone.

   Set a size smaller than the page around it: this is a reference document
   embedded in a form, and matching the form's body size makes a
   ninety-paragraph agreement look like the thing the page is about.
   ============================================= */
.scroll-region {
    height: 330px;
    overflow-y: auto;
    padding: 20px;
    margin: 22px 0;
    border: 1px solid var(--color-outline-variant);
    border-radius: var(--radius-input);
    background: var(--color-surface-container-low);
    font-size: 13px;
    line-height: 1.7;
}
.scroll-region p { margin-bottom: 14px; }
.scroll-region > :last-child { margin-bottom: 0; }
/* Legal text carries bare URLs and long addresses. Without this they push
   the box into horizontal scrolling, which is the one direction a reader
   will not think to look. */
.scroll-region a { overflow-wrap: anywhere; }


/* =============================================
   Legal document — a published terms or privacy policy
   ---------------------------------------------
   The HTML common/text/docx_html.py builds from counsel's Word file: h2–h4,
   paragraphs, lists, links, the odd table, and nothing styled inline. It
   inherits its size from where it sits — 13px inside the terms screen's
   .scroll-region, body size on the public page — so these rules are about
   rhythm and hierarchy, in ems, not about type size.
   ============================================= */
.legal-doc h2,
.legal-doc h3,
.legal-doc h4 {
    font-family: inherit;
    font-weight: 700;
    line-height: 1.35;
    margin: 1.6em 0 0.6em;
    color: var(--color-on-surface);
}
.legal-doc h2 { font-size: 1.25em; }
.legal-doc h3 { font-size: 1.1em; }
.legal-doc h4 { font-size: 1em; }
.legal-doc > :first-child { margin-top: 0; }
.legal-doc p  { margin: 0 0 1em; }
.legal-doc ul,
.legal-doc ol { margin: 0 0 1em; padding-left: 1.6em; }
.legal-doc li { margin-bottom: 0.35em; }
.legal-doc li > ul,
.legal-doc li > ol { margin: 0.35em 0 0; }
.legal-doc a  { overflow-wrap: anywhere; }
.legal-doc .legal-table { overflow-x: auto; margin: 0 0 1em; }
.legal-doc table { border-collapse: collapse; width: 100%; }
.legal-doc td {
    border: 1px solid var(--color-outline-variant);
    padding: 0.5em 0.7em;
    vertical-align: top;
}
.legal-doc td p:last-child { margin-bottom: 0; }

/* The public page: one column of reading, at a reading measure. */
.legal-page { max-width: 820px; margin: 0 auto; }
.legal-page__title { margin-bottom: 6px; }
.legal-page .legal-doc { margin-top: 24px; font-size: 15px; line-height: 1.7; }


/* =============================================
   Password checklist — layout/_password_rules.j2
   ---------------------------------------------
   The rule under a new-password box, each line ticking as it is met. Muted
   until met rather than red until met: an empty box is not an error.
   ============================================= */
.pw-rules {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: grid;
    gap: 3px 16px;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    font-size: 12px;
    color: var(--color-on-surface-variant);
}
.pw-rules li { position: relative; padding-left: 18px; }
.pw-rules li::before {
    content: "○";
    position: absolute;
    left: 0;
}
.pw-rules li.is-met { color: var(--color-success); }
.pw-rules li.is-met::before { content: "✓"; font-weight: 700; }


/* =============================================
   Notice — a standing remark, not an event
   ---------------------------------------------
   A tinted panel with a rule down its leading edge, for information that
   is part of the page rather than a response to something the reader just
   did: "have your ID ready", "dates are UTC", "this link lasts 72 hours".

   NOT a toast and NOT an error summary. Those two interrupt, are dismissed
   or resolved, and take the reader's attention away from the task. A notice
   is always there, says the same thing on every visit, and is read in
   passing — so it is tinted rather than bordered all round, and it carries
   no icon.

   NOT a card either, though the difference is easy to miss. A card is a
   white surface holding its own contents; a notice is a coloured aside
   about the contents around it. Using .card here (which the registration
   screen did at first) reads as "here is another section", when the
   intended reading is "before you go on, know this".
   ============================================= */
.notice {
    background: var(--color-primary-75);
    border-left: 3px solid var(--color-primary);
    /* Square on the leading edge so the rule reads as a margin mark rather
       than as one rounded side of a pill. */
    border-radius: 0 var(--radius-input) var(--radius-input) 0;
    padding: 17px 20px;
    font-size: 14px;
}
.notice p:last-child { margin-bottom: 0; }


/* =============================================
   Card
   ============================================= */
.card {
    background: var(--color-surface);
    border: 1px solid var(--color-outline-variant);
    border-radius: var(--radius);
    padding: 30px;
    box-shadow: var(--shadow-card);
}
.card + .card { margin-top: 20px; }

/* A title row at the top of a card, above a table or a list. Sits ON the
   card because it names the card's contents; a heading over a GROUP of
   cards goes on the page instead (.section-title). */
.card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 24px;
}
.card-head__text { min-width: 0; }
/* The h2 treatment — 23px, and the largest sans on the page. A card's
   heading names a whole region of the screen, so it sits well above the
   16px h3 tier it used to use; measured off the reference at 23px. */
.card-head__title {
    margin: 0;
    font-size: 23px;
    line-height: 1.3;
    font-weight: 700;
}
/* Body size and body ink, NOT a caption. The line under a card heading is
   the sentence that says what the card is for and how to read it — the
   reference sets it as an ordinary paragraph, and dropping it to 13px
   muted turns an explanation into fine print. */
.card-head__sub {
    margin: 10px 0 0;
}
.card-head__actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Panel inset inside a card — a block of related detail that belongs to
   the card rather than beside it. Cooler ground + its own border; never
   another shadow, because a card does not sit on a card. */
.panel {
    background: var(--color-surface-inset, var(--color-neutral-50));
    border: 1px solid var(--color-surface-inset-border, var(--color-outline-variant));
    border-radius: var(--radius-panel);
    padding: 22px;
}
.panel > :last-child { margin-bottom: 0; }


/* =============================================
   Stats — the row of figures at the top of a dashboard
   ---------------------------------------------
   A number set in Georgia at 36px and a caption at 12px. The contrast
   between those two is the entire component: the figure is what you came
   for, the label is only there to say which figure it is.

   Flat and bordered, not shadowed. Four of them in a row, each carrying
   its own shadow, would read as four floating objects rather than one
   band of numbers.

   TWO LINES ONLY. A third line of per-card context was tried and removed:
   it makes each tile a paragraph, and four paragraphs in a row is not a
   band of numbers any more. Anything that qualifies the figures goes in
   the .stats-note sentences underneath, where it is read once instead of
   four times.
   ============================================= */
.stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 15px;
    margin-bottom: 24px;
}
.stat {
    background: var(--color-surface);
    border: 1px solid var(--color-outline-variant);
    border-radius: var(--radius-panel);
    padding: 20px;
}
/* ``line-height: normal`` is not a default here, it is the declaration.
   The reference sets this figure with the ``font:`` SHORTHAND —
   ``font: 36px Georgia, serif`` — and the shorthand resets every property
   it does not name, so the leading comes out as the font's own (~1.14 in
   Georgia) rather than the 1.6 the body would pass down. Writing the
   longhand without it silently makes every figure taller. */
.stat strong {
    display: block;
    font-family: var(--font-display);
    font-size: 36px;
    font-weight: 400;
    line-height: normal;
    margin-bottom: 6px;
    color: var(--color-on-surface);
}
.stat small {
    display: block;
    font-size: 12px;
    color: var(--color-on-surface-variant);
}
/* An optional third line: the figure's context ("8 deactivated"). Quieter
   than the label above it, because it qualifies rather than names. */
/* The sentences under a stats row that explain how the figures relate.
   Body-sized, on the page ground — they are prose, not chrome. */
/* Body size, not a smaller caption tier: in the reference these lines are
   plain <p> under the stats row, so they read at 16px/1.6 like any other
   sentence on the page. */
.stats-note {
    margin: 0 0 12px;
    color: var(--color-on-surface-variant);
}
.stats-note strong { color: var(--color-on-surface); }


/* =============================================
   Buttons
   ---------------------------------------------
   One shape, one colour, and emphasis carried by FILL vs OUTLINE:

     .btn--primary   solid blue. The action of the screen.
     .btn--outline   white, blue label, hairline border. Everything else.
     .btn--tonal     soft blue ground, no border. A repeatable action.
     .btn--ghost     a link that behaves like a button.
     .btn--danger    solid red. Destructive confirmation only.

   Sizes:
     .btn      47px — matches .input, so a control row lines up
     .btn--sm  31px — inside a table row or a dense list
     .btn--lg  53px — a form's final submit

   Width is auto. Add .btn--block for a full-width submit.
   ============================================= */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    border: 0;
    border-radius: var(--radius-control);
    padding: 13px 24px;
    background: var(--color-primary);
    color: #fff;
    font-family: inherit;
    font-size: 16px;
    /* 650 — a real weight in a variable face, and the nearest static one
       otherwise. The reference's number, kept. */
    font-weight: 650;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 120ms, border-color 120ms, color 120ms;
}
.btn:hover { background: var(--color-primary-600); color: #fff; text-decoration: none; }

.btn--primary { background: var(--color-primary); color: #fff; }
.btn--primary:hover { background: var(--color-primary-600); }

.btn--outline {
    background: var(--color-surface);
    color: var(--color-primary);
    border: 1px solid var(--color-outline-strong, var(--color-outline));
}
.btn--outline:hover {
    background: var(--color-primary-75);
    color: var(--color-primary-600);
    border-color: var(--color-primary-300);
}

.btn--tonal {
    background: var(--color-primary-75);
    color: var(--color-primary-600);
}
.btn--tonal:hover { background: var(--color-primary-100); color: var(--color-primary-700); }

.btn--ghost {
    background: none;
    color: var(--color-primary);
    padding: 6px 0;
    text-decoration: underline;
    border-radius: var(--radius-input);
}
.btn--ghost:hover { background: none; color: var(--color-primary-600); }

.btn--danger { background: var(--color-error); color: #fff; }
.btn--danger:hover { background: var(--color-error-600); }

.btn:disabled,
.btn[disabled] {
    background: var(--color-surface-disabled);
    color: var(--color-on-surface-disabled);
    border-color: transparent;
    cursor: not-allowed;
}
.btn--outline:disabled,
.btn--ghost:disabled { background: transparent; text-decoration: none; }

.btn--sm  { padding: 7px 12px; font-size: 13px; gap: 6px; }
/* Full width. For the single submit that ends a form the reader has been
   working down — at that point the button is the next line of the form,
   not one option among several sitting in a row. */
.btn--block { width: 100%; }
.btn--lg  { padding: 16px 30px; font-size: 17px; }

.btn > svg      { flex: 0 0 auto; width: 17px; height: 17px; }
.btn--sm > svg  { width: 14px; height: 14px; }


/* =============================================
   Forms
   ---------------------------------------------
   A label is 14px/600 and sits directly on its control, 6px above. Every
   control is 47px tall with a 6px radius and a border dark enough to
   find from across the page — which is the reason inputs get
   --color-outline (#adbec7) and dividers get --color-outline-variant
   (#d9e3e6); they are doing different jobs and a shared value made one
   of them wrong.
   ============================================= */
.field { margin-bottom: 20px; }

label { font-size: 14px; font-weight: 600; display: block; }
label > input,
label > select,
label > textarea { margin-top: 6px; }

/* A fieldset groups controls that answer one question — a set of
   checkboxes, a set of radios — and that grouping is what a screen reader
   announces. The browser's default chrome for it (a groove border and
   asymmetric padding) belongs to no design system, and there is no case in
   this one where a field group is drawn as a box, so it is reset globally
   rather than per use. Use .section-label or a .field-label for the group's
   visible name; the accessible name comes from <legend> or aria-labelledby. */
fieldset { border: 0; margin: 0; padding-left: 0; padding-right: 0; }
fieldset > legend { font-size: 11px; padding: 0; }

.field-label {
    display: block;
    margin-bottom: 6px;
    font-size: 14px;
    font-weight: 600;
    color: var(--color-on-surface);
}
.field-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 6px;
}
.field-row .field-label { margin-bottom: 0; }
/* Inline qualifier inside a label ("optional", a count). Reads as an
   aside to the label, so it drops the label's weight. */
.field-label__hint,
.field-hint {
    font-weight: 400;
    color: var(--color-on-surface-variant);
}
.field-label__hint { margin-left: 6px; font-size: 13px; }
/* Helper text UNDER a control — what to type, or what happens next. */
.field-hint {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    line-height: 1.5;
}

/* 14px SEMIBOLD, which is not an invention — it is what the reference
   computes to, arrived at sideways. Its reset says
   ``button,input,select{font:inherit}``, and its controls sit INSIDE their
   <label> (that is what ``label input{margin-top:6px}`` is for), so every
   control inherits the label's own ``14px/600``. Measured off the staff
   screenshot: the select reads 14px and visibly heavier than the body copy
   beside it.

   Declared here rather than left to inheritance, because inheritance makes
   the size depend on whether the markup happens to nest the control — ours
   nests it in the filter row and not in the modals, which would render the
   same control at two sizes on two screens. */
.input,
.select-native,
textarea.input {
    width: 100%;
    font-size: 14px;
    font-weight: 600;
    border: 1px solid var(--color-outline);
    border-radius: var(--radius-input);
    background: var(--color-surface);
    padding: 11px 12px;
    min-height: var(--control-h);
    color: var(--color-on-surface);
}
.input::placeholder { color: var(--color-on-surface-muted); }
.input[type="search"] { appearance: none; -webkit-appearance: none; }
textarea.input { min-height: 120px; line-height: 1.6; resize: vertical; }
.select-native { cursor: pointer; }
.select-native--inline { width: auto; min-width: 140px; min-height: 38px; padding: 5px 10px; font-size: 14px; }


/* Invalid: a 2px red border, driven by aria-invalid so the styling and
   the accessibility signal cannot drift apart. .input--error is the same
   thing for markup that has no aria state to set. */
.input[aria-invalid="true"],
.select-native[aria-invalid="true"],
.input--error,
.input--error:focus {
    border: 2px solid var(--color-error);
}

/* Checkbox: the native control, tinted. Custom-drawn boxes lose the
   platform's own focus, hit-target and high-contrast behaviour, and
   accent-color buys the one thing they were drawn for. */
input[type="checkbox"],
input[type="radio"] {
    width: 19px;
    min-height: 19px;
    height: 19px;
    margin: 0;
    accent-color: var(--color-primary);
}
.check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-weight: 400;              /* the label beside it is 600; this is not a label */
    cursor: pointer;
    color: var(--color-on-surface);
}
.check > input {
    margin-top: 3px;
    flex-shrink: 0;
}
/* A row of them side by side (two or three short options). */
.checks { display: flex; gap: 25px; align-items: flex-start; flex-wrap: wrap; }

/* Two-column field grid. .full spans the row — for a long value, or for
   the field that concludes a group. */
.form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}
.form-grid .full { grid-column: 1 / -1; }
/* The grid owns the spacing between fields; a field's own bottom margin
   would double it on every row. */
.form-grid > .field,
.form-grid > .modal__field { margin-bottom: 0; }
.form-field { min-width: 0; }

/* The action row that ends a form. Left-aligned: it is the next step in
   a sequence you are reading down, not a floating toolbar. */
.actions {
    display: flex;
    gap: 14px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 25px;
}

.error { color: var(--color-error); font-size: 13px; }
/* The summary block at the top of a form that failed validation. */
.error-summary {
    background: var(--color-error-50);
    border: 1px solid var(--color-error-200);
    padding: 15px;
    border-radius: var(--radius-input);
    margin-bottom: 20px;
    font-size: 14px;
}
.error-summary p:last-child { margin-bottom: 0; }


/* =============================================
   Notice / alert
   ---------------------------------------------
   A left rule and a tinted ground, square on the left so the rule reads
   as a margin marker on the page rather than as the edge of a pill.
   ============================================= */
.alert {
    background: var(--color-primary-75);
    border-left: 3px solid var(--color-primary);
    padding: 17px 20px;
    border-radius: 0 var(--radius-input) var(--radius-input) 0;
    font-size: 14px;
    line-height: 1.6;
    margin-bottom: 20px;
}
.alert p:last-child { margin-bottom: 0; }

.alert--info    { background: var(--color-primary-75);  border-left-color: var(--color-primary);       color: var(--color-on-surface); }
.alert--error   { background: var(--color-error-50);    border-left-color: var(--color-error);         color: var(--color-error-600); }
.alert--success { background: var(--color-success-75);  border-left-color: var(--color-success-700);   color: var(--color-success-700); }
.alert--warning { background: var(--color-warning-50);  border-left-color: var(--color-warning-500);   color: var(--color-warning-700); }


/* =============================================
   Filters — the labelled controls above a table
   ---------------------------------------------
   Labelled, not a row of bare pills: on an admin screen you return to,
   "Registration state" beside a select is the difference between reading
   the filter and remembering it.
   ============================================= */
.filters {
    display: flex;
    gap: 12px;
    margin-bottom: 20px;
    flex-wrap: wrap;
    align-items: flex-end;
}
.filters label {
    flex: 1;
    min-width: 130px;
}


/* =============================================
   Data table
   ============================================= */
.table-wrap { overflow-x: auto; }

.data-table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
}
/* Content-width variant, for a table of short chips and counts that
   would otherwise be stretched across the card by width:100%. */
.data-table.data-table--fit { width: auto; }

.data-table th {
    text-align: left;
    background: var(--color-neutral-100);
    color: var(--color-on-surface-variant);
    font-size: 11px;
    font-weight: 700;              /* the UA's <th> weight, which the reference leaves alone */
    text-transform: uppercase;
    letter-spacing: 0.7px;
    white-space: nowrap;
}
.data-table td,
.data-table th {
    padding: 13px 12px;
    border-bottom: 1px solid var(--color-outline-variant);
    vertical-align: middle;
}
.data-table td { color: var(--color-on-surface); }
/* The table sits inside a card that is already padded, so the first and
   last columns run to the card's own content edge — otherwise the whole
   table looks indented from the heading above it. */
.data-table th:first-child,
.data-table td:first-child { padding-left: 0; }
.data-table th:last-child,
.data-table td:last-child  { padding-right: 0; text-align: right; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover > td { background: var(--color-neutral-50); }

/* Compact variant — tighter rows for a dense list. */
.data-table--compact th,
.data-table--compact td { padding-top: 9px; padding-bottom: 9px; }

/* Centre every cell except the primary identifier (a name, an id — the
   row's anchor, which stays left-aligned) and the last column of
   actions. For tables that are mostly short values. */
.data-table--center-cells thead th:not(.col-primary):not(:last-child),
.data-table--center-cells tbody td:not(.col-primary):not(.col-status):not(:last-child) {
    text-align: center;
}
.data-table td.col-primary { font-weight: 600; }

/* A trailing column of row actions — as narrow as its button and pinned
   right, so the eye runs down one edge rather than a ragged one. */
.data-table th.col-actions,
.data-table td.col-actions {
    text-align: right;
    width: 1%;
    white-space: nowrap;
}
/* Cap the identifier column so one long name cannot stretch it. Under
   table-layout:auto a max-width on a cell is treated as a hint and often
   ignored, so width is set too and the inner anchor is capped directly —
   that is the element feeding the column's preferred width. */
.data-table th.col-primary,
.data-table td.col-primary {
    width: 380px !important;
    max-width: 380px !important;
}
.data-table td.col-primary > a {
    display: block;
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Muted row — every cell dims uniformly so badges, toggles and counts all
   read as "kept, but inactive". The opacity sits on each <td> rather than
   the <tr> so one cell can opt back out: the status cell keeps full
   intensity, so an Inactive chip looks identical to the same chip in a
   live row. */
.data-table tr.row--muted > td            { opacity: 0.55; }
.data-table tr.row--muted > td.col-status { opacity: 1; }

/* Arrived via /users#u-<id> — tint the row that was linked to. */
.data-table tr:target > td { background: var(--color-primary-75); }

/* Removing — fade out before the row is detached from the DOM. */
.data-table tr { transition: opacity 200ms ease, transform 200ms ease; }
.data-table tr.row--removing {
    opacity: 0;
    transform: translateX(-12px);
    pointer-events: none;
}

/* Two-line cell: a name with a qualifier under it. */
.cell-stack { display: flex; flex-direction: column; gap: 2px; }
.cell-stack__primary   { font-weight: 600; color: var(--color-on-surface); }
.cell-stack__secondary { font-size: 12px; color: var(--color-on-surface-variant); }

/* Nothing to show. Not an error — say so plainly and centred, and say
   what would put something here. */
.empty {
    margin: 0;
    padding: 40px 15px;
    text-align: center;
    color: var(--color-on-surface-variant);
}

/* The strip along the bottom of a table card reporting what is shown. */
.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--color-outline-variant);
    font-size: 13px;
    color: var(--color-on-surface-variant);
}


/* =============================================
   Tabs
   ---------------------------------------------
   Buttons, not underlined text: the same shape as every other control,
   with the current one FILLED and the rest outlined. In a product with
   one action colour this is the clearest "you are here" available — the
   selected tab is the only solid blue object in the row.
   ============================================= */
.tabs {
    display: flex;
    gap: 10px;
    /* No top margin: a tab row always follows a .page-head, which has
       already spaced itself from what comes next. Two stacked margins
       there left the tabs adrift between the title and the panel they
       belong to. */
    margin: 0 0 24px;
    flex-wrap: wrap;
}
.tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--color-outline-strong, var(--color-outline));
    border-radius: var(--radius-control);
    padding: 13px 24px;
    background: var(--color-surface);
    color: var(--color-primary);
    font-family: inherit;
    font-size: 16px;
    font-weight: 650;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 120ms, color 120ms, border-color 120ms;
}
.tab:hover { background: var(--color-primary-75); color: var(--color-primary-600); }
.tab--active,
.tab--active:hover {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}
.tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    padding: 2px 7px;
    border-radius: var(--radius-pill);
    background: var(--color-primary-100);
    color: var(--color-primary-700);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.tab--active .tab-count { background: rgba(255, 255, 255, 0.22); color: #fff; }


/* =============================================
   Badges
   ---------------------------------------------
   11px, pill-shaped, tinted ground with ink from the same family. Three
   tones do almost all the work: amber = waiting on something, green =
   done, red = refused.
   ============================================= */
.badge {
    display: inline-flex;
    align-items: center;
    border-radius: var(--radius-pill);
    background: var(--color-warning-75);
    color: var(--color-warning-700);
    font-size: 11px;
    /* Weight and leading are the inherited body values. 11px at 400 in a
       tinted pill is lighter than it looks like it should be, and it is
       what the reference does — a status is a label on a row, not a second
       heading competing with the row's own text. */
    font-weight: 400;
    padding: 4px 10px;
    white-space: nowrap;
}
.badge--warning  { background: var(--color-warning-75);   color: var(--color-warning-700);  }
.badge--success  { background: var(--color-success-75);   color: var(--color-success-700);  }
.badge--error    { background: var(--color-error-75);     color: var(--color-error-600);    }
.badge--info     { background: var(--color-info-75);      color: var(--color-info-600);     }
.badge--primary  { background: var(--color-primary-75);   color: var(--color-primary-600);  }
.badge--tertiary { background: var(--color-tertiary-100); color: var(--color-tertiary-700); }
.badge--lime     { background: var(--color-lime-75);      color: var(--color-lime-700);     }
.badge--neutral  { background: var(--color-neutral-100);  color: var(--color-on-surface-variant); }
.badge--archived { background: var(--color-neutral-100);  color: var(--color-neutral-400);  }

/* Chip shape — squared off, for a badge used as row DATA (a role, a
   region) rather than as a status. At the full pill radius it reads as
   something you could press. */
.badge--chip { border-radius: var(--radius-input); }
/* One step lighter in the ground, label untouched: a column of statuses
   stays colour-coded without the tint competing with the figures beside
   it. */
.badge--soft.badge--neutral  { background: var(--color-neutral-75);  }
.badge--soft.badge--archived { background: var(--color-neutral-75);  }
.badge--soft.badge--success  { background: var(--color-success-50);  }
.badge--soft.badge--warning  { background: var(--color-warning-50);  }
.badge--soft.badge--info     { background: var(--color-info-50);     }
.badge--soft.badge--error    { background: var(--color-error-50);    }
.badge--soft.badge--tertiary { background: var(--color-tertiary-50); }
.badge--soft.badge--lime     { background: var(--color-lime-50);     }

.badge__icon { width: 12px; height: 12px; margin-right: 5px; margin-left: -2px; flex: 0 0 auto; }
.badge--dot::before {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    margin-right: 6px;
    background: currentColor;
    border-radius: 50%;
}
.status-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-right: 6px;
    border-radius: 50%;
    flex: 0 0 auto;
}
.status-dot--success { background: var(--color-success-700); }
.status-dot--neutral { background: var(--color-on-surface-muted); }

/* Equal-width chips — so a column of pills with different labels renders
   at one width instead of jittering row to row. The visible face and a
   hidden ghost (always the LONGEST variant) share one grid cell; the grid
   sizes to its widest child. No magic numbers: a longer variant means
   changing the ghost label in the template, nothing here. */
.chip-eq        { display: inline-grid; }
.chip-eq__face,
.chip-eq__ghost {
    grid-row: 1;
    grid-column: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
}
.chip-eq__ghost { visibility: hidden; pointer-events: none; user-select: none; }


/* =============================================
   Toggle switch (binary on/off)
   ============================================= */
.toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
}
/* Selector doubled up so it outweighs the platform ``input[type=…]``
   rule above, which would otherwise give this hidden input a 19px box. */
.toggle > .toggle__input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}
.toggle__visual {
    position: relative;
    flex: 0 0 auto;
    width: 42px;
    height: 24px;
    background: var(--color-neutral-300);
    border-radius: var(--radius-pill);
    transition: background 160ms;
}
.toggle__visual::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(25, 55, 68, 0.3);
    transition: transform 160ms;
}
.toggle__input:checked + .toggle__visual { background: var(--color-primary); }
.toggle__input:checked + .toggle__visual::after { transform: translateX(18px); }
.toggle__input:focus-visible + .toggle__visual {
    outline: var(--focus-width) solid var(--color-focus, var(--color-warning-600));
    outline-offset: var(--focus-offset);
}
.toggle__label { font-size: 13px; font-weight: 600; color: var(--color-on-surface-variant); }
.toggle__input:checked ~ .toggle__label { color: var(--color-success-700); }


/* =============================================
   Avatar
   ============================================= */
.avatar {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--color-primary-75);
    color: var(--color-primary-600);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 700;
    overflow: hidden;
    text-decoration: none;
}
.avatar--xs { width: 28px; height: 28px; font-size: 11px; }
.avatar--lg { width: 64px; height: 64px; font-size: 20px; }
.avatar--empty { background: var(--color-neutral-100); }

.avatar-stack { display: inline-flex; align-items: center; }
.avatar-stack > .avatar {
    border: 2px solid var(--color-surface);
    margin-left: -8px;
}
.avatar-stack > .avatar:first-child { margin-left: 0; }
.avatar-stack > .avatar--xs { margin-left: -6px; }
.avatar-stack > .avatar--xs:first-child { margin-left: 0; }


/* =============================================
   Icon button + row actions
   ---------------------------------------------
   Square-ish rather than round: it is a small button, and everything you
   press in this design has the same 7px corner.
   ============================================= */
.icon-btn {
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-outline-strong, var(--color-outline));
    border-radius: var(--radius-control);
    background: var(--color-surface);
    color: var(--color-primary);
    cursor: pointer;
    transition: background-color 120ms, color 120ms, border-color 120ms;
}
.icon-btn:hover {
    background: var(--color-primary-75);
    border-color: var(--color-primary-300);
    color: var(--color-primary-600);
}
.icon-btn > svg { width: 16px; height: 16px; }
.icon-btn--ghost { border-color: transparent; background: transparent; }
.icon-btn--ghost:hover { border-color: var(--color-primary-300); }
.icon-btn--danger { color: var(--color-error); }
.icon-btn--danger:hover {
    background: var(--color-error-50);
    border-color: var(--color-error-200);
    color: var(--color-error-600);
}
/* A spreadsheet download. Green, as spreadsheets are, so the one icon
   reads as "Excel" without a label; the tooltip names what it exports. */
.icon-btn--sheet { color: var(--color-success-600, #2a6c49); }
.icon-btn--sheet:hover {
    background: var(--color-success-50, #eef7f1);
    border-color: var(--color-success-200, #aed2bc);
    color: var(--color-success-600, #2a6c49);
}
.icon-btn:disabled {
    color: var(--color-on-surface-disabled);
    border-color: var(--color-outline-disabled);
    background: transparent;
    cursor: not-allowed;
}

.action-group,
.row-actions {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    justify-content: flex-end;
}


/* =============================================
   Identity strip — who a record is, at the top of its card
   ============================================= */
.identity {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
}
.identity__main { flex: 1 1 240px; min-width: 0; }
/* Sans, not the display face. The serif in this design is spent on three
   things and no more — a page's <h1>, a pull quote, and a stat figure —
   and a name in a panel is none of them. Borrowing it here is what turns a
   deliberate voice into "the font we use for anything important". */
.identity__name {
    font-size: 16px;
    font-weight: 700;
    line-height: 1.4;
    margin: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}
/* Administrator marker. An icon rather than the word: a user's display
   name can literally be "Admin", and the text echo reads as a stutter. */
.identity__admin {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    color: var(--color-primary);
}
.identity__meta {
    margin: 4px 0 0;
    font-size: 13px;
    color: var(--color-on-surface-variant);
}
.identity__badges {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* The profile screen's password panel: VIEW (a row with a button) and
   EDIT (the fields) swap in place, so the card does not jump when it
   opens. Only the spacing lives here — everything visible is .stack-row,
   .form-grid and .actions. */
.profile-password__edit > .form-grid { margin-top: 18px; }

/* A row inside a card: a labelled thing on the left, its control on the
   right, wrapping to two lines when there is no room for one. The shape
   every "setting with a button" uses. */
.stack-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}
.stack-row__text { min-width: 0; flex: 1 1 260px; }
.stack-row__title { font-size: 15px; font-weight: 600; }
.stack-row__sub {
    margin: 2px 0 0;
    font-size: 13px;
    color: var(--color-on-surface-variant);
}


/* =============================================
   Detail grid — label/value pairs for a record
   ============================================= */
.detail-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-bottom: 22px;
}
/* Small and muted, and that is the whole treatment. It had picked up the
   table head's capitals, tracking and bold — three signals for a word
   whose only job is to say which value follows it. */
.detail-grid dt {
    font-size: 11px;
    color: var(--color-on-surface-variant);
    margin-bottom: 3px;
}
.detail-grid dd {
    font-size: 14px;
    margin: 0;
    overflow-wrap: anywhere;
}


/* =============================================
   Brand lockup
   ---------------------------------------------
   One supplied image: the sunrise over BRIGHTSIDE / VOICES.

   The file is 700 x 574 with a TRANSPARENT ground, and the artwork already
   fills it — 691 x 572 of those pixels, so the margin around it is under
   1% on every side. That makes this rule as simple as it looks: set a
   width, let the height follow the file's own proportions, and draw it.

   IT USED TO BE HARDER, and the history is worth one paragraph because it
   explains what was removed. The previous export was 1563px square with a
   WHITE ground and the lockup sitting off-centre in it, leaving 330px of
   empty canvas below. That needed ``mix-blend-mode: multiply`` to make the
   white disappear into the cream page, plus an over-sized image pulled up
   and left inside a fixed box to crop the canvas away. None of it applies
   to a tightly-cropped file with real alpha, and multiply on this one
   would darken the ink against whatever it sits on for no reason.

   So: if the logo is ever re-exported with padding or a solid ground
   again, the fix is to re-export it without them, not to bring the crop
   back.
   ============================================= */
.logo {
    /* The mark's size everywhere but the sign-in screens, which draw it
       larger — see .site-header--auth .logo. Height follows from the
       file's 700:574 proportions; nothing here needs to know them. */
    flex: 0 0 auto;
    width: 150px;
}
.logo > img {
    display: block;
    width: 100%;
    height: auto;
}


/* =============================================
   API keys
   ---------------------------------------------
   One row per configured key; each row is its own VIEW/EDIT cycle.

   The raw key NEVER reaches the DOM. A row shows a mask plus the last
   four characters — enough to tell two keys apart, useless to anyone
   reading over the operator's shoulder — and editing opens an EMPTY
   input to paste into rather than pre-filling the old value.
   ============================================= */
.api-key-card { display: block; }
.api-key-card__empty { color: var(--color-on-surface-variant); font-style: italic; }

.api-key-row-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.api-key-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 14px;
    padding: 16px 20px;
    border: 1px solid var(--color-outline-variant);
    border-radius: 8px;
    background: var(--color-surface);
}
.api-key-row--empty {
    grid-template-columns: 1fr;
    justify-items: start;
}
.api-key-row__server {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-on-surface);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.api-key-row__value {
    display: flex;
    flex: 1;
    min-width: 0;
    padding: 8px 12px;
    border: 1px solid transparent;
    border-radius: var(--radius-input);
    cursor: text;
    transition: background-color 120ms, border-color 120ms;
}
.api-key-row:not(.api-key-row--editing) .api-key-row__value:hover {
    background: var(--color-neutral-75);
    border-color: var(--color-outline-variant);
}
.api-key-row--editing .api-key-row__value {
    background: var(--color-surface);
    border-color: var(--color-primary);
}
.api-key-row__preview {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    color: var(--color-on-surface-variant);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.api-key-row__input {
    flex: 1;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--color-on-surface);
    font-family: var(--font-mono);
    font-size: 14px;
    min-height: 0;
}
.api-key-row__input:focus { outline: none; }
.api-key-row__actions { display: flex; align-items: center; gap: 8px; }

.api-key-card__add { margin-top: 16px; display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.api-key-add-form {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 22px;
    border: 1px solid var(--color-surface-inset-border, var(--color-outline-variant));
    border-radius: var(--radius-panel);
    background: var(--color-surface-inset, var(--color-neutral-50));
}
.api-key-add-form__field { display: flex; flex-direction: column; }
.api-key-add-form__label { font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.api-key-add-form .input { font-family: var(--font-mono); }
.api-key-add-form__actions { display: flex; gap: 12px; align-items: center; }


/* =============================================
   Message list — the demo inbox
   ---------------------------------------------
   One bordered block per message: subject, who it went to and when, the
   body, and the link it carried. Shaped from the reference's ``.mail``
   component — 20px inside an 8px box, body at 14px — because a message is
   a quoted artefact rather than a row of the application's own data, and
   it should look like something that arrived.
   ============================================= */
.message-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.message {
    border: 1px solid var(--color-outline-variant);
    border-radius: 8px;
    padding: 20px;
    margin-top: 15px;
}
.message__head { margin-bottom: 10px; }
.message__subject {
    display: block;
    font-size: 16px;
    font-weight: 700;
    color: var(--color-on-surface);
}
.message__meta {
    display: block;
    margin-top: 2px;
    font-size: 13px;
    color: var(--color-on-surface-variant);
}
.message__body {
    font-size: 14px;
    white-space: pre-line;   /* keep the paragraph breaks the mail was written with */
}


/* =============================================
   Toast — auto-dismissing notification, bottom-right
   ---------------------------------------------
   Ink ground, white text. It is the one element that appears over the
   work without being asked for, so it is the ink colour rather than a
   white card: unmistakably a system message, and it cannot be confused
   with a panel you were already reading.
   ============================================= */
.toast-container {
    position: fixed;
    bottom: 25px;
    right: 25px;
    z-index: 20;
    display: flex;
    flex-direction: column-reverse;
    gap: 10px;
    max-width: min(430px, calc(100vw - 50px));
    pointer-events: none;
}
.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 20px;
    background: var(--color-secondary-800);
    color: #fff;
    border-radius: 8px;
    box-shadow: var(--shadow-pop);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 180ms ease, transform 180ms ease;
}
.toast__icon { flex: 0 0 auto; display: inline-flex; margin-top: 2px; }
.toast__icon > svg { width: 16px; height: 16px; }
.toast__message { flex: 1; min-width: 0; }
.toast__close {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    padding: 0;
    margin-top: -1px;
    background: transparent;
    border: none;
    border-radius: var(--radius-input);
    color: rgba(255, 255, 255, 0.7);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.toast__close:hover { background: rgba(255, 255, 255, 0.14); color: #fff; }
.toast__close > svg { width: 12px; height: 12px; }
.toast--in  { opacity: 1; transform: translateY(0); }
.toast--out { opacity: 0; transform: translateY(8px); }

/* Tint only the icon — the card stays ink so every toast reads the same
   at a glance and the variant is a detail you can check if you care. */
.toast--success .toast__icon { color: var(--color-tertiary-300); }
.toast--error   .toast__icon { color: var(--color-error-300);    }
.toast--warning .toast__icon { color: var(--color-accent-400);   }
.toast--info    .toast__icon { color: var(--color-primary-300);  }


/* =============================================
   Modal dialogs — created by window.confirmDialog() in app.js
   ============================================= */
.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: var(--color-scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity 160ms ease;
    overflow-y: auto;
}
.modal-backdrop--in  { opacity: 1; pointer-events: auto; }
.modal-backdrop--out { opacity: 0; }

/* A dialog opening ON TOP of another — a question about the thing you
   were already answering. The scrim is lighter because the layer beneath
   is already dimmed, and dimming twice buries the thing the question is
   about. */
.modal-backdrop--nested {
    z-index: 10010;
    background: rgba(25, 55, 68, 0.22);
}
.modal-backdrop--nested .modal { max-width: 420px; box-shadow: var(--shadow-deep); }

.modal {
    width: 100%;
    max-width: 480px;
    margin: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-outline-variant);
    border-radius: var(--radius);
    box-shadow: var(--shadow-pop);
    padding: 30px;
    transform: translateY(8px);
    transition: transform 160ms ease;
}
.modal-backdrop--in .modal { transform: translateY(0); }

/* The h2 treatment, because that is the element — see the note on
   .identity__name for why it is not the serif. */
.modal__title {
    margin: 0 0 10px;
    font-size: 23px;
    font-weight: 700;
    line-height: 1.3;
}
.modal__message {
    margin: 0 0 22px;
    font-size: 15px;
    line-height: 1.6;
    color: var(--color-on-surface-variant);
}

/* The specifics, as a label/value grid rather than inside the sentence
   above. A confirm dialog carries two kinds of content: what the action
   DOES, which is prose and reads once, and WHICH THINGS it does it to,
   which is data and gets checked. Run together, the ids — the one part
   the operator has to verify — are the hardest thing to find. */
.modal__facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 8px 16px;
    margin: 0 0 20px;
    padding: 16px 18px;
    background: var(--color-surface-inset, var(--color-neutral-50));
    border: 1px solid var(--color-surface-inset-border, var(--color-outline-variant));
    border-radius: var(--radius-panel);
    font-size: 14px;
    line-height: 1.5;
}
.modal__facts dt {
    color: var(--color-on-surface-variant);
    white-space: nowrap;   /* a wrapped label breaks the column alignment */
}
.modal__facts dd { margin: 0; min-width: 0; overflow-wrap: break-word; }
.modal__facts dd.id-mono { white-space: normal; }
.modal__facts-note {
    margin-left: 8px;
    font-family: var(--font-body);
    letter-spacing: normal;
    color: var(--color-on-surface-variant);
}

/* A consequence the operator has to weigh before they can confirm — not
   a restatement of what the button does. Louder than the instruction on
   every axis that carries meaning, because the instruction offers the
   alternative and if both shouted neither would be read. */
.modal__warning {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin: 0 0 18px;
    padding: 14px 16px;
    border-radius: 0 var(--radius-input) var(--radius-input) 0;
    border-left: 3px solid var(--color-warning-500);
    background: var(--color-warning-50);
}
.modal__warning-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    margin-top: 2px;
    color: var(--color-warning-600);
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
}
.modal__warning-body  { min-width: 0; }
.modal__warning-title { margin: 0; font-size: 14px; font-weight: 700; line-height: 1.5; overflow-wrap: anywhere; }
.modal__warning-title + .modal__warning-text { margin-top: 4px; }
.modal__warning-text  { margin: 0; font-size: 14px; line-height: 1.5; color: var(--color-on-surface-variant); }

.modal__instruction {
    margin: 0 0 20px;
    padding: 14px 16px;
    font-size: 14px;
    line-height: 1.6;
    background: var(--color-primary-75);
    border-left: 3px solid var(--color-primary);
    border-radius: 0 var(--radius-input) var(--radius-input) 0;
}
.modal__list {
    margin: 0 0 20px;
    padding: 16px 18px 16px 34px;
    background: var(--color-surface-inset, var(--color-neutral-50));
    border: 1px solid var(--color-surface-inset-border, var(--color-outline-variant));
    border-radius: var(--radius-panel);
    font-size: 14px;
    list-style: disc outside;
}
.modal__list li { line-height: 1.7; }
.modal__list strong { font-variant-numeric: tabular-nums; }

/* Typed-confirmation box. Sits between the instruction naming what to
   type and the buttons it unlocks, so the three read in order. */
.modal__expect { display: block; width: 100%; margin: 0 0 20px; font-family: var(--font-mono); }

.modal__field { margin-bottom: 20px; }
.modal__label { display: block; margin-bottom: 6px; font-size: 14px; font-weight: 600; }
.modal__field--row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.modal__field--row .modal__label { margin-bottom: 0; }
.modal__hint {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--color-on-surface-variant);
}
.modal__actions { display: flex; justify-content: flex-end; gap: 12px; flex-wrap: wrap; }

/* ---- Form-modal variant ------------------------------------------- */
.modal--form { max-width: 620px; padding: 0; }
.modal__header {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 26px 30px 20px;
    border-bottom: 1px solid var(--color-outline-variant);
}
.modal__head-text { flex: 1; min-width: 0; }
.modal--form .modal__title   { margin: 0 0 6px; font-size: 24px; }
.modal--form .modal__message { margin: 0; font-size: 14px; }
.modal__close {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--radius-input);
    cursor: pointer;
    color: var(--color-on-surface-variant);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.modal__close:hover { background: var(--color-neutral-100); color: var(--color-on-surface); }
.modal__close > svg { width: 16px; height: 16px; }

.modal__body { padding: 26px 30px; }
.modal--form .modal__actions {
    padding: 20px 30px 26px;
    border-top: 1px solid var(--color-outline-variant);
}
.modal__error {
    margin: 0 30px 16px;
    padding: 12px 16px;
    border-radius: var(--radius-input);
    background: var(--color-error-50);
    border: 1px solid var(--color-error-200);
    color: var(--color-error-600);
    font-size: 14px;
    line-height: 1.5;
}


/* =============================================
   Fast tooltip — `.app-tooltip` portaled to <body>
   ---------------------------------------------
   Driven by the handler in app.js: one <div> on document.body,
   re-positioned on mouseover of any element with `data-tip="…"`. Living
   on body means the tip escapes every overflow container, so a long tip
   can run wider than the button's parent and still be fully visible. The
   handler also surfaces tips on [disabled] buttons, which is exactly when
   an operator most needs the "why is this disabled?" hint.

   Usage: `<button data-tip="Helpful label">…</button>`. ~120ms delay.
   ============================================= */
.app-tooltip {
    position: fixed;
    z-index: 10001;
    top: -9999px;
    left: -9999px;
    padding: 8px 12px;
    background: var(--color-secondary-800);
    color: #fff;
    border-radius: 8px;
    font-size: 13px;
    line-height: 1.4;
    max-width: 320px;
    white-space: normal;
    word-wrap: break-word;
    box-shadow: var(--shadow-pop);
    opacity: 0;
    pointer-events: none;
    transition: opacity 120ms ease;
}
.app-tooltip--visible { opacity: 1; }
.app-tooltip::after {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
}
.app-tooltip[data-placement="top"]::after {
    bottom: -4px;
    left: 50%;
    transform: translateX(-50%);
    border-top: 5px solid var(--color-secondary-800);
}
.app-tooltip[data-placement="bottom"]::after {
    top: -4px;
    left: 50%;
    transform: translateX(-50%);
    border-bottom: 5px solid var(--color-secondary-800);
}


/* =============================================
   Narrow viewports
   ---------------------------------------------
   One breakpoint, kept in one place. What a small screen needs is a
   decision about the PAGE — which grids collapse, in what order, how much
   gutter is left — and that is impossible to see when it is scattered
   across twenty component blocks.
   ============================================= */
@media (max-width: 760px) {
    /* The header stacks: mark and account on the first line, the nav on
       its own line beneath them. The nav is what has to stay reachable —
       hiding it behind a control the page then has to explain costs more
       than the line it saves. */
    .site-header { padding: 15px 18px 0; row-gap: 14px; }
    .site-nav {
        order: 3;
        width: 100%;
        gap: 20px;
        overflow-x: auto;
        padding-bottom: 12px;
    }
    .site-nav__link { font-size: 13px; }
    .header-note { display: none; }
    /* One step down, both sizes together. The sign-in mark stays well
       above the other because it is the whole header on that screen. */
    .logo                    { width: 110px; }
    .site-header--auth .logo { width: 170px; }

    /* The PUBLIC header — the registration front door. Two things the
       signed-in header's rules above get wrong for it:

       The 0 bottom padding relies on the nav row beneath the mark to hold
       the rule off it, and this header has no nav, so without this the
       dividing rule was drawn hard against the foot of the mark.

       And 110px is a mark sized to leave room for a nav and an account
       block on one line. Here it shares the line with a 13px link and
       nothing else, so it can be the brand at brand size. Scaled with the
       viewport so it reads at 150px on a 400px phone and 170px on a small
       tablet, and it still clears the staff link on a 360px screen. */
    .site-header--public       { padding-bottom: 15px; }
    .site-header--public .logo { width: clamp(140px, 38vw, 170px); }

    .site-main { padding: 28px 18px 45px; }
    /* Stacked, one item per line. Wrapped as a row, the copyright and the
       links shared the first line and the domain dropped to a second on
       its own, which read as a mistake rather than as a layout. */
    .site-footer { flex-direction: column; align-items: flex-start; gap: 10px;
                   font-size: 12px; padding: 20px 18px 28px; }
    .site-footer__links { gap: 18px; }

    h1, .text-display { font-size: 36px; }
    .page-title { font-size: 29px; }
    .page-head { align-items: flex-start; }

    .layout { grid-template-columns: 1fr; gap: 16px; }
    .layout__aside h1,
    .layout__aside .page-title { font-size: 33px; margin-bottom: 10px; }

    .card { padding: 21px; }
    .form-grid, .detail-grid { grid-template-columns: 1fr; gap: 17px; }
    .stats { grid-template-columns: 1fr 1fr; gap: 10px; }
    .stat { padding: 14px; }
    .stat strong { font-size: 30px; }

    .tabs { gap: 8px; }
    .tab  { padding: 9px 15px; }

    .actions { flex-wrap: wrap; }
    .modal { padding: 22px; }
    .modal__header { padding: 22px 22px 18px; }
    .modal__body { padding: 22px; }
    .modal--form .modal__actions { padding: 18px 22px 22px; }
    .modal__error { margin: 0 22px 14px; }

    .toast-container { left: 18px; right: 18px; bottom: 18px; max-width: none; }
}


/* =============================================
   Short viewports — laptops, not phones
   ---------------------------------------------
   The width breakpoint above asks "is this a phone". This one asks a
   different question: "is there room". A 14-inch laptop is a wide screen
   with a SHORT one — around 610-780px of viewport once browser chrome is
   accounted for — and the generous vertical rhythm this design uses at full
   size costs 320px of header, main padding and footer before a single word
   of content appears. On a 27-inch monitor that framing is the point of the
   design. On a laptop it is the reason a two-paragraph page scrolls.

   So the spacing compacts on HEIGHT, independently of width. Nothing here
   changes a type size that carries meaning, reflows a layout, or hides
   anything — it takes back the air, which is the thing there is least of.
   ============================================= */
@media (max-height: 900px) {

    /* THE MARK IS DELIBERATELY NOT IN HERE. It is the biggest single item
       in the header and the obvious thing to shrink, and these tiers used
       to — down to 110px here and 95px below, which is what a 14-inch
       laptop actually got. But it is the brand, on the page a visitor
       lands on, and a logo that changes size with the window reads as a
       rendering fault rather than as a considerate use of space. The
       padding around it gives back most of the same pixels without
       touching it. */
    .site-header  { padding: 14px var(--shell-pad); }
    .site-main    { padding: 28px var(--shell-pad) 36px; }
    .site-footer  { padding: 14px var(--shell-pad); }

    /* Components whose whitespace is decoration rather than structure. */
    .card         { padding: 22px; }
    .steps        { margin-bottom: 24px; }
    .medallion    { width: 48px; height: 48px; font-size: 24px; margin-bottom: 16px; }

    /* The terms box is a fixed height on purpose (see .scroll-region), so
       it cannot shrink to fit its page — it has to be told to. Still about
       nine lines, and still unmistakably a scrolling region. */
    .scroll-region { height: 220px; margin: 16px 0; }
}

/* A second tier, for the laptop this was actually reported on: a 14-inch
   screen leaves roughly 610-780px of viewport. Everything below is the same
   idea as the tier above, pushed one step further — spacing only. The type
   sizes that carry meaning (a heading's rank, a label against its hint) keep
   their relationships; what shrinks is the room around them. */
@media (max-height: 780px) {

    /* The mark keeps its size here too — see the tier above. */
    .site-header   { padding: 10px var(--shell-pad); }
    .site-main     { padding: 20px var(--shell-pad) 24px; }
    .site-footer   { padding: 10px var(--shell-pad); }

    .card          { padding: 18px; }
    .steps         { margin-bottom: 16px; }
    .actions       { margin-top: 16px; }
    .notice        { padding: 12px 16px; }
    .demo-help     { padding: 10px 14px; margin: 12px 0; }
    .medallion     { width: 44px; height: 44px; font-size: 22px; margin-bottom: 12px; }
    .section-label { padding-top: 16px; margin: 18px 0 14px; }
    .form-grid     { gap: 16px; }
    .field         { margin-bottom: 14px; }

    /* Still seven or eight lines of terms, and still obviously a box that
       scrolls — which is the only thing its height has to communicate. */
    .scroll-region { height: 175px; margin: 12px 0; }
}
