/*
  LunettiStar CV design tokens: white, blue, and black, in a flat, airy
  style -- a white top bar, white cards on thin grey borders, soft shadows,
  pill-shaped buttons, and grey secondary text.

  Light mode is a white page with black text, blue actions, and a navy
  header that matches the logo; dark mode is a black page with white text
  and bright blue accents. Every token keeps the name it was first given
  (--rust is still "the brand hue", --gold "the bright accent fill",
  --choco "the dark header surface", --moss "success") so no downstream CSS
  needed to change selector-by-selector; only the values moved.

  Light/dark is the bare :root / system prefers-color-scheme /
  :root[data-theme="dark"] pattern, chosen with the header's theme toggle or
  Account -> Appearance. There is one colour scheme; theme-init.js always
  sets data-palette="sage", the key of the default token set below.

  The rendered CV is excluded on purpose. resume/preview.css and print.css
  keep their own print-safe colours so an exported CV stays white with black
  text in every theme. Run scripts/check-contrast.mjs after any change here.
*/

:root {
  /* Example text inside an empty field: lighter than typed text, but
     still easy to read (4.5:1 or more on the field). */
  --placeholder: #6B7280;
  color-scheme: light;

  /* Room for the phone's status bar. The page is laid out under it
     (viewport-fit=cover, and a translucent status bar on iOS), so every
     top bar pads itself down by this much. Installed as an app there is no
     browser toolbar above the page either, so it never gets less than a
     little breathing room from the top edge. */
  --safe-top: env(safe-area-inset-top, 0px);

  /* --- White page, black text, blue actions, navy header --------------- */
  --sand: #FFFFFF;
  --card: #FFFFFF;
  --card-2: #F5F8FB;
  --ink: #1D1D20;
  --muted: #5F5F67;
  --rust: #1D4ED8;
  --rust-deep: #1E3A8A;
  --gold: #2563EB;
  --gold-soft: #E8EFFD;
  --moss: #1E40AF;
  --moss-deep: #1E3A8A;
  --moss-soft: #E0EAFF;
  --berry: #B91C1C;
  --berry-soft: #FDE8E8;
  --choco: #FFFFFF;

  /* Text-on-choco: used only inside choco surfaces (header, level banner). */
  --choco-ink: #1D1D20;
  --choco-muted: #5F5F67;
  --choco-line: #E4E7EC;
  --choco-line-soft: #D0D5DD;
  --choco-well: #F2F4F7;

  /* --- Mapped onto the names the rest of the app already uses ------------
     Kept so downstream CSS needs fewer rewrites: --brand is rust, --surface
     is card, --canvas is sand, --success is moss, --warning is gold,
     --danger stays a clear red distinct from rust so an error never reads
     as "the primary action colour". */
  --brand: var(--rust);
  --brand-dark: var(--rust-deep);
  --brand-soft: var(--gold-soft);
  --brand-border: var(--ink);
  /* --brand is the darker accent shade (--rust), so its label needs light
     text -- unlike --on-gold, which sits on the bright fill and stays dark. */
  --on-brand: #FFFFFF;

  --accent-ochre: #7D5309;
  --accent-ochre-soft: #FBF0DC;
  --accent-moss: var(--moss);
  --accent-moss-soft: var(--moss-soft);
  --accent-teal: #1B7A85;
  --accent-teal-soft: #D9EEF0;
  --accent-plum: var(--berry);
  --accent-plum-soft: var(--berry-soft);

  --ink-soft: #2E2E33;
  --subtle: var(--muted);
  --line: #E4E7EC;
  --line-strong: #858D9A;
  --surface: var(--card);
  --surface-muted: var(--card-2);
  --canvas: var(--sand);

  --success: var(--moss);
  --success-soft: var(--moss-soft);
  --warning: #7D5309;
  --warning-soft: #FBF0DC;
  --danger: #B91C1C;
  --danger-soft: #FDE8E8;

  --focus: rgba(37, 99, 235, .4);
  --overlay: rgba(5, 10, 25, .55);

  /* Text set directly on a full-strength accent fill (a current-step marker,
     an earned badge, an active pill). The fill stays a bright, saturated
     colour in both themes and across every accent by design, so this reads
     correctly against it without flipping the way --ink does for body text. */
  --on-gold: #FFFFFF;

  /* --- Shape language: thin glass edges, soft blurred elevation ----------
     Read scripts/check-contrast.mjs before changing any of these. */
  --edge: 1px;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow-md: 0 4px 14px rgba(16, 24, 40, .07);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, .10);
  --shadow-btn: none;
  --shadow-badge: none;

  /* Frosted glass: a blurred, saturated panel over a glowing ground. */
  --glass-bg: var(--surface);
  --glass-border: #E4E7EC;
  --glass-shadow: 0 1px 2px rgba(16, 24, 40, .05);
  --glass-highlight: transparent;
  --glass-blur: 0px;
  --glass-saturate: 100%;
  --page-glow-1: transparent;
  --page-glow-2: transparent;
  --page-glow-3: transparent;

  /* No halftone in the glass system -- the glow gradients carry the ground. */
  --grain: none;

  /* --- Radii: generous, so glass reads soft rather than cut -------------- */
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;
  --content: 1180px;

  /* --- Spacing, 4px base -------------------------------------------------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;

  /* --- Type: a bold wide display face, a warm humanist body face --------- */
  /* Calibri everywhere: headings, body, and numbers alike. */
  --font-display: Calibri, Carlito, "Segoe UI", Arial, sans-serif;
  --font-text: Calibri, Carlito, "Segoe UI", Arial, sans-serif;
  --font-mono: Calibri, Carlito, "Segoe UI", Arial, sans-serif;

  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 16px;
  --text-md: 17px;
  --text-lg: 20px;
  --text-xl: 25px;
  --text-2xl: 32px;
  --text-3xl: 40px;
  --text-4xl: 52px;
  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-normal: 1.55;
  --measure: 68ch;

  /* --- Motion: kept from the earlier system; the mockups are static. ----- */
  --motion-fast: 120ms;
  --motion-base: 220ms;
  --motion-slow: 420ms;
  --ease-out: cubic-bezier(.22, .61, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.26, .64, 1);
}

