* { box-sizing: border-box; }

:root {
  --bg-page: #eeece7;
  --bg-app: #faf9f7;
  --bg-card: #fff;
  --border: #e6e3dd;
  --border-light: #f0eee9;
  --border-mid: #dcd8d0;
  --border-faint: #ebe8e2;
  --text: #1a1917;
  --text-2: #57544f;
  --text-muted: #85817a;
  --text-faint: #b3ada5;
  --text-dim: #8f8a83;
  --accent: oklch(0.52 0.09 205);
  --accent-hover: oklch(0.45 0.09 205);
  --accent-light: oklch(0.86 0.05 205);
  --accent-row: oklch(0.978 0.012 205);
  --accent-dot: oklch(0.75 0.08 205);
  --amber: oklch(0.55 0.08 60);
  --danger: oklch(0.52 0.14 25);
  --radius-lg: 14px;
  --radius-md: 12px;
  --radius-sm: 9px;
  --radius-xs: 8px;
  --shadow-shell: 0 1px 2px rgba(26,25,23,.04), 0 18px 48px rgba(26,25,23,.12);
  --shadow-card: 0 1px 2px rgba(26,25,23,.04);
}

body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text);
  font-family: 'Public Sans', 'PingFang TC', 'Noto Sans TC', sans-serif;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* ---------- app shell ---------- */

body { height: 100dvh; overflow: hidden; }

#app {
  max-width: 480px;
  margin: 0 auto;
  height: 100dvh;
  background: var(--bg-app);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
@media (min-width: 480px) {
  body { height: auto; overflow: visible; padding: 28px 0; }
  #app {
    height: calc(100dvh - 56px);
    border-radius: 20px;
    box-shadow: var(--shadow-shell);
  }
}

#views { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.view { display: flex; flex-direction: column; gap: 22px; padding: 20px 20px 12px; }
.view.hidden { display: none; }

/* ---------- typography helpers ---------- */

.view-title { font: 300 25px/1.2 'Public Sans', 'PingFang TC', sans-serif; letter-spacing: -.02em; margin: 0; }
.eyebrow {
  font: 600 11px/1 'Public Sans', 'PingFang TC', sans-serif;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.eyebrow.accent { color: var(--accent); }
.eyebrow.strong { color: var(--text); }
.muted { color: var(--text-muted); font-size: 14px; }
.error { color: var(--danger); font-size: 14px; }
/* 分頁載入失敗時插在最上面的橫幅。橫排是因為它幾乎總是「離線,無法連上伺服器」
   加一顆「重試」—— 短到不值得佔掉兩行。 */
.view-error {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-card);
}
.hidden { display: none !important; }

/* ---------- buttons ---------- */

button, .button {
  font: inherit;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  color: var(--text-2);
  padding: 0 14px;
  height: 40px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-decoration: none;
  white-space: nowrap;
}
button:hover, .button:hover { background: #f0eee9; }
button:disabled { opacity: .55; cursor: default; }

button.primary, .button.primary {
  border: none;
  background: var(--accent);
  color: #fff;
  font-weight: 500;
}
button.primary:hover, .button.primary:hover { background: var(--accent-hover); }

button.dark {
  border: none;
  background: var(--text);
  color: var(--bg-app);
}
button.dark:hover { background: #33312e; }

button.danger { color: var(--danger); }
button.danger:hover { background: #fbeeec; }

button.link {
  border: none;
  background: none;
  height: auto;
  padding: 0;
  color: var(--accent);
  font-weight: 500;
  font-size: 13px;
}
button.link:hover { background: none; color: var(--accent-hover); }

button.icon-btn { width: 36px; height: 36px; padding: 0; border-radius: var(--radius-sm); font-size: 15px; }

/* ---------- cards ---------- */

.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 18px;
}
.card h3 { margin: 0; }
.card-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.stack { display: flex; flex-direction: column; }
.gap-2 { gap: 2px; } .gap-3 { gap: 3px; } .gap-4 { gap: 4px; } .gap-5 { gap: 5px; }
.gap-6 { gap: 6px; } .gap-8 { gap: 8px; } .gap-10 { gap: 10px; } .gap-12 { gap: 12px; }
.gap-14 { gap: 14px; } .gap-16 { gap: 16px; } .gap-18 { gap: 18px; } .gap-20 { gap: 20px; }
.row { display: flex; flex-direction: row; }
.between { justify-content: space-between; }
.center { align-items: center; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1; }

/* ---------- tab bar ---------- */

#tabbar {
  flex: none;
  height: 76px;
  border-top: 1px solid var(--border);
  background: #fffefc;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: start;
  padding-top: 12px;
  padding-bottom: env(safe-area-inset-bottom);
}
#tabbar button {
  border: none; background: none; height: auto; padding: 0;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
}
#tabbar button:hover { background: none; }
#tabbar .dot { width: 5px; height: 5px; border-radius: 3px; background: transparent; }
#tabbar .label { font: 500 11px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
#tabbar button.active .dot { background: var(--accent); }
#tabbar button.active .label { color: var(--accent); }

