/* TalkWebe — Design system (blue-gray redesign tokens) */
:root {
  /* Canonical tokens */
  --primary: #2F6FED;
  --primary-light: #EAF1FF;
  --success: #16A34A;
  --success-light: #EAF7EE;
  --border-color: #E5E7EB;
  --bg: #F7F8FA;
  --text: #1F2430;
  --text-muted: #6B7280;
  --radius: 10px;
  /* Flat level: a card resting on the page. Raised and overlay levels are
     --shadow-md / --shadow-lg below — previously all three were this same
     value, so nothing could read as being in front of anything else. */
  --shadow: 0 1px 2px rgba(16, 24, 40, .04);

  /* Typography — aliases onto the one scale defined under "Type scale" below.
     These four used to be independent literals, which meant the ~47 existing
     `var(--fs-*)` call sites sat on a second, parallel scale that drifted from
     `var(--text-*)`. One scale, two spellings. */
  --fs-page: var(--text-2xl);
  --fs-card: var(--text-lg);
  --fs-body: var(--text-sm);
  --fs-aux: var(--text-xs);

  /* Backward-compatible aliases */
  --color-primary: var(--primary);
  --color-primary-dark: #1d5ad6;
  --color-accent: var(--success);
  --color-accent-dark: #15803d;
  --color-bg: var(--bg);
  --color-bg-subtle: var(--primary-light);
  --color-bg-elevated: #ffffff;
  --color-surface: rgba(255, 255, 255, 0.92);
  --color-border: var(--border-color);
  --color-border-strong: #d1d5db;
  --color-text: var(--text);
  --color-muted: var(--text-muted);
  --color-danger: #ef4444;
  --color-warn: #d97706;
  --gradient-brand: var(--primary);
  --gradient-brand-hover: var(--color-primary-dark);
  --shadow-card: var(--shadow);
  --shadow-sm: var(--shadow);
  /* Three steps, not one value stamped on everything: controls and chips are
     small, cards and panels medium, modals and overlays large. */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  /* Latin faces first, then CJK: the browser resolves per glyph, so Latin text
     comes from the UI font and CJK from the first face that has the glyph.
     Previously only PingFang SC was listed, which left Windows and Traditional
     Chinese users on an unpredictable fallback. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue",
          "PingFang SC", "PingFang TC", "Hiragino Sans GB", "Microsoft YaHei",
          "Noto Sans CJK SC", "Noto Sans SC", Arial, sans-serif;
  --accent: var(--primary);
  --border: 1px solid var(--border-color);
  --muted: var(--text-muted);
  --green: var(--success);
  --blue: var(--primary);
  --red: var(--color-danger);

  /* Density — the knobs .density-compact turns. Default values are the
     comfortable (product) setting; data-heavy pages opt into the tight one by
     putting `density-compact` on <body>. Components read these instead of
     writing their own px, so one class changes a whole page coherently. */
  --row-pad-y: 14px;      /* list row / control vertical padding */
  --row-pad-x: 18px;      /* list row horizontal padding */
  --card-pad: 20px;       /* card and panel inner padding */
  --section-gap: 32px;    /* gap between page sections */
  --page-max: 1100px;     /* content column width */
  --page-gutter: 32px;    /* page side padding */

  /* 8px spacing grid */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 32px;
  --space-6: 48px;

  /* Type scale — fallback values. The live ones are in the
     html[data-font-scale="..."] blocks further down, which sit on the same
     element at higher specificity; keep the two in step.
     Previously --text-xl and --text-2xl were BOTH 17px, so h1 and h2 rendered
     at the same size and four of the six steps sat within 1.5px of each other:
     nothing on the page could read as a heading. Four distinct steps now —
     page title / section title / row title / body — with captions below. */
  --text-xs: 11.5px;    /* captions, meta, badges */
  --text-sm: 12.5px;    /* secondary text, labels, buttons */
  --text-base: 13.5px;  /* body */
  --text-lg: 15px;      /* h3 / row title */
  --text-xl: 18px;      /* h2 / section title */
  --text-2xl: 26px;     /* h1 / page title */
  --leading-tight: 1.3;
  /* 1.6 rather than 1.5: CJK glyphs fill the em box, so Chinese text needs more
     leading than Latin at the same size to stay readable in mixed zh/en copy. */
  --leading-normal: 1.6;
  --leading-relaxed: 1.75;
  --font-medium: 500;
  --font-semibold: 600;
  --font-bold: 700;

  /* Neutral elevation — three real levels: resting, raised, overlay. */
  --shadow-xs: var(--shadow);
  --shadow-md: 0 2px 8px rgba(16, 24, 40, 0.07), 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.10), 0 2px 6px rgba(16, 24, 40, 0.05);
  --focus-ring: 0 0 0 3px rgba(47, 111, 237, 0.25);

  /* Danger surface (was inlined as #fef2f2 in several pages) */
  --danger-light: #FEF2F2;

  /* Shared transition durations */
  --transition-fast: 0.15s ease;
  --transition-base: 0.2s ease;
}