/*
  Dark: a black page with near-black cards, white text, and the blues
  lifted so links and actions stay bright and legible on black.
*/
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --placeholder: #8E99AB;
    color-scheme: dark;

    --sand: #0E1014;
    --card: #16191F;
    --card-2: #1C2028;
    --ink: #F3F4F6;
    --muted: #A3A9B5;
    --rust: #60A5FA;
    --rust-deep: #93C5FD;
    --gold: #2563EB;
    --gold-soft: #0F1E3D;
    --moss: #60A5FA;
    --moss-deep: #93C5FD;
    --moss-soft: #0F1E3D;
    --berry: #F87171;
    --berry-soft: #3B1414;
    --choco: #16191F;

    --choco-ink: #F3F4F6;
    --choco-muted: #A3A9B5;
    --choco-line: #262B34;
    --choco-line-soft: #323844;
    --choco-well: #0B0D10;

    --brand: var(--rust);
    --brand-dark: var(--rust-deep);
    --brand-soft: var(--gold-soft);
    --brand-border: var(--ink);
    --on-brand: #04101F;
    --on-gold: #FFFFFF;

    --accent-ochre: #F0BE55;
    --accent-ochre-soft: #3A2A0C;
    --accent-moss: var(--moss);
    --accent-moss-soft: var(--moss-soft);
    --accent-teal: #4FB8C4;
    --accent-teal-soft: #163338;
    --accent-plum: var(--berry);
    --accent-plum-soft: var(--berry-soft);

    --ink-soft: #E5E7EB;
    --subtle: var(--muted);
    --line: #262B34;
    --line-strong: #6B7383;
    --surface: var(--card);
    --surface-muted: var(--card-2);
    --canvas: var(--sand);

    --success: var(--moss);
    --success-soft: var(--moss-soft);
    --warning: #F0BE55;
    --warning-soft: #3A2A0C;
    --danger: #F87171;
    --danger-soft: #3B1414;

    --focus: rgba(96, 165, 250, .45);
    --overlay: rgba(0, 0, 0, .72);

    /* No halftone in the glass system -- the glow gradients carry the ground. */
    --grain: none;

    /* Glass over the void: a blurred, saturated panel with a soft dark drop
       and an accent-tinted glow under primary buttons rather than a hard
       ink-coloured offset. */
    --glass-bg: var(--surface);
    --glass-border: #262B34;
    --glass-shadow: 0 1px 2px rgba(0, 0, 0, .3);
    --glass-highlight: transparent;
    --glass-blur: 0px;
    --glass-saturate: 100%;
    --page-glow-1: transparent;
    --page-glow-2: transparent;
    --page-glow-3: transparent;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
    --shadow-md: 0 6px 18px rgba(0, 0, 0, .35);
    --shadow-lg: 0 14px 36px rgba(0, 0, 0, .45);
    --shadow-btn: none;
    --shadow-badge: none;
  }
}

