/* =========================================================================
   funding.css — single stylesheet for the whole site, public and admin.
   Follows CUBE CSS (cube.fyi):
     GLOBAL      design tokens + element defaults
     COMPOSITION flexible, content-agnostic layouts
     UTILITY     one job, done well
     BLOCK       specific components
     EXCEPTION   state variants, via data attributes
   ========================================================================= */

/* -------------------------------------------------------------------------
   GLOBAL — design tokens and sensible element defaults
   ------------------------------------------------------------------------- */
:root {
    /* Colour meanings (semantic families):
         green  = success       (--green-primary, --green-soft)
         blue   = informative   (--blue-primary, --blue-soft)
         red    = error         (--red-primary, --red-soft)
         gold  = warning       (--gold-primary, --gold-soft)
         purple = helpful        (--purple-primary, --purple-soft)
         neutral                (--black, --grey-primary, --grey-soft, --white)

       Every colour is a hue + role primitive (--green-primary / --green-soft),
       used directly — there are no --clr-* alias tokens left. Convention: when a
       -soft fill is used, its text and a thin 1px border take the matching -primary. */

    /* primitives — raw colours, named by hue + role (primary = base, mid = halfway, soft = pale) */
    --green-primary: #146C43;            /* dark green */
    --green-hover: #188050;              /* green-primary lightened — solid button hover.
                                            4.95:1 with white, so the label still clears AA. */
    --green-mid: #74AC8E;                /* midpoint of green primary/soft */
    --green-soft: #D4EDDA;            /* pale green */
    --purple-primary: #660099;           /* brand purple */
    --purple-hover: #8A00CC;             /* purple-primary lightened — solid button hover.
                                            7.1:1 with white, and 1.46:1 against the brand
                                            purple, so the change is plain at a glance. */
    --purple-mid: #9D64BD;               /* midpoint of purple primary/soft */
    --purple-soft: #D4C7E1;           /* pale lavender tint */
    --red-primary: #B02A37;              /* deep red */
    --red-mid: #D48088;                  /* midpoint of red primary/soft */
    --red-soft: #F8D7DA;                 /* pale red */
    --blue-primary: #0B5ED7;             /* strong blue */
    --blue-mid: #76A7EB;                 /* midpoint of blue primary/soft */
    --blue-soft: #E0F0FF;                /* pale blue */
    --gold-primary: #8A6D1A;           /* dark mustard / gold */
    --gold-mid: #C4B27C;               /* midpoint of gold primary/soft */
    --gold-soft: #FDF7DF;              /* pale gold */
    --yellow-primary: #FFCC00;           /* golden yellow (hue 48°, matches soft) */
    --yellow-mid: #FFDE58;               /* midpoint of yellow primary/soft */
    --yellow-soft: #FFEFAF;              /* pale yellow */
    --grey-primary: #5A6072;             /* mid grey */
    --grey-mid: #A8ABB6;                 /* midpoint of grey primary/soft */
    --grey-soft: #f7f6f9;                /* pale grey */
    --black: #000000;                /* black (absolute end) */
    --white: #FFFFFF;                /* white (absolute end) */

    /* brand, status and focus colours all use the hue primitives directly:
       brand   = --purple-primary / --purple-soft,  success = --green-primary / --green-soft,
       error   = --red-primary / --red-soft,         warning = --gold-primary / --gold-soft,
       info    = --blue-primary / --blue-soft.       Focus ring uses --gold-primary;
       the closed-state dot uses --red-primary. */

    /* neutrals (used directly): text = --black, muted text = --grey-primary,
       surfaces = --white, borders / alt fills / closed grey = --grey-soft. */

    /* type + space */
    --ff-base: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --fs-300: 14px; /* 14px floor for small UI text (labels, chips, muted) */
    --fs-350: 14.4px;
    --fs-400: 15.2px;
    --fs-500: 16.8px;
    --fs-600: 20.8px;
    --space-2xs: 4px;
    --space-xs: 8px;
    --space-s: 12px;
    --space-m: 16px;
    --space-l: 24px;
    --space-xl: 32px;

    --radius: 12px;
    --radius-s: 8px;

    /* One height for every button and button-like control, so a row of them
       lines up whatever the mix. 40px clears the 24px WCAG 2.5.8 (AA) target
       size comfortably. The compact button in a card header is the deliberate
       exception — see .card__header .btn. */
    --control-h: 40px;
    /* focus ring uses --gold-primary (clears 3:1 on every light surface);
       on the dark purple header the shortlist button overrides to a white ring. */
}

body {
    font-family: var(--ff-base);
    color: var(--black);
    background: var(--grey-soft);
    max-width: 1100px;
    margin: var(--space-xl) auto;
    padding: 0 var(--space-m);
}

h1 {
    color: var(--purple-primary);
}

/* The !important on every link colour below is not laziness.
   On the T4 CMS this stylesheet loads inside the university's own page, and
   their stylesheet sets link colours with !important. That beats any selector
   we can write, however specific — tested up to
   `article.card .card__header h2 a`, which still lost. Matching !important is
   the only thing that wins, and it has no effect anywhere else, since nothing
   in this file competes with itself. */
a {
    color: var(--blue-primary) !important;
}

/* Buttons that happen to be links. The rule above wins over the component
   rules further down this file, so a <a class="btn"> came out with link-blue
   text on a solid purple fill. Each button-ish component therefore restates
   its own label colour here at the same weight. Keep these in step with
   .btn / .apply-btn / .pagination__link / .icon-btn below — they carry no new
   design decisions, they exist only to outrank the !important above. */
a.btn,
a.apply-btn {
    color: #ffffff !important;
}

a.btn[data-variant="secondary"] {
    color: var(--purple-primary) !important;
}

a.btn[data-variant="secondary"]:hover {
    color: #ffffff !important;
}

a.pagination__link {
    color: var(--black) !important;
}

a.pagination__link:hover {
    color: #ffffff !important;
}

a.icon-btn {
    color: var(--purple-primary) !important;
}

a.icon-btn[data-variant="danger"] {
    color: var(--red-primary) !important;
}

:is(input, select, textarea, button):focus-visible {
    outline: 3px solid var(--gold-primary);
    outline-offset: 1px;
}

/* -------------------------------------------------------------------------
   COMPOSITION — flexible, content-agnostic layouts
   ------------------------------------------------------------------------- */

/* vertical rhythm between direct children */
.flow > * + * {
    margin-block-start: var(--flow-space, var(--space-m));
}

/* responsive card grid */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(520px, 100%), 1fr));
    gap: var(--space-m); /* tightened 3 Sep 2026 — was var(--space-l) */
}

/* horizontal group that wraps, e.g. chips */
.cluster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    align-items: center;
}

/* two even columns that stack when tight */
.pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-xs) var(--space-l);
}

/* Key information facts sit on a fixed 3-column grid so rows line up
   (Study level | Fee status | Number of awards, then Student type |
   Application deadline | —) regardless of how many facts a row has */
.info-card .pair {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 640px) {
    .info-card .pair {
        grid-template-columns: 1fr;
    }
}

/* push children to opposite ends, wrapping gracefully */
.repel {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-s) var(--space-l);
}

/* a field (textarea etc.) beside a small action button */
.row {
    display: flex;
    gap: var(--space-s);
    align-items: flex-start;
}

.row__field {
    flex: 1;
}

/* -------------------------------------------------------------------------
   UTILITY — one job, done well
   ------------------------------------------------------------------------- */

.label {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    font-size: var(--fs-300);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--purple-primary);
}

/* keep the label icons about the size of the letters beside them */
.label .icon {
    width: 1.1em;
    height: 1.1em;
}

.chip {
    display: inline-block;
    padding: 0.4em 1em;
    /* 5px, not a full pill: the labels inside run long enough that a stadium
       shape wastes width and reads as a button. */
    border-radius: 5px;
    font-size: var(--fs-300);
    background: var(--purple-soft);
    color: var(--purple-primary);
    border: 1px solid currentColor;
}

