/*
 * School Dashboard components. Built only from the tokens in tokens.css: no screen has its own
 * one-off styles. Mobile first: the base rules are for a 360px phone, then min-width steps
 * (600 large phone, 768 tablet, 1024 desktop, 1280 wide, 1600 extra wide).
 * The component gallery (/gallery) shows every component in every state.
 */

/* ------------------------------------------------------------------ base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* iPhone and iPad: follow Settings > Display & Text Size > Larger Text (the font family is set on body). */
@supports (font: -apple-system-body) and (-webkit-touch-callout: none) { html { font: -apple-system-body; } }
body {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  font-family: var(--font-sans); font-size: var(--text-md); line-height: var(--leading-normal);
  color: var(--ink); background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}
button, input, select, textarea { font: inherit; color: inherit; }
img, svg { display: block; max-width: 100%; }
h1, h2, h3, h4, p { margin: 0; }
h1 { font-size: var(--text-2xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); }
h2 { font-size: var(--text-lg); font-weight: var(--weight-semibold); line-height: var(--leading-snug); }
h3 { font-size: var(--text-md); font-weight: var(--weight-semibold); line-height: var(--leading-snug); }
a { color: var(--blue-text); text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
strong { font-weight: var(--weight-semibold); }
code, .mono { font-family: var(--font-mono); font-size: .9em; }
:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
::selection { background: var(--blue-150); }
[hidden] { display: none !important; }
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: var(--space-2); top: var(--space-2); z-index: 100; padding: var(--space-3) var(--space-4);
  background: var(--surface); color: var(--blue-text); border-radius: var(--radius-md); box-shadow: var(--shadow-3);
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }
.icon { width: var(--icon); height: var(--icon); flex: none; }
.icon-sm { width: var(--icon-sm); height: var(--icon-sm); flex: none; }
.muted { color: var(--muted); }
.hint { color: var(--muted); font-size: var(--text-xs); line-height: var(--leading-relaxed); }
.nowrap { white-space: nowrap; }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.stack-sm > * + * { margin-top: var(--space-2); }
.stack > * + * { margin-top: var(--space-4); }
.stack-lg > * + * { margin-top: var(--space-6); }
.cluster { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.split { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; justify-content: space-between; }
.eyebrow { font-size: var(--text-2xs); font-weight: var(--weight-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--muted); }

/* ------------------------------------------------------------------ app shell (redesign, stage 1) */
/* Each part of the app has a colour (tokens.css: --sec and its tint, text, line and icon, from data-section). The side
   menu is white with a coloured tile per item; the page's own colour is on <body>, for its band and main buttons. */
.shell { min-height: 100vh; min-height: 100dvh; }
.sidebar { display: none; }
/* overflow-x: clip keeps the band's full-width background inside the page column (it is not a scroll box, so the top
   bar stays sticky). */
.main { min-width: 0; display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; overflow-x: clip; }

.topbar {
  position: sticky; top: 0; z-index: var(--z-header);
  display: flex; align-items: center; gap: var(--space-3);
  min-height: var(--topbar-h); padding: var(--space-1) var(--gutter);
  padding-top: max(var(--space-1), env(safe-area-inset-top));
  background: var(--surface); border-bottom: 1px solid var(--line);
}
.topbar .brand-mini { display: flex; align-items: center; gap: var(--space-3); min-width: 0; flex: 1; }
.topbar .brand-mini strong { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--text-md); line-height: var(--leading-snug); }
.topbar .crumb { display: none; color: var(--muted); font-size: var(--text-sm); min-width: 0; flex: 1; white-space: nowrap; }
.topbar .crumb .place, .crumb-item > [data-truncate] { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.crumb-item { display: contents; }
.crumb-item > [data-truncate] { flex: 0 1 auto; max-width: 30%; }
.topbar .crumb strong { color: var(--ink); font-weight: var(--weight-bold); flex: none; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.topbar-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }

.content {
  width: 100%; max-width: var(--content-max); margin: 0 auto; flex: 1;
  padding: var(--space-5) var(--gutter) calc(var(--bottom-nav-h) + var(--space-8) + env(safe-area-inset-bottom));
}
.content.narrow { max-width: 60rem; }

.monogram {
  display: grid; place-items: center; flex: none;
  width: 2.375rem; height: 2.375rem; border-radius: var(--radius-lg);
  background: var(--sec-home); color: var(--on-solid); font-weight: 800; font-size: var(--text-lg);
}
.monogram.sm { width: 2rem; height: 2rem; border-radius: var(--radius-md); font-size: var(--text-sm); }
.avatar {
  display: grid; place-items: center; flex: none; width: var(--avatar); height: var(--avatar); border-radius: 50%;
  background: var(--sec-home-tint); color: var(--sec-home-text); font-size: var(--text-xs); font-weight: var(--weight-bold);
}
/* The account menu's button: the person's initials (and on computers their name and role). */
.account-button {
  display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap); min-width: var(--tap);
  padding: 4px; border: 0; border-radius: var(--radius-full); background: transparent; color: var(--ink); cursor: pointer; justify-content: center;
}
.account-button:hover { background: var(--surface-2); }
.account-button .who { text-align: left; line-height: 1.25; font-size: var(--text-sm); padding-right: var(--space-2); max-width: 14rem; min-width: 0; }
.account-button .who > span, .account-button .who small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-button .who > span { font-weight: var(--weight-semibold); }
.account-button .who small { color: var(--muted); font-size: var(--text-2xs); }
/* Below computer width the name is only for screen readers (the button shows the initials). */
@media (max-width: 63.99em) { .account-button .who { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; padding: 0; } }

/* A menu item's coloured tile (side menu, the phone's More sheet): tinted, or solid for the page you are on. */
.nav-tile { display: grid; place-items: center; flex: none; width: 1.875rem; height: 1.875rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
.nav-tile .icon { width: var(--icon-sm); height: var(--icon-sm); }

/* phone: bottom bar */
.bottom-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-nav);
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  padding: 0 max(var(--space-1), env(safe-area-inset-right)) env(safe-area-inset-bottom) max(var(--space-1), env(safe-area-inset-left));
  background: var(--surface); border-top: 1px solid var(--line);
}
.bottom-nav a, .bottom-nav button {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: var(--bottom-nav-h); padding: var(--space-1) 1px; border: 0; background: none; cursor: pointer;
  color: var(--ink-2); font-size: var(--text-2xs); font-weight: var(--weight-medium); text-decoration: none; text-align: center;
  line-height: 1.2; min-width: 0;
}
.bottom-nav .pill { display: grid; place-items: center; width: min(2.75rem, 100%); height: 1.75rem; border-radius: var(--radius-full); color: var(--sec-icon); transition: background var(--dur-fast) var(--ease); }
.bottom-nav .pill .icon { width: 1.125rem; height: 1.125rem; }
.bottom-nav [aria-current="page"] { color: var(--sec-text); font-weight: var(--weight-bold); }
.bottom-nav [aria-current="page"] .pill { background: var(--sec-tint); }
/* A label is never split. Its size is capped so the bar stays readable with very large text; if a
   label still does not fit, app.js makes the labels smaller, and as a last resort shows the icons
   alone (the names are still read out). */
.bottom-nav .label { max-width: 100%; overflow: hidden; white-space: nowrap; line-height: 1.15; font-size: var(--nav-label, min(var(--text-2xs), 13px)); }
.bottom-nav.icons-only .label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.bottom-nav.icons-only .pill { width: min(3.5rem, 100%); height: 2.25rem; }
.topbar .top-account .avatar { width: 2rem; height: 2rem; }

/* side menu (tablet: a narrow rail; computer: the full menu), white with a line on its right */
.sidebar {
  background: var(--surface); color: var(--ink);
  position: sticky; top: 0; height: 100vh; height: 100dvh; overflow-y: auto; overscroll-behavior: contain;
  flex-direction: column; gap: var(--space-1); padding: var(--space-4) var(--space-3);
}
.sidebar .brand { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-1) var(--space-2) var(--space-4); color: var(--ink); text-decoration: none; }
/* The organisation's name takes at most two balanced lines (a very long one ends in "…"; the full
   name is on Home and in the account menu); "School dashboard" stays on one line. */
.sidebar .brand > div { min-width: 0; }
.sidebar .brand strong {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; text-wrap: balance;
  font-size: var(--text-md); font-weight: var(--weight-bold); line-height: 1.25;
}
.sidebar .brand small { display: block; margin-top: 2px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--text-2xs); letter-spacing: .06em; color: var(--muted); text-transform: uppercase; font-weight: var(--weight-semibold); }
.sidebar .nav-label { margin: var(--space-4) var(--space-2) var(--space-1); font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--muted); }
.sidebar nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); }
.nav-item {
  display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap); padding: 6px var(--space-2);
  border-radius: var(--radius-md); color: var(--ink); text-decoration: none; font-size: var(--text-sm); font-weight: var(--weight-medium);
}
.nav-item.gap { margin-top: var(--space-3); }
.nav-item:hover { background: var(--surface-2); }
.nav-text { display: grid; min-width: 0; line-height: var(--leading-snug); }
.nav-text .label { overflow-wrap: break-word; }
.nav-sub { font-size: var(--text-2xs); color: var(--muted); font-weight: var(--weight-regular); }
.nav-item[aria-current="page"] { background: var(--sec-tint); }
.nav-item[aria-current="page"] .nav-tile { background: var(--sec); color: var(--on-solid); }
.nav-item[aria-current="page"] .label { color: var(--sec-text); font-weight: var(--weight-bold); }
.nav-item[aria-current="page"] .nav-sub { color: var(--sec-text); }
.sidebar .label-short { display: none; }
.sidebar .side-bottom { margin-top: auto; padding: var(--space-3) var(--space-1) 0; border-top: 1px solid var(--line); display: flex; align-items: center; gap: var(--space-1); }
.side-account { flex: 1 1 auto; justify-content: flex-start; border-radius: var(--radius-md); }
.side-signout { display: grid; place-items: center; flex: none; width: var(--tap); height: var(--tap); border: 0; border-radius: var(--radius-md); background: none; color: var(--muted); cursor: pointer; }
.side-signout:hover { background: var(--surface-2); color: var(--ink); }

@media (min-width: 48em) {
  .shell { display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr); background: linear-gradient(to right, var(--surface) calc(var(--rail-w) - 1px), var(--line) 0 var(--rail-w), transparent 0); }
  .sidebar { display: flex; padding: var(--space-3) var(--space-2); }
  .sidebar .brand { flex-direction: column; justify-content: center; padding: var(--space-1) 0 var(--space-3); }
  .sidebar .brand > div, .sidebar .nav-label, .sidebar .nav-text { display: none; }
  .sidebar .label-short { display: block; max-width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .nav-item { flex-direction: column; justify-content: center; text-align: center; gap: 4px; padding: var(--space-2) var(--space-1); font-size: var(--text-2xs); font-weight: var(--weight-semibold); min-height: 60px; }
  .nav-item[aria-current="page"] .label-short { color: var(--sec-text); font-weight: var(--weight-bold); }
  .sidebar .side-bottom { flex-direction: column; padding: var(--space-3) 0 0; }
  .side-account { flex: none; justify-content: center; }
  .bottom-nav, .topbar .top-account { display: none; }
  .content { padding-bottom: var(--space-12); }
  .topbar .brand-mini { display: none; }
  .topbar .crumb { display: flex; gap: .4em; align-items: baseline; }
}
@media (min-width: 64em) {
  .shell { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); background: linear-gradient(to right, var(--surface) calc(var(--sidebar-w) - 1px), var(--line) 0 var(--sidebar-w), transparent 0); }
  .sidebar { padding: var(--space-4) var(--space-3); }
  .sidebar .brand { flex-direction: row; justify-content: flex-start; padding: var(--space-1) var(--space-2) var(--space-4); }
  .sidebar .brand > div, .sidebar .nav-label { display: block; }
  .sidebar .nav-text { display: grid; }
  .sidebar .label-short { display: none; }
  .nav-item { flex-direction: row; justify-content: flex-start; text-align: left; gap: var(--space-3); padding: 6px var(--space-2); font-size: var(--text-sm); font-weight: var(--weight-medium); min-height: var(--tap); }
  .sidebar .side-bottom { flex-direction: row; padding: var(--space-3) var(--space-1) 0; }
  .side-account { flex: 1 1 auto; justify-content: flex-start; padding: 4px var(--space-2) 4px 4px; }
}

/* "view as" banner and other page-wide notices */
.viewas {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); justify-content: space-between;
  padding: var(--space-3) var(--gutter); background: var(--warning-bg); color: var(--warning-fg);
  border-bottom: 1px solid var(--warning-border); font-size: var(--text-sm);
}
.viewas-text { display: flex; gap: var(--space-2); align-items: center; }
.viewas strong { color: inherit; }

/* ------------------------------------------------------------------ the page's coloured band (redesign, stage 1) */
/* The band at the top of a page: in its part's colour, the full width of the page column (its background reaches the
   edges through ::before), directly under the top bar. The page's tabs sit at its bottom; the one you are on has the
   page's background, so it joins the page. */
.page-head { position: relative; isolation: isolate; display: grid; gap: var(--space-3); margin: 0 0 var(--space-5); padding: var(--space-4) 0; color: var(--sec-text); }
.page-head::before { content: ""; position: absolute; z-index: -1; inset: 0 -100vmax; background: var(--sec-tint); border-bottom: 1px solid var(--sec-line); }
.content > .page-head:first-child, .content > .band-slot:first-child > .page-head { margin-top: calc(-1 * var(--space-5)); }
/* A browser without overflow: clip (Safari before 16): the band's background stops at the page's side margins, so the
   page never scrolls sideways. */
@supports not (overflow-x: clip) { .page-head::before { inset: 0 calc(-1 * var(--gutter)); } }
.band-row { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); align-items: center; }
.band-icon { display: grid; place-items: center; flex: none; width: 2.75rem; height: 2.75rem; border-radius: var(--radius-lg); background: var(--sec); color: var(--on-solid); }
.band-icon .icon { width: 1.375rem; height: 1.375rem; }
.band-photo { flex: none; }
.band-photo .photo { width: 2.75rem; height: 2.75rem; font-size: var(--text-sm); }
/* Redesign stage 5 (4a Student): a record's initials are white on the page's solid colour, at the size of a band's tile. */
.band-photo .photo-none { background: var(--sec-solid); color: var(--on-solid); }
.page-head .titles { min-width: 0; flex: 1 1 16rem; }
.page-head h1 { color: var(--sec-text); overflow-wrap: break-word; }
.page-head .sub { margin-top: var(--space-1); font-size: var(--text-sm); color: color-mix(in oklch, var(--sec-text) 88%, var(--sec-tint)); line-height: var(--leading-relaxed); max-width: 45rem; text-wrap: pretty; }
.page-head .profile-facts { color: color-mix(in oklch, var(--sec-text) 88%, var(--sec-tint)); }
.page-head .back { justify-self: start; margin: calc(-1 * var(--space-2)) 0 calc(-1 * var(--space-2)) calc(-1 * var(--space-2)); color: var(--sec-text); font-size: var(--text-xs); }
.page-head .back:hover { background: color-mix(in oklch, var(--sec) 10%, transparent); }
.page-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-end; }
/* The page's main button is in its colour (secondary buttons stay white). */
.page-head .subnav { margin: 0; }
@media (min-width: 48em) {
  .page-head.has-tabs { padding-bottom: 0; }
  .page-head .subnav-tabs { gap: 2px; padding: 0; background: none; border: 0; border-radius: 0; }
  .page-head .subnav-tabs a { min-height: var(--tap); padding: 9px var(--space-3); border-radius: var(--radius-md) var(--radius-md) 0 0; color: var(--sec-text); font-weight: var(--weight-medium); background: none; }
  .page-head .subnav-tabs a:hover { background: color-mix(in oklch, var(--sec) 8%, transparent); color: var(--sec-text); }
  .page-head .subnav-tabs [aria-current="page"] { position: relative; background: var(--canvas); color: var(--sec-text); font-weight: var(--weight-bold); }
}
/* Redesign stage 5 (4a Staff): a page's own tabs (sectionTabs, e.g. Staff | Volunteers) at the bottom of its band, like
   the band tabs above, on every width; on a phone they wrap onto more lines. The one you are on joins the page; its
   count is a small solid pill in the page's colour. */
.page-head.has-tabs:has(> .section-tabs) { padding-bottom: 0; }
.page-head > .section-tabs { margin: 0; gap: 2px; padding: 0; background: none; border: 0; border-radius: 0; }
.page-head > .section-tabs button { flex: 0 1 auto; min-height: var(--tap); padding: 9px var(--space-3); border-radius: var(--radius-md) var(--radius-md) 0 0; color: var(--sec-text); font-weight: var(--weight-medium); background: none; }
.page-head > .section-tabs button:hover { background: color-mix(in oklch, var(--sec) 8%, transparent); color: var(--sec-text); }
.page-head > .section-tabs [aria-pressed="true"] { background: var(--canvas); color: var(--sec-text); font-weight: var(--weight-bold); }
.page-head > .section-tabs .badge { background: var(--sec-solid); color: var(--on-solid); font-weight: var(--weight-bold); }
/* Students and Staff & volunteers (pageHead cls 'title-first'), on tablets and computers: the buttons go under the title
   when they do not fit beside it, so the title stays on one line and its line under it keeps its width. Only those two
   pages: every other band keeps the layout signed off before, and on a phone the icon stays beside the title. */
@media (min-width: 37.5em) {
  .page-head.title-first .band-row > .titles { flex-basis: 24rem; }
}
@media (max-width: 37.49em) {
  .page-actions { width: 100%; }
  .page-actions > .btn { flex: 1 1 auto; }
  .page-actions > .btn-icon { flex: none; }
}
/* Redesign stage 5: a record's band buttons (Profile sheet (PDF), Edit and "…") stay on one row on a phone, a little
   narrower; a long label wraps between its words instead. A record's tabs (six on a student's page) are a little
   narrower there too, so they take two lines, not three. */
@media (max-width: 37.49em) {
  .page-actions.profile-actions { flex-wrap: nowrap; }
  .page-actions.profile-actions > .btn:not(.btn-icon) { padding-inline: var(--space-3); }
  .page-head > .section-tabs.record-tabs button { padding-inline: calc(var(--space-1) * 1.5); }
}

/* The Settings hub: a tile for each settings page, in the colour of its topic. */
.hub { display: grid; gap: var(--space-6); }
.hub-group > .eyebrow { margin-bottom: var(--space-3); }
.hub-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); grid-template-columns: minmax(0, 1fr); }
.hub-grid > li { min-width: 0; }
.hub-tile { display: flex; gap: var(--space-3); align-items: flex-start; height: 100%; padding: var(--space-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); color: var(--ink); text-decoration: none; }
.hub-tile:hover { background: var(--surface-hover); border-color: var(--sec-line); }
.hub-icon { display: grid; place-items: center; flex: none; width: 2.25rem; height: 2.25rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
.hub-icon .icon { width: 1.125rem; height: 1.125rem; }
.hub-text { display: grid; gap: 2px; align-content: start; min-width: 0; flex: 1; }
.hub-text strong { font-size: var(--text-md); overflow-wrap: break-word; }
.hub-chevron { align-self: center; color: var(--muted); }
@media (min-width: 37.5em) { .hub-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .hub-tile { flex-direction: column; } .hub-chevron { display: none; } }
@media (min-width: 64em) { .hub-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* The phone's More sheet: rows with the item's coloured tile, under Settings and Platform headings. */
.more-heading { margin: var(--space-4) 0 var(--space-2); font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--muted); }
.more-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.more-list + .more-list { margin-top: var(--space-2); }
.more-row { display: flex; align-items: center; gap: var(--space-3); min-height: 3.25rem; padding: var(--space-2) var(--space-3); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); color: var(--ink); text-decoration: none; font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.more-row:hover { background: var(--surface-2); }
.more-row .nav-tile { width: 2rem; height: 2rem; }
.more-label { flex: 1; min-width: 0; overflow-wrap: break-word; }
.more-chevron { color: var(--muted); }
.more-signout { margin-top: var(--space-5); }

/* ------------------------------------------------------------------ buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: var(--control-h); min-width: var(--tap); padding: 10px var(--space-4);
  border: 1px solid transparent; border-radius: var(--radius-md);
  background: var(--sec-action); color: var(--on-solid);   /* the main button is in the page's colour (redesign stage 2) */
  font-size: var(--text-sm); font-weight: var(--weight-semibold); line-height: 1.2; text-decoration: none; text-align: center;
  cursor: pointer; transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.btn:hover { background: color-mix(in oklch, var(--sec-action) 88%, black); }
.btn:active { transform: translateY(1px); }
.btn-secondary { background: var(--surface); color: var(--ink); border-color: var(--border-control); }
.btn-secondary:hover { background: var(--surface-2); border-color: var(--ink-2); }
.btn-quiet { background: var(--blue-100); color: var(--blue-text); }
.btn-quiet:hover { background: var(--blue-150); }
.btn-text { background: none; color: var(--blue-text); padding-inline: var(--space-2); }
.btn-text:hover { background: var(--blue-50); }
.btn-danger { background: var(--danger-solid); color: #fff; }
.btn-danger:hover { background: var(--danger-solid-hover); }
.btn-danger-text { background: none; color: var(--danger-fg); padding-inline: var(--space-2); }
.btn-danger-text:hover { background: var(--danger-bg); }
.btn-on-dark { background: var(--navy-700); color: var(--on-navy); }
.btn-on-dark:hover { background: var(--navy-800); }
.btn-block { width: 100%; }
.btn-icon { padding: 0; width: var(--tap); }
.btn-sm { padding: 6px var(--space-3); font-size: var(--text-xs); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; transform: none; }
.btn[aria-busy="true"] { cursor: progress; }
.btn[aria-busy="true"]::before {
  content: ""; width: 1em; height: 1em; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .btn[aria-busy="true"]::before { animation-duration: 3s; } }

/* ------------------------------------------------------------------ cards, tiles, lists */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); min-width: 0; }
.card-head { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; padding: var(--space-5) var(--space-5) var(--space-3); }
.card-head .hint { margin-top: 2px; }
/* The title and its line, beside the card's buttons: a long word wraps instead of pushing the buttons out. */
.card-titles { min-width: 0; }
/* Redesign stage 2: card titles 16px bold; a tinted header strip (card({ tint })) for a short list to act on. */
.card-head h2, .card-head h3 { font-size: var(--text-md); font-weight: var(--weight-bold); }
.card-tint > .card-head { padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--tint-line); background: var(--tint-bg); border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
.card-tint > .card-head h2, .card-tint > .card-head h3, .card-tint > .card-head .hint { color: var(--tint-fg); }
.card-tint > .card-head .btn-text { color: var(--tint-fg); }
.card-tint > .card-body:not(.flush) { padding-top: var(--space-4); }
.card.tint-info { --tint-bg: var(--info-bg); --tint-fg: var(--info-fg); --tint-line: var(--info-border); }
.card.tint-warning { --tint-bg: var(--warning-bg); --tint-fg: var(--warning-fg); --tint-line: var(--warning-border); }
.card.tint-danger { --tint-bg: var(--danger-bg); --tint-fg: var(--danger-fg-strong); --tint-line: var(--danger-border); }
.card.tint-success { --tint-bg: var(--success-bg); --tint-fg: var(--success-fg); --tint-line: var(--success-border); }
.card.tint-section { --tint-bg: var(--sec-tint); --tint-fg: var(--sec-text); --tint-line: var(--sec-line); }
.card-body { padding: 0 var(--space-5) var(--space-5); }
.card-body.flush { padding: 0; }
.card-foot { padding: var(--space-3) var(--space-5); border-top: 1px solid var(--line-subtle); background: var(--surface-2); border-radius: 0 0 var(--radius-lg) var(--radius-lg); font-size: var(--text-xs); color: var(--muted); }
.card.link-card { display: block; color: inherit; text-decoration: none; padding: var(--space-5); transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease); }
.card.link-card:hover { border-color: var(--blue-border-strong); box-shadow: var(--shadow-2); }
.card.link-card h2 { display: flex; align-items: center; gap: var(--space-2); }
.card.link-card p { margin-top: var(--space-2); color: var(--muted); font-size: var(--text-sm); line-height: var(--leading-relaxed); }
.grid { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 48em) { .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 80em) { .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.grid-main { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 64em) { .grid-main { grid-template-columns: minmax(0, 1.55fr) minmax(18rem, 1fr); align-items: start; } }

.stats { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr)); }
@media (min-width: 64em) { .stats { gap: var(--space-4); } }
.stats.single { grid-template-columns: minmax(0, 20rem); }   /* one figure on its own (Checks › Safeguarding checks due) */
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4); min-width: 0; }
.stat .label { font-size: var(--text-xs); color: var(--muted); line-height: var(--leading-snug); }
.stat { container-type: inline-size; }
/* Big figures fit their tile, whatever the text size (never broken mid-number). */
.stat .number { font-size: var(--text-xl); font-size: min(var(--text-xl), 14cqi); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); line-height: var(--leading-snug); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: var(--space-1); }
.stat.stat-words .number { font-size: var(--text-xl); white-space: normal; overflow: visible; text-overflow: clip; }
.stat .foot { font-size: var(--text-2xs); color: var(--muted); margin-top: var(--space-1); line-height: var(--leading-snug); }
/* Redesign stage 2: a highlighted figure is solid in the page's colour; a tone tints a figure by its meaning. */
.stat.highlight { background: var(--sec-solid); border-color: var(--sec-solid); color: var(--on-solid); }
.stat.highlight .label, .stat.highlight .foot { color: var(--on-solid); }
.stat.tone-info { background: var(--info-bg); border-color: var(--info-border); }
.stat.tone-info, .stat.tone-info .label, .stat.tone-info .foot { color: var(--info-fg); }
.stat.tone-warning { background: var(--warning-bg); border-color: var(--warning-border); }
.stat.tone-warning, .stat.tone-warning .label, .stat.tone-warning .foot { color: var(--warning-fg); }
.stat.tone-danger { background: var(--danger-bg); border-color: var(--danger-border); }
.stat.tone-danger, .stat.tone-danger .label, .stat.tone-danger .foot { color: var(--danger-fg-strong); }
.stat.tone-section { background: var(--sec-tint); border-color: var(--sec-line); }
.stat.tone-section, .stat.tone-section .label, .stat.tone-section .foot { color: var(--sec-text); }
.stat-bar { height: 6px; margin-top: var(--space-2); border-radius: var(--radius-full); background: var(--track); overflow: hidden; }
.stat-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--sec-icon); }
.stat.highlight .stat-bar { background: color-mix(in srgb, var(--on-solid) 35%, transparent); }
.stat.highlight .stat-bar > span { background: var(--on-solid); }
/* A tile that opens its page (the department dashboard, Stage 10). */
a.stat { display: block; color: inherit; text-decoration: none; transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease); }
a.stat:hover { border-color: var(--blue-border-strong); box-shadow: var(--shadow-2); }
a.stat.highlight { color: var(--on-blue); }
@media (min-width: 48em) { .stat { padding: var(--space-5); } }

.rows { list-style: none; margin: 0; padding: 0; }
.rows > li { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-5); border-top: 1px solid var(--line-subtle); min-height: 56px; }
.rows > li:first-child { border-top: 0; }
.rows .row-main { min-width: 0; flex: 1 1 14rem; }
.rows .row-main strong { display: block; overflow-wrap: break-word; }
.rows .row-actions { display: flex; flex-wrap: wrap; gap: var(--space-1); }

/* ---- Redesign stage 6 (5a Expenses, 5a Phone Expenses): Expenses › Overview */
/* The filters: one row of boxes no wider than they need, with their labels, on tablets and computers (on a phone they
   are behind the Filters button). */
.toolbar.exp-filters .field { flex: 0 1 auto; max-width: 100%; }
.toolbar.exp-filters .select { min-width: 10rem; }
/* The figures: on a phone the highlighted Spent takes the whole row and the others sit two by two. */
@media (max-width: 47.99em) { .stats.exp-stats > .stat.highlight { grid-column: 1 / -1; } }
/* The cards: on a phone in the page's order (the action cards, Latest, then the charts). On tablets and computers two to
   a row: By category on the left of the action cards (Waiting for approval above To pay back), as drawn, then By month,
   By department and Latest; with no action cards, Latest takes their place. */
