/* ==========================================================================
   Mijn Accountant — klantportaal stylesheet
   --------------------------------------------------------------------------
   Ported from the Mijn Accountant design system (Claude Design bundle,
   project 10ab5d19). Section 1 is the token layer, copied verbatim from
   `tokens/*.css` so it can be diffed against the source; everything after it
   is this app's own component layer, built only out of those tokens.

   Rules worth keeping in mind while editing:
     - Forest is structure, orange is the single accent. One orange element
       per viewport; never an orange heading, never an orange wash.
     - Nothing is square: 8px inputs and tags, 12px cards, pill buttons.
     - Borders are structural. Never coloured, never an accent, never a
       coloured left edge on a card.
     - No gradients, no blur, no frosted glass, no scroll animation.
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

/* Figtree stands in for the unidentified grotesk on the brand site — see the
   design system readme, "Font substitution". Self-hosted so the portal has no
   render-time dependency on Google Fonts. */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("/assets/fonts/figtree-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("/assets/fonts/figtree-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ---- Base palette: Forest (brand primary) ---- */
  --forest-900: #162924;
  --forest-800: #1c332d;
  --forest-700: #223b35; /* canonical brand green */
  --forest-600: #2a483f;
  --forest-500: #32554b;
  --forest-400: #4a6d63;
  --forest-300: #7b968e;
  --forest-200: #b3c4bf;
  --forest-100: #dde5e2;
  --forest-050: #eef2f1;

  /* ---- Base palette: Signal (accent) ---- */
  --signal-700: #c22c11;
  --signal-600: #e03518;
  --signal-500: #f93e1d; /* canonical accent */
  --signal-400: #fb6749;
  --signal-200: #fdc4b7;
  --signal-050: #fef0ec;

  /* ---- Base palette: Neutral ---- */
  --neutral-000: #ffffff;
  --neutral-025: #f9f9fa;
  --neutral-050: #f2f4f3;
  --neutral-100: #e4e8e6;
  --neutral-200: #cdd4d1;
  --neutral-400: #8e9a96;
  --neutral-600: #5a6b65;
  --neutral-800: #33413c;
  --neutral-900: #162924;

  /* ---- Semantic: surfaces ---- */
  --surface-page: var(--neutral-025);
  --surface-card: var(--neutral-000);
  --surface-inset: var(--neutral-050);
  --surface-dark: var(--forest-700);
  --surface-dark-raised: var(--forest-600);
  --surface-utility: var(--forest-500);
  --surface-accent: var(--signal-500);

  /* ---- Semantic: text ---- */
  --text-heading: var(--forest-700);
  --text-body: var(--neutral-800);
  --text-muted: var(--neutral-600);
  --text-eyebrow: var(--neutral-600);
  --text-link: var(--signal-500);
  --text-on-dark: var(--neutral-025);
  --text-on-dark-muted: #c7cfcc;
  --text-eyebrow-on-dark: #c7cfcc;
  --text-on-accent: var(--neutral-000);

  /* ---- Semantic: lines & focus ---- */
  --border-hairline: var(--neutral-100);
  --border-strong: var(--neutral-200);
  --border-on-dark: rgba(249, 249, 250, .22);
  --focus-ring: var(--signal-500);

  /* ---- Semantic: status ---- */
  --status-success: #2f7d5b;
  --status-warning: #c98a12;
  --status-error: var(--signal-600);
  --status-info: var(--forest-500);
  --status-success-bg: #e8f3ee;
  --status-warning-bg: #fbf3e2;
  --status-error-bg: var(--signal-050);
  --status-info-bg: var(--forest-050);

  /* ---- Typography ---- */
  --font-sans: "Figtree", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-core: var(--font-sans);
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  --fs-display-2: 48px; --lh-display-2: 1.1;  --ls-display-2: -.022em;
  --fs-h1: 40px;        --lh-h1: 1.15;        --ls-h1: -.02em;
  --fs-h2: 32px;        --lh-h2: 1.2;         --ls-h2: -.018em;
  --fs-h3: 22px;        --lh-h3: 1.3;         --ls-h3: -.012em;
  --fs-h4: 18px;        --lh-h4: 1.35;        --ls-h4: -.008em;

  --fs-body-lg: 19px;   --lh-body-lg: 1.65;
  --fs-body: 17px;      --lh-body: 1.65;
  --fs-body-sm: 15px;   --lh-body-sm: 1.6;
  --fs-caption: 13px;   --lh-caption: 1.5;

  --fs-eyebrow: 13px;   --lh-eyebrow: 1.2;    --ls-eyebrow: .14em;

  --fs-label: 15px;
  --fs-button: 16px;    --ls-button: -.005em;
  --fs-nav: 16px;

  /* ---- Spacing ---- */
  --space-1: 4px;   --space-2: 8px;   --space-3: 12px;  --space-4: 16px;
  --space-5: 20px;  --space-6: 24px;  --space-8: 32px;  --space-10: 40px;
  --space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
  --stack-tight: 12px;
  --stack: 24px;
  --stack-loose: 40px;
  --grid-gap: 24px;

  /* ---- Radii ---- */
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 999px;

  /* ---- Elevation ---- */
  --shadow-none: none;
  --shadow-card: 0 1px 2px rgba(22, 41, 36, .04), 0 1px 3px rgba(22, 41, 36, .03);
  --shadow-card-hover: 0 8px 24px rgba(22, 41, 36, .09), 0 2px 6px rgba(22, 41, 36, .04);
  --shadow-panel: 0 16px 48px rgba(22, 41, 36, .14);
  --shadow-sticky: 0 1px 0 rgba(22, 41, 36, .08);

  /* ---- Motion ---- */
  --ease-standard: cubic-bezier(.2, .6, .2, 1);
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --duration-slow: 420ms;
  --transition-hover:
    background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard),
    border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-base) var(--ease-standard),
    transform var(--duration-base) var(--ease-standard);

  /* ---- Layout ---- */
  --container: 1180px;
  --container-narrow: 440px;
  --gutter: 32px;
  --gutter-sm: 20px;
  --portalbar-h: 68px;
  --icon-capsule: 48px;
  --z-dropdown: 200;
}

/* Dark mode remaps the semantic aliases only — the base palette never moves,
   and no view reads a theme flag. Built from the brand's own greens rather
   than a neutral slate, so the portal still reads as Mijn Accountant. */
[data-theme="dark"] {
  --surface-page: var(--forest-900);
  --surface-card: var(--forest-800);
  --surface-inset: var(--forest-700);
  --surface-dark: var(--forest-800);
  --surface-dark-raised: var(--forest-700);
  --surface-utility: var(--forest-700);

  --text-heading: var(--neutral-025);
  --text-body: #dde5e2;
  --text-muted: #a2b5ae;
  --text-eyebrow: #a2b5ae;
  --text-link: var(--signal-400);
  --text-on-dark: var(--neutral-025);
  --text-on-dark-muted: #a2b5ae;

  --border-hairline: rgba(249, 249, 250, .12);
  --border-strong: rgba(249, 249, 250, .26);
  --border-on-dark: rgba(249, 249, 250, .16);

  --shadow-card: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-card-hover: 0 10px 28px rgba(0, 0, 0, .45);
  --shadow-panel: 0 20px 56px rgba(0, 0, 0, .55);
  --shadow-sticky: 0 1px 0 rgba(249, 249, 250, .10);

  --status-success: #7fc3a3;
  --status-warning: #e0b45c;
  --status-error: var(--signal-400);
  --status-info: var(--forest-200);
  --status-success-bg: rgba(47, 125, 91, .18);
  --status-warning-bg: rgba(201, 138, 18, .18);
  --status-error-bg: rgba(224, 53, 24, .18);
  --status-info-bg: rgba(50, 85, 75, .4);
}

