/* ===========================================================================
   PRESTIGE — design system
   ---------------------------------------------------------------------------
   The rule this file follows: nothing gets a bespoke size. Every gap, radius,
   font size and surface comes from a token below. The previous iteration drifted
   into ~14 different paddings and ~11 font sizes, which is what produces the
   "airy and cluttered at the same time" feeling — lots of whitespace, but none
   of it repeating, so the eye never finds a rhythm to lock onto.

   Density targets, chosen to read like a well-made game menu rather than a
   settings page:
     - card padding 12px 16px (was 16/18)
     - vertical rhythm 12px between cards, 8px inside a card
     - one type ramp, 7 steps, no in-between values
     - controls are sized to their content; nothing stretches to fill a row
       just because the row happens to be wide
   =========================================================================== */

:root {
  /* Spacing — the only gap values allowed anywhere in this file. */
  --s1: 2px;
  --s2: 4px;
  --s3: 6px;
  --s4: 8px;
  --s5: 12px;
  --s6: 16px;
  --s7: 22px;
  --s8: 32px;

  /* Type ramp. */
  --t-2xs: 10px;
  --t-xs: 11px;
  --t-sm: 12px;
  --t-md: 13px;
  --t-lg: 15px;
  --t-xl: 19px;
  --t-2xl: 26px;

  --radius-sm: 7px;
  --radius-md: 10px;
  --radius-lg: 13px;
  --radius-pill: 999px;

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;

  --sidebar-w: 216px;
  --content-max: 1180px;
  --rail-w: 300px;

  --ease: cubic-bezier(0.32, 0.72, 0, 1);
}

:root[data-theme="light"] {
  --bg: #f4f5f8;
  --bg-elevated: #ffffff;
  --bg-sunken: #eceef2;
  --bg-inset: #f6f7f9;
  --border: #e1e4ea;
  --border-strong: #ccd1da;
  --text: #12161d;
  --text-muted: #5a6373;
  --text-faint: #8a93a2;
  --accent: #4a63e8;
  --accent-strong: #3b4fd1;
  --accent-soft: rgba(74, 99, 232, 0.12);
  --accent-contrast: #ffffff;
  --success: #16915a;
  --success-soft: rgba(22, 145, 90, 0.12);
  --warn: #b4720c;
  --warn-soft: rgba(180, 114, 12, 0.13);
  --danger: #d64430;
  --danger-soft: rgba(214, 68, 48, 0.11);
  --track: #e4e7ec;
  --shadow-card: 0 1px 2px rgba(15, 23, 42, 0.05);

  /* Quest rarity + XP colors, kept separate from --accent so a user's accent
     choice can never collide with "this quest is epic". */
  --rarity-common: #7b8394;
  --rarity-rare: #3d7fd6;
  --rarity-epic: #8b5cd6;
  --xp-gold: #a8760a;
}

/* True black (OLED). Cards sit one step up and borders — not shadows, which
   are invisible on black — do the separating. */
:root[data-theme="dark"] {
  --bg: #000000;
  --bg-elevated: #0c0d11;
  --bg-sunken: #06070a;
  --bg-inset: #14161e;
  --border: #1e2029;
  --border-strong: #303442;
  --text: #f2f4f8;
  --text-muted: #98a1b1;
  --text-faint: #6a7280;
  --accent: #0a84ff;
  --accent-strong: #3fa1ff;
  --accent-soft: rgba(10, 132, 255, 0.18);
  --accent-contrast: #ffffff;
  --success: #30d158;
  --success-soft: rgba(48, 209, 88, 0.14);
  --warn: #ffb340;
  --warn-soft: rgba(255, 179, 64, 0.14);
  --danger: #ff453a;
  --danger-soft: rgba(255, 69, 58, 0.13);
  --track: #1a1d26;
  --shadow-card: none;

  --rarity-common: #8b94a6;
  --rarity-rare: #4da3ff;
  --rarity-epic: #b183f0;
  --xp-gold: #e8c15a;
}

/* --------------------------------- Reset --------------------------------- */

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--t-md);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  line-height: 1.45;
}
h1, h2, h3, p { margin: 0; }
ul { list-style: none; margin: 0; padding: 0; }
button { cursor: pointer; font: inherit; color: inherit; }
button, input, select, textarea { font-family: inherit; color: inherit; }

input, select, textarea {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 9px;
  font-size: var(--t-md);
  min-width: 0;
}
input[type="number"] { font-variant-numeric: tabular-nums; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
select { cursor: pointer; }

/* Numbers should line up column to column, everywhere. */
.num, .hud-stat-value, .kpi-value, .quest-progress-text { font-variant-numeric: tabular-nums; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ================================== Shell ================================= */

.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
}

.sidebar {
  background: var(--bg-elevated);
  border-right: 1px solid var(--border);
  padding: var(--s6) var(--s5);
  display: flex;
  flex-direction: column;
  gap: var(--s6);
  position: sticky;
  top: 0;
  height: 100vh;
}

.brand { display: flex; align-items: center; gap: var(--s4); padding: 0 var(--s2); }
.brand-mark {
  width: 26px; height: 26px; border-radius: 7px;
  background: var(--accent); color: var(--accent-contrast);
  display: grid; place-items: center;
  font-weight: 800; font-size: var(--t-sm); letter-spacing: -0.02em;
}
.brand-name { font-weight: 700; font-size: var(--t-lg); letter-spacing: -0.015em; }

.nav-list { display: flex; flex-direction: column; gap: var(--s1); }
.nav-item {
  position: relative;
  display: flex; align-items: center; gap: var(--s4);
  padding: 7px var(--s4);
  border-radius: var(--radius-sm);
  border: none; background: transparent; color: var(--text-muted);
  font-size: var(--t-md); font-weight: 500; text-align: left; width: 100%;
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.nav-item svg { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.8; }
.nav-item-label { flex: 1; }
button.nav-item:hover { background: var(--bg-inset); color: var(--text); }
.nav-item--active { background: var(--accent-soft); color: var(--accent-strong); font-weight: 650; }
.nav-item--active svg { opacity: 1; }

/* Unclaimed-reward count, so the nav itself tells you something is waiting. */
.nav-badge {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: var(--radius-pill);
  background: var(--accent); color: var(--accent-contrast);
  font-size: var(--t-2xs); font-weight: 700; display: grid; place-items: center;
  font-variant-numeric: tabular-nums;
}

.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--s4); }
.sidebar-level { display: flex; flex-direction: column; gap: var(--s3); padding: var(--s5); background: var(--bg-inset); border-radius: var(--radius-md); }
.sidebar-level-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); font-size: var(--t-xs); color: var(--text-faint); }
.sidebar-level-name { font-size: var(--t-md); font-weight: 700; color: var(--text); }

.main-content {
  padding: var(--s7) var(--s8) 64px;
  width: 100%;
  max-width: calc(var(--content-max) + var(--s8) * 2);
  margin: 0 auto;
  display: flex; flex-direction: column; gap: var(--s5);
}
.page { display: flex; flex-direction: column; gap: var(--s5); }

/* ================================ HUD header =============================== */

.hud {
  display: flex; align-items: center; gap: var(--s6);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--s5) var(--s6);
  box-shadow: var(--shadow-card);
}