/* outlined variant (e.g. academic year pills): border only, no fill */
.chip--outline {
    background: transparent;
    border: 1px solid currentColor;
}

/* eligible students: pale blue pills — soft fill, primary text + thin border */
.chip--eligible {
    background: var(--blue-soft);
    color: var(--blue-primary);
    border-color: currentColor;
}

/* "What does this mean?" disclosure for the eligible-student pills — now the
   only place those explanations appear, since the pills carry no title= and so
   no hover tooltip. Sits beneath the pills with the toggle pushed to the
   right; the list it reveals stays left-aligned. */
.chip-help {
    margin-block-start: 8px;
    font-size: var(--fs-300);
}

.chip-help summary {
    width: fit-content;
    margin-inline-start: auto; /* right-aligned, but only as wide as its text */
    /* WCAG 2.2 target size (minimum) wants 24px — the text alone is 19px */
    display: flex;
    align-items: center;
    min-height: 24px;
    color: var(--purple-primary);
    cursor: pointer;
    /* underlined at rest, so it reads as a link like every other one on the
       site — a <summary> gets no underline from the browser by default */
    text-decoration: underline;
}

/* Chevrons carry meaning on their own — a direction, an open/shut state —
   rather than decorating a label, so they are drawn heavier than the rest of
   the icon set. A CSS stroke-width beats the stroke-width="2" attribute that
   icon() writes onto the <svg>, and the paths inherit it. */
.chip-help summary .icon,
.move-btn .icon,
.pagination__link--arrow .icon {
    stroke-width: 3;
}

/* Right-pointing when shut, down-pointing when open — the panel has no
   disclosure triangle of its own, because `display: flex` on the summary
   removes the browser's default marker. */
.chip-help summary .icon {
    margin-inline-start: 0.35em;
    transition: transform 0.15s ease;
}

.chip-help[open] summary .icon {
    transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
    .chip-help summary .icon {
        transition: none;
    }
}

/* same keyboard ring the rest of the site uses */
.chip-help summary:focus-visible {
    outline: 3px solid var(--gold-primary);
    outline-offset: 1px;
}

.chip-help dl {
    margin: 8px 0 0;
}

.chip-help dt {
    font-weight: 600;
}

.chip-help dd {
    margin: 0 0 var(--space-2xs);
    color: var(--grey-primary);
}

.chip-help dd:last-child {
    margin-block-end: 0;
}

/* breathing room between a section label and the pills beneath it,
   and between the pills themselves */
.label + .cluster {
    margin-block-start: 8px;
}

.card__section .cluster,
.check-group .cluster {
    gap: 8px;
}

/* pill containers used on the profile page (e.g. academic years, degrees) */
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.muted {
    color: var(--grey-primary);
}

.hint {
    font-size: var(--fs-350);
    color: var(--grey-primary);
    font-weight: 400;
}

.tip {
    border-bottom: 1px dotted var(--grey-primary);
    cursor: help;
}

.updated {
    font-size: var(--fs-300);
    color: var(--grey-primary);
    margin-top: var(--space-2xs);
    text-align: right;
}

.text-right {
    text-align: right;
}

.divider {
    border: none;
    border-top: 1px solid var(--grey-soft);
    margin: var(--space-s) 0;
}

.field-label {
    display: block;
    font-weight: 600;
    font-size: var(--fs-400);
    margin-block-end: var(--space-2xs);
}

.input {
    width: 100%;
    padding: 9.6px 12px;
    font: inherit;
    color: inherit;
    background: var(--white);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius-s);
    box-sizing: border-box;
}

/* top filter box: field borders use grey-mid */
.search-panel .input {
    border-color: var(--grey-mid);
}

.check {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    font-size: var(--fs-400);
}

.check input {
    flex-shrink: 0;
    width: 17.6px;
    height: 17.6px;
    accent-color: var(--purple-primary);
}

/* neat, self-aligning columns of checkboxes that cope with any number of
   options — new choices flow into the grid without breaking the layout */
.check-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: var(--space-s) var(--space-l);
}

.check-grid .check {
    align-items: flex-start;
}

/* clear breathing room above the eligibility group and below its checkboxes.
   Uses .check-group.filter-eligibility so it beats the later `.check-group
   { margin: 0 }` rule, which would otherwise cancel the gap. */
.check-group.filter-eligibility {
    margin-block: var(--space-l);
}

.btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--control-h);
    padding: 0 28px;
    font: inherit;
    font-weight: 600;
    color: #ffffff;
    background: var(--purple-primary);
    border: none;
    border-radius: var(--radius-s);
    cursor: pointer;
    text-decoration: none;
}

/* row of action buttons (admin listing) — a little breathing room */
.btn-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-s);
}

/* Hover lightens the fill rather than darkening it — a lighter purple reads
   more clearly against the brand purple than a darker one did, and both
   --purple-hover and --green-hover keep their white label above 4.5:1. The
   colour does not work alone: buttons also borrow the hover the cards already
   use, lifting on a soft purple shadow. Same shape, same 0.15s, so the two
   read as one idea. */
.btn,
.apply-btn,
a.pagination__link,
.move-btn {
    transition: background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.btn:hover,
.apply-btn:hover,
a.pagination__link:hover,
.move-btn:hover {
    box-shadow: 0 3px 10px rgba(87, 6, 140, 0.28);
    transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {

    .btn,
    .apply-btn,
    a.pagination__link,
    .move-btn {
        transition: none;
    }

    .btn:hover,
    .apply-btn:hover,
    a.pagination__link:hover,
    .move-btn:hover {
        transform: none;
    }
}

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

.sort-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    justify-content: flex-end;
    flex-wrap: wrap;
    margin-block: 24px 16px;
}

.sort-bar .input {
    width: auto;
}

/* -------------------------------------------------------------------------
   PAGINATION
   ------------------------------------------------------------------------- */

.pagination {
    margin-block-start: var(--space-xl);
}

.pagination__list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-xs);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* one style for links, the current page and the disabled steps, so the row
   keeps an even rhythm whatever each item happens to be */
.pagination__link {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--control-h);
    min-height: var(--control-h);
    padding-inline: var(--space-s);
    font-size: var(--fs-400);
    font-weight: 600;
    color: var(--black);
    text-decoration: none;
    background: var(--white);
    border: 1px solid var(--grey-mid);
    border-radius: var(--radius-s);
}

/* the same fill every other button gets on hover, so a page number and the
   Search button behave identically under the pointer */
a.pagination__link:hover {
    color: #ffffff;
    background: var(--purple-hover);
    border-color: var(--purple-hover);
}

a.pagination__link:focus-visible {
    outline: 3px solid var(--gold-primary);
    outline-offset: 1px;
}

/* the page you're on */
.pagination__link[aria-current="page"] {
    color: var(--white);
    background: var(--purple-primary);
    border-color: var(--purple-primary);
    cursor: default;
}

/* Previous / Next at either end */
.pagination__link--step {
    padding-inline: var(--space-m);
}

.pagination__link[aria-disabled="true"] {
    color: var(--grey-primary);
    background: var(--grey-soft);
    border-color: var(--grey-soft);
    cursor: not-allowed;
}

.pagination__gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    min-height: var(--control-h);
    color: var(--grey-primary);
}

/* compact phone control — arrows either side of "Page 2 of 10" */
.pagination__compact {
    display: none;
    align-items: center;
    justify-content: center;
    gap: var(--space-s);
}

.pagination__status {
    margin: 0;
    font-size: var(--fs-400);
    color: var(--grey-primary);
}

.pagination__status strong {
    color: var(--black);
}

.pagination__link--arrow {
    padding-inline: var(--space-xs);
}

.pagination__link--arrow .icon {
    width: 20px;
    height: 20px;
}

/* At its widest the numbered strip is 9 items — Previous, seven numbers with
   two ellipses, Next — which needs about 600px. Below that it would wrap onto
   two or three rows, so swap in the compact bar, which is one row at any page
   count. 720px leaves the strip a comfortable margin rather than a hair's. */