/* ==========================================================================
   2. ELEMENT DEFAULTS
   ========================================================================== */

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

/* The `hidden` attribute has to beat the component layer. Plenty of things here
   set `display` on a class (pills, rows, the theme switch), and an author
   `display` outranks the browser's own `[hidden] { display: none }` — so without
   this, hiding an element from script or markup silently does nothing. */
[hidden] { display: none !important }

html { color-scheme: light }
[data-theme="dark"] { color-scheme: dark }

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-core);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
}

h1, h2, h3, h4 {
  margin: 0;
  color: var(--text-heading);
  font-weight: var(--fw-semibold);
}
h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: var(--ls-h1) }
h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2) }
h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--ls-h3) }
h4 { font-size: var(--fs-h4); line-height: var(--lh-h4); letter-spacing: var(--ls-h4) }
p { margin: 0 }

/* Prose links carry an underline for legibility in dense admin copy, and turn
   orange on hover the way the brand's TextLink does. Anything that is really a
   control — nav item, card, pill — opts out below. */
a {
  color: var(--text-heading);
  font-weight: var(--fw-medium);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 2px;
  transition: var(--transition-hover);
}
a:hover { color: var(--text-link); text-decoration-color: currentColor }

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

/* One 24px-grid outline glyph, inheriting currentColor from its container. */
svg.i { display: inline-block; flex: 0 0 auto; vertical-align: -.16em }

/* Motion is a courtesy, never a requirement. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important }
}

/* ==========================================================================
   3. PAGE SHELL
   ========================================================================== */

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: var(--space-16) var(--gutter) var(--space-24);
}
.wrap.narrow { max-width: var(--container-narrow) }
/* `.narrow` is also used as an inner block on the auth pages. */
.narrow { max-width: var(--container-narrow) }

/* ---- Portal top bar. Forest in both themes: the one constant brand surface. */
header.top {
  background: var(--forest-700);
  border-bottom: 1px solid rgba(249, 249, 250, .12);
}
header.top .wrap {
  max-width: var(--container);
  padding: 0 var(--gutter);
  height: var(--portalbar-h);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
header.top .brand {
  display: inline-flex;
  align-items: center;
  margin-right: var(--space-6);
  text-decoration: none;
  font-weight: var(--fw-regular);
}
header.top .brand img { height: 26px; width: auto; display: block }
/* The brand's double-slash device. Hidden while the wordmark is on show; on a
   narrow bar it replaces the wordmark and reads as the icon of the nav item
   next to it. */
header.top .brand .slash {
  display: none;
  color: var(--text-on-dark);
  font-size: 20px;
  font-weight: var(--fw-bold);
  letter-spacing: -.06em;
  line-height: 1;
}

/* Nav items are pills, not underlined links. */
header.top nav { display: flex; align-items: center; gap: var(--space-1) }
header.top nav a,
header.top nav summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 8px 14px;
  border-radius: var(--radius-pill);
  color: rgba(249, 249, 250, .7);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  white-space: nowrap;
}
header.top nav a:hover,
header.top nav summary:hover { color: var(--text-on-dark); background: rgba(249, 249, 250, .10) }
header.top nav [aria-current="page"] {
  color: var(--text-on-dark);
  background: rgba(249, 249, 250, .10);
}
header.top .spacer { flex: 1 }
header.top .who { color: var(--text-on-dark-muted); font-size: var(--fs-caption) }

/* ---- Bar dropdowns. Each is a <details>, so the bar works with no JS at all —
   the script in the layout only adds closing one by clicking elsewhere, closing
   the others when one opens, and Escape. */
details.menuwrap { position: relative }
details.menuwrap > summary { list-style: none; cursor: pointer; transition: var(--transition-hover) }
details.menuwrap > summary::-webkit-details-marker { display: none }
details.menuwrap > summary .chev { color: rgba(249, 249, 250, .7) }
details.menuwrap[open] > summary .chev { transform: rotate(180deg) }

details.acct > summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 6px 12px 6px 6px;
  border: 1px solid var(--border-on-dark);
  border-radius: var(--radius-pill);
  color: var(--text-on-dark);
  font-size: 14px;
  font-weight: var(--fw-medium);
}
details.acct > summary:hover,
details.acct[open] > summary {
  background: rgba(249, 249, 250, .10);
  border-color: rgba(249, 249, 250, .42);
}
details.acct > summary .mono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border-radius: var(--radius-pill);
  background: var(--signal-500);
  color: var(--text-on-accent);
  font-size: 12px;
  font-weight: var(--fw-bold);
  letter-spacing: 0;
}

details.menuwrap .menu {
  position: absolute;
  top: calc(100% + 10px);
  min-width: 250px;
  z-index: var(--z-dropdown);
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
}
details.acct .menu { right: 0 }
details.adminnav .menu { left: 0; min-width: 200px }
details.menuwrap .menu .who {
  display: block;
  padding: var(--space-3) var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-hairline);
  color: var(--text-muted);
  font-size: var(--fs-caption);
  word-break: break-all;
}
details.menuwrap .menu .who strong {
  display: block;
  margin-bottom: 2px;
  color: var(--text-heading);
  font-size: 14px;
  font-weight: var(--fw-semibold);
}
details.menuwrap .menu a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 9px var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-body);
  font-size: 14px;
  font-weight: var(--fw-medium);
  text-decoration: none;
}
details.menuwrap .menu a:hover { background: var(--surface-inset); color: var(--text-heading) }
details.menuwrap .menu a.out { color: var(--text-link); font-weight: var(--fw-semibold) }
details.menuwrap .menu a.out:hover { background: var(--status-error-bg); color: var(--text-link) }

/* ---- Theme and language switches. Both sit in the account menu, under the
   identity block, as labelled rows — the same shape as every other setting a
   person changes about their own account. Both places they appear are light
   surfaces. */
.menu .themerow,
.menu .langrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-3);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-hairline);
}
.menu .themerow .lbl,
.menu .langrow .lbl {
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
}
.themeswitch,
.langswitch {
  display: inline-flex;
  margin: 0;
  padding: 3px;
  gap: 2px;
  background: var(--surface-inset);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-pill);
}
.themeswitch button,
.langswitch button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: auto;
  height: 28px;
  margin: 0;
  padding: 0 10px;
  border: none;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-core);
  font-size: 13px;
  font-weight: var(--fw-medium);
  letter-spacing: 0;
  cursor: pointer;
}
.themeswitch button:hover,
.langswitch button:hover { background: transparent; color: var(--text-heading) }
.themeswitch button[aria-pressed="true"],
.langswitch button[aria-pressed="true"] {
  background: var(--surface-card);
  color: var(--text-heading);
  box-shadow: var(--shadow-card);
}
/* With no JS the switch never appears, so the label above it would be a lie. */
.menu .themerow:has(.themeswitch[hidden]) { display: none }

/* ==========================================================================
   4. PAGE HEADINGS
   ========================================================================== */

/* The section rhythm is fixed: 12px eyebrow to heading, 24px heading to body. */
.eyebrow {
  color: var(--text-eyebrow);
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  margin-bottom: var(--stack-tight);
}
h2 {
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  margin: var(--space-12) 0 var(--space-5);
}
p.sub {
  margin: var(--space-3) 0 var(--space-10);
  max-width: 68ch;
  color: var(--text-muted);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}
/* The facts strip under a page's h1: badges plus a few plain figures, in the same
   vocabulary the list rows use so a row and its detail screen read alike. */
p.pagefacts {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-4);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
}
p.pagefacts .sep { color: var(--border-strong) }
p.pagefacts + p.sub { margin-top: var(--space-4) }