/* ==========================================================================
   Compact density — for pages that are read as data rather than as documents:
   tracker, history, job picker, usage. Same four type steps, tightened; square
   -er corners; hairline borders instead of shadows (every surface that drops a
   shadow here already carries a 1px border, so it stays a distinct object);
   a wider column, because tables want the width.
   Put `density-compact` on <body>. Do not use it to shrink a page that simply
   has too much padding — fix the padding.
   ========================================================================== */
.density-compact {
  --text-xs: var(--dense-xs);
  --text-sm: var(--dense-sm);
  --text-base: var(--dense-base);
  --text-lg: var(--dense-lg);
  --text-xl: var(--dense-xl);
  --text-2xl: var(--dense-2xl);

  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;

  --shadow: none;
  --shadow-xs: none;
  --shadow-sm: none;
  --shadow-card: none;
  --shadow-md: none;

  --row-pad-y: 7px;
  --row-pad-x: 14px;
  --card-pad: 14px;
  --section-gap: 20px;
  --page-max: 1440px;
  --page-gutter: 24px;
}

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

/* Several pages define a class (e.g. a local .panel) that sets its own
   `display`, which — at equal specificity — beats the browser's built-in
   `[hidden]{display:none}` default. That silently left `hidden` elements
   fully visible (e.g. interview.html's empty workspace editor rendering as
   a large blank block even with no booklet loaded). `!important` makes the
   `hidden` attribute always win, matching what every author actually wants. */
[hidden] { display: none !important; }

body {
  font-family: var(--font);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body.standalone {
  min-height: 100vh;
}

h1, h2, h3, h4 {
  line-height: var(--leading-tight);
  font-weight: var(--font-semibold);
  color: var(--color-text);
}

h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-base); }

.page-title {
  font-size: var(--fs-page);
  font-weight: var(--font-bold);
  margin-bottom: var(--space-2);
  color: var(--text);
}

.page-sub, .sub {
  font-size: var(--text-sm);
  color: var(--color-muted);
  line-height: var(--leading-relaxed);
  margin-bottom: var(--space-4);
}

/* Standalone topbar */
.app-topbar {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  height: 52px;
  padding: 0 var(--space-4);
  background: var(--color-bg-elevated);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-xs);
  position: sticky;
  top: 0;
  z-index: 100;
}
body.standalone .app-topbar { display: flex; }

.back-home {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-bg-elevated);
  color: var(--color-text);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  white-space: nowrap;
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.back-home:hover {
  background: var(--color-bg-subtle);
  border-color: var(--color-border-strong);
}
.back-home:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.topbar-title {
  flex: 1;
  text-align: center;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--color-text);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.topbar-actions a {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-bg-elevated);
  color: var(--color-muted);
  text-decoration: none;
  font-size: var(--text-sm);
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.topbar-actions a:hover {
  color: var(--color-primary);
  border-color: var(--color-border-strong);
  background: var(--color-bg-subtle);
}
.topbar-actions a:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  min-height: 36px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-elevated);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-text);
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.btn:hover:not(:disabled) {
  border-color: var(--color-border-strong);
  background: var(--color-bg-subtle);
}
.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.btn-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border: 2px solid rgba(0, 0, 0, 0.15);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}
.btn-primary.btn-loading::after {
  border-color: rgba(255, 255, 255, 0.4);
  border-top-color: #fff;
}
@keyframes btn-spin {
  to { transform: rotate(360deg); }
}

