/* ==========================================================================
   Mood Diary — local HTML prototype
   Palette, marks and chart chrome follow the data-viz reference palette.
   Mood ramp (--m1…--m5) is the validated one-hue ordinal ramp:
     light  #86b6ef #5598e7 #2a78d6 #1c5cab #104281
     dark   #9ec5f4 #6da7ec #3987e5 #256abf #184f95
   ========================================================================== */

:root {
  color-scheme: light;

  --plane:      #f9f9f7;
  --surface:    #fcfcfb;
  --surface-2:  #f2f1ec;
  --surface-3:  #e9e7e0;

  --ink:        #0b0b0b;
  --ink-2:      #52514e;
  --muted:      #898781;

  --grid:       #e1e0d9;
  --axis:       #c3c2b7;
  --hair:       rgba(11, 11, 11, .10);

  --accent:     #2a78d6;
  --accent-2:   #1c5cab;
  /* Derived, so a bought accent (set as an inline --accent on :root by
     applyAccent) drags its own wash along without JS computing a tint. */
  --accent-wash: color-mix(in srgb, var(--accent) 10%, transparent);
  --on-accent:  #ffffff;

  --good:       #006300;
  --bad:        #d03b3b;

  --m1: #86b6ef;
  --m2: #5598e7;
  --m3: #2a78d6;
  --m4: #1c5cab;
  --m5: #104281;

  --r-xs: 6px;
  --r-sm: 10px;
  --r:    16px;
  --r-lg: 22px;

  --sh-1: 0 1px 2px rgba(11, 11, 11, .04), 0 1px 3px rgba(11, 11, 11, .05);
  --sh-2: 0 10px 30px rgba(11, 11, 11, .12), 0 2px 6px rgba(11, 11, 11, .06);

  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --rail-w: 248px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --plane:     #0d0d0d;
    --surface:   #1a1a19;
    --surface-2: #232322;
    --surface-3: #2e2e2b;
    --ink:       #ffffff;
    --ink-2:     #c3c2b7;
    --muted:     #898781;
    --grid:      #2c2c2a;
    --axis:      #383835;
    --hair:      rgba(255, 255, 255, .10);
    --accent:    #3987e5;
    --accent-2:  #6da7ec;
    --accent-wash: color-mix(in srgb, var(--accent) 14%, transparent);
    --good:      #0ca30c;
    --bad:       #e66767;
    --m1: #9ec5f4;
    --m2: #6da7ec;
    --m3: #3987e5;
    --m4: #256abf;
    --m5: #184f95;
    --sh-1: 0 1px 2px rgba(0, 0, 0, .4);
    --sh-2: 0 10px 30px rgba(0, 0, 0, .55), 0 2px 6px rgba(0, 0, 0, .4);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --plane:     #0d0d0d;
  --surface:   #1a1a19;
  --surface-2: #232322;
  --surface-3: #2e2e2b;
  --ink:       #ffffff;
  --ink-2:     #c3c2b7;
  --muted:     #898781;
  --grid:      #2c2c2a;
  --axis:      #383835;
  --hair:      rgba(255, 255, 255, .10);
  --accent:    #3987e5;
  --accent-2:  #6da7ec;
  --accent-wash: color-mix(in srgb, var(--accent) 14%, transparent);
  --good:      #0ca30c;
  --bad:       #e66767;
  --m1: #9ec5f4;
  --m2: #6da7ec;
  --m3: #3987e5;
  --m4: #256abf;
  --m5: #184f95;
  --sh-1: 0 1px 2px rgba(0, 0, 0, .4);
  --sh-2: 0 10px 30px rgba(0, 0, 0, .55), 0 2px 6px rgba(0, 0, 0, .4);
}

/* ── reset ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html, body { height: 100%; }
body {
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--plane);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; }
a { color: inherit; text-decoration: none; }
img, svg { max-width: 100%; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
h1, h2, h3 { line-height: 1.25; font-weight: 600; letter-spacing: -.01em; }

/* ── app shell ─────────────────────────────────────────────────────────── */
.app { display: flex; min-height: 100%; }