.crumb {
  margin-bottom: var(--space-4);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
}
.crumb a { color: var(--text-muted); font-weight: var(--fw-medium) }
/* A crumb that is a way back rather than a trail: the glyph sits on the text
   baseline and the whole thing reads as one link. */
.crumb a { display: inline-flex; align-items: center; gap: var(--space-2) }
.hint {
  margin-top: var(--space-6);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
}
.right { text-align: right }

/* ==========================================================================
   5. CARDS
   ========================================================================== */

.card {
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-8);
  margin-bottom: var(--space-4);
  transition: var(--transition-hover);
}
/* Cards lift 2px on hover and deepen their shadow. Border and radius never
   change, and a card is never given a coloured edge. */
.card.link {
  display: block;
  text-decoration: none;
}
.card.link:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-card-hover);
  transform: translateY(-2px);
}
.card h3 {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin: 0 0 var(--space-2);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  letter-spacing: var(--ls-h4);
}
.card .meta { color: var(--text-muted); font-size: var(--fs-body-sm) }
.card .meta a { font-size: inherit }
.card > p:not(.meta):not(.hint) + label { margin-top: var(--space-6) }
.card.danger-zone { border-color: var(--status-error) }

/* The "Openen" affordance on a linked card: arrow nudges 3px right on hover. */
.card.link .go {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  color: var(--text-heading);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
}
.card.link:hover .go { color: var(--text-link) }

/* 48px inset capsule holding a 20px glyph — the design system's icon capsule. */
.capsule {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-capsule);
  height: var(--icon-capsule);
  flex: 0 0 auto;
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  color: var(--text-heading);
}
.capsule.alarm { background: var(--status-error-bg); color: var(--status-error) }
.capsule.warn { background: var(--status-warning-bg); color: var(--status-warning) }

/* ---- Site row. A linked card laid out as monogram / detail / affordance, the
   shape the design system's site switcher uses in place of bare cards. */
.card.link.siterow {
  display: grid;
  grid-template-columns: var(--icon-capsule) minmax(0, 1fr) auto;
  gap: var(--space-5);
  align-items: center;
  padding: var(--space-6);
}
.siterow .capsule {
  font-size: 16px;
  font-weight: var(--fw-bold);
  letter-spacing: -.02em;
}
.siterow .body { display: flex; flex-direction: column; gap: 6px; min-width: 0 }
.siterow .title { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap }
.siterow .name {
  color: var(--text-heading);
  font-size: var(--fs-h4);
  letter-spacing: var(--ls-h4);
  font-weight: var(--fw-semibold);
}
.siterow .go { margin-top: 0 }

@media (max-width: 720px) {
  .card.link.siterow { grid-template-columns: var(--icon-capsule) minmax(0, 1fr) }
  .siterow .go { grid-column: 2 }
}

/* ---- Linked row. A whole row that navigates, with one control inside it that
   goes somewhere else. The row cannot be an <a> (it contains a link of its own),
   so the title's anchor is stretched over the row instead and the control is
   lifted above it. */
.card.link.rowlink {
  position: relative;
  display: grid;
  grid-template-columns: var(--icon-capsule) minmax(0, 1fr) auto;
  gap: var(--space-5);
  align-items: center;
  padding: var(--space-5) var(--space-6);
}
.rowlink .body { display: flex; flex-direction: column; gap: 6px; min-width: 0 }
.rowlink .title { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap }
.rowlink .title a.stretch {
  color: var(--text-heading);
  font-size: var(--fs-h4);
  letter-spacing: var(--ls-h4);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}
.rowlink .title a.stretch::after { content: ""; position: absolute; inset: 0 }
.rowlink:hover .title a.stretch { color: var(--text-link) }
.rowlink .facts {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.rowlink .facts .sep { color: var(--border-strong) }
/* Above the stretched anchor, so it stays clickable in its own right. */
.rowlink > .btnlink, .rowlink .facts .tag { position: relative }

@media (max-width: 720px) {
  .card.link.rowlink { grid-template-columns: var(--icon-capsule) minmax(0, 1fr) }
  .rowlink > .btnlink { grid-column: 2; justify-self: start }
  /* Wrapped onto several lines the dots stop separating anything and just dangle
     at the end of a row; the gap does the work instead. */
  .rowlink .facts .sep, p.pagefacts .sep { display: none }
}

/* ---- Search over a list. A real GET form, so it works with no JS; the script
   in the layout narrows the list as you type and hides the submit button. */
.searchbox {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-5);
}
.searchbox .field {
  position: relative;
  display: flex;
  align-items: center;
  flex: 0 1 360px;
}
.searchbox .field > svg {
  position: absolute;
  left: var(--space-4);
  color: var(--text-muted);
  pointer-events: none;
}
.searchbox input[type=search] {
  width: 100%;
  padding-left: calc(var(--space-4) * 2 + 16px);
  /* The browser's own clear affordance, which no design system token covers. */
  appearance: none;
}
.searchbox input[type=search]::-webkit-search-cancel-button {
  appearance: none;
  width: 14px;
  height: 14px;
  cursor: pointer;
  background: currentColor;
  opacity: .45;
  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.5' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center / contain no-repeat;
}
.searchbox input[type=search]::-webkit-search-cancel-button:hover { opacity: .8 }

[data-search-list] > [data-search-empty] { margin: var(--space-6) 0 }

@media (max-width: 720px) {
  .searchbox .field { flex: 1 1 auto }
}

/* ==========================================================================
   5b. ACCORDIONS
   The brand's own disclosure pattern: an inset panel, the question in semibold
   forest, and the chevron in a white capsule on the right. Used for anything a
   page offers but does not lead with — creating a thing, or destroying one.
   ========================================================================== */

details.accordion {
  background: var(--surface-inset);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-3);
  overflow: hidden;
  transition: var(--transition-hover);
}
details.accordion > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  color: var(--text-heading);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  letter-spacing: var(--ls-h4);
  font-weight: var(--fw-semibold);
}
details.accordion > summary::-webkit-details-marker { display: none }
details.accordion > summary:hover { color: var(--text-link) }
details.accordion > summary .mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  margin-left: auto;
  border-radius: var(--radius-pill);
  background: var(--surface-card);
  color: var(--text-link);
  box-shadow: var(--shadow-card);
}
details.accordion[open] > summary .mark { transform: rotate(180deg) }
/* An "add" panel opens and stays open — a plus that never turns, and a heading that
   stops offering itself once there is a form under it to fill in. */
details.accordion.add[open] > summary { cursor: default }
details.accordion.add[open] > summary:hover { color: var(--text-heading) }
details.accordion.add[open] > summary .mark { transform: none }
details.accordion > .panel {
  padding: 0 var(--space-6) var(--space-6);
  /* 420ms is the design system's panel-reveal step. Height cannot be animated on
     a <details>, so the content fades and settles instead. */
  animation: panel-in var(--duration-slow) var(--ease-standard) both;
}
details.accordion > .panel > *:first-child { margin-top: 0 }
details.accordion > .panel > label:first-child { margin-top: 0 }
@keyframes panel-in {
  from { opacity: 0; transform: translateY(-4px) }
  to { opacity: 1; transform: none }
}
@media (prefers-reduced-motion: reduce) {
  details.accordion > .panel { animation: none }
}
/* A destructive accordion says so before it is opened. */
details.accordion.danger-zone { background: var(--status-error-bg) }
details.accordion.danger-zone > summary { color: var(--status-error) }
details.accordion.danger-zone > summary .mark { color: var(--status-error) }

/* ==========================================================================
   6. FORMS
   ========================================================================== */

