/* public/css/components.css — M4 shared UI kit (§4.7). Class prefix .ui- .
   Every color and spacing value comes from tokens.css tokens (§7). Stacking
   order is applied from JS as inline `var(--z-*)` styles, so no stacking
   values live in this file. */

/* ---------- shared button reset ---------- */
.ui-stepper-btn,
.ui-stepper-value,
.ui-numpad-key,
.ui-numpad-action,
.ui-modal-action,
.ui-timer-btn,
.ui-toast-action {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  margin: 0;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

/* ---------- scrim (shared by modal / sheet / timer overlays) ---------- */
.ui-scrim {
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.ui-modal--in .ui-scrim,
.ui-sheet-wrap--in .ui-scrim {
  opacity: 0.6;
}
.ui-timer--in .ui-scrim--deep {
  opacity: 0.85;
}

/* ---------- stepper (§4.7, R2.2/R2.4) ---------- */
.ui-stepper {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.ui-stepper-btn {
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--outline);
  border-radius: var(--radius-sm);
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  padding: 0 var(--sp-2);
}
.ui-stepper-btn--big {
  background: var(--surface);
}
.ui-stepper-btn:active {
  background: var(--outline);
}
.ui-stepper-value {
  flex: 1;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  background: transparent;
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--sp-1);
  color: var(--text);
}
.ui-stepper-num {
  font-size: 26px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.ui-stepper-suffix {
  font-size: 13px;
  color: var(--text-dim);
}
.ui-stepper--ghost .ui-stepper-value {
  opacity: var(--ghost-opacity);
}

/* ---------- numpad (§4.7, R2.4) ---------- */
.ui-numpad {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.ui-numpad-display {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap-min);
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-4);
}
.ui-numpad-value {
  font-size: 34px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.ui-numpad-display--ghost .ui-numpad-value {
  opacity: var(--ghost-opacity);
}
.ui-numpad-suffix {
  font-size: 15px;
  color: var(--text-dim);
}
.ui-numpad-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
}
.ui-numpad-key {
  min-height: calc(var(--tap-min) + var(--sp-2));
  font-size: 22px;
  font-weight: 600;
  color: var(--text);
  background: var(--surface-2);
  border-radius: var(--radius-sm);
}
.ui-numpad-key--fn {
  background: var(--surface);
  border: 1px solid var(--outline);
}
.ui-numpad-key:active {
  background: var(--outline);
}
.ui-numpad-actions {
  display: flex;
  gap: var(--sp-2);
}
.ui-numpad-action {
  flex: 1;
  min-height: var(--tap-min);
  border-radius: var(--radius-sm);
  font-size: 16px;
  font-weight: 600;
}
.ui-numpad-action--plain {
  background: var(--surface-2);
  color: var(--text);
}
.ui-numpad-action--ok {
  background: var(--accent);
  color: var(--accent-contrast);
}

/* ---------- confirm modal (§4.7, z var(--z-guard) from JS) ---------- */
.ui-modal {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
}
.ui-modal-card {
  position: relative;
  width: 100%;
  max-width: 360px;
  background: var(--surface);
  border: 1px solid var(--outline);
  border-radius: var(--radius);
  padding: var(--sp-5);
  opacity: 0;
  transform: translateY(var(--sp-3)) scale(0.97);
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.ui-modal--in .ui-modal-card {
  opacity: 1;
  transform: none;
}
.ui-modal--out .ui-modal-card {
  opacity: 0;
}
.ui-modal-title {
  margin: 0 0 var(--sp-3);
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
}
.ui-modal-body {
  margin: 0 0 var(--sp-4);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-dim);
}
.ui-modal-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.ui-modal-action {
  min-height: var(--tap-min);
  border-radius: var(--radius-sm);
  font-size: 16px;
  font-weight: 600;
  padding: 0 var(--sp-4);
}
.ui-modal-action--primary {
  background: var(--accent);
  color: var(--accent-contrast);
}
.ui-modal-action--danger {
  background: var(--danger);
  color: var(--accent-contrast);
}
.ui-modal-action--plain {
  background: var(--surface-2);
  color: var(--text);
}

/* ---------- bottom sheet (§4.7, z var(--z-sheet) from JS) ---------- */
.ui-sheet-wrap {
  position: fixed;
  inset: 0;
}
.ui-sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--surface);
  border-top: 1px solid var(--outline);
  border-top-left-radius: var(--radius);
  border-top-right-radius: var(--radius);
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  transition: transform 0.22s ease;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.ui-sheet-wrap--in .ui-sheet {
  transform: translateY(0);
}
.ui-sheet--drag {
  transition: none;
}
.ui-sheet-grab {
  flex: none;
  padding: var(--sp-2) var(--sp-4);
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.ui-sheet-pill {
  width: var(--sp-6);
  height: var(--sp-1);
  border-radius: var(--radius-sm);
  background: var(--outline);
  margin: 0 auto;
}
.ui-sheet-title {
  text-align: center;
  font-size: 17px;
  font-weight: 700;
  color: var(--text);
  padding-top: var(--sp-3);
}
.ui-sheet-body {
  overflow-y: auto;
  padding: var(--sp-2) var(--sp-4) var(--sp-4);
}

/* ---------- rest timer (§6.2, z var(--z-timer) from JS) ---------- */
.ui-timer {
  position: fixed;
  inset: 0;
  opacity: 0;
  transition: opacity 0.3s ease;
}
/* §6.2: the set UI stays usable behind the timer ("completing a set mid-rest
   cancels and restarts") — the wrap and scrim pass touches through; only the
   panel and controls are interactive. The #overlay-root selector outranks the
   base.css `#overlay-root > *` pointer-events reset. */
#overlay-root > .ui-timer {
  pointer-events: none;
}
.ui-timer-panel,
.ui-timer-controls {
  pointer-events: auto;
}
.ui-timer--in {
  opacity: 1;
}
.ui-timer--dim {
  /* §6.2: auto-dim to 35% after 5s without touch; any touch restores. */
  opacity: 0.35;
}
.ui-timer-panel {
  position: absolute;
  left: 0;
  right: 0;
  top: 22%;
  text-align: center;
}
.ui-timer-label {
  font-size: 15px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: var(--sp-2);
}
.ui-timer-time {
  font-size: 76px;
  font-weight: 800;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.ui-timer-controls {
  /* Bottom of the screen = thumb zone (R2.1) — but raised clear of the 64px
     COMPLETE SET anchored beneath (its top edge sits at 76px + safe-area from
     the screen bottom): §6.2 pins that completing a set mid-rest cancels and
     restarts the timer, so the primary button must never be shadowed by the
     timer's own hit targets. */
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--tap-primary) + var(--sp-4) + var(--sp-6) + env(safe-area-inset-bottom, 0px));
  display: flex;
  justify-content: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-4);
}
.ui-timer-btn {
  min-height: var(--tap-min);
  min-width: calc(var(--tap-min) + var(--sp-6));
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--outline);
  font-size: 18px;
  font-weight: 700;
  padding: 0 var(--sp-4);
}
.ui-timer-btn--skip {
  background: transparent;
  color: var(--text-dim);
}

