/* ── Tables (forecast and movements) ─────────────────────────────────── */
.scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  /* Without this, swiping past the end of a horizontally scrolling table
     triggers back-navigation on iOS — the real mobile bug here. */
  overscroll-behavior-x: contain;
  scrollbar-gutter: stable;
  /* Week-paging on a phone. `proximity`, not `mandatory`, which would fight
     fine-grained scrolling with a mouse. */
  scroll-snap-type: x proximity;
}
.scroll table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
}
/* The tables still need naming for a screen reader; they no longer need to say
   it on screen, where the heading above already does. */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.scroll th,
.scroll td {
  padding: 6px 12px;
  border-bottom: 1px solid var(--faint);
  text-align: left;
}
.scroll thead th {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  font-weight: 400;
  color: var(--muted);
  font-size: var(--fs-small);
}

/* ── Forecast (#grid) ───────────────────────────────────────────────── */
#grid table { width: auto; }
#grid th,
#grid td {
  white-space: nowrap;
  text-align: right;
}
#grid thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}
#grid thead th time {
  display: block;
  color: var(--ink);
}
#grid [scope=row],
#grid thead th:first-child {
  /* z-index:1, or a right-aligned nowrap price cell that overflows past its
     own left edge — the normal, expected way a sticky column partially covers
     a scrolled column — paints on TOP of this one instead of being covered by
     it: without an explicit value the sticky cell has z-index:auto, and later
     siblings in the same stacking context paint over earlier ones regardless
     of position:sticky. Visible as an icon "bleeding" into the room-name
     column while scrolling with a row expanded. */
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--bg);
  text-align: left;
  box-shadow: 1px 0 0 var(--border);
}
#grid [data-snap] { scroll-snap-align: start; }
#grid thead th:first-child { z-index: 2; }
#grid tbody th { font-weight: 400; }
#grid tr:not([data-variant]) > * { border-bottom: 1px solid var(--border); }
#grid [data-mine] { font-style: italic; }
#grid td[data-beats] {
  color: var(--critical);
  font-weight: 700;
}
#grid td[data-cheapest] {
  color: var(--good);
  font-weight: 700;
}
#grid td[data-absent] {
  color: var(--muted);
  font-style: italic;
  font-size: var(--fs-small);
}
/* The control is the whole cell, not the chevron. */
#grid [scope=row]:has(button) { padding: 0; }
#grid tr:has([data-expand]) { cursor: pointer; }
@media (hover: hover) {
  #grid tr:has([data-expand]):hover td { background: var(--faint); }
}
#grid [scope=row] button {
  border: none;
  background: none;
  color: inherit;
  width: 100%;
  justify-content: flex-start;
  gap: var(--space-small);
  padding: var(--space-small) var(--space-regular);
  text-align: left;
}
#grid [scope=row] button > span {
  display: inline-block;
  color: var(--muted);
}
#grid [scope=row] button[aria-expanded=true] > span { transform: rotate(90deg); }
#grid [data-variant] > * {
  font-size: var(--fs-small);
  color: var(--muted);
}
/* Stacked and clamped, or one long room name sets the column's width. */
#grid [data-variant] [scope=row] {
  white-space: normal;
  max-width: 15rem;
  min-width: 9rem;
}
/* One price per cell now, so it stays on its line with its marks beside it. */
#grid [data-variant] td { white-space: nowrap; }
#grid [data-compared] {
  color: var(--ink);
  font-weight: 700;
}

/* ── Plan marks (breakfast / free cancellation) ──────────────────────
   Marks, not words: with the filters on `any` these are what distinguishes
   one plan from another. Drawn as masks so they take the surrounding text
   colour in either theme, and cost no element of their own beyond the one
   span. Icons are Lucide, via the --icon-* tokens in tokens.css. */
.ic {
  display: inline-flex;
  gap: 2px;
  margin-right: 4px;
}
.ic::before,
.ic::after {
  width: 10px;
  height: 10px;
  background-color: currentColor;
  -webkit-mask: center / contain no-repeat;
  mask: center / contain no-repeat;
}
.ic[data-bf]::before {
  content: "";
  -webkit-mask-image: var(--icon-coffee);
  mask-image: var(--icon-coffee);
}
.ic[data-free]::after {
  content: "";
  -webkit-mask-image: var(--icon-refresh);
  mask-image: var(--icon-refresh);
}
.legend {
  display: flex;
  gap: var(--space-medium);
  align-items: center;
  margin-top: var(--space-small);
  font-size: var(--fs-small);
  color: var(--muted);
}
.legend .ic { margin-right: 2px; }

/* ── Movements (#moves) ────────────────────────────────────────────── */
#moves td:last-child {
  text-align: right;
  white-space: nowrap;
  font-weight: 700;
}
#moves [scope=row]:has(button) { padding: 0; }
#moves tr:has([data-check]) { cursor: pointer; }
@media (hover: hover) {
  #moves tr:has([data-check]):hover td { background: var(--faint); }
}
#moves [scope=row] button {
  border: none;
  background: none;
  color: inherit;
  width: 100%;
  justify-content: flex-start;
  gap: var(--space-small);
  padding: var(--space-small) var(--space-regular);
  text-align: left;
}
#moves [scope=row] button > span { color: var(--muted); }
#moves [scope=row] button[aria-expanded=true] > span {
  display: inline-block;
  transform: rotate(90deg);
}
#moves [data-detail] th { font-weight: 400; }
#moves [data-detail] small {
  display: block;
  color: var(--muted);
  font-size: var(--fs-xsmall);
}
#moves tr[hidden] { display: none; }
#moves [data-dir=up] { color: var(--warning); }
#moves [data-dir=down] { color: var(--good); }
#moves [data-dir=gone] {
  color: var(--muted);
  font-weight: 400;
  font-style: italic;
}
#moves time { color: var(--muted); }
#moves [data-truncated] { font-style: italic; }