.btn-sm {
  min-height: 32px;
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
}

.btn-lg {
  min-height: 44px;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-base);
}

.btn-primary {
  background: var(--primary);
  color: #fff;
  border-color: transparent;
  box-shadow: var(--shadow-xs);
}
.btn-primary:hover:not(:disabled) {
  background: var(--color-primary-dark);
  box-shadow: var(--shadow-sm);
}

.btn-secondary {
  background: var(--color-bg-elevated);
  color: var(--color-primary-dark);
  border-color: var(--color-border-strong);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--color-bg-subtle);
}

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--color-muted);
}
.btn-ghost:hover:not(:disabled) {
  background: var(--color-bg-subtle);
  color: var(--color-text);
  border-color: transparent;
}

/* Form fields */
.field { margin-bottom: var(--space-3); }
.field label, .field-label {
  display: block;
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--color-muted);
  margin-bottom: var(--space-2);
  letter-spacing: 0.01em;
}
.field-hint {
  font-size: var(--text-xs);
  color: var(--color-muted);
  margin-top: var(--space-1);
  line-height: var(--leading-relaxed);
}
.field-error {
  font-size: var(--text-xs);
  color: var(--color-danger);
  margin-top: var(--space-1);
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="search"],
input[type="url"],
select,
textarea {
  width: 100%;
  min-height: 40px;
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--text-sm);
  color: var(--color-text);
  background: var(--color-bg-elevated);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
textarea {
  min-height: 80px;
  padding: var(--space-2) var(--space-3);
  line-height: var(--leading-relaxed);
  resize: vertical;
}
input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--focus-ring);
}
input::placeholder,
textarea::placeholder { color: var(--color-muted); opacity: 0.7; }

.row {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.row .field { flex: 1; min-width: 200px; }

/* Tabs */
.tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--space-4);
  overflow-x: auto;
}
.tab {
  padding: var(--space-2) var(--space-3);
  border: none;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.tab:hover { color: var(--color-text); }
.tab.active {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
}
.tab:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.panel { display: none; }
.panel.active { display: block; animation: panel-fade-in var(--transition-base); }
@keyframes panel-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Cards */
.card, .life-card {
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--card-pad);
  box-shadow: var(--shadow-xs);
  transition: box-shadow 0.15s ease;
}
.card:hover, .life-card:hover { box-shadow: var(--shadow-md); }
.life-card h3, .card h3 {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  margin-bottom: var(--space-3);
  color: var(--color-text);
}

.stat-card {
  background: var(--color-bg-elevated);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: var(--space-3);
  text-align: center;
  box-shadow: var(--shadow);
}
.stat-num {
  font-size: var(--fs-page);
  font-weight: var(--font-bold);
  color: var(--primary);
}
.stat-label {
  font-size: var(--fs-aux);
  color: var(--text-muted);
  margin-top: 4px;
}

/* Tables */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
}
.table, .users-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.table th, .table td,
.users-table th, .users-table td {
  padding: var(--space-2) var(--space-3);
  text-align: left;
  border-bottom: 1px solid var(--color-border);
}
.table th, .users-table th {
  background: var(--color-bg-subtle);
  font-weight: var(--font-semibold);
  font-size: var(--text-xs);
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  position: sticky;
  top: 0;
}
.table tbody tr:hover, .users-table tbody tr:hover {
  background: var(--color-bg-subtle);
}
.table tbody tr:last-child td,
.users-table tbody tr:last-child td { border-bottom: none; }