label {
  display: block;
  margin: var(--space-5) 0 var(--space-2);
  color: var(--text-heading);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
}
.card > label:first-child,
form > label:first-child { margin-top: 0 }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=url], input[type=search], input[type=tel], input[type=file], textarea, select {
  width: 100%;
  padding: 13px var(--space-4);
  font-family: var(--font-core);
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text-body);
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  outline: none;
  transition: var(--transition-hover);
}
textarea { line-height: 1.6; resize: vertical }
select {
  appearance: none;
  padding-right: var(--space-10);
  /* A chevron drawn as a background is the one exception to "icons come from
     the sprite": a <select> cannot hold child markup. Same Lucide geometry. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a6b65' 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 var(--space-4) center;
  background-size: 16px 16px;
}
[data-theme="dark"] select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a2b5ae' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
input[type=file] { padding: 9px var(--space-3); font-size: var(--fs-body-sm) }
input[type=file]::file-selector-button {
  margin-right: var(--space-4);
  padding: 7px 16px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-heading);
  font-family: var(--font-core);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
  cursor: pointer;
}
input[type=file]::file-selector-button:hover { background: var(--surface-inset) }

::placeholder { color: var(--neutral-400) }

/* Focus: orange 1px border plus a 3px soft halo. */
input:focus, textarea:focus, select:focus {
  border-color: var(--focus-ring);
  box-shadow: 0 0 0 3px var(--status-error-bg);
}
input:disabled, textarea:disabled, select:disabled { opacity: .5 }

label.check {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  color: var(--text-body);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-regular);
  cursor: pointer;
}
label.check input { width: auto; accent-color: var(--signal-500) }

/* A set of radios is one field, not three: the legend is its label, and the options
   stack under it more tightly than lone checkboxes do. */
fieldset.radios {
  margin: var(--space-5) 0 0;
  padding: 0;
  border: 0;
}
fieldset.radios > legend {
  padding: 0;
  color: var(--text-heading);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
}
fieldset.radios label.check { margin-top: var(--space-3) }

/* The one-time-code field: wide tracking, centred, mono. */
input.otp {
  font-family: var(--font-mono);
  font-size: 20px;
  letter-spacing: .32em;
  text-align: center;
}

/* ==========================================================================
   7. BUTTONS
   Every button is a pill, in three weights:

     button           solid forest — the ordinary "commit this form" action
     button.primary   orange — AT MOST ONE PER PAGE, the move the page is for
     button.ghost /
     button.sm /
     a.btnlink        outline — everything secondary, including row actions

   The orange is rationed on purpose: one accent element per viewport is a
   brand rule, so a screen with three forms on it does not get three orange
   bars. Destructive actions are outlines in the error colour, which is what
   the design system's own account screen does.
   ========================================================================== */

button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding: 14px 26px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  font-family: var(--font-core);
  font-size: var(--fs-button);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-button);
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  transition: var(--transition-hover);
}
button:hover { background: var(--surface-dark-raised) }
button:active { transform: translateY(1px) }
button:disabled { opacity: .45; cursor: not-allowed; transform: none }
[data-theme="dark"] button { background: var(--forest-600) }
[data-theme="dark"] button:hover { background: var(--forest-500) }

button.primary { background: var(--surface-accent); color: var(--text-on-accent) }
button.primary:hover { background: var(--signal-600) }

/* Publishing something new is the one action the brand's own green marks. */
button.success { background: var(--status-success); color: var(--neutral-000) }
button.success:hover { background: #27664a }
[data-theme="dark"] button.success { background: var(--status-success); color: var(--forest-900) }
[data-theme="dark"] button.success:hover { background: #96d0b5 }

/* Secondary — an outline, used for anything that is not the page's main move. */
button.ghost, button.sm, a.btnlink {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: auto;
  margin: 0;
  padding: 9px 18px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-heading);
  font-family: var(--font-core);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: var(--transition-hover);
}
button.ghost:hover, button.sm:hover, a.btnlink:hover {
  background: var(--surface-inset);
  border-color: var(--text-heading);
  color: var(--text-heading);
}

/* A glyph inside a control never moves and never animates: only the surface
   under it changes on hover. An icon that slides on hover reads as a jump when
   the pointer crosses a row of them. */
button > svg, a.btnlink > svg, .themeswitch svg, header.top svg {
  transition: none;
  transform: none;
}

/* Destructive. An outline in the error colour, so a page full of forms is not a
   page full of filled warnings — and orange stays the accent, not the alarm.
   The error colour is the brand's own orange family; no foreign red is used. */
button.danger, button.sm.danger {
  background: transparent;
  border-color: var(--status-error);
  color: var(--status-error);
}
button.danger:hover, button.sm.danger:hover {
  background: var(--status-error-bg);
  border-color: var(--status-error);
  color: var(--status-error);
}

/* The auth screens are the one place a primary button spans its column, the way
   the design system's login kit has it. */
.auth-form form button { display: flex; width: 100% }

.bar { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap }
.bar.right { justify-content: flex-end }
form.inline { display: inline; margin: 0 }
td .bar { margin: 0; flex-wrap: nowrap; white-space: nowrap }

/* ==========================================================================
   8. NOTICES AND BADGES
   ========================================================================== */

.err, .ok {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-sm);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
}
.err { background: var(--status-error-bg); color: var(--text-heading) }
.ok { background: var(--status-success-bg); color: var(--text-heading) }
.err a, .ok a { color: var(--text-heading); font-weight: var(--fw-semibold) }
.err a:hover, .ok a:hover { color: var(--text-link) }
.err > svg:first-child { color: var(--status-error); margin-top: 3px }
.ok > svg:first-child { color: var(--status-success); margin-top: 3px }

/* Small pill for a status, level or flag. Never larger than 12px. */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--fw-semibold);
  line-height: 1.4;
  letter-spacing: .01em;
  white-space: nowrap;
  vertical-align: 1px;
}
.tag.live, .tag.on {
  background: var(--status-success-bg);
  border-color: transparent;
  color: var(--status-success);
}
.tag.proxy, .tag.admin {
  background: var(--status-info-bg);
  border-color: transparent;
  color: var(--status-info);
}
.tag.off {
  background: var(--status-warning-bg);
  border-color: transparent;
  color: var(--status-warning);
}
.tag.owner {
  background: var(--status-error-bg);
  border-color: transparent;
  color: var(--status-error);
}
.tag.mono { font-family: var(--font-mono); letter-spacing: 0 }

/* ==========================================================================
   9. TABLES
   ========================================================================== */

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body-sm);
}
th, td {
  text-align: left;
  padding: var(--space-3) var(--space-3);
  border-bottom: 1px solid var(--border-hairline);
  vertical-align: middle;
}
th {
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}
tbody tr:last-child td { border-bottom: none }
tbody tr:hover td { background: var(--surface-inset) }
td strong { color: var(--text-heading); font-weight: var(--fw-semibold) }
table th[scope], table tr > th:first-child { white-space: nowrap }
/* A wide table scrolls inside its own box rather than widening the page. */
.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch }

/* A table inside a card reaches the card's edges rather than sitting in a box
   inside a box. Anything after it gets its spacing back. */
.card > table,
.card > .tablewrap { margin: calc(var(--space-8) * -1) calc(var(--space-8) * -1) 0 }
.card > table th:first-child, .card > table td:first-child,
.card > .tablewrap th:first-child, .card > .tablewrap td:first-child { padding-left: var(--space-8) }
.card > table th:last-child, .card > table td:last-child,
.card > .tablewrap th:last-child, .card > .tablewrap td:last-child { padding-right: var(--space-8) }
.card > table + *, .card > .tablewrap + * { margin-top: var(--space-6) }
/* A table is the last thing in most cards, so its final hairline would double up
   with the card's own border. */