.rail {
  display: none;
  width: var(--rail-w);
  flex: 0 0 var(--rail-w);
  flex-direction: column;
  gap: 8px;
  padding: 22px 14px;
  border-right: 1px solid var(--hair);
  background: var(--surface);
  position: sticky; top: 0; height: 100vh;
  transition: margin-left .3s cubic-bezier(.2, .85, .3, 1);
}
/* Collapsing pulls the rail off the left edge and lets .main reflow into the
   space. Content overflowing to the LEFT is not scrollable in LTR, so this
   needs no overflow clipping — which matters, because `overflow: hidden` on an
   ancestor would break the sticky topbar. */
.app.rail-hidden .rail { margin-left: calc(var(--rail-w) * -1); }

/* Needs .topbar to outrank `.btn { display: inline-flex }`, which is defined
   later in this file at the same specificity. */
.topbar .rail-toggle { display: none; align-self: center; margin-right: 2px; flex: none; }
.brand { display: flex; align-items: center; gap: 10px; padding: 4px 10px 18px; }
.brand-mark { font-size: 22px; line-height: 1; }
.brand-name { font-weight: 600; letter-spacing: -.02em; font-size: 17px; }

.rail-nav { display: flex; flex-direction: column; gap: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: var(--r-sm);
  color: var(--ink-2); font-weight: 500;
  transition: background .12s ease, color .12s ease;
  text-align: left; width: 100%;
}
.nav-item:hover { background: var(--surface-2); color: var(--ink); }
.nav-item[aria-current="page"] { background: var(--accent-wash); color: var(--accent); font-weight: 600; }
.nav-item svg { flex: 0 0 20px; }