.hud-identity { display: flex; align-items: center; gap: var(--s5); min-width: 0; }
.hud-names { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.hud-name { font-weight: 700; font-size: var(--t-lg); letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hud-sub { display: flex; align-items: center; gap: var(--s3); font-size: var(--t-xs); color: var(--text-faint); }

/* The XP block is width-capped on purpose: a progress bar stretched across
   800px of empty header reads as a loading screen, not a stat. */
.hud-xp { width: 232px; flex-shrink: 0; display: flex; flex-direction: column; gap: var(--s3); }
.hud-xp-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); font-size: var(--t-xs); }
.hud-xp-label { color: var(--text-faint); letter-spacing: 0.07em; font-weight: 700; }
.hud-xp-value { color: var(--text-muted); font-weight: 600; font-variant-numeric: tabular-nums; }

.hud-stats { display: flex; align-items: center; gap: var(--s6); margin-left: auto; flex-shrink: 0; }
.hud-stat { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.hud-stat-label { font-size: var(--t-2xs); color: var(--text-faint); letter-spacing: 0.08em; font-weight: 700; }
.hud-stat-value { font-weight: 700; font-size: var(--t-lg); display: flex; align-items: center; gap: var(--s2); }
.hud-stat-value svg { width: 14px; height: 14px; }
.hud-stat-value--flame { color: var(--danger); }
.hud-stat-value--up { color: var(--success); }
.hud-stat-value--down { color: var(--danger); }

.xp-bar { height: 5px; border-radius: var(--radius-pill); background: var(--track); overflow: hidden; }
.xp-bar-fill { height: 100%; background: var(--accent); border-radius: var(--radius-pill); transition: width 0.4s var(--ease); }

/* ---------------------------------- Avatar --------------------------------- */

.avatar {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  background: var(--bg-inset); border: 1px solid var(--border-strong);
  display: grid; place-items: center; overflow: hidden;
  font-weight: 700; font-size: var(--t-md); color: var(--text-muted); flex-shrink: 0;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--lg { width: 104px; height: 104px; font-size: 30px; }
.avatar-level {
  position: absolute; bottom: -3px; right: -3px;
  background: var(--accent); color: var(--accent-contrast);
  font-size: var(--t-2xs); font-weight: 800;
  border-radius: var(--radius-pill); min-width: 18px; height: 17px; padding: 0 4px;
  display: grid; place-items: center;
  border: 2px solid var(--bg-elevated);
  font-variant-numeric: tabular-nums;
}

/* ================================== Cards ================================= */

.card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--s5) var(--s6);
  box-shadow: var(--shadow-card);
}
.card--accent { border-color: var(--accent); }

.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  margin-bottom: var(--s5);
  min-height: 22px;
}
.card-title {
  font-size: var(--t-xs); font-weight: 700; letter-spacing: 0.08em;
  color: var(--text-faint); text-transform: uppercase;
  display: flex; align-items: center; gap: var(--s3);
}
.card-title svg { width: 13px; height: 13px; }
.card-head-sub { font-size: var(--t-xs); color: var(--text-faint); }
.card-head-actions { display: flex; align-items: center; gap: var(--s5); }

/* An inset group inside a card — replaces the old habit of nesting a second
   bordered card inside the first, which is what made the pages look boxy. */
.panel { background: var(--bg-inset); border-radius: var(--radius-md); padding: var(--s5); }
.panel--tight { padding: var(--s4); }

.empty-hint { font-size: var(--t-md); color: var(--text-faint); padding: var(--s4) 0; }
.field-label {
  display: block; font-size: var(--t-2xs); font-weight: 700; letter-spacing: 0.07em;
  color: var(--text-faint); text-transform: uppercase; margin-bottom: var(--s3);
}
.divider { height: 1px; background: var(--border); margin: var(--s5) 0; }

/* -------------------------------- Utilities ------------------------------- */

.row { display: flex; align-items: center; gap: var(--s4); }
.row--wrap { flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.stack { display: flex; flex-direction: column; gap: var(--s4); }
.stack--tight { gap: var(--s3); }
.stack--loose { gap: var(--s5); }
.grow { flex: 1; min-width: 0; }
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.tiny { font-size: var(--t-xs); }
.small { font-size: var(--t-sm); }

/* ================================= Controls =============================== */

.btn {
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 7px 13px;
  font-size: var(--t-md); font-weight: 600;
  display: inline-flex; align-items: center; gap: var(--s3);
  background: var(--bg-elevated); color: var(--text); white-space: nowrap;
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease);
}
.btn svg { width: 14px; height: 14px; }
.btn:hover:not(:disabled) { background: var(--bg-inset); }
.btn:disabled { opacity: 0.5; cursor: default; }
.btn--primary { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.btn--primary:hover:not(:disabled) { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn--muted { background: var(--success-soft); border-color: transparent; color: var(--success); }
.btn--ghost { background: transparent; border-color: var(--border); }
.btn--small { padding: 5px 10px; font-size: var(--t-sm); }
.btn--block { width: 100%; justify-content: center; }

.chip {
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: 4px 10px; font-size: var(--t-sm);
  background: var(--bg-inset); color: var(--text-muted);
  display: inline-flex; align-items: center; gap: var(--s3); white-space: nowrap;
  transition: border-color 0.12s var(--ease), color 0.12s var(--ease);
}
.chip svg { width: 12px; height: 12px; }
button.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip--action { background: var(--accent-soft); color: var(--accent-strong); border-color: transparent; font-weight: 600; }
.chip--on { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); font-weight: 600; }
.chip--on:hover { color: var(--accent-contrast); }

.pill {
  font-size: var(--t-2xs); font-weight: 700; padding: 2px 7px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-strong); letter-spacing: 0.02em;
  display: inline-flex; align-items: center; gap: var(--s2);
}
.pill--muted { background: var(--bg-inset); color: var(--text-muted); }
.pill--success { background: var(--success-soft); color: var(--success); }
.pill--warn { background: var(--warn-soft); color: var(--warn); }
.pill--danger { background: var(--danger-soft); color: var(--danger); }

.icon-button {
  width: 30px; height: 30px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--bg-inset);
  display: grid; place-items: center; color: var(--text-muted); flex-shrink: 0;
  transition: color 0.12s var(--ease), border-color 0.12s var(--ease);
}
.icon-button svg { width: 15px; height: 15px; }
.icon-button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.icon-button:disabled { opacity: 0.35; cursor: default; }
.icon-button--ghost { border-color: transparent; background: transparent; }
.icon-button--round { border-radius: var(--radius-pill); }
.icon-button--lg { width: 38px; height: 38px; }
.icon-button--lg svg { width: 17px; height: 17px; }

/* Inputs sized to their content — the single biggest density fix in this pass.
   A field holding "70" has no business being 700px wide. */
.field-input { width: 100%; }
.input--num { width: 74px; }
.input--num-sm { width: 56px; }
.input--text { width: 100%; max-width: 300px; }
.inline-select { padding: 5px 8px; font-size: var(--t-sm); }
.select--auto { width: auto; max-width: 250px; }

