@font-face { font-family: 'Nohemi'; src: url('/fonts/Nohemi-Regular.otf') format('opentype'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Nohemi'; src: url('/fonts/Nohemi-Medium.otf') format('opentype'); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: 'Nohemi'; src: url('/fonts/Nohemi-SemiBold.otf') format('opentype'); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: 'Nohemi'; src: url('/fonts/Nohemi-Bold.otf') format('opentype'); font-weight: 700; font-style: normal; font-display: swap; }

:root {
  color-scheme: dark;
  --bg: #121211;
  --screen: #151513;
  --surface: #1F1F1D;
  --surface-2: #292926;
  --line: rgba(255,255,255,0.08);
  --line-strong: rgba(255,255,255,0.18);
  --text: #ECEAE3;
  --dim: #98968E;
  --faint: #61605A;
  --accent: #D6B36A;
  --heart: #E25A4C;
  --heart-soft: rgba(226,90,76,0.14);
  --rest: #6FB07A;
  --rest-soft: rgba(111,176,122,0.16);
  --done: #D6B36A;
  --accent-soft: rgba(214,179,106,0.16);
  --accent-line: rgba(214,179,106,0.45);
  --font: 'Nohemi', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --display: 'Nohemi', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }
/* The hidden attribute must win over any display rule on the same element. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

.app {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--screen);
  display: flex;
  flex-direction: column;
  /* Room for the pinned tab bar below, so the last thing on a tab is
     never hidden behind it. */
  padding-bottom: calc(58px + env(safe-area-inset-bottom, 0px));
}

.top { display: flex; align-items: baseline; justify-content: space-between; padding: 20px 18px 6px; padding-top: calc(20px + env(safe-area-inset-top, 0px)); }
.top h1 { font-family: var(--display); font-weight: 700; font-size: 26px; letter-spacing: -0.01em; margin: 0; }
.top h1 { color: var(--text); }
.top h1 .one { color: #6E6C66; }
.top small { color: var(--dim); font-size: 12px; }

.tab-panel { padding: 8px 18px 18px; flex: 1; }

.progress { padding: 8px 0 14px; display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; }
.big { font-family: var(--display); font-weight: 700; font-size: 64px; line-height: 0.9; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.big sup { font-size: 28px; color: var(--dim); font-weight: 600; vertical-align: 0.9em; margin-left: 2px; }
.progress .meta { text-align: right; color: var(--dim); font-size: 12px; line-height: 1.5; }
.progress .meta b { color: var(--text); font-weight: 600; }

.bar { height: 4px; background: var(--surface-2); border-radius: 2px; overflow: hidden; margin: 0 0 18px; }
.bar i { display: block; height: 100%; width: 0%; background: var(--accent); border-radius: 2px; }

.players { display: flex; flex-direction: column; gap: 6px; }
.player { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px 11px; display: grid; grid-template-columns: 34px 1fr auto; grid-template-rows: auto auto; column-gap: 10px; row-gap: 8px; align-items: center; }
.player .rank { font-family: var(--display); font-weight: 600; font-size: 15px; color: var(--faint); font-variant-numeric: tabular-nums; grid-row: 1 / span 2; align-self: start; padding-top: 1px; text-align: center; }
/* Board trophies: gold biggest, then silver, then bronze (1 October). */
.player .rank.trophy { position: relative; justify-self: center; padding-top: 0; }
.player .rank.trophy svg { display: block; width: 100%; height: 100%; }
.player .rank.trophy.gold { width: 34px; height: 34px; }
.player .rank.trophy.silver { width: 28px; height: 28px; }
.player .rank.trophy.bronze { width: 23px; height: 23px; }
.player .rank.trophy b { position: absolute; left: 0; right: 0; text-align: center; font-family: var(--font); font-weight: 700; line-height: 1; }
.player .rank.trophy.gold b { top: 7px; font-size: 11px; color: #1a1708; }
.player .rank.trophy.silver b { top: 5.5px; font-size: 9.5px; color: #2a2c30; }
.player .rank.trophy.bronze b { top: 4.5px; font-size: 8px; color: #2a1a0e; }
.player .name { font-weight: 500; font-size: 14px; }
.player.out { background: var(--heart-soft); border-color: rgba(226,90,76,0.4); }
.player.out .name, .player.out .rank { color: var(--heart); }
.player .name em { font-style: normal; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); font-weight: 600; margin-left: 6px; }
.player.out .name em { color: var(--heart); opacity: 0.85; }
.player.back .name em { color: var(--accent); }

.hearts { display: flex; gap: 3px; justify-self: end; }
.hearts svg { width: 13px; height: 12px; }
.hearts .full { fill: var(--heart); }
.hearts .empty { fill: none; stroke: var(--faint); stroke-width: 1.4; }

.days { grid-column: 2 / span 2; display: flex; gap: 2px; flex-wrap: wrap; }
.days i { display: block; flex: 1 1 0; min-width: 0; height: 14px; border-radius: 2px; background: var(--surface-2); }
.days i:nth-child(7n+1):not(:first-child) { margin-left: 4px; }
.days i.clean { background: var(--done); }
.days i.rest { background: var(--rest); }
.days i.missed { background: var(--heart); }
.days i.out { background: transparent; border: 1px solid var(--heart); }
.days i.pending { background: transparent; border: 1px dashed var(--line-strong); }
.days i.future { background: var(--surface-2); border: 0; }
.days i.adjusted { box-shadow: inset 0 0 0 2px var(--accent); }
.days i[data-player] { cursor: pointer; }

.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; color: var(--dim); font-size: 12px; margin: 14px 4px 0; }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 6px; vertical-align: -1px; background: var(--surface-2); }
.legend i.clean { background: var(--done); }
.legend i.rest { background: var(--rest); }
.legend i.missed { background: var(--heart); }
.legend i.pending { background: transparent; border: 1px dashed var(--line-strong); }
.legend i.future { background: var(--surface-2); }
.legend i.out { background: transparent; border: 1px solid var(--heart); }

/* Pinned to the bottom of what the phone actually shows (29 September):
   in the page flow it ended up below the fold in the home-screen app and
   under Safari's floating address bar. The safe-area inset keeps it above
   the home indicator. */
.tabbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; max-width: 480px; margin: 0 auto; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; border-top: 1px solid var(--line); padding: 12px 8px calc(12px + env(safe-area-inset-bottom, 0px)); background: var(--screen); }
.tab { appearance: none; border: 0; background: transparent; text-align: center; font: inherit; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); font-weight: 600; padding: 4px; cursor: pointer; }
.tab.on { color: var(--text); }

/* ---------- setup ---------- */
#tab-admin h2 { font-family: var(--display); font-weight: 700; font-size: 22px; letter-spacing: -0.01em; margin: 4px 0 14px; }
#tab-setup h2 { font-family: var(--display); font-weight: 700; font-size: 22px; letter-spacing: -0.01em; margin: 4px 0 14px; }

.field { margin: 0 0 14px; }
/* Setup: room between the admin controls and the first field, and no empty
   holder box while no admin link has been issued. */
#setup-form { margin-top: 22px; }
.invite-link:empty { display: none; }

.field > label { display: block; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--dim); margin: 0 0 6px; }
.field .hint { font-size: 11px; color: var(--dim); margin: 6px 2px 0; }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.in input, .row-name, .row-min {
  width: 100%; background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  color: var(--text); font: inherit; font-size: 14px; padding: 9px 10px;
}
.in input:focus, .row-name:focus, .row-min:focus, .row-type:focus { outline: none; border-color: var(--line-strong); }

.list { display: flex; flex-direction: column; gap: 6px; margin: 0 0 8px; }
.it { display: flex; align-items: center; gap: 8px; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 8px; }
.it .row-name { flex: 1 1 auto; min-width: 0; border: 0; background: transparent; padding: 4px 2px; }
.it .row-min { width: 76px; flex: 0 0 auto; }
.row-type { background: var(--surface-2); border: 1px solid var(--line); border-radius: 6px; color: var(--text); font: inherit; font-size: 13px; padding: 6px 8px; flex: 0 0 auto; }
.it .remove { appearance: none; border: 0; background: transparent; color: var(--faint); font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 4px; flex: 0 0 auto; }
.it .remove:hover { color: var(--heart); }
.it .move { display: flex; flex-direction: column; gap: 2px; flex: 0 0 auto; }
.it .move button { appearance: none; border: 0; background: transparent; color: var(--faint); font-size: 11px; line-height: 1; cursor: pointer; padding: 2px 4px; }
.it .move button:hover:not(:disabled) { color: var(--text); }
.it .move button:disabled { color: var(--line-strong); cursor: default; }