:root[data-theme="dark"] {
  --placeholder: #8E99AB;
  color-scheme: dark;

  --sand: #0E1014;
  --card: #16191F;
  --card-2: #1C2028;
  --ink: #F3F4F6;
  --muted: #A3A9B5;
  --rust: #60A5FA;
  --rust-deep: #93C5FD;
  --gold: #2563EB;
  --gold-soft: #0F1E3D;
  --moss: #60A5FA;
  --moss-deep: #93C5FD;
  --moss-soft: #0F1E3D;
  --berry: #F87171;
  --berry-soft: #3B1414;
  --choco: #16191F;

  --choco-ink: #F3F4F6;
  --choco-muted: #A3A9B5;
  --choco-line: #262B34;
  --choco-line-soft: #323844;
  --choco-well: #0B0D10;

  --brand: var(--rust);
  --brand-dark: var(--rust-deep);
  --brand-soft: var(--gold-soft);
  --brand-border: var(--ink);
  --on-brand: #04101F;
  --on-gold: #FFFFFF;

  --accent-ochre: #F0BE55;
  --accent-ochre-soft: #3A2A0C;
  --accent-moss: var(--moss);
  --accent-moss-soft: var(--moss-soft);
  --accent-teal: #4FB8C4;
  --accent-teal-soft: #163338;
  --accent-plum: var(--berry);
  --accent-plum-soft: var(--berry-soft);

  --ink-soft: #E5E7EB;
  --subtle: var(--muted);
  --line: #262B34;
  --line-strong: #6B7383;
  --surface: var(--card);
  --surface-muted: var(--card-2);
  --canvas: var(--sand);

  --success: var(--moss);
  --success-soft: var(--moss-soft);
  --warning: #F0BE55;
  --warning-soft: #3A2A0C;
  --danger: #F87171;
  --danger-soft: #3B1414;

  --focus: rgba(96, 165, 250, .45);
  --overlay: rgba(0, 0, 0, .72);

  --grain: none;

  --glass-bg: var(--surface);
  --glass-border: #262B34;
  --glass-shadow: 0 1px 2px rgba(0, 0, 0, .3);
  --glass-highlight: transparent;
  --glass-blur: 0px;
  --glass-saturate: 100%;
  --page-glow-1: transparent;
  --page-glow-2: transparent;
  --page-glow-3: transparent;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
  --shadow-md: 0 6px 18px rgba(0, 0, 0, .35);
  --shadow-lg: 0 14px 36px rgba(0, 0, 0, .45);
  --shadow-btn: none;
  --shadow-badge: none;
}

/*
  Reduced motion, handled once for the whole application. The state still
  changes and no feedback is lost -- only the movement is removed.
*/
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  color-scheme: light;
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
  /* Scroll, but never pinch or double-tap zoom: it should behave like a
     phone app, not a web page. iOS ignores user-scalable=no in the viewport
     meta, so this (and the gesture handler in app.js) is what holds there. */
  touch-action: pan-x pan-y;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* One serif face, bold rather than a separate display cut -- the literal
   `h1, h2, h3 { margin: 0; font-weight: 700; }` rule every mockup sets. */
h1, h2, h3, h4,
.display {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: var(--leading-tight);
  text-wrap: balance;
}

/* Running prose stays inside a comfortable measure. */
.prose,
.prose p {
  max-width: var(--measure);
}

body.modal-open {
  overflow: hidden;
}

button,
input,
textarea,
select {
  color: inherit;
  font: inherit;
}

button,
a {
  -webkit-tap-highlight-color: transparent;
}

button {
  touch-action: manipulation;
}

a {
  color: var(--rust-deep);
  text-decoration: none;
}

a:hover {
  color: var(--ink);
}

img,
svg {
  display: block;
  max-width: 100%;
}

[hidden] {
  display: none !important;
}

.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.container {
  width: min(calc(100% - 40px), var(--content));
  margin-inline: auto;
}

.brand {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  gap: 12px;
  /* Body ink by default; the dark bars below switch it to white. */
  color: var(--ink);
  font-size: 25px;
  font-weight: 700;
  letter-spacing: .01em;
}

.app-header .brand,
.builder-topbar .brand {
  color: var(--choco-ink);
}

.brand-mark {
  display: grid;
  width: 72px;
  height: 44px;
  flex: 0 0 72px;
  padding: 4px 7px;
  place-items: center;
  /* The mark is navy and gold, so it sits on its own white card rather than
     on the dark header. */
  background: #fff;
  border-radius: 10px;
}

.brand-mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.app-header {
  position: sticky;
  z-index: 50;
  top: 0;
  height: calc(74px + var(--safe-top));
  padding-top: var(--safe-top);
  background: var(--choco);
  border-bottom: 1px solid var(--glass-border);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
}

.app-header-inner {
  display: flex;
  width: min(calc(100% - 40px), 1280px);
  height: 100%;
  margin-inline: auto;
  align-items: center;
  justify-content: space-between;
  gap: 26px;
}

.app-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}

.app-nav a {
  position: relative;
  display: inline-flex;
  min-height: 40px;
  padding: 0 15px;
  align-items: center;
  color: #E3D2B6;
  border-radius: var(--radius-pill);
  font-size: var(--text-md);
  font-weight: 700;
}

.app-nav a:hover {
  color: var(--choco-ink);
}