.seg {
  display: inline-flex; background: var(--bg-inset);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 2px; gap: 2px;
}
.seg-btn {
  border: none; background: transparent; color: var(--text-muted);
  font-size: var(--t-sm); font-weight: 600; padding: 5px 13px; border-radius: 5px;
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.seg-btn:hover { color: var(--text); }
.seg-btn--active { background: var(--accent); color: var(--accent-contrast); }
.seg--plain .seg-btn--active { background: var(--bg-elevated); color: var(--text); box-shadow: var(--shadow-card); }

.subtab-row { display: inline-flex; gap: var(--s2); background: var(--bg-inset); padding: 3px; border-radius: var(--radius-md); width: fit-content; }
.subtab {
  border: none; background: transparent; padding: 6px 14px; border-radius: 7px;
  font-size: var(--t-md); font-weight: 600; color: var(--text-muted);
  display: inline-flex; align-items: center; gap: var(--s3);
}
.subtab svg { width: 14px; height: 14px; }
.subtab:hover { color: var(--text); }
.subtab--active { background: var(--bg-elevated); color: var(--text); box-shadow: var(--shadow-card); }
.subtab-count {
  font-size: var(--t-2xs); font-weight: 700; background: var(--accent); color: var(--accent-contrast);
  border-radius: var(--radius-pill); min-width: 16px; height: 16px; padding: 0 4px; display: grid; place-items: center;
}

.checkbox-label { display: inline-flex; align-items: center; gap: var(--s3); font-size: var(--t-sm); color: var(--text-muted); cursor: pointer; }

/* ---------------------------- Progress primitives -------------------------- */

.bar { height: 6px; border-radius: var(--radius-pill); background: var(--track); overflow: hidden; }
.bar--thin { height: 4px; }
.bar--thick { height: 8px; }
.bar-fill { height: 100%; border-radius: var(--radius-pill); background: var(--accent); transition: width 0.4s var(--ease); }
.bar-fill--success { background: var(--success); }

.meter { display: flex; flex-direction: column; gap: var(--s2); }
.meter-top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); font-size: var(--t-sm); }
.meter-label { color: var(--text-muted); }
.meter-value { color: var(--text-faint); font-variant-numeric: tabular-nums; }

/* ================================== Today ================================= */

.today-grid { display: grid; grid-template-columns: minmax(0, 1fr) var(--rail-w); gap: var(--s5); align-items: start; }
.today-main { display: flex; flex-direction: column; gap: var(--s5); min-width: 0; }
.today-rail { display: flex; flex-direction: column; gap: var(--s5); position: sticky; top: var(--s5); }

.panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s5); margin-bottom: var(--s5); flex-wrap: wrap; }
.panel-eyebrow { font-size: var(--t-2xs); font-weight: 700; letter-spacing: 0.08em; color: var(--text-faint); text-transform: uppercase; }
.panel-title { font-size: var(--t-xl); font-weight: 700; letter-spacing: -0.015em; display: flex; align-items: center; gap: var(--s4); margin-top: 1px; }
.panel-title svg { width: 17px; height: 17px; color: var(--accent); }
.panel-head-actions { display: flex; align-items: center; gap: var(--s4); }

/* -------------------------------- Session table ---------------------------- */

.session-table-wrap { overflow-x: auto; }
/* Sized to its content, not to the card. Stretched full-bleed, the exercise
   name and its weight field end up 400px apart and the row stops reading as
   one row; `width: auto` keeps every set on a line you can scan in one go. */
.session-table { width: auto; min-width: min(100%, 520px); border-collapse: collapse; font-size: var(--t-md); }
.session-table th {
  text-align: left; font-size: var(--t-2xs); color: var(--text-faint); font-weight: 700;
  letter-spacing: 0.07em; padding: 0 var(--s4) var(--s3); border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.session-table th:last-child, .session-table td:last-child { text-align: right; }
.session-table th:not(:first-child), .session-table td:not(:first-child) { white-space: nowrap; }
.session-table td { padding: var(--s2) var(--s4); border-bottom: 1px solid var(--border); vertical-align: middle; height: 34px; }
.session-table tbody tr:last-child td { border-bottom: none; }
.set-row--done td { background: var(--success-soft); }
.set-row--done .set-target { color: var(--success); }

.exercise-cell { vertical-align: top !important; padding-top: var(--s4) !important; min-width: 150px; }
.exercise-name { display: flex; align-items: center; gap: var(--s3); font-weight: 650; font-size: var(--t-md); }
.exercise-name svg { width: 13px; height: 13px; color: var(--text-faint); }
.exercise-meta { font-size: var(--t-xs); color: var(--text-faint); margin-top: 1px; text-transform: capitalize; }
.set-num { color: var(--text-faint); width: 26px; font-variant-numeric: tabular-nums; }
.set-target { color: var(--text-faint); font-size: var(--t-sm); white-space: nowrap; font-variant-numeric: tabular-nums; }
.cell-input { width: 60px; padding: 4px 7px; font-size: var(--t-sm); }

.set-check {
  width: 24px; height: 24px; border-radius: 6px;
  border: 1px solid var(--border-strong); background: var(--bg-inset);
  display: grid; place-items: center; color: var(--text-faint);
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease), color 0.12s var(--ease);
}
.set-check svg { width: 13px; height: 13px; }
.set-check:hover { border-color: var(--success); color: var(--success); }
.set-check--on { background: var(--success); border-color: var(--success); color: #fff; }

.session-footer { display: flex; align-items: center; justify-content: space-between; gap: var(--s5); margin-top: var(--s5); flex-wrap: wrap; max-width: 720px; }
.add-exercise-row { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }
.session-progress { font-size: var(--t-sm); color: var(--text-faint); font-variant-numeric: tabular-nums; }
.session-note { width: 100%; max-width: 720px; min-height: 50px; resize: vertical; font-size: var(--t-md); }
.session-note-row { margin-top: var(--s5); }

.rest-day-body { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s5); }
.rest-day-copy { color: var(--text-muted); font-size: var(--t-md); max-width: 54ch; }
.rest-day-actions { display: flex; gap: var(--s4); flex-wrap: wrap; align-items: center; }

/* ---------------------------------- Food ---------------------------------- */

.entry-list { display: flex; flex-direction: column; gap: var(--s2); }
.entry-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) var(--s5); border-radius: var(--radius-sm); background: var(--bg-inset);
}
.entry-name { font-weight: 600; font-size: var(--t-md); }
.entry-meta { font-size: var(--t-xs); color: var(--text-faint); margin-top: 1px; font-variant-numeric: tabular-nums; }

.preset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--s4); }
.preset-card {
  text-align: left; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-inset); padding: var(--s4) var(--s5);
  display: flex; flex-direction: column; gap: 1px;
  transition: border-color 0.12s var(--ease), background 0.12s var(--ease);
}
.preset-card:hover { border-color: var(--accent); background: var(--accent-soft); }
.preset-card-name { font-weight: 650; font-size: var(--t-md); }
.preset-card-serving { font-size: var(--t-xs); color: var(--text-faint); }
.preset-card-macros { font-size: var(--t-xs); color: var(--text-muted); margin-top: var(--s3); font-variant-numeric: tabular-nums; }

.food-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--s4); }
.food-form-grid input:first-child { grid-column: 1 / -1; }
@media (min-width: 620px) {
  .food-form-grid { grid-template-columns: minmax(150px, 2fr) repeat(4, minmax(62px, 82px)); }
  .food-form-grid input:first-child { grid-column: auto; }
}
.food-form-footer { display: flex; align-items: center; justify-content: space-between; gap: var(--s5); margin-top: var(--s5); flex-wrap: wrap; }

/* --------------------------------- Macros --------------------------------- */

.macros-body { display: flex; align-items: center; gap: var(--s6); }
.macro-ring-wrap { position: relative; flex-shrink: 0; display: grid; place-items: center; }
.macro-ring-center { position: absolute; display: flex; flex-direction: column; align-items: center; line-height: 1.15; }
.macro-ring-num { font-size: var(--t-lg); font-weight: 700; font-variant-numeric: tabular-nums; }
.macro-ring-unit { font-size: var(--t-2xs); color: var(--text-faint); letter-spacing: 0.05em; }
.macro-ring-track { fill: none; stroke: var(--track); stroke-width: 7; }
.macro-ring-fill { fill: none; stroke: var(--accent); stroke-width: 7; stroke-linecap: round; transition: stroke-dashoffset 0.5s var(--ease); }
.macro-rows { flex: 1; display: flex; flex-direction: column; gap: var(--s4); min-width: 0; }