.exp-overview { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
.exp-actions { display: grid; gap: var(--space-4); align-content: start; min-width: 0; }
@media (min-width: 48em) {
  .exp-overview { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exp-overview > .exp-cat { order: 1; }
  .exp-overview > .exp-actions, .exp-overview.no-actions > .exp-latest { order: 2; }
  .exp-overview > .exp-month { order: 3; }
  .exp-overview > .exp-dept { order: 4; }
  .exp-overview > .exp-latest { order: 5; }
  /* A short chart beside the long Latest list keeps its own height (one department: By month; no action cards: By category). */
  .exp-overview.no-dept > .exp-month, .exp-overview.no-actions > .exp-cat { align-self: start; }
}
/* A row of the lists: the description (a bold link) with its amount on the right, and today's line under it. In Latest the
   pills follow that line, on the right (or under it when there is no room). */
.rows.exp-rows > li { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title amount" "sub amount"; gap: 2px var(--space-3); align-items: center; }
.rows.exp-rows.with-pills > li { grid-template-areas: "title amount" "sub sub"; gap: var(--space-1) var(--space-3); }
.exp-row-title { grid-area: title; min-width: 0; overflow-wrap: break-word; }
.exp-row-amount { grid-area: amount; font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.exp-row-sub { grid-area: sub; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); min-width: 0; }
.exp-row-sub > .hint { flex: 1 1 12rem; min-width: 0; }
.exp-row-sub > .cluster { margin-left: auto; }

.kv { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-3) var(--space-6); margin: 0; }
.kv div { min-width: 0; }
.kv dt { font-size: var(--text-xs); color: var(--muted); }
.kv dd { margin: 2px 0 0; font-weight: var(--weight-semibold); overflow-wrap: break-word; }
@media (min-width: 37.5em) { .kv { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ------------------------------------------------------------------ badges, tags, notices */
.badge {
  display: inline-flex; align-items: center; gap: 5px; border-radius: var(--radius-sm); padding: 3px 8px; max-width: 100%;
  font-size: var(--text-2xs); font-weight: var(--weight-semibold); line-height: 1.4;
  background: var(--chip-bg); color: var(--ink-2);
}
.badge.dot::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge-paid { background: var(--st-paid-bg); color: var(--st-paid-fg); }
.badge-upto { background: var(--st-upto-bg); color: var(--st-upto-fg); }
.badge-late { background: var(--st-late-bg); color: var(--st-late-fg); }
.badge-future { background: var(--st-future-bg); color: var(--st-future-fg); }
.badge-need { background: var(--st-need-bg); color: var(--st-need-fg); }
.badge-purple { background: var(--purple-bg); color: var(--purple-fg); }
.badge-solid { background: var(--danger-solid); color: #fff; border-radius: var(--radius-full); min-width: 20px; justify-content: center; padding: 1px 6px; }
/* Redesign stage 2: status pills. A tinted status (Active, Left…) is round with its dot; a solid one (fee, expense and
   wage-run statuses on lists, tables and cards) is the status colour with white text and, for fee statuses, an icon. */
.badge.dot { border-radius: var(--radius-full); }
.badge .icon-xs { width: var(--icon-xs); height: var(--icon-xs); flex: none; }
.badge.solid { border-radius: var(--radius-full); padding: 3px 9px; font-weight: var(--weight-bold); color: var(--on-solid); gap: 4px; }
.badge.solid.badge-paid { background: var(--st-paid-solid); }
.badge.solid.badge-upto { background: var(--st-upto-solid); }
.badge.solid.badge-late { background: var(--st-late-solid); }
.badge.solid.badge-future { background: var(--st-future-solid); }
.badge.solid.badge-need { background: var(--st-need-solid); }
.badge.solid.badge-purple { background: var(--st-credit-solid); }
@media print { .badge.solid[class*="badge-"] { background: none; color: #000; box-shadow: inset 0 0 0 1px #000; } }
.page-head .badge-solid { background: var(--sec-solid); }   /* a count on a tab in the band ("To approve 2") */
/* Redesign stage 6 (the Expenses tabs): a tab's count is a small solid pill in the page's colour with bold white
   figures, after the label, in the tabs and in the phone's fold-out list. */
.subnav-count { color: var(--on-solid); font-weight: var(--weight-bold); }
.subnav-menu li a:has(> .subnav-count) { gap: var(--space-2); }
.tag { display: inline-flex; align-items: center; padding: 4px 8px; border: 1px solid var(--border-soft); border-radius: var(--radius-sm); font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: .04em; color: var(--ink-2); white-space: nowrap; }
/* A tag whose words come from the records (a guardian's "Mother of Zakariya Zubair"): it wraps between words when it is
   wider than its box, so a small phone with large text never scrolls sideways (the owner's note, before go-live). */
.tag-wrap { white-space: normal; max-width: 100%; overflow-wrap: break-word; }
.code-chip { display: inline-grid; place-items: center; min-width: 40px; height: 40px; padding: 0 6px; border-radius: var(--radius-md); font-size: var(--text-2xs); font-weight: var(--weight-bold); background: var(--blue-100); color: var(--blue-text); white-space: nowrap; }

.notice { display: flex; gap: var(--space-3); align-items: flex-start; padding: var(--space-3) var(--space-4); border-radius: var(--radius-lg); border: 1px solid var(--info-border); background: var(--info-bg); color: var(--info-fg); font-size: var(--text-sm); line-height: var(--leading-relaxed); }
.notice .icon { margin-top: 2px; }
.notice > div { min-width: 0; flex: 1; }
.notice strong { color: inherit; }
.notice-success { border-color: var(--success-border); background: var(--success-bg); color: var(--success-fg); }
.notice-warning { border-color: var(--warning-border); background: var(--warning-bg); color: var(--warning-fg); }
.notice-danger { border-color: var(--danger-border); background: var(--danger-bg); color: var(--danger-fg-strong); }

/* ------------------------------------------------------------------ forms */
.form { display: grid; gap: var(--space-4); max-width: var(--form-max); }
.form-grid { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 37.5em) { .form-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); } .form-grid .span-2 { grid-column: 1 / -1; } }
.field { display: grid; gap: 6px; min-width: 0; align-content: start; }
.field > label, .field > .label, fieldset > legend { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--ink); }
.field .req { color: var(--danger-fg); }
.input, .select, .textarea {
  width: 100%; min-height: var(--control-h); padding: 10px 12px;
  font-size: var(--text-md); line-height: 1.3;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border-control); border-radius: var(--radius-sm);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--muted); opacity: 1; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-2); }
/* Fields show the ring whenever they have focus (also on a date box's calendar button). */
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--focus); box-shadow: 0 0 0 var(--focus-width) color-mix(in srgb, var(--focus) 35%, transparent); }
.input::-webkit-calendar-picker-indicator { padding: 4px; border-radius: var(--radius-xs); cursor: pointer; }
.input::-webkit-calendar-picker-indicator:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 1px; }
.input[disabled], .select[disabled], .textarea[disabled], .input[readonly] { background: var(--surface-2); color: var(--muted); cursor: not-allowed; }
.textarea { min-height: 96px; resize: vertical; }
.select {
  appearance: none; -webkit-appearance: none; padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%235f6b81' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
.field[data-invalid] .input, .field[data-invalid] .select, .field[data-invalid] .textarea, [aria-invalid="true"] { border-color: var(--danger-fg); }
.field-error { display: flex; gap: 6px; align-items: flex-start; color: var(--danger-fg); font-size: var(--text-sm); line-height: var(--leading-snug); }
.field-error .icon-sm { margin-top: 1px; }
.form-error { color: var(--danger-fg); font-size: var(--text-sm); line-height: var(--leading-normal); min-height: 0; }
.form-error:empty { display: none; }
.form-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
@media (max-width: 37.49em) { .form-actions.stretch > .btn { flex: 1 1 100%; } }
.input-group { display: flex; align-items: stretch; }
.input-group .affix { display: grid; place-items: center; padding: 0 12px; border: 1px solid var(--border-control); border-right: 0; border-radius: var(--radius-sm) 0 0 var(--radius-sm); background: var(--surface-2); color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.input-group .input { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; min-width: 6rem; flex: 1; }
/* The code box (redesign stage 8, B0 2; frames 02, 03, 06, 07): one box, taller than the others, with large spaced-out
   digits that keep their width; a wrong code adds a stronger red border. The same box on the sign-in pages, the code
   window before sensitive actions, API keys and My account; its rules (paste, the phone's code offer) are the input's own. */
.input.code-input { min-height: 3.375rem; padding-inline: var(--space-4); font-size: 1.5rem; font-weight: var(--weight-semibold); letter-spacing: .35em;
  font-variant-numeric: tabular-nums; text-align: left; }
.field[data-invalid] .input.code-input { border-width: 1.5px; }

fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
fieldset > legend { padding: 0; margin-bottom: 6px; }
.choice-list { display: grid; gap: 2px; }
.choice {
  display: flex; gap: var(--space-3); align-items: flex-start; min-height: var(--tap); padding: 10px var(--space-3);
  border-radius: var(--radius-md); cursor: pointer; line-height: var(--leading-snug);
}
.choice:hover { background: var(--surface-2); }
.choice input { width: 20px; height: 20px; margin: 1px 0 0; flex: none; accent-color: var(--blue-600); cursor: pointer; }
.choice .choice-text { min-width: 0; }
.choice .choice-text small { display: block; color: var(--muted); font-size: var(--text-xs); margin-top: 2px; line-height: var(--leading-snug); }
/* Choice cards (redesign stage 2): the chosen one has the page's colour as its border, its tint behind and a filled dot. */
.choice.boxed { border: 1.5px solid var(--border-soft); background: var(--surface); padding: var(--space-3); }
.choice.boxed:has(input:checked) { border-color: var(--sec-action); box-shadow: inset 0 0 0 .5px var(--sec-action); background: var(--sec-action-tint); }
.choice.boxed input { accent-color: var(--sec-action); }
/* ---- Redesign stage 6 (README component 6, 5a Expense detail): large choice tiles (choiceTiles(): Approve | Reject in the
   claim's window), equal and side by side, an icon over the word. The chosen tile is outlined and tinted in its meaning
   (green to approve, red to reject); Reject's word is red. The radio button covers the whole tile, so the tile is the
   tap target and keeps the keyboard's focus ring. */
.choice-tiles .choice-list { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--space-2); }
.choice.choice-tile { position: relative; justify-content: center; align-items: center; min-height: 4.5rem; padding: var(--space-3) var(--space-2);
  border: 1.5px solid var(--border-soft); background: var(--surface); color: var(--ink-2); font-weight: var(--weight-semibold); text-align: center; }
.choice.choice-tile input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; }
.choice-tile .choice-text { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); }
.choice.choice-tile:hover { background: var(--surface-2); }
.choice-tile.tile-danger { color: var(--danger-fg); }
.choice-tile:has(input:checked) { font-weight: var(--weight-bold); }
.choice-tile.tile-success:has(input:checked) { border-color: var(--st-paid-solid); box-shadow: inset 0 0 0 .5px var(--st-paid-solid); background: var(--success-bg); color: var(--success-fg); }
.choice-tile.tile-danger:has(input:checked) { border-color: var(--danger-fg); box-shadow: inset 0 0 0 .5px var(--danger-fg); background: var(--danger-bg); color: var(--danger-fg-strong); }
.choice-tile.tile-section:has(input:checked) { border-color: var(--sec-action); box-shadow: inset 0 0 0 .5px var(--sec-action); background: var(--sec-action-tint); color: var(--sec-text); }
.choice-tile:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
@media (forced-colors: active) { .choice-tile:has(input:checked) { outline: 2px solid CanvasText; outline-offset: -5px; } }
.switch { display: inline-flex; align-items: center; gap: var(--space-3); min-height: var(--tap); cursor: pointer; }
.switch input { appearance: none; -webkit-appearance: none; width: 44px; height: 26px; margin: 0; border-radius: var(--radius-full); background: var(--border-control); position: relative; cursor: pointer; flex: none; transition: background var(--dur-fast) var(--ease); }
.switch input::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: var(--shadow-1); transition: transform var(--dur-fast) var(--ease); }
.switch input:checked { background: var(--blue-600); }
.switch input:checked::after { transform: translateX(18px); }
.switch input:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
/* Redesign stage 7 (7a Org settings): the boxed switch, switchField({ boxed: true }): a grey box, the label in bold with
   its hint under it on the left and the switch on the right (on stays blue, as on every switch). */
.switch.switch-box { display: flex; justify-content: space-between; gap: var(--space-4); padding: 10px var(--space-3); border-radius: var(--radius-md); background: var(--surface-2); }
.switch-box-text { display: grid; gap: 2px; min-width: 0; }
.switch-box-label { font-weight: var(--weight-bold); overflow-wrap: break-word; }
.switch-box .hint { font-weight: var(--weight-regular); }
/* The admin fee when joining a department (16 October 2026): "Pro-rata applies" is greyed, as a greyed button is, while
   "Charge when joining a department" is on (its field has .switch-locked). Only there: other switches that cannot be
   changed (Structure's "In use" without "Change settings") look as they always have. */
.switch-locked .switch { opacity: .55; cursor: not-allowed; }
.switch-locked .switch input { cursor: not-allowed; }

/* ------------------------------------------------------------------ tables */
.table-wrap { overflow: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
.table-wrap.tall { max-height: 70vh; }
.table-wrap:focus-visible { outline-offset: -3px; }
.table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--text-sm); }
.table th {
  position: sticky; top: 0; z-index: 1; text-align: left; white-space: nowrap;
  font-size: var(--text-2xs); font-weight: var(--weight-semibold); color: var(--muted);
  background: var(--surface-2); padding: 10px var(--space-4); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.table th.num { text-align: right; }
.table th.sortable { padding: 0; }
.table th .sort { display: flex; align-items: center; gap: 4px; width: 100%; min-height: var(--tap); padding: 0 var(--space-4); border: 0; border-radius: 0; background: none; color: inherit; font: inherit; cursor: pointer; white-space: nowrap; }
.table th.num .sort { justify-content: flex-end; }
.table th .sort:hover { background: var(--track); color: var(--ink); }
.table th[aria-sort] .sort { color: var(--ink); }
.table td { padding: 10px var(--space-4); border-bottom: 1px solid var(--line-subtle); vertical-align: middle; }
/* Redesign stage 2: the main cell is a bold link with a short line under it; an overdue row is faintly red. */
.table td.primary > a:not(.btn), .table td.primary > strong, .table td.primary > .row-main > a:not(.btn) { font-weight: var(--weight-bold); }
.table td.primary .hint { font-size: var(--text-2xs); }
.table tr.row-late td { background: var(--row-late-bg); }
.table td.num .hint { white-space: normal; }   /* a short line under a figure ("Other charges £12.00") wraps if the table is tight */
.card-list li.row-late .list-card { background: var(--row-late-bg); }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: var(--surface-hover); }
.table td .hint { margin-top: 2px; }
.table td .badge { white-space: nowrap; }
/* The expenses list on a wide screen: set shares of the width, so "What" has the most and a description stays on one
   or two lines, "Paid by" on one or two, and the actions wrap between buttons, never inside one. */
.table th.col-date, .table td.col-date { white-space: nowrap; }
.table td.col-date .hint { white-space: normal; }   /* a second line under a date ("expires 30 Aug 2026") may wrap */
.table td.col-actions { white-space: normal; }
.table td.col-actions .btn { margin: 2px 0; white-space: nowrap; }
/* Redesign stage 6 (5a All expenses): Expense, Category, Department, Date, Amount, Status and Actions. The Status column is
   wide enough for "Approved · to pay back" on one line on a 1280 px screen (only a narrower screen wraps it, rather than
   letting it run under the next column); the amount is bold, as drawn. The table shows from 1200 px (narrower screens
   have the cards). */
@media (min-width: 64em) {
  .table.table-expenses:not(.cards) { table-layout: fixed; }
  .table.table-expenses td .badge { white-space: normal; }
  .table.table-expenses th, .table.table-expenses td { padding-left: var(--space-2); padding-right: var(--space-2); }
  .table.table-expenses th:first-child, .table.table-expenses td:first-child { padding-left: var(--space-4); }
  .table.table-expenses th:last-child, .table.table-expenses td:last-child { padding-right: var(--space-4); }
  .table.table-expenses th.col-tick { width: 3.75rem; }
  .table.table-expenses th.col-tick, .table.table-expenses td.col-tick { padding-left: var(--space-2); }
  .table.table-expenses th.col-cat { width: 11%; }
  .table.table-expenses th.col-dept { width: 14.5%; }
  .table.table-expenses th.col-date { width: 11%; }
  .table.table-expenses th.col-amount { width: 8%; }
  .table.table-expenses th.col-status { width: 20%; }
  .table.table-expenses th.col-actions { width: 19%; }
  /* Waiting approval only (with the tick boxes): its pill is shorter. */
  .table.table-expenses.is-selecting th.col-amount { width: 7%; }
  .table.table-expenses.is-selecting th.col-status { width: 16.5%; }
  .table.table-expenses td.col-amount { font-weight: var(--weight-bold); }
}
.table .cell-actions { text-align: right; white-space: nowrap; }
.table .cell-actions .btn { vertical-align: middle; }
.table-foot { padding: var(--space-3) var(--space-5); font-size: var(--text-xs); color: var(--muted); border-top: 1px solid var(--line-subtle); background: var(--surface-2); border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
/* Filter chips (redesign stage 2): the chosen one is dark; the others white with a border in their status colour. */
.filter-chips { display: flex; flex-wrap: wrap; gap: 0 var(--space-2); }
.filter-chip { display: inline-flex; align-items: center; justify-content: center; min-height: var(--tap); min-width: var(--tap); padding: 0; border: 0; background: none; cursor: pointer; font: inherit; }
.filter-chip .pill { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border: 1px solid var(--chip-line, var(--border-soft)); border-radius: var(--radius-full);
  background: var(--surface); color: var(--chip-fg, var(--ink-2)); font-size: var(--text-xs); font-weight: var(--weight-semibold); line-height: 1.3; white-space: nowrap; }
.filter-chip .count { font-weight: var(--weight-regular); }
.filter-chip:hover .pill { background: var(--surface-2); }
.filter-chip[aria-pressed="true"] .pill { background: var(--ink); border-color: var(--ink); color: var(--surface); }
/* The focus ring goes round the whole chip (its 44 px tap area), so it shows on the button that has the focus. */
.filter-chip { border-radius: var(--radius-full); }
.filter-chip:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 0; }
.filter-chip.chip-paid { --chip-line: var(--st-paid-solid); --chip-fg: var(--st-paid-fg); }
.filter-chip.chip-upto { --chip-line: var(--st-upto-solid); --chip-fg: var(--st-upto-fg); }
.filter-chip.chip-late { --chip-line: var(--st-late-solid); --chip-fg: var(--st-late-fg); }
.filter-chip.chip-future { --chip-line: var(--st-future-solid); --chip-fg: var(--st-future-fg); }
.filter-chip.chip-need { --chip-line: var(--st-need-solid); --chip-fg: var(--st-need-fg); }
/* Redesign stage 5 (E4, Students list): a filter that is set, as a dark chip with × under the filters ("Qaida level: 3");
   × removes it. A long value wraps between words. */
.set-filters { display: flex; flex-wrap: wrap; gap: 0 var(--space-2); padding: 0 var(--space-5) var(--space-2); }
.filter-chip.removable { max-width: 100%; }
.filter-chip.removable .pill { max-width: 100%; background: var(--ink); border-color: var(--ink); color: var(--surface); white-space: normal; overflow-wrap: break-word; text-align: left; }
.filter-chip.removable:hover .pill { background: var(--ink-2); border-color: var(--ink-2); }
.filter-chip.removable .icon-xs { width: var(--icon-xs); height: var(--icon-xs); flex: none; }
.toolbar { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; padding: 0 var(--space-5) var(--space-4); }
.toolbar .field { flex: 1 1 12rem; }
.toolbar.bare { padding: 0 0 var(--space-4); }
.toolbar.bare .field { max-width: 24rem; }
/* ---- Redesign stage 6 (5a All expenses, 5a To approve, 8a To pay back, E5 My claims): the expense lists */
/* "Show" as chips with counts, on a row of its own above the other filters (in the phone's Filters sheet, one of them). */
.toolbar .field.chip-field { flex: 1 1 100%; max-width: none; }
/* Reversed and Reversal: a plain grey label beside the status pill, no dot (README component 4). */
.badge.badge-grey { border-radius: var(--radius-full); padding: 3px 9px; font-weight: var(--weight-bold); }
/* A list's heading on the page ("2 claims waiting for approval", "3 claims"). */
.list-title { font-size: var(--text-md); font-weight: var(--weight-bold); }
/* The amber bar above claims to approve: "2 claims selected · £61.50" (or the hint) and Approve selected. */
.select-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  border: 1px solid var(--warning-border); border-radius: var(--radius-lg); background: var(--warning-bg); color: var(--warning-fg); font-size: var(--text-sm); }
.select-bar-text { flex: 1 1 14rem; min-width: 0; }
.select-bar.has-picks .select-bar-text { font-weight: var(--weight-bold); }
.card .select-bar { margin: 0 var(--space-5) var(--space-4); }
/* One claim as a card: the tick, the receipt's picture, the claim (description, line, pills), the amount and buttons. */
.claim-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.stack > .claim-list:not(:first-child) { margin-top: var(--space-3); }
/* A phone or tablet card's amount (All expenses): on the right of the title, also when it goes under a long one. */
.list-card-amount { margin-left: auto; }
.claim-card { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr) auto; grid-template-areas: "thumb main end"; align-items: center; gap: var(--space-4);
  padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.claim-card.has-lead { grid-template-columns: var(--tap) 7.5rem minmax(0, 1fr) auto; grid-template-areas: "lead thumb main end"; }
.claim-card.tone-warning { border-color: var(--warning-border); box-shadow: inset 0 0 0 .5px var(--warning-border); }
.claim-card.tone-info { border-color: var(--info-border); box-shadow: inset 0 0 0 .5px var(--info-border); }
.claim-lead { grid-area: lead; display: grid; place-items: center; }
.claim-receipt { grid-area: thumb; display: grid; place-items: center; height: 5.625rem; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md);
  background: var(--surface-2); color: var(--ink-2); }
.claim-receipt img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
a.claim-receipt:hover { border-color: var(--ink-2); }
.claim-receipt.is-none { padding: var(--space-2); border: 1px dashed var(--border-control); color: var(--muted); font-size: var(--text-2xs); font-weight: var(--weight-semibold);
  line-height: 1.3; text-align: center; }
.claim-main { grid-area: main; display: grid; gap: var(--space-1); min-width: 0; }
.claim-name { font-size: var(--text-md); overflow-wrap: break-word; }
.claim-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.claim-end { grid-area: end; display: grid; justify-items: end; gap: var(--space-2); }
.claim-amount { font-size: var(--text-xl); line-height: 1.2; font-variant-numeric: tabular-nums; white-space: nowrap; }
.claim-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); }
/* Mark as paid back: a white button in the To pay back blue (plan B3). */
.claim-card.tone-info .claim-actions .btn-secondary { border-color: var(--st-upto-solid); color: var(--st-upto-fg); }
/* On a phone: the picture small on the left of the description and the amount, the lines under them, and the buttons
   full width underneath (the tick box at their left). */
@media (max-width: 47.99em) {
  .claim-card, .claim-card.has-lead { grid-template-columns: min-content minmax(0, 1fr); align-items: start; gap: var(--space-1) var(--space-2); padding: var(--space-3);
    grid-template-areas: "thumb title" "thumb amount" "meta meta" "status status" "actions actions"; }
  .claim-card.has-lead { grid-template-areas: "thumb title" "thumb amount" "meta meta" "status status" "lead actions"; }
  .claim-main, .claim-end { display: contents; }
  .claim-name { grid-area: title; }
  .claim-meta { grid-area: meta; }
  .claim-status { grid-area: status; }
  .claim-amount { grid-area: amount; font-size: var(--text-lg); }
  .claim-actions { grid-area: actions; margin-top: var(--space-2); }
  .claim-actions > .btn { flex: 1 1 0; min-width: max-content; }
  .claim-lead { margin-top: var(--space-2); }
  .claim-lead:has(> [aria-hidden="true"]:empty) { display: none; }
  .claim-receipt { width: 56px; height: 56px; }
  .claim-receipt.is-none { width: auto; min-width: 56px; height: auto; min-height: 56px; padding: var(--space-1); }
  .card .select-bar { margin-inline: var(--space-3); }
  .select-bar > .btn { flex: 1 1 100%; }
}
/* To pay back's blue summary band: "1 claim to pay back · £14" and who it is owed to; on a phone the amount first, large. */
.payback-band { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--info-border);
  border-radius: var(--radius-lg); background: var(--info-bg); color: var(--info-fg); }
.payback-band .fig-icon { background: var(--st-upto-solid); }
.payback-band > div { min-width: 0; }
.payback-band h2 { color: inherit; font-size: var(--text-md); font-weight: var(--weight-bold); }
.payback-band p { font-size: var(--text-xs); }
@media (max-width: 47.99em) {
  .payback-band .fig-icon, .payback-sep { display: none; }
  .payback-band h2 { display: flex; flex-direction: column-reverse; font-size: var(--text-sm); }
  .payback-amount { font-size: var(--text-xl); }
}
/* A line under a list, in a small bordered strip (To pay back's footnote). */
.list-footnote { padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); color: var(--muted);
  font-size: var(--text-xs); }
/* phones, tablets and small laptops (below 1200px): each row becomes a card, with the column name
   above each value, so no column or button is ever hidden off to the side */
@media (max-width: 74.99em) {
  .table.cards thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table.cards, .table.cards tbody, .table.cards tr, .table.cards td { display: block; width: 100%; }
  .table.cards tr { margin: 0 var(--space-3) var(--space-3); width: auto; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); padding: var(--space-2) 0; }
  .table.cards tbody tr:hover td { background: none; }
  .table.cards tr { container-type: inline-size; }
  .table.cards td { border: 0; padding: 6px var(--space-4); display: grid; grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr); gap: var(--space-3); text-align: left; white-space: normal; overflow-wrap: break-word; }
  .table.cards td::before { content: attr(data-label); color: var(--muted); font-size: var(--text-xs); line-height: 1.8; }
  /* A pill keeps its own width (not the whole column) and wraps when the column is narrower ("Schedule needed" at 360 px). */
  .table.cards td > .badge { justify-self: start; white-space: normal; }
  .table.cards td > .count-pill { justify-self: start; }
  .table.cards td.primary { display: block; font-size: var(--text-md); padding-bottom: var(--space-2); }
  .table.cards td.primary::before { display: none; }
  .table.cards td.num { text-align: left; }
  .table.cards td.cell-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); border-top: 1px solid var(--line-subtle); margin-top: var(--space-2); padding-top: var(--space-2); }
  .table.cards td.cell-actions::before { display: none; }
  .card .table-wrap:has(.table.cards) { overflow: visible; }
  /* A narrow card (a phone with larger text): each label above its value, so no word is split. */
  @container (max-width: 18rem) { .table.cards td { grid-template-columns: minmax(0, 1fr); gap: 2px; } }
}
/* An icon (monogram) and a name: the name moves under the icon when there is no room beside it. */
.name-with-icon { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.name-with-icon > div { flex: 1 1 10rem; min-width: 0; overflow-wrap: break-word; }
/* Compact cards (People): a short summary per row; tapping one opens the details. They replace
   the table below laptop width. */
.card-list { display: none; list-style: none; margin: 0; padding: 0 var(--space-3) var(--space-3); gap: var(--space-2); grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr)); }
@media (max-width: 74.99em) {
  .card-list { display: grid; }
  .table-wrap.wide-table { display: none; }
}
.list-card {
  display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--tap); padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); color: var(--ink);
  font: inherit; font-size: var(--text-sm); text-align: left; cursor: pointer;
}
.list-card:hover { background: var(--surface-hover); }
.list-card-main { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
.list-card-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-1) var(--space-2); }
.list-card-main strong { font-size: var(--text-md); overflow-wrap: break-word; min-width: 0; }
.list-card-main .hint { overflow-wrap: break-word; }
.list-card > .icon-sm { color: var(--muted); }
/* Redesign stage 5 (4a Phone Students): a photo or initials on the left of a card. */
.list-card-lead { display: flex; flex: none; align-self: center; }
/* A compact card with its own row of actions under it (Students & fees, Record a payment). */
.list-card-item { display: grid; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.list-card-item > .list-card { border: 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
.list-card-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-2) var(--space-3) var(--space-3); border-top: 1px solid var(--line-subtle); }

