/* SportDex design system — the one place the look and feel is defined.
 *
 * This file is shared by both applications. It lives outside either project
 * and is linked into each wwwroot by the .csproj, so the public website and
 * the app cannot drift apart. Edit it here; never edit the copies that land
 * in wwwroot/css.
 *
 * It holds tokens, the reset, typography and the primitives that both
 * applications use (buttons, fields, chips, notices, tables). Anything that
 * belongs to one screen stays in that screen's scoped .razor.css.
 *
 * Kept to plain CSS with no framework and no runtime dependency on a font CDN:
 * the app downloads all of this before a member can read their agenda on a
 * phone, and a Dutch club site should not be handing visitor addresses to a
 * font host it does not control.
 */

/* ---------------------------------------------------------------- fonts -- */

/* Archivo, variable weight 400-800, self-hosted. One family does display and
   body both; the weight and the tracking carry the difference. */
@font-face {
    font-family: 'Archivo';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url('fonts/archivo-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
        U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
        U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Archivo';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url('fonts/archivo-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
        U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
        U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
        U+A720-A7FF;
}

/* ---------------------------------------------------------------- tokens -- */

:root {
    color-scheme: light dark;

    /* Brand. Sampled from the logo: the navy of the figure and the orange of
       the check. Everything else is derived from these two. */
    --navy-900: #0a2145;
    --navy-800: #0e2b57;
    --navy-700: #123666;
    --navy-600: #1a4a8a;
    --navy-500: #2563a8;
    --orange-500: #f26f1d;
    --orange-600: #d95f13;
    --orange-100: #fdf0e4;

    /* Ink and paper. The text is navy rather than black, so the page agrees
       with the logo instead of sitting next to it. */
    --ink: #12263f;
    --ink-muted: #5a6b80;
    --ink-subtle: #8a97a8;
    --ink-inverse: #ffffff;

    --surface: #ffffff;
    --surface-sunken: #f5f7fa;
    --surface-raised: #ffffff;
    --surface-brand: var(--navy-700);
    --surface-brand-deep: var(--navy-900);

    --line: #e2e7ef;
    --line-strong: #cbd4e1;

    /* Status. Attendance is the one place colour carries meaning, so it gets
       its own set rather than borrowing the accent. Absent is grey on purpose:
       not being there is not an error. */
    --ok: #157f4e;
    --ok-surface: #e9f5ef;
    --ok-line: #a9d8c1;
    --wait: #8a5a00;
    --wait-surface: #fdf4e3;
    --wait-line: #e7cb8e;
    --bad: #b4232a;
    --bad-surface: #fdecec;
    --bad-line: #f0bcbc;

    /* Interactive. The primary action is the logo's orange with navy ink on
       it: 5.1:1, which white on orange would not be. */
    --action: var(--orange-500);
    --action-hover: var(--orange-600);
    --action-ink: var(--navy-900);
    --link: var(--navy-600);
    --focus: var(--navy-600);

    /* Type scale. Built on a 1.25 ratio, opened up at the display sizes so a
       heading has somewhere to go on a wide screen. */
    --text-xs: 0.75rem;
    --text-sm: 0.8125rem;
    --text-base: 1rem;
    --text-md: 1.0625rem;
    --text-lg: 1.25rem;
    --text-xl: 1.5rem;
    --text-2xl: 1.875rem;
    --text-3xl: clamp(2rem, 1.5rem + 2.2vw, 2.75rem);
    --text-4xl: clamp(2.375rem, 1.5rem + 4vw, 4rem);

    --font: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

    /* Space. A 4px base; the named steps are what layouts should reach for. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4rem;
    --space-9: 6rem;

    /* Radius, by role rather than one value everywhere: controls, cards and
       pills are different kinds of object and should not share a corner. */
    --radius-control: 0.5rem;
    --radius-card: 0.875rem;
    --radius-panel: 1.25rem;
    --radius-pill: 999px;

    --shadow-card: 0 1px 2px rgb(10 33 69 / 6%), 0 10px 28px -14px rgb(10 33 69 / 18%);
    --shadow-pop: 0 24px 56px -24px rgb(10 33 69 / 35%);

    --container: 68rem;
    --measure: 34rem;

    /* Big enough for a thumb at the side of a pitch. */
    --tap: 2.75rem;
}

/* ------------------------------------------------------------------ dark -- */

/* The dark palette, and the two ways a page ends up wearing it: the system
   preference when nobody has chosen, and the reader's own choice when somebody
   has. data-theme on <html> is what carries that choice; theme.js writes it
   before the first paint and remembers it. Nothing on the page reads it except
   these two rules and the switch's three faces further down.
 *
 * The declarations appear twice on purpose. CSS has no way to say "this media
 * query or that selector" in one rule, and the alternatives — a second class to
 * keep in step, or light-dark() in every token — cost either a script the page
 * cannot lose or a browser from the last two years. Two copies of a list of
 * colours is the cheaper price. Change one, change the other. */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) {
        --ink: #e7edf5;
        --ink-muted: #9dabbe;
        --ink-subtle: #7b8a9e;

        --surface: #0b1522;
        --surface-sunken: #0f1b2a;
        --surface-raised: #142235;
        --surface-brand: #0f2549;
        --surface-brand-deep: #081a33;

        --line: #223145;
        --line-strong: #31435c;

        --orange-500: #f5843a;
        --orange-600: #ff9752;
        --orange-100: #2a1a0c;

        --navy-600: #6fa8e8;
        --link: #8cbcf0;
        --focus: #8cbcf0;

        --action: #f5843a;
        --action-hover: #ff9752;
        --action-ink: #1a0d03;

        --ok: #5fd39c;
        --ok-surface: #0f2a20;
        --ok-line: #1f4d3a;
        --wait: #ecc275;
        --wait-surface: #2b2211;
        --wait-line: #574526;
        --bad: #f08a8a;
        --bad-surface: #2e1414;
        --bad-line: #5c2a2a;

        --shadow-card: 0 1px 2px rgb(0 0 0 / 40%), 0 10px 28px -14px rgb(0 0 0 / 60%);
        --shadow-pop: 0 24px 56px -24px rgb(0 0 0 / 70%);
    }
}