.app-nav a.active {
  color: var(--choco);
  background: var(--choco-ink);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.header-actions form {
  margin: 0;
}

.header-actions .icon-btn {
  color: var(--choco-ink);
  background: transparent;
  border-color: var(--choco-line);
}

.header-actions .icon-btn:hover {
  color: var(--gold);
  background: transparent;
}

.chip-gold {
  background: var(--gold);
  border-color: var(--choco-ink);
  color: var(--ink);
}

.app-header .chip:not(.chip-gold) {
  background: var(--choco-ink);
  border-color: var(--choco-ink);
  color: var(--ink);
}

.user-chip {
  display: flex;
  width: 40px;
  height: 40px;
  padding: 0;
  align-items: center;
  justify-content: center;
  color: var(--on-gold);
  background: var(--gold);
  border: var(--edge) solid var(--choco-ink);
  border-radius: var(--radius-pill);
  font-size: 18px;
  font-weight: 700;
}

/* The name text is kept for assistive tech and the header's own aria-label,
   collapsed visually so the chip stays the mockup's plain avatar circle. */
.user-chip span:last-child {
  display: none;
}

.user-chip:hover {
  background: var(--rust);
}

.user-avatar {
  display: contents;
}

.btn {
  display: inline-flex;
  min-height: 46px;
  padding: 0 20px;
  align-items: center;
  justify-content: center;
  gap: 9px;
  color: var(--ink);
  background: var(--card);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: var(--text-base);
  font-weight: 700;
  line-height: 1.2;
  transition:
    background-color var(--motion-fast) var(--ease-out),
    border-color var(--motion-fast) var(--ease-out),
    color var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out),
    transform var(--motion-fast) var(--ease-out);
}

/* A press should feel like a press. Transform only, so nothing reflows. */
.btn:active:not(:disabled),
.icon-btn:active:not(:disabled) {
  transform: scale(.98);
}

.btn:focus-visible,
.icon-btn:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
a:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.btn:disabled,
.icon-btn:disabled,
button:disabled {
  cursor: not-allowed;
  opacity: .55;
}

.btn-primary {
  color: var(--on-brand);
  background: var(--brand);
}

.btn-primary:hover {
  background: var(--brand-dark);
}

.btn-secondary {
  color: var(--ink);
  background: var(--card);
}

.btn-secondary:hover {
  background: var(--card-2);
}

.btn-danger {
  color: var(--card);
  background: var(--danger);
}

.btn-danger:hover {
  background: #8A2114;
}

.btn-small {
  min-height: 38px;
  padding: 0 13px;
  box-shadow: var(--shadow-badge);
  font-size: 14px;
}

.btn-link {
  min-height: 36px;
  padding: 0 6px;
  color: var(--rust-deep);
  background: transparent;
  border: 0;
  box-shadow: none;
}

.btn-link:active {
  transform: none;
}