.rail-foot { margin-top: auto; }
.user-chip {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px; border-radius: var(--r-sm); border: 1px solid var(--hair);
  background: var(--surface); text-align: left;
}
.user-chip:hover { background: var(--surface-2); }
.avatar {
  width: 32px; height: 32px; flex: none; border-radius: 50%;
  background: var(--accent); color: var(--on-accent);
  display: grid; place-items: center; font-size: 13px; font-weight: 600;
}
.user-meta { min-width: 0; display: grid; }
.user-label { font-size: 11px; color: var(--muted); }
.user-email { font-size: 13px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: flex-end; gap: 16px;
  padding: 18px 20px 14px;
  background: color-mix(in srgb, var(--plane) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(10px);
  border-bottom: 1px solid var(--hair);
}
.topbar-titles { min-width: 0; flex: 1 1 auto; }
.topbar-title { font-size: 22px; letter-spacing: -.02em; }
.topbar-sub { font-size: 13px; color: var(--muted); margin-top: 2px; }
.topbar-actions { display: flex; gap: 8px; align-items: center; }

.view {
  flex: 1 1 auto;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  padding: 20px 20px 120px;
}

/* ── bottom tabs (mobile) ──────────────────────────────────────────────── */
.tabbar {
  position: fixed; inset: auto 0 0 0; z-index: 30;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  border-top: 1px solid var(--hair);
  padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
}
.tab {
  display: grid; justify-items: center; gap: 3px;
  padding: 6px 2px; border-radius: var(--r-sm);
  color: var(--muted); font-size: 11px; font-weight: 500;
}
.tab[aria-current="page"] { color: var(--accent); font-weight: 600; }
.tab:active { background: var(--surface-2); }

@media (min-width: 900px) {
  .rail { display: flex; }
  .tabbar { display: none; }
  /* Only offered on desktop — phones navigate from the bottom tab bar. */
  .topbar .rail-toggle { display: inline-flex; }
  .view { padding: 26px 28px 80px; }
  .topbar { padding: 22px 28px 16px; }
}

/* ── buttons ───────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 14px; border-radius: 999px;
  border: 1px solid var(--hair); background: var(--surface);
  color: var(--ink); font-weight: 550; font-size: 14px; white-space: nowrap;
  transition: background .12s ease, border-color .12s ease, transform .06s ease;
}
.btn:hover { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); border-color: transparent; color: var(--on-accent); box-shadow: var(--sh-1); }
.btn-primary:hover { background: var(--accent-2); }
.btn-ghost { border-color: transparent; background: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: var(--surface-2); color: var(--ink); }
.btn-danger { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
.btn-danger:hover { background: color-mix(in srgb, var(--bad) 10%, transparent); }
.btn-sm { padding: 6px 11px; font-size: 13px; }
.btn-icon { padding: 9px; border-radius: 50%; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
@media (max-width: 560px) {
  .btn-label-wide { display: none; }
  .view { padding: 16px 14px 110px; }
  .card-body { padding: 12px 12px 14px; }
  .card-head { padding: 14px 14px 0; }
}

/* ── cards & generic bits ──────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  box-shadow: var(--sh-1);
}
.card-head {
  display: flex; align-items: baseline; gap: 12px;
  padding: 16px 18px 0;
}
.card-title { font-size: 15px; font-weight: 600; }
.card-sub { font-size: 12.5px; color: var(--muted); }
.card-head .spacer { flex: 1 1 auto; }
.card-body { padding: 14px 18px 18px; }

.section-label {
  font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin: 26px 4px 10px;
}
.section-label:first-child { margin-top: 4px; }
.stack { display: grid; gap: 14px; }
.muted { color: var(--muted); }
.hint { font-size: 12.5px; color: var(--muted); }

.empty {
  display: grid; justify-items: center; gap: 10px; text-align: center;
  padding: 46px 24px; color: var(--muted);
}
.empty-mark { font-size: 34px; }
.empty h3 { color: var(--ink); font-size: 16px; }
.empty p { max-width: 32ch; font-size: 13.5px; }

/* ── today prompt ──────────────────────────────────────────────────────── */
.today {
  background: var(--surface);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  padding: 18px;
  margin-bottom: 22px;
}
.today-q { font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
.today-date { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.mood-picker { display: flex; gap: 7px; margin-top: 14px; flex-wrap: wrap; }
/* min-width has to clear five buttons inside the DIALOG, which is narrower than
   the diary card — at 62px they wrapped 4+1 on a 375px phone. */
.mood-btn {
  flex: 1 1 0; min-width: 54px;
  display: grid; justify-items: center; gap: 5px;
  padding: 11px 4px; border-radius: var(--r-sm);
  border: 1px solid var(--hair); background: var(--surface);
  transition: background .12s ease, border-color .12s ease, transform .08s ease;
}
.mood-btn:hover { background: var(--surface-2); transform: translateY(-1px); }
.mood-btn[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-wash); }
.mood-btn .glyph { font-size: 24px; line-height: 1; }
.mood-btn .name { font-size: 11.5px; color: var(--ink-2); }
.mood-img { width: 26px; height: 26px; border-radius: var(--r-xs); object-fit: cover; display: block; }

/* ── diary list ────────────────────────────────────────────────────────── */
.month-head {
  display: flex; align-items: baseline; gap: 10px;
  margin: 22px 4px 8px; font-size: 13px; font-weight: 600; color: var(--ink-2);
}
.month-head .count { font-weight: 400; color: var(--muted); font-size: 12px; }

.entry-list { display: grid; gap: 8px; }
.entry-row {
  display: grid; grid-template-columns: 46px 40px 1fr auto; align-items: center; gap: 12px;
  width: 100%; text-align: left;
  padding: 12px 14px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--hair);
  transition: border-color .12s ease, background .12s ease, transform .06s ease;
}
.entry-row:hover { background: var(--surface-2); border-color: color-mix(in srgb, var(--accent) 30%, var(--hair)); }
.entry-row:active { transform: translateY(1px); }
.row-date { display: grid; justify-items: center; line-height: 1.15; }
.row-day { font-size: 18px; font-weight: 600; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.row-dow { font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.row-mood { display: grid; place-items: center; }
.chip {
  width: 36px; height: 36px; border-radius: 11px;
  display: grid; place-items: center; font-size: 20px; line-height: 1;
  box-shadow: inset 0 0 0 1px var(--hair);
}
.chip img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
.row-text { min-width: 0; }
.row-note {
  font-size: 14px; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.row-note.is-blank { color: var(--muted); font-style: italic; }
.row-mood-name { font-size: 12px; color: var(--muted); margin-top: 1px; }
.row-score {
  font-size: 13px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 7px;
}
.score-dot { width: 8px; height: 8px; border-radius: 50%; }
@media (max-width: 560px) { .row-score .of { display: none; } }

/* ── entry detail ──────────────────────────────────────────────────────── */
.detail-hero {
  display: flex; align-items: center; gap: 16px;
  padding: 20px; border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--hair); box-shadow: var(--sh-1);
}
.detail-chip { width: 64px; height: 64px; border-radius: 18px; font-size: 34px; }
.detail-mood { font-size: 20px; font-weight: 600; letter-spacing: -.01em; }
.detail-date { font-size: 13px; color: var(--muted); }
.detail-score { margin-left: auto; text-align: right; }
.detail-score .n { font-size: 30px; font-weight: 600; letter-spacing: -.02em; }
.detail-score .l { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.note-body { white-space: pre-wrap; font-size: 15px; line-height: 1.6; }

.field-grid { display: grid; gap: 1px; background: var(--hair); border-radius: var(--r); overflow: hidden; border: 1px solid var(--hair); }
.field-row { display: flex; gap: 16px; padding: 12px 16px; background: var(--surface); font-size: 13.5px; }
.field-row dt { color: var(--muted); flex: 0 0 130px; }
.field-row dd { color: var(--ink-2); min-width: 0; overflow-wrap: anywhere; }

/* ── calendar ──────────────────────────────────────────────────────────── */
.cal-head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.cal-month { font-size: 16px; font-weight: 600; letter-spacing: -.01em; min-width: 9.5ch; }
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 5px; }
.cal-dow {
  text-align: center; font-size: 11px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); padding-bottom: 4px;
  overflow: hidden;
}
.cal-cell {
  position: relative; aspect-ratio: 1 / 1; min-width: 0;
  display: grid; grid-template-rows: auto 1fr; gap: 2px;
  padding: 4px 3px 6px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--hair);
  transition: border-color .12s ease, transform .06s ease;
}
.cal-cell:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--hair)); }
.cal-cell:active { transform: translateY(1px); }
.cal-cell.is-blank { background: transparent; border-color: transparent; pointer-events: none; }
.cal-cell.is-future { opacity: .4; cursor: default; }
.cal-cell.is-future:hover { border-color: var(--hair); }
/* A past day with nothing logged can never be filled in — dimmed, not tappable. */
.cal-cell.is-missed { opacity: .5; cursor: default; background: transparent; border-style: dashed; }
.cal-cell.is-missed:hover { border-color: var(--hair); }
/* Repaired by a streak repair: still a day with no mood on it, so it keeps the
   dashed empty treatment and only gains a link mark. It must never look logged. */