/* ------------------------------- Consistency ------------------------------- */

.streak-count { display: flex; align-items: baseline; gap: var(--s3); font-size: var(--t-2xl); font-weight: 700; margin-bottom: var(--s5); font-variant-numeric: tabular-nums; }
.streak-count svg { width: 19px; height: 19px; color: var(--danger); align-self: center; }
.streak-count-label { font-size: var(--t-sm); font-weight: 500; color: var(--text-faint); }
.week-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--s3); }
.week-cell {
  aspect-ratio: 1; border-radius: 6px; display: grid; place-items: center;
  font-size: var(--t-xs); font-weight: 600; color: var(--text-faint); background: var(--track);
}
.week-cell--done { background: var(--accent); color: var(--accent-contrast); }
.week-cell--planned_rest { background: transparent; border: 1px dashed var(--border-strong); }
.week-cell--missed { background: var(--danger-soft); color: var(--danger); }
.week-cell--future { background: var(--bg-inset); }

/* ---------------------------------- Volume --------------------------------- */

.volume-bars { display: flex; flex-direction: column; gap: var(--s4); }
.volume-bar-row { display: grid; grid-template-columns: 60px 1fr 20px; align-items: center; gap: var(--s4); }
.volume-bar-label { font-size: var(--t-sm); color: var(--text-muted); text-transform: capitalize; }
.volume-bar-value { font-size: var(--t-xs); color: var(--text-faint); text-align: right; font-variant-numeric: tabular-nums; }

/* -------------------------------- Rest timer ------------------------------- */

.rest-timer-row { display: flex; align-items: center; gap: var(--s4); }
.rest-timer-time { flex: 1; display: flex; align-items: baseline; gap: var(--s3); font-size: var(--t-2xl); font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.rest-timer-total { font-size: var(--t-sm); font-weight: 500; color: var(--text-faint); }
.rest-timer-presets { display: flex; gap: var(--s3); margin-top: var(--s5); }
.rest-timer-bar { margin-top: var(--s5); }

/* ================================== Quests ================================= */

.quest-list { display: flex; flex-direction: column; gap: var(--s4); }

.quest {
  display: grid;
  /* Three columns — what it is, how far along, what it pays. A single stretchy
     column would put a 900px progress bar on a wide screen, which is exactly
     the "airy but unreadable" failure mode this pass exists to fix. */
  grid-template-columns: minmax(0, 1fr) 210px 132px;
  gap: 0 var(--s6);
  align-items: center;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--s5) var(--s5) var(--s5) var(--s6);
  position: relative;
  overflow: hidden;
}
/* A hairline rarity stripe rather than a fully colored card — enough to read
   the tier at a glance without turning the board into a pile of color blocks. */
.quest::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--rarity-common); }
.quest--rare::before { background: var(--rarity-rare); }
.quest--epic::before { background: var(--rarity-epic); }
.quest--complete { border-color: var(--success); }
.quest--claimed { opacity: 0.55; }

.quest-body { display: flex; flex-direction: column; gap: var(--s3); min-width: 0; }
.quest-top { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }
.quest-title { font-weight: 650; font-size: var(--t-md); }
.quest-blurb { font-size: var(--t-sm); color: var(--text-muted); }
.quest-progress { display: flex; align-items: center; gap: var(--s4); }
.quest-progress .bar { flex: 1; }
.quest-progress-text { font-size: var(--t-xs); color: var(--text-faint); white-space: nowrap; min-width: 76px; text-align: right; }
.quest-side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--s3); }
.quest-progress-col { display: flex; flex-direction: column; gap: var(--s3); }

.quest-xp { font-size: var(--t-sm); font-weight: 700; color: var(--xp-gold); white-space: nowrap; font-variant-numeric: tabular-nums; }
.rarity-tag { font-size: var(--t-2xs); font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--rarity-common); }
.rarity-tag--rare { color: var(--rarity-rare); }
.rarity-tag--epic { color: var(--rarity-epic); }

.quest-board-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; }

/* Compact variant used in Today's rail. */
.quest--mini { grid-template-columns: 1fr; padding: var(--s4) var(--s4) var(--s4) var(--s5); gap: var(--s3); }
.quest--mini .quest-progress-col { gap: var(--s3); }
.quest--mini .quest-blurb { display: none; }
.quest--mini .quest-side { flex-direction: row; align-items: center; justify-content: space-between; width: 100%; }

/* -------------------------------- Questgivers ------------------------------ */

.portrait {
  width: 54px; height: 54px; border-radius: var(--radius-md);
  display: grid; place-items: center; flex-shrink: 0; overflow: hidden;
  border: 1px solid var(--border-strong);
  font-size: 25px; line-height: 1;
  background: var(--bg-inset);
}
.portrait img { width: 100%; height: 100%; object-fit: cover; }
.portrait--lg { width: 74px; height: 74px; font-size: 34px; border-radius: var(--radius-lg); }
.portrait--sm { width: 36px; height: 36px; font-size: 18px; }

.questline { display: flex; gap: var(--s5); align-items: flex-start; }
.questline-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s4); }
.questline-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; }
.questline-name { font-weight: 700; font-size: var(--t-lg); letter-spacing: -0.01em; }
.questline-giver { font-size: var(--t-xs); color: var(--text-faint); }
.questline-quote { font-size: var(--t-sm); color: var(--text-muted); font-style: italic; }
.questline-tiers { display: flex; gap: var(--s3); flex-wrap: wrap; }
/* Cap the questline's progress bar. A 1000px-wide bar is unreadable as a
   proportion - the eye can't judge "how far along" across that distance. */
.questline .quest-progress { max-width: 560px; }
.tier-pip {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--t-2xs); font-weight: 700; padding: 2px 7px; border-radius: var(--radius-pill);
  background: var(--bg-inset); color: var(--text-faint); border: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}
.tier-pip--done { background: var(--success-soft); color: var(--success); border-color: transparent; }
.tier-pip--current { background: var(--accent-soft); color: var(--accent-strong); border-color: transparent; }

.npc-card { display: flex; gap: var(--s5); align-items: flex-start; }
.npc-name { font-weight: 700; font-size: var(--t-md); }
.npc-title { font-size: var(--t-xs); color: var(--text-faint); }
.npc-blurb { font-size: var(--t-sm); color: var(--text-muted); margin-top: var(--s3); }

/* ============================ Readiness & warmups ========================== */

.status-strip { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.status-chip {
  display: inline-flex; align-items: center; gap: var(--s3);
  font-size: var(--t-sm); font-weight: 600; padding: 4px 10px;
  border-radius: var(--radius-pill); border: 1px solid transparent;
}
.status-chip svg { width: 13px; height: 13px; }
.status-chip--buff { background: var(--success-soft); color: var(--success); }
.status-chip--debuff { background: var(--danger-soft); color: var(--danger); }
.status-chip-progress { font-size: var(--t-2xs); opacity: 0.75; font-variant-numeric: tabular-nums; }

.checkin-block { display: flex; flex-direction: column; gap: var(--s4); }
.flag-grid { display: flex; flex-wrap: wrap; gap: var(--s3); }

.routine {
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-inset); padding: var(--s5);
  display: flex; flex-direction: column; gap: var(--s4);
}
.routine--prescribed { border-color: var(--accent); }
.routine-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s4); }
.routine-name { font-weight: 650; font-size: var(--t-md); display: flex; align-items: center; gap: var(--s3); }
.routine-meta { font-size: var(--t-xs); color: var(--text-faint); margin-top: 1px; }
.routine-blurb { font-size: var(--t-sm); color: var(--text-muted); }
.routine-moves { display: flex; flex-direction: column; gap: var(--s2); padding-top: var(--s3); border-top: 1px solid var(--border); }
.routine-move { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; gap: var(--s4); align-items: baseline; font-size: var(--t-sm); }
.routine-move-num { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.routine-move-name { font-weight: 600; }
.routine-move-cue { color: var(--text-faint); font-size: var(--t-xs); }
.routine-move-time { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.routine-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--s4); }
.routine-actions { display: flex; gap: var(--s3); align-items: center; }

