/* Pumo Feed Log — styles.css.
   Visual system from the "Pumo" Design System artifact (tokens.json + component previews):
   warm cream/ink palette, Fredoka type, soft-everywhere radii, a sticker-ledge Log button.
   Structure, copy, states and a11y behavior are unchanged and still come from design.md/contract.md —
   only color, type, spacing, radius, shadow and iconography changed. Every selector below is the
   same one home.js/history.js/ui.js already render into; none were renamed. */

:root {
  color-scheme: light dark;

  --surface-100: #FBF2E4;
  --surface-000: #FFFDF8;
  --surface-200: #EDE1CE;
  --border-strong: #8F7E69;
  --ink: #262019;
  --ink-soft: #6E6255;
  --accent: #BFE1F0;
  --accent-strong: #1B6E93;
  --on-accent-strong: #FFFFFF;
  --warning: #8A4B12;
  --warning-bg: #F6E1C2;
  --danger: #A23B2B;
  --danger-bg: #F5DAD3;
  --on-danger: #FFFFFF;
  --success: #2F7A4F;

  --shadow-sm: 0 1px 2px rgba(38, 32, 25, 0.10);
  --shadow-md: 0 6px 16px rgba(38, 32, 25, 0.12);
  --shadow-button: 0 3px 0 #124F6B;

  --font-family: "Fredoka", ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface-100: #1E1913;
    --surface-000: #2A231B;
    --surface-200: #332B21;
    --border-strong: #7E6B54;
    --ink: #F3E9D8;
    --ink-soft: #C2B29C;
    --accent: #24404C;
    --accent-strong: #6FBBDE;
    --on-accent-strong: #16222A;
    --warning: #E7A756;
    --warning-bg: #4A341C;
    --danger: #E2836F;
    --danger-bg: #4A241C;
    --on-danger: #1E1913;
    --success: #7FC98F;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
    --shadow-md: 0 6px 16px rgba(0, 0, 0, 0.45);
    --shadow-button: 0 3px 0 #3E7C96;
  }
}

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

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

html {
  font-size: 100%;
}

