/*
 * Base stylesheet. Every value here resolves to a design token (contract item 11):
 * there is no literal colour, radius, spacing or type size below this comment.
 * Regenerate tokens with: node scripts/build-tokens.mjs
 */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--size-100);
    line-height: var(--leading-relaxed);
    color: var(--text);
    background: var(--surface);
}

h1, h2, h3, h4 {
    margin: 0 0 var(--space-075);
    line-height: var(--leading-tight);
    font-weight: var(--weight-semibold);
    color: var(--text);
}

h1 { font-size: var(--size-600); }
h2 { font-size: var(--size-400); }
h3 { font-size: var(--size-300); }

p {
    margin: 0 0 var(--space-100);
    max-width: 68ch;   /* measure, not a magic width: long lines hurt comprehension */
}

a {
    color: var(--interactive);
    text-decoration-thickness: var(--border-1);
    text-underline-offset: var(--underline-offset);
}

a:hover {
    color: var(--interactive-hover);
}

/* A skip target is a destination, not a control.
 *
 * `tabindex="-1"` lets the skip link move focus into <main> without adding it to the tab order.
 * Because activating the link is keyboard-initiated, :focus-visible then matches and draws an
 * outline around the entire page body, which reads as a rendering fault rather than as feedback.
 *
 * WCAG 2.4.7 asks for a visible indicator on interactive components. A container that has just
 * received focus programmatically is not one, and the reader already knows where they are: the
 * page scrolled and the next Tab continues from the content. */
[tabindex="-1"]:focus {
    outline: none;
}

/* Visible focus is an accessibility requirement, not a style preference. */
:focus-visible {
    outline: var(--border-2) solid var(--interactive);
    outline-offset: var(--border-2);
}

/* WHEN SOMEBODY HAS ASKED FOR LESS MOTION, GIVE THEM LESS MOTION (S-000948).
 *
 * `prefers-reduced-motion` is not a guess about a device - it is a preference the reader has set
 * deliberately, at operating-system level, usually because motion makes them ill. Until now this
 * application ignored it completely: there was no `prefers-*` query anywhere in the stylesheet.
 *
 * Three transitions exist, all on `--motion-fast`. Two are colour fades and mild; the
 * third moves the skip link into view, which is real movement, on the one control a keyboard user
 * meets first. None of them is essential to understanding anything, which is exactly the class the
 * preference is about.
 *
 * OVERRIDING THE TOKEN RATHER THAN EACH RULE is what makes this hold for transitions nobody has
 * written yet. A rule-by-rule override is a list that goes stale the first time somebody adds an
 * animation; redefining the duration means the next one inherits the behaviour without knowing
 * this block exists.
 *
 * `01ms` rather than `0s`: a zero-length transition never fires `transitionend`, so anything that
 * waits for that event would hang. This is the widely-used form for that reason. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --motion-fast: 0.01ms;
        --motion-base: 0.01ms;
        --motion-slow: 0.01ms;
    }
}

.skip-link {
    position: absolute;
    left: var(--space-100);
    top: calc(var(--space-100) * -4);
    z-index: var(--layer-modal);
    padding: var(--space-050) var(--space-100);
    background: var(--surface);
    border-radius: var(--radius-md);
    transition: top var(--motion-fast) ease;
}

.skip-link:focus {
    top: var(--space-100);
}

/* ---------------------------------------------------------------- marketing shell */

.marketing {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.marketing__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-100);
    padding: var(--space-100) var(--space-150);
    border-bottom: var(--border-1) solid var(--border);
    background: var(--surface);
    position: sticky;
    top: 0;
    z-index: var(--layer-sticky);
}

.marketing__wordmark {
    font-weight: var(--weight-bold);
    font-size: var(--size-200);
    color: var(--brand-700);
    text-decoration: none;
    letter-spacing: var(--tracking-tight);
}

.marketing__main {
    flex: 1;
}

.wrap {
    width: 100%;
    max-width: var(--width-page);
    margin: 0 auto;
    padding: 0 var(--space-150);

    /* A LONG UNBREAKABLE STRING IS NOT A LAYOUT DECISION, IT IS A REFERENCE NUMBER.
     *
     * At 320px the detail page overflowed by 27px, and nothing on it was individually too wide -
     * it was three separate pieces of content that could not wrap: a heading, the definition list's
     * values, and the file picker. Reference codes, file names and identifiers have no spaces to
     * break at, so a narrow column cannot contain them and the page grows instead.
     *
     * `break-word` rather than `anywhere`: it only breaks a word that would otherwise overflow, so
     * ordinary prose is unaffected and nothing about the reading measure changes. Proved in the
     * live browser before being written here - 27 to 0 on the detail page. */
    overflow-wrap: break-word;
}