/* ---------- swipe rows (§6.4) ---------- */
.ui-swipe {
  position: relative;
  overflow: hidden;
  touch-action: pan-y; /* vertical scroll stays native; horizontal is ours */
  /* Gesture surface: a lingering press or slow drag must never pop iOS text
     selection / the callout — WebKit would pointercancel and abort the swipe
     with the selection loupe left over the list. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.ui-swipe-content {
  position: relative;
  background: inherit;
  transition: transform 0.18s ease; /* spring-back */
}
.ui-swipe-content--drag {
  transition: none;
}
.ui-swipe-under {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: stretch;
  visibility: hidden;
}
.ui-swipe--r .ui-swipe-under--right {
  visibility: visible;
}
.ui-swipe--l .ui-swipe-under--left {
  visibility: visible;
}
.ui-swipe-under--right {
  justify-content: flex-start;
  background: var(--success);
}
.ui-swipe-under--left {
  justify-content: flex-end;
  background: var(--surface-2);
}
.ui-swipe-ic {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-primary);
  font-size: 22px;
}
.ui-swipe-ic--check {
  color: var(--accent-contrast);
}
.ui-swipe-ic--edit {
  background: var(--warn);
  color: var(--accent-contrast);
}
.ui-swipe-ic--delete {
  background: var(--danger);
  color: var(--accent-contrast);
}