.card > table tr:last-child td, .card > table tr:last-child th,
.card > .tablewrap tr:last-child td, .card > .tablewrap tr:last-child th { border-bottom: none }

/* ---- The user list. A table of accounts is read down one column at a time —
   who is this, who has no second factor, who is a site holding up — so it is
   built as a grid whose columns line up across every row, rather than as a
   <table> whose cells each grow to fit their own contents. The headings sort,
   the row's own controls sit at the right, and everything a second factor needs
   is behind one control instead of spread over three columns. */

.filters {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin: var(--space-8) 0 var(--space-4);
}
.filters .field { position: relative; flex: 1 1 280px; min-width: 220px }
.filters .field > svg {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--neutral-400);
  pointer-events: none;
}
.filters input[type=search] { margin: 0; padding-left: 40px }
.filters select {
  width: auto;
  margin: 0;
  padding: 10px 34px 10px 14px;
  color: var(--text-heading);
  font-weight: var(--fw-semibold);
}
.filters button[type=submit] { margin: 0 }
/* Grouping is a view, not a filter, so it reads as a pressed control rather than
   as another box to fill in. */
.filters .toggle.on {
  background: var(--forest-700);
  border-color: var(--forest-700);
  color: var(--text-on-dark);
}
.filters .toggle.on:hover { background: var(--forest-600); border-color: var(--forest-600) }

.resultline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 22px;
  margin-bottom: var(--space-3);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
}
.resultline a { font-weight: var(--fw-semibold) }

/* The grid itself. One template, declared once and inherited by the header and
   every row, is what keeps the columns aligned. */
/* The heading and every row are separate grid containers, so a content-sized track
   would resolve to a different width in each of them and the columns would drift
   apart. The template is declared once, here, and every track has a size that does
   not depend on what is in it. */
.card.usertable {
  --user-cols: minmax(0, 1fr) 96px 132px 56px 224px;
  padding: 0;
  overflow: visible;
}
.usertable .head,
.usertable .row {
  display: grid;
  grid-template-columns: var(--user-cols);
  align-items: center;
  gap: var(--space-3);
  padding: 14px var(--space-5);
  border-bottom: 1px solid var(--border-hairline);
}
.usertable .row:last-child { border-bottom: none }
.usertable .row:hover { background: var(--surface-inset) }
.usertable .head { border-bottom: 1px solid var(--border-hairline) }
.usertable .col {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
}
a.col:hover { color: var(--text-heading) }
.usertable .col.sorted { color: var(--text-heading) }
.usertable .col > svg { opacity: .7 }
.usertable .col.right { justify-content: flex-end; text-align: right }

/* A level heading over the accounts that hold it. */
.usertable .group {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px var(--space-5);
  background: var(--surface-inset);
  border-bottom: 1px solid var(--border-hairline);
}
.usertable .group .label {
  color: var(--text-heading);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: .12em;
  text-transform: uppercase;
}
.usertable .group .count { color: var(--text-muted); font-size: var(--fs-caption) }

/* Name over address: the name is what somebody is looked up by, the address is
   what confirms it is the right one. */
.usertable .who { min-width: 0 }
.usertable .who .name { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap }
.usertable .who .name > a,
.usertable .who .name { color: var(--text-heading); font-size: var(--fs-body); font-weight: var(--fw-semibold) }
.usertable .who .name > a:hover { color: var(--text-link) }
.usertable .who .self {
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: var(--fw-semibold);
  letter-spacing: .06em;
  text-transform: uppercase;
}
.usertable .who .mail {
  display: block;
  margin-top: 3px;
  overflow: hidden;
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.usertable .count { text-align: right; font-variant-numeric: tabular-nums }

/* Level badges. Owner is the accent, admin is forest, and a plain account is an
   outline — the levels read as a ladder rather than as three unrelated colours. */
.usertable .lvl {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: var(--fw-semibold);
  letter-spacing: .02em;
  white-space: nowrap;
}
.usertable .lvl.owner { background: var(--surface-accent); color: var(--text-on-accent) }
.usertable .lvl.admin { background: var(--forest-700); color: var(--text-on-dark) }
.usertable .lvl.user {
  background: var(--surface-card);
  border-color: var(--border-strong);
  color: var(--text-muted);
}

/* Three states, three tones: enrolled, told to enrol, and neither. */
.usertable .pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}
.usertable .pill.on { padding-left: 8px; background: var(--status-success-bg); color: var(--status-success) }
.usertable .pill.pending { padding-left: 8px; background: var(--status-warning-bg); color: var(--status-warning) }
.usertable .pill.off { background: var(--surface-inset); color: var(--text-muted) }

.usertable .row > .acts {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  position: relative;
}

/* The second-factor menu. A <details>, so it opens with no JS; the script in the
   layout only adds closing it by clicking elsewhere. */
details.rowmenu > summary {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 8px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  color: var(--text-heading);
  font-size: 14px;
  font-weight: var(--fw-semibold);
  list-style: none;
  white-space: nowrap;
  cursor: pointer;
}
details.rowmenu > summary::-webkit-details-marker { display: none }
details.rowmenu > summary:hover { background: var(--surface-inset); border-color: var(--text-heading) }
details.rowmenu[open] > summary { background: var(--surface-inset) }
details.rowmenu[open] > summary > svg { transform: rotate(180deg) }
/* An account a site is holding up says so on the control that fixes it. */
details.rowmenu.flagged > summary { border-color: var(--status-warning); color: var(--status-warning) }
details.rowmenu > .menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: var(--z-dropdown);
  width: 316px;
  padding: var(--space-4);
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
  text-align: left;
}
details.rowmenu .menu .eyebrow { margin-bottom: var(--space-2) }
details.rowmenu .menu .status {
  margin: 0;
  color: var(--text-body);
  font-size: var(--fs-body-sm);
  line-height: 1.5;
}
details.rowmenu .menu .need {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--status-warning-bg);
}
details.rowmenu .menu .need .head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  color: var(--status-warning);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
}
details.rowmenu .menu .need .site {
  margin: var(--space-2) 0 0;
  color: var(--text-body);
  font-size: var(--fs-body-sm);
}
details.rowmenu .menu .need .site ~ .site { margin-top: var(--space-1) }
details.rowmenu .menu .acts {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-hairline);
}
details.rowmenu .menu .acts form { margin: 0 }
/* A button carries the centring and the no-wrap of a page's main action, and
   neither belongs in a menu: the glyphs have to line up down the left edge, and
   a long label wraps rather than being forced onto one line. */
details.rowmenu .menu .acts button {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-3);
  width: 100%;
  margin: 0;
  padding: 10px var(--space-3);
  white-space: normal;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-heading);
  font-family: var(--font-core);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: 0;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
details.rowmenu .menu .acts button:hover { background: var(--surface-inset) }
details.rowmenu .menu .acts button.danger { color: var(--status-error) }
details.rowmenu .menu .acts button.danger:hover { background: var(--status-error-bg) }

.usertable .empty {
  margin: 0;
  padding: var(--space-12) var(--space-6);
  color: var(--text-muted);
  font-size: var(--fs-body);
  text-align: center;
}

/* The rules the table is operated under, kept out of the card so they read as
   documentation rather than as another row. */
.notes {
  max-width: 820px;
  margin-top: var(--space-8);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.notes p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  line-height: 1.65;
}
.notes strong { color: var(--text-body) }

/* ==========================================================================
   10. CODE, SECRETS AND RECOVERY CODES
   ========================================================================== */

code {
  padding: 1px 6px;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-xs);
  background: var(--surface-inset);
  color: var(--text-heading);
  font-family: var(--font-mono);
  font-size: .88em;
}
.secret {
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  background: var(--surface-inset);
  color: var(--text-heading);
  font-family: var(--font-mono);
  font-size: 16px;
  letter-spacing: .06em;
  word-break: break-all;
}
/* The QR stays on white in both themes — a dark-mode inversion would stop it
   scanning. */