body {
  margin: 0;
  background: var(--surface-100);
  color: var(--ink);
  font-family: var(--font-family);
  font-size: 1.0625rem;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

button, input {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

button:disabled {
  cursor: default;
}

a {
  color: var(--accent-strong);
}

/* Author-origin `display` on a component class (e.g. .banner, .undo-notice, .name-card,
   .older-error, .btn) otherwise beats the UA's default `[hidden]{display:none}`, so any
   element we toggle with the `hidden` attribute must be forced hidden here regardless of
   what else targets it. */
[hidden] {
  display: none !important;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

h1, h2, p {
  margin: 0;
}

time, .tabular {
  font-variant-numeric: tabular-nums;
}

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

:focus-visible {
  outline: 3px solid var(--accent-strong);
  outline-offset: 2px;
}

/* ---- Layout ----------------------------------------------------------------------------- */

.page {
  max-width: 440px;
  margin-inline: auto;
  padding: 16px calc(20px + env(safe-area-inset-right)) calc(28px + env(safe-area-inset-bottom)) calc(20px + env(safe-area-inset-left));
  padding-top: calc(24px + env(safe-area-inset-top));
  display: flex;
  flex-direction: column;
  /* design.md §3.1's AC-2.3a fallback, step 1: v1.1's pet-picker row (§3.0) eats into the
     375×553 budget, so the section gap is tightened from its original 16px. */
  gap: 8px;
}

#data-block {
  display: flex;
  flex-direction: column;
}

/* ---- Banner (refresh error, S4) ---------------------------------------------------------- */

.banner {
  background: var(--danger-bg);
  color: var(--danger);
  border-radius: 16px;
  padding: 12px 16px;
  font-size: 0.9375rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.banner__retry {
  min-height: 44px;
  min-width: 44px;
  font-weight: 600;
  color: var(--danger);
  text-decoration: underline;
  flex-shrink: 0;
}

/* ---- Pet picker (design.md §3.0, v1.1) --------------------------------------------------- */

.pet-picker {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
}

/* design.md §3.1's AC-2.3a fallback, step 2: the 375×553 budget needs the picker row shrunk
   below its default 40px/48px sizing. The tap target itself stays a fixed 44×44 (accessible
   minimum) via centering padding — only the *visual* avatar inside it (in .pet-avatar below)
   gets smaller. v1.3: bumped back up from 28px/32px to 32px/36px (Dathan's "a little bigger,
   more accessible" ask, re-verified against AC-2.3a's 375×553 budget — see docs/design.md
   §3.1). Still short of the original 40px/48px full-size intent, which the budget doesn't
   allow at this viewport. */
.pet-picker__item {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  flex-shrink: 0;
  opacity: 0.7;
  transition: opacity 120ms ease;
}

.pet-picker__item:hover,
.pet-picker__item:focus-visible {
  opacity: 1;
}

.pet-picker__item--selected {
  opacity: 1;
}

.pet-avatar {
  display: block;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--accent);
}

.pet-picker__item--selected .pet-avatar {
  width: 36px;
  height: 36px;
  border: 2px solid var(--accent-strong);
}

.pet-avatar__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.pet-avatar--placeholder.pet-avatar--dog {
  background: var(--surface-200);
}

.pet-avatar__ear {
  fill: var(--accent-strong);
}

.pet-avatar--cat .pet-avatar__fill {
  fill: var(--accent-strong);
}

.pet-avatar--cat .pet-avatar__initial {
  fill: var(--on-accent-strong);
}

/* A fixed (non-theme-flipping) dark neutral, same family as --border-strong, chosen so its
   white initial clears 4.5:1 in both light and dark mode (validated: 8.01:1) — same pattern as
   --pumo, the avatar-ring token, which is also one constant hex across both modes. */
.pet-avatar--dog .pet-avatar__fill {
  fill: #5D4E3C;
}

.pet-avatar--dog .pet-avatar__initial {
  fill: #FFFFFF;
}

.pet-avatar__initial {
  font-family: var(--font-family);
  font-weight: 700;
  font-size: 17px;
}

/* ---- Header ------------------------------------------------------------------------------ */

.header {
  display: flex;
  align-items: center;
  gap: 12px;
}

.header__text h1 {
  font-size: 1.375rem;
  line-height: 1.18;
  font-weight: 700;
}

.header .tagline {
  color: var(--ink-soft);
  font-size: 0.8125rem;
  line-height: 1.4;
  margin-top: 1px;
}

/* ---- Headline ---------------------------------------------------------------------------- */

.headline__line {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.headline .label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink-soft);
}

.headline .label .icon {
  color: var(--ink-soft);
}

.headline .value {
  font-size: 2.75rem;
  line-height: 1.045;
  font-weight: 600;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}

.headline .value.value--empty {
  font-size: 1.5rem;
  font-weight: 600;
}

.headline .value.value--placeholder {
  display: inline-block;
  width: 60%;
  height: 2.75rem;
  border-radius: 10px;
  background: var(--surface-200);
}

/* ---- Counter pill -------------------------------------------------------------------------- */

.counter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  margin-top: 10px;
  margin-bottom: 0;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 700;
  background: var(--accent);
  color: var(--ink);
}

.counter.counter--warn {
  background: var(--warning-bg);
  color: var(--warning);
}

.counter.counter--loading {
  background: var(--surface-000);
  color: var(--ink-soft);
}

.counter .icon {
  color: currentColor;
}

/* ---- Recent list / rows -------------------------------------------------------------------- */

.recent {
  margin-top: 24px;
}

.recent__label {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 8px;
  display: block;
}