.btn svg,
.icon-btn svg {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

.icon-btn {
  display: inline-grid;
  width: 42px;
  height: 42px;
  padding: 0;
  place-items: center;
  color: var(--ink);
  background: var(--card);
  border: var(--edge) solid var(--glass-border);
  border-radius: var(--radius);
  cursor: pointer;
}

.icon-btn:hover {
  color: var(--rust-deep);
  background: var(--card);
}

.mobile-menu-button {
  display: none;
}

/* Header theme control: CSS picks the icon from data-theme-mode so it is
   correct on first paint, before the deferred script runs. */
.theme-toggle svg {
  display: none;
}

:root:not([data-theme-mode="light"]):not([data-theme-mode="dark"]) .theme-toggle [data-theme-icon="system"],
:root[data-theme-mode="light"] .theme-toggle [data-theme-icon="light"],
:root[data-theme-mode="dark"] .theme-toggle [data-theme-icon="dark"] {
  display: block;
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.field {
  display: grid;
  gap: 7px;
}

.field label {
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 700;
}

.field input,
.field textarea,
.field select,
.input {
  width: 100%;
  min-height: 48px;
  padding: 0 13px;
  color: var(--ink);
  background: var(--card);
  border: var(--edge) solid var(--glass-border);
  border-radius: var(--radius-sm);
  outline: none;
  transition:
    border-color var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out),
    background-color var(--motion-fast) var(--ease-out),
    transform var(--motion-fast) var(--ease-out);
}

input::placeholder,
textarea::placeholder {
  color: var(--placeholder);
  opacity: 1;
}

.field input:focus,
.field textarea:focus,
.field select:focus {
  box-shadow: 0 0 0 3px var(--focus);
}

.field input:disabled,
.field textarea:disabled,
.field select:disabled {
  color: var(--muted);
  background: var(--card-2);
  cursor: not-allowed;
}

.field textarea {
  min-height: 116px;
  resize: vertical;
}

.field-hint,
.muted {
  color: var(--muted);
  font-size: 13px;
}

.form-errors {
  display: grid;
  gap: 3px;
}

.form-error {
  color: var(--danger);
  font-size: 12px;
  font-weight: 600;
}

/* A show/hide toggle docked inside a password field -- used wherever a
   password is collected outside the auth pages' own <form> (the builder's
   account-claim modal), not just on /register and /login themselves. */
.password-wrap {
  position: relative;
}

.password-wrap input {
  padding-right: 66px;
}

.password-wrap button {
  position: absolute;
  top: 50%;
  right: 7px;
  min-width: 48px;
  min-height: 34px;
  padding: 6px 8px;
  color: var(--brand-dark);
  background: transparent;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  font-size: 12px;
  font-weight: 750;
  transform: translateY(-50%);
}

.alert {
  display: flex;
  padding: 12px 14px;
  align-items: flex-start;
  gap: 10px;
  border: 1px solid;
  border-radius: 9px;
  font-size: 14px;
}

.alert-success {
  color: #126442;
  background: var(--success-soft);
  border-color: #badfce;
}

.alert-danger {
  color: #912036;
  background: var(--danger-soft);
  border-color: #f0c4cc;
}

.modal {
  position: fixed;
  z-index: 100;
  inset: 0;
  display: none;
  padding: 20px;
  align-items: center;
  justify-content: center;
  background: var(--overlay);
}

.modal.open {
  display: flex;
  animation: backdrop-in var(--motion-base) var(--ease-out);
}

.modal.open .modal-dialog {
  animation: dialog-in var(--motion-slow) var(--ease-spring);
}

@keyframes backdrop-in {
  from { opacity: 0; }
}

/* Arrivals may overshoot; nothing moves more than a few pixels. */
@keyframes dialog-in {
  from { opacity: 0; transform: scale(.97) translateY(6px); }
}

.modal-dialog {
  width: min(100%, 480px);
  max-height: calc(100vh - 40px);
  padding: 24px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.modal-header {
  display: flex;
  margin-bottom: 20px;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
}

.modal-header h2 {
  margin: 0;
  font-size: 21px;
  letter-spacing: -.02em;
}

.modal-actions {
  display: flex;
  margin-top: 22px;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 10px;
}

.toast-region {
  position: fixed;
  z-index: 200;
  right: 20px;
  bottom: 20px;
  display: grid;
  max-width: min(390px, calc(100vw - 40px));
  gap: 10px;
}

.toast {
  padding: var(--space-3) var(--space-4);
  color: #FFF6EE;
  background: #33261F;
  border: 1px solid rgba(255, 246, 238, .14);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm);
  animation: toast-in var(--motion-slow) var(--ease-spring);
}

.toast.error {
  background: #7A1C2B;
}

.toast.success {
  background: #1F5236;
}

/* Leaving is never a spring: it fades and settles. The class is added by
   app.js so the element is still there while it goes. */
.toast.is-leaving {
  animation: toast-out var(--motion-base) var(--ease-out) forwards;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
}

@keyframes toast-out {
  to { opacity: 0; transform: translateY(4px); }
}

.empty-state {
  padding: 48px 24px;
  color: var(--muted);
  text-align: center;
}

.empty-state-icon {
  display: grid;
  width: 52px;
  height: 52px;
  margin: 0 auto 16px;
  place-items: center;
  color: var(--brand);
  background: var(--brand-soft);
  border: 1px solid var(--brand-border);
  border-radius: 12px;
}

.empty-state h1,
.empty-state h2,
.empty-state h3 {
  margin: 0 0 8px;
  color: var(--ink);
  font-size: 21px;
  letter-spacing: -.02em;
}

.empty-state p {
  max-width: 520px;
  margin: 0 auto 20px;
}

.page-shell {
  min-height: calc(100vh - 68px);
  padding: 40px 0 64px;
}

.page-heading {
  display: flex;
  margin-bottom: 28px;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}

.eyebrow {
  margin: 0 0 8px;
  color: var(--brand-dark);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.page-heading h1 {
  margin: 0;
  font-size: clamp(28px, 4vw, 38px);
  letter-spacing: -.035em;
  line-height: 1.12;
}

.page-heading p {
  max-width: 640px;
  margin: 8px 0 0;
  color: var(--muted);
}

.spinner {
  width: 17px;
  height: 17px;
  border: 2px solid rgba(255, 255, 255, .38);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.error-page {
  display: grid;
  min-height: 100vh;
  padding: calc(32px + var(--safe-top)) 20px 32px;
  place-items: center;
}

.error-card {
  width: min(100%, 620px);
  padding: 48px 32px;
}

.error-wrap {
  width: min(100%, 620px);
}

.error-brand {
  display: flex;
  margin-bottom: 24px;
  justify-content: center;
}

.error-card .error-code {
  display: block;
  margin-bottom: 10px;
  color: var(--brand-dark);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* Below the width where the bottom navigation takes over (see
   .bottom-nav's own 900px rule), the header's own nav links and hamburger
   are redundant, so the top bar shrinks to brand, streak/XP, and account. */
@media (max-width: 900px) {
  .app-nav,
  .mobile-menu-button {
    display: none;
  }
}

@media (max-width: 640px) {
  .chip-full-label {
    display: none;
  }

  .chip-gold {
    padding: 0 10px;
  }
}

@media (max-width: 760px) {
  .container,
  .app-header-inner {
    width: min(calc(100% - 28px), var(--content));
  }

  .app-header {
    height: calc(62px + var(--safe-top));
  }

  .app-header-inner {
    position: relative;
  }

  .page-shell {
    min-height: calc(100vh - 64px);
    padding: 28px 0 48px;
  }

  .page-heading {
    align-items: flex-start;
    flex-direction: column;
  }

  .modal {
    padding: 12px;
  }

  .modal-dialog {
    max-height: calc(100vh - 24px);
    padding: 20px;
  }
}

@media (max-width: 480px) {
  .brand > span:last-child {
    font-size: 17px;
  }

  .modal-actions {
    align-items: stretch;
    flex-direction: column-reverse;
  }

  .modal-actions .btn {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .app-header .brand > span:last-child {
    display: none;
  }
}

/* ==========================================================================
   Touch and small screens
   Shared corrections for phones and small tablets. Component stylesheets load
   after this one, so anything they set at a higher specificity is corrected in
   their own files rather than fought with !important here.
   ========================================================================== */

@media (max-width: 820px) {
  /* iOS Safari zooms the whole viewport when a focused control has type
     smaller than 16px, and there is no way back without a pinch. Every form
     control therefore reaches 16px on touch-sized screens. */
  input,
  textarea,
  select,
  .field input,
  .field textarea,
  .field select,
  .input {
    font-size: 16px;
  }

  /* A finger needs roughly 44px. The desktop sizes are comfortable with a
     mouse but too tight to hit reliably by thumb. */
  .btn,
  .btn-small,
  .btn-link {
    min-height: 44px;
  }

  .icon-btn {
    width: 44px;
    height: 44px;
  }

  .field-hint,
  .muted {
    font-size: 12px;
  }

  .error-card .error-code {
    font-size: 12px;
  }
}

/* Notched and rounded phones: keep content clear of the status bar, the home
   indicator, and the rounded corners in landscape. */
@supports (padding: max(0px)) {
  .app-header-inner {
    padding-right: max(0px, env(safe-area-inset-right));
    padding-left: max(0px, env(safe-area-inset-left));
  }

  .page-shell {
    padding-bottom: calc(48px + env(safe-area-inset-bottom));
  }
}

/* Mobile browser chrome makes 100vh taller than the visible area, which pushes
   the bottom of a full-height screen under the address bar. dvh tracks the
   area actually on screen. */
@supports (height: 100dvh) {
  .page-shell {
    min-height: calc(100dvh - 68px);
  }
}

/* A long email, URL, or CV name should wrap rather than widen the page. */
.container,
.page-shell,
.modal-dialog {
  overflow-wrap: break-word;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ==========================================================================
   Install prompt
   Offered from the app rather than left to the browser, so it can be dismissed
   for good and never covers the bottom navigation on a phone.
   ========================================================================== */

.install-banner {
  position: fixed;
  z-index: 60;
  right: 16px;
  bottom: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom));
  left: 16px;
  display: flex;
  max-width: 420px;
  margin-inline: auto;
  padding: 12px 14px;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
}

.install-banner p {
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
}

.install-banner-actions {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 8px;
}

.install-banner-close {
  width: 36px;
  height: 36px;
  font-size: 20px;
  line-height: 1;
}

/* The builder already owns the bottom of a phone screen with its own view
   switcher, so the banner sits above it. */
.builder-page .install-banner {
  bottom: calc(76px + env(safe-area-inset-bottom));
}

@media (max-width: 820px) {
  .install-banner-close {
    width: 44px;
    height: 44px;
  }
}

/* ==========================================================================
   Surfaces and the bottom navigation — Glass.

   Depth is blur and translucency now, not a hard ink-coloured offset: every
   card and modal is a frosted pane (--glass-blur/--glass-saturate) floating
   over the page's own glow gradients, rather than a flat cutout sitting on
   halftone paper.
   ========================================================================== */

/* Three soft radial glows behind everything -- the ground glass floats on. */
body {
  background-color: var(--sand);
  background-image:
    radial-gradient(52% 40% at 14% 0%, var(--page-glow-1), transparent 62%),
    radial-gradient(44% 36% at 92% 18%, var(--page-glow-2), transparent 60%),
    radial-gradient(60% 46% at 50% 100%, var(--page-glow-3), transparent 64%);
  background-attachment: fixed;
}

.card,
.modal-dialog {
  background: var(--card);
  border: var(--edge) solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
}

/* Hovering lifts a glass card toward the viewer -- more blur-shadow, not a
   press into a hard offset. */
.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.btn {
  border: var(--edge) solid var(--glass-border);
  box-shadow: var(--shadow-btn);
}

.btn:active:not(:disabled) {
  transform: scale(.97);
  box-shadow: none;
}

/* A pill-shaped label, used across the header, quests, badges, and rewards. */
.chip {
  display: inline-flex;
  height: 34px;
  padding: 0 13px;
  align-items: center;
  gap: 7px;
  border: var(--edge) solid var(--glass-border);
  border-radius: var(--radius-pill);
  background: var(--card);
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 700;
}

.chip svg {
  width: 15px;
  height: 15px;
  flex: none;
}

.chip-small {
  height: 28px;
  padding: 0 11px;
  font-size: 13px;
}

/* ==========================================================================
   Bottom navigation. Mobile and tablet only; the header keeps the desktop.
   Ported from Phone.dc.html: a pill bar with a raised centre action.
   ========================================================================== */
.bottom-nav {
  position: fixed;
  z-index: 90;
  right: 0;
  bottom: 0;
  left: 0;
  display: none;
  padding: 10px 12px 14px;
  padding-bottom: calc(14px + env(safe-area-inset-bottom));
  justify-content: center;
}

.bottom-nav-inner {
  display: flex;
  width: min(100%, 460px);
  padding: 5px;
  align-items: center;
  gap: 3px;
  background: var(--card);
  border: var(--edge) solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: visible;
}

.bottom-nav-item {
  display: flex;
  flex: 1;
  min-height: 54px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  color: var(--muted);
  text-decoration: none;
  border-radius: var(--radius-sm);
  font-size: 11px;
  font-weight: 700;
}

.bottom-nav-item svg {
  width: 20px;
  height: 20px;
  flex: none;
}

.bottom-nav-item[aria-current="page"] {
  color: var(--on-gold);
  background: var(--gold);
}

.bottom-nav-item:hover:not([aria-current="page"]) {
  color: var(--ink);
  background: var(--card-2);
}

.bottom-nav-item:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.bottom-nav-item:active {
  transform: scale(.97);
}

/* The raised centre action, ported from Phone.dc.html's own FAB. */
.bottom-nav-fab {
  display: flex;
  width: 54px;
  height: 54px;
  margin: -18px 2px 0;
  flex: none;
  align-items: center;
  justify-content: center;
  color: var(--card);
  background: var(--rust);
  border: var(--edge) solid var(--glass-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-btn);
  transition:
    transform var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out);
}

.bottom-nav-fab svg {
  width: 24px;
  height: 24px;
}

.bottom-nav-fab:active {
  transform: scale(.94);
  box-shadow: none;
}

.bottom-nav-fab:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}

/* The bar needs room for the button that rises out of it. */
.bottom-nav-inner:has(.bottom-nav-fab) {
  overflow: visible;
}

@media (max-width: 900px) {
  .bottom-nav {
    display: flex;
  }

  /* Room so the bar never covers the last row of content. */
  body:has(.bottom-nav) .page-shell {
    padding-bottom: calc(104px + env(safe-area-inset-bottom));
  }
}

/* Printing a CV must never carry app chrome onto the page. */
@media print {
  .bottom-nav,
  .install-banner {
    display: none !important;
  }
}

/* Phone header. The top bar has to hold the logo, theme switch, streak,
   account and sign-out in one row. These rules come after .chip so they win
   over it -- written before it, the XP chip stayed visible and the row ran
   past the screen edge, which let the whole page slide sideways. */
@media (max-width: 640px) {
  .app-header .chip-gold {
    padding: 0 10px;
  }

  .app-header .header-actions {
    gap: 8px;
  }

  .app-header-inner {
    gap: 12px;
  }
}

/* The logo mark alone carries the brand where the wordmark will not fit. */
@media (max-width: 480px) {
  .app-header .brand > span:last-child {
    display: none;
  }
}

/* Installed on a phone, the app starts right under the status bar with no
   browser toolbar in between; a tap on the top bar should not land on the
   status bar or pull down the notification shade. */
@media (display-mode: standalone), (display-mode: minimal-ui) {
  :root {
    --safe-top: max(env(safe-area-inset-top, 0px), 14px);
  }
}

/* ==========================================================================
   Flat, airy surfaces
   Pill-shaped buttons with no glow, cards on a thin border, and a plain
   top bar whose links are grey until chosen.
   ========================================================================== */
.btn {
  border-radius: var(--radius-pill);
  box-shadow: none;
  font-weight: 700;
}

.btn:hover {
  transform: none;
}

.card,
.modal-dialog {
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}

.app-nav a {
  color: var(--choco-muted);
  background: transparent;
  font-weight: 700;
}

.app-nav a:hover {
  color: var(--choco-ink);
  background: var(--choco-well);
}

.app-nav a.active {
  color: var(--brand);
  background: var(--brand-soft);
}

.app-header {
  box-shadow: 0 1px 0 var(--line);
}

h1,
h2,
h3 {
  letter-spacing: 0;
}

/* ==========================================================================
   Premium finish
   Purely visual: depth, light, and motion on things people touch. Nothing
   here changes layout, sizes, or colours of text, so contrast is unchanged.
   Movement is removed by the reduced-motion rule near the top of the file.
   ========================================================================== */
:root {
  --glow: rgba(29, 78, 216, .28);
  --glow-soft: rgba(29, 78, 216, .14);
  --lift-shadow: 0 10px 24px -8px rgba(16, 24, 40, .18), 0 2px 6px rgba(16, 24, 40, .06);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --glow: rgba(96, 165, 250, .32);
    --glow-soft: rgba(96, 165, 250, .16);
    --lift-shadow: 0 12px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px rgba(0, 0, 0, .35);
  }
}

:root[data-theme="dark"] {
  --glow: rgba(96, 165, 250, .32);
  --glow-soft: rgba(96, 165, 250, .16);
  --lift-shadow: 0 12px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px rgba(0, 0, 0, .35);
}

::selection {
  color: var(--on-brand);
  background: var(--brand);
}

/* ---- Buttons ------------------------------------------------------------ */
.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition:
    background-color var(--motion-base) var(--ease-out),
    border-color var(--motion-base) var(--ease-out),
    color var(--motion-base) var(--ease-out),
    box-shadow var(--motion-base) var(--ease-out),
    transform var(--motion-base) var(--ease-spring);
}

.btn:hover:not(:disabled) {
  transform: translateY(-1px);
}

.btn:active:not(:disabled) {
  transform: translateY(0) scale(.98);
  transition-duration: 60ms;
}

/* Primary: a soft top-light, a coloured glow, and a sheen that sweeps
   across on hover. */
.btn-primary {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .14), rgba(255, 255, 255, 0) 60%);
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .12), 0 4px 12px -2px var(--glow-soft), inset 0 1px 0 rgba(255, 255, 255, .18);
}