.invite { appearance: none; border: 1px solid var(--line-strong); background: transparent; color: var(--accent); font: inherit; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 6px; padding: 6px 8px; cursor: pointer; flex: 0 0 auto; }
.invite-link { font-size: 11px; color: var(--dim); word-break: break-all; flex: 1 1 100%; }
.invite-hint { font-size: 11px; color: var(--faint); flex: 0 0 auto; white-space: nowrap; }
/* Accounts: the foot of Profile, and each player's account row in Setup. */
.account-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin: 22px 4px 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 12px; color: var(--dim); }
.account-foot .link { appearance: none; border: 0; background: transparent; padding: 0; font: inherit; color: var(--dim); }
.acct-chip { flex: 0 0 auto; font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600; border-radius: 999px; padding: 4px 9px; border: 1px solid var(--line-strong); color: var(--dim); white-space: nowrap; }
.acct-chip.ok { color: var(--rest); border-color: rgba(111,176,122,0.45); }
.acct-chip.wait { color: var(--accent); border-color: rgba(214,179,106,0.45); }
/* ---------- admin: People ---------- */
.admin-seg { margin-bottom: 14px; }
.admin-seg button.on { background: var(--surface-2); }
.ad-sum { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin: 0 0 12px; }
.ad-sum div { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 9px 6px; text-align: center; font-size: 10px; color: var(--faint); }
.ad-sum b { display: block; font-family: var(--display); font-size: 20px; color: var(--text); margin-bottom: 2px; }
.ad-sum b.gold { color: var(--accent); }
.ad-sum b.red { color: var(--heart); }
.ad-card { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 11px 12px; margin: 0 0 8px; }
.ad-card.open { border-color: var(--line-strong); }
.ad-top { display: flex; justify-content: space-between; align-items: center; gap: 8px; cursor: pointer; }
.ad-nm { font-weight: 600; }
.ad-nm.big { font-family: var(--display); font-size: 20px; }
.ad-nm em { font-style: normal; font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); margin-left: 6px; font-weight: 600; }
.ad-subline { display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--dim); margin-top: 4px; }
.ad-subline .hearts svg, .ad-tr .hearts svg { width: 12px; height: 11px; }
.ad-body { border-top: 1px solid var(--line); margin-top: 11px; padding-top: 10px; }
.admin-detail .ad-body { border-top: 0; margin-top: 8px; padding-top: 0; }
.ad-kv { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; padding: 4px 0; }
.ad-kv span { color: var(--faint); }
.ad-kv b { font-weight: 500; text-align: right; }
.ad-body .warn, .ad-tr .warn { color: var(--accent); }
.ad-body .red, .ad-tr .red { color: var(--heart); }
.ad-body label, .ad-addform label { display: block; font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); font-weight: 600; margin: 10px 0 5px 2px; }
.ad-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ad-body input, .ad-addform input { flex: 1 1 140px; min-width: 0; background: var(--screen); border: 1px solid var(--line-strong); border-radius: 8px; padding: 9px 10px; font: inherit; font-size: 14px; color: var(--text); color-scheme: dark; }
.ad-addform input { display: block; width: 100%; margin: 0 0 8px; }
.ad-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.invite.red { color: var(--heart); border-color: rgba(226,90,76,0.4); }
.ad-sec { font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); font-weight: 600; margin: 14px 0 0 2px; }
.ad-sub { background: var(--screen); border: 1px solid var(--line); border-radius: 10px; padding: 2px 10px 10px; margin-top: 8px; }
.ad-sub.ad-confirm { padding-top: 10px; font-size: 12px; color: var(--dim); }
.ad-sub.ad-confirm .ad-row { margin-top: 8px; }
.ad-note { font-size: 12px; color: var(--dim); margin: 10px 0 0; word-break: break-all; }
.ad-note.error { color: var(--heart); word-break: normal; }
.ad-add { display: block; width: 100%; appearance: none; background: transparent; border: 1px dashed var(--line-strong); border-radius: 12px; padding: 11px; text-align: center; color: var(--accent); font: inherit; font-size: 12px; font-weight: 600; margin-top: 4px; cursor: pointer; }
.ad-table { margin: 0 0 12px; }
.ad-tr { display: grid; grid-template-columns: 1.1fr 1.6fr 158px 84px 1fr 0.9fr 0.7fr; column-gap: 12px; align-items: center; padding: 10px 8px; border-bottom: 1px solid var(--line); font-size: 12px; color: var(--dim); cursor: pointer; }
.ad-tr > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-tr .ad-nm { color: var(--text); }
.ad-tr .ad-em i { color: var(--faint); }
.ad-tr.ad-th { cursor: default; font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); font-weight: 600; }
.ad-tr.sel { background: var(--surface); border-radius: 8px; }
.shell:not(.admin-on) #admin-detail { display: none; }

.add { text-align: center; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); border: 1px dashed var(--line-strong); border-radius: 8px; padding: 9px; cursor: pointer; }