/* ------------------------------------------------------------------ tabs (segmented) */
/* Tabs wrap onto a second line rather than hiding any of them off to the side. */
.tabs { display: flex; flex-wrap: wrap; gap: 4px; padding: 4px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.tabs a, .tabs button { flex: 1 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: var(--tap); padding: 6px 14px; border: 0; border-radius: var(--radius-md); background: none; color: var(--muted); font-size: var(--text-sm); font-weight: var(--weight-semibold); text-decoration: none; cursor: pointer; white-space: nowrap; }
/* A tab wider than the whole row (larger text on a phone) wraps its words instead of sticking out. */
.tabs a, .tabs button { max-width: 100%; }
@media (max-width: 37.5em) { .tabs a, .tabs button { white-space: normal; text-align: center; } }
.tabs a:hover, .tabs button:hover { background: var(--surface-2); color: var(--ink); }
.tabs [aria-current="page"], .tabs [aria-selected="true"], .tabs [aria-pressed="true"] { background: var(--blue-600); color: var(--on-blue); }

/* The pages of one menu item: tabs from tablet width, a drop-down list on phones. */
.subnav { margin-bottom: var(--space-5); }
.subnav-tabs { display: none; }
.subnav-tabs a { flex: 0 1 auto; }
.subnav-menu { border: 1px solid var(--border-control); border-radius: var(--radius-md); background: var(--surface); }
.subnav-menu > summary { display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap); padding: var(--space-2) var(--space-4); cursor: pointer; list-style: none; }
/* With larger text the label and the current page stack when they do not fit side by side. */
.subnav-menu > summary { flex-wrap: wrap; row-gap: 0; }
.subnav-menu > summary::-webkit-details-marker { display: none; }
.subnav-menu > summary::after { content: ""; flex: none; margin-left: auto; width: 8px; height: 8px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-2px); transition: transform var(--dur-fast) var(--ease); }
.subnav-menu[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }
.subnav-menu-label { color: var(--muted); font-size: var(--text-sm); }
.subnav-menu:not([open]) > nav { display: none; }
.subnav-menu ul { border-top: 1px solid var(--line-subtle); padding: var(--space-1); }
.subnav-menu li a { display: flex; align-items: center; min-height: var(--tap); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); color: var(--ink); text-decoration: none; }
.subnav-menu li a:hover { background: var(--surface-2); }
.subnav-menu li a[aria-current="page"] { background: var(--sec-tint); color: var(--sec-text); font-weight: var(--weight-semibold); }
@media (min-width: 48em) { .subnav-tabs { display: flex; } .subnav-menu { display: none; } }

/* ------------------------------------------------------------------ dialogs and bottom sheets */
.dialog {
  width: min(560px, calc(100% - 32px)); max-height: min(88vh, 100% - 32px); padding: 0; border: 0;
  border-radius: var(--radius-xl); background: var(--surface); color: var(--ink); box-shadow: var(--shadow-dialog);
  overflow: hidden; display: flex; flex-direction: column;
}
.dialog:not([open]) { display: none; }
.dialog.wide { width: min(900px, calc(100% - 32px)); }
.dialog.medium { width: min(640px, calc(100% - 32px)); }
.dialog::backdrop { background: var(--backdrop); backdrop-filter: blur(2px); }
/* Redesign stage 2: a header strip tinted by meaning (the page's colour unless it approves or pays, success, or reverses
   or deletes, danger), with an icon tile; on a phone the sheet's header is plain, as drawn. */
.dialog-head { display: flex; gap: var(--space-3); align-items: center; padding: var(--space-4) var(--space-5); border-bottom: 1px solid transparent; }
.dialog-head h2 { font-size: var(--text-lg); font-weight: var(--weight-bold); line-height: var(--leading-tight); color: var(--dlg-fg); }
.dialog-titles { min-width: 0; flex: 1; }
.dialog-icon { display: grid; place-items: center; width: 38px; height: 38px; flex: none; border-radius: var(--radius-md); background: var(--dlg-solid); color: var(--on-solid); }
.dialog-head.tone-section { --dlg-tint: var(--sec-tint); --dlg-fg: var(--sec-text); --dlg-solid: var(--sec-solid); --dlg-line: var(--sec-line); }
.dialog-head.tone-success { --dlg-tint: var(--success-bg); --dlg-fg: var(--success-fg); --dlg-solid: var(--st-paid-solid); --dlg-line: var(--success-border); }
.dialog-head.tone-danger { --dlg-tint: var(--danger-bg); --dlg-fg: var(--danger-fg-strong); --dlg-solid: var(--danger-solid); --dlg-line: var(--danger-border); }
.dialog-head.tone-warning { --dlg-tint: var(--warning-bg); --dlg-fg: var(--warning-fg); --dlg-solid: var(--st-need-solid); --dlg-line: var(--warning-border); }
@media (min-width: 37.5em) {
  .dialog-head { background: var(--dlg-tint); border-bottom-color: var(--dlg-line); }
  .dialog-head > .btn-text { background: var(--surface); border-radius: var(--radius-full); }
  .dialog-head > .btn-text:hover { background: var(--surface-2); }
}
.dialog-head.raised { border-bottom-color: var(--line); }
.dialog-sub { color: var(--muted); font-size: var(--text-sm); line-height: var(--leading-relaxed); margin: 0 0 var(--space-4); }
/* flex: 1 1 auto with min-height: 0 lets the body shrink and scroll inside the sheet on every browser (iPhone included). */
.dialog-body { padding: var(--space-4) var(--space-5) var(--space-6); overflow-y: auto; overscroll-behavior: contain; flex: 1 1 auto; min-height: 0; }
.dialog .form { max-width: none; }
.dialog-foot { display: flex; flex: none; flex-wrap: wrap-reverse; gap: var(--space-2); justify-content: flex-end; padding: var(--space-3) var(--space-5) var(--space-4); border-top: 1px solid var(--line); background: var(--surface-2); position: relative; }
.dialog-foot.raised { box-shadow: var(--shadow-edge); }
.dialog-head { flex: none; }
.dialog .grip { display: none; }
@media (max-width: 37.49em) {
  .dialog, .dialog.wide, .dialog.medium { width: 100%; max-width: 100%; max-height: 92vh; max-height: 92dvh; margin: auto 0 0; border-radius: var(--radius-xl) var(--radius-xl) 0 0; padding-bottom: env(safe-area-inset-bottom); }
  .dialog[open] { animation: sheet-up var(--dur) var(--ease); }
  .dialog .grip { display: block; width: 40px; height: 4px; border-radius: 2px; background: var(--border-soft); margin: var(--space-2) auto 0; flex: none; }
  .dialog-head { padding-top: var(--space-3); }
  .dialog-foot > .btn { flex: 1 1 auto; min-height: 48px; }
  .dialog-foot > .btn:last-child { flex-grow: 2; }
}
@media (min-width: 37.5em) { .dialog[open] { animation: pop-in var(--dur) var(--ease); } }
@keyframes sheet-up { from { transform: translateY(40px); opacity: .6; } }
@keyframes pop-in { from { transform: scale(.97); opacity: 0; } }

/* account menu (a small panel under the account button) */
.menu { position: absolute; z-index: var(--z-toast); min-width: 240px; max-width: calc(100vw - 24px); padding: var(--space-2); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-3); }
.menu .menu-head { padding: var(--space-2) var(--space-3) var(--space-3); border-bottom: 1px solid var(--line-subtle); margin-bottom: var(--space-1); overflow-wrap: break-word; }
.menu a, .menu button { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--tap); padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-md); background: none; color: var(--ink); text-decoration: none; font-size: var(--text-sm); cursor: pointer; text-align: left; }
.menu a:hover, .menu button:hover { background: var(--surface-2); }
.menu .danger { color: var(--danger-fg); }
.menu .menu-org { margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--line-subtle); font-size: var(--text-sm); font-weight: var(--weight-semibold); overflow-wrap: break-word; }
.menu .menu-text { display: grid; gap: 2px; }
.menu .menu-text small { font-size: var(--text-xs); color: var(--muted); }
.menu .is-disabled, .menu .is-disabled.danger { color: var(--muted); }

/* ---- Redesign stage 6 (README "Phone primary action"; stage 1 answer E5): the floating main button of an Expenses page
   on a phone (floatingButton(), "Log an expense"), a pill in the page's colour at the bottom right above the bottom bar.
   It takes the place of the band's button there (has-fab), and the page leaves room at its foot so it never covers the
   last line. Toasts stay above it (--z-toast). Tablets and computers keep the band's button only. */
.fab { position: fixed; right: var(--gutter); bottom: calc(var(--bottom-nav-h) + var(--space-4) + env(safe-area-inset-bottom)); z-index: var(--z-nav);
  max-width: calc(100% - 2 * var(--gutter)); padding: var(--space-3) var(--space-5); border-radius: var(--radius-full); box-shadow: var(--shadow-toast); font-weight: var(--weight-bold); }
.fab.fab-demo { position: static; max-width: 100%; }
@media (min-width: 48em) { .fab:not(.fab-demo) { display: none; } }
@media (max-width: 47.99em) {
  .page-actions > .has-fab, .page-actions:has(> .has-fab:only-child) { display: none; }
  .content:has(> .fab) { padding-bottom: calc(var(--bottom-nav-h) + var(--space-4) + var(--tap) + var(--space-8) + env(safe-area-inset-bottom)); }
}

/* ------------------------------------------------------------------ toasts */
.toasts { position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(var(--bottom-nav-h) + var(--space-4) + env(safe-area-inset-bottom)); z-index: var(--z-toast); display: grid; gap: var(--space-2); width: min(32rem, calc(100% - 24px)); pointer-events: none; }
@media (min-width: 48em) { .toasts { bottom: var(--space-6); } }
.toast { pointer-events: auto; display: flex; gap: var(--space-3); align-items: center; padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4); background: var(--navy-900); color: var(--on-navy); border-radius: var(--radius-md); box-shadow: var(--shadow-toast); font-size: var(--text-sm); line-height: var(--leading-snug); animation: toast-in var(--dur) var(--ease); }
.toast .msg { flex: 1; min-width: 0; padding: var(--space-2) 0; }
.toast .icon { color: var(--on-navy-ok); }
.toast.error .icon { color: var(--on-navy-error); }
.toast button { color: var(--on-navy-2); }
.toast button:hover { background: var(--navy-800); color: var(--on-navy); }
.toast button:focus-visible { outline-color: var(--focus-on-dark); }
@keyframes toast-in { from { transform: translateY(8px); opacity: 0; } }

/* ------------------------------------------------------------------ empty states and loading */
/* Empty and error states (redesign stage 2): left-aligned, a grey icon tile, the title, a line and one button. On the
   page itself (under the band) the title is larger. */
.empty { display: grid; justify-items: start; gap: var(--space-3); padding: var(--space-6) var(--space-5); text-align: left; color: var(--ink-2); }
.empty .empty-icon { display: grid; place-items: center; width: 56px; height: 56px; border-radius: var(--radius-lg); background: var(--chip-bg); color: var(--ink-2); }
.empty .empty-icon .icon { width: 26px; height: 26px; }
.empty p { max-width: 36rem; line-height: var(--leading-relaxed); }
.empty strong { color: var(--ink); font-size: var(--text-md); }
.content > .empty { padding-inline: 0; }
.content > .empty strong { font-size: var(--text-xl); line-height: var(--leading-tight); }
.content > .empty p { font-size: var(--text-md); }
.skel { border-radius: var(--radius-md); background: linear-gradient(90deg, var(--skeleton-a) 25%, var(--skeleton-b) 50%, var(--skeleton-a) 75%); background-size: 200% 100%; animation: shimmer 1.3s ease-in-out infinite; }
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }
.loading-page { display: grid; gap: var(--space-4); }
.loading-page > .stats { margin-top: var(--space-3); }
.skel.skel-lg { border-radius: var(--radius-lg); }   /* the shape of a card or a figure tile */
/* The loading card while an organisation opens (app.js, and the server's first card in Pages.php): a wider gap before each group of shapes, a smaller one inside it. */
.skel.skel-gap { margin-top: calc(var(--space-6) + var(--space-1)); }
.skel.skel-gap-sm { margin-top: calc(var(--space-3) + var(--space-1) / 2); }

/* ------------------------------------------------------------------ sign-in
   The page's first loading card and the needs-JavaScript card (the server's page). The sign-in pages themselves are in the
   "Redesign stage 8: the sign-in pages" block at the end. */
.auth { min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: var(--space-6) var(--gutter); background: radial-gradient(1200px 600px at 10% -10%, var(--blue-100), transparent 60%), var(--canvas); }
.auth-card { width: 100%; max-width: 26.875rem; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-xl); box-shadow: var(--shadow-3); padding: var(--space-6) var(--space-5); }
@media (min-width: 37.5em) { .auth-card { padding: var(--space-8); } }
.auth-card h1 { font-size: var(--text-2xl); }
.auth-card .lead { margin-top: var(--space-2); color: var(--muted); line-height: var(--leading-relaxed); }
.auth-card form { margin-top: var(--space-5); }
.resend { display: grid; justify-items: start; gap: var(--space-1); margin-top: var(--space-4); }

/* ------------------------------------------------------------------ structure tree, permissions, codes */
.tree { list-style: none; margin: 0; padding: 0; }
.tree .tree { margin-left: var(--space-4); padding-left: var(--space-3); border-left: 2px solid var(--line); }
@media (min-width: 48em) { .tree .tree { margin-left: var(--space-6); } }
/* One tidy row per entry, with a line between rows; the actions sit behind "…". */
.tree > li + li { border-top: 1px solid var(--line); }
.tree .tree > li:first-child { border-top: 1px solid var(--line-subtle); }
.tree-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; min-height: 64px; }
.tree { container-type: inline-size; }
.tree-item .code-chip { min-width: 3.75rem; }
/* A narrow row (a phone with larger text) leaves the name room to breathe: the code is on the line below anyway. */
@container (max-width: 17rem) { .tree-item .code-chip { display: none; } }
.tree-item .row-main { min-width: 0; flex: 1 1 auto; }
.tree-item .row-main strong { overflow-wrap: break-word; }
.tree-item .hint { margin-top: 2px; }
.tree-item .lock { display: inline-flex; vertical-align: -2px; margin-left: 4px; color: var(--muted); }
.tree-actions { display: flex; align-items: center; gap: var(--space-1); flex: none; }
.wide-only { display: none; }
@media (min-width: 48em) { .wide-only { display: inline-flex; } }
.wide-block { display: none; }
.narrow-only { display: block; }
@media (min-width: 48em) { .wide-block { display: block; } .narrow-only { display: none; } }
@media (max-width: 47.99em) { .tree-facts { display: none; } }
.perm-group { border: 1px solid var(--line); border-radius: var(--radius-lg); padding: var(--space-3); }
.perm-group > legend { padding: 0 var(--space-2); }
.perm-groups { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 56.25em) { .perm-groups { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* ---- Redesign stage 7: People & access, Roles & permissions, Structure, My account (7a People, Roles, Structure,
   Account). Each role in its own colour (plan B5), from the part of the app it is closest to: roleChip() and roleSquare()
   put the role's section on the chip, so it takes that section's tint and text (AA in light and dark, as the bands). */
.badge.role-chip { background: var(--sec-tint); color: var(--sec-text); font-weight: var(--weight-bold); }
.role-square { display: inline-block; flex: none; width: 10px; height: 10px; border-radius: 3px; background: var(--sec-solid); }
/* People & access: each role's chip with where it applies under it in grey; an end date in amber, as drawn. */
.access-list { display: grid; gap: var(--space-2); }
.access-item { display: grid; justify-items: start; gap: 2px; }
.kv-rows dd .access-item { justify-items: end; }
.ends-on { color: var(--warning-fg); }
/* Roles & permissions: the square and the role's name, the number of people at the top right, then the tags. */
.role-cards { list-style: none; margin: 0; padding: 0; }
.role-card { display: flex; flex-direction: column; height: 100%; }
.role-card > .card-head { display: grid; justify-content: stretch; gap: var(--space-2); }
.role-card-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); min-width: 0; }
.role-card-title h2 { min-width: 0; overflow-wrap: break-word; }
.role-card-title h2 > .role-square { margin-right: var(--space-2); vertical-align: .1em; }   /* stays beside the name when it wraps */
.role-count { flex: none; margin-left: auto; font-size: var(--text-xs); color: var(--muted); }
.role-card > .card-body { flex: 1; }
.role-perms { margin-top: var(--space-3); font-size: var(--text-sm); }
.role-card > .card-foot { background: none; }
/* Structure: a department's row tinted in its colour (as its card on Departments), its code chip solid in that colour
   and its words in the colour's text shade; an inactive department grey. The other levels keep their plain rows. */
.tree > li.dept-li, .tree > li + li.dept-li { border-top: 0; }
.tree > li.dept-li + li.dept-li { margin-top: var(--space-2); }
.tree-item.dept-row { --dept-ink: var(--ink-2); --dept-solid: var(--st-future-solid); --dept-on: var(--on-solid);
  padding-inline: var(--space-3); border-radius: var(--radius-lg); background: var(--surface-2); }
.tree-item.dept-row.d1 { --dept-ink: var(--dept-text-1); background: color-mix(in srgb, var(--dept-1) 11%, var(--surface)); }
.tree-item.dept-row.d2 { --dept-ink: var(--dept-text-2); background: color-mix(in srgb, var(--dept-2) 11%, var(--surface)); }
.tree-item.dept-row.d3 { --dept-ink: var(--dept-text-3); background: color-mix(in srgb, var(--dept-3) 11%, var(--surface)); }
.tree-item.dept-row.d4 { --dept-ink: var(--dept-text-4); background: color-mix(in srgb, var(--dept-4) 11%, var(--surface)); }
.tree-item.dept-row.d5 { --dept-ink: var(--dept-text-5); background: color-mix(in srgb, var(--dept-5) 11%, var(--surface)); }
.tree-item.dept-row.d6 { --dept-ink: var(--dept-text-6); background: color-mix(in srgb, var(--dept-6) 11%, var(--surface)); }
.tree-item.dept-row.d7 { --dept-ink: var(--dept-text-7); background: color-mix(in srgb, var(--dept-7) 11%, var(--surface)); }
.tree-item.dept-row.d8 { --dept-ink: var(--dept-text-8); background: color-mix(in srgb, var(--dept-8) 11%, var(--surface)); }
.tree-item.dept-row.tinted { --dept-solid: var(--dept-ink); --dept-on: var(--surface); }
.tree-item.dept-row .code-chip { background: var(--dept-solid); color: var(--dept-on); }
.tree-item.dept-row .row-main strong, .tree-item.dept-row .hint, .tree-item.dept-row .lock { color: var(--dept-ink); }
/* Structure's Levels: a numbered circle before each level; the department level solid, its box tinted in the page's
   action blue; a level not in use greyed (its fields keep their colours, so they stay readable). */
.level-box > legend { float: left; width: 100%; display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); padding: 0; font-weight: var(--weight-bold); }
.level-box > legend + * { clear: both; }
.level-num { display: grid; place-items: center; flex: none; width: 1.5rem; height: 1.5rem; border-radius: 50%; background: var(--st-future-solid); color: var(--on-solid); font-size: var(--text-2xs); font-weight: var(--weight-bold); }
.level-box.is-dept { border-color: var(--sec-home-line); background: var(--sec-action-tint); }
.level-box.is-dept > legend { color: var(--sec-home-text); }
.level-box.is-dept .level-num { background: var(--sec-action); }
.level-box.is-off { background: var(--surface-2); }
.level-box.is-off > legend { color: var(--muted); }
.level-box.is-off .level-num { background: var(--surface); color: var(--muted); box-shadow: inset 0 0 0 1px var(--border-soft); }
/* My account: two columns of cards from the top; the devices as compact rounded rows, the one in use in the page's tint. */
.grid.account-grid { align-items: start; }
.card.account-step { max-width: 40rem; padding: var(--space-6); }
.device-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.device-rows > li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--surface-2); }
.device-rows .row-main { min-width: 0; flex: 1 1 12rem; }
.device-rows .row-main strong { display: block; overflow-wrap: break-word; }
.device-rows > li.is-current { background: var(--sec-tint); }
.device-rows > li.is-current strong, .device-rows > li.is-current .hint { color: var(--sec-text); }
/* Appearance: the three-part switch. "Follow this device" takes the room first, up to its one-line width (so it stays on
   one line on a computer), and Light and Dark share the rest. On a narrow card the three parts stay on one row and
   "Follow this device" wraps inside its own part; only when even that does not fit (larger text on a phone) do Light
   and Dark move to a second row, so the page never scrolls sideways. */
.theme-field .choice-list.segmented .segment { flex: 1 1 auto; }
.theme-field .choice-list.segmented .segment:first-child { flex: 100 1 0; max-width: max-content; }
.qr { display: grid; place-items: center; padding: var(--space-3); background: #fff; border-radius: var(--radius-md); border: 1px solid var(--line); width: fit-content; margin-inline: auto; }
.qr svg { width: 188px; height: 188px; }
.request { overflow-wrap: anywhere; }
/* A row kept for the record only (e.g. a revoked API key): greyed, on a computer and on a phone. */
tr.row-muted td, li.row-muted .list-card { color: var(--muted); }
/* ---- Redesign stage 7: data and safety (API keys, Audit log, Deleted items; 7a API keys, 7a Deleted). partChip(): the
   part of the app something belongs to (an API key's permissions, a deleted item's kind) as a small chip in that part's
   tint and text colour, AA in light and dark as the bands. A revoked key's chips are greyed with the rest of its row. */
.badge.part-chip { background: var(--sec-tint); color: var(--sec-text); font-weight: var(--weight-bold); }
.table td .badge.part-chip { white-space: normal; }
.part-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.part-chips.is-muted .badge.part-chip { background: var(--chip-bg); color: var(--muted); }
/* Deleted items: the kind's chip before the item's title, on the same line while there is room. */
.kind-title > .part-chip { margin-right: var(--space-2); }
/* API keys: "How keys work" in the small text it had (no one-off style). */
.keys-how { font-size: var(--text-sm); }
.secret { font-family: var(--font-mono); font-size: var(--text-md); letter-spacing: .08em; overflow-wrap: anywhere; background: var(--surface-2); border: 1px dashed var(--border-soft); border-radius: var(--radius-md); padding: var(--space-3); text-align: center; }
.codes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); list-style: none; margin: 0; padding: var(--space-3); background: var(--surface-2); border-radius: var(--radius-md); font-family: var(--font-mono); font-size: var(--text-md); text-align: center; }
.steps { counter-reset: step; list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
.steps > li { counter-increment: step; display: grid; grid-template-columns: 32px minmax(0, 1fr); gap: var(--space-3); }
.steps > li::before { content: counter(step); display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--blue-100); color: var(--blue-text); font-weight: var(--weight-bold); font-size: var(--text-sm); }

/* ------------------------------------------------------------------ gallery helpers */
.swatches { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }
.swatch { border: 1px solid var(--line); border-radius: var(--radius-md); overflow: hidden; background: var(--surface); font-size: var(--text-xs); }
.swatch .chip { height: 48px; }
.swatch div:last-child { padding: var(--space-2); overflow-wrap: break-word; }
.icon-grid { display: grid; gap: var(--space-2); grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); }
.icon-grid figure { margin: 0; display: grid; justify-items: center; gap: 6px; padding: var(--space-3) var(--space-1); border: 1px solid var(--line-subtle); border-radius: var(--radius-md); font-size: var(--text-2xs); color: var(--muted); text-align: center; overflow-wrap: break-word; }
/* Plain lists (Choose an organisation's rows are in the redesign stage 8 block) */
.plain-list { list-style: none; margin: 0; padding: 0; }
.plain-list > li { container-type: inline-size; }

.demo-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.type-sample > * + * { margin-top: var(--space-3); }

/* ------------------------------------------------------------------ show more */
.more-details > summary { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap); padding: 0 var(--space-2); margin-left: calc(-1 * var(--space-2)); border-radius: var(--radius-md); color: var(--blue-text); font-size: var(--text-sm); font-weight: var(--weight-semibold); cursor: pointer; list-style: none; }
.more-details > summary::-webkit-details-marker { display: none; }
.more-details > summary::after { content: ""; width: 8px; height: 8px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-2px); transition: transform var(--dur-fast) var(--ease); }
.more-details[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }
.more-details > summary:hover { background: var(--blue-50); }

/* ------------------------------------------------------------------ records: photos, profiles, notes, documents, history */
.photo { display: grid; place-items: center; flex: none; border-radius: 50%; object-fit: cover; background: var(--blue-100); color: var(--blue-text); font-weight: var(--weight-bold); overflow: hidden; }
.photo-sm { width: var(--avatar); height: var(--avatar); font-size: var(--text-xs); }
.photo-lg { width: 4.5rem; height: 4.5rem; font-size: var(--text-xl); }
@media (min-width: 48em) { .photo-lg { width: 6rem; height: 6rem; } }
.person-cell { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.person-cell > div { min-width: 0; overflow-wrap: break-word; }
/* Redesign stage 5 (4a Students, 4a Staff): initials in a list take the page's colour (violet on Students, pink on Staff
   & volunteers); a photo stays a photo. */
.person-cell .photo-none, .list-card-lead .photo-none { background: var(--sec-tint); color: var(--sec-text); }
/* The Students and Staff & volunteers tables (4a): compact rows, the name with room to stay on one line, headings that
   wrap between words, the family code in bold, an arrow at the end of a student's row (the name is the real link; the
   arrow is only a bigger place to click). */
.table.table-people td { padding: 7px var(--space-3); }
.table.table-people th { padding-left: var(--space-3); padding-right: var(--space-3); white-space: normal; overflow-wrap: normal; word-break: keep-all; hyphens: none; }
.table.table-people th.sortable { padding: 0; }
.table.table-people th .sort { padding: 0 var(--space-3); white-space: normal; text-align: left; }
.table.table-people td.primary .person-cell a { white-space: nowrap; }
.table.table-people td.col-family { white-space: nowrap; }
.table.table-people td.col-family a { font-weight: var(--weight-bold); }
.table.table-people td.col-open { width: 1%; padding-left: 0; text-align: right; }
.table.table-people .row-arrow { display: inline-grid; place-items: center; width: 2rem; height: 2rem; border-radius: var(--radius-md); color: var(--sec-text); }
.table.table-people .row-arrow:hover { background: var(--sec-tint); }
.dbs-cell { display: grid; justify-items: start; gap: 2px; }
.dbs-line { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); }
.kv .kv-wide { grid-column: 1 / -1; }
.kv .kv-wide dd { white-space: pre-line; }
.kv dd.muted { font-weight: var(--weight-regular); }
/* Redesign stage 5 (4a Student): a record's facts are one line of text joined by "·", the status pill first, that wraps
   between words like a sentence (a "·" ends a line, never starts one). */
.profile-facts { margin-top: var(--space-1); color: var(--muted); font-size: var(--text-sm); line-height: var(--leading-relaxed); overflow-wrap: break-word; }
.profile-facts > .badge { margin-right: var(--space-2); vertical-align: 1px; }
.page-head .profile-facts a { color: inherit; }
.section-tabs { margin-bottom: var(--space-4); }
.section-body > * + * { margin-top: var(--space-4); }
.input[type="file"] { padding: 8px; }
.notes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.note { border: 1px solid var(--line); border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4); background: var(--surface); min-width: 0; }
/* Redesign stage 5 (4a Student, E4): a pinned note is amber, with the note icon and an amber "Pinned"; "Restricted" has a lock. */
.note.pinned { border-color: var(--warning-border); background: var(--warning-bg); }
.note-icon { display: inline-flex; color: var(--warning-fg); }
.note-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); justify-content: space-between; }
.note-head .cluster { min-width: 0; }
.note-body { margin-top: var(--space-2); white-space: pre-line; overflow-wrap: break-word; line-height: var(--leading-relaxed); }
.note-meta { margin-top: var(--space-2); }
.quote { margin: 0; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--line); background: var(--surface-2); border-radius: var(--radius-sm); white-space: pre-line; overflow-wrap: break-word; line-height: var(--leading-relaxed); }
.note-additions { list-style: none; margin: var(--space-3) 0 0; padding: 0 0 0 var(--space-3); border-left: 2px solid var(--line); display: grid; gap: var(--space-3); }
.timeline { list-style: none; margin: 0; padding: 0; }
/* History as a timeline (E4): its line and dots in the page's colour (violet on a student's or family's page, pink on a
   staff member's, grey in Settings › Audit log). */
.timeline > li { position: relative; margin-left: 6px; padding: 0 0 var(--space-5) var(--space-5); border-left: 2px solid var(--sec-line); min-width: 0; }
.timeline > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.timeline > li::before { content: ""; position: absolute; left: -7px; top: 3px; width: 12px; height: 12px; border-radius: 50%; background: var(--surface); border: 2px solid var(--sec-icon); }
.timeline strong { display: block; overflow-wrap: break-word; }
.changes { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: grid; gap: 4px; font-size: var(--text-sm); }
.changes li { overflow-wrap: break-word; line-height: var(--leading-snug); }
.changes .from { color: var(--muted); text-decoration: line-through; }
.changes .icon-sm { display: inline-block; vertical-align: -3px; margin: 0 4px; color: var(--muted); }
.contact-links { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); min-width: 0; }
/* Each number or address is a full-size tap target (it calls or emails). */
.contact-links > a { display: inline-flex; align-items: center; min-height: var(--tap); overflow-wrap: anywhere; font-size: var(--text-sm); }
.link-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
/* ---- Redesign stage 5: the record pages (a student, a family, a staff member) */
/* A card's buttons stay at the right of its title, beside a long line under it (Extra details' Edit, Add guardian, Add a
   note); they go under it only when there is no room. */