.row-list {
  background: var(--surface-000);
  border-radius: 16px;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.row {
  /* design.md §3.1: rows may shrink as far as this 56px floor (never below it) when the
     375x553 budget (AC-2.3a) needs the room; the round-2 QA fix drops vertical padding
     from 12px to 6px so height = the 44px delete button + 6+6px padding = 56px exactly.
     .row__actions (below) keeps its buttons' own fixed 44x44 sizing, independent of this
     height, so the tap targets are unaffected by the row shrinking.
     v1.2: gap and horizontal padding are trimmed a little further (12px->8px, 16px->12px)
     to make room for the new second (Edit) icon button without touching row height at all —
     per tasks.md's self-review note, height is non-negotiable but width is "fine to solve". */
  min-height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 12px;
  border-bottom: 1px solid var(--surface-200);
}

.row-list > .row:last-child {
  border-bottom: none;
}

.row__info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.row__line1 {
  font-size: 1rem;
  line-height: 1.375;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  /* v1.2: with a second icon button now sharing the row's width, a single-line ellipsis
     protects the fixed 56px row height (never wrapping to 2 lines) instead of letting a long
     label eat into the AC-2.3a vertical budget — a judgment call, see the hand-off notes. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.row__line2 {
  font-size: 0.875rem;
  line-height: 1.3;
  font-weight: 500;
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* v1.2: Edit + Delete now sit together, 4px apart (design.md §3.1/§3.6b), inside this wrapper. */
.row__actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.row__edit,
.row__delete {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  color: var(--ink-soft);
}

.row__edit:hover,
.row__delete:hover {
  background: var(--surface-200);
}

.row--placeholder {
  position: relative;
}

.row--placeholder::before,
.row--placeholder::after {
  content: '';
  position: absolute;
  left: 16px;
  height: 12px;
  border-radius: 6px;
  background: var(--surface-200);
}

.row--placeholder::before { top: 15px; width: 45%; }
.row--placeholder::after { top: 33px; width: 28%; }

.recent__empty {
  background: var(--surface-000);
  border-radius: 16px;
  box-shadow: var(--shadow-sm);
  padding: 18px 16px;
  color: var(--ink-soft);
  text-align: center;
}

/* ---- Row delete confirmation (design.md §3.6) ---------------------------------------------- */

.row--confirm {
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
  padding: 14px 16px 16px;
  background: var(--danger-bg);
}

.row__confirm-text {
  font-size: 0.875rem;
  line-height: 1.45;
  font-weight: 500;
  color: var(--danger);
}

.row__confirm-text--warn {
  font-weight: 700;
}

.row__deleting {
  color: var(--danger);
  font-size: 0.875rem;
  font-weight: 500;
}

.row__confirm-buttons {
  display: flex;
  gap: 10px;
}

/* ---- Row inline edit-time (design.md §3.6b, v1.2) ------------------------------------------ */
/* A neutral (non-warning) variant of the same "row grows in place" shape as .row--confirm —
   editing isn't a destructive action, so it doesn't borrow --danger-bg (§2's color-meaning
   rule: warm brown/rust is reserved for warnings/armed/not-saved states). The edit-failed and
   "this feed was deleted" states fall back to .row--confirm's own danger-bg instead, since
   design.md §3.6b explicitly asks the failed state to mirror §3.6's delete-failure look. */
.row--edit-open {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 14px 16px 16px;
  background: var(--surface-100);
}

.row__edit-label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
}

.row__edit-input {
  min-height: 44px;
  padding: 0 12px;
  border-radius: 12px;
  border: 2px solid var(--border-strong);
  background: var(--surface-000);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  align-self: stretch;
}

/* ---- Buttons (shared) ------------------------------------------------------------------------ */

.btn {
  min-height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.875rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 1;
}

.btn--outline {
  background: transparent;
  border: 2px solid var(--border-strong);
  color: var(--ink);
}

.btn--accent {
  background: var(--accent-strong);
  color: var(--on-accent-strong);
}

.btn--warn {
  background: var(--danger);
  color: var(--on-danger);
}

.btn--warn-outline {
  background: transparent;
  border: 2px solid var(--danger);
  color: var(--danger);
}

.btn--text {
  background: none;
  color: var(--accent-strong);
  flex: none;
  padding: 0 8px;
}

.btn--full {
  width: 100%;
  flex: none;
}

.btn:disabled {
  opacity: 0.6;
}

/* ---- Log button (design.md §3.4) -------------------------------------------------------------- */

.log-button {
  width: 100%;
  min-height: 64px;
  border-radius: 999px;
  font-size: 1.0625rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 22px;
  text-align: center;
  position: relative;
  overflow: hidden;
  transition: transform 120ms ease, box-shadow 120ms ease;
}

.log-button:active:not(:disabled) {
  transform: translateY(2px);
}

.log-button--loading {
  background: var(--surface-000);
  color: var(--ink-soft);
}

.log-button--ready {
  background: var(--accent-strong);
  color: var(--on-accent-strong);
  box-shadow: var(--shadow-button);
}

.log-button--ready:active:not(:disabled) {
  box-shadow: none;
}

.log-button--saving,
.log-button--logged,
.log-button--load-failed {
  background: var(--accent-strong);
  color: var(--on-accent-strong);
}

.log-button--saving {
  opacity: 0.92;
}

.log-button--guarded {
  background: var(--surface-100);
  border: 2px solid var(--border-strong);
  color: var(--ink);
}

.log-button--not-saved {
  background: var(--danger-bg);
  border: 2px solid var(--danger);
  color: var(--danger);
}

.log-button--armed {
  min-height: 72px;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding-top: 6px;
  background: var(--warning-bg);
  border: 2px solid var(--warning);
  color: var(--warning);
  font-size: 0.9375rem;
}

.log-button__bar {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
  height: 4px;
  width: auto;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.12);
  overflow: hidden;
}

.log-button__bar::before {
  content: '';
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 999px;
  background: var(--warning);
  transform-origin: left;
  animation: armed-shrink 6s linear forwards;
}