.btn-primary:hover:not(:disabled) {
  box-shadow: 0 2px 4px rgba(16, 24, 40, .12), 0 10px 24px -6px var(--glow), inset 0 1px 0 rgba(255, 255, 255, .22);
}

.btn-primary::after {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  left: -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .28), transparent);
  transform: skewX(-18deg) translateX(0);
  transition: transform 700ms var(--ease-out);
  pointer-events: none;
}

.btn-primary:hover:not(:disabled)::after {
  transform: skewX(-18deg) translateX(420%);
}

/* Secondary: an outlined pill that fills faintly with the brand tint. */
.btn-secondary:hover:not(:disabled) {
  color: var(--ink);
  background: var(--brand-soft);
  border-color: var(--brand);
  box-shadow: 0 6px 16px -8px var(--glow);
}

.btn-danger {
  box-shadow: 0 4px 12px -4px rgba(185, 28, 28, .35);
}

.btn-danger:hover:not(:disabled) {
  box-shadow: 0 10px 22px -8px rgba(185, 28, 28, .5);
}

.btn-link {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 6px calc(100% - 7px);
  background-size: 0 1.5px;
  transition: background-size var(--motion-base) var(--ease-out), color var(--motion-fast) var(--ease-out);
}

.btn-link:hover:not(:disabled) {
  transform: none;
  background-size: calc(100% - 12px) 1.5px;
}