.record-body .card-head > :first-child { flex: 1 1 14rem; }
/* A list whose rows reach the card's edges. */
.rows.bleed { margin: 0 calc(-1 * var(--space-5)); }
/* Documents (E4): each file's icon in a tile in the page's colour. */
.doc-icon { display: grid; place-items: center; flex: none; width: 2.5rem; height: 2.5rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
/* A person in a record's list (4a Student's family card): grey initials in a circle on a grey row; the main contact's
   row is tinted in the page's colour, with solid initials. */
.person-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.person-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-2) var(--space-3); padding: var(--space-3); border-radius: var(--radius-md); background: var(--surface-2); min-width: 0; }
.person-row.is-main { background: var(--sec-tint); }
.person-row > .photo-none { background: var(--st-future-solid); color: var(--on-solid); }
.person-row.is-main > .photo-none { background: var(--sec-solid); }
.person-main { flex: 1 1 12rem; min-width: 0; display: grid; gap: 2px; justify-items: start; }
.person-main > strong { max-width: 100%; overflow-wrap: break-word; }
.person-main > .cluster { margin: 2px 0; }
.person-row > .row-actions { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-left: auto; }
.hint.pre-line { white-space: pre-line; }
/* The student's Enrolments tab: the Enrolments table across the page, then the fee cards; on computers the Family &
   contacts card beside them (answer 4a), on phones and small tablets under them. Other charges come next, across the
   page again, so its table keeps its width. */
.student-fees-layout { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); align-items: start; }
.student-fees-layout > :empty { display: none; }
@media (min-width: 75em) {
  .student-fees-layout.with-side { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); grid-template-areas: "fees side" "other other"; }
  .student-fees-layout.with-side > .fees-block { grid-area: fees; }
  .student-fees-layout.with-side > .enrol-side { grid-area: side; }
  .student-fees-layout.with-side > :last-child { grid-area: other; }
}
.enrol-side .side-link { justify-self: start; margin-left: calc(-1 * var(--space-2)); }
/* "This parent is already recorded. Link them?" (E4): the question and its two choices in a blue information notice. */
.match-notice .field > legend { color: inherit; font-weight: var(--weight-bold); }
.match-notice .hint { color: inherit; }
/* A part of a dialog with its own heading (Add student's Main guardian, Edit's Medical and support). */
.form-section { padding: var(--space-4); border-radius: var(--radius-md); background: var(--surface-2); }
.form-section > legend { float: left; width: 100%; margin-bottom: var(--space-3); padding: 0; font-weight: var(--weight-bold); }
.form-section > legend + * { clear: both; }
.dialog-text { line-height: var(--leading-relaxed); }
/* A family's children (4a Family): each a row tinted in the page's colour with solid initials (a photo stays a photo);
   the whole row opens the child. Brothers and sisters outside your access are grey and do not open. */
.child-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.child-row { position: relative; display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); border-radius: var(--radius-md); background: var(--sec-tint); min-width: 0; }
.child-row > .photo-none { background: var(--sec-solid); color: var(--on-solid); }
.child-main { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; }
.child-main .row-link { color: var(--ink); text-decoration: none; }
.child-main .row-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.child-row:hover:not(.is-elsewhere) { box-shadow: inset 0 0 0 2px var(--sec-line); }
.child-row:hover .row-link { text-decoration: underline; }
.child-row > .badge { flex: none; }
.child-row.is-elsewhere { background: var(--surface-2); }
.child-row.is-elsewhere > .photo-none { background: var(--st-future-solid); }
/* A family's guardians (4a Family): each in a bordered box, Main contact and Pays fees beside the name. */
.guardian-boxes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.guardian-box { display: grid; gap: 2px; padding: var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-md); min-width: 0; }
.guardian-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-1) var(--space-2); }
.guardian-top > strong { min-width: 0; overflow-wrap: break-word; }
.guardian-box > .cluster { margin-top: var(--space-1); }
/* ---- Redesign stage 5: a staff member's or volunteer's page (4a Staff member; answers 7, 8 and 9) */
/* Details as label / value rows (details({ rows: true })): the label on the left in grey, the value on the right in bold,
   a thin line between rows. A value too long to sit beside its label (an email address) takes the next line whole, so
   it breaks only when it is wider than the card; a wide detail (an address) has its label above it. */
.kv.kv-rows { grid-template-columns: minmax(0, 1fr); gap: 0; font-size: var(--text-sm); }
.kv-rows > div { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px var(--space-4); padding: var(--space-2) 0; border-top: 1px solid var(--line-subtle); }
.kv-rows > div:first-child { padding-top: 0; border-top: 0; }
.kv-rows > div:last-child { padding-bottom: 0; }
.kv-rows dt { font-size: inherit; }
.kv-rows dd { min-width: 0; margin: 0 0 0 auto; text-align: right; }
.kv-rows > .kv-wide { display: grid; }
.kv-rows > .kv-wide dd { margin: 0; text-align: left; }
/* The Details and Pay profile tabs' cards keep their own height (side by side on a computer); a card's buttons stay on its
   title row while there is room (Bank details: Show and Change). */
.grid.staff-details { align-items: start; }
.staff-details .card-head > :first-child { flex-basis: 12rem; }
/* A line under a date ("expires 30 Aug 2028"). */
.kv-sub { display: block; font-size: var(--text-xs); font-weight: var(--weight-regular); }
/* Answer 9a: the Teaching card's sentence in the frame's violet figure box. */
.teach-tile .fig-main { font-weight: var(--weight-semibold); line-height: var(--leading-snug); overflow-wrap: break-word; }
/* Answer 7: the DBS check and the safeguarding training, each tinted in the colour of its state in Reports › DBS and
   training expiry (Fine green, Due soon and Not recorded amber, Expired red, Not required grey) with that state as a
   pill; without the report they are grey, with the dates only. */
.sg-row, .sg-check { --sg-bg: var(--surface-2); --sg-fg: var(--ink-2); --sg-line: var(--line-subtle); }
.sg-paid { --sg-bg: var(--st-paid-bg); --sg-fg: var(--st-paid-fg); --sg-line: var(--success-border); }
.sg-need { --sg-bg: var(--st-need-bg); --sg-fg: var(--st-need-fg); --sg-line: var(--warning-border); }
.sg-late { --sg-bg: var(--st-late-bg); --sg-fg: var(--st-late-fg); --sg-line: var(--danger-border); }
.sg-future { --sg-bg: var(--st-future-bg); --sg-fg: var(--st-future-fg); --sg-line: var(--line); }
.sg-icon { display: inline-flex; flex: none; }
/* The Details tab's "Safeguarding checks" card: each check a row that opens the Safeguarding tab. */
.sg-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.sg-row { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--tap); padding: var(--space-3); border: 1px solid var(--sg-line); border-radius: var(--radius-md); background: var(--sg-bg); color: var(--sg-fg); font: inherit; text-align: left; cursor: pointer; }
.sg-row:hover { box-shadow: inset 0 0 0 1px var(--sg-fg); }
.sg-row > .icon { flex: none; }
.sg-main { display: grid; gap: var(--space-1); flex: 1 1 auto; min-width: 0; font-size: var(--text-sm); overflow-wrap: break-word; }
.sg-state { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); }
/* The Safeguarding tab: the same two checks as tinted boxes holding their facts. */
.sg-checks { display: grid; gap: var(--space-3); }
.sg-check { display: grid; gap: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--sg-line); border-radius: var(--radius-md); background: var(--sg-bg); min-width: 0; }
.sg-check-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); color: var(--sg-fg); }
.sg-check-head h3 { flex: 1 1 auto; min-width: 0; margin: 0; color: inherit; font-size: var(--text-md); font-weight: var(--weight-bold); overflow-wrap: break-word; }
.sg-check .kv dt, .sg-check .kv-sub { color: var(--sg-fg); }
@media print { .sg-row, .sg-check { background: none; } }

/* ------------------------------------------------------------------ fees: status bar, figures, fee and plan editors */
/* The fee status bar: one part per status, as wide as its share (the words are in its label). */
.status-bar { display: flex; height: 10px; min-width: 6rem; border-radius: var(--radius-full); overflow: hidden; background: var(--track); gap: 2px; }
.status-bar .seg { display: block; height: 100%; min-width: 3px; }
.seg-paid { background: var(--st-paid-fill); }
.seg-credit { background: var(--st-credit-fill); }
.seg-upto { background: var(--st-upto-fill); }
.seg-late { background: var(--st-late-fill); }
.seg-future { background: var(--st-future-fill); }
.seg-need { background: var(--st-need-fill); }
.seg-written { background: var(--st-written-fill); }
.seg-nofees { background: var(--st-nofees-fill); }
.legend { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); list-style: none; margin: 0; padding: 0; font-size: var(--text-xs); color: var(--muted); }
.legend li { display: inline-flex; align-items: center; gap: 6px; }
.swatch-dot { display: inline-block; flex: none; width: 10px; height: 10px; border-radius: 50%; }
.figures { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr)); padding: var(--space-3) 0; border-top: 1px solid var(--line-subtle); border-bottom: 1px solid var(--line-subtle); }
.figure { display: grid; gap: 2px; min-width: 0; }
.figure strong { font-size: var(--text-lg); font-weight: var(--weight-bold); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.figure span { font-size: var(--text-xs); color: var(--muted); line-height: var(--leading-snug); }
.figure .figure-note { font-size: var(--text-2xs); }
.figure.late strong, .money-red { color: var(--danger-fg); }
/* An amount that no longer counts (a reversed expense or wage line), as a voided payment. */
.h-sm { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--ink-2); }
.section-head { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline; justify-content: space-between; margin: var(--space-5) 0 var(--space-3); padding-top: var(--space-4); border-top: 1px solid var(--line-subtle); }
.section-head:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.fee-total { font-variant-numeric: tabular-nums; }
.hint.warn, .hint .warn { color: var(--warning-fg); }
.hint.block { display: block; }
.plain { list-style: none; margin: 0; padding: 0; }
.plain > li + li { margin-top: var(--space-1); }
.fee-rows { display: grid; gap: var(--space-2); }
.fee-row { display: grid; gap: var(--space-2) var(--space-3); grid-template-columns: minmax(0, 1fr); align-items: center; padding: var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.fee-row.on { border-color: var(--blue-border); background: var(--blue-50); }
.fee-row-main { display: flex; gap: var(--space-3); align-items: flex-start; min-width: 0; cursor: pointer; }
.fee-row-main input { width: 20px; height: 20px; margin: 2px 0 0; flex: none; accent-color: var(--blue-600); cursor: pointer; }
.fee-row-main > span { display: grid; gap: 2px; min-width: 0; overflow-wrap: break-word; }
.fee-amount .input { min-width: 0; }
.fee-note { grid-column: 1 / -1; }
@media (min-width: 37.5em) { .fee-row { grid-template-columns: minmax(0, 1fr) 11rem; } }
.plan-tools { align-items: flex-end; }
.plan-tools .field { flex: 1 1 10rem; max-width: 16rem; }
.plan-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.plan-rows > li { display: grid; grid-template-columns: 2rem minmax(0, 1fr); gap: var(--space-2) var(--space-3); align-items: end; }
.plan-rows > li > .field { grid-column: 2; grid-template-columns: minmax(0, 1fr); } /* a date field shrinks to the row with larger text */
@media (min-width: 37.5em) { .plan-rows > li { grid-template-columns: 2rem minmax(0, 1fr) minmax(0, 1fr); } .plan-rows > li > .field { grid-column: auto; } }
.plan-no { display: grid; place-items: center; width: 28px; height: 28px; margin-bottom: 8px; border-radius: 50%; background: var(--blue-100); color: var(--blue-text); font-size: var(--text-sm); font-weight: var(--weight-bold); }
.plan-rows > li > .plan-no { grid-row: span 2; align-self: start; margin: 26px 0 0; }
@media (min-width: 37.5em) { .plan-rows > li > .plan-no { grid-row: auto; align-self: end; margin: 0 0 8px; } }
/* A loan's repayment plan (Other income): the fee plan's rows with a Remove button at the end. */
.plan-rows.removable > li > .plan-remove { grid-column: 2; justify-self: start; }
@media (min-width: 37.5em) { .plan-rows.removable > li { grid-template-columns: 2rem minmax(0, 1fr) minmax(0, 1fr) auto; } .plan-rows.removable > li > .plan-remove { grid-column: auto; align-self: end; } }
.plan-check { display: flex; gap: var(--space-2); align-items: flex-start; font-size: var(--text-sm); line-height: var(--leading-snug); }
.plan-check .icon-sm { margin-top: 2px; }
.plan-check.ok { color: var(--success-fg); }
.plan-check.bad { color: var(--danger-fg); }
/* A plan's dates that have passed (left out of the schedule), and "This start date is 5 weeks into the year. Joined
   late?" beside the switch (the owner's Laragon check of redesign stage 5): information lines with their icon. */
.plan-passed, .late-prompt { display: flex; gap: var(--space-2); align-items: flex-start; margin: 0; font-size: var(--text-sm); line-height: var(--leading-snug); color: var(--info-fg); }
.plan-passed .icon-sm, .late-prompt .icon-sm { flex: none; margin-top: 2px; }
.late-prompt[hidden] { display: none; }
.mini-list { list-style: none; margin: 0; padding: 0; font-size: var(--text-sm); }
.mini-list > li { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); align-items: center; justify-content: space-between; padding: var(--space-2) 0; border-top: 1px solid var(--line-subtle); min-width: 0; }
.mini-list > li:first-child { border-top: 0; }
.mini-list > li > span:first-child { min-width: 0; flex: 1 1 12rem; overflow-wrap: break-word; }
.mini-list strong { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mini-list > li.voided > span:first-child, .mini-list > li.voided strong { color: var(--muted); }
.mini-list > li.voided strong { text-decoration: line-through; }
.fee-details { padding: var(--space-3) 0 0; }
/* A student's fees (redesign stage 5, 4a Student): the Fees heading with its line and Fee statement (PDF), then one card
   per enrolment with a header in the department's colour (code, department · year, the enrolment's line, the solid fee
   pill), its four figures as tinted tiles, its buttons (Record a payment solid green, the whole width on a phone) and the
   closed Instalments and payments fold-out. */
.fees-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-3); }
.fees-head > div { flex: 1 1 14rem; min-width: 0; }
/* Its buttons (Fee statement (PDF) and, since 16 October 2026, Fee letter (PDF) beside it) keep their own width, so they sit
   side by side; on a narrow screen they go under the heading. */
.fees-head > .fees-head-actions { flex: 0 1 auto; }
.fees-head h2 { font-size: var(--text-md); font-weight: var(--weight-bold); }
.fees-head .hint { margin-top: 2px; }
.fee-cards { display: grid; gap: var(--space-4); }
.fee-card:hover { border-color: var(--line); box-shadow: none; }   /* a card, not a link */
.fee-card .dept-card-title h3 { color: inherit; font-size: var(--text-md); font-weight: var(--weight-bold); overflow-wrap: break-word; }
.fee-card .dept-card-title > span { overflow-wrap: break-word; }
.fee-card .dept-card-title h3 > span { font-size: inherit; }   /* the year, kept on one line */
.fee-card .dept-card-head > .badge { margin-left: auto; }
.fee-card-body { display: grid; gap: var(--space-4); padding: var(--space-4); }
.fee-card-body > .more-details { margin-top: calc(-1 * var(--space-2)); }
.fee-card .fig-boxes .figure { align-content: start; }
/* The fourth tile is words or a date ("1 Oct 2026", "Paid in full"): a size smaller, so it fits a narrow tile. */
.fee-card .fig-boxes .figure.fig-words strong { font-size: var(--text-md); overflow-wrap: break-word; }
@media (max-width: 47.99em) { .fee-card-actions > .pay-main { flex: 1 1 100%; } }
@media print { .fee-card .dept-card-head { background: none; color: #000; } .fee-card .dept-code { background: none; color: #000; box-shadow: inset 0 0 0 1px #000; } }
.picked { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4); border: 1px solid var(--blue-border); border-radius: var(--radius-md); background: var(--blue-50); }
.picked > div { min-width: 0; flex: 1 1 12rem; overflow-wrap: break-word; }
.pick-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.pick-list .list-card { min-height: 56px; }
.steps-form { display: grid; gap: var(--space-4); max-width: 60rem; }
.step-card .card-head h2 { display: flex; align-items: center; gap: var(--space-3); }
/* A step's number in the page's colour (redesign stage 5: violet on Students › Add many at once, pink on Staff's). */
.step-no { display: grid; place-items: center; flex: none; width: 28px; height: 28px; border-radius: 50%; background: var(--sec-solid); color: var(--on-solid); font-size: var(--text-sm); font-weight: var(--weight-bold); }
.sticky-actions { position: sticky; bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom)); z-index: var(--z-sticky); display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow-2); }
@media (min-width: 48em) { .sticky-actions { bottom: var(--space-3); } }
/* New enrolment (redesign stage 5, 4a New enrolment), still one page: each part's header strip in the colour of what it
   is about (--step-*: Student violet, Class blue, Fees and First payment green, Payment plan the "Up to date" blue); the
   parts listed on the left on a computer, or a slim bar of their colours under the band on phones and tablets, each a
   link, the part in view lit (no ticks); the chosen student in violet with initials; the class's fields in a row;
   amounts with the "£" inside; the buttons on the right (the whole width on a phone). */
.enrol-step, .enrol-step-link { --step-solid: var(--sec-solid); --step-tint: var(--sec-tint); --step-text: var(--sec-text); }
.enrol-step.is-upto, .enrol-step-link.is-upto { --step-solid: var(--st-upto-solid); --step-tint: var(--st-upto-bg); --step-text: var(--st-upto-fg); }
.card.tint-upto { --tint-bg: var(--st-upto-bg); --tint-fg: var(--st-upto-fg); --tint-line: var(--info-border); }
.enrol-step { scroll-margin-top: calc(var(--topbar-h) + var(--tap) + var(--space-3)); }
.enrol-step .step-no { background: var(--step-solid); color: var(--on-solid); }
.enrol-step > .card-head > .cluster { margin-left: auto; }
.enrol-step > .card-head .fee-total { color: var(--step-text); font-size: var(--text-md); font-weight: var(--weight-bold); }
.enrol-step > .card-head .plan-check { font-weight: var(--weight-semibold); }
.enrol-step .choice-list.segmented { width: fit-content; max-width: 100%; }
.picked.picked-tint { justify-content: flex-start; gap: var(--space-2) var(--space-3); border-color: var(--sec-line); background: var(--sec-tint); }
.picked-tint > .avatar { background: var(--sec-solid); color: var(--on-solid); }
.picked-tint > .btn-text { margin-left: auto; color: var(--sec-text); }
.picked-tint > .btn-text:hover { background: var(--surface); }
@media (min-width: 37.5em) { .form-grid.enrol-class-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Teacher | Start date | Academic year in one row, the teacher's name and role given the most room; with Class or group
   too, two by two. */
@media (min-width: 64em) { .form-grid.enrol-class-fields:not(:has(> :nth-child(4))) { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, .8fr); } }
.enrol-step .pro-rata > .field > .hint { padding-left: calc(var(--tap) + var(--space-3)); }   /* under "Joined late?", beside the switch */
.enrol-step .pro-rata > .late-prompt { padding-left: calc(var(--tap) + var(--space-3)); }   /* lined up with the switch's hint */
@media (min-width: 37.5em) { .enrol-step .fee-row { grid-template-columns: minmax(0, 1fr) 9rem; } }
.amount-inside .enrol-step .fee-amount, .amount-inside .enrol-step .plan-rows .input-group { position: relative; }
.amount-inside .enrol-step .fee-amount .affix, .amount-inside .enrol-step .plan-rows .affix { position: absolute; top: 0; bottom: 0; left: 0; z-index: 1; padding: 0 2px 0 12px; border: 0; background: none; pointer-events: none; }
.amount-inside .enrol-step .fee-amount .input, .amount-inside .enrol-step .plan-rows .input-group .input { padding-left: 2rem; border-radius: var(--radius-sm); text-align: right; font-variant-numeric: tabular-nums; }
.enrol-step.is-upto .plan-no { background: var(--st-upto-bg); color: var(--st-upto-fg); }
.enrol-layout { display: grid; gap: var(--space-3); }
.enrol-steps ol { display: flex; gap: 4px; margin: 0; padding: 0; list-style: none; }
.enrol-step-link { display: flex; align-items: center; min-height: var(--tap); border-radius: var(--radius-md); color: var(--ink-2); text-decoration: none; }
@media (max-width: 74.99em) {
  .enrol-steps { position: sticky; top: var(--topbar-h); z-index: var(--z-sticky); margin-top: calc(-1 * var(--space-3)); background: var(--canvas); }
  .enrol-steps li { flex: 1 1 0; min-width: 0; }
  .enrol-step-link { padding: 0 2px; }
  .enrol-step-link .enrol-no { display: none; }
  .enrol-step-link .step-name { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .step-bar { flex: 1; height: 4px; border-radius: var(--radius-full); background: var(--step-solid); }
  .enrol-step-link[aria-current] .step-bar { height: 10px; }
}
@media (min-width: 75em) {
  .enrol-layout:not(.no-steps) { grid-template-columns: 12.5rem minmax(0, 60rem); gap: var(--space-4); align-items: start; }
  .enrol-steps { position: sticky; top: calc(var(--topbar-h) + var(--space-4)); }
  .enrol-steps ol { flex-direction: column; }
  .enrol-step-link { gap: var(--space-3); padding: 6px 10px; font-size: var(--text-sm); font-weight: var(--weight-medium); line-height: var(--leading-snug); }
  .enrol-step-link:hover { background: var(--surface); color: var(--ink); }
  .enrol-step-link[aria-current] { background: var(--step-tint); color: var(--ink); font-weight: var(--weight-bold); }
  .enrol-no { display: grid; place-items: center; flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--step-solid); color: var(--on-solid); font-size: var(--text-xs); font-weight: var(--weight-bold); }
  .step-bar { display: none; }
  .enrol-step { scroll-margin-top: calc(var(--topbar-h) + var(--space-4)); }
}
.enrol-actions { justify-content: flex-end; }
.enrol-actions > .hint { flex: 1 1 12rem; min-width: 0; }
@media (max-width: 47.99em) {
  .enrol-actions { margin-inline: calc(-1 * var(--gutter)); border-inline: 0; border-radius: 0; }
  .enrol-actions > .hint { flex-basis: 100%; }
  .enrol-actions > .btn:last-child { flex: 1 1 auto; }
}
@media print { .enrol-steps { display: none; } }
/* Redesign stage 7: Organisation settings (7a Org settings). On a computer the page's cards are listed on the left, as
   New enrolment lists its parts (their own titles, the card in view lit in the settings colour, each a link to its card);
   phones and tablets have no list. The logo card: the logo (or the dashed "No logo" box), its line beside it and the
   buttons on the right; on a phone each under the one before. */
.org-layout { display: grid; gap: var(--space-4); }
.org-steps { display: none; }
.org-cards > .card, .org-cards > .gs-slot > .card { scroll-margin-top: calc(var(--topbar-h) + var(--space-4)); }
@media (min-width: 64em) {
  .org-layout { grid-template-columns: 12.5rem minmax(0, 60rem); align-items: start; }
  .org-steps { display: block; position: sticky; top: calc(var(--topbar-h) + var(--space-4)); }
  .org-steps ol { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
  .org-step-link { display: flex; align-items: center; min-height: var(--tap); padding: 6px 10px; border-radius: var(--radius-md); color: var(--ink); font-size: var(--text-sm); font-weight: var(--weight-medium); line-height: var(--leading-snug); text-decoration: none; }
  .org-step-link:hover { background: var(--surface); }
  .org-step-link[aria-current] { background: var(--sec-tint); color: var(--sec-text); font-weight: var(--weight-bold); }
}
@media print { .org-steps { display: none; } }
.logo-row { display: grid; gap: var(--space-3) var(--space-4); }
.logo-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@media (min-width: 37.5em) {
  .logo-row { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; }
  .logo-actions { flex-direction: column; align-items: stretch; }
}
/* Redesign stage 7: Academic years (7a Years). Each year is a row: a calendar tile, the name in bold with the Current
   pill and the dates under it, and Make current and Change on the right (under the rest on a phone). The current year's
   row is outlined in blue with a solid blue tile (blue: the settings pages' action colour). */
.year-list { display: grid; gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.year-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-3) var(--space-4); align-items: center; padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.year-row.is-current { border-color: var(--sec-action); box-shadow: inset 0 0 0 1px var(--sec-action); }
.year-tile { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
.year-row.is-current .year-tile { background: var(--sec-action); color: var(--on-solid); }
.year-main { display: grid; gap: 2px; min-width: 0; }
.year-name { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.year-name strong { font-size: var(--text-md); }
.year-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); grid-column: 1 / -1; }
@media (min-width: 37.5em) {
  .year-row { grid-template-columns: auto minmax(0, 1fr) auto; }
  .year-actions { grid-column: auto; justify-content: flex-end; }
}
/* Redesign stage 7: Words used in the app (7a Words). On a computer "The words" on the left and "How it will look" on
   the right, kept in view while scrolling; phones and tablets keep the preview above the words (it comes first in the
   page). The preview's lines sit in a box tinted in the settings pages' blue (as the chosen choice cards). Each word is a
   row with a thin line between rows (the legend floats, so the line runs above it, not through it); on a computer its
   heading sits in a column on the left. "Save words" is the form foot of Log an expense. */
.words-layout { display: grid; gap: var(--space-4); }
.words-preview { display: grid; gap: var(--space-2); padding: var(--space-3) var(--space-4); border: 1px solid var(--sec-home-line); border-radius: var(--radius-md); background: var(--sec-action-tint); overflow-wrap: break-word; }
.words-preview strong { color: var(--sec-home-text); }
.word-rows { display: grid; }
.word-row { min-width: 0; margin: 0; padding: var(--space-4) 0; border: 0; border-top: 1px solid var(--line-subtle); }
.word-row:first-child { padding-top: 0; border-top: 0; }
.word-row > legend { float: left; width: 100%; margin: 0 0 var(--space-3); padding: 0; }
.word-row-body { display: grid; gap: var(--space-2); min-width: 0; clear: left; }
.word-row-body > .cluster:empty { display: none; }
@media (min-width: 64em) {
  .words-layout { grid-template-columns: minmax(0, 1.3fr) minmax(16rem, 1fr); align-items: start; }
  .words-layout > .words-card { grid-area: 1 / 1; }
  .words-layout > .words-preview-card { grid-area: 1 / 2; position: sticky; top: calc(var(--topbar-h) + var(--space-4)); }
  .word-row > legend { width: 9rem; margin: 0; }
  .word-row-body { clear: none; margin-left: calc(9rem + var(--space-4)); }
}
/* Redesign stage 7: Extra details (E6). The kind is a small grey chip that may wrap in a narrow column or a phone's card
   ("Yes / No with a date"); a list's choices sit in a grey line under it. */
.table td .kind-cell .badge { white-space: normal; }
.success-card { border-color: var(--success-border); background: var(--success-bg); }
.success-card h2 { color: var(--success-fg); display: flex; align-items: center; gap: var(--space-2); }
.check-list { display: grid; gap: var(--space-2); }
.check-row { display: flex; gap: var(--space-3); align-items: flex-start; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); }
.check-row:hover { background: var(--surface-2); }
.check-row input { width: 20px; height: 20px; margin: 2px 0 0; flex: none; accent-color: var(--blue-600); }
.check-row > span { min-width: 0; overflow-wrap: break-word; }
.preview-totals { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }

/* ------------------------------------------------------------------ stakeholder dashboard */
.year-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-5); padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); font-size: var(--text-sm); }
.year-bar .icon { color: var(--blue-text); }
.year-bar-end { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin-left: auto; }
.page-foot { margin-top: var(--space-8); padding-top: var(--space-4); border-top: 1px solid var(--line); font-size: var(--text-xs); color: var(--muted); line-height: var(--leading-relaxed); }
.page-foot p + p { margin-top: var(--space-1); }
.dept-chip { display: inline-grid; place-items: center; flex: none; min-width: 2.5rem; height: 2rem; padding: 0 6px; border-radius: var(--radius-md); background: var(--chip-bg); color: var(--ink-2); font-size: var(--text-2xs); font-weight: var(--weight-bold); white-space: nowrap; }
.dept-chip.d1 { color: var(--dept-text-1); background: color-mix(in srgb, var(--dept-1) 14%, var(--surface)); }
.dept-chip.d2 { color: var(--dept-text-2); background: color-mix(in srgb, var(--dept-2) 14%, var(--surface)); }
.dept-chip.d3 { color: var(--dept-text-3); background: color-mix(in srgb, var(--dept-3) 14%, var(--surface)); }
.dept-chip.d4 { color: var(--dept-text-4); background: color-mix(in srgb, var(--dept-4) 14%, var(--surface)); }
.dept-chip.d5 { color: var(--dept-text-5); background: color-mix(in srgb, var(--dept-5) 14%, var(--surface)); }
.dept-chip.d6 { color: var(--dept-text-6); background: color-mix(in srgb, var(--dept-6) 14%, var(--surface)); }
.dept-chip.d7 { color: var(--dept-text-7); background: color-mix(in srgb, var(--dept-7) 14%, var(--surface)); }
.dept-chip.d8 { color: var(--dept-text-8); background: color-mix(in srgb, var(--dept-8) 14%, var(--surface)); }
.dept-name { display: inline-flex; align-items: center; gap: var(--space-3); min-width: 0; min-height: var(--tap); color: inherit; text-decoration: none; }
.dept-name strong { overflow-wrap: break-word; min-width: 0; }
.dept-name:hover strong { text-decoration: underline; }
.collect-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.collect-line .big { font-size: var(--text-stat); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); font-variant-numeric: tabular-nums; }
.progress { height: 12px; margin: var(--space-3) 0 var(--space-4); border-radius: var(--radius-full); background: var(--track); overflow: hidden; }
.progress > span { display: block; height: 100%; border-radius: var(--radius-full); background: var(--st-paid-fill); }
.status-lines { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); font-size: var(--text-sm); }
.status-lines > li { display: flex; align-items: center; gap: var(--space-3); min-height: 36px; padding: 0 var(--space-1); border-bottom: 1px solid var(--line-subtle); }
.status-lines > li:last-child { border-bottom: 0; }
.status-lines .grow { flex: 1 1 auto; min-width: 0; }
.status-lines strong { font-variant-numeric: tabular-nums; }
.status-lines .muted { min-width: 3em; text-align: right; font-variant-numeric: tabular-nums; }
section.quick-actions { display: grid; gap: var(--space-2); margin-bottom: var(--space-5); padding: var(--space-4); border: 1px solid var(--blue-border); border-radius: var(--radius-lg); background: var(--blue-50); }   /* the Stage 10 preview, as it was drawn */
.levels { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.level { padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-md); }
.level-head { display: flex; align-items: center; gap: var(--space-3); }
.level-head strong { flex: 1 1 auto; min-width: 0; }
.level-no { display: grid; place-items: center; flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--blue-100); color: var(--blue-text); font-size: var(--text-xs); font-weight: var(--weight-bold); }
.level-people { list-style: none; margin: var(--space-2) 0 0; padding: 0 0 0 calc(26px + var(--space-3)); display: grid; gap: var(--space-1); }
.level-people > li { display: flex; flex-wrap: wrap; gap: 0 var(--space-3); align-items: baseline; justify-content: space-between; min-height: 32px; font-size: var(--text-sm); }
.level-people > li > :first-child { min-width: 0; overflow-wrap: break-word; }
.level-people > li > a { display: inline-flex; align-items: center; min-height: var(--tap); }
.level > .hint { margin: var(--space-1) 0 0 calc(26px + var(--space-3)); }   /* "No active … assigned" */
.banner { margin-bottom: var(--space-5); padding: var(--space-5); border-radius: var(--radius-lg); background: var(--navy-800); color: var(--on-navy-2); }
.banner .eyebrow { color: var(--on-navy-3); }
.banner-big { margin: var(--space-1) 0; font-size: var(--text-2xl); font-weight: var(--weight-bold); color: var(--on-navy); }
.meanings { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.meanings > li { display: grid; gap: var(--space-1); justify-items: start; font-size: var(--text-sm); line-height: var(--leading-snug); }
.link-button { display: inline-flex; align-items: center; min-height: var(--tap); padding: 0; border: 0; background: none; color: var(--blue-text); font: inherit; font-size: var(--text-sm); text-align: left; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.refresh-bar { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; margin-top: var(--space-6); padding: var(--space-3) var(--space-4); border: 1px dashed var(--border-soft); border-radius: var(--radius-lg); font-size: var(--text-sm); color: var(--muted); line-height: var(--leading-snug); }
.refresh-bar p { flex: 1 1 18rem; min-width: 0; }
.run-result { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; }
.run-result > div { min-width: 0; flex: 1 1 16rem; }

/* ------------------------------------------------------------------ print */
.print-only { display: none; }
.working { font-size: var(--text-sm); color: var(--muted); line-height: var(--leading-snug); overflow-wrap: anywhere; }
@media print {
  .print-only { display: block; margin-bottom: 8px; }
  .sidebar, .bottom-nav, .topbar, .toasts, .viewas, .page-actions, .skip-link, .no-print, .subnav, .band-icon, .page-head .back { display: none !important; }
  .page-head { margin-top: 0 !important; padding: 0; color: #000; }
  .page-head::before { display: none; }
  .page-head h1, .page-head .sub { color: #000; }
  .shell { display: block; }
  body, .card, .stat { background: #fff; color: #000; }
  .stat.highlight, .stat[class*="tone-"] { background: #fff; border-color: #000; }
  .stat.highlight, .stat.highlight .label, .stat.highlight .foot, .stat[class*="tone-"], .stat[class*="tone-"] .label, .stat[class*="tone-"] .foot { color: #000; }
  .content { padding: 0; max-width: none; }
  .card, .stat { break-inside: avoid; box-shadow: none; }
  a { color: inherit; text-decoration: none; }
}

/* ------------------------------------------------------------------ reports (Stage 5): the printed header */
.print-head { display: flex; gap: var(--space-3); align-items: center; font-size: var(--text-sm); }
.print-head.print-only { display: none; }
.print-head .logo-box { flex: none; width: 48px; height: 48px; border: 1px dashed var(--line); border-radius: var(--radius); display: grid; place-items: center; font-size: var(--text-2xs); color: var(--muted); }
@media print { .print-only.print-head { display: flex; } }
@media (min-width: 64em) {
  .table.table-report:not(.cards) { table-layout: fixed; }
  .table.table-report td .badge { white-space: normal; }
  .table.table-report:not(.cards) th { white-space: normal; overflow-wrap: normal; word-break: keep-all; hyphens: none; }
  /* Every column gets a share (a browser would otherwise squeeze the unsized ones to nothing); widths over 100% scale down together. */
  .table.table-report th.col-what { width: 18%; }
  .table.table-report th.col-who { width: 13%; }
  .table.table-report th.num { width: 7%; }
  .table.table-report th.col-date { width: 11%; }
  .table.table-report th.col-badge { width: 10%; }
  .table.table-report th.col-actions { width: 12%; }
  .table.table-report th.col-menu { width: 6%; }
  .table.table-report:not(.cards) td { padding-left: var(--space-2); padding-right: var(--space-2); }
  .table.table-report:not(.cards) th .sort { flex-wrap: wrap; white-space: normal; padding: 0 var(--space-1); text-align: inherit; }
}
.report-links { list-style: none; margin: 0; padding: 0; font-size: var(--text-sm); }
.report-links li { border-top: 1px solid var(--line-subtle); }
.report-links a { display: block; padding: var(--space-3) 0; min-height: 44px; color: var(--blue-text); font-weight: var(--weight-semibold); text-decoration: none; }
.report-links a:hover { text-decoration: underline; }

/* ---- Redesign stage 7: Reports (7a Reports, 7a Phone Reports, 7a Report, 7a Scheduled) */
/* The Report centre: the search box about as wide as drawn; the groups' cards keep their own height. */
.toolbar.bare .field.report-search { flex: 1 1 26.25rem; max-width: 26.25rem; }
.report-presets:not(:empty) { margin-bottom: var(--space-4); }
.grid.report-groups { align-items: start; }
@media (max-width: 47.99em) { .grid.report-groups { gap: var(--space-2); } }
/* A group of reports. On a phone (the base look) it is one row: a solid icon tile in the group's colour, its name, "N
   reports" and an arrow; tapping it opens the list in place and turns the arrow down. On tablets and computers it is the
   drawn card: a header strip in the group's colour and every list open. */
.card.report-group { overflow: hidden; }
.report-group-icon { display: grid; place-items: center; flex: none; width: 2.125rem; height: 2.125rem; border-radius: var(--radius-md); background: var(--sec-solid); color: var(--on-solid); }
.report-group-icon .icon { width: 1.125rem; height: 1.125rem; }
.report-group-head { display: none; }
.report-group-phone { margin: 0; font-size: inherit; font-weight: inherit; }
.report-group-toggle { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--tap); padding: 10px var(--space-3); border: 0; border-radius: 0;
  background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.report-group-toggle:hover { background: var(--surface-hover); }
.report-group-toggle:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: calc(-1 * var(--focus-width)); }
.report-group-text { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.report-group-text strong { font-size: var(--text-md); overflow-wrap: break-word; }
.report-group-chevron { flex: none; color: var(--muted); transition: transform var(--dur-fast) var(--ease); }
.report-group.is-open .report-group-chevron { transform: rotate(90deg); }
.report-group > .report-rows { display: none; }
.report-group.is-open > .report-rows { display: block; }
.report-links.report-rows.report-group-list a { padding-inline: var(--space-3); }
@media (min-width: 48em) {
  .report-group:not(.phone-look) > .report-rows.report-group-list a { padding-inline: var(--space-4); }
  .report-group:not(.phone-look) > .report-group-phone { display: none; }
  .report-group:not(.phone-look) > .report-group-head { display: flex; align-items: center; gap: var(--space-3); margin: 0; padding: 10px var(--space-4);
    background: var(--sec-tint); border-bottom: 1px solid var(--sec-line); color: var(--sec-text); font-size: var(--text-md); font-weight: var(--weight-bold); }
  .report-group:not(.phone-look) > .report-group-head .report-group-icon { width: 1.875rem; height: 1.875rem; }
  .report-group:not(.phone-look) > .report-rows { display: block; }
  .report-group:not(.phone-look) > .report-rows > li:first-child { border-top: 0; }
}
.report-group-name { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; }
.report-group-count { flex: none; font-size: var(--text-xs); font-weight: var(--weight-semibold); }
/* A report (or a preset) as a row: the whole row opens it; the name is the bold link, an arrow at the end. */
.report-links.report-rows a { display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap); padding: 9px var(--space-4); }
.report-links.report-rows a:hover { background: var(--surface-hover); }
.report-links.report-rows a:focus-visible { outline-offset: calc(-1 * var(--focus-width)); }
.report-row-text { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; }
span.report-row-text:has(> .hint) { display: grid; gap: 2px; }
.report-row-text > .hint { font-weight: var(--weight-regular); }
.report-row-chevron { flex: none; color: var(--muted); }
.report-row-tile { display: grid; place-items: center; flex: none; width: 1.875rem; height: 1.875rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
.card-tint > .card-body.flush > .report-rows > li:first-child { border-top: 0; }
/* One report: the filters in use as teal chips beside the Filters button (phones), and the filter row (tablets and
   computers) with Run report and Presets at its end. */
.report-filter-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.report-chips { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; margin: 0; padding: 0; list-style: none; }
.report-chips > li { max-width: 100%; padding: 6px 11px; border-radius: var(--radius-full); background: var(--sec-tint); color: var(--sec-text); font-size: var(--text-xs);
  font-weight: var(--weight-semibold); line-height: var(--leading-snug); overflow-wrap: break-word; }
.report-filter-line > .filter-open { flex: none; }
/* On a phone the same space under the Filters line (and Presets, when there are any) as under a list's filter bar; an
   empty Presets box takes no room. */
.report-filter-block > .narrow-only:empty { display: none; }
@media (max-width: 47.99em) { .report-filter-block { margin-bottom: var(--space-4); } }
/* Presets ends the row of filters (a long preset name is cut short in the closed box, as any long choice is). */
.toolbar.report-filters .field.report-preset-field { max-width: 16rem; }
.toolbar.report-filters .field.report-preset-field .select { min-width: 12rem; }
/* A figure solid in a meaning colour (the drawn "Total overdue"): red while something is overdue or expired. */
.stat.highlight.stat-alert { background: var(--danger-solid); border-color: var(--danger-solid); }
/* On a phone the highlighted figure comes first on a row of its own and the others pair up in their order, so no row is
   left half empty (the page's order for screen readers does not change). */
@media (max-width: 47.99em) { .stats.report-stats > .stat.highlight { order: -1; } }
/* The totals row under its columns, where the table shows (from 1200px wide, as since stage 3); phones and tablets show
   the cards, which keep today's totals line. */
.card.report-table { overflow: hidden; }
.table tfoot tr.report-totals td { padding: 10px var(--space-4); background: var(--surface-2); border-top: 1px solid var(--line); font-weight: var(--weight-bold); }
.table.table-report:not(.cards) tfoot tr.report-totals td { padding-left: var(--space-2); padding-right: var(--space-2); }
.table tfoot tr.report-totals td.col-date { white-space: normal; }   /* a words total in a date column ("Totals · 3 handovers") wraps */
.table-foot.report-foot-table { display: none; }
@media (min-width: 75em) { .table-foot.report-foot-cards { display: none; } .table-foot.report-foot-table { display: block; } }
/* A status column has room for the solid pill with its icon ("Overdue"), which cannot wrap inside a word. */
@media (min-width: 64em) { .table.table-report th.col-badge { width: 12%; } }
/* A report table of a dozen columns or more (Expenses by month): each column takes the width its amounts need, in
   slightly smaller figures, so no amount (or total) runs into the next column. */
@media (min-width: 64em) {
  .table.table-report.report-dense:not(.cards) { table-layout: auto; }
  .table.table-report.report-dense:not(.cards) th.num { width: auto; }
  .table.table-report.report-dense:not(.cards) td.num { padding-left: var(--space-1); padding-right: var(--space-1); font-size: var(--text-xs); white-space: nowrap; }
}
/* Scheduled reports: one full-width row per schedule; the "when" pill on the right (solid teal, grey while it is off);
   the buttons under the lines on phones and tablets, and at the right of the row, under the pill, on a computer. */
.sched-list { display: grid; gap: var(--space-3); margin: var(--space-4) 0 0; padding: 0; list-style: none; }
.sched-row { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "icon main" "icon when" "actions actions"; gap: var(--space-2) var(--space-4); align-items: start; padding: var(--space-4); }
.sched-icon { grid-area: icon; display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
.sched-main { grid-area: main; display: grid; gap: var(--space-1); min-width: 0; }
.sched-main > p { margin: 0; overflow-wrap: break-word; }
.sched-name { font-size: var(--text-md); font-weight: var(--weight-bold); overflow-wrap: break-word; }
.badge.solid.sched-when { grid-area: when; justify-self: start; background: var(--sec-solid); }
.badge.solid.sched-when.is-off { background: var(--st-future-solid); }
.sched-actions { grid-area: actions; }
@media (min-width: 48em) {
  .sched-row { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "icon main when" ". actions actions"; padding: var(--space-4) var(--space-5); }
  .badge.solid.sched-when { justify-self: end; }
}
@media (min-width: 64em) {
  .sched-row { grid-template-columns: auto minmax(0, 1fr) minmax(0, max-content); grid-template-rows: auto 1fr; grid-template-areas: "icon main when" "icon main actions"; }
  .sched-actions { align-self: end; justify-content: flex-end; }
}
@media print {
  .stat.highlight.stat-alert { background: #fff; border-color: #000; }
  .badge.solid.sched-when { background: none; color: #000; box-shadow: inset 0 0 0 1px #000; }
}

/* ------------------------------------------------------------------ expenses and claims (Stage 4) */
.receipt-pick { display: grid; gap: var(--space-2); }
@media (min-width: 37.5em) { .receipt-pick { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.receipt-preview { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; padding: var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-2); }
.receipt-preview img, .receipt-preview .code-chip { width: 72px; height: 72px; object-fit: cover; border-radius: var(--radius-sm); background: var(--surface); flex: none; }
.receipt-preview > div { min-width: 0; flex: 1 1 10rem; overflow-wrap: anywhere; }
.receipt-view { display: block; max-width: 100%; border-radius: var(--radius-md); }
.receipt-view img { max-height: 24rem; width: auto; max-width: 100%; margin: 0 auto; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-2); }
.receipt-file { display: flex; gap: var(--space-3); align-items: center; padding: var(--space-4); border: 1px dashed var(--border-soft); border-radius: var(--radius-md); color: var(--muted); }
/* ---- Redesign stage 6 (5a Log an expense and its phone frame, 8a Edit expense): Log an expense, Log a claim and Edit
   expense. On a computer the form's card is on the left and the receipt's card on the right; on phones and tablets one
   column with the receipt first (it comes first in the page). The rows of fields follow the form's own width (a
   container), so with larger text they fall back to one field per row. */
.expense-form-layout { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); align-items: start; max-width: 75rem; }
.expense-form-layout > .card > .card-body { padding-top: var(--space-5); }
@media (min-width: 64em) {
  .expense-form-layout { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
  .expense-form-layout > .expense-form-card { grid-area: 1 / 1; }
  .expense-form-layout > .receipt-card { grid-area: 1 / 2; }
}
.form.expense-form { container-type: inline-size; max-width: none; }
/* Who paid?: the two boxed choices side by side when there is room (tablets and computers), stacked on a phone. */
@container (min-width: 30em) { .who-paid .choice-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); } }
/* Amount | Date (Edit: Amount | Date | Category), and Category | Department. On a phone the date gets a little more room
   than the amount, so the whole date shows. */
.form-grid.amount-row .input { min-width: 0; }
@container (min-width: 17em) {
  .form-grid.amount-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); }
  .form-grid.amount-row > .field:nth-child(3) { grid-column: 1 / -1; }
}
@container (min-width: 26em) { .form-grid.place-row, .form-grid.amount-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@container (min-width: 30em) {
  .form-grid.amount-row.with-category { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .form-grid.amount-row.with-category > .field:nth-child(3) { grid-column: auto; }
}
/* The facts that do not change (a teacher's claim, Edit expense) in a grey strip: a small grey label over a bold value,
   the cells divided by lines; they wrap one under the other when there is no room. */
.kv.fact-strip { display: flex; flex-wrap: wrap; gap: 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-2); }
.fact-strip > div { flex: 1 1 10rem; margin: -1px 0 0 -1px; padding: var(--space-2) var(--space-3); border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.fact-strip dd { font-weight: var(--weight-bold); }
/* The receipt's card: the field's own heading heads the card; with no receipt yet, the two buttons sit in the dashed area
   in the page's colour under a camera tile (a look only: nothing is dropped there). */
.receipt-card > .card-body { display: grid; gap: var(--space-4); }
.receipt-card .receipt-field { gap: var(--space-3); }
.receipt-card .receipt-field > legend { margin-bottom: var(--space-3); font-size: var(--text-md); font-weight: var(--weight-bold); }
.receipt-card .receipt-pick { grid-template-columns: minmax(0, 1fr); width: min(100%, 20rem); }
.receipt-card .receipt-view img { max-height: 14rem; }   /* Edit expense: the attached receipt, smaller than on its page */
.receipt-drop { display: grid; justify-items: center; gap: var(--space-4); padding: var(--space-6) var(--space-3);
  border: 2px dashed color-mix(in oklch, var(--sec) 45%, var(--surface)); border-radius: var(--radius-lg); background: var(--sec-tint); }
.receipt-drop-icon { display: grid; place-items: center; width: 52px; height: 52px; border-radius: var(--radius-lg); background: var(--sec-solid); color: var(--on-solid); }
/* The buttons: at the foot of the form, Cancel then the main button on the right, under a thin line on a computer; on a
   tablet they stay in view at the bottom; on a phone a bar from edge to edge at the bottom, the main button filling it,
   as on New enrolment. */
.sticky-actions.form-foot { justify-content: flex-end; margin-top: var(--space-5); }
@media (min-width: 64em) {
  .sticky-actions.form-foot { position: static; padding: var(--space-4) 0 0; border: 0; border-top: 1px solid var(--line-subtle); border-radius: 0; background: none; box-shadow: none; }
}
/* A field the keyboard moves to scrolls clear of the phone's bottom menu and of a form's Save bar kept in view (Words, Log
   an expense, Email settings), so it is never hidden behind them. */
@media (max-width: 47.99em) {
  html { scroll-padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--space-3)); }
  html:has(.sticky-actions.form-foot) { scroll-padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + 5rem); }
}
@media (min-width: 48em) and (max-width: 63.99em) {
  html:has(.sticky-actions.form-foot) { scroll-padding-bottom: 6rem; }
}
@media (max-width: 47.99em) {
  .sticky-actions.form-foot { margin-inline: calc(-1 * (var(--gutter) + var(--space-5) + 1px)); margin-bottom: calc(-1 * (var(--space-5) + 1px)); border-inline: 0; border-radius: 0; }
  .sticky-actions.form-foot > .btn:last-child { flex: 1 1 auto; }
}
/* ---- Redesign stage 6 (5a Expense detail, 5a Phone Claim): one expense or claim. On a computer the Details on the left,
   the Receipt and the cards under it on the right; on phones and tablets the Receipt comes first (it is first in the
   page). On a phone, for someone who may decide, Reject and Approve in a bar from edge to edge at the bottom, which takes
   the place of the band's Approve or reject. Reject is in red words (also in the Approve or reject window). */
@media (min-width: 64em) {
  .grid-main.expense-layout { grid-template-rows: auto 1fr; }
  .expense-layout > .expense-details { grid-area: 1 / 1 / span 2; }
  .expense-layout > .expense-receipt { grid-area: 1 / 2; }
  .expense-layout > .expense-side { grid-area: 2 / 2; }
}
.sticky-actions.claim-decide-bar { flex-wrap: nowrap; margin: var(--space-4) calc(-1 * var(--gutter)) 0; border-inline: 0; border-radius: 0; }
.claim-decide-bar > .btn { flex: 1 1 0; }
.claim-decide-bar > .btn:last-child { flex-grow: 1.4; }
@media (min-width: 48em) { .sticky-actions.claim-decide-bar { display: none; } }
@media (max-width: 47.99em) { .page-actions > .in-phone-bar, .page-actions:has(> .in-phone-bar:only-child) { display: none; } }
.btn-secondary.btn-reject { color: var(--danger-fg); border-color: var(--danger-border); }
.btn-secondary.btn-reject:hover { background: var(--danger-bg); border-color: var(--danger-fg); }
/* Mark as paid back (8a To pay back and its phone sheet): Date paid back, How and Bank reference or receipt no. side by
   side when the window has room, one under the other in the phone's sheet (and with larger text). */
.form.pay-back-form { container-type: inline-size; }
@container (min-width: 24em) {
  .form-grid.pay-back-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-grid.pay-back-fields > .field:nth-child(3) { grid-column: 1 / -1; }
}
@container (min-width: 34em) {
  .form-grid.pay-back-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end; }
  .form-grid.pay-back-fields > .field:nth-child(3) { grid-column: auto; }
}
.amount-reversed { color: var(--muted); text-decoration: line-through; }
.bars { display: grid; gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.bars li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-1) var(--space-3); align-items: center; font-size: var(--text-sm); }
.bars .bar-label { min-width: 0; overflow-wrap: anywhere; }
.bars .status-bar { grid-column: 1 / -1; min-width: 0; height: 14px; }
.bars .bar-value { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: var(--weight-semibold); }
.bars .bar-foot { grid-column: 1 / -1; font-size: var(--text-xs); color: var(--muted); }
@media (min-width: 48em) {
  .bars li { grid-template-columns: minmax(7rem, 11rem) minmax(0, 1fr) auto; }
  .bars .status-bar { grid-column: auto; }
  .bars .bar-foot { grid-column: 2 / -1; }
}
/* Redesign stage 6 (Expenses › Overview, Spending and Reports): the label | bar | amount row follows the chart's own width,
   not the screen's. In a narrow chart (a half-width card on a tablet) the bar would shrink to a sliver and a budget line
   would break over four lines, so there the label, the bar and the amount stack as on a phone. Where the row fits
   (computers, and full-width charts on a tablet) nothing changes. */
.bars { container-type: inline-size; }
@container (max-width: 380px) {
  .bars li { grid-template-columns: minmax(0, 1fr) auto; }
  .bars .status-bar, .bars .bar-foot { grid-column: 1 / -1; }
}
.progress > span.over { background: var(--st-late-fill); }
/* ---- Redesign stage 6 (5a Categories, plan A12 and B2): Categories & budgets. One card per budget of the year, three
   across on a computer, two on a tablet, one on a phone: the category; where it applies (a department's coloured dot)
   and the note; what has gone out or is owed, large, in the Expenses colour, then "of £1,500.00 budget"; a thin bar in
   the page's colour (README: a 6px bar on the track), red only when over; today's line, red only when over; and Edit and
   Remove at the foot (on phones too). */
.budget-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 48em) { .budget-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 80em) { .budget-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.budget-card { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); }
.budget-name { font-size: var(--text-md); font-weight: var(--weight-bold); overflow-wrap: break-word; }
.budget-where { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0; }
.budget-where > .dept-dot { margin-top: calc((1lh - 9px) / 2); }   /* level with the first line when the note wraps */
.budget-where > span { min-width: 0; overflow-wrap: break-word; }
.budget-figure { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-2); margin: 0; color: var(--muted); font-size: var(--text-xs); }
.budget-figure strong { font-size: var(--text-xl); line-height: 1.2; font-weight: var(--weight-bold); color: var(--sec-text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.budget-bar { height: 6px; border-radius: var(--radius-full); background: var(--track); overflow: hidden; }
.budget-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--sec); }
.budget-card.is-over .budget-bar > span { background: var(--st-late-fill); }
.budget-state { margin: 0; font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--ink-2); }
.budget-state.money-red { color: var(--danger-fg); }
.budget-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: auto; padding-top: var(--space-2); border-top: 1px solid var(--line-subtle); }
/* The Categories list on a phone or tablet: Teacher wages has no actions, so its card has no empty strip at the foot. */
@media (max-width: 74.99em) { .table.cards.table-categories td.cell-actions:empty { display: none; } }
.row-tick-wrap { display: inline-grid; place-items: center; width: var(--tap); height: var(--tap); border-radius: var(--radius-md); cursor: pointer; }
.row-tick-wrap:hover { background: var(--surface-2); }
.row-tick { width: 20px; height: 20px; margin: 0; accent-color: var(--blue-600); cursor: pointer; }
.adj-row { display: grid; gap: var(--space-2); grid-template-columns: minmax(0, 1fr); align-items: center; }
@media (min-width: 37.5em) { .adj-row { grid-template-columns: minmax(8rem, 1fr) minmax(7rem, 9rem) minmax(0, 1.4fr) auto; } }

/* ------------------------------------------------------------------ reports (Stage 5): the logo and the search filter */
.logo-preview { max-width: 12rem; max-height: 4.5rem; width: auto; height: auto; border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-2); background: #fff; }
.logo-preview.empty { display: grid; place-items: center; width: 8rem; height: 4rem; color: var(--muted); font-size: var(--text-xs); border-style: dashed; background: var(--surface-2); }
.print-head img.logo-box { object-fit: contain; border-style: solid; padding: 2px; background: #fff; }
.search-results { list-style: none; margin: var(--space-1) 0 0; padding: 0; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); max-height: 14rem; overflow: auto; box-shadow: var(--shadow-2); }
.search-results li.hint { padding: var(--space-2) var(--space-3); }
.search-result { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; min-height: 44px; padding: var(--space-2) var(--space-3); border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.search-result:hover, .search-result:focus-visible { background: var(--surface-hover); }
.seg-late.swatch-dot, .seg-need.swatch-dot { opacity: 1; }

/* ------------------------------------------------------------------ launch (Stage 8): Getting started on Home */
.gs-slot:empty, .dept-changes-slot:empty { display: none; }
.gs-count { font-size: var(--text-sm); font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; }
.gs-progress { margin: 0 0 var(--space-2); }
.gs-list { list-style: none; margin: 0 calc(-1 * var(--space-5)); padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); }
.gs-list > li { border-top: 1px solid var(--line-subtle); }
@media (min-width: 64em) {
  .gs-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gs-list > li:nth-child(even) { border-left: 1px solid var(--line-subtle); }
}
.gs-item { display: flex; align-items: flex-start; gap: var(--space-2); min-height: var(--tap); height: 100%; padding: var(--space-3) var(--space-4); color: inherit; text-decoration: none; }
@media (min-width: 37.5em) { .gs-item { gap: var(--space-3); padding: var(--space-3) var(--space-5); } }
.gs-item:hover { background: var(--surface-hover); }
.gs-mark { flex: none; display: inline-flex; margin-top: 1px; color: var(--muted); }
.gs-item.done .gs-mark { color: var(--success-fg); }
.gs-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.gs-body strong { overflow-wrap: break-word; }
.gs-state { font-size: var(--text-sm); color: var(--muted); overflow-wrap: break-word; }
.gs-word { font-weight: 600; color: var(--ink-2); }
.gs-item.done .gs-word { color: var(--success-fg); }
.gs-text { font-size: var(--text-sm); color: var(--ink-2); line-height: var(--leading-relaxed); }
.gs-go { flex: none; align-self: center; display: none; color: var(--muted); }
@media (min-width: 37.5em) { .gs-go { display: inline-flex; } }
.gs-foot { display: flex; justify-content: flex-end; }
.gs-all-done { display: flex; align-items: flex-start; gap: var(--space-2); color: var(--success-fg); line-height: var(--leading-relaxed); }
.gs-all-done svg { flex: none; margin-top: 3px; }