/* Guided player — deliberately the loudest thing on screen while it runs. */
.player { display: flex; flex-direction: column; gap: var(--s5); }
.player-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); }
.player-routine { font-size: var(--t-xs); font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--accent); }
.player-step { font-size: var(--t-xs); color: var(--text-faint); font-variant-numeric: tabular-nums; }
.player-main { display: flex; align-items: center; justify-content: space-between; gap: var(--s6); flex-wrap: wrap; }
.player-move { font-size: var(--t-xl); font-weight: 700; letter-spacing: -0.02em; }
.player-cue { font-size: var(--t-md); color: var(--text-muted); margin-top: var(--s2); max-width: 46ch; }
.player-timer { font-size: 40px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.03em; line-height: 1; }
.player-controls { display: flex; align-items: center; gap: var(--s4); }
.player-dots { display: flex; gap: var(--s2); }
.player-dot { height: 3px; flex: 1; border-radius: 2px; background: var(--track); }
.player-dot--done { background: var(--accent); opacity: 0.5; }
.player-dot--current { background: var(--accent); }

/* ------------------------------ Activity quick-log ------------------------- */

.activity-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--s4); }
.activity-tile {
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-inset); padding: var(--s5);
  display: flex; flex-direction: column; gap: var(--s4);
}
.activity-tile-name { font-size: var(--t-2xs); font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-faint); }
.activity-tile-value { font-size: var(--t-xl); font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.activity-tile-unit { font-size: var(--t-xs); font-weight: 500; color: var(--text-faint); margin-left: 3px; }
.activity-tile-actions { display: flex; gap: var(--s3); align-items: center; }
.activity-tile-actions .input--num-sm { flex: 1; min-width: 0; }

/* ================================ Character =============================== */

.split-2 { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: var(--s5); align-items: start; }
.split-2--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.split-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s5); align-items: start; }
.split-profile { display: grid; grid-template-columns: 250px minmax(0, 1fr) minmax(0, 1fr); gap: var(--s5); align-items: start; }
.class-targets { max-width: 560px; }

.avatar-card { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--s5); }
.avatar-card-actions { display: flex; gap: var(--s4); flex-wrap: wrap; justify-content: center; }

.field-rows { display: flex; flex-direction: column; gap: var(--s5); }
.field-row { display: grid; grid-template-columns: 92px minmax(0, 1fr); align-items: center; gap: var(--s5); }
.field-row .field-label { margin-bottom: 0; }
.field-row-control { display: flex; gap: var(--s4); align-items: center; }

.class-grid { display: flex; flex-wrap: wrap; gap: var(--s3); }
.class-chip {
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 7px 12px;
  background: var(--bg-inset); color: var(--text-muted); font-size: var(--t-md); font-weight: 600;
}
.class-chip:hover { border-color: var(--accent); color: var(--accent); }
.class-chip--active { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); gap: var(--s5); }
.kpi { display: flex; flex-direction: column; gap: 1px; }
.kpi--center { align-items: center; }
.kpi-value { font-size: var(--t-xl); font-weight: 700; letter-spacing: -0.02em; }
.kpi-label { font-size: var(--t-2xs); color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600; }

.accent-swatch-grid { display: flex; flex-wrap: wrap; gap: var(--s4); }
.accent-swatch {
  width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent;
  display: grid; place-items: center; color: #fff;
  box-shadow: 0 0 0 1px var(--border) inset;
  transition: transform 0.12s var(--ease);
}
.accent-swatch svg { width: 14px; height: 14px; }
.accent-swatch:hover { transform: scale(1.1); }
.accent-swatch--active { border-color: var(--bg-elevated); box-shadow: 0 0 0 2px var(--text); }

.badge-tier-display { display: flex; align-items: center; gap: var(--s5); }
.badge-medal { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center; color: #fff; }
.badge-medal svg { width: 19px; height: 19px; }
.badge-tier-name { font-size: var(--t-lg); font-weight: 700; }
.badge-tier-sub { font-size: var(--t-xs); color: var(--text-faint); margin-top: 1px; }
.badge-chip {
  display: inline-flex; align-items: center; gap: var(--s3); font-size: var(--t-2xs); font-weight: 700;
  padding: 2px 8px 2px 6px; border-radius: var(--radius-pill); background: var(--bg-inset); color: var(--text-muted);
}
.badge-chip-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }

/* ================================== Charts ================================ */

.chart-wrap { display: flex; flex-direction: column; gap: var(--s3); }
.chart-svg { width: 100%; height: 108px; display: block; }
.chart-axis { stroke: var(--border); stroke-width: 1; }
.chart-target-line { stroke: var(--text-faint); stroke-width: 1; stroke-dasharray: 4 3; }
.chart-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.chart-dot { fill: var(--accent); stroke: var(--bg-elevated); stroke-width: 1.5; }
.chart-x-labels { display: flex; justify-content: space-between; font-size: var(--t-2xs); color: var(--text-faint); }
.chart-target-label { color: var(--text-muted); }
.chart-empty { font-size: var(--t-sm); color: var(--text-faint); padding: var(--s7) var(--s2); text-align: center; }

/* ================================== Stats ================================= */

.pb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--s4); }
.pb-card { border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--s5); background: var(--bg-inset); display: flex; flex-direction: column; gap: var(--s4); }
.pb-card--empty { justify-content: center; }
.pb-card-head { display: flex; align-items: center; gap: var(--s4); }
.pb-card-head .inline-select { flex: 1; }
.pb-card-body { display: flex; align-items: center; gap: var(--s4); }
.pb-unit, .pb-at { font-size: var(--t-sm); color: var(--text-faint); }
.pb-hint { font-size: var(--t-xs); color: var(--text-faint); }