.hero {
    padding: var(--space-600) 0 var(--space-400);
    background: linear-gradient(180deg, var(--brand-050), var(--surface));
    border-bottom: var(--border-1) solid var(--border);
}

.hero__lede {
    font-size: var(--size-200);
    color: var(--text-muted);
}

.button {
    display: inline-block;
    padding: var(--space-075) var(--space-150);
    border-radius: var(--radius-md);
    font-weight: var(--weight-semibold);
    font-size: var(--size-100);
    text-decoration: none;

    /* A TRANSPARENT BORDER THAT IS LOAD-BEARING, AND LOOKS EXACTLY LIKE A NO-OP (S-000949).
     *
     * In Windows High Contrast Mode - `forced-colors: active` - the browser DISCARDS author
     * colours and repaints everything from the system palette. A filled button loses its
     * background, so a button styled only by `background` becomes indistinguishable from the text
     * around it: the affordance disappears for the readers who most need it to be obvious.
     *
     * A border reserved here, transparent in the default state, is repainted by the system as a
     * visible outline. That is the whole reason it exists, and nothing about the rule says so - it
     * reads as a property doing nothing, which is precisely what somebody tidying would delete.
     *
     * Measured on the deployed site rather than assumed: with forced colours off, the primary
     * button's border is `rgba(0, 0, 0, 0)`; with them on, the same border computes to a solid
     * system colour while the background goes transparent. J-46 asserts both states. */
    border: var(--border-1) solid transparent;
    cursor: pointer;
    transition: background var(--motion-fast) ease, color var(--motion-fast) ease;
}

.button--primary {
    background: var(--interactive);
    color: var(--text-inverse);
}

.button--primary:hover {
    background: var(--interactive-hover);
    color: var(--text-inverse);
}

.button--quiet {
    background: transparent;
    color: var(--interactive);
    border-color: var(--border-strong);
}

.section {
    padding: var(--space-400) 0;
}

.section--sunken {
    background: var(--surface-sunken);
    border-block: var(--border-1) solid var(--border);
}

.grid {
    display: grid;
    gap: var(--space-150);
    grid-template-columns: repeat(auto-fit, minmax(var(--width-sidebar), 1fr));
}

.card {
    padding: var(--space-150);
    background: var(--surface);
    border: var(--border-1) solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-1);
}

.card h3 {
    font-size: var(--size-200);
    margin-bottom: var(--space-050);
}

.card p {
    margin: 0;
    color: var(--text-muted);
    font-size: var(--size-075);
}

.marketing__foot {
    padding: var(--space-200) 0 var(--space-300);
    background: var(--surface-inverse);
    color: var(--text-inverse);
    font-size: var(--size-075);
}

.marketing__foot a {
    color: var(--brand-100);
}

.marketing__foot p {
    color: var(--brand-100);
}

.regulatory {
    font-size: var(--size-050);
    line-height: var(--leading-snug);
    color: var(--brand-100);
}

/* ---------------------------------------------------------------- icons */

.icon {
    display: inline-block;
    vertical-align: middle;
    flex: none;
}

/* ---------------------------------------------------------------- floating action buttons */

.fab {
    position: fixed;
    right: var(--space-150);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--space-300);
    height: var(--space-300);
    border: var(--border-1) solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--interactive);
    box-shadow: var(--shadow-2);
    cursor: pointer;
    z-index: var(--layer-fab);
    transition: background var(--motion-fast) ease, color var(--motion-fast) ease;
}

.fab:hover {
    background: var(--interactive);
    color: var(--text-inverse);
}

/* Stacked from the bottom so a second button (feedback, S-000702) sits above without moving this
   one - a control that changes position when a sibling appears is a control people misclick. */
.fab--help {
    bottom: var(--space-150);
}

/* ---------------------------------------------------------------- contextual help panel */

.help-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(var(--width-panel), 100vw);
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-left: var(--border-1) solid var(--border);
    box-shadow: var(--shadow-3);
    z-index: var(--layer-panel);
}

.help-panel__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-075);
    padding: var(--space-100) var(--space-150);
    border-bottom: var(--border-1) solid var(--border);
}

.help-panel__title {
    margin: 0;
    font-size: var(--size-200);
}

.help-panel__close {
    display: inline-flex;
    padding: var(--space-050);
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}

.help-panel__close:hover {
    color: var(--text);
    background: var(--surface-sunken);
}

.help-panel__body {
    padding: var(--space-150);
    overflow-y: auto;
    font-size: var(--size-075);
    line-height: var(--leading-relaxed);
}