/* ------------------------------------------------------------------ launch (Stage 8): Add many at once */
.bulk-tips { margin: 0; padding-left: 1.25rem; display: grid; gap: var(--space-1); line-height: var(--leading-relaxed); }
.bulk-problems > li { flex-wrap: nowrap; align-items: flex-start; justify-content: flex-start; gap: var(--space-3); min-height: 0; padding: var(--space-3) var(--space-4); }
@media (min-width: 37.5em) { .bulk-problems > li { padding: var(--space-3) var(--space-5); } }
.bulk-row-no { flex: none; min-width: 4.5rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.bulk-row-text { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; line-height: var(--leading-relaxed); }
.bulk-problems > li:has(.bulk-tick) { align-items: center; }
.bulk-tick { display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap); cursor: pointer; }
.bulk-tick .row-tick { flex: none; }
/* Redesign stage 5 (E4): the check's answers as rows like Checks › Things to fix (issueRow), each with its pill. A possible
   duplicate's tick and message make a full-height row to tap; its icon and pill line up with the message. */
.bulk-issues .issue-row:has(.bulk-tick) > .issue-icon, .bulk-issues .issue-row:has(.bulk-tick) > .issue-end { margin-top: var(--space-2); }

/* ------------------------------------------------------------------ Stage 9: a due date as a day and a month; a problem shared by many rows */
.day-month-pair { display: grid; grid-template-columns: minmax(5rem, 1fr) minmax(0, 2fr); gap: var(--space-3); max-width: 24rem; }
.bulk-sub { margin: 0; padding: var(--space-4) var(--space-4) var(--space-1); font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--ink-2); }
@media (min-width: 37.5em) { .bulk-sub { padding-inline: var(--space-5); } }
.bulk-rows { display: block; margin-top: var(--space-1); }

/* ------------------------------------------------------------------ launch (Stage 8): the role guides */
/* Redesign stage 7 (E6): the guides are tiles like the Settings hub's (one column on a phone, two to three on wider
   screens), the name with the violet "Your role" pill beside it; the Owner's guide after them across the whole row. */
.guide-name { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); font: inherit; }   /* a heading in the tile's own text size */
.guide-name strong { font-size: var(--text-md); overflow-wrap: break-word; }
.guide-owner-tile { grid-column: 1 / -1; }
@media (min-width: 37.5em) { .guide-owner-tile > .hub-tile { flex-direction: row; } }
@media (min-width: 64em) { .hub-grid.guide-list { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* A guide's card with no title (the tasks; the Owner's guide's contents): the first line is spaced from the card's top. */
@media screen { .guide-card > .card-body:first-child, .guide-contents > .card-body:first-child { padding-top: var(--space-5); } }
.guide-tasks { margin: 0; padding-left: 1.5rem; display: grid; gap: var(--space-4); }
.guide-tasks li::marker { font-weight: 700; color: var(--muted); }
.guide-tasks strong { display: block; font-size: var(--text-md); }
.guide-tasks p { margin-top: 2px; color: var(--ink-2); line-height: var(--leading-relaxed); }
.guide-signin { margin: 0; padding-left: 1.25rem; display: grid; gap: var(--space-2); color: var(--ink-2); line-height: var(--leading-relaxed); }
/* The site's address wraps when it is wider than a phone with larger text (a word never does: it fits). */
.guide-signin li { overflow-wrap: anywhere; }
.guide-print-org { display: none; }
/* Stage 9: the owner's guide (sections of text, lists with a bold title, numbered steps) */
.guide-text { color: var(--ink-2); line-height: var(--leading-relaxed); }
.guide-items, .guide-steps { margin: 0; padding-left: 1.25rem; display: grid; gap: var(--space-2); color: var(--ink-2); line-height: var(--leading-relaxed); }
.guide-items strong { color: var(--ink); }
.guide-section h3 { margin-top: var(--space-2); }
.guide-contents a { font-weight: var(--weight-semibold); }
.health-version { margin-top: var(--space-2); }
/* ---- Redesign stage 7: the platform pages (7a Organisations, 7a Health, 8a Email settings). */
/* Organisations: one card per organisation, two to a row on tablets and computers and one on a phone: the monogram, the
   name in bold (it wraps when long) with its grey line, the pill, then Open and Edit. In a wide card the pill is on the
   right, as drawn; in a narrow one (a phone, a tablet, larger text) it goes under the name. */
.platform-orgs { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 48em) { .platform-orgs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.platform-org { container-type: inline-size; min-width: 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.platform-org-in { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "mono main" "mono status" "acts acts"; gap: var(--space-2) var(--space-3); align-items: start; padding: var(--space-4); }
.platform-org-in > .monogram { grid-area: mono; width: 2.875rem; height: 2.875rem; }
.platform-org-main { grid-area: main; display: grid; gap: 2px; min-width: 0; overflow-wrap: break-word; }
.platform-org-main > strong { font-size: var(--text-md); font-weight: var(--weight-bold); line-height: var(--leading-snug); }
.platform-org-status { grid-area: status; }
.platform-org-actions { grid-area: acts; display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
@container (min-width: 26em) {
  .platform-org-in { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "mono main status" "mono acts acts"; }
}
/* Edit an organisation: the App colour box. */
.colour-input { width: 4rem; height: var(--tap); padding: var(--space-1); border: 1px solid var(--border-control); border-radius: var(--radius-sm); background: var(--surface); cursor: pointer; }
/* Health: the six checks at the top, three to a row on a computer, two on a tablet and one on a phone. A tile is green when
   all is well, amber when something needs a look, red only for private files that anyone can open, and grey until it is
   known. Its title is the link to its card below, and the whole tile can be tapped. */
.check-tiles { display: grid; gap: var(--space-3); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 30em) { .check-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64em) { .check-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.check-tile { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); color: var(--ink); overflow-wrap: break-word; }
.check-tile.tone-success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-fg); }
.check-tile.tone-warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-fg); }
.check-tile.tone-danger { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger-fg-strong); }
.check-tile-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); font-weight: var(--weight-bold); line-height: var(--leading-snug); }
.check-tile-head > .icon-sm { flex: none; }
.check-tile-title a { color: inherit; text-decoration: none; }
.check-tile-title a::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius-lg); }
.check-tile.has-link:hover { box-shadow: inset 0 0 0 1px currentColor; }
.check-tile-label, .check-tile-foot { font-size: var(--text-xs); line-height: var(--leading-snug); }
.check-tile:not([class*="tone-"]) .check-tile-label, .check-tile:not([class*="tone-"]) .check-tile-foot { color: var(--muted); }
.check-tile-value { font-size: var(--text-lg); font-weight: var(--weight-bold); line-height: var(--leading-snug); font-variant-numeric: tabular-nums; }
.check-tile-value.is-words { font-size: var(--text-sm); font-weight: var(--weight-medium); }
.check-tile-action { position: relative; z-index: 1; }
.health-page .card[id] { scroll-margin-top: calc(var(--topbar-h) + var(--space-4)); }
.grid.health-pairs { align-items: start; }
.health-update-actions { margin-top: var(--space-3); }
/* Recent errors: the log's lines as they are written, wrapping where they must. */
.error-log { margin: 0; padding: var(--space-3); font-family: var(--font-mono); font-size: var(--text-xs); line-height: var(--leading-normal); white-space: pre-wrap; overflow-wrap: anywhere;
  background: var(--surface-2); border: 1px dashed var(--border-soft); border-radius: var(--radius-md); }
/* Restore from a backup file: a red-bordered card (E6); its window has the red header. */
.card.health-restore { border-color: color-mix(in srgb, var(--danger-fg) 60%, var(--surface)); }
/* Email settings: Send from, Sender name and Replies go to in one row when the card has room for three whole addresses (as
   drawn; a large screen), two to a row in a narrower card (a laptop, where a third of the card would cut an address off)
   and one on a phone, by the form's own width, so larger text falls back too; the SMTP and email-sending service boxes
   keep their border, with the title in bold; Save is in the form's foot, as on Log an expense. */
.form.email-form { container-type: inline-size; max-width: none; }
@container (min-width: 24em) { .form-grid.from-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@container (min-width: 40em) { .form-grid.from-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.email-form .perm-group > legend { font-weight: var(--weight-bold); }
@media print {
  .guide-print-org { display: block; font-weight: 700; }
  .guide-card { border: 0; }
  .guide-card .card-body { padding: 0; }
  .guide-tasks { gap: 6pt; }
}

/* ------------------------------------------------------------------ Home and the dashboard (redesign stage 3) */
/* Home's greeting sits on the page itself, with no band and no icon tile (frames 1a Admin Home and 1a Viewer Home); the
   dashboard's tabs, when the person has them, stay under it. */
.page-head.is-plain { color: var(--ink); padding-top: var(--space-2); }
.page-head.is-plain::before { background: none; border-bottom: 0; }
.page-head.is-plain.has-tabs::before { border-bottom: 1px solid var(--line); }
.page-head.is-plain h1 { color: var(--ink); font-size: var(--text-2xl); }
.page-head.is-plain .sub { color: var(--muted); font-size: var(--text-md); }
/* Quick actions, each in the colour of the part of the app it opens (New enrolment violet, Record a payment green, Log an
   expense orange). On a phone they are big tiles, two to a row, as drawn. */
.page-head .quick-actions .btn { white-space: nowrap; }
@media (max-width: 47.99em) {
  .page-head .quick-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .page-head .quick-actions .btn { min-height: 4rem; flex-direction: column; align-items: flex-start; justify-content: space-between; padding: var(--space-3); white-space: normal; text-align: left; }
  .page-head .quick-actions .field { grid-column: 1 / -1; }
}
/* The top bar on the dashboard's pages (computers): the year and "Figures as at", LIVE DATA, and "Read-only view" for
   people who only look at the figures. Narrower screens keep the year bar on the page. */
.topbar-extra { display: none; }
.year-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 6px 10px; border-radius: var(--radius-md); background: var(--sec-home-tint); color: var(--sec-home-text); font-size: var(--text-xs); white-space: nowrap; }
.year-chip .sep { opacity: .6; }
.live-pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 9px; border-radius: var(--radius-full); background: var(--success-bg); color: var(--success-fg); font-size: var(--text-2xs); font-weight: var(--weight-bold); letter-spacing: .04em; white-space: nowrap; }
.live-pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.live-pill.updating { background: var(--warning-bg); color: var(--warning-fg); }
/* Figures more than two hours old: their age in amber instead of LIVE DATA (6 October 2026). */
.live-pill.old { background: var(--warning-bg); color: var(--warning-fg); box-shadow: inset 0 0 0 1px var(--warning-border); letter-spacing: 0; }
.readonly-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: var(--radius-full); background: var(--chip-bg); color: var(--ink-2); font-size: var(--text-xs); font-weight: var(--weight-semibold); white-space: nowrap; }
@media (min-width: 64em) {
  .topbar-extra { display: flex; flex: none; align-items: center; gap: var(--space-2); }
  .year-bar.dash-year { display: none; }
}
/* Alerts at the top of Home: overdue fees (red) and claims waiting (orange), only when there is something to act on. */
.alert-row { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }
.alert-row:empty { display: none; }
.alert-card { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); padding: var(--space-3) var(--space-4); border: 1px solid; border-radius: var(--radius-lg); }
.alert-card.alert-danger { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger-fg-strong); }
.alert-card.alert-section { background: var(--sec-tint); border-color: var(--sec-line); color: var(--sec-text); }
.alert-icon { display: grid; place-items: center; flex: none; width: 2.5rem; height: 2.5rem; border-radius: var(--radius-md); color: var(--on-solid); }
.alert-danger .alert-icon { background: var(--st-late-solid); }
.alert-section .alert-icon { background: var(--sec-solid); }
.alert-text { display: grid; gap: 2px; flex: 1 1 12rem; min-width: 0; }
.alert-text strong { font-size: var(--text-md); }
.alert-text span { font-size: var(--text-sm); }
.alert-card .btn.alert-action { background: var(--surface); color: inherit; border-color: color-mix(in srgb, currentColor 35%, transparent); }
.alert-card .btn.alert-action:hover { background: var(--surface-2); }
/* "Money in · Fees" and "Money out · Expenses": a tinted strip, the main figure, a bar, then three small figures. */
.money-row { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }
.money-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; min-width: 0; }
.money-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); background: var(--sec-tint); color: var(--sec-text); }
/* The page the card's figures come from (6 October 2026): a small "Open →" at the end of the strip, a full tap target. */
.money-open { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; margin: calc(-1 * var(--space-3)) calc(-1 * var(--space-2)) calc(-1 * var(--space-3)) 0;
  padding: 0 var(--space-2); color: inherit; font-size: var(--text-xs); font-weight: var(--weight-bold); text-decoration: none; border-radius: var(--radius-md); }
.money-open:hover { text-decoration: underline; }
.money-open:focus-visible { outline-offset: -3px; }   /* inside the card, which clips anything outside it */
.money-head h2 { font-size: var(--text-sm); font-weight: var(--weight-bold); color: inherit; }
.money-tail { display: inline-flex; align-items: center; gap: var(--space-3); margin-left: auto; white-space: nowrap; }
.money-year { font-size: var(--text-xs); font-weight: var(--weight-semibold); }
.money-body { display: grid; gap: var(--space-3); padding: var(--space-4); }
.money-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-2); color: var(--muted); }
.money-big { font-size: var(--text-stat); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); line-height: 1.1; color: var(--sec-text); font-variant-numeric: tabular-nums; }
.money-bar { height: 10px; border-radius: var(--radius-full); background: var(--track); overflow: hidden; }
.money-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--sec-icon); }
.money-bar.on-tint { height: 8px; background: var(--surface); }
.money-caption { margin-top: calc(-1 * var(--space-2)); font-size: var(--text-xs); color: var(--muted); }
.money-card .figures { border-bottom: 0; padding-bottom: 0; }
.money-card.loading .money-big { color: var(--muted); }
/* Payment status: one tall bar in the status colours with the counts on it, then a key of pills with count and share. */
.status-grid { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 64em) { .status-grid { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); } }
.mix-bar { display: flex; gap: 3px; height: 30px; border-radius: var(--radius-md); overflow: hidden; background: var(--track); }
.mix-bar.labelled { height: 38px; }
.mix-seg { display: flex; align-items: center; min-width: 4px; padding: 0 8px; color: var(--on-solid); font-size: var(--text-2xs); font-weight: var(--weight-bold); white-space: nowrap; overflow: hidden; container-type: inline-size; }
@container (max-width: 1.6em) { .mix-n { visibility: hidden; } }
@container (max-width: 9em) { .mix-label { display: none; } }
.mix-paid { background: var(--st-paid-solid); }
.mix-credit { background: var(--st-credit-solid); }
.mix-upto { background: var(--st-upto-solid); }
.mix-late { background: var(--st-late-solid); }
.mix-future { background: var(--st-future-solid); }
.mix-need { background: var(--st-need-solid); }
.mix-written { background: var(--st-written-fill); color: var(--ink); }
.mix-nofees { background: var(--st-nofees-fill); color: var(--st-nofees-ink); }
.status-key { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: 0 var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }
.status-key > li { display: flex; align-items: center; gap: var(--space-3); min-height: 40px; border-bottom: 1px solid var(--line-subtle); font-size: var(--text-sm); }
.status-key > li > .badge { margin-right: auto; }
.status-key strong { font-variant-numeric: tabular-nums; }
.status-key .muted { min-width: 3em; text-align: right; font-variant-numeric: tabular-nums; }
/* Figures in a tinted tile with an icon, in the colour of what they count (Unique students, Teaching team, …). */
.fig-tiles { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); align-content: start; }
@media (min-width: 64em) { .status-grid .fig-tiles { grid-template-columns: minmax(0, 1fr); } }
.fig-tile { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-lg); background: var(--sec-tint); color: var(--sec-text); }
.fig-icon { display: grid; place-items: center; flex: none; width: 2.25rem; height: 2.25rem; border-radius: var(--radius-md); background: var(--sec-solid); color: var(--on-solid); }
.fig-main { display: grid; flex: 1 1 6rem; min-width: 0; }
.fig-label { font-size: var(--text-xs); font-weight: var(--weight-semibold); }
.fig-value { font-size: var(--text-xl); font-weight: var(--weight-bold); line-height: 1.2; font-variant-numeric: tabular-nums; }
.fig-foot { font-size: var(--text-2xs); }
/* A department's figures open their pages; Left to pay is blue, as its count elsewhere. */
a.fig-tile { text-decoration: none; transition: box-shadow var(--dur-fast) ease; }
a.fig-tile:hover { box-shadow: inset 0 0 0 2px var(--sec-line); }
.fig-tile.tone-info { background: var(--info-bg); color: var(--info-fg); }
.fig-tile.tone-info .fig-icon { background: var(--st-upto-solid); }
a.fig-tile.tone-info:hover { box-shadow: inset 0 0 0 2px var(--info-border); }
.card-links { margin-top: var(--space-3); }
/* Counts in tinted pills (Left to pay; the teaching groups' fee statuses): a 0 stays plain. */
.count-pill { display: inline-block; min-width: 1.75rem; padding: 2px 8px; border-radius: var(--radius-full); text-align: center; font-size: var(--text-xs); font-weight: var(--weight-bold); font-variant-numeric: tabular-nums; color: var(--muted); }
.count-pill.k-upto, .count-pill.k-info { background: var(--st-upto-bg); color: var(--st-upto-fg); }
.count-pill.k-paid { background: var(--st-paid-bg); color: var(--st-paid-fg); }
.count-pill.k-late { background: var(--st-late-bg); color: var(--st-late-fg); }
.count-pill.k-future { background: var(--st-future-bg); color: var(--st-future-fg); }
.count-pill.k-need { background: var(--st-need-bg); color: var(--st-need-fg); }
.count-pill.k-purple { background: var(--purple-bg); color: var(--purple-fg); }
.table th.col-owing { color: var(--info-fg); }
.table th.col-tocome, .table td.col-tocome { color: var(--sec-fees-text); }
.table td.col-tocome { font-weight: var(--weight-bold); }
/* The viewers' Home: three big tinted cards (Fees collected, Students, Spending). */
.glance-row { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.glance-row.four { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); } /* with Other income's card (agreed 7 October 2026) */
.glance-card { display: grid; gap: var(--space-2); align-content: start; padding: var(--space-4) var(--space-5); border-radius: var(--radius-lg); background: var(--sec-tint); color: var(--sec-text); min-width: 0; }
.glance-label { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); font-weight: var(--weight-bold); color: inherit; }
.glance-label .fig-icon { width: 1.875rem; height: 1.875rem; }
.glance-value { font-size: var(--text-stat); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); line-height: 1.1; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.glance-card p { font-size: var(--text-sm); line-height: var(--leading-snug); }
/* The department colours (code chips, cards, initials), from the department's place in the list. */
.dept-card, .band-code, .avatar-xs, .dept-pick { --dept: var(--chip-bg); --dept-ink: var(--ink-2); }
.dept-card.d1, .band-code.d1, .avatar-xs.d1, .dept-pick.d1 { --dept: var(--dept-1); --dept-ink: var(--dept-text-1); }
.dept-card.d2, .band-code.d2, .avatar-xs.d2, .dept-pick.d2 { --dept: var(--dept-2); --dept-ink: var(--dept-text-2); }
.dept-card.d3, .band-code.d3, .avatar-xs.d3, .dept-pick.d3 { --dept: var(--dept-3); --dept-ink: var(--dept-text-3); }
.dept-card.d4, .band-code.d4, .avatar-xs.d4, .dept-pick.d4 { --dept: var(--dept-4); --dept-ink: var(--dept-text-4); }
.dept-card.d5, .band-code.d5, .avatar-xs.d5, .dept-pick.d5 { --dept: var(--dept-5); --dept-ink: var(--dept-text-5); }
.dept-card.d6, .band-code.d6, .avatar-xs.d6, .dept-pick.d6 { --dept: var(--dept-6); --dept-ink: var(--dept-text-6); }
.dept-card.d7, .band-code.d7, .avatar-xs.d7, .dept-pick.d7 { --dept: var(--dept-7); --dept-ink: var(--dept-text-7); }
.dept-card.d8, .band-code.d8, .avatar-xs.d8, .dept-pick.d8 { --dept: var(--dept-8); --dept-ink: var(--dept-text-8); }
/* A department in figures: small cards on the viewers' Home, bigger ones with a tinted header on Departments. */
.dept-mini-grid { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr)); }
.dept-mini { display: grid; gap: var(--space-3); align-content: start; padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); color: inherit; text-decoration: none; min-width: 0; }
.dept-mini:hover, .dept-card:hover { border-color: var(--border-soft); box-shadow: var(--shadow-2); }
.dept-mini-head { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.dept-mini-head strong { min-width: 0; overflow-wrap: break-word; }
.dept-mini:hover .dept-mini-head strong, .dept-card:hover .dept-card-title strong { text-decoration: underline; }
.dept-figs { display: grid; gap: var(--space-2) var(--space-1); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.dept-figs.five { grid-template-columns: repeat(auto-fit, minmax(min(100%, 5rem), 1fr)); }
.dept-fig { display: grid; align-content: start; min-width: 0; }
.dept-fig strong { font-size: var(--text-lg); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dept-fig > span { font-size: var(--text-2xs); color: var(--muted); }
.dept-fig.box-info, .dept-fig.box-fees { padding: 4px 8px; border-radius: var(--radius-md); }
.dept-fig.box-info { background: var(--info-bg); color: var(--info-fg); }
.dept-fig.box-fees { background: var(--sec-fees-tint); color: var(--sec-fees-text); }
.dept-fig.box-info > span, .dept-fig.box-fees > span { color: inherit; font-weight: var(--weight-semibold); }
.dept-grid { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(min(100%, 28rem), 1fr)); }
.dept-card { display: grid; align-content: start; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); overflow: hidden; color: inherit; text-decoration: none; min-width: 0; }
.dept-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-4); background: color-mix(in srgb, var(--dept) 11%, var(--surface)); color: var(--dept-ink); }
.dept-code { display: inline-grid; place-items: center; flex: none; min-width: 3.5rem; height: 2.125rem; padding: 0 8px; border-radius: var(--radius-md); background: var(--dept-ink); color: var(--surface); font-size: var(--text-2xs); font-weight: var(--weight-bold); white-space: nowrap; }
.dept-card-title { display: grid; flex: 1 1 10rem; min-width: 0; }
.dept-card-title strong { font-size: var(--text-md); overflow-wrap: break-word; }
.dept-card-title span { font-size: var(--text-xs); }
.dept-open { display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.dept-card-body { display: grid; gap: var(--space-3); padding: var(--space-4); }
/* One department's page: its code as the band's tile, and the links to its other pages in the band. */
.band-code { display: inline-grid; place-items: center; flex: none; min-width: 4.25rem; height: 2.75rem; padding: 0 10px; border-radius: var(--radius-lg); background: var(--dept-ink); color: var(--surface); font-size: var(--text-sm); font-weight: var(--weight-bold); white-space: nowrap; }
.band-initials { font-size: var(--text-sm); font-weight: var(--weight-bold); }
.dept-links .btn { background: var(--surface); color: var(--sec-text); border-color: var(--sec-line); }
.dept-links .btn:hover { background: var(--sec-tint); }
.stat.accent .number { color: var(--sec-text); }
.dept-layout { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); align-items: start; }
/* Side by side from 1280 px, as drawn; the teaching groups' table is compact so its seven columns fit. */
@media (min-width: 80em) { .dept-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr); } }
.table.table-groups th, .table.table-groups td { padding-left: var(--space-2); padding-right: var(--space-2); }
.table.table-groups th { white-space: normal; overflow-wrap: normal; word-break: keep-all; hyphens: none; }
/* The hierarchy, each level in its own colour (Headteacher pink, Volunteer green); on its own page each person sits in a
   small white box and the levels are joined by a line (frame 4a Hierarchy). */