.btn { appearance: none; border: 1px solid var(--line-strong); border-radius: 10px; font: inherit; font-weight: 600; font-size: 14px; padding: 12px; cursor: pointer; background: var(--surface-2); color: var(--text); }
.btn.pri { background: var(--accent); color: #1a1708; border-color: var(--accent); }
.btn.no { color: var(--dim); background: var(--surface); }
.btn.on { border-color: var(--accent); background: var(--accent-soft); color: var(--text); }
/* Check-in answers (Pedro chose treatment A, 28 September): tinted at rest,
   solid once chosen. Scoped by the data-yn attribute so the out sheet's own
   Yes and Not yet buttons keep their look. */
.btn[data-yn="1"] { background: var(--rest-soft); border-color: rgba(111,176,122,0.45); color: var(--rest); }
.btn[data-yn="0"] { background: var(--heart-soft); border-color: rgba(226,90,76,0.45); color: var(--heart); }
.btn[data-yn="1"].on { background: var(--rest); border-color: var(--rest); color: #0f1a12; }
.btn[data-yn="0"].on { background: var(--heart); border-color: var(--heart); color: #fff; }
.btn.wide { width: 100%; margin-top: 16px; }
.btn:disabled { opacity: 0.4; cursor: default; }

.error { color: var(--heart); font-size: 12px; margin: 10px 0 0; }
.hint { color: var(--dim); font-size: 13px; padding: 12px 4px; }

/* ---------- check-in ---------- */
.eyebrow { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); font-weight: 600; }
.deadline { display: flex; justify-content: space-between; align-items: center; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin: 0 0 14px; font-size: 12px; color: var(--dim); }
.deadline b { color: var(--text); font-weight: 600; }
.deadline .t { font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--accent); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.checkin-note { padding: 0 0 12px; margin: -4px 0 0; }
.steps { display: flex; gap: 4px; margin: 0 0 20px; }
.steps i { flex: 1; height: 3px; border-radius: 2px; background: var(--surface-2); }
.steps i.done { background: var(--accent); }
.steps i.now { background: var(--text); }
.q .pillar { font-family: var(--display); font-weight: 700; font-size: 32px; letter-spacing: -0.01em; line-height: 1; margin: 0 0 6px; }
.q .rule { color: var(--dim); font-size: 13px; margin: 0 0 18px; }
.q h3 { font-size: 16px; font-weight: 600; margin: 0 0 12px; }
.yn { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.chips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 16px; }
.chip { appearance: none; border: 1px solid var(--line); background: var(--surface); color: var(--text); font: inherit; font-size: 13px; font-weight: 500; border-radius: 10px; padding: 10px 6px; cursor: pointer; font-variant-numeric: tabular-nums; }
.chip.on { border-color: var(--accent); background: var(--accent-soft); }
.custom { display: none; margin-top: 10px; gap: 8px; align-items: center; }
.custom.show { display: flex; }
.custom input { flex: 1; background: var(--surface); border: 1px solid var(--line-strong); border-radius: 10px; color: var(--text); font: inherit; font-size: 14px; padding: 10px 12px; min-width: 0; }
.custom span { color: var(--dim); font-size: 12px; }
.summary .row { display: flex; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.summary .row span:last-child { color: var(--dim); font-variant-numeric: tabular-nums; }
.summary .row.miss span:last-child { color: var(--heart); }
.summary .row[data-i] { cursor: pointer; }
.back-link { appearance: none; border: 0; background: none; padding: 0; margin: 0 0 14px; font: inherit; font-size: 13px; font-weight: 600; color: var(--dim); cursor: pointer; display: block; }
.btn.rest { background: var(--rest); color: #0f1a12; border-color: var(--rest); margin-top: 10px; }
.btn.rest:disabled { background: var(--surface-2); color: var(--faint); border-color: var(--line); opacity: 1; cursor: default; }
.deadline .t { white-space: nowrap; }
.deadline-label { display: flex; flex-direction: column; gap: 2px; }
.deadline-label small { font-size: 11px; color: var(--faint); }
.checkin-for { margin: -12px 0 4px; padding-top: 0; color: var(--dim); }
.rest-hint { margin: 8px 4px 0; text-align: center; font-size: 12px; color: var(--faint); }
.rest-link { margin: 16px 4px 0; text-align: center; font-size: 12px; color: var(--faint); }
.rest-link .rest { color: var(--rest); font-weight: 600; }

/* Classes for what used to be inline style attributes; the CSP blocks those. */
.link { cursor: pointer; text-decoration: underline; }
.top-tight { padding: 0 0 10px; }
.rule-anyway { margin: 18px 0 8px; }
.chips-tight { margin-top: 0; }
.row-result { border-bottom: 0; font-weight: 600; }
.result-missed { color: var(--heart); }
.result-clean { color: var(--accent); }
.result-late { color: var(--dim); }

.late-days { margin: 20px 4px 0; }
.late-days .eyebrow { margin: 0 0 8px 2px; }
.late-day { display: block; width: 100%; text-align: left; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin: 0 0 6px; font: inherit; font-size: 13px; color: var(--text); cursor: pointer; }
.late-day .dim { color: var(--dim); }

.activity { margin: 20px 4px 0; }
.activity .eyebrow { margin: 0 0 8px 2px; }
.activity-list .empty { color: var(--faint); font-size: 13px; margin: 0 0 0 2px; }
.activity-row { display: flex; gap: 12px; padding: 9px 2px; border-bottom: 1px solid var(--line); }
.activity-row:last-child { border-bottom: none; }
.activity-when { flex: 0 0 60px; color: var(--faint); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; padding-top: 1px; }
.activity-when .aw-time, .activity-when .aw-day { display: block; }
.activity-when .aw-day { font-size: 9px; margin-top: 3px; }
.activity-body { font-size: 13px; color: var(--dim); }
.activity-body b { color: var(--text); font-weight: 500; }

/* Press feedback for the late-day rows and every button/chip, plus the
   row-collapse when a late check-in is submitted. Reduced-motion users
   get the instant version: no transition rules outside this guard. */
@media (prefers-reduced-motion: no-preference) {
  .late-day {
    overflow: hidden;
    max-height: 60px;
    transition: transform 120ms ease, filter 120ms ease;
  }
  .late-day.leaving {
    transition: transform 260ms ease, opacity 260ms ease, max-height 260ms ease,
      margin-bottom 260ms ease, padding 260ms ease;
    transform: translateX(-24px);
    opacity: 0;
    max-height: 0;
    margin-bottom: 0;
    padding-top: 0;
    padding-bottom: 0;
  }
  .btn,
  .chip,
  .tab,
  .invite,
  .player {
    transition: transform 120ms ease, filter 120ms ease;
  }
  .late-day:active,
  .btn:active,
  .chip:active,
  .tab:active,
  .invite:active,
  .player:active {
    transform: scale(0.97);
    filter: brightness(0.9);
  }

  /* Board row re-rank (ticket #24): renderBoard reuses each player's row
     node across a refresh instead of rebuilding it, so a class swap here
     always has a previous frame to transition from -- see reconcilePlayers
     in app.js, which measures the row's old position and sets this class
     while it animates back to 0. */
  .player.player-flip {
    transition: transform 220ms ease;
  }

  /* A day cell's colour is just a class (see server/board.py's states);
     reusing the same <i> across a refresh (mergeDayCells, app.js) means
     swapping that class fades to the new colour instead of popping. */
  .days i {
    transition: background-color 160ms ease, border-color 160ms ease;
  }

  /* The heart that just went from full to empty on someone else's screen
     (mergeHearts, app.js) -- the Board-row echo of the life-lost overlay's
     own beat-then-hollow (ticket #22), for a viewer who wasn't the one who
     lost it and so never saw that overlay. */
  .hearts svg.row-heart-lost {
    animation: rowHeartLost 480ms ease;
  }
  @keyframes rowHeartLost {
    0% { fill: var(--heart); stroke: none; transform: scale(1); }
    45% { fill: var(--heart); stroke: none; transform: scale(1.3); }
    100% { fill: none; stroke: var(--faint); stroke-width: 1.4; transform: scale(1); }
  }

  /* Tab switches cross-fade (switchTab/animateTabSwitch, app.js): the
     outgoing panel fades out, then the incoming one fades in, ~90ms each
     for ~180ms total rather than the instant hidden-attribute swap. */
  .tab-panel {
    transition: opacity 90ms ease;
  }
  .tab-panel.tab-fade-out {
    opacity: 0;
  }
  /* The incoming panel animates itself to full opacity: no JS cleanup is
     needed for it to become visible, so a superseded switch or a throttled
     frame can never leave a panel stuck at opacity zero. */
  .tab-panel.tab-fade-in {
    animation: tab-in 90ms ease both;
  }
  @keyframes tab-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  /* Check-in step bar fill (drawCheckin/animateStepsFill, app.js): each
     step's fill state is a class already; the JS briefly reverts a freshly
     drawn bar to its previous classes, then restores the real ones on the
     next frame so this transition has something to animate across. */
  .steps i {
    transition: background-color 200ms ease;
  }

  /* Check-in step slide (drawCheckin, app.js): the next pillar (or the
     summary) enters from the right; going back to "Change an answer"
     enters from the left. Both are pure entrance keyframes -- the step
     being left is destroyed the same instant the next one is drawn, so
     there is nothing to animate out. */
  .q-forward,
  .q-back {
    animation-duration: 220ms;
    animation-timing-function: ease;
    animation-fill-mode: both;
  }
  .q-forward { animation-name: stepEnterForward; }
  .q-back { animation-name: stepEnterBack; }
  @keyframes stepEnterForward {
    from { opacity: 0; transform: translateX(24px); }
    to { opacity: 1; transform: translateX(0); }
  }
  @keyframes stepEnterBack {
    from { opacity: 0; transform: translateX(-24px); }
    to { opacity: 1; transform: translateX(0); }
  }

  /* Answering a timed pillar reveals the minute chips (questionHtml,
     app.js tags the container the first time it appears for that answer,
     so picking a different chip afterwards doesn't replay this). */
  .chips.chips-reveal,
  .custom.custom-reveal {
    animation: chipsReveal 200ms ease;
  }
  @keyframes chipsReveal {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
  }

  /* The elimination sheet already rises on arrival (sheet-rise-in, below);
     "Not yet" plays a slide down instead before the sheet actually closes
     (out-not-yet handler, app.js). */
  #out-overlay .sheet.sheet-leaving {
    animation: sheetSink 360ms cubic-bezier(.4,0,.8,.4) forwards;
  }

  /* Centred sheets' shared rise-and-settle entrance (ticket #38): the out
     sheet, once its life-lost sequence finishes, and the after-check-in
     summary sheet both use this -- see playLifeLostSequence's finish()
     and showSummarySheet in app.js. A "Not yet" tap during the rise
     removes this class before adding sheet-leaving above, since the two
     would otherwise tie on specificity and this one, being declared
     later, would win. */
  .sheet.sheet-rise-in {
    animation: sheetRise 620ms cubic-bezier(.2,1,.3,1) both;
  }
  @keyframes sheetRise {
    from { transform: translateY(60px) scale(0.96); opacity: 0; }
    to { transform: translateY(0) scale(1); opacity: 1; }
  }

  /* The summary sheet's own dismiss (hideSummarySheet, app.js): Done or a
     tap on the dark area sinks it away before the app returns to the
     Board. */
  .sheet.sheet-sink-out {
    animation: sheetSink 360ms cubic-bezier(.4,0,.8,.4) forwards;
  }
  @keyframes sheetSink {
    to { transform: translateY(40px) scale(0.96); opacity: 0; }
  }

  /* The shell's blur/dim/scale-back behind the summary sheet eases in and
     out (showSummarySheet/hideSummarySheet, app.js) rather than popping. */
  #shell.summary-behind,
  #shell.summary-leaving {
    transition: filter 500ms ease, transform 500ms ease;
  }

  /* Each pillar row lands 80ms after the last (showSummarySheet, app.js,
     which sets the per-row animation-delay). */
  .stat.stat-enter {
    animation: statIn 420ms cubic-bezier(.2,.8,.3,1) both;
  }
  @keyframes statIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
  }

  /* Stats pillar switcher: the highlighted block glides to the tapped
     pillar (up or down a row too, when the phone wraps the pillars) and
     the leader-and-ranking block below slides a touch in the same
     direction, then comes back in with the new pillar's numbers. Pedro
     chose treatment C in prototypes/stats-slider.html. */
  .seg .seg-ind {
    transition: left 320ms cubic-bezier(0.22, 1, 0.36, 1), width 320ms cubic-bezier(0.22, 1, 0.36, 1),
      top 320ms cubic-bezier(0.22, 1, 0.36, 1), height 320ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  .seg > button { transition: color 220ms ease; }
  .stats-by button { transition: color 200ms ease, background-color 200ms ease, border-color 200ms ease; }
  .stats-body.leaving-l, .stats-body.leaving-r {
    opacity: 0;
    transition: opacity 120ms ease-in, transform 120ms ease-in;
  }
  .stats-body.leaving-l { transform: translateX(-14px); }
  .stats-body.leaving-r { transform: translateX(14px); }
  /* Self-completing, like tab-in: nothing has to lift the class for the
     new numbers to be visible. */
  .stats-body.entering-l { animation: statsInFromLeft 240ms cubic-bezier(0.22, 1, 0.36, 1) both; }
  .stats-body.entering-r { animation: statsInFromRight 240ms cubic-bezier(0.22, 1, 0.36, 1) both; }
  @keyframes statsInFromLeft {
    from { opacity: 0; transform: translateX(-14px); }
    to { opacity: 1; transform: translateX(0); }
  }
  @keyframes statsInFromRight {
    from { opacity: 0; transform: translateX(14px); }
    to { opacity: 1; transform: translateX(0); }
  }

  /* "Monk mode complete" (treatment A): the veil fades, the tall sheet
     rises, then each line lands in turn and the days pop in one by one
     (playReveal, app.js sets each cell's delay). */
  .rv-overlay .rv-veil { opacity: 0; transition: opacity 400ms ease; }
  .rv-overlay .rv-sheet { transform: translateY(110%); transition: transform 620ms cubic-bezier(0.2, 0.9, 0.22, 1); }
  .rv-overlay.open .rv-veil { opacity: 1; }
  .rv-overlay.open .rv-sheet { transform: none; }
  .rv-overlay .rv-step { opacity: 0; transform: translateY(14px); }
  .rv-overlay.open .rv-title { animation: revealIn 500ms cubic-bezier(0.2, 0.8, 0.2, 1) 550ms forwards; }
  .rv-overlay.open .rv-done { animation: revealIn 600ms cubic-bezier(0.2, 0.8, 0.2, 1) 700ms forwards; }
  .rv-overlay.open .rv-count { animation: revealIn 500ms cubic-bezier(0.2, 0.8, 0.2, 1) 1250ms forwards; }
  .rv-overlay.open .rv-rank { animation: revealIn 500ms cubic-bezier(0.2, 0.8, 0.2, 1) 1450ms forwards; }
  .rv-overlay.open .rv-cta { animation: revealIn 500ms cubic-bezier(0.2, 0.8, 0.2, 1) 2500ms forwards; }
  .rv-overlay .rv-cal i { opacity: 0; transform: scale(0.6); }
  .rv-overlay.open .rv-cal i { animation: revealPop 320ms cubic-bezier(0.2, 0.9, 0.3, 1.4) forwards; }
  @keyframes revealIn {
    to { opacity: 1; transform: none; }
  }
  @keyframes revealPop {
    to { opacity: 1; transform: none; }
  }

  /* The podium (treatment A): after the sheet rises, the steps grow out
     of the floor third to first, each name landing as its step settles,
     then the rest of the tribe and the Next button. */
  .pd-overlay .pd-step { height: 0; }
  .pd-overlay .pd-who { opacity: 0; transform: translateY(10px); }
  .pd-overlay.open .pd-c3 .pd-step { animation: podiumRise 700ms cubic-bezier(0.2, 0.8, 0.2, 1) 1300ms forwards; }
  .pd-overlay.open .pd-c3 .pd-who { animation: revealIn 400ms ease 1900ms forwards; }
  .pd-overlay.open .pd-c2 .pd-step { animation: podiumRise 700ms cubic-bezier(0.2, 0.8, 0.2, 1) 2200ms forwards; }
  .pd-overlay.open .pd-c2 .pd-who { animation: revealIn 400ms ease 2800ms forwards; }
  .pd-overlay.open .pd-c1 .pd-step { animation: podiumRise 800ms cubic-bezier(0.2, 0.8, 0.2, 1) 3100ms forwards; }
  .pd-overlay.open .pd-c1 .pd-who { animation: revealIn 500ms ease 3800ms forwards; }
  .pd-overlay.open .pd-rest { animation: revealIn 500ms ease 4200ms forwards; }
  .pd-overlay.open .rv-cta { animation: revealIn 500ms ease 4200ms forwards; }
  @keyframes podiumRise {
    to { height: var(--pd-h); }
  }

  /* Another player's profile (treatment A): the veil fades in and the
     sheet rises with a soft spring; on the laptop the centred panel lifts
     a little and fades in instead. Closing plays it in reverse. */
  .pf-overlay .pf-veil { opacity: 0; transition: opacity 320ms ease; }
  .pf-overlay .pf-sheet { transform: translateY(105%); transition: transform 460ms cubic-bezier(0.2, 0.9, 0.25, 1); }
  .pf-overlay.open .pf-veil { opacity: 1; }
  .pf-overlay.open .pf-sheet { transform: none; }
  #shell { transition: filter 320ms ease, transform 420ms cubic-bezier(0.2, 0.9, 0.25, 1); }
  @media (min-width: 900px) {
    .pf-overlay .pf-sheet { transform: translateY(28px); opacity: 0; transition: transform 380ms cubic-bezier(0.2, 0.9, 0.25, 1), opacity 260ms ease; }
    .pf-overlay.open .pf-sheet { transform: none; opacity: 1; }
  }
}

/* ---------- stats ---------- */
#tab-stats h2 { font-family: var(--display); font-weight: 700; font-size: 22px; letter-spacing: -0.01em; margin: 4px 0 14px; }
#tab-checkin h2 { font-family: var(--display); font-weight: 700; font-size: 22px; letter-spacing: -0.01em; margin: 4px 0 14px; }
.seg { position: relative; display: flex; flex-wrap: wrap; gap: 4px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 4px; margin: 0 0 18px; }
.seg button { position: relative; z-index: 1; flex: 1 1 auto; appearance: none; border: 0; background: transparent; color: var(--dim); font: inherit; font-size: 10px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; padding: 9px 8px; border-radius: 9px; cursor: pointer; }
.seg button.on { color: var(--text); }
/* The highlighted block is one element that the JS moves under whichever
   pillar is selected (placeSegIndicator, app.js), so it can glide between
   pillars. Until the JS has measured it once (the tab may still be hidden),
   the selected button paints its own background instead. */
.seg .seg-ind { position: absolute; z-index: 0; top: 4px; left: 4px; width: 0; height: 0; background: var(--surface-2); border-radius: 9px; pointer-events: none; }
.seg:not(.has-ind) button.on { background: var(--surface-2); }
.seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* "Rank by" buttons under the pillars: one number per row, chosen here. */
.stats-by { display: flex; flex-wrap: wrap; gap: 6px; margin: -6px 4px 16px; }
.stats-by button { appearance: none; border: 1px solid var(--line); background: transparent; color: var(--dim); font: inherit; font-size: 11px; font-weight: 500; padding: 6px 11px; border-radius: 999px; cursor: pointer; }
.stats-by button.on { border-color: var(--accent); color: var(--text); background: var(--accent-soft); }
.stats-by button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lead .tot b.green { color: var(--rest); }
.lead { display: flex; align-items: baseline; justify-content: space-between; padding: 0 4px 16px; }
.lead .who { font-size: 12px; color: var(--dim); }
.lead .who b { display: block; font-family: var(--display); font-size: 30px; font-weight: 700; color: var(--text); letter-spacing: -0.01em; line-height: 1; margin-bottom: 4px; }
.lead .tot { text-align: right; font-size: 12px; color: var(--dim); }
.lead .tot b { display: block; font-family: var(--display); font-size: 30px; font-weight: 600; color: var(--accent); line-height: 1; margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.ranked { display: flex; flex-direction: column; gap: 16px; padding: 0 4px; }
.stat-row { display: grid; grid-template-columns: 18px 1fr auto; column-gap: 10px; row-gap: 8px; align-items: center; }
.stat-row .rank { font-family: var(--display); font-size: 15px; font-weight: 600; color: var(--faint); font-variant-numeric: tabular-nums; grid-row: 1 / span 2; }
.stat-row .name { font-size: 14px; font-weight: 500; }
.stat-row .value { font-size: 13px; color: var(--dim); font-variant-numeric: tabular-nums; }
.stat-row .bar { grid-column: 2 / span 2; height: 6px; background: var(--surface-2); border-radius: 3px; overflow: hidden; margin: 0; }
.stat-row .bar i { display: block; height: 100%; background: var(--dim); border-radius: 3px; }
.stat-row:first-child .bar i { background: var(--accent); }
.stat-row:first-child .name { font-weight: 600; }
.stat-row.you .name::after { content: 'you'; font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); margin-left: 8px; font-weight: 600; }
.note { font-size: 12px; color: var(--faint); padding: 14px 4px 0; }

/* ---------- another player's profile, over the Board ---------- */
.players .player { cursor: pointer; }
.players .player.out, .players .player.back { cursor: pointer; }
.pf-overlay { position: fixed; inset: 0; z-index: 25; display: flex; align-items: flex-end; justify-content: center; }
.pf-veil { position: absolute; inset: 0; background: rgba(0,0,0,0.35); }
.pf-sheet { position: relative; width: 100%; max-width: 480px; max-height: calc(100vh - 40px); max-height: calc(100dvh - 40px - env(safe-area-inset-top, 0px)); overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: #191918; border: 1px solid var(--line-strong); border-bottom: 0; border-radius: 24px 24px 0 0; padding: 12px 16px calc(24px + env(safe-area-inset-bottom, 0px)); box-shadow: 0 -20px 60px rgba(0,0,0,0.6); }
.pf-grab { width: 36px; height: 4px; border-radius: 2px; background: var(--line-strong); margin: 0 auto 10px; }
.pf-close { position: sticky; top: 0; float: right; z-index: 2; margin-left: 12px; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--line-strong); background: var(--surface-2); color: var(--dim); font: inherit; font-size: 18px; line-height: 1; cursor: pointer; }
.pf-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pf-sheet .pf-hero { padding-top: 6px; }
body.pf-lock { overflow: hidden; }
@media (min-width: 900px) {
  .pf-overlay { align-items: center; padding: 24px; }
  .pf-sheet { max-width: 560px; max-height: 88vh; border-radius: 22px; border-bottom: 1px solid var(--line-strong); padding: 18px 20px 24px; box-shadow: 0 24px 70px rgba(0,0,0,0.6); }
  .pf-grab { display: none; }
}

/* ---------- the end-of-monk-mode report page ---------- */
.report-page { position: fixed; inset: 0; z-index: 35; background: var(--bg); overflow-y: auto; overscroll-behavior: contain; }
.report-inner { max-width: 480px; margin: 0 auto; padding: 20px 18px calc(30px + env(safe-area-inset-bottom, 0px)); padding-top: calc(20px + env(safe-area-inset-top, 0px)); }
.report-inner .top { padding: 0 0 14px; }
.report-inner .top h1 { font-family: var(--display); font-weight: 700; font-size: 26px; letter-spacing: -0.01em; margin: 0; color: var(--text); }
.report-inner .top h1 .one { color: #6E6C66; }
.report-inner .top small { color: var(--dim); font-size: 12px; }
.report-inner .pf-hero { padding-top: 6px; }
.rp-verdict { display: flex; justify-content: space-between; align-items: flex-end; background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 14px; margin: 0 0 10px; }
.rp-verdict b { display: block; font-family: var(--display); font-size: 34px; font-weight: 700; color: var(--accent); line-height: 1; margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.rp-verdict b.out { color: var(--heart); }
.rp-verdict b small { font-size: 16px; color: var(--faint); }
.rp-verdict span { font-size: 12px; color: var(--dim); }
.rp-verdict .r { text-align: right; }
.pf-tile b.red { color: var(--heart); }
.rp-pl { padding: 9px 0; border-top: 1px solid var(--line); }
.rp-pl:first-of-type { border-top: 0; }
.pf-card .eyebrow + .rp-pl { border-top: 0; margin-top: 4px; }
.rp-pl-top { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.rp-pl-n { font-size: 14px; font-weight: 600; }
.rp-pl-top b { font-family: var(--display); font-size: 17px; font-weight: 700; color: var(--accent); white-space: nowrap; font-variant-numeric: tabular-nums; }
.rp-pl-top b.green { color: var(--rest); }
.rp-pl-sub { color: var(--dim); font-size: 12px; margin-top: 2px; }
.rp-against { font-size: 13px; color: var(--dim); line-height: 1.5; }
.rp-against b { color: var(--text); }
.rp-actions { margin-top: 6px; }
.rp-actions .btn.ghost { background: transparent; color: var(--accent); margin-top: 8px; }
.rp-actions .hint { text-align: center; margin: 12px 0 0; }
.rp-past { margin-top: 14px; }
.rp-past-row { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--line); }
.rp-past-row:first-of-type { border-top: 0; margin-top: 6px; }
.rp-past-row b { display: block; font-size: 14px; font-weight: 600; }
.rp-past-row .pf-sub { color: var(--faint); font-size: 11px; }

/* ---------- "monk mode complete" reveal (treatment A) ---------- */
.rv-overlay { position: fixed; inset: 0; z-index: 32; display: flex; align-items: flex-end; justify-content: center; }
.rv-veil { position: absolute; inset: 0; background: rgba(0,0,0,0.45); }
.rv-sheet { position: relative; width: 100%; max-width: 480px; height: calc(100% - 56px); height: calc(100dvh - 56px - env(safe-area-inset-top, 0px)); background: #191918; border: 1px solid var(--line-strong); border-bottom: 0; border-radius: 26px 26px 0 0; padding: 12px 20px 0; display: flex; flex-direction: column; box-shadow: 0 -30px 80px rgba(0,0,0,0.6); }
.rv-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 6px 0 12px; }
.rv-title { font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); font-weight: 600; }
.rv-done { font-family: var(--display); font-size: 36px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.05; margin-top: 8px; }
.rv-count { margin-top: 26px; }
.rv-count .n { font-family: var(--display); font-size: 96px; font-weight: 700; line-height: 1; letter-spacing: -0.04em; color: var(--accent); font-variant-numeric: tabular-nums; }
.rv-count .n small { font-size: 34px; color: var(--faint); letter-spacing: -0.02em; }
.rv-count .l { color: var(--dim); font-size: 14px; margin-top: 6px; }
.rv-rank { margin-top: 22px; display: flex; gap: 22px; flex-wrap: wrap; }
.rv-rank div { font-size: 12px; color: var(--dim); }
.rv-rank b { display: block; font-family: var(--display); font-size: 26px; font-weight: 700; color: var(--text); line-height: 1; margin-bottom: 4px; }
.rv-rank .hearts { margin-bottom: 6px; }
.rv-cal { margin-top: 26px; margin-bottom: 8px; }
.rv-cta { flex: 0 0 auto; padding: 14px 0 calc(18px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--line); background: #191918; }
.rv-later { display: block; width: 100%; appearance: none; border: 0; background: transparent; margin-top: 10px; font: inherit; font-size: 12px; color: var(--faint); text-align: center; }
@media (min-width: 900px) {
  .rv-overlay { align-items: center; padding: 24px; }
  .rv-sheet { height: auto; max-height: 90vh; border-radius: 22px; border-bottom: 1px solid var(--line-strong); }
  .rv-sheet .pf-grab { display: none; }
}

/* ---------- the final podium (treatment A) ---------- */
.pd-pod { display: grid; grid-template-columns: 1fr 1.15fr 1fr; gap: 8px; align-items: end; height: 300px; margin-top: 6px; }
.pd-col { display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
.pd-who { text-align: center; }
.pd-who svg { width: 34px; height: 34px; display: block; margin: 0 auto 6px; }
.pd-who b { display: block; font-family: var(--display); font-size: 16px; font-weight: 700; }
.pd-c1 .pd-who b { font-size: 19px; }
.pd-who span { display: block; color: var(--accent); font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }
.pd-who small { color: var(--faint); font-size: 10px; }
.pd-step { margin-top: 10px; border-radius: 12px 12px 0 0; background: var(--surface); border: 1px solid var(--line-strong); border-bottom: 0; display: flex; align-items: flex-start; justify-content: center; padding-top: 10px; height: var(--pd-h); }
.pd-step i { font-style: normal; font-family: var(--display); font-weight: 700; font-size: 22px; color: var(--faint); }
.pd-c3 { --pd-h: 90px; }
.pd-c2 { --pd-h: 130px; }
.pd-c1 { --pd-h: 180px; }
.pd-c1 .pd-step { background: linear-gradient(180deg, rgba(214,179,106,0.35), rgba(214,179,106,0.08)); border-color: rgba(214,179,106,0.5); }
.pd-c1 .pd-step i { color: var(--accent); }
.pd-rest { margin-top: 18px; }
.pd-row { display: grid; grid-template-columns: 18px 1fr auto; gap: 10px; padding: 9px 0; border-top: 1px solid var(--line); font-size: 13px; }
.pd-row span { color: var(--faint); font-weight: 600; }
.pd-row em { font-style: normal; color: var(--dim); font-variant-numeric: tabular-nums; }
.pd-row.out b, .pd-row.out em { color: var(--faint); }

/* ---------- rank trophies (the aside's Rank card) ---------- */
.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
#tro-gold .s1 { stop-color: #F0D58E; } #tro-gold .s2 { stop-color: #C9A04E; }
#tro-silver .s1 { stop-color: #EEF0F3; } #tro-silver .s2 { stop-color: #9EA3AB; }
#tro-bronze .s1 { stop-color: #E3A877; } #tro-bronze .s2 { stop-color: #9C5F32; }
.stat-row .rank.trophy { position: relative; width: 26px; height: 26px; }
.stat-row .rank.trophy svg { display: block; width: 26px; height: 26px; }
.stat-row .rank.trophy b { position: absolute; top: 5px; left: 0; right: 0; text-align: center; font-family: var(--font); font-size: 9px; font-weight: 700; line-height: 1; }
.stat-row .rank.trophy.gold b { color: #1a1708; }
.stat-row .rank.trophy.silver b { color: #2a2c30; }
.stat-row .rank.trophy.bronze b { color: #2a1a0e; }

/* ---------- join page (GET /join/<token>) ---------- */
/* The one-time link opens this page; only its button redeems the link,
   so a chat app's link preview cannot use it up (29 September). */
.join-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 24px 20px; }
.join { width: 100%; max-width: 380px; text-align: center; }
.join h1 { font-family: var(--display); font-weight: 700; font-size: 30px; letter-spacing: -0.01em; margin: 0 0 28px; color: var(--text); }
.join h1 .one { color: #6E6C66; }
.join h2 { font-family: var(--display); font-weight: 700; font-size: 22px; letter-spacing: -0.01em; margin: 0 0 8px; }
.join .hint { margin: 0 0 22px; }
.join form { display: flex; justify-content: center; }
.join .btn { min-width: 200px; padding: 14px 20px; font-size: 15px; }
.join a.btn { display: inline-block; text-decoration: none; }
/* Set-password form (GET /claim/<token>) and the in-app sign-in form. */
.join .join-form { display: block; text-align: left; margin-top: 24px; }
.join .join-form label { display: block; font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); font-weight: 600; margin: 0 0 6px 2px; }
.join .join-form input { display: block; width: 100%; background: var(--surface); border: 1px solid var(--line-strong); border-radius: 10px; padding: 13px 12px; color: var(--text); font: inherit; font-size: 16px; margin: 0 0 14px; }
.join .join-form input[readonly] { color: var(--dim); }
.join .join-form input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.join .join-form .btn { width: 100%; margin-top: 4px; }
.join .join-form .fine { text-align: center; color: var(--faint); font-size: 12px; line-height: 1.5; margin: 26px 0 0; }
.signin { position: fixed; inset: 0; z-index: 40; background: var(--bg); overflow-y: auto; }
.join .join-form .error { color: var(--heart); font-size: 13px; margin: 0 0 12px; }

/* ---------- profile ---------- */
#tab-profile h2 { font-family: var(--display); font-weight: 700; font-size: 22px; letter-spacing: -0.01em; margin: 4px 0 14px; }
.pf-hero { display: flex; justify-content: space-between; align-items: flex-end; padding: 0 4px 16px; }
.pf-hero .pf-name { font-family: var(--display); font-size: 34px; font-weight: 700; letter-spacing: -0.01em; line-height: 1; }
.pf-hero .hearts { margin-top: 8px; }
.pf-hero .pf-rank { text-align: right; }
.pf-hero .pf-rank b { display: block; font-family: var(--display); font-size: 30px; font-weight: 700; color: var(--accent); line-height: 1; margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.pf-hero .pf-rank span { color: var(--dim); font-size: 12px; }
.pf-hero .pf-rank b.out { color: var(--heart); }
.pf-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 0 0 10px; }
.pf-tile { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 12px; }
.pf-tile .eyebrow { display: block; }
.pf-tile b { display: block; font-family: var(--display); font-size: 24px; font-weight: 700; line-height: 1; margin: 6px 0 5px; font-variant-numeric: tabular-nums; }
.pf-tile b small { font-size: 14px; color: var(--faint); font-weight: 600; }
.pf-tile b.gold { color: var(--accent); }
.pf-tile b.green { color: var(--rest); }
.pf-tile b.red { color: var(--heart); }
.pf-tile .pf-sub { color: var(--faint); font-size: 11px; }
.pf-card { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 14px; margin: 0 0 10px; }
.pf-pillar { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.pf-pillar .pf-n { font-size: 15px; font-weight: 600; }
.pf-pillar .pf-v { font-family: var(--display); font-size: 20px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pf-pillar .pf-v.green { color: var(--rest); }
.pf-meta { display: flex; justify-content: space-between; gap: 10px; color: var(--dim); font-size: 12px; margin-top: 3px; }
.pf-bars { display: flex; align-items: flex-end; gap: 3px; height: 34px; margin-top: 10px; }
.pf-bars i { flex: 1 1 0; min-width: 0; background: var(--surface-2); border-radius: 2px 2px 0 0; min-height: 2px; }
.pf-bars i.on { background: var(--accent); }
.pf-dots { display: flex; gap: 4px; margin-top: 10px; }
.pf-dots i { flex: 1 1 0; min-width: 0; height: 6px; border-radius: 3px; background: var(--surface-2); }
.pf-dots i.done { background: var(--rest); }
.pf-dots i.not { background: var(--heart); }
.pf-dots i.rest { background: transparent; border: 1px dashed var(--line-strong); }
.pf-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; margin-top: 10px; max-width: 380px; }
.pf-cal .pf-d { font-size: 9px; color: var(--faint); text-align: center; letter-spacing: 0.1em; font-weight: 600; }
.pf-cal i { display: block; aspect-ratio: 1; border-radius: 5px; background: var(--surface-2); }
.pf-cal i.clean { background: var(--done); }
.pf-cal i.rest { background: var(--rest); }
.pf-cal i.missed { background: var(--heart); }
.pf-cal i.out { background: transparent; border: 1px solid var(--heart); }
.pf-cal i.pending { background: transparent; border: 1px dashed var(--line-strong); }
.pf-cal i.future { background: var(--surface-2); opacity: 0.55; }
.pf-cal i.late { box-shadow: inset 0 0 0 2px rgba(0,0,0,0.35); }
.pf-legend { display: flex; flex-wrap: wrap; gap: 6px 12px; color: var(--dim); font-size: 11px; margin-top: 10px; }
.pf-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; vertical-align: -1px; background: var(--surface-2); }
.pf-legend i.clean { background: var(--done); }
.pf-legend i.rest { background: var(--rest); }
.pf-legend i.missed { background: var(--heart); }
.pf-legend i.pending { background: transparent; border: 1px dashed var(--line-strong); }

/* ---------- elimination sheet ---------- */
.dimmed { filter: blur(6px) brightness(0.45); transform: scale(0.98); pointer-events: none; }
/* Above #life-lost-overlay (z-index 20, below) so the "you're out" sheet
   always slides up over the life-lost veil rather than under it, whatever
   order the two happen to sit in the document (ticket #22). */
.overlay { position: fixed; inset: 0; z-index: 30; display: flex; align-items: flex-end; justify-content: center; padding: 16px; background: rgba(0,0,0,0.35); }
/* Centred sheets (ticket #38): the out sheet and the after-check-in
   summary sheet both float mid-screen instead of anchoring to the
   bottom, with a shadow that falls away from them on every side rather
   than the bottom-anchored sheets' upward-only one. */
.overlay.rise { align-items: center; overflow-y: auto; }
.overlay .sheet { width: 100%; max-width: 480px; background: #1B1614; border: 1px solid rgba(226,90,76,0.45); border-radius: 22px; padding: 22px 20px 20px; box-shadow: 0 -20px 60px rgba(0,0,0,0.6); }
.overlay.rise .sheet { box-shadow: 0 24px 70px rgba(0,0,0,0.6); }
.overlay #out-hearts { display: flex; gap: 4px; margin: 0 0 4px; }
.overlay #out-hearts svg { width: 20px; height: 18px; }
.overlay #out-hearts .empty { fill: none; stroke: var(--heart); stroke-width: 1.5; opacity: 0.7; }
.overlay .eyebrow { color: var(--heart); }
.overlay h2 { font-family: var(--display); font-weight: 700; font-size: 44px; line-height: 0.95; margin: 8px 0 12px; letter-spacing: -0.01em; }
.overlay p { color: var(--dim); font-size: 13px; margin: 0 0 18px; }
.overlay .pun { display: flex; align-items: center; justify-content: space-between; background: var(--heart-soft); border-radius: 12px; padding: 12px 14px; margin-bottom: 18px; }
.overlay .pun b { font-family: var(--display); font-size: 24px; font-weight: 700; letter-spacing: -0.01em; }
.overlay .pun span { font-size: 12px; color: var(--dim); text-align: right; }
.overlay .pun span strong { color: var(--heart); }
.overlay h3 { font-size: 16px; font-weight: 600; margin: 0 0 12px; }
.overlay .yn .btn.pri { background: var(--heart); border-color: var(--heart); color: #fff; }
.overlay .fine { font-size: 11px; color: var(--faint); margin: 14px 0 0; text-align: center; }
.overlay .fine b { color: var(--accent); font-weight: 600; }

/* ---------- after-check-in summary sheet (ticket #38) ---------- */
/* The shell's own blur/dim/scale-back behind it (showSummarySheet, app.js)
   -- a touch heavier than .dimmed's, matching the approved prototype
   (prototypes/checkin-done.html). */
.summary-behind { filter: blur(6px) brightness(0.45); transform: scale(0.98); pointer-events: none; }
.summary-sheet { border-color: var(--line-strong); }
.summary-sheet .eyebrow { color: var(--accent); }
.summary-sheet h2 { font-size: 34px; margin: 6px 0 4px; }
.summary-sheet .sub { margin: 0 0 16px; }
.stat { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 4px 12px; padding: 11px 0; border-top: 1px solid var(--line); }
.stat .n { font-weight: 500; font-size: 15px; }
.stat .k { font-size: 11px; color: var(--faint); grid-column: 1; }
.stat .v { font-weight: 700; font-size: 26px; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; text-align: right; }
.stat .v.streak { color: var(--rest); }
.stat .d { grid-column: 2; text-align: right; font-size: 12px; color: var(--accent); font-weight: 600; }

/* ---------- life-lost animation (ticket #22) ----------
   One CSS-driven sequence, structured after the approved prototype
   (prototypes/life-lost.html, Pedro, 27 September 2026): a big heart
   lands and beats twice, cracks while it shakes, splits and falls away
   with a few shards, then "-1 life" and the player's hearts hold for a
   moment before the veil lifts. Driven entirely by two classes on <body>
   -- .life-lost-run starts it, .life-lost-last switches the ending to
   hold the veil for the "you're out" sheet instead of lifting it -- so
   nothing here needs an inline style. */
#life-lost-overlay {
  position: fixed; inset: 0; z-index: 20;
  display: grid; place-items: center; padding: 16px;
  background: rgba(12,10,10,0); opacity: 0; pointer-events: none;
}
.life-lost-stage { display: grid; place-items: center; gap: 20px; width: 100%; max-width: 320px; }
.life-lost-big { width: 120px; height: 110px; position: relative; opacity: 0; }
.life-lost-big svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.life-lost-big .whole { fill: var(--heart); filter: drop-shadow(0 0 24px rgba(226,90,76,0.5)); }
.life-lost-big .half { fill: var(--heart); opacity: 0; }
.life-lost-big .half.l { clip-path: polygon(0 0, 50% 0, 44% 32%, 57% 46%, 45% 64%, 55% 82%, 50% 100%, 0 100%); }
.life-lost-big .half.r { clip-path: polygon(50% 0, 100% 0, 100% 100%, 50% 100%, 55% 82%, 45% 64%, 57% 46%, 44% 32%); }
.life-lost-big .crack { fill: none; stroke: #1a0e0c; stroke-width: 1.1; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 30; stroke-dashoffset: 30; }
.life-lost-shard { position: absolute; width: 5px; height: 5px; background: var(--heart); border-radius: 1px; opacity: 0; left: 50%; top: 50%; }
.life-lost-shard:nth-child(5) { --dx: -58px; --dy: -32px; }
.life-lost-shard:nth-child(6) { --dx: 60px; --dy: -24px; }
.life-lost-shard:nth-child(7) { --dx: -40px; --dy: 50px; }
.life-lost-shard:nth-child(8) { --dx: 46px; --dy: 46px; }
.life-lost-shard:nth-child(9) { --dx: -10px; --dy: -62px; }
.life-lost-shard:nth-child(10) { --dx: 16px; --dy: 64px; }
.life-lost-caption { text-align: center; opacity: 0; }
.life-lost-caption .lost { font-family: var(--display); font-weight: 700; font-size: 36px; line-height: 1; letter-spacing: -0.01em; color: var(--heart); }
.life-lost-caption .left { color: var(--dim); font-size: 13px; margin-top: 8px; }
.life-lost-caption .left b { color: var(--text); font-weight: 600; }
.life-lost-remaining { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: 100%; opacity: 0; }
.life-lost-remaining svg { width: 22px; height: 20px; }
.life-lost-remaining .full { fill: var(--heart); }
.life-lost-remaining .empty { fill: none; stroke: var(--faint); stroke-width: 1.5; }
.life-lost-remaining .just { fill: var(--heart); }

body.life-lost-run #life-lost-overlay { animation: lifeLostVeil 4.9s ease forwards; pointer-events: auto; }
body.life-lost-run #shell { animation: lifeLostDim 4.9s ease forwards; }
body.life-lost-run .life-lost-big {
  animation:
    lifeLostHeartIn 0.55s cubic-bezier(.2,1.4,.4,1) 0.15s forwards,
    lifeLostBeat 0.5s ease-in-out 0.75s 2,
    lifeLostShake 0.35s ease 1.65s 1,
    lifeLostHoldOut 0.01s linear 2.05s forwards;
}
body.life-lost-run .life-lost-big .crack { animation: lifeLostCrack 0.45s ease-out 1.55s forwards, lifeLostFadeWhole 0.01s linear 2.05s forwards; }
body.life-lost-run .life-lost-big .whole { animation: lifeLostFadeWhole 0.01s linear 2.05s forwards; }
body.life-lost-run .life-lost-big .half { animation: lifeLostShowHalf 0.01s linear 2.05s forwards; }
body.life-lost-run .life-lost-big .half.l { animation: lifeLostShowHalf 0.01s linear 2.05s forwards, lifeLostFallL 0.7s ease-in 2.05s forwards; }
body.life-lost-run .life-lost-big .half.r { animation: lifeLostShowHalf 0.01s linear 2.05s forwards, lifeLostFallR 0.7s ease-in 2.05s forwards; }
body.life-lost-run .life-lost-shard { animation: lifeLostBurst 0.7s ease-out 2.05s forwards; }
body.life-lost-run .life-lost-caption { animation: lifeLostRise 0.45s ease 2.35s forwards, lifeLostHold 0.01s linear 3.5s forwards; }
body.life-lost-run .life-lost-remaining { animation: lifeLostRise 0.45s ease 2.6s forwards; }
body.life-lost-run .life-lost-remaining .just { animation: lifeLostLoseOne 0.6s ease 2.95s forwards; }

@keyframes lifeLostVeil { 0% { opacity: 0; background: rgba(12,10,10,0); } 6% { opacity: 1; background: rgba(12,10,10,0.78); } 90% { opacity: 1; background: rgba(12,10,10,0.78); } 100% { opacity: 0; background: rgba(12,10,10,0); } }
@keyframes lifeLostDim { 0% { filter: none; } 6% { filter: blur(3px) brightness(0.4); } 90% { filter: blur(3px) brightness(0.4); } 100% { filter: none; } }
@keyframes lifeLostHeartIn { from { opacity: 0; transform: scale(0.4); } to { opacity: 1; transform: scale(1); } }
@keyframes lifeLostBeat { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.09); } }
@keyframes lifeLostShake { 0%, 100% { transform: translateX(0) rotate(0); } 20% { transform: translateX(-5px) rotate(-2deg); } 40% { transform: translateX(5px) rotate(2deg); } 60% { transform: translateX(-4px) rotate(-1.5deg); } 80% { transform: translateX(4px) rotate(1.5deg); } }
@keyframes lifeLostCrack { to { stroke-dashoffset: 0; } }
@keyframes lifeLostFadeWhole { to { opacity: 0; } }
@keyframes lifeLostShowHalf { to { opacity: 1; } }
@keyframes lifeLostHoldOut { to { opacity: 1; } }
@keyframes lifeLostFallL { to { transform: translate(-42px, 64px) rotate(-28deg); opacity: 0; } }
@keyframes lifeLostFallR { to { transform: translate(42px, 64px) rotate(28deg); opacity: 0; } }
@keyframes lifeLostBurst { 0% { opacity: 1; transform: translate(-50%, -50%) scale(1); } 100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0.4) rotate(120deg); } }
@keyframes lifeLostRise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
@keyframes lifeLostHold { to { opacity: 1; } }
@keyframes lifeLostLoseOne { 0% { fill: var(--heart); transform: scale(1); } 50% { fill: var(--heart); transform: scale(1.25); } 100% { fill: transparent; stroke: var(--faint); stroke-width: 1.5px; transform: scale(1); } }

/* When the last life goes, the veil holds and the existing "you're out"
   sheet (#out-overlay) slides up under the empty hearts instead of the
   normal ending lifting it. */
body.life-lost-run.life-lost-last #life-lost-overlay { animation: lifeLostVeilStay 3.2s ease forwards; }
body.life-lost-run.life-lost-last #shell { animation: lifeLostDimStay 3.2s ease forwards; }
body.life-lost-run.life-lost-last .life-lost-caption .lost { color: var(--heart); }
@keyframes lifeLostVeilStay { 0% { opacity: 0; background: rgba(12,10,10,0); } 8%, 100% { opacity: 1; background: rgba(12,10,10,0.78); } }
@keyframes lifeLostDimStay { 0% { filter: none; } 8%, 100% { filter: blur(6px) brightness(0.4); } }
/* The out sheet's own arrival, now that it's centred (ticket #38), is the
   same .sheet-rise-in used by the after-check-in summary sheet -- see the
   reduced-motion guard below. */

/* While the life-lost veil is up (including held, under the sheet above),
   #out-overlay's own backdrop would double up with the veil's -- so it
   goes transparent for as long as body carries .life-lost-run, and comes
   back once that's cleared (clearLifeLostOverlay, on "Not yet" or a
   buy-back) (review, ticket #22). */
body.life-lost-run #out-overlay { background: transparent; }

/* Tapping anywhere after the crack jumps straight to the held result
   (ticket #22): freezes every piece in its end state instead of playing
   the rest of the fall. */
body.life-lost-skip .life-lost-big,
body.life-lost-skip .life-lost-big .crack,
body.life-lost-skip .life-lost-big .whole,
body.life-lost-skip .life-lost-big .half,
body.life-lost-skip .life-lost-shard { animation: none !important; opacity: 0 !important; }
body.life-lost-skip .life-lost-caption,
body.life-lost-skip .life-lost-remaining { animation: none !important; opacity: 1 !important; }
body.life-lost-skip .life-lost-remaining .just { animation: none !important; fill: transparent !important; stroke: var(--faint); stroke-width: 1.5px; }
body.life-lost-skip #life-lost-overlay { animation: none !important; opacity: 1 !important; background: rgba(12,10,10,0.78) !important; }
body.life-lost-skip #shell { animation: none !important; filter: blur(3px) brightness(0.4) !important; }

@media (prefers-reduced-motion: reduce) {
  body.life-lost-run .life-lost-big,
  body.life-lost-run .life-lost-big .crack,
  body.life-lost-run .life-lost-big .whole,
  body.life-lost-run .life-lost-big .half,
  body.life-lost-run .life-lost-shard { animation: none !important; }
  body.life-lost-run .life-lost-big { opacity: 0; }
  body.life-lost-run .life-lost-caption,
  body.life-lost-run .life-lost-remaining { animation-delay: 0.2s !important; }
}

/* ---------- admin day adjustment sheet ---------- */
.adjust-sheet { border-color: var(--accent-line); }
.adjust-sheet .eyebrow { color: var(--accent); }
.adjust-sheet h2 { font-size: 24px; margin: 6px 0 8px; }
.adjust-choices { grid-template-columns: repeat(3, 1fr); margin: 4px 0 16px; }
.adjust-choices .btn { padding: 10px 6px; font-size: 13px; }
.adjust-sheet .fine { cursor: pointer; }
.readout { background: var(--accent-soft); border-radius: 10px; padding: 8px 10px; font-size: 12px; color: var(--text); margin: 0 0 14px; }
.adjust-or { text-align: center; margin: 0 0 10px; }
.adjust-answers { display: flex; flex-direction: column; gap: 8px; margin: 0 0 16px; }
.adjust-answer-row { display: flex; align-items: center; gap: 8px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; }
.adjust-answer-row .name { flex: 1 1 auto; font-size: 13px; font-weight: 500; }
.yn.small { display: flex; gap: 6px; flex: 0 0 auto; }
.yn.small .btn { padding: 6px 10px; font-size: 12px; }
.adjust-answer-row .adjust-minutes { width: 84px; flex: 0 0 auto; background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; color: var(--text); font: inherit; font-size: 12px; padding: 6px 8px; }

/* ---------- read-only day sheet ---------- */
.day-sheet { border-color: var(--accent-line); }
.day-sheet .eyebrow { color: var(--accent); }
.day-sheet h2 { font-size: 24px; margin: 6px 0 8px; }
.day-sheet .fine { cursor: pointer; }

/* ---------- past monk modes (archive) ---------- */
.past-modes-link { margin: -6px 0 14px; font-size: 12px; color: var(--dim); }
.archive-banner { display: flex; align-items: center; justify-content: space-between; background: var(--accent-soft); border: 1px solid var(--accent-line); border-radius: 10px; padding: 9px 12px; margin: 0 0 14px; font-size: 12px; color: var(--text); }
.archive-banner .link { color: var(--accent); font-weight: 600; }
.archive-sheet { border-color: var(--accent-line); }
.archive-sheet .eyebrow { color: var(--accent); }
.archive-sheet h2 { font-size: 24px; margin: 6px 0 14px; }
.archive-row { display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin: 0 0 6px; font: inherit; color: var(--text); cursor: pointer; }
.archive-row .name { font-size: 14px; font-weight: 500; }
.archive-row .dates { font-size: 12px; color: var(--dim); }
.archive-sheet .fine { cursor: pointer; }

/* ---------- removal confirmation row (Setup) ---------- */
.confirm-remove { justify-content: space-between; }
.confirm-remove .confirm-text { flex: 1 1 auto; font-size: 12px; color: var(--dim); }
.confirm-remove .btn { flex: 0 0 auto; padding: 6px 10px; font-size: 12px; }

/* ---------- laptop layout (900px and up) ----------
   Below 900px `.rail` and `.aside` stay display:none and `.shell` is a
   plain block, so `.app` renders exactly as it does today: phone width,
   centred, bottom tabbar. At 900px this turns into a three-column rail
   / main / aside shell and the bottom tabbar hands off to the rail. */
.rail, .aside, .thead { display: none; }

@media (min-width: 900px) {
  /* The rail and aside run to the screen edges on any width; the middle
     column is what gets capped and centred. (A capped-and-centred shell
     left an empty strip outside the rail on wide MacBook screens, which
     made the rail look pushed rightwards.) */
  .shell { display: grid; grid-template-columns: minmax(232px, 1fr) minmax(0, 896px) minmax(296px, 1fr); min-height: 100vh; }

  .rail { display: flex; flex-direction: column; gap: 4px; padding: 26px 16px; border-right: 1px solid var(--line); }
  .rail-wm { font-family: var(--display); font-weight: 700; font-size: 24px; letter-spacing: -0.01em; padding: 0 0 26px; text-align: center; }
  .rail-wm { color: var(--text); }
  .rail-wm .one { color: #6E6C66; }
  /* The tabs sit in a block exactly as wide as the widest label; the block
     is centred in the rail and the icons line up in one column inside it. */
  .rail-tabs { display: flex; flex-direction: column; gap: 4px; align-self: center; width: 100%; max-width: 188px; }
  .rail-nav { display: flex; align-items: center; justify-content: flex-start; gap: 12px; width: 100%; text-align: left; padding: 11px 16px; border-radius: 10px; font-size: 15px; font-weight: 500; text-transform: none; letter-spacing: normal; color: var(--dim); }
  .rail-nav svg { width: 19px; height: 19px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; flex: 0 0 auto; }
  .rail-nav.on { background: var(--surface-2); color: var(--text); }
  .rail-me { margin-top: auto; border-top: 1px solid var(--line); padding-top: 16px; text-align: center; }
  .rail-me .eyebrow { text-align: center; }
  .rail-me:empty { display: none; }
  .rail-me .eyebrow { padding: 0 10px 6px; }
  .rail-me .who { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 0 10px; font-size: 14px; font-weight: 600; }

  .tabbar { display: none; }
  /* While Admin is open, the right-hand column holds the selected person. */
  .shell.admin-on .aside > .card:not(#admin-detail) { display: none; }
  .ad-add { max-width: 240px; }

  .app { max-width: none; margin: 0; min-height: auto; padding-bottom: 0; }
  .app .top { padding: 26px 30px 6px; }
  .app .top h1 { font-size: 30px; }
  .app .tab-panel { padding: 8px 30px 30px; }

  .thead { display: grid; grid-template-columns: 38px 160px 90px 1fr; column-gap: 14px; padding: 0 12px 8px; align-items: end; border: 1px solid transparent; border-bottom: 0; }
  .app .activity { display: none; }
  .thead .eyebrow { font-size: 9px; }
  .weeks { display: flex; gap: 2px; }
  .weeks i { flex: 1 1 0; min-width: 0; text-align: center; font-style: normal; font-size: 9px; color: var(--faint); font-weight: 600; letter-spacing: 0.04em; }
  .weeks i:nth-child(7n+1):not(:first-child) { margin-left: 4px; }

  .player { grid-template-columns: 38px 160px 90px 1fr; grid-template-rows: auto; column-gap: 14px; padding: 9px 12px; }
  .player .rank { grid-row: auto; padding-top: 0; }
  .player .rank.trophy { align-self: center; }
  .player .name { grid-column: 2; }
  .player .hearts { grid-column: 3; justify-self: start; }
  .player .days { grid-column: 4; grid-row: auto; flex-wrap: nowrap; }

  .aside { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; padding: 26px 20px; border-left: 1px solid var(--line); overflow-y: auto; }
  /* On a wide screen the aside column grows, but its cards stay a card's width, hugging the content. */
  .aside > * { width: 100%; max-width: 340px; }
  .card { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 16px; }
  .card .eyebrow { margin-bottom: 8px; }
  .card .t { font-family: var(--display); font-size: 34px; font-weight: 700; color: var(--accent); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
  .card p { margin: 6px 0 12px; color: var(--dim); font-size: 12px; }
  .card .btn { width: 100%; padding: 11px; font-size: 14px; }

  .mini { display: flex; flex-direction: column; gap: 12px; }
  .mini .stat-row { grid-template-columns: 26px 1fr auto; column-gap: 10px; row-gap: 6px; }
  .mini .stat-row .rank { text-align: center; }
  .mini .stat-row .rank, .mini .stat-row .name, .mini .stat-row .value { font-size: 12px; }
  .mini .stat-row .bar { height: 4px; }

  #aside-activity-list { max-height: 320px; overflow-y: auto; }
}