@keyframes armed-shrink {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

.icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* icon('spinner', 'spin') renders className="icon icon--spinner spin" — target the plain
   modifier class actually produced, not a compound "icon--spin" that would never match. */
.spin {
  animation: spin 900ms linear infinite;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ---- Undo notice (design.md §3.5) -------------------------------------------------------------- */

.undo-notice {
  position: relative;
  background: var(--surface-000);
  border-radius: 22px;
  box-shadow: var(--shadow-md);
  padding: 14px 16px 16px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  overflow: hidden;
  animation: fade-in 150ms ease;
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.undo-notice__text {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--ink);
}

.undo-notice__text .icon {
  color: var(--success);
}

.undo-notice__text--warn {
  color: var(--danger);
}

.undo-notice__text--warn .icon {
  color: var(--danger);
}

.undo-notice__action {
  min-height: 44px;
  padding: 0 10px;
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--accent-strong);
  flex-shrink: 0;
}

.undo-notice__dismiss {
  min-height: 44px;
  min-width: 44px;
  color: var(--danger);
  flex-shrink: 0;
}

.undo-notice__bar {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  width: 100%;
  background: var(--surface-200);
  overflow: hidden;
}

.undo-notice__bar::before {
  content: '';
  display: block;
  height: 100%;
  width: 100%;
  background: var(--accent-strong);
  transform-origin: left;
  animation: undo-shrink 10s linear forwards;
}

@keyframes undo-shrink {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

/* ---- History link / back link ------------------------------------------------------------------ */

.history-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 44px;
  margin-top: 2px;
  font-weight: 700;
  font-size: 0.875rem;
  color: var(--accent-strong);
  text-decoration: none;
}

.history-link .chevron,
.back-link .chevron {
  vertical-align: -3px;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  color: var(--accent-strong);
  font-weight: 700;
  font-size: 0.9375rem;
  text-decoration: none;
  align-self: flex-start;
}

/* ---- Name card (design.md §3.7) ------------------------------------------------------------------ */

.name-card {
  background: var(--surface-000);
  border-radius: 16px;
  box-shadow: var(--shadow-md);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.name-card__title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--ink);
}

.name-card__title .icon {
  color: var(--ink-soft);
}

.name-card__body {
  color: var(--ink-soft);
  font-size: 0.875rem;
  line-height: 1.5;
}

.name-card__label {
  font-size: 0.875rem;
  font-weight: 600;
}

.name-card__input {
  min-height: 48px;
  padding: 0 14px;
  border-radius: 12px;
  border: 2px solid var(--border-strong);
  background: var(--surface-100);
  color: var(--ink);
}

.name-card__input::placeholder {
  color: var(--ink-soft);
}

.name-card__buttons {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
}

.name-card .btn {
  min-height: 48px;
}

/* ---- Footer -------------------------------------------------------------------------------------- */

.footer {
  color: var(--ink-soft);
  font-size: 0.8125rem;
  text-align: center;
}

.footer__link {
  color: var(--accent-strong);
  font-weight: 700;
  min-height: 44px;
  padding: 0 4px;
}

/* ---- Error panel ---------------------------------------------------------------------------------- */

.panel {
  border-radius: 16px;
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.panel--warn {
  background: var(--danger-bg);
  color: var(--danger);
}

.panel__title {
  font-weight: 700;
  font-size: 1.0625rem;
}

.panel__body {
  font-size: 0.9375rem;
}

.panel .btn {
  align-self: flex-start;
  margin-top: 6px;
}

/* ---- History screen ---------------------------------------------------------------------------------- */

/* Direct-child combinator: matches only history.html's "Feed history" heading, never the
   home header's h1 (which sits nested inside .header__text, not a direct child of .page). */
.page > h1 {
  font-size: 1.875rem;
  line-height: 1.15;
  font-weight: 700;
  margin-top: 10px;
  color: var(--ink);
}

.day-group {
  margin-top: 24px;
}

.day-group__heading-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 8px;
}

.day-group h2 {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.day-group__count {
  color: var(--ink-soft);
  font-size: 0.8125rem;
  font-weight: 500;
}

.day-group__heading-placeholder {
  height: 0.75rem;
  width: 35%;
  border-radius: 8px;
  background: var(--surface-200);
  margin-bottom: 12px;
}

.history-empty {
  color: var(--ink-soft);
  padding: 12px 0;
}

.older-error {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--danger);
  font-size: 0.9375rem;
}

/* v1.2: #csv-error (shares .older-error's base look) now sits inside the heatmap card, between
   its header (legend + CSV button, v1.3) and the calendar grid below — .older-error's centered
   alignment reads oddly there and, with no margin of its own, crammed straight up against the
   grid right below it. Left-align it (matching the left-aligned legend/grid, instead of the
   centered "Show older feeds" error's own layout) and give it room to breathe on both sides. */