@media (max-width: 720px) {
    .pagination__list {
        display: none;
    }

    .pagination__compact {
        display: flex;
    }
}

/* available to screen readers, hidden on screen */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
    border: 0;
    clip-path: inset(50%);
}

.btn[data-variant="secondary"] {
    color: var(--purple-primary);
    background: transparent;
    border: 1px solid var(--purple-primary);
}

.btn[data-variant="secondary"]:hover {
    color: #ffffff;
    background: var(--purple-hover);
    border-color: var(--purple-hover);
}

.link-btn {
    display: inline-flex;
    align-items: center;
    min-height: 24px; /* WCAG 2.5.8 minimum target size */
    padding: 3.2px 2.4px;
    font: inherit;
    font-weight: 600;
    color: var(--blue-primary);
    background: none;
    border: none;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.icon {
    flex-shrink: 0;
    vertical-align: -2px;
}

.dot {
    display: inline-block;
    width: 11.2px;
    height: 11.2px;
    border-radius: 50%;
    background: var(--grey-primary);
    border: 1px solid rgba(0, 0, 0, 0.25);
    vertical-align: baseline;
}

.error {
    background: var(--red-soft);
    color: var(--red-primary);
    border: 1px solid var(--red-primary);
    padding: var(--space-s) var(--space-m);
    border-radius: var(--radius-s);
    margin-top: var(--space-m);
    margin-bottom: var(--space-l);
}

.error p {
    margin: 0;
    font-weight: 600;
}

.error ul {
    margin: var(--space-2xs) 0 0;
    padding-inline-start: 20px;
}

/* validation error highlight on a field or group — JS clears it on first edit */
.admin-form [data-error],
.admin-form fieldset[data-error] {
    border-color: var(--red-primary);
    box-shadow: 0 0 0 1px var(--red-primary);
}

.success {
    background: var(--green-soft);
    color: var(--green-primary);
    border: 1px solid var(--green-primary);
    padding: var(--space-s) var(--space-m);
    border-radius: var(--radius-s);
    margin-top: var(--space-m);
}

/* System page: bordered panels for each group of settings */
.system-panel {
    margin-block: var(--space-l);
    padding: var(--space-m) var(--space-l) var(--space-l);
    background: var(--white);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius-s);
}

.system-panel h2 {
    margin-top: 0;
}

/* -------------------------------------------------------------------------
   BLOCK — admin nav bar
   ------------------------------------------------------------------------- */

.admin-nav {
    display: flex;
    flex-wrap: wrap;   /* six sections plus the user block overflow below ~1000px */
    gap: var(--space-xs) var(--space-m);
    align-items: center;
    padding: var(--space-xs) 0;
    border-bottom: 1px solid var(--grey-soft);
    margin-bottom: var(--space-l);
    font-size: var(--fs-400);
}

.admin-nav__user {
    margin-left: auto;
}

/* -------------------------------------------------------------------------
   BLOCK — search panel
   ------------------------------------------------------------------------- */

.search-panel {
    background: var(--white);
    border: 1px solid var(--grey-mid);
    border-radius: var(--radius);
    padding: var(--space-l);
    margin-block: var(--space-l) var(--space-xl);
}

.search-panel h2 {
    margin: 0;
    font-size: var(--fs-500);
    /* stated rather than left to the browser's bold default: the university's
       stylesheet sets headings to 300, so on the CMS this arrived thin */
    font-weight: 700;
}

.search-panel .repel p {
    margin: 0;
    font-size: var(--fs-300);
}

.check-group {
    border: none;
    margin: 0;
    padding: 0;
    background: none;
}

.check-group legend {
    padding: 0;
    background: none;
    border-radius: 0;
    font-weight: 600;
    color: var(--black);
    font-size: var(--fs-400);
    margin-block-end: var(--space-2xs);
}

.search-panel__foot {
    display: flex;
    justify-content: flex-end;
    border-block-start: 1px solid var(--grey-soft);
    padding-block-start: var(--space-m);
}

/* three even filter groups, separated by thin vertical rules */
.filter-columns {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-l);
}

.filter-columns > * + * {
    border-inline-start: 1px solid var(--grey-soft);
    padding-inline-start: var(--space-l);
}

@media (max-width: 640px) {
    .filter-columns {
        grid-template-columns: 1fr;
    }

    .filter-columns > * + * {
        border-inline-start: none;
        padding-inline-start: 0;
    }
}

/* -------------------------------------------------------------------------
   BLOCK — the funding card (homepage)
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   LISTING-CARD DENSITY — tightened 3 September 2026
   -------------------------------------------------------------------------
   The four values below are the only thing that changed. To put the original,
   roomier spacing back, restore them to the "was" values in the comments:

       --card-pad-y       var(--space-s)   12px
       --card-pad-x       var(--space-l)   24px
       --card-band-pad-y  var(--space-m)   16px
       .card-grid gap     var(--space-l)   24px

   They are declared on .card, not :root, so the scheme page's .info-card —
   which shares .card__header, .card__section and .card__banner — is untouched:
   with the properties unset there, each rule falls back to its original value.
   ------------------------------------------------------------------------- */
.card {
    --card-pad-y: var(--space-xs);      /* was var(--space-s) */
    --card-pad-x: var(--space-m);       /* was var(--space-l) */
    --card-band-pad-y: var(--space-s);  /* was var(--space-m) */
    position: relative;
    background: var(--white);
    border: 1px solid var(--purple-primary);
    border-radius: var(--radius);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

/* The lift is the card's "this is clickable" cue, so it fires only while the
   pointer is over the header, which is the only clickable part. :has() reads
   as "the card containing a hovered header"; where it is unsupported the card
   simply does not lift, which is the honest fallback.
   The extra 0 0 0 1px ring visually doubles the border without shifting layout. */
.card:has(.card__header:hover) {
    box-shadow: 0 0 0 1px var(--purple-primary), 0 4px 14px rgba(87, 6, 140, 0.18);
    transform: translateY(-2px);
}

/* keyboard users get an unmissable ring around the whole card */
.card:focus-within {
    outline: 3px solid var(--gold-primary);
    outline-offset: 2px;
}

.card__header {
    background: var(--purple-primary);
    padding: var(--card-band-pad-y, var(--space-m)) var(--card-pad-x, var(--space-l));
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-s);
    color: #ffffff;
}

.card__header h2 {
    margin: 0;
    font-size: var(--fs-600);
    /* stated rather than left to the browser's bold default: the university's
       stylesheet puts headings at 300, which arrived here as a thin, washed-out
       scheme title. 700 matches how it has always rendered locally. */
    font-weight: 700;
    line-height: 1.3;
    /* reserve the height of two lines so single-line titles match
       two-line titles and every purple header is the same size */
    min-height: calc(1.3em * 2);
    display: flex;
    align-items: center;
}