/* Badges */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  border-radius: 999px;
  line-height: 1.4;
}
.badge-success { background: var(--color-bg-subtle); color: var(--color-accent-dark); }
.badge-warn { background: #fffbeb; color: var(--color-warn); }
.badge-muted { background: var(--color-bg-subtle); color: var(--color-muted); }
.badge-danger { background: #fef2f2; color: var(--color-danger); }

.badge-new {
  display: inline-block;
  margin-left: var(--space-1);
  padding: 1px 6px;
  font-size: 0.65rem;
  font-weight: var(--font-bold);
  color: #fff;
  background: var(--primary);
  border-radius: 4px;
  vertical-align: middle;
}
.status-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  font-size: var(--fs-aux);
  font-weight: var(--font-medium);
  border-radius: 999px;
  background: #f3f4f6;
  color: var(--text-muted);
  white-space: nowrap;
}
.status-badge.success {
  background: var(--success-light);
  color: var(--success);
}
.status-badge.primary {
  background: var(--primary-light);
  color: var(--primary);
}
.badge-recommend {
  color: var(--color-accent-dark);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
}

/* Progress */
.progress-bar {
  background: var(--color-bg-subtle);
  border-radius: var(--radius-sm);
  height: 8px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: var(--primary);
  border-radius: var(--radius);
  transition: width 0.3s ease;
}

/* Hints & test results */
.hint-box {
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-muted);
  line-height: var(--leading-relaxed);
}
.hint-box a { color: var(--color-primary); }

.test-result { font-size: var(--text-sm); color: var(--color-muted); }
.test-result.ok { color: var(--color-accent-dark); }
.test-result.err { color: var(--color-danger); }

.test-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-3);
}

/* Empty state */
.empty-state {
  text-align: center;
  padding: var(--space-6) var(--space-4);
  color: var(--color-muted);
}
.empty-state h3 {
  font-size: var(--text-lg);
  color: var(--color-text);
  margin-bottom: var(--space-2);
}
.empty-state p {
  font-size: var(--text-sm);
  max-width: 360px;
  margin: 0 auto var(--space-3);
  line-height: var(--leading-relaxed);
}

/* Skeleton loading */
.skeleton {
  background: linear-gradient(90deg, #eef0f3 25%, #f7f8fa 50%, #eef0f3 75%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.2s ease-in-out infinite;
  border-radius: var(--radius);
}
.skeleton-line {
  height: 10px;
  margin-bottom: var(--space-2);
  border-radius: 4px;
  background: #e5e7eb;
}
.skeleton-line:last-child { width: 70%; margin-bottom: 0; }
@keyframes skeleton-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── Redesign shared components (3.1–3.5) ── */

/* 3.2 Chip filter */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  background: #fff;
  color: var(--text-muted);
  font-size: var(--fs-body);
  font-weight: var(--font-medium);
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  line-height: 1.3;
}
.chip:hover {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--primary-light);
}
.chip.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: var(--space-3);
}
/* Multi-select variant. Plain .chip.active is used for single-select groups
   (font size, view mode) where "one is highlighted" reads correctly; in a
   multi-select filter every chip can be on at once, which otherwise looks like
   a row of pressed buttons with no way to tell on from off. */
.chip-toggle::before {
  content: "";
  display: inline-block;
  width: 0;
  overflow: hidden;
  transition: width var(--transition-fast);
}
.chip-toggle.active::before {
  content: "✓";
  width: auto;
  margin-right: 2px;
  font-weight: var(--font-bold);
}

/* Custom dropdown — progressive-enhancement wrapper around <select>, see dropdown.js */
.dropdown {
  position: relative;
  display: inline-block;
  width: 100%;
}
.dropdown-native {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
}
.dropdown-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  min-height: 40px;
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-elevated);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
}
.dropdown-trigger:hover { border-color: var(--color-border-strong); }
.dropdown-trigger:focus-visible,
.dropdown.open .dropdown-trigger {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--focus-ring);
}
.dropdown-trigger-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dropdown-caret {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--color-muted);
  border-bottom: 2px solid var(--color-muted);
  transform: rotate(45deg);
  margin-top: -4px;
  transition: transform var(--transition-fast);
}
.dropdown.open .dropdown-trigger .dropdown-caret {
  transform: rotate(-135deg);
  margin-top: 3px;
}
.dropdown-trigger.disabled { opacity: 0.45; cursor: not-allowed; }