#csv-error {
  justify-content: flex-start;
  margin-bottom: 12px;
}

/* ---- CSV button (design.md §4.2; v1.2: restyled to .btn--text and moved into the heatmap
   card's own header; v1.3: icon-only, inline with the legend rather than right-aligned alone) - */

#csv-button.is-checking {
  opacity: 0.85;
}

/* v1.3: a compact square variant of .btn--text for icon-only controls — .btn's 44px min-height
   plus a matching fixed width gives a real 44×44 tap target around just the icon, no padding
   wide enough to imply hidden text (design.md §4.2/§7's icon-only-control rule). */
.btn--icon-only {
  width: 44px;
  padding: 0;
  flex: none;
}

/* ---- Heatmap (design.md §4.1, v1.1; §4.1/§4.2 header, v1.2) ---------------------------------- */

.heatmap {
  margin-top: 20px;
  background: var(--surface-000);
  border-radius: 16px;
  box-shadow: var(--shadow-sm);
  padding: 16px;
}

/* v1.3: a static header row, never touched by renderHeatmap()'s own clear/rebuild (it only
   targets #heatmap-content) — holds the legend on the left and the icon-only CSV button on the
   right, in one inline row. (architecture.md §4's "Heatmap card DOM shape" note, design.md
   §4.1/§4.2) The legend itself (#heatmap-legend) IS safe to rebuild — it's stateless and holds
   no listeners, unlike #csv-button — renderHeatmapLegend() just isn't called on every data
   refresh the way renderHeatmap() is, since the legend never depends on data. */
.heatmap__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.heatmap__legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
}

.heatmap__legend-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.heatmap__legend-swatch {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  display: inline-block;
}

.heatmap__legend-sep {
  font-size: 0.8125rem;
  color: var(--ink-soft);
  margin: 0 -6px;
}

.heatmap__weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  margin-bottom: 4px;
}

.heatmap__weekdays span {
  text-align: center;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--ink-soft);
}

.heatmap__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.heat-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  min-height: 40px;
  border-radius: 8px;
  padding: 4px;
  text-align: left;
}

.heat-cell__num {
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
}

.heat-cell--tier-0 {
  background: var(--surface-200);
}
.heat-cell--tier-0 .heat-cell__num {
  color: var(--ink-soft);
}

/* Sequential ramp, one hue (the app's teal accent), light→dark in light mode and dark→light in
   dark mode — chosen with the dataviz skill's ordinal-ramp validator (monotone OKLCH L, >=0.06
   adjacent step, light/dark-end contrast vs surface, single hue) and with each tier's own
   on-fill text color checked for >=4.5:1 (see build notes for the exact validator output). */
.heat-cell--tier-1 { background: #82B6CE; }
.heat-cell--tier-2 { background: #409EC9; }
.heat-cell--tier-3 { background: #20759D; }
.heat-cell--tier-4 { background: #155775; }
.heat-cell--tier-1 .heat-cell__num,
.heat-cell--tier-2 .heat-cell__num {
  color: var(--ink);
}
.heat-cell--tier-3 .heat-cell__num,
.heat-cell--tier-4 .heat-cell__num {
  color: #FFFFFF;
}

@media (prefers-color-scheme: dark) {
  .heat-cell--tier-1 { background: #2E586B; }
  .heat-cell--tier-2 { background: #326B85; }
  .heat-cell--tier-3 { background: #3D98C2; }
  .heat-cell--tier-4 { background: #5CAFD6; }
  .heat-cell--tier-1 .heat-cell__num,
  .heat-cell--tier-2 .heat-cell__num {
    color: var(--ink);
  }
  .heat-cell--tier-3 .heat-cell__num,
  .heat-cell--tier-4 .heat-cell__num {
    color: #16222A;
  }
}

.heat-cell--out {
  opacity: 0.4;
}

.heat-cell--today {
  outline: 2px solid var(--accent-strong);
  outline-offset: -2px;
}

.heat-cell--expanded {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
}

.heatmap__panel {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--surface-200);
}

.heatmap__panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.heatmap__panel-title {
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.heatmap__panel-close {
  min-height: 44px;
  min-width: 44px;
  color: var(--ink-soft);
}

.heatmap__panel-empty {
  color: var(--ink-soft);
  font-size: 0.875rem;
  padding: 4px 0;
}

.row--static {
  cursor: default;
}

/* ---- Reduced motion (design.md §2, motion) ----------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .log-button__bar::before,
  .undo-notice__bar::before {
    animation: none !important;
    transform: scaleX(0);
  }
}
