/* Shared design system for the student and admin pages. Blue is reserved for the primary action, focus and progress.
   Every control sits on the same height scale (--h-s / --h / --h-l) so rows line up by construction.
   Motion: press feedback and state changes only, on the curves below; hover styles live behind a capability query. */
:root {
  color-scheme: light;
  --bg: #f5f5f7;
  --surface: #ffffff;
  --fill: rgb(118 118 128 / .08);
  --fill-hover: rgb(118 118 128 / .14);
  --fill-press: rgb(118 118 128 / .2);
  --thumb: #ffffff;
  --ink: #1d1d1f;
  --ink-2: #66666b;
  --ink-3: #7f7f85;
  --line: #e8e8ed;
  --line-2: #d2d2d7;
  --blue: #0071e3;
  --blue-hover: #0077ed;
  --blue-press: #0064c8;
  --blue-text: #0066cc;
  --blue-glow: rgb(0 113 227 / .22);
  --on-blue: #ffffff;
  --ok-fill: #34c759;
  --warn-fill: #ff9f0a;
  --err: #d70015;
  --err-fill: #ff3b30;
  --err-wash: rgb(255 59 48 / .09);
  --warn-wash: rgb(255 159 10 / .12);
  --series-ok: #2a78d6;
  --series-fail: #d03b3b;
  --nav-bg: rgb(245 245 247 / .78);
  --pop-bg: rgb(255 255 255 / .9);
  --toast-bg: rgb(29 29 31 / .94);
  --stage: #0b0b0c;
  --shadow-1: 0 1px 2px rgb(0 0 0 / .05), 0 2px 10px rgb(0 0 0 / .03);
  --shadow-2: 0 1px 3px rgb(0 0 0 / .06), 0 10px 30px rgb(0 0 0 / .08);
  --shadow-3: 0 2px 6px rgb(0 0 0 / .05), 0 24px 64px rgb(0 0 0 / .11);
  --shadow-pop: 0 10px 40px rgb(0 0 0 / .16), 0 1px 3px rgb(0 0 0 / .08);
  --shadow-thumb: 0 1px 3px rgb(0 0 0 / .14), 0 0 1px rgb(0 0 0 / .1);
  --backdrop: rgb(0 0 0 / .4);
  --frost: saturate(180%) blur(20px);

  --nav-h: calc(56px + env(safe-area-inset-top, 0px));
  --h: 38px;
  --h-s: 32px;
  --h-l: 48px;
  --r-s: 8px;
  --r: 12px;
  --r-l: 18px;
  --r-xl: 24px;
  /* Chinese system fonts on Windows have no medium weight: 500 falls back to regular, so emphasis uses 600. */
  --bold: 600;
  --track-tight: -.015em;
  --track-display: -.022em;
  /* The only four text sizes on the site; --fs-s is the body size, so a rule never needs to restate it.
     --fs-m also sits above the 16px under which iOS zooms into an input. */
  --fs-s: 14px;
  --fs-m: 17px;
  --fs-l: 24px;
  --fs-xl: clamp(36px, 4.3vw, 60px);
  --ease-out: cubic-bezier(.23, 1, .32, 1);
  --ease-in-out: cubic-bezier(.77, 0, .175, 1);
  --ease-drawer: cubic-bezier(.32, .72, 0, 1);
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Segoe UI Variable Text", "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", "Noto Sans SC", system-ui, sans-serif;
  --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "PingFang SC", "Segoe UI Variable Display", "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", "Noto Sans SC", system-ui, sans-serif;
}
/* shared.js sets the attribute before the body parses: dark only when chosen with the toggle. */
:root[data-resolved-theme="dark"] {
  color-scheme: dark;
  --bg: #000000;
  --surface: #1c1c1e;
  --fill: rgb(118 118 128 / .24);
  --fill-hover: rgb(118 118 128 / .32);
  --fill-press: rgb(118 118 128 / .4);
  --thumb: #636366;
  --ink: #f5f5f7;
  --ink-2: #aeaeb2;
  --ink-3: #8e8e93;
  --line: #2c2c2e;
  --line-2: #3a3a3c;
  --blue: #0a84ff;
  --blue-hover: #2e96ff;
  --blue-press: #0071e3;
  --blue-text: #4ea1ff;
  --blue-glow: rgb(10 132 255 / .32);
  --ok-fill: #30d158;
  --err: #ff6961;
  --err-fill: #ff453a;
  --err-wash: rgb(255 69 58 / .16);
  --warn-wash: rgb(255 159 10 / .16);
  --series-ok: #3987e5;
  --series-fail: #e0524f;
  --nav-bg: rgb(22 22 23 / .72);
  --pop-bg: rgb(44 44 46 / .92);
  --toast-bg: rgb(58 58 60 / .96);
  --stage: #000000;
  --shadow-1: 0 0 0 1px rgb(255 255 255 / .05);
  --shadow-2: 0 0 0 1px rgb(255 255 255 / .06);
  --shadow-3: 0 0 0 1px rgb(255 255 255 / .08);
  --shadow-pop: 0 0 0 1px rgb(255 255 255 / .08), 0 12px 44px rgb(0 0 0 / .7);
  --backdrop: rgb(0 0 0 / .62);
}
@media (pointer: coarse) {
  :root { --h: 44px; --h-s: 38px; --h-l: 50px; }
  /* iOS zooms into inputs under 16px and never zooms back. */
  input, textarea, select { font-size: var(--fs-m) !important; }
}
@media (max-width: 860px) {
  :root { --fs-xl: clamp(36px, 9.6vw, 56px); }
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; scroll-behavior: smooth; }
body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--ink);
  font: var(--fs-s)/1.5 var(--font);
  font-synthesis: none;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; font-weight: inherit; }