.cal-cell.is-bridged { opacity: .75; border-color: color-mix(in srgb, var(--accent) 45%, var(--hair)); }
.cal-bridge { place-self: center; font-size: clamp(10px, 2.6vw, 14px); line-height: 1; filter: grayscale(.3); }
.cal-cell.is-today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.cal-num { font-size: 11px; font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums; text-align: center; }
.cal-cell.is-today .cal-num { color: var(--accent); }
.cal-chip {
  place-self: center; width: min(100%, 32px); aspect-ratio: 1;
  border-radius: 9px; display: grid; place-items: center;
  font-size: clamp(12px, 3.4vw, 18px); line-height: 1;
}
.cal-chip img { width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }
.cal-empty-dot { place-self: center; width: 5px; height: 5px; border-radius: 50%; background: var(--surface-3); }

.legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 16px; }
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-2); }
.legend-swatch { width: 12px; height: 12px; border-radius: 4px; }
.legend-line { width: 16px; height: 2px; border-radius: 1px; }

/* ── insights ──────────────────────────────────────────────────────────── */
.filter-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.segmented {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--surface-2); border-radius: 999px; border: 1px solid var(--hair);
}
.segmented button {
  padding: 6px 13px; border-radius: 999px; font-size: 13px; font-weight: 500; color: var(--ink-2);
  transition: background .12s ease, color .12s ease;
}
.segmented button:hover { color: var(--ink); }
.segmented button[aria-pressed="true"] { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: var(--sh-1); }

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-bottom: 16px; }
.tile { padding: 16px 18px; }
.tile-label { font-size: 12.5px; color: var(--muted); }
.tile-value { font-size: 30px; font-weight: 600; letter-spacing: -.025em; margin-top: 4px; }
.tile-value.hero { font-size: 52px; line-height: 1.05; letter-spacing: -.03em; }
.tile-foot { font-size: 12.5px; color: var(--muted); margin-top: 4px; display: flex; align-items: center; gap: 5px; }
.delta { display: inline-flex; align-items: center; gap: 4px; font-weight: 600; }
.delta.up { color: var(--good); }
.delta.down { color: var(--bad); }
.delta.flat { color: var(--muted); }