.card__header h2 a {
    color: #ffffff !important;
    text-decoration: none;
    /* Clamp long titles to two lines with an ellipsis. Default word wrapping
       means the cut always lands after a whole word, never mid-word. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: normal;
    word-break: normal;
}

/* the ring on the card replaces the anchor's own outline */
.card__header h2 a:focus-visible {
    outline: none;
}

/* Only the title and the roundel are links, so the "go" cues fire from the
   purple header rather than from anywhere on the card — hovering the body no
   longer suggests the whole card can be clicked, because it cannot. */
.card__header:hover h2 a {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* arrow in a white roundel — a clear "go" affordance */
.card__header .icon {
    width: 30px;
    height: 30px;
    padding: 6px;
    box-sizing: border-box;
    background: #ffffff;
    color: var(--purple-primary);
    border-radius: 50%;
    transition: transform 0.15s ease;
}

/* The roundel's link. The title-only rules above are scoped to `h2 a` so none
   of them reach this: the line clamp's `overflow: hidden` used to crop the
   circle the moment the icon inside slid 4px on hover. `overflow: visible` is
   stated anyway, so a future rule on .card__header a cannot crop it again. */
.card__go {
    display: inline-flex;
    flex: none;
    overflow: visible;
    border-radius: 50%;
}

.card__header:hover .icon {
    transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
    .card,
    .card__header .icon {
        transition: none;
    }

    .card:has(.card__header:hover) {
        transform: none;
    }

    .card__header:hover .icon {
        transform: none;
    }
}

.card__section {
    padding: var(--card-pad-y, var(--space-s)) var(--card-pad-x, var(--space-l));
    border-block-start: 1px solid var(--purple-soft);
}

/* fee strip — the scannable headline figure on each card */
.card__fee {
    display: flex;
    align-items: center;
    gap: 7.2px;
    margin: 0;
    padding: var(--card-pad-y, var(--space-s)) var(--card-pad-x, var(--space-l));
    background: var(--purple-soft);
    color: var(--purple-primary);
    font-size: var(--fs-600);
    font-weight: 700;
}

/* scale the currency icon to the headline figure, like the fact icons */
.card__fee .icon {
    width: 0.85em;
    height: 0.85em;
}

.card__fee-label {
    font-size: var(--fs-300);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.card__section:first-of-type {
    border-block-start: none;
}

/* sub-headings inside a card section, e.g. the three parts of "Application and
   selection process". The stylesheet has no h3 rules at all, so without this
   they fall back to the browser default and sit oddly against the card type. */
.card__section h3 {
    margin: 0 0 var(--space-2xs);
    font-size: var(--fs-500);
    color: var(--purple-primary);
}

.card__section h3 + .rich-text > :first-child {
    margin-block-start: 0;
}

/* -------------------------------------------------------------------------
   RICH TEXT — markup generated by render_rich_text() from editors' plain text
   ------------------------------------------------------------------------- */

.rich-text > :first-child {
    margin-block-start: 0;
}

.rich-text > :last-child {
    margin-block-end: 0;
}

.rich-text p {
    margin-block: 0 var(--space-s);
}

/* "Personal factors:" and friends. Same size and colour as the body text —
   bold and the space above are what set them apart. */
.rich-text .rt-heading {
    margin-block: var(--space-m) var(--space-2xs);
    font-size: inherit;
    font-weight: 700;
    color: inherit;
}

.rich-text .rt-list {
    margin-block: 0 var(--space-s);
    padding-inline-start: var(--space-l);
}

.rich-text .rt-list li {
    margin-block-end: var(--space-2xs);
    line-height: 1.5;
}

.rich-text a {
    color: var(--purple-primary) !important;
    /* long pasted addresses must not push the card wider than its column */
    overflow-wrap: anywhere;
}

/* "How to format" under each admin textarea — one quiet line until opened */
/* the trigger sits right, under the end of the textarea; the rules it opens
   stay left-aligned so they read normally */
.format-help {
    /* the trailing gap keeps whatever follows — the Active checkbox on the
       eligibility and priority fieldsets — clear of the opened rules */
    margin-block: var(--space-xs) var(--space-l);
    text-align: end;
}

.format-help summary {
    display: inline-block;
    font-weight: 600;
    color: var(--purple-primary);
    cursor: pointer;
}

.format-help summary:hover {
    text-decoration: underline;
}

/* sits on the fieldset's own background — a white panel with a border reads
   as another input, which is the one thing this must not look like */
.format-help ul {
    margin-block: var(--space-xs) 0;
    padding-block: 0;
    padding-inline-start: var(--space-l);
    background: transparent;
    list-style-position: outside;
    text-align: start;
}

.format-help li {
    margin-block-end: var(--space-2xs);
}

.format-help li:last-child {
    margin-block-end: 0;
}

.format-help code {
    padding: 0.05em 0.3em;
    background: var(--grey-soft);
    border: 1px solid var(--grey-mid);
    border-radius: var(--radius-s);
    font-size: 0.95em;
    /* the link example is long — let it wrap rather than widen the fieldset */
    overflow-wrap: anywhere;
}

.card__excerpt {
    margin: 0;
    font-size: var(--fs-400);
    font-weight: 500;
    line-height: 1.55;
}

.fact dt {
    margin: 0;
}

.fact dd {
    margin: var(--space-2xs) 0 0;
    font-size: var(--fs-400);
}

/* highlighted fact row, e.g. award value */
.card__section[data-highlight] {
    background: var(--purple-soft);
}

/* status strip across the card foot — mirrors the header bar */
.card__banner {
    margin-block-start: auto;
    padding: var(--card-band-pad-y, var(--space-m)) var(--card-pad-x, var(--space-l));
    /* a rule top and bottom only — each state sets its own border colour */
    border-block: 1px solid var(--purple-primary);
    font-size: var(--fs-400);
    font-weight: 600;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--space-xs);
}

/* -------------------------------------------------------------------------
   BLOCK — scheme profile page
   ------------------------------------------------------------------------- */

.profile h1 {
    margin-bottom: var(--space-2xs);
}

.profile .lead {
    font-size: 18.4px;
    font-weight: 500;
    color: var(--black);
}

/* "still unsure?" nudge — sits above the status banner in the card foot */
.card__unsure {
    text-align: center;
}

.card__unsure p {
    margin: 0;
}

/* apply call-to-action in the scheme summary card foot */
.card__apply {
    text-align: center;
    border-block-start: 1px solid var(--purple-primary);
}

/* shortlist button in the info-card's purple header — white outline so it
   stands out against the same-colour bar */
.card__header .basket-toggle {
    margin: 0;
}

/* The one control that is deliberately not --control-h: it sits inside the
   card header beside the scheme title, where a full-height button would
   dominate the card. Same shape and same hover fill, just smaller. */
.card__header .btn {
    min-height: 32px;
    padding: 0 16px;
    font-size: var(--fs-300);
    background: var(--purple-soft);
    color: var(--black); /* dark text — readable on the light lavender fill */
    border: 1px solid #ffffff;
}

.card__header .btn:hover {
    background: var(--purple-hover);
    color: #ffffff; /* flip to white on the dark hover fill */
}

/* compound focus ring: a dark inner ring (box-shadow) clears 3:1 against the pale
   lavender button, and the white outer outline clears the dark purple header —
   so one edge always has contrast whichever surface the ring borders */
.card__header .btn:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 2px;
    box-shadow: 0 0 0 4px var(--purple-primary);
}

.card__apply .apply-btn {
    display: inline-block;
    margin: 0;
    padding: 9.6px 28px;
    min-width: 208px;
    box-sizing: border-box;
    text-align: center;
    border-radius: var(--radius-s);
}

/* award-value breakdown in the scheme summary card */
.award-list {
    margin: 8px 0 0;
}

.award-list > div {
    display: flex;
    flex-wrap: wrap;
    gap: 6.4px 12px;
    margin-block-end: 6.4px;
}

.award-list dt {
    margin: 0;
    font-weight: 600;
    min-width: 216px; /* fits the longest label so every value lines up */
}

.award-list dd {
    margin: 0;
}

/* scheme-page summary box — reuses the listing card's look for consistency */
.info-card {
    margin: var(--space-l) 0;
    background: var(--white);
    border: 1px solid var(--purple-primary);
    border-radius: var(--radius);
    overflow: hidden;
}

.key-info h2 {
    margin: 0 0 var(--space-m);
    font-size: 19.2px;
}

.ki-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--space-m) var(--space-l);
    margin: 0;
}

.ki-grid dt {
    font-weight: 700;
    font-size: var(--fs-350);
    margin: 0;
}

.ki-grid dd {
    margin: var(--space-2xs) 0 0;
    font-size: var(--fs-400);
}

.ki-grid dd .icon {
    margin-right: 3.2px;
}

.apply-box {
    margin: var(--space-xl) 0 var(--space-m);
    padding: var(--space-m) 20px;
    border-radius: var(--radius-s);
    background: var(--grey-soft);
}