/* ---------- today ---------- */

/* The one card the 今日 tab exists for, so it sits a step above the generic
   .card: rounder, and roomier inside. */
.plan-card { border-radius: var(--radius-lg); padding: 22px; }

.today-head { display: flex; align-items: flex-end; justify-content: space-between; }
.today-date-label { font: 600 11px/1 'Public Sans', sans-serif; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); }
.today-date { font: 300 28px/1.15 'Public Sans', 'PingFang TC', sans-serif; letter-spacing: -.02em; }
.streak-num { font: 500 20px/1 'Public Sans', sans-serif; color: var(--accent); text-align: right; }
.streak-label { font: 400 11px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }

.week-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.week-strip .wd { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.week-strip .wd-label { font: 400 11px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
.week-strip .wd-label.today { font-weight: 600; color: var(--text); }
.week-strip .wd-bar { width: 100%; height: 3px; border-radius: 2px; background: var(--border); }
.week-strip .wd-bar.done { background: var(--accent); }
.week-strip .wd-bar.planned { background: var(--accent-light); }

.plan-stats { display: flex; gap: 24px; }
.plan-stat { display: flex; flex-direction: column; gap: 3px; }
.plan-stat .num { font: 400 20px/1 'Public Sans', sans-serif; }
.plan-stat .num small { font-size: 13px; color: var(--text-muted); }
.plan-stat .lbl { font: 400 11px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }

.exercise-line { display: flex; justify-content: space-between; align-items: center; }
.exercise-line .name { font: 400 14px/1.4 'Public Sans', sans-serif; }
.exercise-line .meta { font: 400 13px/1.4 'Public Sans', sans-serif; color: var(--text-muted); }
.plan-exlist { display: flex; flex-direction: column; gap: 8px; padding-top: 16px; border-top: 1px solid var(--border-light); }

.compare-line { display: flex; justify-content: space-between; align-items: center; }
.compare-line .name { font: 400 14px/1.4 'Public Sans', sans-serif; color: var(--text-2); }
.compare-line .val { font: 400 13px/1.4 'Public Sans', sans-serif; }
.compare-up { color: var(--accent); }
.compare-flat { color: var(--text-muted); }

.empty-state { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; padding: 8px 0; }

/* ---------- timeline ---------- */

.timeline-header {
  flex: none; margin: -20px -20px 0; padding: 20px 20px 16px;
  display: flex; align-items: center; justify-content: space-between;
  background: #fffefc; border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;
}
/* .segmented 是 inline-flex,但身為 .view(flex column,預設 stretch)的 flex
   item 會被 blockify、寬度被拉滿,所以要收縮回自己的內容寬度。margin 歸零而
   不是照抄設定頁的 14px:.view 本身已經有 gap: 22px 負責跟前後元素的間距,
   兩者疊加會讓上下留白比頁面其他地方都大一截,看起來不對稱。 */
#view-timeline .segmented { align-self: flex-start; margin: 0; }
.week-head { display: flex; align-items: baseline; justify-content: space-between; padding-top: 6px; }
.week-days { display: flex; flex-direction: column; }
.day-row {
  display: flex; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--border-faint);
}
.day-row.past { opacity: .72; }
.day-row .day-num { width: 34px; flex: none; display: flex; flex-direction: column; align-items: center; gap: 2px; }
.day-row .day-num span:first-child { font: 400 17px/1 'Public Sans', sans-serif; }
.day-row .day-num.muted span:first-child { color: var(--text-muted); }
.day-row .day-num .wd { font: 400 10px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
.day-row .day-info { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.day-row .day-info .name { font: 400 15px/1.3 'Public Sans', sans-serif; }
.day-row .day-info .name.muted { color: var(--text-2); }
.day-row .day-info .sub {
  font: 400 12px/1.4 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.day-row .day-value { flex: none; align-self: center; font: 400 12px/1 'Public Sans', 'PingFang TC', sans-serif; }
.day-value.tonnage { color: var(--accent); }
.day-value.skipped { color: var(--amber); }
.day-value.planned { color: var(--text-muted); }

.today-inline-card {
  margin: 10px 0; background: var(--bg-card); border: 1px solid var(--border-mid); border-radius: var(--radius-lg);
  padding: 20px; display: flex; flex-direction: column; gap: 16px; box-shadow: var(--shadow-card);
}

/* ---------- shared view header ---------- */

.view-head { display: flex; align-items: center; justify-content: space-between; }

/* ---------- calendar ---------- */

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-weekday { text-align: center; font: 400 11px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); padding-bottom: 8px; }
.cal-day {
  height: 46px; border-radius: var(--radius-sm); cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
}
.cal-day .cal-num { font: 400 14px/1 'Public Sans', sans-serif; }
.cal-day .cal-dot { width: 5px; height: 5px; border-radius: 3px; background: transparent; }
.cal-day .cal-dot.done { background: var(--accent); }
.cal-day .cal-dot.planned { border: 1px solid var(--accent-dot); }
.cal-day.today .cal-num { color: var(--accent); font-weight: 600; }
.cal-day.selected { background: var(--text); }
.cal-day.selected .cal-num { color: var(--bg-app); font-weight: 500; }
.cal-day.selected .cal-dot.done { background: var(--accent-light); }
.cal-day.selected .cal-dot.planned { border-color: var(--accent-light); }

.day-summary-card { display: flex; flex-direction: column; gap: 12px; }
.day-summary-row { display: flex; align-items: center; justify-content: space-between; }

/* ---------- templates (課表) ---------- */

.tpl-card { display: flex; flex-direction: column; gap: 14px; }
.tpl-card .name { font: 500 18px/1.2 'Public Sans', sans-serif; }
.tpl-card .summary { font: 400 12px/1.5 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
.tpl-actions { display: flex; gap: 8px; align-items: center; }
.tpl-actions input[type="date"] {
  font: inherit; font-size: 12px; padding: 0 8px; height: 40px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--bg-app); color: var(--text-2); width: 128px;
}
.tpl-actions button.apply { flex: 1; background: var(--bg-app); }

.trash-card { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* ---------- settings ---------- */

.settings-card { display: flex; flex-direction: column; gap: 14px; }
.kv-list { padding: 4px 18px; }
.kv-row { display: flex; align-items: center; justify-content: space-between; height: 52px; border-bottom: 1px solid var(--border-light); }
.kv-row:last-child { border-bottom: none; }
.kv-row .k { font: 400 15px/1 'Public Sans', 'PingFang TC', sans-serif; }
.kv-row .v { font: 400 14px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }

/* Preference rows expand a control in place, so the separator belongs to the
   whole item — sitting on .kv-row it would cut between a row and its own
   control and read as if the control belonged to the row below. */
.prefs-card .kv-row { border-bottom: none; cursor: pointer; }
.pref-item { border-bottom: 1px solid var(--border-light); }
.pref-item:last-child { border-bottom: none; }
.segmented { display: inline-flex; margin: 0 0 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.segmented button {
  height: 34px; padding: 0 18px; border: none; border-radius: 0; background: var(--bg-card);
  font-size: 14px; color: var(--text-2);
}
.segmented button + button { border-left: 1px solid var(--border); }
.segmented button.active { background: var(--accent); color: #fff; font-weight: 500; }
.segmented button.active:hover { background: var(--accent-hover); }
.pref-field { display: flex; align-items: center; gap: 8px; margin: 0 0 14px; }
.pref-field .chip-input.rest { width: 72px; }
.pref-unit { font: 400 14px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-2); }
.pref-hint { font: 400 12px/1 'Public Sans', sans-serif; color: var(--text-faint); }
.pref-error { padding: 0 0 12px; }

/* ---------- set checklist (today card + edit sheet share the idiom) ---------- */

.set-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.set-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px 12px;
  padding: 6px; border-radius: var(--radius-xs); flex-wrap: wrap;
}
.set-item:hover { background: var(--border-light); }
.set-toggle { display: flex; align-items: center; gap: 10px; cursor: pointer; }
.set-toggle input[type="checkbox"] { width: 19px; height: 19px; flex-shrink: 0; accent-color: var(--accent); }
.set-name { font-size: 14px; }
.set-item.done .set-name { text-decoration: line-through; color: var(--text-dim); }
.set-fields { display: flex; align-items: center; gap: 4px; font-size: 13px; color: var(--text-muted); }
.set-fields input {
  width: 60px; font: inherit; font-size: 14px; color: var(--text);
  padding: 4px 6px; border: 1px solid var(--border); border-radius: var(--radius-xs); text-align: center;
}
.instance-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.instance-actions .error { font-size: 13px; }

/* ---------- overlays ---------- */

.overlay {
  position: fixed; inset: 0; display: flex; flex-direction: column; z-index: 10;
  max-width: 480px; margin: 0 auto;
}
.overlay.hidden { display: none; }
.overlay-backdrop { flex: 1; border: none; background: rgba(26,25,23,.28); cursor: pointer; padding: 0; }

/* ---------- workout session ---------- */

#workout-overlay { background: var(--bg-app); }
.session-head { flex: none; padding: 18px 20px 16px; display: flex; flex-direction: column; gap: 16px; background: #fffefc; border-bottom: 1px solid var(--border); }
.session-title { font: 500 20px/1.2 'Public Sans', sans-serif; }
.session-meta { font: 400 12px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
.session-progress { height: 3px; border-radius: 2px; background: var(--border); overflow: hidden; }
.session-progress > div { height: 100%; background: var(--accent); }

.session-body { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 22px; }
.ex-group { display: flex; flex-direction: column; gap: 10px; }
.ex-group-head { display: flex; align-items: center; gap: 8px; }
.ex-group-head .name-input {
  flex: 1; min-width: 0; font: 500 15px/1.3 'Public Sans', sans-serif; color: var(--text-muted);
  border: none; background: none; padding: 0; height: auto; overflow: hidden; text-overflow: ellipsis;
}
.ex-group.active .ex-group-head .name-input { color: var(--text); font-size: 16px; }
.ex-group-head .meta { flex: none; font: 400 12px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); white-space: nowrap; }
/* Sits with the exercise name, not the set rows: one unit per movement. Kept
   quiet so it reads as a label on the heading rather than a fourth control
   competing with the set inputs below. */
.ex-group-head .unit-select {
  flex: none; height: auto; padding: 3px 4px; border: 1px solid var(--border); border-radius: var(--radius-xs);
  background: var(--bg-app); font: 400 12px/1 'Public Sans', sans-serif; color: var(--text-2);
}

.ex-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 6px 14px; display: flex; flex-direction: column; }
.ex-card.active-card { border-color: var(--accent-light); box-shadow: 0 0 0 1px var(--accent-light); }
/* Every row bleeds 8px past the card's text column so a completed row's tint
   reads as a highlighted band rather than a chip floating inside the card. The
   padding cancels the margin, so the controls themselves don't shift — and the
   separator, drawn back at the text column's width, stays put in every state. */
.ex-row {
  position: relative;
  display: flex; align-items: center; gap: 8px; min-height: 56px;
  margin: 0 -8px; padding: 0 8px; border-radius: var(--radius-sm);
}
.ex-row + .ex-row::before {
  content: ''; position: absolute; left: 8px; right: 8px; top: 0;
  height: 1px; background: var(--border-light);
}
.ex-row .idx { flex: none; width: 14px; font: 400 13px/1 'Public Sans', sans-serif; color: var(--text-muted); }
.ex-row .icon-btn { flex: none; }
.ex-row.is-active .idx { font-weight: 600; color: var(--text); }

/* A finished set is settled, not disabled: it keeps full contrast and gains a
   tint, while its inputs shed their chrome. Fading the row out — what this
   used to do — made the numbers you just earned the hardest ones to read. */
.ex-row.is-done { background: var(--accent-row); }
.ex-row.is-done .idx { font-weight: 500; color: var(--accent); }
.ex-row.is-done .chip-input { border-color: transparent; background: transparent; font-weight: 500; }

/* Sets the workout hasn't reached yet. Scoped to session mode: with no active
   set there is no "yet", so "not done" would mean every field, and dimming
   them all would make an editable form look disabled. */
.mode-session .ex-row:not(.is-done):not(.is-active) .chip-input { color: var(--text-dim); }

/* Three states, three shapes: a filled tick for a set that's done, a wide
   labelled pill for the one in progress — the only thing the workout is asking
   for right now — and an empty dashed circle for the rest. All keep a 44px
   tap target regardless of how small the mark inside them is. */
.set-check {
  flex: none; height: 44px; padding: 0; border: none; border-radius: 22px; background: none;
  display: flex; align-items: center; justify-content: center; gap: 6px;
}
.set-check:hover { background: none; }
.set-check.done, .set-check.todo { width: 44px; }
.set-check .mark {
  width: 26px; height: 26px; border-radius: 13px;
  display: flex; align-items: center; justify-content: center;
  font: 600 14px/1 'Public Sans', sans-serif;
}
.set-check.done .mark { background: var(--accent); color: #fff; }
.set-check.todo .mark { border: 1.5px dashed var(--border-mid); background: var(--bg-app); }
.set-check.active {
  padding: 0 14px; background: var(--accent); color: #fff;
  font: 500 14px/1 'Public Sans', 'PingFang TC', sans-serif;
}
.set-check.active:hover { background: var(--accent-hover); }
.set-check.active .tick { font: 600 13px/1 'Public Sans', sans-serif; }

/* `font: inherit` carries no colour, and an input left to the UA default lands
   on pure black — a shade harder than every other number on the screen. */
.chip-input {
  flex: none; padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--bg-app);
  font: inherit; font-size: 14px; text-align: center; color: var(--text);
}
.chip-input.weight { width: 56px; padding-left: 4px; padding-right: 4px; }
.chip-input.reps { width: 44px; padding-left: 4px; padding-right: 4px; }
.x-sep { flex: none; font: 400 12px/1 'Public Sans', sans-serif; color: var(--text-faint); }

.ex-collapsed-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 14px; display: flex; align-items: center; justify-content: space-between; }

.rest-row { display: flex; align-items: center; gap: 12px; }
.rest-row .rest-label { font: 400 12px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
.rest-row .rest-time { font: 400 17px/1 'Public Sans', sans-serif; color: var(--accent); }
.rest-row .rest-bar { flex: 1; height: 3px; border-radius: 2px; background: var(--border); overflow: hidden; }
.rest-row .rest-bar > div { height: 100%; background: var(--accent-light); }
.rest-row button { border: none; background: none; height: auto; padding: 0; font-size: 13px; color: var(--text-muted); }

.session-footer { flex: none; border-top: 1px solid var(--border); background: #fffefc; padding: 14px 20px calc(20px + env(safe-area-inset-bottom)); display: flex; flex-direction: column; gap: 12px; }
.session-footer button.finish { height: 48px; width: 100%; }

.session-title-input {
  font: 500 20px/1.2 'Public Sans', sans-serif; border: none; background: none; padding: 0; height: auto; color: var(--text); width: 100%;
}
.session-sub {
  font: 400 12px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.session-sub input[type="date"], .session-sub select {
  font: inherit; font-size: 12px; color: var(--text-muted); background: none; border: none; padding: 2px 0;
}
.spacer { flex: 1; min-width: 4px; }
.ex-add-set { align-self: flex-start; margin-left: 26px; padding: 8px 0; }
.ex-add-exercise { flex-shrink: 0; height: 44px; border: 1px dashed var(--border-mid); background: none; width: 100%; font: 500 14px/1 'Public Sans', 'PingFang TC', sans-serif; }
/* 另存為模板 / 刪除 sit under the finish button, so they stay a size down from
   it — secondary to the one action that ends the workout. */
.session-footer .row button { height: 36px; padding: 0 12px; font-size: 13px; }

/* Reordering. The handle is the only surface with touch-action:none, so the
   drag never competes with scrolling anywhere else in the overlay. */
.drag-handle {
  position: relative;
  flex: none; width: 20px; height: 36px; padding: 0;
  border: none; background: none; color: var(--text-faint);
  font-size: 14px; cursor: grab; touch-action: none;
}
.drag-handle:hover { background: none; color: var(--text-muted); }
.drag-handle:active { cursor: grabbing; }
/* Widens the *tap* target to 44px without widening the glyph: the header row
   is already tight, and growing the visible control would eat into the
   exercise name input beside it. The name input has no left padding, so
   rightward growth of the hit area must stop well short of it — .session-body
   sets overflow-y, which per spec forces its overflow-x to 'auto' too and
   clips anything that reaches past its own padding edge, so the left side
   only has ~20px of unclipped room before the header's own left edge. Split
   the extra 24px as 20 left (the most that room allows) and 4 right (well
   inside the 8px gap before .name-input's unpadded left edge) to land on
   44px total without clipping on one side or overlapping on the other.
   Ruled exception at <=380px: the media query below narrows .session-body's
   padding to 14px, shrinking the unclipped room on the left, so the hit area
   is 38x44 there instead of 44x44. Measured and accepted — see "Global
   Constraints" in docs/superpowers/plans/2026-08-06-exercise-reordering.md. */
.drag-handle::before {
  content: '';
  position: absolute;
  inset: -4px -4px -4px -20px;
}

/* Single-line stand-ins, used only while a drag is in progress. An expanded
   exercise group is ~300px tall — dragging one on a phone puts the drop target
   off-screen and forces edge auto-scroll. Uniform rows keep 3-6 exercises on
   one screen and make the drop target a division rather than a hit test. */
.drag-row {
  position: relative;
  display: flex; flex: none; align-items: center; gap: 10px;
  height: 44px; padding: 0 14px;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-md); will-change: transform;
}
.drag-row + .drag-row { margin-top: 8px; }
.drag-row .grip { flex: none; width: 20px; color: var(--text-faint); }
.drag-row .name {
  flex: 1; min-width: 0; font: 500 15px/1.3 'Public Sans', sans-serif;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.drag-row .meta { flex: none; font: 400 12px/1 'Public Sans', 'PingFang TC', sans-serif; color: var(--text-muted); }
.drag-row.lifted { z-index: 2; border-color: var(--accent-light); box-shadow: 0 8px 24px rgba(26,25,23,.18); }
/* Only the rows getting out of the way animate; the lifted one must track the
   finger exactly, with no easing lag. */
.drag-row.shifting { transition: transform .16s ease; }

/* A set row's natural content is ~253px wide in session mode (idx + weight +
   × + reps + checkmark + remove) now that the unit picker has moved up to the
   exercise heading. That still overruns the card's inner width on a 320px
   viewport, so keep tightening the row there rather than letting the remove
   button be the one thing that shrinks. */
@media (max-width: 380px) {
  .session-body { padding: 20px 14px; }
  .ex-card { padding: 6px 10px; }
  .ex-row { gap: 4px; }
  .chip-input.weight { width: 50px; }
  .chip-input.reps { width: 40px; }
}