a { color: inherit; }
button, input, textarea, select { font: inherit; color: inherit; }
button, a, label, [role="button"] { touch-action: manipulation; }
button, [role="button"], .chip, .seg label { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
::selection { background: var(--blue-glow); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 200ms; animation-timing-function: ease; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icon { flex: none; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.tnum { font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-3); }
.grow { flex: 1 1 auto; min-width: 0; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.surface { background: var(--surface); border-radius: var(--r-l); box-shadow: var(--shadow-1); }
.heading { font: var(--bold) var(--fs-l)/1.3 var(--font-display); letter-spacing: var(--track-tight); }
.banner { padding: 10px 24px; background: var(--warn-wash); overflow-wrap: anywhere; }
.more { display: flex; justify-content: center; }
.more .btn { min-width: 128px; }

/* Buttons. The label stays in layout while loading, so a button never changes width. */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--h);
  padding: 0 16px;
  border: 0;
  border-radius: 980px;
  background: transparent;
  color: var(--ink);
  font: 500 var(--fs-s)/1 var(--font);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  transition: transform 160ms var(--ease-out), background-color 120ms ease, color 120ms ease, opacity 160ms ease;
}
.btn > * { transition: opacity 150ms ease, filter 150ms ease, transform 150ms var(--ease-out); }
.btn:active:not(:disabled, [data-state]) { transform: scale(.97); transition-duration: 100ms; }
.btn-primary { background: var(--blue); color: var(--on-blue); font-weight: var(--bold); }
.btn-primary:active { background: var(--blue-press); }
.btn-secondary { background: var(--fill); }
.btn-secondary:active { background: var(--fill-press); }
.btn-ghost { color: var(--ink-2); }
.btn-ghost:active { background: var(--fill-hover); }
.btn-link { color: var(--blue-text); }
.btn-link:active { background: var(--fill-hover); }
.btn-s { height: var(--h-s); padding: 0 12px; }
.btn-l { height: var(--h-l); padding: 0 22px; font-size: var(--fs-m); }
.btn-block { width: 100%; }
.btn-icon { width: var(--h); padding: 0; }
.btn-s.btn-icon { width: var(--h-s); }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn[data-state] { pointer-events: none; }
/* Label to spinner: a small blur merges the two states into one change. */
.btn[data-state] > * { opacity: 0; filter: blur(2px); transform: scale(.96); }
.btn[data-state]::after { content: ""; position: absolute; inset: 0; margin: auto; }
.btn[data-state="loading"]::after { width: 16px; height: 16px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin .6s linear infinite; }
.btn[data-state="done"]::after { width: 6px; height: 11px; border: solid currentColor; border-width: 0 2px 2px 0; transform: translateY(-1px) rotate(45deg); animation: settle 180ms var(--ease-out) both; }
/* Upload progress along the bottom of a button, driven by --progress from 0 to 1. */
.btn-progress::before { content: ""; position: absolute; inset: auto 0 0 0; height: 3px; background: currentColor; opacity: .6; transform: scaleX(var(--progress, 0)); transform-origin: left; transition: transform 200ms linear; }
/* Two-step confirm: arm on first click; the line under the label drains until it disarms. */
.btn.arming { background: var(--err-wash); color: var(--err); }
.btn.arming::before { content: ""; position: absolute; inset: auto 0 0 0; height: 2px; background: var(--err); transform-origin: left; animation: drain var(--arm-ms) linear both; }

/* Fields */
.field { display: grid; gap: 6px; min-width: 0; }
.field-label { font-weight: var(--bold); color: var(--ink); }
.field-hint { color: var(--ink-3); }
.input, .textarea, .select { display: block; width: 100%; border: 1px solid var(--line-2); border-radius: var(--r); background: var(--surface); color: var(--ink); transition: border-color 120ms ease, box-shadow 120ms ease; }
.input, .select { height: var(--h); padding: 0 13px; }
.textarea { padding: 10px 13px; line-height: 1.6; resize: none; }
.input::placeholder, .textarea::placeholder { color: var(--ink-3); }
.input:focus, .textarea:focus, .select:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 4px var(--blue-glow); }
.input:disabled, .textarea:disabled, .select:disabled { background: var(--fill); color: var(--ink-3); cursor: not-allowed; }
.select { appearance: none; padding-right: 32px; background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%, var(--ink-3) 60%, transparent 60%), linear-gradient(-45deg, transparent 50%, var(--ink-3) 50%, var(--ink-3) 60%, transparent 60%); background-position: right 17px center, right 13px center; background-size: 5px 5px; background-repeat: no-repeat; cursor: pointer; }
.input-wrap { position: relative; display: block; }
.input-wrap > .input { padding-right: 42px; }
.input-wrap > .input-action { position: absolute; top: calc(50% - 16px); right: 5px; width: 32px; height: 32px; padding: 0; color: var(--ink-3); }
.input-wrap.with-lead > .input { padding-left: 36px; padding-right: 14px; border-color: transparent; border-radius: 980px; background: var(--fill); }
.input-wrap.with-lead > .input:focus { background: var(--surface); border-color: var(--blue); }
.input-lead { position: absolute; top: 50%; left: 13px; margin-top: -8px; color: var(--ink-3); pointer-events: none; }
input[type="search"]::-webkit-search-cancel-button { appearance: none; }