/* ---------- toasts + persistent banner (§4.7, z var(--z-toast) from JS) ---------- */
/* §7: top-anchored, below the safe-area inset — never at the bottom, where it
   would cover thumb-zone primary actions. Newest toast is prepended (top of
   the stack) and slides in from the top edge. When the persistent banner is
   shown, toast.mjs measures its rendered height into --ui-banner-h and adds
   .ui-toast-stack--below-banner so the stack reflows below it (the banner's
   own padding already absorbs the safe-area inset). */
.ui-toast-stack {
  position: fixed;
  left: var(--sp-4);
  right: var(--sp-4);
  top: calc(env(safe-area-inset-top, 0px) + var(--sp-3));
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  align-items: stretch;
  pointer-events: none;
  transition: top 0.25s ease;
}
.ui-toast-stack--below-banner {
  top: calc(var(--ui-banner-h, var(--sp-6)) + var(--sp-2));
}
.ui-toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--tap-min);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--outline);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-4);
  opacity: 0;
  transform: translateY(calc(-1 * var(--sp-4)));
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.ui-toast--in {
  opacity: 1;
  transform: none;
}
.ui-toast--info {
  border-left-color: var(--accent);
}
.ui-toast--success {
  border-left-color: var(--success);
}
.ui-toast--warn {
  border-left-color: var(--warn);
}
.ui-toast--error {
  border-left-color: var(--danger);
}
.ui-toast-msg {
  flex: 1;
  font-size: 15px;
}
.ui-toast-action {
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  padding: 0 var(--sp-3);
  background: transparent;
  color: var(--accent);
  font-weight: 700;
  font-size: 15px;
  border-radius: var(--radius-sm);
}
.ui-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  padding: calc(var(--sp-2) + env(safe-area-inset-top, 0px)) var(--sp-4) var(--sp-2);
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  background: var(--warn);
  color: var(--bg);
  transform: translateY(-100%);
  transition: transform 0.25s ease;
}
.ui-banner--in {
  transform: translateY(0);
}

/* ---------- charts (§4.7, R5.5 — token colors only) ---------- */
.ui-chart {
  display: block;
  max-width: 100%;
  height: auto;
  color: var(--accent); /* line/bar marks draw with currentColor */
}
.ui-chart-grid {
  stroke: var(--outline);
  stroke-width: 1;
}
.ui-chart-line {
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}
.ui-chart-dot {
  fill: currentColor;
}
.ui-chart-bar {
  fill: currentColor;
}
.ui-chart-ticklabel {
  fill: var(--text-dim);
  font-size: 10px;
}
.ui-chart-axislabel {
  fill: var(--text-dim);
  font-size: 11px;
  font-weight: 600;
}
.ui-chart-empty {
  fill: var(--text-dim);
  font-size: 13px;
}

/* ---------- progress bar (§4.7, R5.2) ---------- */
.ui-progress {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.ui-progress-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3);
}
.ui-progress-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.ui-progress-nums {
  font-size: 13px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.ui-progress-track {
  height: var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
}
.ui-progress-fill {
  height: 100%;
  border-radius: var(--radius-sm);
  background: var(--accent);
  transition: width 0.3s ease;
}
.ui-progress--done .ui-progress-fill {
  background: var(--success);
}