.level.lvl-head { background: var(--sec-staff-tint); border-color: var(--sec-staff-line); }
.level.lvl-head .level-no { background: var(--sec-staff-solid); color: var(--on-solid); }
.level.lvl-head .level-head strong { color: var(--sec-staff-text); }
.level.lvl-admin, .level.lvl-teacher { background: var(--surface-2); }
.level.lvl-admin .level-no, .level.lvl-teacher .level-no { background: var(--st-future-solid); color: var(--on-solid); }
.level.lvl-vol { background: var(--success-bg); border-color: var(--success-border); }
.level.lvl-vol .level-no { background: var(--st-paid-solid); color: var(--on-solid); }
.level.lvl-vol .level-head strong { color: var(--success-fg); }
.level-head .badge { background: var(--surface); }
.levels.boxed { gap: var(--space-5); }
.levels.boxed > .level { position: relative; }
.levels.boxed > .level + .level::before { content: ""; position: absolute; left: 50%; bottom: 100%; height: var(--space-5); border-left: 2px solid var(--line); }
.levels.boxed .level-people { grid-template-columns: repeat(auto-fill, minmax(min(100%, 11rem), 1fr)); gap: var(--space-2); }
.levels.boxed .level-people > li { display: grid; align-content: start; gap: 2px; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--surface); min-height: 0; }
.levels.boxed .level-people > li > a { font-weight: var(--weight-semibold); }
.dept-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.dept-pick { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap); padding: 0 var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-full); background: var(--surface); color: var(--dept-ink); font: inherit; font-size: var(--text-sm); font-weight: var(--weight-semibold); cursor: pointer; }
.dept-pick .dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--dept-ink); }
.dept-pick:hover { background: var(--surface-2); }
.dept-pick[aria-pressed="true"] { background: var(--dept-ink); border-color: var(--dept-ink); color: var(--surface); }
.dept-pick[aria-pressed="true"] .dot { display: none; }
/* Staff: the teaching roles in pink chips. Volunteers: a green band with the count. */
.badge.role-teach { background: var(--sec-staff-tint); color: var(--sec-staff-text); }
.hero-band { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); padding: var(--space-5); border: 1px solid var(--success-border); border-radius: var(--radius-lg); background: var(--success-bg); color: var(--success-fg); }
.hero-band .fig-icon { width: 3.25rem; height: 3.25rem; background: var(--st-paid-solid); }
.hero-band > div { flex: 1 1 14rem; min-width: 0; }
.hero-band .eyebrow { color: inherit; }
.hero-band .banner-big { margin: var(--space-1) 0; color: inherit; }
/* The students lists: the fee statuses as chips with counts, each student's initials, the department's code. */
.chip-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); padding: 0 var(--space-5) var(--space-3); }
.chip-bar-label { font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.ledger-who { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.ledger-who > div { min-width: 0; }
.avatar-xs { display: grid; place-items: center; flex: none; width: 2rem; height: 2rem; border-radius: 50%; background: color-mix(in srgb, var(--dept) 14%, var(--surface)); color: var(--dept-ink); font-size: var(--text-2xs); font-weight: var(--weight-bold); }
/* The student pop-up's figures as small tinted tiles (Fee, Paid, Remaining), as in the payment dialog. */
.figures.fig-boxes { border: 0; padding: 0; gap: var(--space-2); }
.fig-boxes .figure { padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--surface-2); }
.fig-boxes .figure.box-fees { background: var(--sec-fees-tint); color: var(--sec-fees-text); }
.fig-boxes .figure.box-late { background: var(--danger-bg); color: var(--danger-fg-strong); }
.fig-boxes .figure.box-info { background: var(--info-bg); color: var(--info-fg); }
.fig-boxes .figure.box-fees span, .fig-boxes .figure.box-late span, .fig-boxes .figure.box-info span { color: inherit; }
/* About these figures: each status beside what it means. */
@media (min-width: 48em) {
  .meanings > li { grid-template-columns: 10rem minmax(0, 1fr); gap: var(--space-4); align-items: start; padding-bottom: var(--space-3); border-bottom: 1px solid var(--line-subtle); }
  .meanings > li:last-child { border-bottom: 0; padding-bottom: 0; }
}
/* Home without the dashboard (frame 8a Simple Home): each link with a solid tile in the colour of what it opens. */
.card.link-card.dest-card { height: 100%; }
.card.link-card.dest-card h2 { gap: var(--space-3); }
.dest-tile { display: grid; place-items: center; flex: none; width: 2.375rem; height: 2.375rem; border-radius: var(--radius-md); background: var(--sec-solid); color: var(--on-solid); }
.dest-card h2 .grow { flex: 1 1 auto; min-width: 0; }
.dest-card h2 > .icon:last-child { color: var(--muted); }
/* Its Academic year card: the year a size larger, its dates just under it. */
.home-year strong { font-size: var(--text-lg); }
.home-year + .hint { margin-top: var(--space-1); }
.money-slot { min-width: 0; }
.stat.tone-success { background: var(--success-bg); border-color: var(--success-border); }
.stat.tone-success, .stat.tone-success .label, .stat.tone-success .foot { color: var(--success-fg); }
/* The Departments table on Home: ten columns that fit a 1200 px screen (narrower screens show each row as a card). */
.table.table-depts:not(.cards) th, .table.table-depts th, .table.table-depts td { padding-left: var(--space-2); padding-right: var(--space-2); }
.table.table-depts th { white-space: normal; overflow-wrap: normal; word-break: keep-all; hyphens: none; }
.table.table-depts .status-bar { min-width: 4rem; }
.page-head.is-plain h1 { font-size: min(var(--text-2xl), 1.625rem); }
.filter-chip.chip-purple { --chip-line: var(--st-credit-solid); --chip-fg: var(--purple-fg); }
.narrow-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
.off-note { margin-top: var(--space-3); }   /* "Includes £339 of reductions · £100 of discounts this year." */
@media (min-width: 64em) { .narrow-status { display: none; } }

/* ------------------------------------------------------------------ redesign stage 4: fees and the fee tools */
/* A green-tinted button in the page's colour (6a: Payment, Record payment on Due & overdue). */
.btn-tint { background: var(--sec-action-tint); color: var(--sec-action-text); }
.btn-tint:hover { background: color-mix(in oklch, var(--sec-action) 20%, var(--surface)); }
/* ---- Redesign stage 7: data and safety (7a Deleted). On the Settings pages a tinted button is in their action blue, like
   their main button: its tint already is (tokens.css), so its words are blue too (Deleted items' Restore, as drawn). A
   part in another colour inside such a page keeps its own. */
:root, [data-section] { --sec-action-text: var(--sec-text); }
[data-section="settings"] { --sec-action-text: var(--sec-home-text); }
/* ---- Redesign stage 7: Backups and exports, Data protection (7a Backups, 7a Data protection). */
/* The amber tinted button (button({ variant: 'tint-warning' })): an action on something past its time (Due for review's
   Anonymise and Delete, as drawn), in the amber of the pills that wait for someone; AA in light and dark. */
.btn-tint-warning { background: var(--st-need-bg); color: var(--warning-fg); }
.btn-tint-warning:hover { background: color-mix(in oklch, var(--st-need-fill) 22%, var(--surface)); }
/* Backups and exports on a wide screen (1920): the list on the left, as wide as the one-column list at 1280, and the
   Recovery kit, Off-site copies and Download everything to read in a column of 25rem on the right, as drawn. Below 105em
   (1680px at normal text size) one column, so at 1280 the list keeps the room its five columns need. */
.backups-layout { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 105em) { .backups-layout { grid-template-columns: minmax(0, 1fr) 25rem; align-items: start; } }
@media print { .btn-tint-warning { background: none; color: #000; box-shadow: inset 0 0 0 1px #000; } }
/* A department's coloured square before its name (6a Prices), in the colours of the department chips. */
.dept-dot { display: inline-block; flex: none; width: 9px; height: 9px; border-radius: 3px; background: var(--muted); vertical-align: baseline; }
.dept-dot.d1 { background: var(--dept-1); } .dept-dot.d2 { background: var(--dept-2); } .dept-dot.d3 { background: var(--dept-3); }
.dept-dot.d4 { background: var(--dept-4); } .dept-dot.d5 { background: var(--dept-5); } .dept-dot.d6 { background: var(--dept-6); }
.dept-dot.d7 { background: var(--dept-7); } .dept-dot.d8 { background: var(--dept-8); }
/* A department's code or dot beside its name in a list (not a link): closer together, with no tap height. Home's
   department links keep their own spacing (stage 3). */
.dept-name.tight { gap: var(--space-2); min-height: 0; }
/* Inside a line of text (a family's Fees rows), the chip sits on the line with no tap height. */
.dept-name.inline { min-height: 0; flex-wrap: wrap; }
/* A small icon inside a box (the magnifier of a search box). */
.input-icon { position: relative; display: block; min-width: 0; }
.input-icon > .input-glyph { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; z-index: 1; }
.input-icon > .input, .input-icon > .input-group .input { padding-left: 38px; }
/* The amount that matters most in a form (a payment's Amount), outlined in the page's colour with the "£" inside. */
/* The "£" sits inside the box; the box keeps the usual focus ring. */
.input-group.key .input { border: 1.5px solid var(--sec-action); font-size: var(--text-lg); font-weight: var(--weight-bold); }
/* A one-character symbol ("£", "€") sits inside the box; a longer one ("US$", "PKR") stays in front of it, so it never
   covers the amount typed. */
.input-group.key.inside { position: relative; }
.input-group.key.inside .affix { position: absolute; top: 0; bottom: 0; left: 0; z-index: 1; padding: 0 2px 0 12px; border: 0; background: none; color: var(--muted); font-size: var(--text-lg); font-weight: var(--weight-bold); pointer-events: none; }
.input-group.key.inside .input, .input-group.key:not(:has(.affix)) .input { border-radius: var(--radius-sm); }
.input-group.key.inside .input { padding-left: 2.25rem; }
.input-group.key .input:focus { border-color: var(--focus); }
.field[data-invalid] .input-group.key .input { border-color: var(--danger-solid); }
/* A few short choices side by side as one switch (Payment | Refund | Write-off), the chosen one solid. */
.choice-list.segmented { display: flex; flex-wrap: wrap; gap: 2px; padding: 3px; border: 1px solid var(--border-soft); border-radius: var(--radius-md); background: var(--surface-2); }
.choice-list.segmented .segment { position: relative; flex: 1 1 0; justify-content: center; align-items: center; min-height: var(--tap); padding: 6px var(--space-3); border-radius: var(--radius-sm); color: var(--ink-2); font-weight: var(--weight-semibold); text-align: center; }
.choice-list.segmented .segment input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.choice-list.segmented .segment:hover { background: var(--surface); }
.choice-list.segmented .segment:has(input:checked) { background: var(--sec-action); color: var(--on-solid); }
.choice-list.segmented .segment:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.choice-list.segmented .segment:has(input:disabled) { opacity: .55; cursor: not-allowed; }
.choice-list.segmented .choice-text small { display: none; }
@media (forced-colors: active) {
  .choice-list.segmented .segment:has(input:checked) { outline: 2px solid CanvasText; outline-offset: -4px; }
  /* The chosen part keeps its line; keyboard focus gets its own, outside it. */
  .choice-list.segmented .segment:has(input:focus-visible) { outline: 3px solid Highlight; outline-offset: 2px; }
}
/* One line under a dialog's title, in its header ("Ella Johnson · WDEM-E004 · Weekend Education"). */
.dialog-head-sub { margin: 2px 0 0; color: var(--dlg-fg); font-size: var(--text-sm); line-height: var(--leading-snug); overflow-wrap: anywhere; }
/* The small tabs drawn in 6a Checks, in the page's colour. */
.tabs.pill-tabs { gap: 4px; padding: 0; background: none; border: 0; border-radius: 0; }
.tabs.pill-tabs a, .tabs.pill-tabs button { flex: 0 0 auto; min-height: var(--tap); padding: 6px 12px; color: var(--muted); font-weight: var(--weight-semibold); }
.tabs.pill-tabs a:hover, .tabs.pill-tabs button:hover { background: var(--surface-2); color: var(--ink); }
.tabs.pill-tabs [aria-current="page"], .tabs.pill-tabs [aria-pressed="true"] { background: var(--sec-tint); color: var(--sec-text); font-weight: var(--weight-bold); }
.tabs.pill-tabs .badge { background: var(--sec-solid); color: var(--on-solid); }
@media (max-width: 37.5em) { .tabs.pill-tabs a, .tabs.pill-tabs button { flex: 0 1 auto; } }
.page-tabs { margin-bottom: var(--space-4); }
/* Figure tiles by meaning (6a Checks, 3a Due). */
.fig-tile.tone-danger { background: var(--danger-bg); color: var(--danger-fg-strong); }
.fig-tile.tone-danger .fig-icon { background: var(--danger-solid); }
.fig-tile.tone-warning { background: var(--warning-bg); color: var(--warning-fg); }
.fig-tile.tone-warning .fig-icon { background: var(--st-need-solid); }
/* Nothing to act on (0 errors, £0 overdue): plain, not red, amber or the page's colour (the owner, 8 October 2026). */
.fig-tile.tone-neutral { background: var(--surface-2); color: var(--ink); }
.fig-tile.tone-neutral .fig-icon { background: var(--st-future-solid); }
.fig-tiles.row3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); margin-bottom: var(--space-4); }
/* Something to fix, as a row (6a Checks). */
.issue-list { list-style: none; margin: 0; padding: 0; }
.issue-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-4); border-top: 1px solid var(--line-subtle); }
.issue-row:first-child { border-top: 0; }
.issue-icon { display: grid; place-items: center; flex: none; width: 1.75rem; height: 1.75rem; border-radius: var(--radius-sm); background: var(--danger-solid); color: var(--on-solid); }
.issue-row.k-warning .issue-icon { background: var(--st-need-solid); }
.issue-row.k-info .issue-icon { background: var(--st-upto-solid); }
.issue-row.k-done .issue-icon { background: var(--st-future-solid); }
/* 12rem keeps the icon tile beside the message on a 360-wide phone; the pill and link wrap under it. */
.issue-main { flex: 1 1 12rem; min-width: 0; display: grid; gap: 2px; }
.issue-main strong { overflow-wrap: anywhere; }
.issue-end { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-left: auto; }
.issue-end > a { display: inline-flex; align-items: center; min-height: var(--tap); }
/* One thing a page lets you do, as a card (6a Transfers). */
.action-cards { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); margin-bottom: var(--space-4); }
.action-card { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.action-icon { display: grid; place-items: center; flex: none; width: 2.75rem; height: 2.75rem; border-radius: var(--radius-md); background: var(--sec-tint); color: var(--sec-text); }
.action-card h2 { margin: var(--space-1) 0 0; font-size: var(--text-md); }
.action-card p { flex: 1; margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: var(--leading-relaxed); }
.action-card .btn { margin-top: var(--space-1); }
/* A plan's instalments as numbered rows (4a Student). */
.inst-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.inst-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-subtle); border-radius: var(--radius-md); background: var(--surface); }
.inst-no { display: grid; place-items: center; flex: none; width: 1.75rem; height: 1.75rem; border-radius: 50%; background: var(--surface-2); color: var(--ink-2); font-size: var(--text-xs); font-weight: var(--weight-bold); }
.inst-date { flex: 1 1 8rem; min-width: 0; display: grid; }
/* "Next" sits under the date, so the amount stays on the row's first line on a phone. */
.inst-date > .badge { justify-self: start; margin-top: 2px; }
.inst-amount { margin-left: auto; font-variant-numeric: tabular-nums; }
.inst-row.is-next { border-color: var(--info-border); background: var(--info-bg); }
.inst-row.is-next .inst-no { background: var(--st-upto-solid); color: var(--on-solid); }
.fig-boxes .figure.box-credit { background: color-mix(in srgb, var(--st-credit-solid) 12%, var(--surface)); color: var(--purple-fg); }
.fig-boxes .figure.box-credit span { color: inherit; }
@media print {
  .btn-tint { background: none; color: #000; box-shadow: inset 0 0 0 1px #000; }
  .fig-tile, .issue-icon, .inst-row.is-next { background: none !important; color: #000 !important; box-shadow: inset 0 0 0 1px #000; }
}
/* Students & fees and Record a payment (3a Fees, 6a Record a payment): the search takes the room left; Record a
   payment's search is the large box above the list, outlined in the page's colour. */
.toolbar .field.grow { flex: 2 1 18rem; }
.toolbar.bare.wide .field { max-width: none; }
.toolbar.bare.wide .field:not(.grow) { flex: 0 1 18rem; }
.search-lg .input { min-height: 50px; border: 2px solid var(--sec-action); font-size: var(--text-md); }
.search-lg .input:focus { border-color: var(--focus); }
/* Due & overdue (3a Due): each department's card has a header in its colour. */
.due-group .dept-card-title h2 { margin: 0; color: inherit; font-size: var(--text-md); overflow-wrap: break-word; }
.due-group .dept-card-head .cluster { margin-left: auto; }
/* A card, not a link: no lift on hover; a wide table scrolls inside it. */
.due-group { display: block; }
.due-group:hover { border-color: var(--line); box-shadow: none; }
.due-group:hover .dept-card-title strong { text-decoration: none; }
@media print { .due-group .dept-card-head { background: none; color: #000; } .due-group .dept-code { background: none; color: #000; box-shadow: inset 0 0 0 1px #000; } }
/* The payment dialog's recent payments as small grey rows (3a Payment dialog). */
.mini-list.boxed { display: grid; gap: 4px; }
.mini-list.boxed > li { padding: var(--space-2) var(--space-3); border-top: 0; border-radius: var(--radius-sm); background: var(--surface-2); }
.mini-list.boxed > li.voided strong { text-decoration: line-through; color: var(--muted); }
/* Fees & plan, New enrolment, Complete a transfer and the Pro-rata calculator (E3): ticked items in the fees colour
   with a green tick, wherever they open; the plan's numbers in the fees colour. */
.fee-row.on { border-color: var(--sec-fees-line); background: var(--sec-fees-tint); }
.fee-row-main input { accent-color: var(--sec-fees-solid); }
.plan-no { background: var(--sec-fees-tint); color: var(--sec-fees-text); }
.section-head.strip { padding: var(--space-2) var(--space-3); border-top: 0; border-radius: var(--radius-md); background: var(--surface-2); }
/* "Joined late?" in a soft grey box, its working in a blue box. */
.pro-rata { padding: var(--space-3); border-radius: var(--radius-md); background: var(--surface-2); }
.hint.pro-rata-line:not(:empty) { padding: var(--space-2) var(--space-3); border: 1px solid var(--info-border); border-radius: var(--radius-sm); background: var(--info-bg); color: var(--info-fg); }
/* The leaving balance: the working in a grey box, the outcome in a tinted box. */
.working.boxed { padding: var(--space-3); border-radius: var(--radius-md); background: var(--surface-2); color: var(--ink-2); }
.outcome-box { padding: var(--space-3) var(--space-4); border: 1px solid var(--sec-line); border-radius: var(--radius-md); background: var(--sec-tint); }
.outcome-box > h3 { color: var(--sec-text); }
/* A fee kept at the price on the day its enrolment closed: a grey line with a lock. */
.hint.kept-line { display: flex; align-items: center; gap: 4px; }
.kept-line .icon-sm { flex: none; }
/* A voided other charge: its amounts struck through (E3). */
.table tr.row-void td.num { text-decoration: line-through; color: var(--muted); }
/* Fee plans as boxes (6a Prices): the default plan in the fees colour; its instalments as small boxes. */
.plan-boxes { list-style: none; margin: 0; padding: var(--space-3) var(--space-4) var(--space-4); display: grid; gap: var(--space-3); }
.plan-box { display: grid; gap: var(--space-2); padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-2); min-width: 0; }
.plan-box.is-default { border-color: var(--sec-line); background: var(--sec-tint); }
.plan-box.is-retired { background: var(--surface); border-style: dashed; }
.plan-box-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-3); }
.plan-box-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-width: 0; }
.plan-box-title > strong { font-size: var(--text-md); overflow-wrap: break-word; }
.plan-box > .hint { margin: 0; }
.part-boxes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); }
.part-boxes > li { display: grid; gap: 2px; padding: var(--space-2) var(--space-3); border: 1px solid var(--line-subtle); border-radius: var(--radius-sm); background: var(--surface); font-size: var(--text-sm); }
.part-boxes > li > span { color: var(--muted); font-size: var(--text-xs); }
/* The Pro-rata calculator's answer (6a Pro-rata): a solid green band with the big figure, the rest below. */
.result-card { overflow: hidden; }
.result-solid { display: grid; gap: var(--space-3); padding: var(--space-4) var(--space-5); background: var(--sec-solid); color: var(--on-solid); }
.result-solid h2 { color: inherit; font-size: var(--text-md); }
.result-hero { display: grid; gap: 2px; }
.result-hero > span { font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.result-hero > strong { font-size: var(--text-stat); line-height: 1.1; font-variant-numeric: tabular-nums; }
.result-solid .figures { border-color: color-mix(in srgb, var(--on-solid) 30%, transparent); }
.result-solid .figures, .result-solid .figure span { color: inherit; }
.btn-secondary.on-solid { background: transparent; color: var(--on-solid); border-color: color-mix(in srgb, var(--on-solid) 70%, transparent); }
.btn-secondary.on-solid:hover { background: color-mix(in srgb, var(--on-solid) 12%, transparent); }
/* White on the solid band (about 4.6:1), so keyboard focus on Print shows. */
.result-solid :focus-visible { outline-color: var(--on-solid); }
@media print { .result-solid { background: none; color: #000; padding: 0; } .result-solid .figures { border-color: #000; } }
.rows.issue-list > li.issue-row { align-items: flex-start; justify-content: flex-start; padding: var(--space-3) 0; min-height: 0; }
/* The handovers table: nine columns that fit a 1280 px screen (narrower screens show each handover as a card). */
.table.table-cash th, .table.table-cash td { padding-left: var(--space-2); padding-right: var(--space-2); }
.table.table-cash th { white-space: normal; overflow-wrap: normal; word-break: keep-all; hyphens: none; }
/* Due & overdue on a phone: the two money figures only. */
@media (max-width: 37.49em) { .fig-tile.wide-tile { display: none; } }
/* Answer 4: a list's filters. On a computer they stay in the toolbar row as before; on a phone they fold into a Filters
   button beside the search box (the sheet holds the same fields while it is open). */
.filter-bar > .filter-fields { display: contents; }
.filter-bar > .filter-open { flex: none; }
@media (max-width: 47.99em) { .filter-bar > .filter-fields { display: none; } }
@media (min-width: 48em) { .filter-bar > .filter-open { display: none; } }
/* Redesign stage 5: a few fields that come and go together (the Students list's extra detail value, Containing, From and
   To) sit in the row, or in the sheet, as if each were its own filter. */
.filter-group { display: contents; }
.stack > .filter-group > * { margin-top: var(--space-4); }
/* A stack whose first block is hidden (Staff & volunteers' figures, on the Volunteers tab) starts with the next one. */
.stack > [hidden]:first-child + * { margin-top: 0; }
/* Students & fees with the Department column: the row's buttons may wrap onto two lines in their cell on a laptop. */
.table td.cell-actions.wrap-actions { white-space: normal; }
.table td.cell-actions .cell-buttons { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: var(--space-1) var(--space-2); }
/* A phone card's money line (Remaining, To collect): the amount in bold in the ink colour. */
.list-card-main .card-figure strong { color: var(--ink); font-size: var(--text-sm); }
.list-card-main .card-figure strong.money-red { color: var(--danger-fg); }
/* The payment sheet on a phone (3a Phone Payment sheet): the three figures in one row; Type and Amount full width; Date
   and Method side by side (Date alone when a write-off has no method). An amount is never split across two lines: when
   the three do not fit side by side (a large amount, or larger text), a box goes onto the next row; and Date and Method
   go one under the other when they do not fit side by side (final check, 18 October 2026: "£3,000.0 / 0", and the Date
   box under Method at 150% text). */
@media (max-width: 37.49em) {
  .dialog .fig-boxes { display: flex; flex-wrap: wrap; }
  .dialog .fig-boxes .figure { flex: 1 1 0; min-width: min-content; padding: var(--space-2); }
  .dialog .fig-boxes .figure strong { font-size: var(--text-md); }
  .dialog .fig-boxes .figure:not(.fig-text) strong { white-space: nowrap; }
  .dialog .fig-boxes .figure.fig-text { flex-basis: 100%; }
  .form-grid.two.pay-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr)); }
  .pay-grid > .field { grid-column: 1 / -1; }
  .pay-grid > .field:has(input[type="date"]):not(:has(~ .field[hidden] select[name="method"])),
  .pay-grid > .field:not([hidden]):has(select[name="method"]) { grid-column: auto; }
}
/* A tile that holds a name (a gift's "From"), not an amount: ordinary-size text that wraps between words, and the
   whole row on a phone, so a long name such as a trust's is never split inside a word. */
.fig-boxes .figure.fig-text strong { font-size: var(--text-md); overflow-wrap: break-word; }
@media (max-width: 37.49em) { .fig-boxes .figure.fig-text { grid-column: 1 / -1; } }

/* ------------------------------------------------------------------ Money in breakdown */
/* "What makes up Money in · Fees" (agreed 16 October 2026, docs/proposals/money-in-and-admin-fee.md, picture B; also in the
   gallery, /gallery?preview=money-in, where picture A uses the box's own caption lines). The big figure (dotted underline)
   and a small "What makes it up" link under it open the parts (ui/money-parts.js); on a computer a small window next to the
   box (a popover, placed by the script), on a phone the ordinary sheet. The parts are rows as in .status-lines, each group
   of "Not part of the fees" with its items indented under it, and the total line under the fee parts. */
.money-big-open { display: inline-flex; align-items: center; min-height: var(--tap); padding: 0; border: 0; background: none; font-family: inherit; cursor: pointer;
  text-decoration: underline dotted color-mix(in srgb, currentColor 45%, transparent); text-decoration-thickness: 2px; text-underline-offset: .2em; }
.money-big-open:hover { text-decoration-color: currentColor; }
.btn.money-parts-open { justify-self: start; margin: calc(-1 * var(--space-2)) 0 calc(-1 * var(--space-2)) calc(-1 * var(--space-2)); color: var(--sec-text); }
.btn.money-parts-open:hover { background: var(--sec-tint); text-decoration: underline; }
.money-pop { inset: auto; margin: 0; padding: 0; width: min(23rem, calc(100vw - 24px)); max-height: calc(100vh - 24px); border: 1px solid var(--line);
  border-radius: var(--radius-xl); background: var(--surface); color: var(--ink); box-shadow: var(--shadow-3); overflow: hidden; }
/* Hidden until it opens, also in a browser without popovers (Safari before 17, Firefox before 125), which never opens it
   (the ordinary window opens instead) and would otherwise show it as an empty panel inside the box. */
.money-pop { display: none; }
.money-pop:popover-open { display: flex; flex-direction: column; }
.money-parts { display: grid; gap: var(--space-2); }
.money-parts > h3:not(:first-child) { margin-top: var(--space-3); }
.money-parts .money-parts-group { font-weight: var(--weight-semibold); }
.money-parts .money-parts-item { padding-left: var(--space-5); color: var(--muted); }
.money-parts .money-parts-item strong { font-weight: var(--weight-regular); }
.money-parts-total { display: flex; align-items: center; gap: var(--space-3); min-height: 40px; padding: 0 var(--space-1); border-top: 2px solid var(--line);
  font-size: var(--text-sm); font-weight: var(--weight-bold); color: var(--sec-text); font-variant-numeric: tabular-nums; }
.money-parts-total .grow { flex: 1 1 auto; min-width: 0; }
.money-parts > .hint { margin-top: var(--space-2); }
/* Viewers' "Fees collected" card: the figure and the link keep their own width. */
.glance-card > .money-big-open, .glance-card > .btn.money-parts-open { justify-self: start; }
/* A teacher's "Fees collected" box (My teaching group): its figure and "What makes it up" open the parts. On a phone the
   box is narrow, so the link wraps: it keeps to the left, like the rest of the box. */
.stat .number > .money-big-open { max-width: 100%; }
.stat-parts .btn.money-parts-open { margin-top: var(--space-1); justify-content: flex-start; text-align: start; }
/* Its "Open" (to Fees) at the end of the name's line, as on the Money in box's strip; on a narrow box it goes under the name. */
.stat-parts .label { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; column-gap: var(--space-2); }
.stat-parts .label > .money-open { margin: calc(-1 * var(--space-3)) calc(-1 * var(--space-2)) calc(-1 * var(--space-3)) auto; }

/* ------------------------------------------------------------------ Fee letters (agreed 16 October 2026) */
/* docs/proposals/fee-letters.md, pictures "The list" and "The wording" (Fees › Fee letters and Settings › Fee letters; the
   gallery's previews, /gallery?preview=fee-letters and ?preview=fee-letter-wording, use the same parts). The Fee letters
   page: the letter and its Pay by date in a row of their own, which stays on screen on a phone (the other filters go behind
   the Filters button under it). */
.toolbar.letters-kind { padding-bottom: var(--space-3); }
.toolbar.letters-kind .field { flex: 0 1 auto; }
.toolbar.letters-kind .choice-list.segmented .segment { flex: 1 1 auto; white-space: nowrap; }
/* The list: a table on a computer, where a family's grey note sits on a line of its own under its row; one card per family
   (its tick box on the left) on phones and tablets. The amber bar is above the list on a computer; on phones and tablets
   it comes after the list and stays at the foot of the screen, above the bottom menu, while the list scrolls. */
.letters-list { display: flex; flex-direction: column; }
.letters-list > .letters-not-listed { order: 1; }
.letters-list > .letters-bar { order: 2; position: sticky; bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--space-2)); z-index: var(--z-sticky);
  margin-top: var(--space-3); box-shadow: var(--shadow-2); }
@media (min-width: 48em) { .letters-list > .letters-bar { bottom: var(--space-3); } }
.letters-table-view { display: none; }
.letters-table td { vertical-align: top; }
.letters-table th.col-tick, .letters-table td.col-tick { width: 3.5rem; padding: var(--space-1) 0 var(--space-1) var(--space-2); }
.letters-table tr.has-note > td { border-bottom: 0; }
.letters-table tr.letters-note > td { padding-top: 0; }
.letters-children { display: grid; gap: 2px; }
.letters-note-text { display: flex; align-items: flex-start; gap: var(--space-1); color: var(--muted); font-size: var(--text-xs); line-height: var(--leading-relaxed); }
.letters-note-text > svg { flex: none; margin-top: 3px; }
.letters-cards { list-style: none; margin: 0; padding: 0 var(--space-3) var(--space-3); display: grid; gap: var(--space-3); }
@media (min-width: 37.5em) { .letters-cards { padding-inline: var(--space-5); } }
.letters-card { display: grid; grid-template-columns: var(--tap) minmax(0, 1fr); align-items: start; gap: var(--space-1);
  padding: var(--space-1) var(--space-3) var(--space-3) var(--space-1); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.letters-card-main { display: grid; gap: var(--space-1); min-width: 0; padding-top: var(--space-2); font-size: var(--text-sm); }
.letters-card-top { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 var(--space-3); font-size: var(--text-md); }
.letters-figures { display: flex; flex-wrap: wrap; gap: 0 var(--space-3); }
@media (min-width: 64em) {
  .letters-table-view { display: block; }
  .letters-cards { display: none; }
  .letters-list > .letters-bar { order: 0; position: static; margin-top: 0; box-shadow: none; }
}
/* The grey notes of a row, one under the other; the line saying the letters are counted by family (from Print letters on
   Due & overdue or the Overdue report), above the list. */
.letter-notes { display: grid; gap: 2px; }
.letters-from { margin: 0 var(--space-5) var(--space-3); }
@media (max-width: 47.99em) { .letters-from { margin-inline: var(--space-3); } }
/* The print window of one letter (a student's or family's page): the amount it asks for stands out. */
.letter-asks { font-size: var(--text-md); }
/* Settings › Fee letters, laid out like Words used in the app (its .words-layout). "How it will look" is a small sheet of
   paper with the letter as it prints: the navy band, the name and address, the wording, the fees in short, the amount box
   (a red edge on a final notice), How to pay, the sign-off and the footer. */
.letter-preview { overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); box-shadow: var(--shadow-1);
  font-size: var(--text-xs); line-height: var(--leading-relaxed); }