.chart-host { position: relative; margin-top: 6px; }
.chart-host svg { display: block; width: 100%; overflow: visible; }
.chart-host svg:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* Bar hit targets are focusable links into that mood's entries. */
.chart-host svg rect:focus-visible { outline: 2px solid var(--accent); }

.link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.link:hover { text-decoration-thickness: 2px; }
a.mood-refs { color: var(--accent); }

.tip {
  position: absolute; z-index: 5; pointer-events: none; opacity: 0;
  transform: translate(-50%, -100%);
  background: var(--surface); border: 1px solid var(--hair); border-radius: var(--r-sm);
  box-shadow: var(--sh-2); padding: 8px 10px; min-width: 120px;
  transition: opacity .1s ease;
}
.tip.on { opacity: 1; }
.tip-date { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.tip-row { display: flex; align-items: center; gap: 7px; margin-top: 4px; white-space: nowrap; }
.tip-key { width: 14px; height: 2px; border-radius: 1px; flex: none; }
.tip-key.sq { width: 10px; height: 10px; border-radius: 3px; }
.tip-val { font-size: 15px; font-weight: 600; color: var(--ink); }
.tip-name { font-size: 12.5px; color: var(--ink-2); }

.data-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.data-table caption { text-align: left; font-size: 12.5px; color: var(--muted); padding-bottom: 8px; }
.data-table th, .data-table td { padding: 7px 10px; text-align: left; border-bottom: 1px solid var(--grid); }
.data-table th { font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 600; }
.data-table td.num, .data-table th.num { text-align: right; }
.data-table td.num { font-variant-numeric: tabular-nums; }
.table-wrap { max-height: 320px; overflow: auto; }
[hidden] { display: none !important; }

/* ── moods admin ───────────────────────────────────────────────────────── */
.mood-list { display: grid; gap: 8px; }
.mood-row {
  display: grid; grid-template-columns: 48px 1fr auto auto; align-items: center; gap: 14px;
  padding: 12px 14px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--hair);
}
.mood-row .chip { width: 44px; height: 44px; font-size: 24px; }
.mood-name { font-weight: 550; }
.mood-refs { font-size: 12.5px; color: var(--muted); }
.pill {
  font-size: 12px; font-weight: 600; padding: 3px 9px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.pill.accent { background: var(--accent-wash); color: var(--accent); }

/* ── coins ─────────────────────────────────────────────────────────────────
   Earning is mood-blind on purpose (see app.js), so nothing here ranks a day by
   how good it was — the shop is the only place value appears.

   The pill carries .btn.btn-sm in the markup; only the overrides live here. */
.coin-pill {
  flex: 0 0 auto; gap: 6px;
  background: var(--surface-2); font-weight: 600; font-variant-numeric: tabular-nums;
}
.coin-pill:hover { background: var(--surface); border-color: color-mix(in srgb, var(--accent) 40%, var(--hair)); }
.coin-pill.is-boosted { border-color: var(--accent); background: var(--accent-wash); color: var(--accent); }
.coin-mark { font-size: 14px; line-height: 1; }
.coin-boost { font-size: 11px; font-weight: 700; }

.daily-btn { position: relative; align-self: center; flex: none; }
.daily-btn.is-ready { color: var(--accent); }
.daily-dot {
  position: absolute; top: 4px; right: 4px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 2px var(--plane);
}

.daily-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(74px, 1fr));
  gap: 8px; margin: 14px 0;
}
.daily-day { gap: 6px; padding: 12px 6px; }
.daily-day.is-done { border-color: color-mix(in srgb, var(--accent) 40%, var(--hair)); opacity: .7; }
.daily-n { font-size: 11px; font-weight: 600; color: var(--muted); letter-spacing: .03em; }
.daily-coins { font-size: 19px; font-weight: 600; font-variant-numeric: tabular-nums; }
.daily-day.is-now .daily-coins { color: var(--accent); }
.daily-tick { display: grid; place-items: center; height: 25px; color: var(--accent); }