.dropdown-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 400;
  max-height: 280px;
  overflow-y: auto;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  padding: var(--space-1);
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--transition-fast), transform var(--transition-fast), visibility 0s linear var(--transition-fast);
}
.dropdown.open .dropdown-list {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity var(--transition-fast), transform var(--transition-fast), visibility 0s linear 0s;
}
.dropdown-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--color-text);
  cursor: pointer;
  transition: background 0.1s ease, color 0.1s ease;
}
.dropdown-option:hover,
.dropdown-option.highlighted {
  background: var(--color-bg-subtle);
  color: var(--color-primary);
}
.dropdown-option.selected {
  color: var(--color-primary);
  font-weight: var(--font-semibold);
}
.dropdown-option.selected::after {
  content: "\2713";
  font-weight: var(--font-bold);
}
.dropdown-option[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* 3.1 Pick card (list → avatar card) */
.pick-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  background: #fff;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: border-color 0.15s, background 0.15s;
}
.pick-card:hover {
  border-color: var(--primary);
  background: var(--primary-light);
}
.pick-card.selected,
.pick-card.active {
  border-color: var(--primary);
  background: var(--primary-light);
}
.pick-card-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: #fff;
  flex-shrink: 0;
  background: var(--primary);
}
.pick-card-body {
  flex: 1;
  min-width: 0;
}
.pick-card-title {
  font-size: var(--fs-card);
  font-weight: var(--font-semibold);
  color: var(--text);
  line-height: 1.3;
}
.pick-card-sub {
  font-size: var(--fs-aux);
  color: var(--text-muted);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 3.5 Template thumbnail grid */
.template-thumb-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.template-thumb {
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: 10px;
  background: #fff;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: border-color 0.15s, background 0.15s;
}
.template-thumb:hover {
  border-color: var(--primary);
}
.template-thumb.active,
.template-thumb.selected {
  border: 2px solid var(--primary);
  background: var(--primary-light);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 40%, transparent);
}
.thumb-preview {
  height: 72px;
  border-radius: 6px;
  background: #f3f4f6;
  padding: 8px;
  margin-bottom: 8px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  overflow: hidden;
}
.thumb-preview.sidebar {
  flex-direction: row;
  gap: 6px;
}
.thumb-preview.sidebar .thumb-side {
  width: 22%;
  background: #d1d5db;
  border-radius: 3px;
  height: 100%;
}
.thumb-preview.sidebar .thumb-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.thumb-preview.topbar .thumb-bar {
  height: 10px;
  background: #9ca3af;
  border-radius: 2px;
  margin-bottom: 2px;
}
.thumb-line {
  height: 5px;
  background: #d1d5db;
  border-radius: 2px;
}
.thumb-line.w60 { width: 60%; }
.thumb-line.w80 { width: 80%; }
.thumb-line.w40 { width: 40%; }
.thumb-line.w90 { width: 90%; }
.template-thumb .name {
  font-size: var(--fs-card);
  font-weight: var(--font-semibold);
  color: var(--text);
}
.template-thumb .desc {
  font-size: var(--fs-aux);
  color: var(--text-muted);
  margin-top: 2px;
  line-height: 1.35;
}

/* 3.4 Collapse rail */
.collapse-rail {
  width: 22px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--text-muted);
  font-size: var(--text-lg);
  line-height: 1;
  padding: 0;
  transition: color 0.15s, background 0.15s;
  align-self: stretch;
  border-left: 1px solid var(--border-color);
  border-right: 1px solid var(--border-color);
}
.collapse-rail:hover {
  color: var(--primary);
  background: var(--primary-light);
}
.collapse-rail:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.section-label {
  font-size: var(--fs-aux);
  font-weight: var(--font-semibold);
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0.02em;
  margin-bottom: 8px;
}

/* UI font scale (settings general.ui_font_scale)
   Root sizes: sm 12 / md 14 / lg 17 / xl 20 — all --text-* and --fs-* follow. */
/* --- User font-size preference (font-scale.js stamps data-font-scale) -------
   This is where the type scale actually lands: these blocks sit on the same
   <html> element as :root but at higher specificity, so they win. They used to
   restate a flat scale — --text-xl and --text-2xl identical, four steps inside
   1.5px — which is why a page title rendered the same size as a section
   heading no matter what :root said.
   Each block now carries the same four-step hierarchy at its own size, plus a
   --dense-* set that .density-compact maps onto, so the compact pages tighten
   *relative to the size the user picked* instead of snapping back to medium.
   --fs-* is deliberately not redefined here: :root aliases it onto --text-*,
   so one definition drives both spellings. */