.help-panel__subheading {
    margin-top: var(--space-150);
    font-size: var(--size-100);
}

.help-panel__body ul {
    padding-left: var(--space-150);
}

.help-panel__body li {
    margin-bottom: var(--space-050);
}

/* ---------------------------------------------------------------- release notes */

.notes {
    list-style: none;
    margin: var(--space-200) 0 var(--space-400);
    padding: 0;
    display: grid;
    gap: var(--space-150);
}

.notes__current {
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-left: var(--space-025) solid var(--interactive);
    border-radius: var(--radius-md);
}

.notes__empty {
    padding: var(--space-150);
    background: var(--warning-100);
    border-radius: var(--radius-md);
    color: var(--text);
}

/* The line that tells a reader how much of the history they are looking at. Muted, because it is
   context rather than content: it should be findable when wanted and ignorable otherwise. */
.notes__scope {
    color: var(--text-muted);
    font-size: var(--size-075);
    margin-bottom: var(--space-150);
}

/* The way to the rest of the history. Wraps rather than scrolling sideways, because at 320px three
   items in a row do not fit and a page-level horizontal scroll is the thing J-43 exists to prevent.
   space-between keeps "newer" and "older" at the two ends whether or not both are present, so the
   position of a control does not move as a reader walks through the pages. */
.notes__pages {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-075);
    margin-top: var(--space-200);
}

.notes__page-of {
    color: var(--text-muted);
    font-size: var(--size-075);
}

.notes__entry {
    padding: var(--space-150);
    background: var(--surface);
    border: var(--border-1) solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-1);
}

.notes__version {
    font-family: var(--font-family-mono);
    font-size: var(--size-300);
    margin-bottom: var(--space-025);
}

.notes__when {
    margin: 0 0 var(--space-100);
    font-size: var(--size-075);
    color: var(--text-muted);
}

.notes__body {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: var(--font-sans);
    font-size: var(--size-075);
    line-height: var(--leading-relaxed);
    color: var(--text);
}

/* ---------------------------------------------------------------- repayment calculator */

.calc {
    padding: var(--space-200);
    background: var(--surface);
    border: var(--border-1) solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2);
    max-width: var(--width-reading);
}

.calc h3 {
    margin-bottom: var(--space-150);
}

.calc__controls {
    display: grid;
    gap: var(--space-150);
    margin-bottom: var(--space-200);
}

.calc__field label {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-075);
    font-weight: var(--weight-medium);
    margin-bottom: var(--space-050);
}

.calc__value {
    /* Monospace so digits hold their column as the slider moves and the value does not jitter. */
    font-family: var(--font-family-mono);
    font-size: var(--size-200);
    font-weight: var(--weight-semibold);
    color: var(--interactive);
}

.calc__field input[type="range"] {
    width: 100%;
    accent-color: var(--interactive);
    cursor: pointer;
}

.calc__hint {
    margin: var(--space-025) 0 0;
    font-size: var(--size-050);
    color: var(--text-muted);
}

.calc__pending {
    /* Says why the controls above are inert. Deliberately NOT muted: it is the only thing on the
       screen that explains a control the page has just told the reader to use, and for a visitor
       whose circuit never attaches it is the permanent state rather than a passing one. Muted
       styling here would hide the explanation exactly where it is needed most. */
    margin: 0 0 var(--space-150);
    padding: var(--space-075) var(--space-100);
    font-size: var(--size-075);
    line-height: var(--leading-snug);
    background: var(--surface-sunken);
    border-inline-start: var(--border-3) solid var(--border);
    border-radius: var(--radius-sm);
}

.calc__results {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--size-control), 1fr));
    gap: var(--space-100);
    margin: 0 0 var(--space-150);
    padding: var(--space-150);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
}

.calc__result dt {
    font-size: var(--size-075);
    color: var(--text-muted);
    margin-bottom: var(--space-025);
}

.calc__result dd {
    margin: 0;
    font-family: var(--font-family-mono);
    font-size: var(--size-300);
    font-weight: var(--weight-semibold);
}

.calc__result--lead dd {
    font-size: var(--size-400);
    color: var(--interactive);
}

.calc__basis {
    margin: 0 0 var(--space-075);
    font-size: var(--size-075);
    color: var(--text-muted);
}

.calc__disclaimer {
    /* A regulated financial-promotion disclaimer. Small, but never hidden, never collapsed and
       never lighter than the muted text colour: burying it is how a promotion becomes misleading. */
    margin: 0;
    font-size: var(--size-050);
    line-height: var(--leading-snug);
    color: var(--text-muted);
    max-width: none;
}