.qr {
  display: inline-block;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--neutral-000);
  line-height: 0;
}
.qr img { display: block; width: 200px; height: 200px }
ol.codes {
  columns: 2;
  margin: 0;
  padding-left: var(--space-6);
  color: var(--text-heading);
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
}
ol.codes li { margin: var(--space-1) 0 }

details.alt { margin-top: var(--space-6) }
details.alt summary {
  cursor: pointer;
  color: var(--text-heading);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
}
details.alt summary:hover { color: var(--text-link) }

/* ==========================================================================
   11. AUTH PAGES
   One rounded card on forest ground: a forest brand column beside the panel the
   current step of signing in is drawn on. The ground and the brand column stay
   forest in both themes; the step panel is the card surface, so it follows the
   reader's choice like every other panel in the portal.

   Every step is its own URL, so there is no cross-fade between them — the panel
   arrives with the page. What is animated is what the reader did: the boxes of a
   code sweeping while it is checked, sweeping back and shaking when it is
   refused, and the button holding the wait it started.
   ========================================================================== */

.auth {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-12) var(--gutter) var(--space-16);
  background: var(--forest-900);
}

/* The card is clipped to its own rounded corners, so anything that has to sit
   outside it lives in this wrapper instead — which shares the card's width, so a
   corner of the wrapper is a corner of the card. */
.authshell { position: relative; width: 100%; max-width: 1060px }

.authcard {
  position: relative;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr);
  overflow: hidden;
  border-radius: var(--radius-xl);
  background: var(--surface-card);
  box-shadow: var(--shadow-panel);
}

/* The wordmark on its own row, for the widths where the brand column is gone. */
.authbar { display: none }

.brandcol {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-12);
  padding: var(--space-12) var(--space-10) var(--space-10);
  background: var(--forest-700);
}
/* The hero's barely-there diagonal sheen: two 3%-white bands at 111deg, a narrow
   one leading a wider one. It is the only gradient in the system that is not a
   photo scrim. */
.brandcol::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(111deg,
    transparent 50%,
    rgba(249, 249, 250, .03) 50%,
    rgba(249, 249, 250, .03) 55%,
    transparent 55%,
    transparent 58%,
    rgba(249, 249, 250, .03) 58%,
    rgba(249, 249, 250, .03) 63%,
    transparent 63%);
}
.brandcol > * { position: relative }
.brandcol img.logo { height: 30px; width: auto; align-self: flex-start }
.brandcol .pitch { display: flex; flex-direction: column; gap: var(--space-6) }
.brandcol .eyebrow { color: var(--text-eyebrow-on-dark); margin-bottom: 0 }
.brandcol h2 {
  margin: 0;
  color: var(--text-on-dark);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  text-wrap: pretty;
}
.brandcol p {
  margin: 0;
  max-width: 34ch;
  color: var(--text-on-dark-muted);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}
.brandcol ul.checks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.brandcol ul.checks li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--text-on-dark-muted);
  font-size: var(--fs-body-sm);
  line-height: 1.5;
}
.brandcol ul.checks svg { flex: 0 0 auto; color: var(--signal-500) }

.steppanel { position: relative; display: flex; background: var(--surface-card) }
/* One copy of the switches for both layouts: while there are two columns they sit in
   the step panel's corner, and once there is one they step off the card entirely.
   Rendering a set per layout would put two of every control on the page. */
.authshell > .authtools {
  position: absolute;
  top: var(--space-6);
  right: var(--space-6);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* The step itself, at a fixed height so the card is the same size on every step of
   the flow — a panel that grows and shrinks as somebody moves through it reads as
   the page reloading rather than as one card advancing. The band is pinned to the
   bottom, so a step with less in it than the tallest one leaves its slack above the
   band rather than shortening the card. */
.step {
  flex: 1;
  min-width: 0;
  height: 604px;
  display: flex;
  flex-direction: column;
  /* 28px and 56px are the signing-in design's own, and are not on the spacing
     scale — the rest of the portal has no use for them. */
  gap: 28px;
  padding: var(--space-12) 56px var(--space-10);
}
.step > header { display: flex; flex-direction: column; gap: var(--space-2) }
.step h1 {
  margin: var(--space-4) 0 0;
  color: var(--text-heading);
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
}
.step.compact h1 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2) }
.step p.sub { margin: 0; max-width: 48ch }
/* Signing in is the step with two fields where the others have one, so it is what
   the fixed height is sized to. Its fields are tighter than the portal's own: a
   label sits close to the input it names, and the run of them has to fit the box
   without the card having to grow around it. */
.step > form {
  margin: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.step > form label { margin: 0 0 var(--space-1) }
.step > form input { margin: 0; padding: 10px var(--space-4) }
.step > form button { margin: 0 }

/* Both bands — the brand column's and the step's — are the same height, so the
   card ends on one line rather than two. */
.brandcol .band,
.step .band {
  min-height: 72px;
  margin: auto 0 0;
  padding-top: var(--space-5);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-size: var(--fs-caption);
}
.brandcol .band {
  border-top: 1px solid var(--border-on-dark);
  color: var(--text-on-dark-muted);
}
/* One element per side of a band, so a band holding a single thing keeps it at
   the left and a band holding two puts one at each end. */
.brandcol .band .note,
.step .band .note {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}
.brandcol .band .note svg,
.step .band .note svg { flex: 0 0 auto }
.step .band {
  justify-content: space-between;
  border-top: 1px solid var(--border-hairline);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
}
.step .band .aside {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  text-align: right;
}
.step .band .aside > span { font-size: var(--fs-caption) }
/* A way back is not a call to action: it stays quiet until it is wanted. */
.step .band a.quiet {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
}
.step .band a.quiet:hover { color: var(--text-link); text-decoration: underline; text-underline-offset: 3px }

/* The label of a code field, with what the field's own clock or count says on the
   other end of the same line. */
.step p.fieldhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin: 0;
}
.step p.fieldhead label {
  margin: 0;
  color: var(--text-heading);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
}
.step p.fieldhead .count {
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
}