/* The same palette, for a reader who asked for dark whatever their device says.
   color-scheme is narrowed along with it so the furniture the browser draws
   itself — scrollbars, date pickers, the caret — agrees with the page. */
:root[data-theme='dark'] {
    color-scheme: dark;

    --ink: #e7edf5;
    --ink-muted: #9dabbe;
    --ink-subtle: #7b8a9e;

    --surface: #0b1522;
    --surface-sunken: #0f1b2a;
    --surface-raised: #142235;
    --surface-brand: #0f2549;
    --surface-brand-deep: #081a33;

    --line: #223145;
    --line-strong: #31435c;

    --orange-500: #f5843a;
    --orange-600: #ff9752;
    --orange-100: #2a1a0c;

    --navy-600: #6fa8e8;
    --link: #8cbcf0;
    --focus: #8cbcf0;

    --action: #f5843a;
    --action-hover: #ff9752;
    --action-ink: #1a0d03;

    --ok: #5fd39c;
    --ok-surface: #0f2a20;
    --ok-line: #1f4d3a;
    --wait: #ecc275;
    --wait-surface: #2b2211;
    --wait-line: #574526;
    --bad: #f08a8a;
    --bad-surface: #2e1414;
    --bad-line: #5c2a2a;

    --shadow-card: 0 1px 2px rgb(0 0 0 / 40%), 0 10px 28px -14px rgb(0 0 0 / 60%);
    --shadow-pop: 0 24px 56px -24px rgb(0 0 0 / 70%);
}

/* Light needs no tokens of its own — :root is already light — but the browser
   still has to be told, or it keeps drawing dark controls on a light page for
   somebody who turned dark down. */
:root[data-theme='light'] {
    color-scheme: light;
}