html, html[data-font-scale="md"] {
  font-size: 14px;
  --text-xs: 11.5px;
  --text-sm: 12.5px;
  --text-base: 13.5px;
  --text-lg: 15px;
  --text-xl: 18px;
  --text-2xl: 26px;
  --dense-xs: 11px;
  --dense-sm: 12px;
  --dense-base: 13px;
  --dense-lg: 14px;
  --dense-xl: 16px;
  --dense-2xl: 22px;
}
html[data-font-scale="sm"] {
  font-size: 12px;
  --text-xs: 10px;
  --text-sm: 11px;
  --text-base: 11.5px;
  --text-lg: 13px;
  --text-xl: 15.5px;
  --text-2xl: 22px;
  --dense-xs: 9.5px;
  --dense-sm: 10.5px;
  --dense-base: 11px;
  --dense-lg: 12px;
  --dense-xl: 14px;
  --dense-2xl: 19px;
}
html[data-font-scale="lg"] {
  font-size: 17px;
  --text-xs: 13.5px;
  --text-sm: 14.5px;
  --text-base: 16px;
  --text-lg: 17.5px;
  --text-xl: 21px;
  --text-2xl: 30.5px;
  --dense-xs: 13px;
  --dense-sm: 14px;
  --dense-base: 15px;
  --dense-lg: 16.5px;
  --dense-xl: 19px;
  --dense-2xl: 26px;
}
html[data-font-scale="xl"] {
  font-size: 20px;
  --text-xs: 15px;
  --text-sm: 16.5px;
  --text-base: 18px;
  --text-lg: 20px;
  --text-xl: 24px;
  --text-2xl: 34.5px;
  --dense-xs: 14.5px;
  --dense-sm: 16px;
  --dense-base: 17px;
  --dense-lg: 18.5px;
  --dense-xl: 21.5px;
  --dense-2xl: 29px;
}

/* Modal (global fallback for standalone pages) */
.modal {
  display: flex;
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.4);
  backdrop-filter: blur(4px);
  z-index: 300;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--transition-base), visibility 0s linear var(--transition-base);
}
.modal.show {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--transition-base), visibility 0s linear 0s;
}
.modal-box {
  background: var(--color-bg-elevated);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  max-width: 440px;
  width: 100%;
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-lg);
  transform: translateY(8px) scale(0.98);
  transition: transform var(--transition-base);
}
.modal.show .modal-box { transform: translateY(0) scale(1); }
.modal-box h3 {
  margin-bottom: var(--space-2);
  font-size: var(--text-lg);
}
.modal-actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
  margin-top: var(--space-4);
}

/* Page container for standalone pages.
   1100px is the shared content width across the wizard steps (settings,
   region, jobs, apply, upload, project) — keep new pages on this value so the
   column does not change width as the user moves between steps. */
.page-container {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--section-gap) var(--page-gutter);
}

.page-container-narrow {
  max-width: 480px;
  margin: 0 auto;
  padding: var(--space-5) var(--space-4);
}

/* Lang toggle */
.lang-btn {
  border: 1px solid var(--color-border);
  background: var(--color-bg-elevated);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  color: var(--color-text);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.lang-btn:hover {
  border-color: var(--color-border-strong);
  background: var(--color-bg-subtle);
}
.lang-btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Infer rows (settings) */
.infer-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
}
.infer-row:last-child { border-bottom: none; }
.infer-val { color: var(--color-muted); flex: 1; text-align: right; }

/* Drop zone */
.drop-zone {
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  text-align: center;
  background: var(--color-bg-elevated);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.drop-zone:hover, .drop-zone.dragover {
  border-color: var(--color-primary);
  background: var(--color-bg-subtle);
}

/* Accessibility */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .skeleton { animation: none; background: var(--color-bg-subtle); }
}

@media (max-width: 768px) {
  .page-container, .page-container-narrow {
    padding: var(--space-3);
  }
  .row .field { min-width: 100%; }
}