.letter-preview-band { display: grid; gap: 2px; padding: var(--space-3) var(--space-4); background: var(--navy-800); color: var(--on-navy); }
.letter-preview-band strong { font-size: var(--text-md); }
.letter-preview-band span { color: var(--on-navy-2); }
.letter-preview-body { display: grid; gap: var(--space-2); padding: var(--space-4); }
.letter-preview-to { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-1); }
.letter-preview-to > div, .letter-preview-sign, .letter-preview-fees, .letter-preview-amount, .letter-preview-pay { display: grid; gap: 2px; }
.letter-preview-date { color: var(--muted); }
.letter-preview-fees, .letter-preview-amount { padding: var(--space-2) var(--space-3); border-radius: var(--radius-xs); background: var(--surface-2); }
.letter-preview-amount strong { font-size: var(--text-sm); }
.letter-preview-amount.is-final { border-left: 3px solid var(--danger-solid); background: var(--danger-bg); }
.letter-preview-pay { padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-xs); white-space: pre-line; }
.letter-preview-pay strong { color: var(--blue-text); }
.letter-preview-foot { padding: var(--space-2) var(--space-4); border-top: 1px solid var(--line-subtle); color: var(--muted); font-size: var(--text-2xs); }
.letter-placeholders { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-2) var(--space-4); margin: 0; font-size: var(--text-sm); }
.letter-placeholders dd { margin: 0; color: var(--ink-2); }
/* On a phone with larger text the placeholder takes most of the row, so each description goes under its placeholder
   (20em is 320 px at the normal text size, so phones keep the two columns then). */
@media (max-width: 20em) { .letter-placeholders { grid-template-columns: minmax(0, 1fr); row-gap: 0; } .letter-placeholders dd { margin-bottom: var(--space-2); } }
/* Its cards are one form (with the Save bar), as wide as the column it sits in. */
.form.letters-settings { max-width: none; }
/* "Save fee letters" in a bar that stays at the foot of the screen (from edge to edge on a phone), as on New enrolment. */
.sticky-actions.letters-save { justify-content: flex-end; }
.letters-save > .hint { flex: 1 1 12rem; min-width: 0; }
@media (max-width: 47.99em) {
  .sticky-actions.letters-save { margin-inline: calc(-1 * var(--gutter)); border-inline: 0; border-radius: 0; }
  .letters-save > .btn { flex: 1 1 auto; }
}

/* ------------------------------------------------------------------ Redesign stage 8: the error and message pages
   (docs/proposals/redesign-stage-8.md B0 4 and 5, B4, B5, E; frames 8a Page not found, No permission, Could not load and
   the outside messages). The outside card is drawn by the app (ui/messages.js) and, with the same classes, by the server
   for a browser that asks for a page and is refused (app/src/Http/OutsidePage.php, the owner's answers 11 and 12). The
   needs-JavaScript card is the server's own page, restyled here only (answer 13 a). */

/* Meaning tiles: grey (not found), amber (not available, being updated or restored, no access), red (something went wrong,
   needs JavaScript), blue (your sign-in has ended). */
.meaning-tile { display: grid; place-items: center; flex: none; width: 2.75rem; height: 2.75rem; border-radius: var(--radius-lg); background: var(--chip-bg); color: var(--ink-2); }
.meaning-tile .icon { width: 1.375rem; height: 1.375rem; }
.meaning-tile.tone-warning { background: var(--st-need-bg); color: var(--st-need-fg); }
.meaning-tile.tone-danger { background: var(--danger-bg); color: var(--danger-fg); }
.meaning-tile.tone-info { background: var(--sec-home-tint); color: var(--sec-home-icon); }

/* The outside card: white, in the middle of the grey page, as the page's main area; the buttons across its width. It grows
   with the text size. */
.outside { display: grid; place-items: center; min-height: 100vh; min-height: 100dvh; padding: var(--space-6) var(--gutter); background: var(--canvas); }
.outside:focus { outline: none; }
.outside-card { width: 100%; max-width: 22.5rem; padding: var(--space-6); border: 1px solid var(--line); border-radius: var(--radius-xl); background: var(--surface);
  box-shadow: var(--shadow-3); }
.outside-brand { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-5); }
.outside-brand > div { min-width: 0; }
.outside-brand .monogram { width: 2.25rem; height: 2.25rem; border-radius: var(--radius-md); font-size: var(--text-md); }
.outside-brand strong { display: block; font-size: var(--text-sm); line-height: var(--leading-snug); overflow-wrap: break-word; }
.outside-brand small { display: block; color: var(--muted); font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-caps);
  text-transform: uppercase; }
.outside-card h1 { margin-top: var(--space-4); font-size: var(--text-xl); overflow-wrap: break-word; }
.outside-card p { margin-top: var(--space-2); color: var(--ink-2); font-size: var(--text-sm); line-height: var(--leading-relaxed); }
.outside-actions { display: grid; gap: var(--space-2); margin-top: var(--space-5); }

/* Inside a page (8a No permission, Could not load; a fault inside a page): a small solid tile, the first sentence in bold,
   the second under it, and a white "Try again" edged in red. */
.notice.tile-notice { max-width: 45rem; padding: var(--space-4); }
.notice-tile { display: grid; place-items: center; flex: none; width: 2rem; height: 2rem; border-radius: var(--radius-md); background: var(--st-need-solid); color: var(--on-solid); }
.notice-danger .notice-tile { background: var(--st-late-solid); }
.notice .notice-tile .icon { width: var(--icon-sm); height: var(--icon-sm); margin: 0; }
.tile-notice strong { display: block; font-size: var(--text-md); line-height: var(--leading-snug); }
.tile-notice p { margin-top: 2px; }
.tile-notice .btn { margin-top: var(--space-3); }
.btn.btn-outline-danger { border-color: var(--danger-fg); background: var(--surface); color: var(--danger-fg-strong); }
.btn.btn-outline-danger:hover { background: var(--danger-bg); }

/* This app needs JavaScript (the server's own card, inside <noscript>; the style sheet only, answer 13 a): the loading card
   that never ends is hidden, and the card sits at the top in the outside card's look, with a red "code" tile drawn here. */
@media (scripting: none) { #app { display: none; } }
body:has(> noscript .auth) > #app { display: none; }
noscript .auth { display: grid; place-items: start center; min-height: 100vh; min-height: 100dvh;
  padding: var(--space-12) var(--gutter) var(--space-6); background: var(--canvas); }
noscript .auth-card { position: relative; max-width: 22.5rem; padding: var(--space-6); }
noscript .auth-card::before { content: ''; display: block; width: 2.75rem; height: 2.75rem; margin-bottom: var(--space-4); border-radius: var(--radius-lg);
  background: var(--danger-bg); }
noscript .auth-card::after { content: ''; position: absolute; top: calc(var(--space-6) + .6875rem); left: calc(var(--space-6) + .6875rem); width: 1.375rem; height: 1.375rem;
  background: var(--danger-fg);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='16 18 22 12 16 6'/%3E%3Cpolyline points='8 6 2 12 8 18'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='16 18 22 12 16 6'/%3E%3Cpolyline points='8 6 2 12 8 18'/%3E%3C/svg%3E") center / contain no-repeat; }
noscript .auth-card h1 { font-size: var(--text-xl); overflow-wrap: break-word; }
noscript .auth-card .lead { margin-top: var(--space-2); color: var(--ink-2); font-size: var(--text-sm); }

/* ------------------------------------------------------------------ Redesign stage 8: the sign-in pages
   docs/proposals/redesign-stage-8.md B0 to B3, and B5's Choose an organisation (screens/signin.js, twofactor.js,
   choose.js). The sign-in layout: on a computer the Home-blue panel on the left (the badge, the name and "SCHOOL
   DASHBOARD" at the top, the welcome words at the foot, kept in view) and the form in the middle of the white column; on
   phones and tablets a blue header, with the welcome line on the first screens only and a slim bar on the longer steps.
   The welcome line gives way on a short screen or with large text (the media query is in em, so it follows the text
   size), so the form starts on the first screen. No photo (the owner's answer 1 a). */
.signin { --signin-panel: var(--sec-home-solid); min-height: 100vh; min-height: 100dvh; background: var(--surface); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .signin { --signin-panel: color-mix(in oklch, var(--sec-home) 62%, var(--navy-900)); } }
:root[data-theme="dark"] .signin { --signin-panel: color-mix(in oklch, var(--sec-home) 62%, var(--navy-900)); }
.signin-panel { background: var(--signin-panel); color: var(--on-blue); }
.signin-panel-in { padding: var(--space-3) var(--gutter); }
.signin-panel.is-first .signin-panel-in { padding-block: var(--space-4) var(--space-5); }
.signin-brand { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.signin-brand > div { min-width: 0; }
.monogram.signin-badge { width: 2.5rem; height: 2.5rem; border-radius: var(--radius-md); background: var(--on-blue); color: var(--sec-home-solid); }
.signin-brand strong { display: block; font-size: var(--text-md); line-height: var(--leading-snug); overflow-wrap: break-word; }
.signin-brand small { display: block; font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: color-mix(in srgb, var(--on-blue) 85%, var(--signin-panel)); }
.signin-welcome { display: none; }
.signin-panel.is-first .signin-welcome { display: block; margin-top: var(--space-4); }
.signin-welcome-title { font-size: var(--text-xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); overflow-wrap: break-word; }
.signin-welcome-sub { display: none; margin-top: var(--space-2); line-height: var(--leading-normal); }
@media (max-width: 63.99em) and (max-height: 34em) { .signin-panel.is-first .signin-welcome { display: none; } }
.signin-main { padding: var(--space-6) var(--gutter) var(--space-10); }
.signin-form { width: 100%; max-width: 25rem; margin-inline: auto; }
.signin-form.is-wide { max-width: 30rem; }
@media (min-width: 64em) {
  .signin { display: grid; grid-template-columns: minmax(0, 35rem) minmax(0, 1fr); }
  .signin-panel-in { position: sticky; top: 0; display: flex; flex-direction: column; justify-content: space-between; gap: var(--space-8);
    min-height: 100vh; min-height: 100dvh; padding: var(--space-8); }
  .signin-panel.is-first .signin-panel-in { padding: var(--space-8); }
  .signin-panel .signin-welcome, .signin-panel.is-first .signin-welcome { display: block; margin-top: 0; }
  .signin-welcome-title { font-size: var(--text-2xl); }
  .signin-welcome-sub { display: block; }
  .signin-main { display: grid; place-items: center; padding: var(--space-10) var(--space-8); }
}

/* The steps: the title, its line, the grey step line ("Step 1 of 3"), the notices and the forms. */
.signin-form > h1 { overflow-wrap: break-word; }
.signin-lead { margin-top: var(--space-2); color: var(--muted); line-height: var(--leading-relaxed); }
/* The email address breaks after "@" and "." (emailBreaks); a part still wider than a phone breaks where it must, as the
   sign-in page itself would otherwise scroll sideways. */
.signin-lead, .signin-sent { overflow-wrap: break-word; }
.signin-step-line { margin-top: var(--space-1); color: var(--muted); font-size: var(--text-sm); }
.signin-step-line + .signin-lead { margin-top: var(--space-3); }
.signin-message { margin-bottom: var(--space-5); }
.signin-message:empty { display: none; }
.signin-message[role="status"] .notice > div { font-weight: var(--weight-semibold); }   /* "You have signed out." in bold (frame 05) */
.signin-note { margin-top: var(--space-4); }
.signin-sent:not(:empty), .setup-failed:not(:empty) { margin-top: var(--space-4); }
.form.signin-fields { margin-top: var(--space-5); }
.btn.signin-big { min-height: calc(var(--control-h) + var(--space-1)); }
.btn-text.is-flush { padding-inline: 0; }
.btn-text.is-flush:hover { background: none; text-decoration: underline; }
.btn-text.is-quiet { color: var(--muted); }
.signin .field-error, .account-step .field-error { font-weight: var(--weight-semibold); }
/* The grey box under Sign in (frame 02): the "Not arrived?" line, Send a new code and Use a different email. */
.signin-wait { display: grid; justify-items: start; margin-top: var(--space-4); padding: var(--space-3) var(--space-4) var(--space-1); border-radius: var(--radius-md);
  background: var(--canvas); color: var(--muted); font-size: var(--text-sm); line-height: var(--leading-snug); }
.signin-wait .resend { gap: 0; margin-top: 0; }
.signin-links { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); margin-top: var(--space-2); }
/* A link that wraps (larger text on a phone) keeps its words on the left, under each other, as "Sign out" is. */
.signin-links > .btn-text { justify-content: flex-start; text-align: start; }
.signin-foot-links { margin-top: var(--space-4); }
.signin-foot { margin-top: var(--space-5); color: var(--muted); font-size: var(--text-xs); line-height: var(--leading-relaxed); }
.signin-foot-link { color: var(--blue-text); font-weight: var(--weight-semibold); }
/* A step's small tinted tile above its title (B0 3): the phone (authenticator code) or the key (recovery code, set-up). */
.signin-tile { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; margin-bottom: var(--space-4); border-radius: var(--radius-lg);
  background: var(--sec-home-tint); color: var(--sec-home-icon); }
/* The recovery-code box: as tall as the code box, its letters spaced out a little less. */
.input.recovery-input { min-height: 3.375rem; padding-inline: var(--space-4); font-family: var(--font-mono); font-size: var(--text-lg); letter-spacing: .1em; }

/* Set up two-step sign-in (frames 07 and 08), at sign-in and in My account's card: Start (and Turn on two-step sign-in)
   take the room beside Cancel, or the whole width without it; solid numbered circles; the QR code beside its words where
   there is room (on a phone under "Scan this QR code with the app.", as before; always on white, at least 188 pixels);
   the key in a grey chip; the recovery codes in an amber box; the tick in a grey box. */
.setup-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-6); }
.form .setup-actions { margin-top: 0; }
.setup-actions > .signin-big { flex: 1 1 12rem; }
.steps.setup-steps { margin-top: var(--space-5); }
.steps.setup-steps > li::before { width: 26px; height: 26px; background: var(--sec-home-solid); color: var(--on-solid); font-size: var(--text-xs); }
.qr-row { display: grid; gap: var(--space-3); }
.qr-row > .qr { margin-inline: 0; }
@media (min-width: 64em) {
  .signin-form.is-wide .qr-row, .account-step .qr-row { grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto 1fr; align-items: start; column-gap: var(--space-4); }
  .signin-form.is-wide .qr-row > .qr, .account-step .qr-row > .qr { grid-column: 1; grid-row: 1 / span 2; }
  .signin-form.is-wide .qr-row > :not(.qr), .account-step .qr-row > :not(.qr) { grid-column: 2; }
}
.secret.key-chip { width: fit-content; max-width: 100%; padding: var(--space-1) var(--space-2); border: 0; border-radius: var(--radius-sm); background: var(--line-subtle);
  font-size: var(--text-sm); text-align: left; }
.codes.recovery-codes { margin-top: var(--space-5); padding: var(--space-3) var(--space-4); gap: var(--space-2) var(--space-6); border: 1px solid var(--warning-border);
  background: var(--warning-bg); color: var(--warning-fg); text-align: left; }
.recovery-buttons { margin-top: var(--space-3); }
.tick-box .choice { background: var(--canvas); }
.card.account-step { max-width: 44rem; }

/* Choose an organisation (frame 09, the owner's answer 6 c): one row per organisation, one under another, inside the app
   with its menu; the full width on a phone, up to about 720 pixels on a computer. On a narrow row (a phone with larger
   text) the arrow gives its room to the name, which moves under the badge, so no word is split. */
.org-rows { display: grid; gap: var(--space-3); max-width: 45rem; margin: 0; padding: 0; list-style: none; }
.org-rows > li { container-type: inline-size; }
.org-row { display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap); padding: var(--space-3) var(--space-4); border: 1.5px solid var(--line);
  border-radius: var(--radius-lg); background: var(--surface); color: var(--ink); text-decoration: none; }
.org-row:hover { border-color: var(--blue-border); background: var(--surface-hover); }
.org-row .monogram { width: 2.625rem; height: 2.625rem; }
.org-row-text { flex: 1; min-width: 0; }
.org-row-text strong { display: block; font-size: var(--text-md); overflow-wrap: break-word; }
.org-row-text span { display: block; color: var(--muted); font-size: var(--text-xs); overflow-wrap: break-word; }
.org-row > .icon { flex: none; color: var(--muted); }
@container (max-width: 17rem) { .org-row { flex-wrap: wrap; } .org-row-text { flex-basis: 100%; } .org-row > .icon { display: none; } }

/* ------------------------------------------------------------------ Redesign stage 8: the installer
   install.php (the first-time set-up, and its Installed and Already installed pages) in the app's own look: the owner's
   answers 14 and 15. Its security setting allows only styles written inside the page (and no scripts), so install.php
   copies tokens.css and this block, between the two marks below, into its page; nothing else of app.css reaches it. So
   every rule here is scoped to body.installer (the app itself never matches), uses only the tokens, and draws without
   url() (the security setting would block a picture). Dark mode and larger text come from the tokens. */
/* install.php copies from here */
body.installer { margin: 0; min-height: 100vh; min-height: 100dvh; background: var(--canvas); color: var(--ink); font-family: var(--font-sans);
  font-size: var(--text-md); line-height: var(--leading-normal); -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
.installer *, .installer *::before, .installer *::after { box-sizing: border-box; }
.installer :is(h1, h2, h3, p, ol, ul) { margin: 0; }
.installer h1 { font-size: var(--text-2xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); overflow-wrap: break-word; }
.installer h2 { font-size: var(--text-md); font-weight: var(--weight-semibold); line-height: var(--leading-snug); }
.installer .installer-sub { margin-top: var(--space-2); font-size: var(--text-sm); font-weight: var(--weight-semibold); line-height: var(--leading-snug); }
.installer a:not(.installer-btn) { color: var(--blue-text); text-underline-offset: 2px; overflow-wrap: anywhere; }
.installer :is(b, strong) { font-weight: var(--weight-semibold); }
.installer :focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.installer .icon { width: var(--icon); height: var(--icon); flex: none; }
.installer .visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0; }
.installer-main { padding: var(--space-8) var(--gutter) var(--space-12); }
.installer-col, .installer-form { display: grid; gap: var(--space-4); min-width: 0; }
.installer-col { max-width: 47.5rem; margin: 0 auto; }
/* The title with the app's badge (one letter, in the Home blue). */
.installer-head { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.installer-badge { display: grid; place-items: center; flex: none; width: 2.375rem; height: 2.375rem; border-radius: var(--radius-lg); background: var(--sec-home);
  color: var(--on-solid); font-size: var(--text-lg); font-weight: 800; }
/* A numbered section card: the number in a small solid tile (green when the server check passed, red when it did not). */
.installer-card { display: grid; gap: var(--space-4); min-width: 0; padding: var(--space-4) var(--space-5) var(--space-5); border: 1px solid var(--line);
  border-radius: var(--radius-lg); background: var(--surface); }
.installer-card-head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-2) var(--space-3); }
/* 12rem as previewed ("All passed" under the title on a phone), but never wider than the room beside the number, so the
   title stays beside it on a 360 phone at 150% text. */
.installer-titles { flex: 1 1 min(12rem, 100% - 3rem); min-width: 0; padding-top: 3px; }
.installer-titles .hint { margin-top: 2px; }
.installer-num { display: grid; place-items: center; flex: none; min-width: 1.75rem; height: 1.75rem; border-radius: var(--radius-md); background: var(--sec-home-solid);
  color: var(--on-solid); font-size: var(--text-sm); font-weight: var(--weight-bold); }
.installer-num.is-done { background: var(--st-paid-solid); }
.installer-num.is-bad { background: var(--st-late-solid); }
.installer-passed { display: inline-flex; align-items: center; gap: 4px; margin-top: 2px; padding: 3px 9px; border-radius: var(--radius-full); background: var(--st-paid-solid);
  color: var(--on-solid); font-size: var(--text-2xs); font-weight: var(--weight-bold); line-height: 1.4; white-space: nowrap; }
.installer-passed .icon { width: var(--icon-xs); height: var(--icon-xs); }
/* The server check: a tick (or a red mark) on each line, in two columns where there is room. */
.installer-checks { display: grid; gap: var(--space-2) var(--space-6); padding: 0; list-style: none; }
@media (min-width: 48em) { .installer-checks { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.installer-checks li { display: flex; align-items: flex-start; gap: var(--space-2); min-width: 0; font-size: var(--text-sm); line-height: var(--leading-snug); }
.installer-checks li > div { min-width: 0; }
.installer-checks .icon { width: var(--icon-sm); height: var(--icon-sm); margin-top: 2px; color: var(--st-paid-fg); }
.installer-checks small { display: block; margin-top: 1px; color: var(--muted); font-size: var(--text-xs); overflow-wrap: anywhere; }
.installer-checks .is-bad :is(.icon, b) { color: var(--danger-fg); }
/* Notices: the red problem, the green "sent" and "is ready", the amber "already installed"; a small solid tile with its icon. */
.installer-notice { display: flex; align-items: flex-start; gap: var(--space-3); min-width: 0; padding: var(--space-4); border: 1px solid var(--info-border);
  border-radius: var(--radius-lg); background: var(--info-bg); color: var(--info-fg); font-size: var(--text-sm); line-height: var(--leading-relaxed); }
.installer-notice > p { flex: 1; min-width: 0; padding-top: 3px; overflow-wrap: break-word; }
.installer-notice.is-success { border-color: var(--success-border); background: var(--success-bg); color: var(--success-fg); }
.installer-notice.is-warning { border-color: var(--warning-border); background: var(--warning-bg); color: var(--warning-fg); }
.installer-notice.is-danger { border-color: var(--danger-border); background: var(--danger-bg); color: var(--danger-fg-strong); font-weight: var(--weight-semibold); }
.installer-tile { display: grid; place-items: center; flex: none; width: 2rem; height: 2rem; border-radius: var(--radius-md); background: var(--st-upto-solid); color: var(--on-solid); }
.is-success > .installer-tile { background: var(--st-paid-solid); }
.is-warning > .installer-tile { background: var(--st-need-solid); }
.is-danger > .installer-tile { background: var(--st-late-solid); }
.installer-tile .icon { width: var(--icon-sm); height: var(--icon-sm); }
.installer-notice > p.installer-ready { font-size: var(--text-md); line-height: var(--leading-snug); padding-top: 5px; }
/* Fields: the label above its box and the hint under it, as in the app; two or three to a row where there is room. */
.installer-row { display: grid; gap: var(--space-4); min-width: 0; }
@media (min-width: 40em) { .installer-row { grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); } }
.installer .field { display: grid; gap: 6px; min-width: 0; align-content: start; }
.installer :is(.field > label, legend) { font-size: var(--text-sm); font-weight: var(--weight-semibold); line-height: var(--leading-snug); color: var(--ink); }
.installer .hint { color: var(--muted); font-size: var(--text-xs); line-height: var(--leading-relaxed); }
.installer .hint b { overflow-wrap: anywhere; }
.installer :where(input:not([type="radio"], [type="file"], [type="hidden"]), select, textarea) { width: 100%; min-width: 0; min-height: var(--control-h);
  margin: 0; padding: 10px 12px; border: 1px solid var(--border-control); border-radius: var(--radius-sm); background-color: var(--surface); color: var(--ink);
  font: inherit; font-size: var(--text-md); line-height: 1.3; }
.installer :where(input:not([type="radio"], [type="file"]), select, textarea):hover { border-color: var(--ink-2); }
.installer :where(input:not([type="radio"], [type="file"]), select, textarea):focus { outline: none; border-color: var(--focus);
  box-shadow: 0 0 0 var(--focus-width) color-mix(in srgb, var(--focus) 35%, transparent); }
.installer input::-webkit-calendar-picker-indicator { padding: 4px; border-radius: var(--radius-xs); cursor: pointer; }
/* "How to send" and the other choices stay drop-downs; the arrow is drawn with two gradients (no picture). */
.installer select { appearance: none; -webkit-appearance: none; padding-right: 40px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%; background-size: 5px 5px; background-repeat: no-repeat; }
.installer input[type="file"] { width: 100%; min-width: 0; min-height: var(--tap); color: var(--ink-2); font: inherit; font-size: var(--text-sm); }
.installer input[type="file"]::file-selector-button { min-height: var(--control-h); margin-right: var(--space-3); padding: 10px var(--space-4);
  border: 1px solid var(--border-control); border-radius: var(--radius-md); background: var(--surface); color: var(--ink); font: inherit;
  font-weight: var(--weight-semibold); cursor: pointer; }
.installer textarea { min-height: 16rem; font-family: var(--font-mono); font-size: var(--text-xs); resize: vertical; }
/* "What is this copy?": two choices with their round buttons, each a full-height row to tap. */
.installer-choices { display: grid; gap: 2px; min-width: 0; margin: 0; padding: 0; border: 0; }
.installer-choices legend { margin-bottom: 6px; padding: 0; }
.installer-choice { display: flex; align-items: flex-start; gap: var(--space-3); min-height: var(--tap); padding: 10px var(--space-3); border-radius: var(--radius-md);
  line-height: var(--leading-snug); cursor: pointer; }
.installer-choice:hover { background: var(--surface-2); }
.installer-choice input { flex: none; width: 20px; height: 20px; margin: 1px 0 0; accent-color: var(--blue-600); cursor: pointer; }
.installer-choice span { min-width: 0; }
/* Buttons: Install and Go to sign in in the Home blue, "Send a test email to me" white with a border. */
.installer-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); min-height: var(--control-h); min-width: var(--tap);
  padding: 10px var(--space-4); border: 1px solid transparent; border-radius: var(--radius-md); background: var(--sec-home-solid); color: var(--on-solid);
  font: inherit; font-size: var(--text-sm); font-weight: var(--weight-semibold); line-height: 1.2; text-align: center; text-decoration: none; cursor: pointer; }
.installer-btn:hover { background: color-mix(in oklch, var(--sec-home-solid) 88%, black); }
.installer-btn.is-secondary { border-color: var(--border-control); background: var(--surface); color: var(--ink); }
.installer-btn.is-secondary:hover { border-color: var(--ink-2); background: var(--surface-2); }
.installer-btn.is-big { min-height: calc(var(--control-h) + var(--space-1)); padding-inline: var(--space-5); }
.installer-btn .icon { width: var(--icon-sm); height: var(--icon-sm); }
/* "Restoring from an earlier copy?", folded away until opened (it works without scripts). */
.installer-restore { min-width: 0; border: 1px dashed var(--border-soft); border-radius: var(--radius-lg); background: var(--surface); }
.installer-restore > summary { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: var(--tap);
  padding: var(--space-3) var(--space-5); border-radius: var(--radius-lg); cursor: pointer; list-style: none; }
.installer-restore > summary::-webkit-details-marker { display: none; }
.installer-restore > summary > span { min-width: 0; }
.installer-restore > summary strong { display: block; line-height: var(--leading-snug); }
.installer-restore > summary small { display: block; margin-top: 2px; color: var(--muted); font-size: var(--text-xs); line-height: var(--leading-snug); }
.installer-restore > summary .icon { color: var(--muted); }
.installer-restore[open] > summary .icon { transform: rotate(180deg); }
.installer-restore-body { display: grid; gap: var(--space-4); padding: 0 var(--space-5) var(--space-5); }
/* Installed: today's two lines (config.php, private files) with a tick or a red mark, then the next steps, numbered. */
.installer-lines { gap: var(--space-3); }
.installer-line { display: flex; align-items: flex-start; gap: var(--space-2); color: var(--success-fg); overflow-wrap: break-word; }
.installer-line.is-bad { color: var(--danger-fg); font-weight: var(--weight-semibold); }
.installer-line .icon { width: var(--icon-sm); height: var(--icon-sm); margin-top: 4px; }
.installer-line > span { min-width: 0; }
.installer-next { display: grid; gap: var(--space-3); padding: 0; list-style: none; counter-reset: installer-next; }
.installer-next > li { display: flex; align-items: flex-start; gap: var(--space-3); line-height: var(--leading-relaxed); counter-increment: installer-next; }
.installer-next > li::before { content: counter(installer-next); display: grid; place-items: center; flex: none; width: 1.75rem; height: 1.75rem;
  border-radius: var(--radius-md); background: var(--sec-home-tint); color: var(--sec-home-text); font-size: var(--text-sm); font-weight: var(--weight-bold); }
.installer-next > li > span { min-width: 0; padding-top: 1px; }
@media (prefers-reduced-motion: no-preference) { .installer-restore > summary .icon { transition: transform var(--dur-fast) var(--ease); } }
/* install.php copies to here */