.form-error { color: var(--err); }
.form-error:empty { display: none; }
.shake { animation: shake 240ms var(--ease-out); }

/* A real input stretched over a custom control: arrow keys and screen readers work natively. */
.seg input, .chip input, .switch input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: inherit; }

/* Segmented control. Thumb position comes from --i / --n, set by UI.seg. */
.seg { --pad: 2px; position: relative; display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; height: var(--h); padding: var(--pad); border-radius: 980px; background: var(--fill); isolation: isolate; }
.seg::before { content: ""; position: absolute; z-index: -1; top: var(--pad); bottom: var(--pad); left: var(--pad); width: calc((100% - 2 * var(--pad)) / var(--n, 2)); border-radius: 980px; background: var(--thumb); box-shadow: var(--shadow-thumb); transform: translateX(calc(var(--i, 0) * 100%)); }
.seg.ready::before { transition: transform 200ms var(--ease-in-out); }
.seg label { position: relative; display: flex; align-items: center; justify-content: center; gap: 5px; padding: 0 14px; font-weight: 500; color: var(--ink-2); white-space: nowrap; cursor: pointer; transition: color 120ms ease; }
.seg label:has(input:checked) { color: var(--ink); font-weight: var(--bold); }
.seg label:has(input:focus-visible) { outline: 2px solid var(--blue); outline-offset: 1px; border-radius: 980px; }
.seg label:has(input:disabled) { cursor: not-allowed; opacity: .55; }
.seg .seg-sub { font-weight: 400; color: var(--ink-3); }
.seg-s { height: var(--h-s); }
.seg-s label { padding: 0 12px; }