#blazor-error-ui {
    display: none;
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: var(--layer-modal);
    padding: var(--space-075) var(--space-150);
    background: var(--warning-100);
    color: var(--text);
    box-shadow: var(--shadow-3);
}

/* The reload link in the connection-error banner. Rendered by both layouts and, until v0.26.0,
 * styled by nothing: it fell back to a default browser link inside a warning-coloured bar. Found
 * by UnstyledMarkupTests on its first run. */
#blazor-error-ui .reload {
    color: var(--text);
    font-weight: 600;
    margin-inline-start: var(--space-050);
    text-underline-offset: var(--underline-offset);
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: var(--space-075);
    top: var(--space-050);
}

/* ---------------------------------------------------------------- signed-in application shell
 *
 * MainLayout renders .app-shell / .app-shell__nav / .app-shell__main, and until v0.25.0 none of
 * them had any styling: the layout inherited from the Blazor template targeted .page/.sidebar,
 * which the markup stopped using, and nothing replaced it. The signed-in surface was an unstyled
 * document flow. It went unnoticed because the surface is behind sign-in and every automated
 * journey that runs today is anonymous.
 *
 * Deliberately plain. The navigation is generated from the capability catalogue in S-000501, so
 * anything elaborate here would be rewritten within a tick.
 */
.app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.app-shell__nav {
    border-bottom: var(--border-1) solid var(--border);
    background: var(--surface-sunken);
    padding: var(--space-075) var(--space-100);
}

.app-shell__main {
    flex: 1;
    padding: var(--space-150) var(--space-100);
}

/* WRAPS, AND THE MISSING KEYWORD COST 90 PIXELS ON EVERY SIGNED-IN PAGE (S-000947, J-44).
 *
 * Below 641px this is a horizontal row, and without `flex-wrap` a flex row does not wrap: it
 * overflows. At 320px the navigation ran to 410px, so EVERY signed-in surface scrolled sideways by
 * 90px regardless of what was on it - a constant tax paid by the shell, underneath whatever the
 * page itself did.
 *
 * It went unseen for the reason J-43 recorded and then only half-fixed: no journey rendered a
 * SIGNED-IN surface at any width but 1280. J-43 closed the anonymous half.
 *
 * `gap` already applies to both axes, so wrapped rows space themselves. */
.nav-shell ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-100);
    list-style: none;
    margin: 0;
    padding: 0;
}

/* A table that scrolls in its own right rather than widening the document (S-000947).
 *
 * WCAG 2.1 SC 1.4.10 (Reflow) forbids the PAGE needing two scroll directions and explicitly allows
 * a table to be an exception. So the fix is a container, not a redesign of a data table into cards -
 * which would also have been a redesign of something nobody has complained about.
 *
 * `max-width: 100%` is what makes it work: without it the container grows to the table's intrinsic
 * width and scrolls nothing.
 *
 * The focus ring is deliberate. This region is focusable so a keyboard user can scroll it at all
 * (SC 2.1.1), and a focusable thing that shows no focus is SC 2.4.7 traded for SC 2.1.1. */
.table-scroll {
    max-width: 100%;
    overflow-x: auto;

    /* POSITIONED, AND WITHOUT THIS THE CONTAINER CLIPS NOTHING THAT MATTERS.
     *
     * The Actions column header carries a `.visually-hidden` label, which is `position: absolute`.
     * With no positioned ancestor its containing block is the initial one, so it escaped this
     * scroll container entirely and sat at the table's full width - and the document grew to reach
     * it. Measured: the page overflowed by exactly 313px while its right edge was at 633px on a
     * 320px viewport, and every other wide element reported itself correctly clipped.
     *
     * So the screen-reader-only label, whose entire purpose is to be invisible, was the thing
     * making the page too wide for everybody. Proved by setting this one property in the live
     * browser and re-measuring: 313 to 0. */
    position: relative;
}

.table-scroll:focus-visible {
    outline: var(--border-2) solid var(--interactive);
    outline-offset: var(--border-2);
}

.nav-shell a {
    color: var(--text-muted);
    text-decoration: none;
    font-weight: 500;
}