.btn svg {
  transition: transform var(--motion-base) var(--ease-spring);
}

.btn:hover:not(:disabled) svg {
  transform: translateX(1px) scale(1.06);
}

/* Icon buttons: a round lift with a tinted ring. */
.icon-btn {
  transition:
    background-color var(--motion-base) var(--ease-out),
    border-color var(--motion-base) var(--ease-out),
    color var(--motion-base) var(--ease-out),
    box-shadow var(--motion-base) var(--ease-out),
    transform var(--motion-base) var(--ease-spring);
}

.icon-btn:hover:not(:disabled) {
  color: var(--brand);
  background: var(--brand-soft);
  border-color: var(--brand);
  box-shadow: 0 6px 16px -8px var(--glow);
  transform: translateY(-1px);
}

.theme-toggle:hover:not(:disabled) svg {
  transform: rotate(18deg);
  transition: transform var(--motion-slow) var(--ease-spring);
}

/* ---- Cards -------------------------------------------------------------- */
.card {
  transition:
    transform var(--motion-base) var(--ease-out),
    box-shadow var(--motion-base) var(--ease-out),
    border-color var(--motion-base) var(--ease-out);
}

.card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--brand) 30%, var(--line));
  box-shadow: var(--lift-shadow);
}

/* Forms and dialogs are cards too, but should hold still while typed in. */
.card:has(input:focus, textarea:focus, select:focus),
.modal-dialog.card:hover {
  transform: none;
}