.app-facts {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-l);
}

.app-facts li {
    display: flex;
    align-items: center;
    gap: 6.4px;
    white-space: nowrap;
}

.apply-btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--control-h);
    margin-top: var(--space-s);
    padding: 0 28px;
    background: var(--green-primary);
    color: #ffffff;
    text-decoration: none;
    border-radius: var(--radius-s);
    font-weight: 600;
}

.apply-btn:hover {
    background: var(--green-hover);
}

.contact p {
    margin: var(--space-2xs) 0;
    display: flex;
    align-items: center;
    gap: 6.4px;
}

/* generic profile section: consistent heading, divider, list rhythm */
.section {
    margin-top: var(--space-xl);
    padding-top: var(--space-m);
    border-top: 1px solid var(--grey-soft);
}

.section h2 {
    font-size: 19.2px;
    margin: 0 0 var(--space-xs);
}

.section ul {
    margin: 0;
    padding-left: 20px;
}

.section li {
    margin-bottom: var(--space-xs);
}

/* -------------------------------------------------------------------------
   BLOCK — admin forms (scheme edit, statements, login, register)
   ------------------------------------------------------------------------- */

.admin-form {
    background: var(--white);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius);
    padding: var(--space-l) var(--space-xl) var(--space-xl);
}

.admin-form label {
    display: block;
    font-weight: 700;
    margin-top: 32px;
    color: var(--purple-primary);
}

/* the display:block above beats the browser's [hidden] rule, so restore it —
   lets JS show/hide the application toggles and contact fields */
.admin-form [hidden] {
    display: none !important;
}

.admin-form :is(input[type="text"], input[type="date"], input[type="email"], input[type="url"], input[type="number"], input[type="password"], input[type="search"], select, textarea) {
    width: 100%;
    padding: 8.8px 12px;
    margin-top: var(--space-2xs);
    box-sizing: border-box;
    font: inherit;
    color: inherit;
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius-s);
    background: var(--white);
}

.admin-form textarea {
    min-height: 128px;
    overflow: hidden;  /* no scrollbar — the JS grows the box instead */
    resize: vertical;  /* manual drag still works if wanted */
}

.admin-form textarea[data-size="s"] {
    min-height: 64px;
}

/* statements editor: let every box shrink to fit its own statement */
.admin-form.statements-form textarea {
    min-height: 44px;
}

/* space after the "no application required" checkbox, before the date fields */
.admin-form .app-toggle {
    margin-block-end: var(--space-m);
}

/* internal-only notes box — tinted so it's clearly not public content */
.admin-form fieldset.internal-notes {
    background: var(--purple-soft);
    border-color: var(--gold-primary);
    border: 1px solid var(--grey-soft);
}

.admin-form fieldset.internal-notes legend {
    background: var(--purple-soft);
    color: var(--purple-primary);
    border: 1px solid var(--purple-primary);
}

.admin-form fieldset {
    margin-top: 32px;
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius-s);
    padding: var(--space-s) var(--space-m) var(--space-m);
}

/* general info boxes: a little darker than the wrapping .bare-fieldset grey */
.admin-form fieldset:not(.bare-fieldset):not(.internal-notes) {
    background: var(--purple-soft);
}

/* .hint's --grey-primary is set for hints on white (6.3:1). Against the
   lavender above it drops to 3.9:1 — under AA — and thin 14.4px strokes
   antialias toward the background, so it reads washed out. Black on the same
   tint is 13:1. Hints on white pages are left alone. */
.admin-form fieldset:not(.bare-fieldset) .hint {
    color: var(--black);
}

.admin-form legend {
    font-weight: 600;
    color: var(--purple-primary);
    background: var(--purple-soft);
    padding: 3.2px 12.8px;
    border-radius: 999px;
    border: 1px solid var(--purple-primary);
    font-size: 14.4px;
}

.admin-form fieldset label {
    font-weight: 400;
    margin-top: var(--space-2xs);
    color: var(--black);
}

/* field labels inside a fieldset (open/close dates, contact, etc.) get a
   clear gap between questions — checkbox-option labels (no `for`) stay tight */
.admin-form fieldset label[for] {
    margin-top: var(--space-l);
    font-weight: 700;
}

/* top-level fields (scheme, slug, status, excerpt, …) sit directly in the
   .bare-fieldset wrapper, so give them clear spacing between questions */
.admin-form .bare-fieldset > label {
    margin-top: 32px;
}

/* no gap above the very first field, and keep Description close to Excerpt */
.admin-form .bare-fieldset > label:first-of-type {
    margin-top: 0;
}

.admin-form .bare-fieldset > label.tight-top {
    margin-top: 16px;
}

.admin-form fieldset label[data-layout="inline"] {
    display: inline-block;
    margin-right: var(--space-m);
}

.admin-form input[type="checkbox"] {
    accent-color: var(--purple-primary);
    width: 16.8px;
    height: 16.8px;
}

.admin-form button[type="submit"]:not(.del) {
    margin-top: var(--space-l);
    padding: 9.6px var(--space-xl);
    font: inherit;
    font-weight: 600;
    color: #ffffff;
    background: var(--purple-primary);
    border: none;
    border-radius: var(--radius-s);
    cursor: pointer;
}

.admin-form button[type="submit"]:not(.del):hover {
    background: var(--purple-primary);
}

.admin-form .cancel {
    margin-left: var(--space-m);
}

/* statements editor: bare clickable trash icon (still a real button for
   keyboard/screen-reader users — just without the button chrome) */
.del {
    margin-top: 14.4px;
    padding: 3.2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--red-primary);
    background: none;
    border: none;
    border-radius: var(--radius-s);
    cursor: pointer;
}

.del:hover {
    color: var(--red-primary);
    background: var(--red-soft);
}

/* clear gap between statement rows; the timestamp hugs its own field */
.row + .row {
    margin-block-start: var(--space-l);
}

.add {
    margin-top: var(--space-m);
    padding: 6.4px var(--space-m);
    font: inherit;
    font-size: 14.4px;
    font-weight: 600;
    color: var(--purple-primary);
    background: var(--purple-soft);
    border: none;
    border-radius: var(--radius-s);
    cursor: pointer;
}

/* -------------------------------------------------------------------------
   BLOCK — admin data tables (funding list, users)
   ------------------------------------------------------------------------- */

.data-table {
    border-collapse: collapse;
    width: 100%;
    margin-top: var(--space-m);
    font-size: var(--fs-400);
    background: var(--white);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius);
}

.data-table th,
.data-table td {
    text-align: left;
    padding: var(--space-xs) var(--space-s);
    border-bottom: 1px solid var(--grey-soft);
}

/* leading row-number column — as narrow as the digits allow, and lined up
   on the decimal so 9 and 10 don't jitter against each other */
.data-table .row-num {
    width: 1%;
    white-space: nowrap;
    text-align: right;
    color: var(--grey-primary);
    font-variant-numeric: tabular-nums;
}

/* "20/34 schemes" under the table, bottom left */
.table-count {
    margin: var(--space-s) 0 0;
    font-size: var(--fs-300);
    color: var(--grey-primary);
}

.table-count strong {
    color: var(--black);
}

.inline-form {
    display: inline;
}

/* pill badges: scheme statuses and user account states */
.status,
.badge {
    display: inline-block;
    padding: 2.4px 8px;
    border-radius: 999px;
    font-size: var(--fs-300);
    background: var(--grey-soft);
}

/* thin border matching the pill's own text colour */
.status {
    border: 1px solid currentColor;
}

/* published schemes read as live — green, not grey */
.status[data-status="published"] {
    background: var(--green-soft);
    color: var(--green-primary);
}

/* holding = gold, archived = red (border follows the text colour) */
.status[data-status="holding"] {
    background: var(--gold-soft);
    color: var(--gold-primary);
}

.status[data-status="archived"] {
    background: var(--red-soft);
    color: var(--red-primary);
}