/* Filter chips: selection is a colour change, nothing moves. */
.chips { display: inline-flex; gap: 2px; padding: 2px; border-radius: 980px; background: var(--fill); }
.chip { position: relative; display: inline-flex; flex: 1 1 auto; align-items: center; justify-content: center; height: calc(var(--h-s) - 4px); padding: 0 14px; border-radius: 980px; color: var(--ink-2); white-space: nowrap; cursor: pointer; transition: background-color 120ms ease, color 120ms ease, transform 160ms var(--ease-out); }
.chip:active { transform: scale(.97); transition-duration: 100ms; }
.chip:has(input:checked) { background: var(--thumb); color: var(--ink); font-weight: var(--bold); box-shadow: var(--shadow-thumb); }
.chip:has(input:focus-visible) { outline: 2px solid var(--blue); outline-offset: 2px; }

/* Switch: the knob stretches while pressed. */
.switch { position: relative; display: inline-flex; width: 42px; height: 26px; flex: none; cursor: pointer; }
.switch-track { position: absolute; inset: 0; border-radius: 13px; background: var(--fill-press); transition: background-color 200ms ease; }
.switch-knob { position: absolute; top: 2px; left: 2px; width: 22px; height: 22px; border-radius: 11px; background: #fff; box-shadow: 0 2px 6px rgb(0 0 0 / .22), 0 0 1px rgb(0 0 0 / .2); transform-origin: left center; transition: transform 200ms var(--ease-out); pointer-events: none; }
.switch input:checked ~ .switch-track { background: var(--ok-fill); }
.switch input:checked ~ .switch-knob { transform: translateX(16px); transform-origin: right center; }
.switch:active .switch-knob { transform: scaleX(1.18); }
.switch:active input:checked ~ .switch-knob { transform: translateX(16px) scaleX(1.18); }
.switch input:focus-visible ~ .switch-track { outline: 2px solid var(--blue); outline-offset: 2px; }
.switch input:disabled { cursor: not-allowed; }
.switch input:disabled ~ .switch-track { opacity: .5; }

/* Status: dot plus label, never colour alone. */
.status { display: inline-flex; align-items: center; gap: 6px; color: var(--ink-2); white-space: nowrap; }
.dot { position: relative; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--ink-3); }
.status-queued .dot { background: var(--warn-fill); }
.status-running .dot, .status-validating .dot { background: var(--blue); }
.status-running .dot::after, .status-validating .dot::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--blue); animation: pulse 1.6s var(--ease-out) infinite; }
.status-succeeded .dot { background: var(--ok-fill); }
.status-failed .dot { background: var(--err-fill); }
.status-cancelled .dot { background: var(--line-2); }

/* Meter */
.meter { display: block; height: 4px; border-radius: 2px; background: var(--fill-hover); overflow: hidden; }
.meter > i { display: block; height: 100%; width: 100%; border-radius: inherit; background: var(--blue); transform: scaleX(var(--v, 0)); transform-origin: left; transition: transform 280ms var(--ease-out), background-color 200ms ease; }
.meter.warn > i { background: var(--warn-fill); }
.meter.danger > i { background: var(--err-fill); }

/* Progress ring with rounded caps. --p runs from 0 to 1; a progress estimate moves at constant speed, hence linear. */
.ring { display: block; flex: none; transform: rotate(-90deg); }
.ring-track { stroke: var(--fill-hover); }
.ring-value { stroke: var(--blue); stroke-linecap: round; stroke-dasharray: 1 1; stroke-dashoffset: calc(1 - var(--p, 0)); transition: stroke-dashoffset 500ms linear, stroke 200ms ease; }
.ring.empty .ring-value { opacity: 0; }
.ring.warn .ring-value { stroke: var(--warn-fill); }

.avatar { display: inline-grid; place-items: center; flex: none; width: 32px; height: 32px; border-radius: 50%; background: var(--fill-hover); color: var(--ink); font-weight: var(--bold); line-height: 1; user-select: none; -webkit-user-select: none; }
.avatar-l { width: 48px; height: 48px; font-size: var(--fs-l); }

/* Rolling number: the digit moves the way the value moved. */
.roll { display: inline-grid; overflow: hidden; vertical-align: bottom; line-height: inherit; }
.roll > * { grid-area: 1 / 1; display: block; text-align: inherit; }
.roll-out { animation: roll-out 200ms var(--ease-out) both; }
.roll-in { animation: roll-in 200ms var(--ease-out) both; }