/* ----------------------------------------------------------------- reset -- */

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

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

body {
    margin: 0;
    background: var(--surface);
    color: var(--ink);
    font-family: var(--font);
    font-size: var(--text-base);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Installed on a home screen there is no page behind this one to bounce
       into: overscrolling only shows a strip of background above the header. */
    overscroll-behavior-y: none;
}

@media (min-width: 48rem) {
    body {
        font-size: var(--text-md);
    }
}

img,
svg {
    display: block;
    max-width: 100%;
}

/* Anything the thumb types into keeps at least 16px. Safari on iOS zooms the
   whole page in on a field smaller than that and does not zoom back out, which
   leaves the screen scrolled sideways for everything after it. */
input,
select,
textarea,
button {
    font-family: inherit;
    font-size: max(1rem, 16px);
    line-height: inherit;
}

:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
    border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ------------------------------------------------------------ typography -- */

h1,
h2,
h3,
h4 {
    margin: 0 0 var(--space-3);
    font-weight: 700;
    line-height: 1.15;
    /* Archivo sets loose by default at display sizes; pulling it in is what
       makes a heading look set rather than typed. */
    letter-spacing: -0.02em;
    text-wrap: balance;
}

h1 {
    font-size: var(--text-3xl);
    letter-spacing: -0.03em;
}

/* Blazor's FocusOnNavigate moves focus to the heading after every navigation so
   a screen reader announces the new page. That is programmatic focus on
   something nobody tabbed to, and drawing a ring around the headline for it
   just looks like a bug. */
h1:focus,
h1:focus-visible {
    outline: none;
}

h2 {
    font-size: var(--text-xl);
}

h3 {
    font-size: var(--text-lg);
}

p {
    margin: 0 0 var(--space-4);
    text-wrap: pretty;
}

a {
    color: var(--link);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}

a:hover {
    text-decoration-thickness: 2px;
}

small,
.text-sm {
    font-size: var(--text-sm);
}

.muted {
    color: var(--ink-muted);
}

/* Times, dates and counts line up in a column when they are tabular. On an
   agenda that is most of the numbers on the screen. */
.tnum,
time,
.count {
    font-variant-numeric: tabular-nums;
}

.lede {
    max-width: var(--measure);
    color: var(--ink-muted);
    font-size: var(--text-lg);
    line-height: 1.5;
}

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

/* --------------------------------------------------------------- buttons -- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: var(--tap);
    padding: 0.625rem 1.125rem;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    font-size: var(--text-base);
    font-weight: 600;
    letter-spacing: -0.01em;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn-primary {
    background: var(--action);
    color: var(--action-ink);
}

.btn-primary:hover {
    background: var(--action-hover);
}

.btn-secondary {
    background: transparent;
    border-color: var(--line-strong);
    color: var(--ink);
}

.btn-secondary:hover {
    border-color: var(--ink-muted);
    background: var(--surface-sunken);
}

.btn-quiet {
    min-height: auto;
    padding: 0.25rem 0;
    background: none;
    border: 0;
    color: var(--link);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

.btn-danger {
    background: transparent;
    border-color: var(--bad-line);
    color: var(--bad);
}

.btn-danger:hover {
    background: var(--bad-surface);
}

.btn-sm {
    min-height: 2.25rem;
    padding: 0.3125rem 0.75rem;
    font-size: var(--text-sm);
}

.btn:disabled,
.btn[aria-disabled='true'] {
    opacity: 0.55;
    cursor: default;
}

/* On a dark panel the outline button has to pick up the panel's foreground
   rather than the page's. */
.on-brand .btn-secondary {
    border-color: rgb(255 255 255 / 35%);
    color: #fff;
}

.on-brand .btn-secondary:hover {
    background: rgb(255 255 255 / 10%);
    border-color: rgb(255 255 255 / 60%);
}

/* --------------------------------------------------------- theme switch -- */