.nav-shell a:hover,
.nav-shell a.active {
    color: var(--interactive);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

/* Side-by-side once there is room. The literal is required here: a custom property is invalid in
 * a media condition. The value is recorded as breakpoint.regular-min in the token source. */
@media (min-width: 641px) {
    .app-shell {
        flex-direction: row;
    }

    .app-shell__nav {
        width: var(--width-sidebar);
        border-bottom: 0;
        border-right: var(--border-1) solid var(--border);
        padding: var(--space-150) var(--space-100);
    }

    .nav-shell ul {
        flex-direction: column;
        gap: var(--space-050);
    }

    .app-shell__main {
        padding: var(--space-200);
    }
}

/* ---------------------------------------------------------------------------------------------
   Capability exposure (staff-only administration surface, S-000501)

   Every value resolves through a design token (contract item 11). The table is the only one in the
   application so far, so its rules are deliberately local to this block rather than a global
   `table` style that would then apply to tables nobody has designed yet.
   --------------------------------------------------------------------------------------------- */

.exposure__lede {
    max-width: var(--width-reading);
    color: var(--text-muted);
    margin-bottom: var(--space-200);
}

/* Loading and empty read identically to a scanner and mean opposite things to a person, so they
   share one style deliberately: the DIFFERENCE is carried by the words, which is where a reader
   actually looks. Styling them apart would imply a distinction the colour cannot express. */
.exposure__state {
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    margin-bottom: var(--space-150);
}

/* What the client experiences, stated beside the control that causes it. NOT muted, unlike the
   state messages above: this is the one thing on the card that changes what the person does next,
   and a reader who skims past it will not make the phone call. No warning colour either - granting
   a capability is ordinary work, and an alarm would misdescribe it. */
.exposure__consequence {
    max-width: 60ch;
    margin: 0 0 var(--space-100);
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    line-height: var(--leading-relaxed);
}

/* Subordinate to the h2 above it, because it is the far end of the SAME list rather than a new
   question. Sizing it like a peer would read as a third independent finding on a page whose whole
   structure is "each list says which question it answers". */
.exposure__subheading {
    margin: var(--space-200) 0 var(--space-075);
    font-size: var(--size-200);
}

.exposure__field {
    display: block;
    margin-bottom: var(--space-100);
    font-weight: var(--weight-semibold);
}

.exposure__field select,
.exposure__field input {
    display: block;
    margin-top: var(--space-050);
    padding: var(--space-075);
    border: var(--border-1) solid var(--border-strong);
    border-radius: var(--radius-md);
    font-size: var(--size-100);
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
}

.exposure {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: var(--space-200);
}

.exposure__caption {
    text-align: left;
    color: var(--text-muted);
    padding-bottom: var(--space-075);
}

.exposure th,
.exposure td {
    text-align: left;
    padding: var(--space-075);
    border-bottom: var(--border-1) solid var(--border);
}

.exposure th {
    font-weight: var(--weight-semibold);
    color: var(--text-muted);
}

.exposure__row td {
    vertical-align: middle;
}

.exposure__grant {
    max-width: var(--width-reading);
}

.exposure__grant h2 {
    font-size: var(--size-200);
    margin-bottom: var(--space-100);
}

/* The domain refuses several operations on purpose and its messages explain why at length, so this
   is sized to be read rather than glanced at. */
.exposure__problem {
    margin-top: var(--space-150);
    padding: var(--space-100) var(--space-150);
    max-width: var(--width-reading);
    background: var(--surface-sunken);
    border-left: var(--border-3) solid var(--negative);
    border-radius: var(--radius-md);
    color: var(--text);
}

/* "not withdrawn" in the withdrawal column: present, and quieter than the names beside it, because
   it is the absence of an event rather than one. */
.exposure__none {
    color: var(--text-muted);
    font-style: italic;
}

/* The second FAB, stacked above the help button exactly as that block anticipated. Help stays put
   when this appears, because a control that moves when a sibling arrives is one people misclick. */
.fab--feedback {
    bottom: calc(var(--space-150) + var(--space-300) + var(--space-075));
}

.feedback__note {
    display: block;
    width: 100%;
    margin-top: var(--space-050);
    padding: var(--space-075);
    border: var(--border-1) solid var(--border-strong);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--size-100);
    background: var(--surface);
    color: var(--text);
}

/* What is sent without being typed, and what is not available yet. Quieter than the field it sits
   under, because it is context rather than an instruction. */
.feedback__captured {
    margin-top: var(--space-075);
    color: var(--text-muted);
    font-size: var(--size-075);
}

/* The attachment area, set apart from the note so the picker does not read as part of the sentence
   above it. */
/* THE DOCUMENTS BLOCK SHARES THESE RULES AND NOT THEIR NAMES (v1.135.0). The application-documents
   list and its attach control wore `feedback__*` names because they look the same and the styles
   were already written. Two costs, and the second is the one that bit: a payslip attached to a
   credit application is not feedback, and every selector on those names is AMBIGUOUS the moment the
   feedback panel is open - which is how a journey comes to set a file on the wrong input and fail
   with nothing to say. Same defect as borrowing `calc__figures` at v1.122.0, with more reach.

   One declaration, two names: the blocks genuinely look alike, so copying the rules would create a
   second place for them to drift. */