.log-list { display: flex; flex-direction: column; }
.log-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: var(--s5); align-items: center;
  padding: var(--s4) 0; border-bottom: 1px solid var(--border); font-size: var(--t-md);
}
.log-row:last-child { border-bottom: none; }
.log-reason { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.log-date { font-size: var(--t-xs); color: var(--text-faint); font-variant-numeric: tabular-nums; }
.log-xp { font-weight: 700; color: var(--xp-gold); font-variant-numeric: tabular-nums; }

/* ================================== Goals ================================= */

.goal-card { display: flex; flex-direction: column; gap: var(--s5); }
.goal-row { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }
.goal-current { font-size: var(--t-xl); font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.goal-current-label { font-size: var(--t-xs); font-weight: 500; color: var(--text-faint); margin-left: var(--s2); }
.goal-hint { font-size: var(--t-sm); color: var(--text-faint); display: flex; align-items: center; gap: var(--s3); }
.goal-hint svg { width: 13px; height: 13px; }
.goal-hint--met { color: var(--success); font-weight: 600; }

/* ================================= Planner ================================ */

.planner-header { display: flex; align-items: center; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; }
.planner-header-left { display: flex; align-items: center; gap: var(--s3); }
.planner-header-label { font-size: var(--t-lg); font-weight: 700; min-width: 156px; letter-spacing: -0.01em; }

.week-bar { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--s4); }
.week-bubble {
  min-height: 60px;
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-inset);
  padding: var(--s4) var(--s3);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s1);
  color: var(--text-muted); text-align: center;
  transition: border-color 0.12s var(--ease);
}
.week-bubble:hover { border-color: var(--accent); color: var(--text); }
.week-bubble--selected { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.week-bubble--today:not(.week-bubble--selected) { border-color: var(--accent); }
.week-bubble-day { font-size: var(--t-2xs); font-weight: 700; letter-spacing: 0.06em; opacity: 0.75; }
.week-bubble-num { font-size: var(--t-lg); font-weight: 700; font-variant-numeric: tabular-nums; }
.week-bubble-status { width: 5px; height: 5px; border-radius: 50%; background: var(--track); }
.week-bubble-status--done { background: var(--accent); }
.week-bubble--selected .week-bubble-status--done { background: #fff; }
.week-bubble-status--missed { background: var(--danger); }
.week-bubble-status--planned_rest { background: transparent; border: 1px dashed var(--border-strong); }
.week-bubble--selected .week-bubble-status--planned_rest { border-color: rgba(255,255,255,0.7); }
.week-bubble-status--today_pending { background: var(--accent); opacity: 0.55; }
.week-bubble-status--future { background: var(--track); }
.week-bubble-plan { font-size: var(--t-2xs); opacity: 0.8; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.month-view { display: flex; flex-direction: column; gap: var(--s5); }
.month-grid-dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--s3); margin-bottom: var(--s3); }
.month-grid-dow span { font-size: var(--t-2xs); font-weight: 700; letter-spacing: 0.06em; color: var(--text-faint); text-align: center; }
.month-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--s3); }
.month-cell {
  aspect-ratio: 1; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--bg-inset);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  color: var(--text-muted); padding: 2px; overflow: hidden;
}
.month-cell:hover { border-color: var(--accent); }
.month-cell-num { font-size: var(--t-sm); font-weight: 700; font-variant-numeric: tabular-nums; }
.month-cell-glance { font-size: 8.5px; opacity: 0.8; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.month-cell--outside { opacity: 0.32; }
.month-cell--done { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-strong); }
.month-cell--missed { background: var(--danger-soft); border-color: transparent; color: var(--danger); }
.month-cell--planned_rest { border-style: dashed; }
.month-cell--today_pending { border-color: var(--accent); }
.month-cell--selected { outline: 2px solid var(--accent); outline-offset: -2px; }
.month-cell--today { font-weight: 800; }

.month-charts-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); }

.day-plan-train { display: flex; flex-direction: column; gap: var(--s5); max-width: 820px; }
.day-plan-template-row { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }
.day-plan-template-name { font-size: var(--t-md); font-weight: 700; }
.day-rest-hint { display: flex; align-items: center; gap: var(--s3); font-size: var(--t-sm); color: var(--text-faint); }
.day-rest-hint svg { width: 13px; height: 13px; color: var(--danger); }
.day-history-list { display: flex; flex-direction: column; gap: var(--s2); font-size: var(--t-md); color: var(--text-muted); }
.day-history-note { font-size: var(--t-sm); color: var(--text-faint); font-style: italic; }
.day-history-status { text-transform: capitalize; }

.default-pattern-list { display: flex; flex-direction: column; gap: var(--s2); max-width: 620px; }
.default-day-row {
  display: grid; grid-template-columns: 46px auto minmax(0, 1fr); align-items: center; gap: var(--s5);
  padding: var(--s3) var(--s4); border-radius: var(--radius-sm);
}
.default-day-row:hover { background: var(--bg-inset); }
.default-day-label { font-size: var(--t-sm); font-weight: 700; color: var(--text-muted); }
.default-day-row select { max-width: 230px; }

/* Same reasoning as the session table: an editor row whose controls are
   separated by 500px of nothing is harder to use, not airier. */
.exercise-editor { display: flex; flex-direction: column; gap: var(--s4); max-width: 820px; }
.template-exercise-list { display: flex; flex-direction: column; gap: var(--s3); }
.template-exercise-row {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s3) var(--s4); border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-inset); flex-wrap: wrap;
}
.template-exercise-select { flex: 1; min-width: 150px; max-width: 290px; }
.template-row-scheme { display: flex; align-items: center; gap: var(--s3); }
.template-num-input { width: 52px; padding: 4px 6px; font-size: var(--t-sm); }
.template-row-sep { font-size: var(--t-sm); color: var(--text-faint); }
.template-row-actions { display: flex; gap: var(--s2); margin-left: auto; }
.template-row-actions .icon-button { width: 26px; height: 26px; }
.template-card-head { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }
.template-name-input { flex: 1; font-weight: 700; max-width: 270px; }
.template-card-count { font-size: var(--t-xs); color: var(--text-faint); white-space: nowrap; }
.template-card-actions { display: flex; gap: var(--s3); margin-left: auto; }
.template-switcher { max-width: 250px; }
.template-editor { display: flex; flex-direction: column; gap: var(--s4); padding-top: var(--s5); border-top: 1px solid var(--border); }
.add-exercise-block { display: flex; flex-direction: column; gap: var(--s3); }
.new-exercise-details { font-size: var(--t-sm); }
.new-exercise-details summary { color: var(--accent); cursor: pointer; font-weight: 600; user-select: none; }
.new-exercise-form { display: flex; gap: var(--s4); margin-top: var(--s4); flex-wrap: wrap; align-items: center; }
.new-exercise-form .field-input { flex: 1; min-width: 130px; max-width: 210px; }
.new-template-row { display: flex; gap: var(--s4); flex-wrap: wrap; max-width: 620px; }
.new-template-row .field-input { flex: 1; min-width: 150px; max-width: 290px; }

/* ================================ Responsive ============================== */

@media (max-width: 1240px) {
  .quest { grid-template-columns: minmax(0, 1fr) 170px 120px; gap: 0 var(--s5); }
}

@media (max-width: 1080px) {
  /* minmax(0, 1fr), never a bare 1fr: a bare `1fr` track is minmax(auto, 1fr),
     whose auto floor is the content's min-content width - so a card holding a
     4-column stat grid forces its own track wider than the screen and the page
     scrolls sideways. Letting the track reach 0 pushes the wrapping decision
     down into the grid that can actually wrap. */
  .today-grid { grid-template-columns: minmax(0, 1fr); }
  .today-rail { position: static; }
  .split-2, .split-3, .split-profile { grid-template-columns: minmax(0, 1fr); }
  .month-charts-grid { grid-template-columns: minmax(0, 1fr); }
  .hud-xp { width: 180px; }
}