.coin-hero { display: flex; align-items: center; gap: 16px; }
.coin-hero-mark { font-size: 34px; line-height: 1; }
.coin-hero-num { font-size: 34px; font-weight: 600; line-height: 1.05; font-variant-numeric: tabular-nums; }
.coin-hero-label { font-size: 12.5px; color: var(--muted); }
.coin-hero-boost { margin-left: auto; display: grid; gap: 4px; justify-items: end; text-align: right; }

.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
/* Shop tiles and daily-reward tiles are the same object: a bordered square with
   a centred stack and a selected state. Kept as one rule so they cannot drift. */
.shop-item, .daily-day {
  display: grid; gap: 8px; justify-items: center; text-align: center;
  padding: 14px 10px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--hair);
}
.shop-item.is-worn, .daily-day.is-now { border-color: var(--accent); }
.daily-day.is-now { background: var(--accent-wash); }
.shop-name { font-size: 13px; font-weight: 550; }
/* One medallion size for both marks, rather than a comment asking for one. */
.swatch, .boost-mult { width: 46px; height: 46px; border-radius: 50%; }
.swatch {
  background: linear-gradient(135deg, var(--s1) 0 50%, var(--s2) 50% 100%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.boost-mult {
  display: grid; place-items: center;
  background: var(--accent-wash); color: var(--accent);
  font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums;
}

.ledger-row {
  display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 12px;
  padding: 10px 14px; background: var(--surface); font-size: 13.5px;
}
.ledger-label { min-width: 0; overflow-wrap: anywhere; }
.ledger-when { color: var(--muted); font-size: 12px; }
.ledger-amt { font-weight: 600; font-variant-numeric: tabular-nums; min-width: 46px; text-align: right; }
.ledger-amt.up { color: var(--good); }
.ledger-amt.down, .ledger-amt.flat { color: var(--muted); }

.streak-coins {
  margin-top: 10px; display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px; border-radius: 999px;
  background: var(--accent-wash); color: var(--accent);
  font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums;
}

/* ── recently deleted ──────────────────────────────────────────────────── */
.trash-list { display: grid; gap: 8px; }
.trash-row {
  display: grid; grid-template-columns: 36px 1fr auto; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--hair);
}
.trash-row .chip { width: 34px; height: 34px; font-size: 18px; }
.trash-date { font-size: 14px; font-weight: 550; }
.trash-meta { font-size: 12px; color: var(--muted); margin-top: 1px; }
.trash-note {
  font-size: 12.5px; color: var(--ink-2); margin-top: 4px;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
.trash-foot {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--hair);
}
.trash-foot .hint { flex: 1 1 220px; }

/* ── dialog ────────────────────────────────────────────────────────────── */
.dlg {
  padding: 0; border: none; background: transparent; color: inherit;
  margin: auto;                       /* the global margin reset kills the UA default */
  width: min(520px, calc(100% - 32px)); max-height: 92vh;

}

/* Sheet motion is done with plain @keyframes, deliberately.
   The earlier version used @starting-style + `transition-behavior:
   allow-discrete` inside the `transition` shorthand. An unsupported value in a
   shorthand invalidates the WHOLE declaration, so on any browser without
   allow-discrete the sheet lost its movement AND its fade and simply snapped
   open — which is what happened on iOS. Keyframes have worked everywhere for a
   decade, and closing is driven from JS (closeSheet) rather than relying on the
   `overlay` property, which WebKit still doesn't support.

   To change the direction, edit the two keyframe pairs below — nothing else
   references them. */
.dlg[open] { animation: sheet-rise .34s cubic-bezier(.2, .85, .3, 1) both; }
.dlg[open]::backdrop { animation: backdrop-in .3s ease both; }

@keyframes sheet-rise {
  from { opacity: 0; transform: translateY(22px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes sheet-fall {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(14px) scale(.98); }
}
@keyframes sheet-slide-up {
  from { opacity: 0; transform: translateY(100%); }
  to   { opacity: 1; transform: none; }
}
@keyframes sheet-slide-down {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(100%); }
}
@keyframes backdrop-in  { from { background-color: rgba(11, 11, 11, 0); } to { background-color: rgba(11, 11, 11, .42); } }
@keyframes backdrop-out { from { background-color: rgba(11, 11, 11, .42); } to { background-color: rgba(11, 11, 11, 0); } }

/* Must come after the [open] rules — same specificity, so source order wins. */
.dlg.is-closing { animation: sheet-fall .2s ease-in both; }
.dlg.is-closing::backdrop { animation: backdrop-out .2s ease both; }

.dlg::backdrop { background: rgba(11, 11, 11, .42); backdrop-filter: blur(2px); }
.sheet {
  background: var(--surface); border: 1px solid var(--hair);
  border-radius: var(--r-lg); box-shadow: var(--sh-2);
  display: flex; flex-direction: column; max-height: 92vh; overflow: hidden;
}
.sheet-head { display: flex; align-items: center; gap: 12px; padding: 18px 20px 12px; }
.sheet-title { font-size: 17px; font-weight: 600; letter-spacing: -.01em; flex: 1 1 auto; }
.sheet-body { padding: 4px 20px 18px; overflow-y: auto; display: grid; gap: 16px; }
.sheet-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 14px 20px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--hair); background: var(--surface);
}
.sheet-foot .spacer { flex: 1 1 auto; }
@media (max-width: 560px) {
  .dlg { width: 100%; max-width: 100%; margin: auto 0 0; }
  /* Phones get a full slide-up — the sheet already sits on the bottom edge.
     No scale: scaling a full-width sheet reads as a glitch. */
  .dlg[open] { animation-name: sheet-slide-up; }
  .dlg.is-closing { animation-name: sheet-slide-down; }
  .sheet { border-radius: var(--r-lg) var(--r-lg) 0 0; border-bottom: none; }
}