.otpring { display: inline-flex; align-items: center; gap: var(--space-2) }
.otpring svg { transform: rotate(-90deg) }
.otpring circle { fill: none; stroke-width: 3 }
.otpring .track { stroke: var(--border-hairline) }
.otpring .arc { stroke: var(--signal-500); stroke-linecap: round }
.otpring .left {
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---- Code fields. With no JavaScript this is one ordinary text input; the boxes
   are built by the script, which then hides the input over them. The input keeps
   the focus and the keyboard the whole time — the boxes are decoration, and are
   hidden from assistive technology for that reason. */
.codefield { position: relative }
.codefield .cells {
  display: grid;
  align-items: center;
  gap: var(--space-2);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}
/* Six digits in squares: a box the shape of the character it holds, so the row of
   them reads as a code rather than as a row of fields. */
.codefield .cell {
  position: relative;
  height: auto;
  aspect-ratio: 1;
  max-height: 68px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  background: var(--surface-inset);
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.codefield .cell .char {
  color: var(--text-heading);
  font-size: 28px;
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.codefield .cell .caret {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 24px;
  margin: -12px 0 0 -1px;
  border-radius: 2px;
  background: var(--signal-500);
  opacity: 0;
}
.codefield .cell.here .caret { opacity: 1; animation: ma-blink 1s steps(1) infinite }
.codefield .cell.here {
  border-color: var(--signal-500);
  box-shadow: 0 0 0 3px var(--status-error-bg);
}
.codefield .sep { width: 16px; height: 2px; margin: 0 2px; border-radius: 2px }
/* Ten characters in two fives. Squares would be too narrow to read at ten across,
   so these stay rectangles, and the dash earns its place because a recovery code is
   written with one. */
.codefield[data-code-len="10"] .cells { gap: 6px }
.codefield[data-code-len="10"] .cell {
  height: 58px;
  aspect-ratio: auto;
  max-height: none;
  border-radius: var(--radius-sm);
}
.codefield[data-code-len="10"] .cell .char { font-size: 20px; font-variant-numeric: normal }
.codefield[data-code-len="10"] .cell .caret { height: 20px; margin-top: -10px }
.codefield[data-code-len="10"] .sep { width: 14px; margin: 0 3px; background: var(--border-strong) }

.codefield.enhanced input.codeinput {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  opacity: 0;
  cursor: pointer;
  font-size: 16px; /* anything smaller and a phone zooms the page on focus */
}
/* Without the script the input is the field, so it reads like every other one. */
.codefield:not(.enhanced) input.codeinput {
  font-family: var(--font-mono);
  font-size: 22px;
  letter-spacing: .32em;
  text-align: center;
}

/* Checking: the boxes lift in turn, left to right. */
.codefield.sweeping .cell {
  animation: ma-sweep 260ms var(--ease-standard) calc(var(--i) * 22ms) 1 forwards;
}
/* Refused: they drop back the other way, and the field shakes once. */
.codefield.bad { animation: ma-shake 320ms var(--ease-standard) 1 }
.codefield.bad .cell {
  animation: ma-sweep-back 260ms var(--ease-standard) calc(var(--r) * 22ms) 1 forwards;
}

@keyframes ma-blink { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }
@keyframes ma-sweep {
  0% { transform: translateY(0) scale(1); border-color: var(--border-hairline) }
  45% { transform: translateY(-5px) scale(1.04); border-color: var(--signal-500) }
  100% { transform: translateY(0) scale(1); border-color: var(--border-hairline) }
}
@keyframes ma-sweep-back {
  0% { transform: translateY(0) scale(1); border-color: var(--border-hairline) }
  45% { transform: translateY(5px) scale(.96); border-color: var(--status-error) }
  100% { transform: translateY(0) scale(1); border-color: var(--status-error) }
}
@keyframes ma-shake {
  0%, 100% { transform: translateX(0) }
  18% { transform: translateX(-6px) }
  38% { transform: translateX(5px) }
  58% { transform: translateX(-3px) }
  78% { transform: translateX(2px) }
}
@keyframes ma-rise { from { transform: translateY(8px); opacity: 0 } to { transform: none; opacity: 1 } }
@keyframes ma-spin { to { transform: rotate(360deg) } }

/* The line a step keeps for a refusal. It is there whether or not it says
   anything, so a refusal never moves the button under it. */
/* Not scoped to a step: the enrolment screen keeps a line for a refused code too,
   and it needs the same reserved slot so a refusal does not move the button. */
.errline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 22px;
  margin: 0;
  color: var(--status-error);
  font-size: var(--fs-body-sm);
}
.errline svg { flex: 0 0 auto }
.errline[data-empty] { visibility: hidden }

/* A step's own action, full width: there is one thing to do on each of these
   screens, and it is the width of the screen. */
.step button.primary.lg {
  width: 100%;
  height: 56px;
  padding: 0 var(--space-6);
  font-size: var(--fs-body);
}

/* The wait the action started. Not the brand accent: an orange bar that stays
   orange while nothing happens reads as a button that did not take. This blue is
   the one colour in the portal that is not from the design system — it comes from
   the signing-in design, where it marks every in-flight and onward step. */
:root {
  --pending-500: #2f6fd0;
  --pending-600: #265aad;
}
.pendingbtn,
button.onward,
a.onward {
  width: 100%;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--pending-500);
  color: var(--neutral-000);
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}
.step .band a.onward { height: 52px }
button.onward:hover,
a.onward:hover { background: var(--pending-600); color: var(--neutral-000) }
/* On a page of cards it is one action among a form, not a full-width bar. */
.card > .onward { width: auto; padding: 0 var(--space-8); margin-top: var(--space-6) }
.pendingbtn .spin {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: var(--neutral-000);
  border-radius: var(--radius-pill);
  animation: ma-spin 1400ms linear infinite;
}

/* The ten codes a spent last code earns, in two columns, arriving in order. */
ol.newcodes {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-4);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  background: var(--surface-inset);
}
ol.newcodes li {
  color: var(--text-heading);
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
  letter-spacing: .06em;
  animation: ma-rise 240ms var(--ease-standard) calc(var(--i) * 30ms) 1 both;
}
p.codeactions { margin: 0; display: flex; justify-content: flex-end }
p.codeactions button { margin: 0 }

@media (prefers-reduced-motion: reduce) {
  .codefield.sweeping .cell,
  .codefield.bad,
  .codefield.bad .cell,
  ol.newcodes li,
  .codefield .cell.here .caret { animation: none }
  /* The spinner is left to the portal-wide reduced-motion rule, which stops it. The
     label beside it is what says a request is in flight; the ring was only ever the
     decoration on top of that. */
}

/* ==========================================================================
   11b. THE SIGNED-IN ENROLMENT SCREEN
   Setting a second factor up happens inside the portal, with the top bar still
   there, so it is not the signing-in card — it is a panel of its own: a forest
   column carrying the three steps, beside the QR code and the field that
   confirms it. Reached from Security, and from a login by an account the portal
   requires one of, which is why its footer can carry a destination.
   ========================================================================== */

.mfa-setup-shell { width: 100%; max-width: 1060px; margin: 0 auto }
/* Led here straight from a login there is nothing else on the screen, so the
   panel centres in what the top bar leaves. `safe center` keeps a panel taller
   than the viewport reachable from its top rather than clipping both ends. */
.mfa-setup-login-wrap {
  min-height: calc(100vh - var(--portalbar-h));
  display: flex;
  align-items: safe center;
  padding-top: var(--space-8);
  padding-bottom: var(--space-8);
}
.mfa-setup-panel {
  display: grid;
  grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  overflow: hidden;
  border-radius: var(--radius-xl);
  background: var(--surface-card);
  box-shadow: var(--shadow-panel);
}
.mfa-setup-guide {
  min-height: 640px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-16);
  padding: var(--space-12) var(--space-10);
  background: var(--forest-700);
  color: var(--text-on-dark);
}
.mfa-setup-guide .eyebrow { margin: 0; color: var(--text-on-dark-muted) }
.mfa-setup-guide h2 {
  margin: 0;
  color: var(--text-on-dark);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
}
.mfa-guide-content { display: flex; flex-direction: column; gap: var(--space-6); margin: auto 0 }
.mfa-setup-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
}
.mfa-setup-steps li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--text-on-dark-muted);
  font-size: var(--fs-body-sm);
}
.mfa-setup-steps li > span {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-on-dark);
  border-radius: var(--radius-pill);
  color: var(--text-on-dark);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
}
/* The same strip the signing-in card's brand column carries, on the same surface. */
.auth-brand-footer {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-on-dark);
  color: var(--text-on-dark-muted);
  font-size: var(--fs-caption);
}
.auth-brand-footer svg { flex: 0 0 auto }

