/* SHARED·DRUM (1052) — the two-column scroll wheel behind a readout.
 *
 * A big display-face number that, tapped, becomes two snapping columns with a selection band
 * across the middle. Sleep asks it for hours + minutes; the weight logger asks it for kilos +
 * grams. Copy-first port off `workbench/weaning/_shared/logger-surface.css`'s own THE SPIN
 * CONTROL block — class names unchanged (`.spin`/`.spin-open`/`.spin-cols`/`.spin-band`/
 * `.drum`/`.dv`/`.du`), which is what makes the two consumers a MOVE rather than a rewrite.
 * That kind-freedom was deliberate in the kept source and is stated there: "The class names are
 * deliberately kind-free (.spin, not .spin-duration) so the port is a move, not a rewrite."
 *
 * Owns: `.spin` · `.spin .v` · `.spin .v em` · `.spin.is-zero` · `.spin .cv` · `.spin .cv svg` ·
 * `.spin:focus-visible` · `.spin-open` · `.spin-cols` · `.spin-band` · `.drum` ·
 * `.drum::-webkit-scrollbar` · `.dv` · `.dv.on` · `.dv:focus-visible` · `.du`.
 *
 * NOT owned, deliberately (the caller's, per this card's boundary): the question label above the
 * readout, the confirm CTA inside the open panel (`.lg-cta`), the caption under a derived
 * readout (`.out-note`), and which value the wheel parks on when it opens.
 *
 * ⚠️ CANDIDATE DEFECT, CARRIED ACROSS UNFIXED (copy-first, flagged not silently repaired).
 * The kept sleep template renders the derived readout as `<div class="spin is-out">` — a static
 * div — but the only `is-out` rule anywhere in logger-surface.css is `.stepper.is-out`, a
 * DIFFERENT control. So `.spin.is-out` has never had a rule of its own: it inherits `.spin`
 * whole, including `cursor: pointer` on something that is not clickable. Verified directly:
 *   grep -c '\.spin\.is-out' workbench/weaning/_shared/logger-surface.css  ->  0
 *   grep -c 'spin is-out'    workbench/weaning/_bakeoffs/sleep-duration.js ->  1
 * Reported, not fixed — a pointer cursor on a readout is a real fault, and changing it here
 * would be a design ruling this port has no mandate to make.
 *
 * Font-size role tokens (D-463): --size-28 -> --text-display-sm (exact) · --size-14 ->
 * --text-body-sm (exact). --size-20 has NO role token — the scale names 18 (--text-subtitle) and
 * 22 (--text-title) and nothing between; the unselected drum row sits on that unnamed step in
 * the kept source, and moving it to either neighbour would resize a component this port is
 * meant to carry across unchanged. Kept, with the exception marked on the line.
 */

/* 🔴 THE NUMBER IS CENTRED IN THE PILL (Andrew, 2026-08-09), and centred against the FULL width,
 * not against what the caret leaves over — the caret comes out of the flow entirely. That is why
 * the closed number lands exactly where the open columns' band lands, so tapping it does not make
 * the figure jump. `justify-content: space-between` (the original) pinned the value hard left and
 * read as a list row; a plain `center` would sit it visibly left of true middle, the same bug in
 * a smaller hat. */
.spin { position: relative; width: 100%; display: flex; align-items: center;
  justify-content: center;
  background: var(--surface-card); border: 0; border-radius: var(--radius-pill);
  padding: var(--space-16) var(--space-20); cursor: pointer; }
.spin .v { font-family: var(--font-display); font-size: var(--text-display-sm);
  font-weight: var(--weight-600); color: var(--text-primary); }
.spin .v em { font-style: normal; font-family: var(--font-body); font-size: var(--text-body-sm);
  font-weight: var(--weight-500); color: var(--text-secondary);
  margin: 0 var(--space-8) 0 var(--radius-2); }
/* Untouched: a real zero in the quietest ink. Not dashes — an absence dressed as a value reads
 * as a control that failed. (The kept source's own words, and its own behaviour: this card
 * renders a grey ZERO for "nothing yet", never "--".) */
.spin.is-zero .v, .spin.is-zero .v em { color: var(--text-tertiary); }
.spin .cv { position: absolute; right: var(--space-20); top: 50%; transform: translateY(-50%);
  color: var(--text-tertiary); display: inline-flex; }
.spin .cv svg { width: var(--dim-16); height: var(--dim-16); }
.spin:focus-visible { outline: var(--radius-2) solid var(--accent); outline-offset: var(--radius-2); }

/* Open — same slot, same card, same radius. It grows downward only as far as three rows. */
.spin-open { background: var(--surface-card); border-radius: var(--radius-card);
  padding: var(--space-16); }
.spin-cols { display: flex; align-items: center; justify-content: center; gap: var(--space-8);
  position: relative; }
/* 🔴 THE SELECTED ROW IS A BAND ACROSS BOTH COLUMNS, which is what makes two independent
 * scrollers read as ONE reading. Behind the numbers, never over them. */
.spin-band { position: absolute; left: 0; right: 0; top: 50%; height: var(--dim-40);
  transform: translateY(-50%); background: var(--surface-well);
  border-radius: var(--radius-control); pointer-events: none; }

/* `position: relative` so the columns paint ABOVE the selection band — an absolutely positioned
 * sibling otherwise covers static ones, and the selected number vanished.
 *
 * ⚠️ THE HEIGHT IS NAMED ONCE. The kept rule wrote 132px twice — once as the height, once inside
 * the padding calc that centres the first and last values in the band — with its own comment
 * warning that a hard value "would drift the moment either changes". Two literals is exactly that
 * drift waiting to happen, so the port names it as one local custom property and derives the
 * padding from it. Computed values are identical: height 132px, padding calc((132px - 40px)/2) =
 * 46px. Three rows, so the neighbours above and below stay visible — that is what makes a drum
 * read as a drum and not a list. (The kept file also carries the history of getting this wrong:
 * the padding once asked for a --space-44 that does not exist, the whole declaration was dropped
 * silently at parse time, and 0h sat at the TOP of a column while the band highlighted 1h.) */
.drum { --drum-h: 132px; /* token-exception */
  position: relative; height: var(--drum-h);
  overflow-y: auto; scroll-snap-type: y mandatory; display: flex; flex-direction: column;
  scrollbar-width: none;
  padding: calc((var(--drum-h) - var(--dim-40)) / 2) 0; }
.drum::-webkit-scrollbar { display: none; }
.dv { scroll-snap-align: center; background: none; border: 0; cursor: pointer;
  padding: 0 var(--space-12); height: var(--dim-40); line-height: var(--dim-40);
  font-family: var(--font-display); font-size: var(--size-20); /* token-exception */
  color: var(--text-tertiary); }
.dv.on { font-size: var(--text-display-sm); font-weight: var(--weight-600);
  color: var(--text-primary); }
/* ⚠️ ONE ADDITION BEYOND THE KEPT SOURCE, DISCLOSED: `.dv:focus-visible`. Every value in an open
 * column is a real <button> and the kept block gave the closed pill a focus ring but gave the
 * column values none — so keyboard focus inside an open drum was invisible. Same ring, same
 * tokens, same shape as `.spin:focus-visible` two rules up; nothing else about the row changes. */
.dv:focus-visible { outline: var(--radius-2) solid var(--accent); outline-offset: var(--radius-2); }
.du { font-family: var(--font-body); font-size: var(--text-body-sm); color: var(--text-secondary);
  z-index: 1; }