/* Dialogs stay centred; menus grow from their trigger. Exit is faster than entry. */
dialog.dialog { padding: 0; border: 0; background: transparent; color: var(--ink); max-width: calc(100vw - 32px); max-height: calc(100dvh - 32px); overflow: visible; }
dialog.dialog::backdrop { background: var(--backdrop); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); animation: fade-in 200ms ease both; }
dialog.dialog[open] > .dialog-panel { animation: dialog-in 240ms var(--ease-drawer) both; }
dialog.dialog.closing::backdrop { animation: fade-out 120ms ease both; }
dialog.dialog.closing > .dialog-panel { animation: dialog-out 120ms ease both; }
.dialog-panel { width: 420px; max-width: 100%; padding: 24px; border-radius: var(--r-xl); background: var(--surface); box-shadow: var(--shadow-pop); display: grid; gap: 16px; }
.dialog-actions { display: grid; grid-auto-flow: column; grid-auto-columns: 96px; justify-content: end; gap: 8px; margin-top: 4px; }

.menu { position: fixed; z-index: 60; min-width: 208px; padding: 6px; border-radius: 14px; background: var(--pop-bg); -webkit-backdrop-filter: var(--frost); backdrop-filter: var(--frost); box-shadow: var(--shadow-pop); transition: opacity 160ms var(--ease-out), transform 160ms var(--ease-out); }
@starting-style { .menu { opacity: 0; transform: scale(.97); } }
.menu.closing { opacity: 0; transform: scale(.98); transition-duration: 100ms; pointer-events: none; }
.menu-item { display: flex; align-items: center; gap: 10px; width: 100%; height: 36px; padding: 0 10px; border: 0; border-radius: var(--r-s); background: none; color: var(--ink); text-align: left; cursor: pointer; }
.menu-item:focus-visible { background: var(--fill-hover); outline: none; }
.menu-item:active { background: var(--fill-press); }
.menu-item .icon { color: var(--ink-2); }
.menu-item.danger, .menu-item.danger .icon { color: var(--err); }
.menu-sep { height: 1px; margin: 6px 10px; background: var(--line-2); opacity: .6; }
/* Phones: the same menu as an action sheet. Enters and leaves through the bottom edge. */
.menu-scrim { position: fixed; z-index: 59; inset: 0; background: var(--backdrop); transition: opacity 200ms ease; }
@starting-style { .menu-scrim { opacity: 0; } }
.menu-scrim.closing { opacity: 0; transition-duration: 120ms; pointer-events: none; }
.menu-sheet { top: auto; left: 8px; right: 8px; bottom: calc(8px + env(safe-area-inset-bottom, 0px)); padding: 8px; border-radius: var(--r-xl); background: var(--surface); -webkit-backdrop-filter: none; backdrop-filter: none; transition: transform 280ms var(--ease-drawer); }
@starting-style { .menu-sheet { opacity: 1; transform: translateY(calc(100% + 16px)); } }
.menu-sheet.closing { opacity: 1; transform: translateY(calc(100% + 16px)); transition-duration: 180ms; }
.menu-sheet .menu-item { height: 50px; padding: 0 14px; font-size: var(--fs-m); border-radius: var(--r); }