/* ==========================================================================
   Application shell
   --------------------------------------------------------------------------
   Every engine page used to invent its own chrome, so the page title landed at
   seven different heights across the app and two pages had no title at all.
   These are the structural pieces, lifted from resume_hub.html — the one page
   that was actually designed — so each page composes the same shell instead of
   rebuilding one. Adding a page to the shell should let its local <style>
   block shrink, not grow.
   ========================================================================== */

/* --- What is NOT here ----------------------------------------------------
   A rail + content shell (.app-layout / .app-rail / .app-main / .app-page) was
   written here for a layout that never shipped: adoption stayed at zero while
   the shell that actually ships is main.css's .main-layout / .sidebar /
   .content-area / .footer-bar on the dashboard. Two shells meant nobody could
   tell which was canonical, so the unused one is gone. The shell lives in
   main.css; the page-level pieces below are what engine pages compose. */

/* --- Page header ---------------------------------------------------------
   The fix for "the title is somewhere different on every page": title, optional
   subtitle, optional right-aligned actions, one rule underneath — same shape
   and same position everywhere. */
.page-head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}
.page-head-main { flex: 1 1 320px; min-width: 0; }
.page-head h1,
.page-head h2,
.page-head .page-title {
  margin: 0;
  /* Was a hard-coded 1.05rem, which bypassed the type scale entirely and left
     the page title the same size as a section heading. */
  font-size: var(--text-2xl);
  font-weight: 650;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--color-text);
}
.page-head p,
.page-head .page-sub {
  margin: 6px 0 0;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-muted);
}
.page-head-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  flex-shrink: 0;
  margin-left: auto;
}

/* --- Metric strip --------------------------------------------------------
   The alternative to a row of 300x85 cards each holding one number, which
   fills the first screen and gives a supporting figure the same weight as the
   headline one. One bordered strip, cells divided by hairlines, and
   .metric--quiet for the figure that is context rather than headline (a
   running token total, say). Promoted from history's local copy. */
.metric-strip {
  display: flex;
  flex-wrap: wrap;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
  overflow: hidden;
  margin-bottom: var(--space-3);
}
.metric {
  flex: 1 1 120px;
  padding: var(--space-2) var(--space-3);
  border-left: 1px solid var(--color-border);
}
.metric:first-child { border-left: none; }
.metric-num {
  font-size: var(--text-xl);
  font-weight: var(--font-semibold);
  line-height: 1.25;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.metric-label { font-size: var(--text-xs); color: var(--color-muted); margin-top: 2px; }
.metric--quiet { background: var(--color-bg); }
.metric--quiet .metric-num {
  font-size: var(--text-base);
  font-weight: var(--font-medium);
  color: var(--color-muted);
}

/* --- Two-column form grid (matches resume_hub's existing definition) ------ */
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px 14px;
}
.form-grid .field-span-2 { grid-column: 1 / -1; }

@media (max-width: 640px) {
  .form-grid { grid-template-columns: 1fr; }
  /* The actions group is flex-shrink: 0 by default so it never collapses next
     to a long title; on a phone it has to give, or a header with three or four
     buttons pushes the page sideways. */
  .page-head-actions { margin-left: 0; flex-shrink: 1; min-width: 0; }
  .page-head-main { flex-basis: 100%; }
}

/* --- Degraded-result banner ----------------------------------------------
   One component for every "the AI or a scraper failed, so this result is not
   what it should be" case. Previously each engine swallowed its own failure
   and served the fallback silently, so a degraded run looked identical to a
   good one. Anything that sets `degraded: true` on its payload renders this
   and offers the retry. */
.degraded-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  background: #fef6e7;
  border: 1px solid var(--color-warn);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  margin-bottom: 14px;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: #7c4a03;
}
.degraded-banner > span { flex: 1 1 12ch; min-width: 0; }
.degraded-banner .btn { flex-shrink: 0; }
.degraded-banner[hidden] { display: none !important; }

/* Inline variant for list/table headers where a full banner is too heavy. */
.degraded-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #fef6e7;
  border: 1px solid var(--color-warn);
  border-radius: 100px;
  padding: 2px 10px;
  font-size: var(--text-xs);
  color: #7c4a03;
  white-space: nowrap;
}
.degraded-chip[hidden] { display: none !important; }