.feedback__attach {
    margin-top: var(--space-100);
    padding-top: var(--space-100);
    border-top: var(--border-1) solid var(--border);
}

.feedback__attach-label,
.documents__attach-label {
    display: block;
    font-weight: var(--weight-medium);
}

.feedback__file,
.documents__file {
    display: block;
    margin-top: var(--space-050);
    font-family: inherit;
    font-size: var(--size-075);
    color: var(--text);

    /* A file input has an INTRINSIC width the browser chooses - wide enough for its button and its
     * "no file chosen" text - and it does not shrink to its column on its own. On a 320px screen
     * that was part of the 27px the detail page overflowed by. Both file pickers get it, because
     * the feedback panel is narrower still. */
    max-width: 100%;
}

/* Photograph this page. Sits with the picker rather than beside the send button, because it is one
   of two ways to attach the same thing and separating them would read as two different actions. */
.feedback__photograph {
    display: inline-flex;
    align-items: center;
    gap: var(--space-050);
    margin-top: var(--space-075);
}

/* What is currently attached. A list rather than a count, because somebody who cannot see WHICH
   files are staged cannot tell a duplicate from a missing one. */
.feedback__staged,
.documents__list {
    margin-top: var(--space-075);
    padding: 0;
    list-style: none;
}

.feedback__staged-item,
.documents__item {
    display: flex;
    gap: var(--space-050);
    align-items: center;
    padding: var(--space-050) var(--space-075);
    margin-bottom: var(--space-050);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    font-size: var(--size-075);
}

/* The size sits between the name and the remove control, and pushes the control to the right edge
   so it lands in the same place on every row. A target that moves per row is one people misclick. */
.feedback__staged-size,
.documents__size {
    margin-left: auto;
    color: var(--text-muted);
}

.feedback__staged-remove {
    display: inline-flex;
    padding: var(--space-025);
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}

.feedback__staged-remove:hover {
    color: var(--negative);
}

/* Files that were turned away, named one by one. Marked in the negative colour because this is the
   moment somebody would otherwise assume their picture went with their words. */
.feedback__refused {
    margin-top: var(--space-075);
    padding: var(--space-075);
    list-style: none;
    background: var(--surface-sunken);
    border-left: var(--border-3) solid var(--negative);
    border-radius: var(--radius-md);
    font-size: var(--size-075);
}

/* The confirmation carries a reference, so a silent close cannot be mistaken for a failed send. */
.feedback__done {
    padding: var(--space-100);
    background: var(--surface-sunken);
    border-left: var(--border-3) solid var(--positive);
    border-radius: var(--radius-md);
}

/* Somebody else's words, set apart from the columns around them so a reader can tell what was
   reported from what the system recorded about the report. */
.feedback__quoted {
    max-width: var(--width-reading);
    white-space: pre-wrap;
}

/* The fault pages: /Error and /not-found.

   Styled at v1.85.0, when they were rewritten from the .NET template. They are the two pages a
   reader reaches in the worst state, so the type is set larger than body copy and the reference is
   set apart - somebody reading it is usually copying it out by hand, often onto paper. */
.fault__lead {
    max-width: 60ch;
    font-size: var(--size-200);
    color: var(--text);
}

.fault__reference {
    max-width: 60ch;
    margin-top: var(--space-150);
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-left: var(--space-025) solid var(--interactive);
    border-radius: var(--radius-md);
}

.fault__next {
    max-width: 60ch;
    padding-left: var(--space-150);
    color: var(--text);
}

.fault__next li {
    margin-bottom: var(--space-050);
}

.fault__away {
    margin-top: var(--space-200);
}

/* The application form (S-001203). Deliberately plain: this is the page where a decorative flourish
   reads as a promise, and every reassuring embellishment on a lending form is a representation
   about credit made by a system that has assessed nothing. */
.apply__lede {
    max-width: 60ch;
    font-size: var(--size-200);
    color: var(--text-muted);
}

.apply__field {
    display: block;
    max-width: 40ch;
    margin-bottom: var(--space-100);
    font-weight: var(--weight-medium);
}

.apply__input {
    display: block;
    width: 100%;
    margin-top: var(--space-050);
    padding: var(--space-050) var(--space-075);
    font-family: inherit;
    font-size: var(--size-100);
    color: var(--text);
    background: var(--surface);
    border: var(--border-1) solid var(--border-strong);
    border-radius: var(--radius-md);
}