/* user account status pills: active = green, deactivated = red */
.badge[data-status="active"] {
    background: var(--green-soft);
    color: var(--green-primary);
    border: 1px solid var(--green-primary);
}

.badge[data-status="deactivated"] {
    background: var(--red-soft);
    color: var(--red-primary);
    border: 1px solid var(--red-primary);
}

/* user list filter bar: live search + role/status dropdowns + reset */
.user-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px 20px;
    margin-block: 24px 16px;
    padding: 12px 20px 20px;
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius-s);
    min-inline-size: 0;
}

.user-filters > legend {
    padding-inline: 6.4px;
    font-weight: 600;
    color: var(--purple-primary);
}

.user-filters .filter-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
}

.user-filters .filter-label {
    font-weight: 600;
    font-size: var(--fs-400);
}

.user-filters .filter-search {
    flex: 1 1 220px;
}

.user-filters select.input {
    width: auto;
}

/* role pills: admin = purple (authority/power), editor = steel blue.
   thin border matches the pill's own text colour */
.badge[data-role] {
    border: 1px solid currentColor;
}

.badge[data-role="admin"] {
    background: var(--purple-soft);
    color: var(--purple-primary);
}

.badge[data-role="editor"] {
    background: var(--blue-soft);
    color: var(--blue-primary);
    border: 1px solid var(--blue-primary);
}

/* row of icon actions (manage users) */
.user-actions {
    display: flex;
    align-items: center;
    gap: 2.4px;
}

.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4.8px;
    background: none;
    border: none;
    border-radius: var(--radius-s);
    color: var(--purple-primary);
    text-decoration: none;
    cursor: pointer;
}

.icon-btn:hover {
    background: var(--purple-soft);
}

.icon-btn[data-variant="danger"] {
    color: var(--red-primary);
}

.icon-btn[data-variant="danger"]:hover {
    background: var(--red-soft);
}

/* -------------------------------------------------------------------------
   EXCEPTION — state and variant styling, via data attributes
   ------------------------------------------------------------------------- */

/* page width: admin pages run wider, the profile page narrower */
body[data-width="wide"] {
    max-width: 1200px;
}

body[data-width="narrow"] {
    max-width: 720px;
}

/* card banner states */
.card__banner[data-state="open"] {
    background: var(--green-soft);
    color: var(--green-primary);
    border-block-color: var(--green-primary);
}

/* "continuous" = open all year round; same green as an open window */
.card__banner[data-state="continuous"] {
    background: var(--green-soft);
    color: var(--green-primary);
    border-block-color: var(--green-primary);
}

/* "auto" = no application; blue signals it happens automatically */
.card__banner[data-state="auto"] {
    background: var(--blue-soft);
    color: var(--blue-primary);
    border-block-color: var(--blue-primary);
}

.card__banner[data-state="upcoming"] {
    background: var(--gold-soft);
    color: var(--gold-primary);
    border-block-color: var(--gold-primary);
}

.card__banner[data-state="closed"] {
    background: var(--grey-mid);
    color: var(--black);
    border-block-color: var(--grey-primary);
}

/* no dates set at all — quiet grey */
.card__banner[data-state="none"] {
    background: var(--grey-soft);
    color: var(--grey-primary);
    border-block-color: var(--grey-soft);
}

/* application-status dot states */
.dot[data-state="open"],
.dot[data-state="continuous"] { background: var(--green-primary); }
.dot[data-state="upcoming"] { background: var(--gold-primary); }
.dot[data-state="closed"]   { background: var(--red-primary); }
.dot[data-state="none"]     { background: var(--grey-soft); }

/* apply box tint while open */
.apply-box[data-state="open"] {
    background: var(--green-soft);
    border: 1px solid var(--green-primary);
}

/* ---- scheme profile redesign ------------------------------------------- */

/* header: status pill above the title */
.profile-head {
    margin-block-end: var(--space-l);
}

.profile-head h1 {
    margin-block: var(--space-xs) 0;
}

.profile-head .lead {
    font-size: var(--fs-500);
    color: var(--grey-primary);
    margin-block-start: var(--space-s);
}

.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    padding: 0.35em 1em;
    border-radius: 999px;
    font-size: var(--fs-300);
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.status-pill[data-state="open"] {
    background: var(--green-soft);
    color: var(--green-primary);
    border: 1px solid var(--green-primary);
}

.status-pill[data-state="upcoming"] {
    background: var(--gold-soft);
    color: var(--gold-primary);
    border: 1px solid var(--gold-primary);
}

.status-pill[data-state="closed"],
.status-pill[data-state="none"] {
    background: var(--grey-soft);
    color: var(--grey-primary);
    border: 1px solid var(--grey-soft);
}

/* key info facts sit in white cells on the lavender panel */
.ki-grid > div {
    background: var(--white);
    border: 1px solid rgba(87, 6, 140, 0.15);
    border-radius: 8px;
    padding: var(--space-s) var(--space-m);
}

.ki-grid dd .icon {
    vertical-align: -0.15em;
    color: var(--purple-primary);
}

/* application-status cell tinted to match its pill */
.ki-grid > .ki-status[data-state="open"] {
    background: var(--green-soft);
    border-color: var(--green-primary);
}

.ki-status[data-state="open"] dt {
    color: var(--green-primary);
}

.ki-grid > .ki-status[data-state="upcoming"] {
    background: var(--gold-soft);
    border-color: var(--gold-primary);
}

.ki-status[data-state="upcoming"] dt {
    color: var(--gold-primary);
}

.ki-grid > .ki-status[data-state="closed"],
.ki-grid > .ki-status[data-state="none"] {
    background: var(--grey-soft);
    border-color: var(--grey-soft);
}

.ki-status[data-state="closed"] dt,
.ki-status[data-state="none"] dt {
    color: var(--grey-primary);
}

/* pill sits on a same-coloured cell, so give it a white base to stand out */
.ki-status .status-pill {
    background: var(--white);
}

/* the two numbers a scanning student cares about most */
.ki-fee {
    font-size: var(--fs-600);
    font-weight: 800;
    color: var(--purple-primary);
}

.ki-grid > .ki-highlight {
    background: var(--white);
    border-color: rgba(87, 6, 140, 0.15);
}

.ki-highlight dd {
    font-weight: 700;
}

.ki-highlight dd .icon {
    color: var(--purple-primary);
}

/* key statement callouts */
.callout {
    display: flex;
    gap: var(--space-s);
    align-items: flex-start;
    background: var(--grey-soft);
    border-inline-start: 4px solid var(--purple-primary);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: var(--space-s) var(--space-m);
    margin-block: var(--space-s);
}

/* student testimonial / quote on the scheme page */
.scheme-quote {
    --quote-gold: #e0a51e;
    position: relative;
    margin: var(--space-l) 0;
    padding: 41.6px 0;
}

/* big decorative gold quotation marks, top-left and bottom-right */
.scheme-quote::before,
.scheme-quote::after {
    position: absolute;
    font-family: Georgia, "Times New Roman", serif;
    font-size: 72px;
    line-height: 1;
    color: var(--quote-gold);
}

.scheme-quote::before {
    content: "\201C";
    top: 0;
    left: 0;
}

.scheme-quote::after {
    content: "\201D";
    right: 0;
    bottom: -25.6px; /* the closing glyph sits high within its line box */
}

.scheme-quote p {
    margin: 0;
    font-size: var(--fs-600);
    font-style: italic;
    line-height: 1.6;
    color: var(--black);
}

/* responsive 16:9 YouTube embed on the scheme page */
.video-embed {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius);
    overflow: hidden;
}

.video-embed iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.callout .icon {
    flex-shrink: 0;
    margin-block-start: 0.2em;
    color: var(--purple-primary);
}

.callout p {
    margin: 0;
}

/* term heading, bold on its own line above the term text.
   Scoped to .callout so it outweighs the `.callout p { margin: 0 }` above. */