@media (max-width: 760px) {
  .app-shell { grid-template-columns: 1fr; }
  /* A grid item defaults to min-width:auto, so the nav row's content (six items,
     ~578px) stretches the grid track past the viewport and the whole PAGE
     scrolls sideways instead of just the nav. It only showed up on the tabs
     whose nav item sits far enough right that the browser scrolled it into
     view. min-width:0 lets overflow-x:auto do its job inside the bar. */
  .app-shell, .sidebar, .main-content { min-width: 0; }
  .sidebar {
    position: static; height: auto; flex-direction: row; align-items: center;
    overflow-x: auto; padding: var(--s4) var(--s5); gap: var(--s5);
    border-right: none; border-bottom: 1px solid var(--border);
    scrollbar-width: none;
  }
  .sidebar::-webkit-scrollbar { display: none; }
  .nav-list { flex-shrink: 0; }
  .nav-item { white-space: nowrap; }
  .brand-name { display: none; }
  .nav-list { flex-direction: row; }
  .nav-item { padding: 6px var(--s4); }
  .sidebar-foot { display: none; }
  .main-content { padding: var(--s5) var(--s5) 48px; }

  .hud { flex-wrap: wrap; row-gap: var(--s5); gap: var(--s5); }
  .hud-xp { width: 100%; order: 3; }
  .hud-stats { margin-left: auto; gap: var(--s5); }

  .field-row { grid-template-columns: minmax(0, 1fr); gap: var(--s3); }
  .week-bar { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .default-day-row { grid-template-columns: minmax(0, 1fr); row-gap: var(--s3); }
  .default-day-row select { max-width: none; }
  .month-cell-glance { display: none; }
  .quest { grid-template-columns: minmax(0, 1fr); gap: var(--s4); }
  .quest-progress-col { width: 100%; }
  .quest-side { flex-direction: row; justify-content: space-between; width: 100%; align-items: center; }
  .planner-header { align-items: stretch; flex-direction: column; }
  .template-exercise-row { align-items: stretch; flex-direction: column; }
  .template-exercise-select { max-width: none; }
  .template-row-actions { margin-left: 0; justify-content: flex-end; }
  .player-main { gap: var(--s5); }
}

/* ---------------------- Toggle chips (checkbox / radio) --------------------
   Used by the readiness check-in. These are real inputs rather than buttons
   that write to the store, so a half-filled check-in survives any re-render
   the app happens to do while you're filling it in — there is no draft state
   to lose because the DOM *is* the draft.                                   */

.chip-toggle { position: relative; display: inline-flex; cursor: pointer; }
.chip-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip-toggle span {
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: 5px 11px; font-size: var(--t-sm); font-weight: 600;
  background: var(--bg-inset); color: var(--text-muted);
  display: inline-flex; align-items: center; gap: var(--s3); white-space: nowrap;
  transition: background 0.12s var(--ease), color 0.12s var(--ease), border-color 0.12s var(--ease);
}
.chip-toggle span svg { width: 13px; height: 13px; }
.chip-toggle:hover span { border-color: var(--accent); color: var(--accent); }
.chip-toggle input:checked + span { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.chip-toggle input:focus-visible + span { box-shadow: 0 0 0 3px var(--accent-soft); }
/* Body-area flags read as a problem you're reporting, not a thing you want. */
.chip-toggle--flag input:checked + span { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
.chip-toggle--flag:hover span { border-color: var(--danger); color: var(--danger); }

.checkin-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--s5); }

/* ================================ First-run setup ==========================
   Renders instead of the app shell, so it gets its own centred layout rather
   than inheriting the sidebar grid.                                         */

.setup { min-height: 100vh; display: flex; justify-content: center; padding: var(--s8) var(--s6) 64px; background: var(--bg); }
.setup-inner { width: 100%; max-width: 940px; display: flex; flex-direction: column; gap: var(--s7); }

.setup-header { display: flex; flex-direction: column; gap: var(--s5); align-items: flex-start; }
.setup-title { font-size: 28px; font-weight: 700; letter-spacing: -0.025em; }
.setup-sub { font-size: var(--t-lg); color: var(--text-muted); max-width: 62ch; line-height: 1.5; }

.setup-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: var(--s5); }

.setup-card {
  text-align: left; border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--bg-elevated); padding: var(--s6);
  display: flex; flex-direction: column; gap: var(--s5);
  transition: border-color 0.12s var(--ease), transform 0.12s var(--ease);
}
.setup-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.setup-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s4); }
.setup-card-name { font-size: var(--t-lg); font-weight: 700; letter-spacing: -0.01em; }
.setup-card-suits { font-size: var(--t-xs); color: var(--text-faint); margin-top: 1px; }
.setup-card-blurb { font-size: var(--t-sm); color: var(--text-muted); line-height: 1.5; }
.setup-card-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); margin-top: auto; }
.setup-card-go { display: inline-flex; align-items: center; gap: var(--s2); font-size: var(--t-sm); font-weight: 700; color: var(--accent); }
.setup-card-go svg { width: 13px; height: 13px; }

/* Seven-day preview strip. Rest days stay recessive so the training pattern is
   readable at a glance without reading any words. */
.setup-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--s2); }
.setup-day {
  border-radius: var(--radius-sm); background: var(--bg-inset); border: 1px solid transparent;
  height: 28px; display: grid; place-items: center;
}
.setup-day--train { background: var(--accent-soft); border-color: var(--accent); }
.setup-day-letter { font-size: var(--t-xs); font-weight: 700; color: var(--text-faint); }
.setup-day--train .setup-day-letter { color: var(--accent-strong); }

.setup-workouts { display: flex; flex-wrap: wrap; gap: var(--s3); }
.setup-workout {
  font-size: var(--t-xs); font-weight: 600; color: var(--text-muted);
  background: var(--bg-inset); border-radius: var(--radius-pill); padding: 2px 8px; white-space: nowrap;
}

.setup-blank {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s6); flex-wrap: wrap;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-lg);
  padding: var(--s6); background: transparent;
}
.setup-foot { text-align: center; }

@media (max-width: 620px) {
  .setup { padding: var(--s6) var(--s5) 48px; }
  .setup-title { font-size: 23px; }
  .setup-sub { font-size: var(--t-md); }
  .setup-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------- Danger zone -------------------------------
   Native <details> so the "are you sure" state lives in the DOM rather than in
   a store flag the app's full re-render could desync.                        */

.danger-zone summary {
  display: flex; align-items: center; gap: var(--s3); cursor: pointer; user-select: none;
  font-size: var(--t-md); font-weight: 600; color: var(--text-muted); list-style: none;
}
.danger-zone summary::-webkit-details-marker { display: none; }
.danger-zone summary svg { width: 14px; height: 14px; }
.danger-zone summary:hover { color: var(--text); }
.danger-zone[open] summary { color: var(--text); margin-bottom: var(--s5); }
.danger-body { display: flex; flex-direction: column; gap: var(--s5); }
.danger-row {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s6);
  padding: var(--s5); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-inset);
}
.danger-row > div:first-child { max-width: 64ch; }
.danger-row-title { font-size: var(--t-md); font-weight: 650; margin-bottom: var(--s2); }
.danger-row .btn { flex-shrink: 0; }
.btn--danger { color: var(--danger); border-color: var(--danger); background: transparent; }
.btn--danger:hover:not(:disabled) { background: var(--danger-soft); border-color: var(--danger); }

@media (max-width: 620px) {
  .danger-row { flex-direction: column; gap: var(--s4); }
}
.hud-name--unset { background: none; border: none; padding: 0; color: var(--accent); text-align: left; }
.hud-name--unset:hover { text-decoration: underline; }

/* ============================ Generated art ================================
   Everything here frames output from render/art.ts. The art itself carries no
   sizing or colour of its own beyond CSS custom properties, so a class sigil
   picks up the user's accent and a chest picks up --xp-gold without either
   file knowing which theme is active.
   =========================================================================== */

.class-sigil { display: grid; place-items: center; flex-shrink: 0; }
.class-sigil svg { display: block; }