.apply__captured {
    max-width: 60ch;
    color: var(--text-muted);
    font-size: var(--size-075);
}

.apply__state {
    max-width: 60ch;
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    color: var(--text);
}

/* Explains the one-word state above it. NOT muted: it is the answer to the question the page was
   opened with, and the state on its own does not give it. Sunken like the other statements on this
   page so it reads as part of the record rather than as an aside somebody added. */
.apply__meaning {
    max-width: 60ch;
    margin: var(--space-100) 0 0;
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    line-height: var(--leading-relaxed);
}

.apply__done {
    max-width: 60ch;
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-left: var(--space-025) solid var(--interactive);
    border-radius: var(--radius-md);
    color: var(--text);
}

/* What to do if the application just sent is wrong. Quieter than .apply__done - it is guidance
   rather than the confirmation itself - but NOT muted: it is the one thing on this screen a person
   acts on, and only if they read it. No warning colour either: making a mistake is ordinary, and
   dressing the remedy as an alarm would tell somebody they have done something wrong when they have
   only noticed a typo. */
.apply__correction {
    max-width: 60ch;
    padding: var(--space-100) var(--space-150);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    line-height: var(--leading-relaxed);
}

.apply__problem {
    max-width: 60ch;
    color: var(--negative);
    font-weight: var(--weight-medium);
}

/* The form's own container, which exists so the page can say whether it is live yet. A prerendered
   Blazor page discards anything typed before the circuit connects, so the fields are disabled until
   it does - and this attribute is what the journeys wait for rather than guessing at a delay. */
.apply__form {
    display: block;
}

/* The list of what somebody has asked for (S-001204). Shares the shape of the staff table rather
   than inventing a second one: two tables that look different for no reason make a reader wonder
   which convention applies where. */
.applications {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: var(--space-200);
}

.applications__caption {
    text-align: left;
    color: var(--text-muted);
    padding-bottom: var(--space-075);
}

.applications th,
.applications td {
    text-align: left;
    padding: var(--space-075) var(--space-100);
    border-bottom: var(--border-1) solid var(--border);
    vertical-align: top;
}

.applications th {
    font-weight: var(--weight-semibold);
    color: var(--text);
    background: var(--surface-sunken);
}

.applications__row td {
    color: var(--text);
}

/* A label for assistive technology only. The actions column needs a header - a table with an
   unlabelled column reads as a structural error to a screen reader - and a visible one would be a
   word doing no work for anybody who can see the buttons beneath it. */
.visually-hidden {
    position: absolute;
    width: var(--border-1);
    height: var(--border-1);
    padding: 0;
    margin: calc(var(--border-1) * -1);
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* One application in detail. A description list rather than a table: a table implies a set of
   comparable things and this is one thing described, which is the difference a screen reader
   announces. */
.detail {
    display: grid;
    grid-template-columns: minmax(0, var(--width-sidebar)) minmax(0, 1fr);
    gap: var(--space-075) var(--space-150);
    max-width: var(--width-reading);
    margin-bottom: var(--space-200);
}

.detail dt {
    font-weight: var(--weight-semibold);
    color: var(--text);
}

.detail dd {
    margin: 0;
    color: var(--text);
}

/* The consent notice (S-001301). Shown in full rather than behind a link, so it needs to read as
   something to be read rather than as fine print - the type is the body size, not smaller. */
.consent {
    max-width: var(--width-reading);
    margin-bottom: var(--space-150);
    padding: var(--space-100) var(--space-150);
    border: var(--border-1) solid var(--border-strong);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
}

.consent__legend {
    padding: 0 var(--space-050);
    font-weight: var(--weight-semibold);
    color: var(--text);
}

/* What the stored consent text IS (v1.358.0). Quieter than the notice it introduces: it explains
   the thing below it rather than being the thing, and equal weight would read as part of the
   agreement. Tokens only, per item 11. */
.consent__provenance {
    max-width: var(--width-reading);
    margin-bottom: var(--space-075);
    color: var(--text-muted);
    font-size: var(--size-075);
    line-height: var(--leading-relaxed);
}

.consent__text {
    margin-bottom: var(--space-100);
    color: var(--text);
}

.consent__agree {
    display: flex;
    align-items: baseline;
    gap: var(--space-050);
    font-weight: var(--weight-medium);
    color: var(--text);
}

/* The consent shown back on an application (S-001302). Muted, because it is a record rather than
   something to act on - but the text itself keeps the body size, since it is the evidence. */
.consent__meta {
    max-width: var(--width-reading);
    color: var(--text-muted);
    font-size: var(--size-075);
}

/* What has been sent to an applicant about one application (S-001501). A plain list rather than a
   table: two facts per row and no column anybody would compare down. The subject keeps body size
   and full contrast because it is what the person actually received; the timestamp is muted,
   matching the consent record directly above, because it locates the message rather than being it. */
.notices {
    max-width: var(--width-reading);
    margin: 0 0 var(--space-100);
    padding: 0;
    list-style: none;
}

.notices__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-025) var(--space-075);
    padding: var(--space-050) 0;
    border-bottom: var(--border-1) solid var(--border);
}