/* Lives on the navy bar in both applications, so it takes its colour from the
   bar rather than from the page's ink. See ThemeToggle in the branding library
   for the markup. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: var(--tap);
    height: var(--tap);
    padding: 0;
    border: 0;
    border-radius: var(--radius-control);
    background: transparent;
    color: inherit;
    cursor: pointer;
}

.theme-toggle:hover {
    background: rgb(255 255 255 / 12%);
}

/* The page's focus ring is navy, which on a navy bar is no ring at all. */
.theme-toggle:focus-visible {
    outline-color: #fff;
}

.theme-toggle svg {
    width: 1.3125rem;
    height: 1.3125rem;
}

/* Which of the three faces is showing is a question about the document, so the
   stylesheet answers it: no script has to keep the button in step with the
   choice, and there is nothing to put back after a re-render. */
.theme-face {
    display: none;
    align-items: center;
    justify-content: center;
}

:root:not([data-theme]) .theme-face-system,
:root[data-theme='light'] .theme-face-light,
:root[data-theme='dark'] .theme-face-dark {
    display: flex;
}

/* ---------------------------------------------------------------- fields -- */

.field {
    display: block;
    margin-bottom: var(--space-4);
}

.field > .label,
.field > span:first-child,
.label {
    display: block;
    margin-bottom: var(--space-1);
    color: var(--ink);
    font-size: var(--text-sm);
    font-weight: 600;
}

.field em,
.hint {
    display: block;
    color: var(--ink-muted);
    font-size: var(--text-sm);
    font-style: normal;
    font-weight: 400;
}

.input,
.field input:not([type='checkbox']):not([type='radio']),
.field select,
.field textarea {
    width: 100%;
    min-height: var(--tap);
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-control);
    background: var(--surface);
    color: var(--ink);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.input:focus,
.field input:focus,
.field select:focus,
.field textarea:focus {
    outline: none;
    border-color: var(--focus);
    box-shadow: 0 0 0 3px rgb(26 74 138 / 18%);
}

.field select {
    appearance: none;
    padding-right: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%235a6b80' stroke-width='1.6' stroke-linecap='round'%3E%3Cpath d='M1.5 1.75 6 6.25l4.5-4.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 0.75rem;
}

/* A row of radios or checkboxes, each its own tap target. */
.choice {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--tap);
    font-weight: 400;
}

.choice input {
    width: 1.125rem;
    height: 1.125rem;
    accent-color: var(--navy-600);
}

fieldset.field {
    margin-inline: 0;
    padding: 0;
    border: 0;
}

fieldset.field > legend {
    margin-bottom: var(--space-1);
    padding: 0;
    font-size: var(--text-sm);
    font-weight: 600;
}

/* Blazor puts these on inputs it has validated. */
.valid.modified:not([type='checkbox']) {
    border-color: var(--ok);
}

.invalid {
    border-color: var(--bad);
}

.validation-message,
.field .error {
    display: block;
    margin-top: var(--space-1);
    color: var(--bad);
    font-size: var(--text-sm);
}

.validation-errors {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--bad-line);
    border-radius: var(--radius-control);
    background: var(--bad-surface);
    color: var(--bad);
    font-size: var(--text-sm);
    list-style-position: inside;
}

/* Fields side by side once there is room, one under the other when there is
   not. No column classes in the markup: the fields in these forms are all of a
   size, and naming a width per field is how a form ends up laid out for a
   screen nobody has. */
.form-grid {
    display: grid;
    gap: 0 var(--space-5);
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.form-grid > .field-wide {
    grid-column: 1 / -1;
}

/* A Dutch name is three parts, and the middle one is the short one. Given to
   the auto-fitting grid above they break two-and-one, which reads as though the
   surname belongs to something else. */
.name-grid {
    display: grid;
    gap: 0 var(--space-4);
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 30rem) {
    .name-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 0.55fr) minmax(0, 1fr);
    }
}

/* A form that is a single column of questions, at a width that stays readable.
   Registration and the detail forms use this rather than the grid. */
.form-column {
    max-width: 32rem;
}