.field { display: grid; gap: 6px; }
.field > label, .field-legend { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.field .sub { font-size: 12px; color: var(--muted); }
.input, textarea.input, select.input {
  width: 100%; padding: 10px 12px; border-radius: var(--r-sm);
  border: 1px solid var(--hair); background: var(--surface-2); color: var(--ink);
  font-size: 15px; transition: border-color .12s ease, background .12s ease;
}
.input:focus { outline: none; border-color: var(--accent); background: var(--surface); box-shadow: 0 0 0 3px var(--accent-wash); }
textarea.input { resize: vertical; min-height: 96px; line-height: 1.55; }
.input[readonly] { color: var(--muted); background: var(--surface-2); }
fieldset { border: none; padding: 0; margin: 0; }
.readonly-note { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
.note-count { justify-self: end; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.derived {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px dashed var(--hair);
}
.derived .n { font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; }

.locked-field {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px dashed var(--hair);
  color: var(--ink-2); font-size: 14.5px;
}
.locked-field svg { color: var(--muted); flex: none; }
.locked-field .pill { margin-left: auto; }

.locked-note {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 14px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--hair);
  color: var(--muted); font-size: 12.5px;
}
.locked-note svg { flex: none; }

/* ── settings ──────────────────────────────────────────────────────────── */
.setting-row {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 18px; border-bottom: 1px solid var(--hair);
}
.setting-row:last-child { border-bottom: none; }
.setting-text { flex: 1 1 220px; min-width: 0; }
.setting-title { font-size: 14px; font-weight: 550; }
.setting-desc { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

.schema { font-size: 13px; }
.schema code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; background: var(--surface-2); padding: 1px 5px; border-radius: var(--r-xs);
}
.schema .table-name { font-weight: 600; margin: 14px 0 6px; }
.schema .table-name:first-child { margin-top: 0; }
.schema ul { margin: 0; padding-left: 18px; color: var(--ink-2); display: grid; gap: 3px; }

/* ── toast ─────────────────────────────────────────────────────────────── */
.toast {
  position: fixed; left: 50%; bottom: calc(84px + env(safe-area-inset-bottom)); z-index: 60;
  transform: translate(-50%, 12px); opacity: 0; pointer-events: none;
  background: var(--ink); color: var(--plane);
  padding: 10px 16px; border-radius: 999px; font-size: 13.5px; font-weight: 500;
  box-shadow: var(--sh-2); transition: opacity .16s ease, transform .16s ease;
}
.toast.on { opacity: 1; transform: translate(-50%, 0); }
@media (min-width: 900px) { .toast { bottom: 28px; } }

/* ── streak celebration ────────────────────────────────────────────────── */
/* Fires when logging a day extends the streak. Deliberately warm rather than
   exuberant: this is a mood diary, and a rough day still deserves credit for
   showing up. Sparks are suppressed at score <= 2 — confetti over "couldn't
   get out of bed" would be tone-deaf. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

.streak-cheer {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center; padding: 20px;
  pointer-events: none;                 /* never blocks the app underneath */
}
.streak-cheer.is-out { opacity: 0; transition: opacity .3s ease; }
/* Soft scrim so the card reads as an overlay rather than floating in the list.
   Purely visual — the parent is pointer-events: none, so nothing is blocked. */
.streak-cheer::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(closest-side circle at 50% 50%,
    color-mix(in srgb, var(--plane) 78%, transparent) 0%, transparent 72%);
  animation: cheer-fade .45s ease both;
}
@keyframes cheer-fade { from { opacity: 0; } to { opacity: 1; } }