.notices__row:last-child {
    border-bottom: none;
}

.notices__subject {
    color: var(--text);
    font-weight: var(--weight-medium);
}

.notices__when {
    color: var(--text-muted);
    font-size: var(--size-075);
}

/* Taking back an agreement (S-001303). Its own names rather than the consent's, and that is not
   tidiness: reusing `consent__meta` for the consequence warning made J-32's existing, correct
   assertion ambiguous, and the right fix was to name the element for what it is rather than to
   weaken a test that was doing its job. A consequence warning is not metadata about a consent. */
/* Who else can see the list, on the applications page (v1.354.0). Quieter than the lede it
   follows: it answers a worry rather than describing the page, and giving it equal weight would
   make a reassurance read as a warning. Tokens only, per item 11. */
.applications__privacy {
    max-width: var(--width-reading);
    margin-bottom: var(--space-100);
    color: var(--text-muted);
    font-size: var(--size-075);
    line-height: var(--leading-relaxed);
}

.withdrawal__consequence {
    max-width: var(--width-reading);
    margin-top: var(--space-050);
    color: var(--text-muted);
    font-size: var(--size-075);
}

.withdrawal__meta {
    max-width: var(--width-reading);
    margin-top: var(--space-100);
    color: var(--text-muted);
    font-size: var(--size-075);
}

/* Body size and full contrast, matching .consent__text, because this is evidence of what the
   person was told when they exercised a right - not a footnote about it. */
.withdrawal__text {
    max-width: var(--width-reading);
    margin-bottom: var(--space-100);
    color: var(--text);
}

/* A control belonging to one row of a list (S-001404). Smaller because it acts on that item rather
   than on the page, and quiet because withdrawing a document is a correction, not something the
   page is inviting somebody to do. */
.button--small {
    padding: var(--space-025) var(--space-050);
    font-size: var(--size-075);
}

/* The attach control and its limits, grouped so the page can say whether the circuit is live
   (S-001404). Presentational only - the grouping exists to carry `data-interactive`. */
.documents__attach {
    display: block;
}

/* What a staff action just did (S-000741). Styled like the applicant's confirmation, because it is
   the same thing on a different surface: the outcome of something somebody chose to do. */
.exposure__done {
    max-width: var(--width-reading);
    margin-bottom: var(--space-075);
    color: var(--text);
    font-weight: var(--weight-medium);
}

/* The cost illustration on the application form (S-001004). Set apart from the fields, because it
   is the consequence of the answers rather than another question - and quiet, because a figure
   styled like a headline on an application form reads as an offer. */
.apply__illustration {
    max-width: var(--width-reading);
    margin-bottom: var(--space-100);
    padding: var(--space-075);
    border: var(--border-1) solid var(--border);
    border-radius: var(--radius-md);
}

/* WHY THE FIGURES ARE ABSENT, on the application form (v1.352.0). Deliberately quieter than the
   illustration it stands in for: it is an explanation, not a result, and giving it the same weight
   would make an out-of-range entry look like an outcome. Sunken rather than bordered for the same
   reason - present, readable, and plainly not a figure.

   Every value is a token. Item 11 allows no hardcoded colour, radius or spacing anywhere. */
.apply__illustration-absent:empty {
    /* NOTHING TO SAY, SO NOTHING DRAWN. The element stays in the DOM because a live region that
       appears with its message announces nothing; it must collapse rather than leave a box. */
    display: none;
}

.apply__illustration-absent {
    max-width: var(--width-reading);
    margin-bottom: var(--space-100);
    padding: var(--space-075);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    font-size: var(--size-075);
    line-height: var(--leading-relaxed);
}

/* The illustration's figures on the application form (S-001004). A definition list because that is
   what it is: three labelled amounts. Laid out in rows rather than a table, because three pairs do
   not need column alignment and a table here would read as a statement of account. */
.apply__figures {
    margin: 0 0 var(--space-075);
}

.apply__figures dt {
    color: var(--text-muted);
    font-size: var(--size-075);
}

.apply__figures dd {
    margin: 0 0 var(--space-050);
    color: var(--text);
    font-weight: var(--weight-medium);
}