/* --------------------------------------------------------- facts about x -- */

.definition-list {
    display: grid;
    gap: 0;
    margin: 0 0 var(--space-5);
}

@media (min-width: 40rem) {
    .definition-list {
        grid-template-columns: minmax(8rem, 14rem) minmax(0, 1fr);
    }
}

.definition-list dt {
    padding: var(--space-3) 0 0;
    color: var(--ink-muted);
    font-size: var(--text-sm);
    font-weight: 600;
}

.definition-list dd {
    margin: 0;
    padding: 0 0 var(--space-3);
    border-bottom: 1px solid var(--line);
}

@media (min-width: 40rem) {
    .definition-list dt {
        padding: var(--space-3) var(--space-4) var(--space-3) 0;
        border-bottom: 1px solid var(--line);
    }

    .definition-list dd {
        padding: var(--space-3) 0;
    }
}

.back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    margin-bottom: var(--space-4);
    color: var(--ink-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
}

.back-link:hover {
    color: var(--link);
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

.text-ok {
    color: var(--ok);
    font-weight: 600;
}

.text-bad {
    color: var(--bad);
    font-weight: 600;
}

/* A stack trace or an error from somewhere else. It wraps rather than scrolling
   sideways: the useful part of these is usually the first line. */
.code-block {
    margin: var(--space-2) 0 0;
    padding: var(--space-3);
    border-radius: var(--radius-control);
    background: var(--surface-sunken);
    color: var(--ink-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--text-sm);
    line-height: 1.45;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ----------------------------------------------------------------- chips -- */

/* One word saying where a member stands, readable before the row is. */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.125rem 0.625rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
    color: var(--ink-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    white-space: nowrap;
}

.chip::before {
    content: '';
    width: 0.4375rem;
    height: 0.4375rem;
    border-radius: 50%;
    background: currentColor;
}

.chip-present {
    border-color: var(--ok-line);
    background: var(--ok-surface);
    color: var(--ok);
}

.chip-waiting {
    border-color: var(--wait-line);
    background: var(--wait-surface);
    color: var(--wait);
}

.chip-absent {
    border-color: var(--line-strong);
    background: var(--surface-sunken);
    color: var(--ink-muted);
}

.chip-bad {
    border-color: var(--bad-line);
    background: var(--bad-surface);
    color: var(--bad);
}

/* Not a status: a role, a count, something the row simply is. No dot, because
   there is nothing for a colour to mean. */
.chip-neutral {
    border-color: var(--line-strong);
    background: transparent;
    color: var(--ink-muted);
    font-weight: 600;
}

.chip-neutral::before {
    display: none;
}

.chip-plain::before {
    display: none;
}

/* --------------------------------------------------------------- notices -- */

.notice {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--line);
    border-left-width: 3px;
    border-radius: var(--radius-control);
    background: var(--surface-sunken);
    font-size: var(--text-base);
}

.notice > :last-child {
    margin-bottom: 0;
}

.notice-good {
    border-color: var(--ok-line);
    border-left-color: var(--ok);
    background: var(--ok-surface);
    color: var(--ok);
}

.notice-warn {
    border-color: var(--wait-line);
    border-left-color: var(--wait);
    background: var(--wait-surface);
    color: var(--wait);
}

.notice-bad {
    border-color: var(--bad-line);
    border-left-color: var(--bad);
    background: var(--bad-surface);
    color: var(--bad);
}

/* ---------------------------------------------------------------- tables -- */

/* Wide screens get a real table. Narrow ones get the same rows stacked, each
   cell labelled from data-label, because a club administrator opening the
   members list on a phone should not be scrolling sideways. */
.table-wrap {
    margin-bottom: var(--space-5);
}

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-base);
}

.table th,
.table td {
    padding: var(--space-3) var(--space-3);
    text-align: left;
    vertical-align: middle;
}

.table thead th {
    border-bottom: 1px solid var(--line-strong);
    color: var(--ink-muted);
    font-size: var(--text-sm);
    font-weight: 600;
}