.callout .callout__heading {
    font-weight: 600;
    margin-block-end: var(--space-2xs);
}

/* `.callout p { margin: 0 }` above keeps a one-line callout tight; a callout
   with more than one paragraph still needs a gap between them */
.callout p + p {
    margin-block-start: var(--space-s);
}

/* the "keep notes general" line above the shortlist: small print like any
   other .hint, but with the icon held clear of the wrapping text */
.notes-disclaimer {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2xs);
    margin-block: var(--space-s) 0;
}

.notes-disclaimer .icon {
    flex-shrink: 0;
    margin-block-start: 0.15em;
}

/* the shortlist's "how this is kept" notice is small print, not body copy */
.shortlist-note {
    margin-block-start: var(--space-l);
    font-size: var(--fs-350);
}

/* -------------------------------------------------------------------------
   BLOCK — admin terms and conditions editor
   Each term is one bordered card holding its heading and its text, so a long
   list reads as separate terms rather than a wall of boxes.
   ------------------------------------------------------------------------- */

/* rows are numbered 1, 2, 3… by CSS counter, so rows added or removed in the
   browser renumber themselves without any JavaScript */
.terms-editor {
    counter-reset: term;
}

.terms-editor .row {
    background: var(--white);
    border: 1px solid var(--grey-primary);
    border-radius: var(--radius);
    padding: var(--space-m);
}

.terms-editor .row::before {
    counter-increment: term;
    content: counter(term);
    flex: none;
    min-width: 24px;
    font-weight: 700;
    color: var(--purple-primary);
    line-height: 2.5;
    text-align: right;
}

.terms-editor .row + .row {
    margin-block-start: var(--space-m);
}

/* nothing sits above the first control any more, so it starts flush with the
   top of its card. The default --grey-soft outline is near-white, so the two
   controls are given a visible edge of their own. */
.admin-form .terms-editor :is(input[type="text"], textarea) {
    display: block;
    width: 100%;
    margin-block-start: 0;
    border-color: var(--grey-mid);
}

/* space between the heading field and the term text below it */
.terms-editor input[type="text"] {
    margin-block-end: var(--space-m);
    font-weight: 600;   /* the heading reads as a heading while editing */
}

/* the timestamp brings its own margin, so the textarea needs none */
.terms-editor textarea {
    margin-block-end: 0;
}

/* trash button sits level with the first label rather than floating mid-card */
.terms-editor .del {
    margin-top: 0;
}

.terms-editor .updated {
    margin-block-end: 0;
}

/* ------------------------------------------------------------------ *
 * Basket                                                             *
 * ------------------------------------------------------------------ */

/* "Award Pack" explainer box between the search panel and the results */
.pack-info {
    margin-block: var(--space-l);
    padding: var(--space-m) var(--space-l);
    background: var(--yellow-soft);
    border: 1px solid var(--grey-soft);
    border-left: 4px solid var(--purple-primary);
    border-radius: var(--radius-s);
}

.pack-info h2 {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin: 0 0 var(--space-2xs);
    font-size: var(--fs-500);
    font-weight: 700;   /* see .search-panel h2 — the CMS sets headings to 300 */
    color: var(--purple-primary);
}

.pack-info p {
    margin: 0;
    color: var(--purple-primary);
}

/* "Filters" summary box: same shape as the shortlist note, but transparent
   with a thin border so it reads as secondary */
/* halve the gap where the filters box sits directly under the search panel
   (adjacent margins collapse, so both sides need trimming) */
.search-panel:has(+ .pack-info--plain) {
    margin-block-end: var(--space-m);
}

.search-panel + .pack-info--plain {
    margin-block-start: var(--space-m);
}

.pack-info--plain {
    background: transparent;
    /* same frame as the search panel above: even border on all four sides */
    border: 1px solid var(--grey-mid);
    border-radius: var(--radius);
    padding: var(--space-l);
}

/* matching breathing room above and below the pill row */
.filter-pills {
    margin-block-start: var(--space-m);
}

.filter-pills .chip__label {
    font-weight: 600;
}

/* pills that can be dismissed: text, then an X button on the right */
.chip--removable {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    padding-inline-end: 0.45em;
}

.chip__remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.4em;
    height: 1.4em;
    border-radius: 50%;
    background: var(--purple-primary);
    color: var(--white);
    text-decoration: none;
    transition: background-color 0.15s ease;
}

.chip__remove .icon {
    width: 0.85em;
    height: 0.85em;
}

.chip__remove:hover,
.chip__remove:focus-visible {
    background: var(--purple-mid);
}

.pack-info p.filter-pills__reset {
    margin-block-start: var(--space-m);
    font-size: var(--fs-350);
}

/* Status pills in the pack list: green when open, grey when not yet open */
.chip[data-state="open"],
.chip[data-state="continuous"] {
    background: var(--green-primary);
    color: #ffffff;
}

.chip[data-state="upcoming"],
.chip[data-state="closed"] {
    background: var(--grey-soft);
    color: var(--grey-primary);
}

/* "My Awards Pack (n)" link shown in page headers */
/* Carries .btn as well, which supplies the height, purple fill, white label,
   hover and focus ring. Only the room for the count pill belongs here — any
   colour or padding set here would outrank .btn and break the match. */
.basket-link {
    gap: var(--space-xs);
    white-space: nowrap;
}

/* white pill, purple number — reads as a count on the button rather than a
   second button, and holds its colours through the hover */
.basket-link__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22.4px;
    height: 22.4px;
    padding: 0 5.6px;
    font-size: var(--fs-300, 13.6px);
    color: var(--purple-primary);
    background: #ffffff;
    border-radius: 999px;
}

/* Apply + pack buttons sit in a row at the foot of the scheme page */
.apply-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--space-m);
    margin-block-start: var(--space-l);
}

/* Make the two buttons identical in size and keep them on one line. Only the
   width is set here — the height comes from --control-h like every other
   button, so vertical padding must stay out of it. */
.apply-actions .apply-btn,
.apply-actions .basket-toggle .btn {
    margin: 0;
    padding-inline: 28px;
    min-width: 208px;
    box-sizing: border-box;
    font: inherit;
    font-weight: 600;
    text-align: center;
    border-radius: var(--radius-s);
}

.apply-actions .basket-toggle {
    margin: 0;
}

/* Add/remove pack button on the scheme detail page */
.basket-toggle {
    margin: 0;
}

/* Add/remove button pinned to the bottom of a listing card. */
.card__basket {
    padding: var(--card-pad-y, var(--space-s)) var(--card-pad-x, var(--space-l)) var(--card-band-pad-y, var(--space-m));
    text-align: center; /* centre the button, which sizes to its label */
}

/* Basket page listing */
.basket-actions {
    margin-block: var(--space-m) var(--space-l);
    align-items: center;
}

/* Clearing the shortlist is the destructive one, so it sits away from the
   download button at the far end of the row rather than next to it. Done with
   an auto margin rather than justify-content, so that when the row wraps on a
   narrow screen it still ends up right-aligned on its own line. */
.basket-actions__clear {
    margin-inline-start: auto;
}

.basket-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
    list-style: none;
    margin: 0;
    padding: 0;
}

.basket-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-s);
    padding: var(--space-m) var(--space-l);
    background: var(--white);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius-s);
}

.basket-item.is-dragging {
    position: relative;
    z-index: 5;
    border-color: var(--purple-primary);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.2);
    cursor: grabbing;
}

/* Brief green flash on a row once it settles into a new position. */
.basket-item.just-moved {
    animation: basket-flash 1800ms ease;
}

@keyframes basket-flash {
    from { background-color: var(--green-soft); }
    to   { background-color: var(--white); }
}