.streak-card {
  /* Ring and sparks wear the ACCENT, not the mood colour: the mood ramp's dark
     end disappears on the dark surface and its pale end disappears on the light
     one, so a "Great" day would get the dimmest ring. The mood still shows up,
     as the badge's background tint, where contrast doesn't matter. */
  --cheer: var(--accent);
  --cheer-tint: var(--accent);
  display: grid; justify-items: center; gap: 3px;
  padding: 26px 34px 24px; border-radius: 28px;
  background: var(--surface); border: 1px solid var(--hair);
  box-shadow: var(--sh-2);
  animation: cheer-in .52s cubic-bezier(.18, .86, .28, 1.14) both;
}
@keyframes cheer-in {
  from { opacity: 0; transform: translateY(16px) scale(.86); }
  60%  { opacity: 1; transform: translateY(0) scale(1.03); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.streak-badge {
  position: relative; width: 92px; height: 92px; margin-bottom: 10px;
  display: grid; place-items: center; border-radius: 50%;
  background: color-mix(in srgb, var(--cheer-tint) 18%, var(--surface));
  box-shadow: inset 0 0 0 3px var(--cheer);
}
/* The number sits on the surface, never on the coloured fill — the mood ramp's
   pale steps can't carry white text and its dark steps can't carry ink. */
.streak-num { font-size: 40px; font-weight: 600; letter-spacing: -.03em; line-height: 1; color: var(--ink); }
.streak-num.is-bump { animation: cheer-bump .44s cubic-bezier(.2, .9, .3, 1.3) both; }
@keyframes cheer-bump {
  from { transform: scale(.55); opacity: .25; }
  55%  { transform: scale(1.2); opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}

.streak-ring {
  position: absolute; inset: -5px; border-radius: 50%;
  border: 2px solid var(--cheer);
  animation: cheer-ring 1s ease-out both;
}
.streak-ring.two { animation-delay: .2s; }
@keyframes cheer-ring {
  from { transform: scale(.74); opacity: .7; }
  to   { transform: scale(1.6); opacity: 0; }
}

.streak-spark {
  position: absolute; top: 50%; left: 50%;
  width: 7px; height: 7px; border-radius: 50%; background: var(--cheer);
  animation: cheer-spark .85s cubic-bezier(.2, .7, .3, 1) both;
  animation-delay: var(--d, 0s);
}
@keyframes cheer-spark {
  from { transform: translate(-50%, -50%) rotate(var(--a)) translateY(0) scale(1); opacity: 0; }
  22%  { opacity: 1; }
  to   { transform: translate(-50%, -50%) rotate(var(--a)) translateY(calc(var(--r) * -1)) scale(.25); opacity: 0; }
}

.streak-title { font-size: 18px; font-weight: 600; letter-spacing: -.01em; }
.streak-sub { font-size: 13px; color: var(--muted); text-align: center; max-width: 26ch; margin-top: 2px; }

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: .01ms !important; animation-duration: .01ms !important; }
  /* The card's end state is the visible one, so it still appears and still
     reads; only the motion is dropped. Rings and sparks end at opacity 0 and
     are purely decorative, so losing them costs nothing. */
}

/* Moods screen footer: the note and the reset control share a row on desktop
   and stack on a phone, so the button never crowds the sentence explaining it. */
.mood-foot {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; margin-top: 14px; flex-wrap: wrap;
}
.mood-foot .hint { flex: 1 1 320px; margin: 0; }
.mood-foot .btn { flex: 0 0 auto; }