/* Toast: enters and leaves through the bottom edge. Transitions, so a new toast retargets instead of restarting. */
.toast-region { position: fixed; z-index: 70; left: 50%; bottom: max(24px, env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); width: max-content; max-width: calc(100vw - 32px); pointer-events: none; }
.toast { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 18px; border-radius: 22px; background: var(--toast-bg); color: #fff; -webkit-backdrop-filter: var(--frost); backdrop-filter: var(--frost); box-shadow: var(--shadow-pop); pointer-events: auto; transition: transform 280ms var(--ease-drawer), opacity 200ms ease; }
@starting-style { .toast { opacity: 0; transform: translateY(100%); } }
.toast.leaving { opacity: 0; transform: translateY(100%); transition-duration: 180ms; }
.toast-action { margin: -5px -10px -5px 4px; height: 30px; padding: 0 12px; border: 0; border-radius: 980px; background: rgb(255 255 255 / .18); color: inherit; font-weight: var(--bold); cursor: pointer; }
.toast-action:active { background: rgb(255 255 255 / .34); }

/* Frosted navigation. The hairline only appears once content actually slides under it. */
.nav { position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: 6px; height: var(--nav-h); padding: env(safe-area-inset-top, 0px) max(clamp(16px, 2.2vw, 32px), env(safe-area-inset-right, 0px)) 0 max(clamp(16px, 2.2vw, 32px), env(safe-area-inset-left, 0px)); background: var(--nav-bg); -webkit-backdrop-filter: var(--frost); backdrop-filter: var(--frost); box-shadow: 0 1px 0 var(--line); }
@supports (animation-timeline: scroll()) {
  .nav { box-shadow: 0 1px 0 transparent; animation: nav-edge linear both; animation-timeline: scroll(); animation-range: 0 12px; }
}

/* Theme toggle: an instant icon swap; the page itself crossfades through a view transition. */
.theme-toggle .moon { display: none; }
:root[data-resolved-theme="dark"] .theme-toggle .sun { display: none; }
:root[data-resolved-theme="dark"] .theme-toggle .moon { display: block; }

/* Pointers that can really hover. Touch browsers fake :hover and leave it stuck after a tap. */
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover:not(:active) { background: var(--blue-hover); }
  .btn-secondary:hover:not(:active) { background: var(--fill-hover); }
  .btn-ghost:hover { background: var(--fill); color: var(--ink); }
  .btn-link:hover { background: var(--fill); }
  .input:hover, .textarea:hover, .select:hover { border-color: var(--ink-3); }
  .input:focus:hover, .textarea:focus:hover, .select:focus:hover { border-color: var(--blue); }
  .input-wrap.with-lead > .input:hover:not(:focus) { border-color: transparent; background: var(--fill-hover); }
  .seg label:hover:not(:has(input:disabled)) { color: var(--ink); }
  .seg label:hover:not(:has(input:disabled)) .seg-sub { color: inherit; font-weight: inherit; }
  .chip:hover:not(:has(input:checked)) { color: var(--ink); }
  .menu-item:hover { background: var(--fill-hover); }
  .menu-item.danger:hover { background: var(--err-wash); }
  .toast-action:hover { background: rgb(255 255 255 / .3); }
}

/* Group entrance, only on first load of a list: 40ms apart and never blocking input. */
.enter { animation: rise 240ms var(--ease-out) both; animation-delay: calc(var(--stagger, 0) * 40ms); }

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes settle { from { opacity: 0; transform: translateY(-1px) rotate(45deg) scale(.8); } to { opacity: 1; transform: translateY(-1px) rotate(45deg) scale(1); } }
@keyframes drain { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@keyframes shake { 25% { transform: translateX(-4px); } 60% { transform: translateX(3px); } 85% { transform: translateX(-1px); } }
@keyframes pulse { 0% { transform: scale(1); opacity: .6; } 80%, 100% { transform: scale(2.6); opacity: 0; } }
@keyframes roll-out { to { transform: translateY(calc(var(--dir, 1) * -100%)); opacity: 0; } }
@keyframes roll-in { from { transform: translateY(calc(var(--dir, 1) * 100%)); opacity: 0; } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }
@keyframes dialog-in { from { opacity: 0; transform: scale(.97); } }
@keyframes dialog-out { to { opacity: 0; transform: scale(.98); } }
@keyframes nav-edge { to { box-shadow: 0 1px 0 var(--line); } }

/* Gentler, not zero: colour and opacity stay, movement goes. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-property: opacity, color, background-color, border-color, box-shadow !important; }
  .enter, .roll-in, .roll-out, dialog.dialog[open] > .dialog-panel { animation: fade-in 200ms ease both !important; }
  .roll-out { animation-name: fade-out !important; }
  .shake, .status-running .dot::after, .status-validating .dot::after { animation: none !important; }
  .btn:active:not(:disabled), .chip:active { transform: none !important; }
  @starting-style { .menu, .toast { transform: none; } .menu-sheet { opacity: 0; transform: none; } }
  .toast.leaving, .menu.closing { transform: none; }
  .menu-sheet { transition-duration: 200ms; }
  .menu-sheet.closing { opacity: 0; transform: none; transition-duration: 120ms; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
@media (prefers-reduced-transparency: reduce) {
  :root { --frost: none; }
  .nav, .menu { background: var(--surface); }
  dialog.dialog::backdrop { -webkit-backdrop-filter: none; backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  :root, :root[data-resolved-theme="dark"] { --ink-2: var(--ink); --ink-3: var(--ink); --line: var(--line-2); }
  .surface, .menu, .dialog-panel { box-shadow: 0 0 0 1px var(--ink); }
}