.mfa-setup-main { min-width: 0; padding: var(--space-12) 56px var(--space-10) }
.mfa-setup-main .crumb { margin-bottom: var(--space-3) }
.mfa-setup-main > .sub { margin-bottom: var(--space-8) }
.mfa-setup-qr-row { display: flex; align-items: flex-start; gap: var(--space-6) }
.mfa-setup-qr { flex: 0 0 auto; padding: var(--space-2); border: 1px solid var(--border-hairline) }
.mfa-setup-qr img { width: 168px; height: 168px }
.mfa-manual-key { min-width: 0; display: flex; flex-direction: column; gap: var(--space-3) }
.mfa-manual-key > p { color: var(--text-body); font-size: var(--fs-body-sm); line-height: var(--lh-body-sm) }
/* The key spelled out, for a reader who cannot point a camera at their own screen. */
.secret-copy {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 14px var(--space-4);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  background: var(--surface-inset);
}
.secret-copy code {
  min-width: 0;
  flex: 1;
  padding: 0;
  border: 0;
  background: transparent;
  word-break: break-word;
  letter-spacing: .04em;
}
.secret-copy button { flex: 0 0 auto; padding: 7px 14px }
.setup-code-form { display: flex; flex-direction: column; margin-top: var(--space-8) }
.setup-code-form > button { width: 100%; min-height: 56px; margin-top: var(--space-6) }
.setup-leave-hint {
  margin-top: var(--space-4);
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.6;
}

/* A set of codes handed over on a signed-in page, rather than on the way in. */
.mfa-codes-page { width: 100%; max-width: 780px; margin: 0 auto }
.mfa-codes-card { margin-top: var(--space-8) }
.mfa-codes-card ol.codes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-8);
  margin: 0;
  columns: auto;
}
.mfa-action-warning {
  max-width: 780px;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--status-warning-bg);
  color: var(--text-body);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
}
.mfa-action-warning svg { flex: 0 0 auto; margin-top: 2px; color: var(--status-warning) }

@media (max-width: 1080px) {
  .mfa-setup-shell { max-width: 720px }
  .mfa-setup-panel { grid-template-columns: 1fr }
  .mfa-setup-guide { min-height: 0; padding: var(--space-8) }
  .mfa-guide-content { margin: 0 }
  .mfa-setup-guide .auth-brand-footer { display: none }
  .mfa-setup-main { padding: var(--space-8) }
  .mfa-setup-qr-row { flex-direction: column }
}

@media (max-width: 480px) {
  .mfa-setup-main, .mfa-setup-guide { padding: var(--space-6) var(--space-5) }
  .mfa-setup-qr img { width: 148px; height: 148px }
  .secret-copy { align-items: stretch; flex-direction: column }
  .secret-copy button { align-self: flex-start }
  .mfa-codes-card ol.codes { grid-template-columns: 1fr }
}

/* ==========================================================================
   12. NARROWER VIEWPORTS
   ========================================================================== */

/* Below this the brand column is a screen of scrolling to get past before anyone
   can sign in, so it goes, and the wordmark moves to a bar across the top of the
   card. A tablet is included: two columns at that width leave the code boxes too
   narrow to read. */
@media (max-width: 1024px) {
  /* Not a card down here: a card floating on a phone is a page with a margin drawn
     round it, and that margin is the room the code boxes need while a keyboard is
     up. So the panel fills the screen and drops its corners and its shadow. */
  .auth { align-items: stretch; padding: 0; min-height: 100dvh }
  /* The panel is the page, so it reaches the bottom of the screen rather than
     ending where its content does and leaving the ground showing under it. */
  .authshell { max-width: none; display: flex; flex-direction: column }
  .authcard {
    flex: 1;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    border-radius: 0;
    box-shadow: none;
  }
  .brandcol { display: none }
  /* The only lockup supplied is the white one, so the bar it sits on stays forest —
     the same surface the portal's own top bar keeps in both themes. */
  .authbar {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background: var(--forest-700);
    border-bottom: 1px solid var(--border-on-dark);
  }
  .authbar img { height: 24px; width: auto }
  /* The switches are the portal's own furniture, not part of the card the design
     specifies, and at this width they and the wordmark cannot share a row — the
     pair of them is wider than a phone. So they step off the card and sit above
     it, where they cost the card no height and can never cover the wordmark. */
  /* The language switch rides at the end of the logo bar. The theme switch does not
     come along: the two of them are wider than a phone next to the wordmark, and of
     the pair this is the one that changes what the page says. */
  .authshell > .authtools { top: 16px; right: var(--space-5) }
  .authshell > .authtools .themeswitch { display: none }
  /* Out there they are on the forest ground, where the card-surface fill they wear
     inside the card is all but invisible. This is the same on-dark treatment the
     portal's own top bar gives its controls. */
  .authshell > .authtools .langswitch,
  .authshell > .authtools .themeswitch {
    background: rgba(249, 249, 250, .10);
    border-color: var(--border-on-dark);
  }
  .authshell > .authtools button { color: var(--text-on-dark-muted) }
  .authshell > .authtools button:hover { color: var(--text-on-dark) }
  .authshell > .authtools button[aria-pressed="true"] {
    background: rgba(249, 249, 250, .18);
    color: var(--text-on-dark);
    box-shadow: none;
  }
  /* No fixed height here. It bought one card size across the steps, but on a phone
     what matters is that the boxes being typed into stay above the keyboard, and
     height held against that is height spent on nothing. */
  .step {
    height: auto;
    min-height: 0;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-5) var(--space-4);
  }
  /* The heading carries the step; the sentence of reassurance under it costs two
     lines of the screen the code needs. */
  .step > header p.sub { display: none }
  .step h1 { margin-top: 0; font-size: var(--fs-h2); line-height: var(--lh-h2) }
  .step .band { min-height: 0; padding-top: var(--space-4) }
  .codefield .cell { max-height: 56px }
  .codefield .cell .char { font-size: 22px }
  .codefield[data-code-len="10"] .cell { height: 46px }
  .codefield[data-code-len="10"] .cell .char { font-size: 15px }
  .codefield[data-code-len="10"] .cell .caret { height: 16px; margin-top: -8px }
}

@media (max-width: 720px) {
  :root { --gutter: var(--gutter-sm) }
  .wrap { padding: var(--space-10) var(--gutter) var(--space-16) }
  h1 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2) }
  /* One row, always: the wordmark gives way to the double-slash device, which then
     serves as the icon of "My sites" next to it, and the account chip keeps just
     its monogram. */
  header.top .wrap { padding: var(--space-3) var(--gutter); gap: var(--space-1) }
  header.top .brand { margin-right: var(--space-2) }
  header.top .brand img { display: none }
  header.top .brand .slash { display: block }
  header.top nav a, header.top nav summary { padding: 8px 10px }
  header.top nav a.sites > svg { display: none }
  details.acct > summary { padding: 6px 6px }
  details.acct > summary .label, details.acct > summary .chev { display: none }
  .card { padding: var(--space-5) }
  /* The five columns stop fitting long before this, so the row becomes two: the
     account over its own controls, with the badges in a line between them. */
  .usertable .head { display: none }
  .usertable .row {
    gap: var(--space-2) var(--space-3);
    padding: var(--space-4) var(--space-5);
  }
  .card.usertable { --user-cols: 1fr auto }
  .usertable .row > .who { grid-column: 1 / -1 }
  .usertable .row > .count { text-align: left }
  .usertable .row > .count::before { content: attr(data-label); margin-right: 6px; color: var(--text-muted) }
  .usertable .row > .acts { grid-column: 1 / -1; justify-content: flex-start; flex-wrap: wrap }
  details.rowmenu > .menu { right: auto; left: 0; width: min(316px, calc(100vw - var(--gutter) * 4)) }
  .card > table,
  .card > .tablewrap { margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) 0 }
  .card > table th:first-child, .card > table td:first-child,
  .card > .tablewrap th:first-child, .card > .tablewrap td:first-child { padding-left: var(--space-5) }
  .card > table th:last-child, .card > table td:last-child,
  .card > .tablewrap th:last-child, .card > .tablewrap td:last-child { padding-right: var(--space-5) }
  ol.codes { columns: 1 }
}