.class-hero { display: flex; align-items: center; gap: var(--s6); margin-bottom: var(--s5); }
.class-hero-text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.class-hero-name { font-size: var(--t-xl); font-weight: 700; letter-spacing: -0.02em; }
.class-hero-title { font-size: var(--t-sm); color: var(--accent); font-weight: 650; }
.class-hero-blurb { margin-top: var(--s3); line-height: 1.5; }

/* Generated questgiver portraits. The frame is the character's own colour (set
   inline per character); the art inside fills it edge to edge. */
.portrait--art { overflow: hidden; padding: 0; }
.portrait--art svg { display: block; width: 100%; height: 100%; }

/* ------------------------------- Reward chests --------------------------- */

.card--reward { border-color: var(--accent); }

.chest-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: var(--s5); }

.chest {
  position: relative;
  /* The burst is drawn larger than the tile so its rays reach the corners.
     Clipping here keeps it inside its own card instead of spilling over the
     chest next door. */
  overflow: hidden;
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
  padding: var(--s5) var(--s4);
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-inset);
  transition: transform 0.15s var(--ease), border-color 0.15s var(--ease);
}
.chest:hover { border-color: var(--accent); transform: translateY(-2px); }
.chest:active { transform: translateY(0); }

.chest-art { position: relative; z-index: 1; }
.chest-art svg { display: block; }

/* The chest jumps once on open. Small, fast, and only ever plays on a tap the
   user made - nothing on this screen animates on its own. */
.chest--opening .chest-art { animation: chest-pop 0.5s var(--ease); }
@keyframes chest-pop {
  0% { transform: scale(1) translateY(0); }
  35% { transform: scale(1.12) translateY(-6px); }
  100% { transform: scale(1) translateY(0); }
}

.chest-burst {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  pointer-events: none; z-index: 0;
}
.chest-burst svg { display: block; }
.chest--opening .burst-ray { animation: burst-out 0.6s var(--ease) backwards; animation-delay: var(--d, 0s); }
.chest--opening .burst-ring { animation: burst-ring 0.7s var(--ease) backwards; }
@keyframes burst-out {
  from { opacity: 0; transform: scale(0.4); transform-origin: 50% 50%; }
  60% { opacity: 1; }
  to { opacity: 0; transform: scale(1.15); transform-origin: 50% 50%; }
}
@keyframes burst-ring {
  from { opacity: 0.9; transform: scale(0.5); transform-origin: 50% 50%; }
  to { opacity: 0; transform: scale(1.4); transform-origin: 50% 50%; }
}

.chest-spark { opacity: 0; animation: chest-spark 0.8s var(--ease) forwards; animation-delay: var(--d, 0s); }
@keyframes chest-spark {
  0% { opacity: 0; transform: translateY(6px) scale(0.6); }
  40% { opacity: 1; transform: translateY(0) scale(1); }
  100% { opacity: 0; transform: translateY(-8px) scale(0.9); }
}

.chest-meta { display: flex; flex-direction: column; align-items: center; gap: 1px; z-index: 1; }
.chest-level { font-size: var(--t-sm); font-weight: 700; }
.chest-xp { font-size: var(--t-xs); font-weight: 700; color: var(--xp-gold); font-variant-numeric: tabular-nums; }

/* Respect the setting. The chest still opens - it just stops bouncing about it. */
@media (prefers-reduced-motion: reduce) {
  .chest--opening .chest-art,
  .chest--opening .burst-ray,
  .chest--opening .burst-ring,
  .chest-spark { animation: none; }
  .chest-spark { opacity: 1; }
}

@media (max-width: 760px) {
  .class-hero { gap: var(--s5); }
  .chest-grid { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--s4); }
}

/* =========================== Installed-app (PWA) ===========================
   Everything below exists because Prestige is installed to a phone home screen
   and launched without browser chrome. In a normal browser tab most of it is
   inert; in standalone mode it's the difference between "a website in a
   frameless window" and "an app".
   =========================================================================== */

/* The update prompt. Fixed to <body> (see src/pwa.ts for why it can't live
   inside #app) and inset from the home indicator on a phone. */
.pwa-toast {
  position: fixed;
  left: var(--s5);
  right: var(--s5);
  bottom: calc(var(--s6) + env(safe-area-inset-bottom));
  margin-inline: auto;
  max-width: 430px;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--s6);
  padding: var(--s5) var(--s6);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.28);
  animation: pwa-toast-in 0.26s var(--ease);
}
.pwa-toast-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pwa-toast-text strong { font-size: var(--t-md); font-weight: 700; }
.pwa-toast-sub { font-size: var(--t-sm); color: var(--text-muted); }
.pwa-toast-actions { display: flex; gap: var(--s4); margin-left: auto; flex-shrink: 0; }

@keyframes pwa-toast-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .pwa-toast { animation: none; }
}

/* 100vh is wrong on a phone browser whose address bar collapses on scroll;
   100dvh tracks the real viewport. The 100vh declarations further up stay as
   the fallback for anything without dvh support. */
.app-shell, .setup { min-height: 100dvh; }

body {
  /* Without this, an overscroll at the top of a long workout list triggers
     Chrome's pull-to-refresh and reloads the app mid-set. */
  overscroll-behavior-y: contain;
  -webkit-tap-highlight-color: transparent;
}

@media (max-width: 760px) {
  /* viewport-fit=cover lets the app paint under the notch and the home
     indicator — which is what stops it looking like a web page in a box — but
     then anything at an edge has to inset itself or it sits under the status
     bar and is unreadable. */
  .sidebar {
    padding-top: calc(var(--s4) + env(safe-area-inset-top));
    padding-left: calc(var(--s5) + env(safe-area-inset-left));
    padding-right: calc(var(--s5) + env(safe-area-inset-right));
    /* Sticky so the six tabs stay reachable without scrolling back up a long
       Stats or Planner page. Delete these two lines to restore the old
       scroll-away nav. */
    position: sticky;
    top: 0;
    z-index: 20;
  }
  .main-content {
    padding-left: calc(var(--s5) + env(safe-area-inset-left));
    padding-right: calc(var(--s5) + env(safe-area-inset-right));
    padding-bottom: calc(48px + env(safe-area-inset-bottom));
  }
  .setup {
    padding-top: calc(var(--s6) + env(safe-area-inset-top));
    padding-bottom: calc(48px + env(safe-area-inset-bottom));
  }

  /* iOS Safari zooms the viewport whenever you focus a control whose font-size
     is under 16px, and it does not zoom back out afterwards. Logging a workout
     is a dozen field taps in a row, so at 13px every set left the page
     magnified and had to be pinched back. 16px is the only reliable fix —
     `user-scalable=no` has been ignored since iOS 10, and it would break
     pinch-zoom for everyone anyway. The widths below grow to match, because a
     three-digit weight has to still fit. */
  input, select, textarea,
  .cell-input, .inline-select, .session-note, .template-num-input { font-size: 16px; }
  .cell-input { width: 72px; }
  .input--num { width: 84px; }
  .input--num-sm { width: 66px; }
  .template-num-input { width: 62px; }

  /* The Recovery quick-log tiles are ~136px of usable width and hold a preset
     chip, a free-entry field and a confirm button. At 13px all three squeezed
     onto one row; at 16px the field collapsed to ~25px and clipped the number
     you were typing. Giving the field its own full-width row fixes that and is
     a bigger tap target besides - the two buttons still pair up underneath. */
  .activity-tile-actions { flex-wrap: wrap; }
  .activity-tile-actions .input--num-sm { order: -1; flex: 1 1 100%; }
}