/* Drag handle */
.basket-item__handle {
    flex: none;
    align-self: stretch;
    display: flex;
    align-items: center;
    padding: 0 var(--space-2xs);
    margin: calc(var(--space-m) * -1) 0;
    background: none;
    border: 0;
    color: var(--grey, #888);
    font-size: 22.4px;
    line-height: 1;
    cursor: grab;
    touch-action: none;
}

.basket-item__handle:active {
    cursor: grabbing;
}

.basket-item__handle:focus-visible {
    outline: 2px solid var(--purple-primary);
    outline-offset: 2px;
    border-radius: var(--radius-s);
}

/* Position number */
/* Position in the list, not something to press — so it is just the numeral in
   brand purple. No fill and no border: both read as a control next to the
   chevrons and Remove link sitting alongside it. The 28px box stays so the
   scheme titles line up whether the number is 1 or 21. */
.basket-item__num {
    box-sizing: border-box;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    color: var(--purple-primary);
    /* matches the scheme title beside it, so the two sit on one line */
    font-size: var(--fs-500, 19.2px);
    font-weight: 700;
}

.basket-item__body {
    flex: 1;
    min-width: 0;
}

.basket-item__body h2 {
    margin-block: 0 var(--space-2xs);
    font-size: var(--fs-500, 19.2px);
}

.basket-item__body p {
    margin-block: 0 var(--space-s);
}

/* Per-award notes (session only — never saved to the database) */
.basket-item__notes {
    margin-block-start: var(--space-s);
}

.basket-item__notes label {
    display: block;
    font-size: var(--fs-300, 14.4px);
    font-weight: 600;
    color: var(--grey, #6e6e6e);
}

.basket-item__notes textarea {
    width: 100%;
    min-height: 56px;
    padding: 8.8px 12px;
    margin-top: var(--space-2xs);
    box-sizing: border-box;
    font: inherit;
    color: inherit;
    background: var(--white);
    border: 1px solid var(--grey-mid);
    border-radius: var(--radius-s);
    resize: vertical;
}

.basket-item__notes textarea:hover {
    border-color: var(--grey-primary);
}

/* Holds the save status (and, without JS, the Save button). The min-height
   reserves the line so the row below doesn't jump when "Saved" appears. */
.basket-item__notes-actions {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    min-height: 22.4px;
    margin-top: var(--space-2xs);
}

.basket-item__notes-status {
    font-size: var(--fs-300, 14.4px);
    color: var(--grey-primary);
}

/* Right-hand controls: up/down + remove */
.basket-item__controls {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-xs);
}

.basket-item__move {
    display: flex;
    gap: var(--space-3xs, 4px);
}

.move-btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--control-h);
    height: var(--control-h);
    background: var(--white);
    border: 1px solid var(--purple-soft);
    border-radius: var(--radius-s);
    color: var(--purple-primary);
    line-height: 1;
    cursor: pointer;
}

.move-btn:hover {
    color: #ffffff;
    background: var(--purple-hover);
    border-color: var(--purple-hover);
}

/* the chevron carries the button, so give it a little more than icon() 16px */
.move-btn .icon {
    width: 20px;
    height: 20px;
}

/* `.inline-form { display: inline }` is a class selector and so outranks the
   browser's own `[hidden] { display: none }`. Without this the up / down form
   hidden on the end rows would still be on screen. */
.inline-form[hidden] {
    display: none;
}

/* Stack controls under the body on narrow screens */
@media (max-width: 600px) {
    .basket-item {
        flex-wrap: wrap;
    }

    .basket-item__controls {
        flex-basis: 100%;
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
        padding-left: calc(22.4px + 28px + var(--space-s) * 2);
    }
}

/* -------------------------------------------------------------------------
   BLOCK — funding-criteria admin (manage lookup values)
   ------------------------------------------------------------------------- */

/* hub: cards linking to each value set */
.criteria-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-l);
    margin-block: var(--space-l);
}

.criteria-card {
    display: block;
    padding: var(--space-l);
    background: var(--white);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius);
    text-decoration: none;
    color: inherit;
}

.criteria-card:hover {
    border-color: var(--purple-primary);
}

.criteria-card h2 {
    margin: 0 0 5.6px;
    font-size: var(--fs-500);
    color: var(--purple-primary);
}

.criteria-card p {
    margin: 0 0 var(--space-s);
    font-size: var(--fs-300);
    color: var(--black);
}

.criteria-card .count {
    font-weight: 600;
    font-size: var(--fs-300);
    color: var(--black);
}

/* edit-lock: listing note + editor banner */
.lock-note {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    color: var(--gold-primary);
    font-style: italic;
}

.lock-banner {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin-block-end: var(--space-m);
    padding: var(--space-s) var(--space-m);
    background: var(--gold-soft);
    border: 1px solid var(--gold-primary);
    color: var(--gold-primary);
    border-radius: var(--radius-s);
}

.last-edited {
    margin-block: 0 var(--space-m);
    text-align: right;
}

/* status filter on the admin listing */
.status-filter {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    margin-block: var(--space-m);
}

.status-filter .input {
    width: auto;
}

/* sortable table headers (admin listing) */
.sort-link {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    color: inherit;
    text-decoration: none;
}

.sort-link:hover {
    color: var(--purple-primary);
}

.sort-arrow[data-inactive] {
    opacity: 0.35;
}

/* wrapper used to disable the whole edit form when a scheme is locked */
.bare-fieldset {
    border: 0;
    margin: 0;
    padding: 0;
    min-inline-size: 0;
    background: var(--grey-soft);
}

/* edit form + delete button sit together in the Value cell */
.criteria-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-m);
}

/* criteria table: Name/Description inputs fill their columns; the Used-by
   and Actions columns shrink to their content so the fields take the space */
.criteria-table td .input {
    width: 100%;
    box-sizing: border-box;
}

/* fields wrap and grow to show all their text — no inner scrolling */
.criteria-table textarea.input {
    resize: vertical;
    overflow: hidden;
    min-height: 38.4px;
    line-height: 1.35;
    font: inherit;
}

/* with a description column, keep the name compact so description fills the
   rest; with no description, the name column fills the row instead */
.criteria-table.has-desc .cell-name {
    width: 224px;
}

.criteria-table .cell-used {
    width: 1%;
    white-space: nowrap;
}

.criteria-save {
    margin-block: var(--space-m);
}

/* inline add/edit rows */
.criteria-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-s);
    margin: 0;
}

.criteria-form .input {
    width: auto;
}

.criteria-form input[type="text"] {
    flex: 1 1 192px;
    min-width: 128px;
}

/* drag-to-reorder handle */
.criteria-table .drag-cell {
    width: 1%;
    white-space: nowrap;
    text-align: left;
    vertical-align: middle;
}

.drag-handle {
    display: inline-block;
    cursor: grab;
    opacity: 0.45;
    font-size: 16px;
    line-height: 1;
    letter-spacing: -0.15em;
    user-select: none;
    color: var(--black);
}

.drag-handle:hover {
    opacity: 1;
}

.criteria-table tr.dragging {
    opacity: 0.4;
}

/* the standalone "Add a new value" form gets a little breathing room */
h2 + .criteria-form {
    margin-block-start: var(--space-s);
}

/* where-used modal */
.usage-dialog {
    max-width: 512px;
    width: calc(100% - 32px);
    padding: var(--space-l);
    border: 1px solid var(--grey-soft);
    border-radius: var(--radius);
    color: var(--black);
}

.usage-dialog::backdrop {
    background: rgba(0, 0, 0, 0.45);
}

.usage-dialog h2 {
    margin-block: 0 var(--space-s);
    font-size: var(--fs-500);
}

.usage-dialog ul {
    margin-block: 0 var(--space-m);
    padding-inline-start: 19.2px;
}

.usage-dialog li {
    margin-block-end: 5.6px;
}

/* -------------------------------------------------------------------------
   BLOCK — site footer (public pages)
   ------------------------------------------------------------------------- */

.site-footer {
    margin-top: var(--space-l);
    padding-top: var(--space-s);
    border-top: 1px solid var(--grey-soft);
    font-size: var(--fs-350);
}

.site-footer a {
    color: var(--grey-primary) !important;
}