/* ---- Fields ------------------------------------------------------------- */
.field input:hover:not(:focus):not(:disabled),
.field textarea:hover:not(:focus):not(:disabled),
.field select:hover:not(:focus):not(:disabled),
.input:hover:not(:focus):not(:disabled) {
  border-color: var(--line-strong);
}

.field input:focus,
.field textarea:focus,
.field select:focus,
.input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 4px var(--glow-soft);
}

/* ---- Navigation --------------------------------------------------------- */
.app-nav a {
  transition: color var(--motion-fast) var(--ease-out), background-color var(--motion-base) var(--ease-out);
}

.app-header {
  background: color-mix(in srgb, var(--choco) 86%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
}

.user-chip {
  transition: transform var(--motion-base) var(--ease-spring), box-shadow var(--motion-base) var(--ease-out);
}

.user-chip:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 0 3px var(--glow-soft);
}

.bottom-nav-inner {
  background: color-mix(in srgb, var(--card) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  box-shadow: var(--lift-shadow);
}

.bottom-nav-item {
  transition: color var(--motion-fast) var(--ease-out), background-color var(--motion-base) var(--ease-out), transform var(--motion-base) var(--ease-spring);
}

.bottom-nav-fab {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, 0) 60%);
  box-shadow: 0 8px 20px -6px var(--glow);
}

.bottom-nav-fab:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 26px -6px var(--glow);
}

.chip {
  transition: border-color var(--motion-base) var(--ease-out), background-color var(--motion-base) var(--ease-out);
}

a.chip:hover,
button.chip:hover {
  border-color: var(--brand);
  background: var(--brand-soft);
}

/* ---- Scrollbars --------------------------------------------------------- */
html {
  scrollbar-color: var(--line-strong) transparent;
}

@media print {
  .btn,
  .card {
    box-shadow: none !important;
    transform: none !important;
  }
}