.table tbody tr + tr {
    border-top: 1px solid var(--line);
}

.table tbody tr:hover {
    background: var(--surface-sunken);
}

.table td:first-child,
.table th:first-child {
    padding-left: 0;
}

.table td:last-child,
.table th:last-child {
    padding-right: 0;
    text-align: right;
}

.table .actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: flex-end;
}

@media (max-width: 47.99rem) {
    .table thead {
        display: none;
    }

    .table,
    .table tbody,
    .table tr,
    .table td {
        display: block;
    }

    .table tbody tr {
        margin-bottom: var(--space-3);
        padding: var(--space-3) var(--space-4);
        border: 1px solid var(--line);
        border-radius: var(--radius-card);
        background: var(--surface-raised);
    }

    .table tbody tr + tr {
        border-top: 1px solid var(--line);
    }

    .table td {
        display: flex;
        gap: var(--space-4);
        justify-content: space-between;
        align-items: baseline;
        padding: 0.375rem 0;
        text-align: right;
    }

    .table td:first-child {
        padding-top: 0;
        font-size: var(--text-lg);
        font-weight: 700;
        letter-spacing: -0.01em;
    }

    .table td:last-child {
        padding-bottom: 0;
    }

    .table td::before {
        content: attr(data-label);
        color: var(--ink-muted);
        font-size: var(--text-sm);
        font-weight: 600;
        text-align: left;
    }

    /* The name cell is the row's heading, so it does not repeat its label. */
    .table td:first-child::before,
    .table td[data-label='']::before {
        display: none;
    }

    .table .actions {
        justify-content: flex-start;
    }
}

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

.card {
    /* A card is a block in the page's flow, and what follows it is usually the
       heading of the next section. Without room below, that heading reads as
       though it belongs to the card. */
    margin-bottom: var(--space-6);
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface-raised);
}

.card > :last-child {
    margin-bottom: 0;
}

/* Separates two things that belong to the same panel but are not the same
   decision — approving and rejecting, say. */
.rule {
    margin: var(--space-5) 0;
    border: 0;
    border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------- layout -- */

.container {
    width: 100%;
    max-width: var(--container);
    margin-inline: auto;
    padding-inline: var(--space-4);
}

@media (min-width: 48rem) {
    .container {
        padding-inline: var(--space-5);
    }
}

.stack > * + * {
    margin-top: var(--space-4);
}

.row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
}

/* On a narrow screen the buttons fill the row they are on: two short answers
   sit side by side and split it, and a pair too long to share a line wraps, at
   which point each is the full width. Either way there are no buttons that are
   merely as wide as their own label, which down a list reads as debris. */
@media (max-width: 29.99rem) {
    .row-actions > .btn {
        flex: 1 1 auto;
    }
}

/* The heading of a screen, with whatever action belongs to the screen as a
   whole sitting beside it. */
.page-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: flex-end;
    justify-content: space-between;
    margin-bottom: var(--space-5);
}

.page-head h1 {
    margin-bottom: 0;
}

.page-head .lede {
    margin-top: var(--space-2);
    margin-bottom: 0;
}

/* Nothing here yet, and what to do about it. */
.empty {
    padding: var(--space-6) var(--space-5);
    border: 1px dashed var(--line-strong);
    border-radius: var(--radius-card);
    color: var(--ink-muted);
    text-align: center;
}

.empty > :last-child {
    margin-bottom: 0;
}

/* ------------------------------------------------------------ error rail -- */

#blazor-error-ui {
    display: none;
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 1000;
    padding: var(--space-3) var(--space-5);
    padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
    background: var(--bad-surface);
    border-top: 1px solid var(--bad-line);
    color: var(--bad);
    font-size: var(--text-base);
}

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

.blazor-error-boundary {
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius-card);
    background: var(--bad-surface);
    border: 1px solid var(--bad-line);
    color: var(--bad);
}

.blazor-error-boundary::after {
    content: 'Er is een onverwachte fout opgetreden.';
}