/* --- Demo mode ----------------------------------------------------------
   A new account's first screen was an empty dropzone: nothing to see before
   handing over a resume and an API key. The offer sits above the dropzone,
   and once the sample is loaded a standing bar makes sure it is never
   mistaken for the user's own data. */
.demo-offer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin-bottom: 16px;
  background: var(--color-bg-subtle);
}
.demo-offer[hidden] { display: none !important; }
.demo-offer strong { display: block; font-size: var(--text-base); margin-bottom: 3px; }
.demo-offer p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-muted);
  line-height: 1.5;
  max-width: 56ch;
}
.demo-offer .btn { flex-shrink: 0; }

.demo-active-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  background: #eef4ff;
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-sm);
  padding: 9px 14px;
  margin-bottom: 16px;
  font-size: var(--text-sm);
  color: var(--color-primary-dark);
}
.demo-active-bar[hidden] { display: none !important; }


/* ── Layout tokens and phone rules shared by every page (2026-10) ──────────
   Spacing runs 4 / 8 / 12 / 16 / 24 / 32 (--space-1 … --space-5 above, with
   --space-2h for the 12 the older scale skipped). New code uses these and the
   --text-* sizes above rather than a number of its own. */
:root {
  --space-2h: 12px;
  --tap-min: 44px;            /* smallest thing a finger is asked to hit */
  --sidebar-w: 248px;         /* the shell's rail, open */
  --sidebar-rail-w: 56px;     /* …folded to icons */
  --content-max: var(--page-max);   /* reading width: text does not run the width of a wide screen */
  --content-max-wide: 1280px;       /* boards and tables */
}

/* A finger needs 44px. Applied where there is a finger (or a narrow window),
   not on a desktop with a mouse, so dense toolbars there stay dense. */
@media (pointer: coarse), (max-width: 768px) {
  button, .btn, a.btn, [role="button"], summary, select,
  .tab, .chip, .rail-link, .step-nav-item, .account-menu-item, .lang-btn,
  input[type="text"], input[type="email"], input[type="password"], input[type="number"],
  input[type="search"], input[type="tel"], input[type="url"], input[type="date"] {
    min-height: var(--tap-min);
  }
  button, .btn, a.btn, [role="button"], .tab, .chip { min-width: var(--tap-min); }
  /* A row of buttons that grew taller should wrap rather than squeeze. */
  .actions, .toolbar, .tool-actions, .modal-actions { flex-wrap: wrap; }
  /* 16px stops iOS zooming the page when a field is focused. */
  input, select, textarea { font-size: 16px; }
}

/* A table on a phone: each row becomes a card, each cell a "label  value"
   line. Add class="cards-on-phone" to the table and data-label to each cell. */
@media (max-width: 640px) {
  table.cards-on-phone, table.cards-on-phone tbody, table.cards-on-phone tr, table.cards-on-phone td { display: block; width: auto; }
  table.cards-on-phone { border: 0; background: none; box-shadow: none; }
  table.cards-on-phone thead { display: none; }
  table.cards-on-phone tr {
    margin: 0 0 var(--space-2h); padding: var(--space-2h) var(--space-3);
    border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-bg-elevated);
  }
  table.cards-on-phone td {
    display: flex !important; justify-content: space-between; align-items: center; gap: var(--space-3);
    padding: 4px 0; border: 0; text-align: right; min-width: 0; overflow-wrap: anywhere;
  }
  table.cards-on-phone td::before {
    content: attr(data-label); flex: 0 0 auto; color: var(--color-muted); font-size: var(--text-sm); text-align: left;
  }
  table.cards-on-phone td:not([data-label])::before { content: none; }
  table.cards-on-phone td:not([data-label]) { justify-content: flex-end; }
  table.cards-on-phone td:first-child { font-weight: var(--font-semibold); }
}

/* Phones (owner, 2026-10-23 — the send page swayed left and right when a field was tapped): an iPhone zooms into any
   field whose text is under 16px, and the zoomed page then slides sideways. Every field is 16px on a touch screen, and
   no page scrolls sideways. */
@media (pointer: coarse) {
  input:not([type=checkbox]):not([type=radio]):not([type=range]), select, textarea { font-size: 16px !important; }
  html, body { overflow-x: hidden; }
}
