/* OHT — one stylesheet, no framework.
   Phone-first: everything stacks in one column, then widens into a grid at 720px / 1100px. */

:root {
  --bg: #0d1017;
  --panel: #151a23;
  --panel-2: #1b2029;
  --line: #262d3a;
  --ink: #e7ecf3;
  --ink-2: #9aa5b6;
  --ink-3: #6b7688;

  --accent: #5b9dff;
  --fat: #f2a65a;
  --muscle: #4fc48b;
  --bone: #8f9bb3;
  --carb: #7c8cf8;
  --protein: #4fc48b;
  --warn: #f2705a;

  /* Body regions. Colour tells exercises apart at a glance; a glyph carries the same
     distinction so it survives colour blindness and greyscale. */
  --region-chest: #e0645f;
  --region-back: #4a90d9;
  --region-arms: #a06fd8;
  --region-legs: #45b97c;
  --region-shoulders: #e39a3c;
  --region-core: #3fb3b3;
  --region-other: #8f9bb3;

  --radius: 14px;
  --gap: 14px;
  --pad: 18px;

  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f4f6fa;
    --panel: #ffffff;
    --panel-2: #f0f3f8;
    --line: #dfe4ed;
    --ink: #131722;
    --ink-2: #5b6577;
    --ink-3: #8a94a6;
    --accent: #2b6fd6;
    --bone: #7d879b;
  }
}

* { box-sizing: border-box; }

/* An author `display` rule outranks the UA stylesheet's `[hidden] { display: none }`, so
   .gate's `display: grid` would keep it on screen even when hidden. Restore the intent. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  -webkit-text-size-adjust: 100%;
}

body { padding-bottom: env(safe-area-inset-bottom); }

code { font-family: var(--mono); font-size: .9em; }

/* ---------------------------------------------------------------- sign-in */

.gate {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
}

.gate__card {
  width: min(360px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  display: grid;
  gap: 14px;
}

.gate__title { margin: 0; font-size: 30px; letter-spacing: .14em; }
.gate__sub { margin: -8px 0 6px; color: var(--ink-2); font-size: 13px; }
.gate__error { margin: 0; color: var(--warn); font-size: 13px; }

/* Backup and restore live on the gate (OHT-62). The moment you actually want a restore is the
   moment the app will not load, so the one screen that always renders is where they belong. */
.gate__mode {
  margin: 0;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
}
.gate__mode--restore {
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  border-color: color-mix(in srgb, var(--warn) 40%, var(--line));
}

.gate__panel { width: min(460px, 100%); }
.gate__heading { margin: 0; font-size: 19px; }
.gate__actions { display: flex; gap: 10px; }
.gate__actions .btn { flex: 1 1 auto; }

.gate__results { margin: 0; padding-left: 18px; display: grid; gap: 6px; font-size: 14px; }
.gate__results .is-bad { color: var(--warn); }

/* Capped so that twenty snapshots still leave the buttons below them on screen. */
.gate__list {
  display: grid;
  gap: 8px;
  max-height: min(46dvh, 380px);
  overflow-y: auto;
  margin: 0 -4px;
  padding: 2px 4px;
}

.bk {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "db when" "db meta";
  gap: 1px 10px;
  align-items: center;
  width: 100%;
  padding: 10px 12px;
  text-align: left;
  font: inherit;
  color: var(--ink);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
}
.bk:hover { border-color: var(--accent); }

/* Which database, said in colour and in words - the two are never the same database, and
   picking the wrong one is the mistake with no undo worth having. */
.bk__db {
  grid-area: db;
  align-self: center;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.bk__db--training { background: color-mix(in srgb, var(--accent) 22%, transparent); color: var(--accent); }
.bk__db--security { background: color-mix(in srgb, var(--muscle) 22%, transparent); color: var(--muscle); }
.bk__when { grid-area: when; font-size: 14px; }
.bk__meta { grid-area: meta; color: var(--ink-2); font-size: 12px; }

/* ---------------------------------------------------------- disclaimer (OHT-41) */

/* Above everything, including the gate, and opaque rather than translucent: a legal notice you
   read through the dashboard is one you were shown but not really told. */
.disclaimer {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 20px;
  overflow-y: auto;
  background: var(--bg);
}

.disclaimer__card {
  width: min(520px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  display: grid;
  gap: 14px;
}

.disclaimer__title { margin: 0; font-size: 22px; }
.disclaimer__lead { margin: 0; color: var(--ink); font-size: 15px; }

.disclaimer__points { margin: 0; display: grid; gap: 12px; }
.disclaimer__points dt {
  font-weight: 650;
  font-size: 14px;
  margin-bottom: 2px;
}
.disclaimer__points dd {
  margin: 0;
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.5;
}

.disclaimer__meta { margin: 0; color: var(--ink-3); font-size: 12px; }
.disclaimer__error { margin: 0; color: var(--warn); font-size: 13px; }
.disclaimer__actions { display: flex; gap: 10px; }
.disclaimer__actions .btn { flex: 1 1 auto; }

.field { display: grid; gap: 6px; }
/* A locked field. The point is that it reads as inert at a glance without the value getting
   harder to read - the panel exists to show those numbers. So: a flatter surface, a dashed
   edge, and a small tag on the label. The emoji padlock that was here first was the only
   glyph of its kind in the app and looked pasted on. */
.field--locked input, .field--locked select {
  background: var(--panel-2);
  border-style: dashed;
  cursor: not-allowed;
}
.field--locked input:disabled, .field--locked select:disabled { opacity: 1; color: var(--ink-2); }
.field--locked .field__label { color: var(--ink-3); }
.field__lock {
  margin-left: 7px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .09em;
  padding: 2px 6px;
  border-radius: 999px;
  color: var(--ink-3);
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.plan-lock {
  margin: 12px 0 0; padding: 9px 11px 9px 13px; border-radius: 8px; font-size: 12px;
  color: var(--ink-2); background: var(--panel-2); border: 1px solid var(--line);
  /* A quiet accent edge does the work the padlock emoji was doing, in the app's own idiom. */
  border-left: 3px solid color-mix(in srgb, var(--ink-3) 45%, var(--line));
}
/* The same box, but carrying a way out rather than only an explanation. */
.plan-lock--action {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap;
}
.field__label { font-size: 12px; color: var(--ink-2); text-transform: uppercase; letter-spacing: .08em; }

/* Every text-ish input, listed by type so a date or a checkbox is not caught by it. A type that
   is missing here gets the browser's own control instead, sitting next to styled ones at a
   different height and a different colour - which is what happened to the email box on the
   sign-in card the day it was added. Adding an input type means adding it here. */
input[type=password], input[type=text], input[type=number], input[type=email],
input[type=tel], input[type=url], input[type=search] {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--ink);
  font: inherit;
  padding: 11px 12px;
  width: 100%;
}
input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.btn {
  font: inherit;
  font-weight: 600;
  border-radius: 9px;
  border: 1px solid transparent;
  padding: 11px 14px;
  cursor: pointer;
  white-space: nowrap;
}
.btn--primary { background: var(--accent); color: #fff; }
/* Destructive, and clickable. The button is only ever red when pressing it will shorten a
   block you are already running, so the colour is the warning, not decoration. */
.btn--danger { background: var(--warn); color: #fff; }
.btn--ghost {
  background: transparent; color: var(--ink-2); border-color: var(--line); padding: 7px 12px;
  font-size: 13px;
}
.btn:hover { filter: brightness(1.08); }

/* ---------------------------------------------------------------- chrome */

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  padding-top: max(12px, env(safe-area-inset-top));
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.topbar__brand { display: flex; align-items: baseline; gap: 12px; min-width: 0; }
.topbar__logo { font-weight: 700; letter-spacing: .16em; font-size: 15px; }
.topbar__date { color: var(--ink-2); font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar__actions { display: flex; align-items: center; gap: 10px; flex: none; }

/* On a phone the bar holds a logo, a date, a phase chip and the primary action. The chip is
   the one that can go - the mesocycle panel says the same thing a screen below. */
@media (max-width: 520px) {
  .topbar__logo { letter-spacing: .1em; }
  #topbar-phase { display: none; }
  /* Editing adds two more buttons; the date is the least useful thing in that moment. */
  body.is-layout-editing .topbar__date { display: none; }
}

.chip {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
  white-space: nowrap;
}
.chip--accent { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
/* The security alert. A button, so it needs the reset a chip does not normally carry. */
.chip--warn {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 45%, var(--line));
  background: color-mix(in srgb, var(--warn) 10%, var(--panel-2));
  font: inherit;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: none;
  cursor: pointer;
}
.chip--warn:hover { background: color-mix(in srgb, var(--warn) 18%, var(--panel-2)); }
.chip--warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, var(--line)); }
.chip--muscle { color: var(--muscle); border-color: color-mix(in srgb, var(--muscle) 40%, var(--line)); }

/* --- OHT-40: the settings menu ---------------------------------------------------------
   The detail chips were built into the topbar first and measured at 375px: the bar overflowed
   by 34px with the date already crushed to zero width and the phase chip already hidden. There
   was no concession left to make, so the layout editor became Settings and took them in. */
/* NOT position:relative. Anchoring the menu to the button hangs it 3px off the left edge at
   375px - the button is not at the edge of the bar, Weigh-in is to its right, so a 272px panel
   right-aligned to it starts at -3. The topbar is position:sticky and therefore already a
   containing block, so the menu anchors to the BAR and lines up with its padding instead. */
.settings { position: static; }

.settings__menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 16px;
  z-index: 20;
  width: min(272px, calc(100vw - 32px));
  padding: 8px;
  display: grid;
  gap: 2px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 14px 36px rgb(0 0 0 / .38);
}

.settings__item {
  appearance: none;
  cursor: pointer;
  font: inherit;
  text-align: left;
  display: grid;
  gap: 2px;
  padding: 9px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink);
}
.settings__item:hover { background: var(--panel-2); }
.settings__item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.settings__label { font-size: 13px; font-weight: 600; }
.settings__sub { font-size: 11px; color: var(--ink-2); line-height: 1.4; }

.settings__group {
  display: grid;
  gap: 8px;
  margin-top: 6px;
  padding: 12px 10px 4px;
  border-top: 1px solid var(--line);
}
.settings__heading {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* The chips are the ones from the 3-dot menu, not a second kind of chip: same component, same
   .is-on. A settings menu is not the place to introduce a new way of showing "this one". */
.settings__chips { display: flex; gap: 6px; flex-wrap: wrap; }

/* --- OHT-60: the diet panel's two actions -----------------------------------------------
   Every other panel ends with one full-width button. This one ends with two, so they share a
   row and only the primary is filled. */
.panel__actions { display: flex; gap: 8px; margin-top: auto; }
.panel__actions .btn { flex: 1; }

/* --- OHT-60: meal breakdown ------------------------------------------------------------- */
.meals__day { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.meals__daynum { font-size: 30px; font-weight: 700; letter-spacing: -.02em; }
.meals__dayunit { color: var(--ink-2); font-size: 13px; }
.meals__daymacros { margin-left: auto; color: var(--ink-2); font-size: 12px; }

.meals__slider { display: grid; gap: 10px; margin-bottom: 20px; }
.meals__count { display: flex; align-items: baseline; gap: 8px; }
.meals__countnum { font-size: 26px; font-weight: 700; color: var(--accent); min-width: 1.2em; }
.meals__countunit { color: var(--ink-2); font-size: 13px; }

/* A native range input, restyled rather than rebuilt: the thumb, the keyboard support and the
   drag behaviour are all free and all correct, which a div-and-pointer-events version is not. */
.meals__range {
  appearance: none; -webkit-appearance: none;
  width: 100%; height: 28px; background: transparent; cursor: pointer; margin: 0;
}
.meals__range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px; background: var(--panel-2); border: 1px solid var(--line);
}
.meals__range::-moz-range-track {
  height: 6px; border-radius: 999px; background: var(--panel-2); border: 1px solid var(--line);
}
.meals__range::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 24px; height: 24px; margin-top: -10px;
  border-radius: 50%; background: var(--accent); border: 2px solid var(--bg);
  box-shadow: 0 1px 6px rgb(0 0 0 / .35);
}
.meals__range::-moz-range-thumb {
  width: 24px; height: 24px;
  border-radius: 50%; background: var(--accent); border: 2px solid var(--bg);
  box-shadow: 0 1px 6px rgb(0 0 0 / .35);
}
.meals__range:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* The notches are also the tap targets. Browsers disagree about whether they draw datalist
   ticks at all, so these are what actually guarantees the stops are visible - and on a phone
   they are an easier hit than the thumb. */
.meals__notches { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
.meals__notch {
  appearance: none; cursor: pointer; font: inherit; font-size: 13px; font-weight: 600;
  padding: 7px 0; border-radius: 8px;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-2);
}
.meals__notch:hover { color: var(--ink); }
.meals__notch.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
.meals__notch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.meals__table { display: grid; gap: 2px; }
.meals__row {
  display: grid; grid-template-columns: 1fr repeat(4, minmax(44px, auto));
  gap: 8px; align-items: baseline;
  padding: 8px 2px; border-bottom: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
.meals__row > span:not(.meals__label) { text-align: right; }
.meals__row--head {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  border-bottom-color: var(--line);
}
.meals__label { color: var(--ink-2); font-size: 13px; }
.meals__kcal { font-weight: 700; }

/* --- OHT-60: the food log ---------------------------------------------------------------- */
.food__day { display: grid; gap: 8px; padding-bottom: 16px; border-bottom: 1px solid var(--line); }
.food__daymacros { color: var(--ink-2); font-size: 12px; }

.food__meal { display: grid; gap: 6px; padding: 16px 0; border-bottom: 1px solid var(--line); }
.food__meal--stray { opacity: .85; }
.food__mealhead { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.food__mealname { margin: 0; font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.food__none { margin: 0; color: var(--ink-3); font-size: 12px; }

.food__meta {
  display: flex; align-items: center; gap: 8px;
  color: var(--ink-2); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.food__meta.is-over { color: var(--warn); }
.food__bar { width: 60px; height: 5px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
.food__fill { display: block; height: 100%; background: var(--accent); }
.food__meta.is-over .food__fill { background: var(--warn); }

.food__entry { display: flex; align-items: center; gap: 10px; padding: 7px 0; }
.food__what { display: grid; gap: 1px; min-width: 0; flex: 1; }
.food__name { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.food__qty { color: var(--ink-3); font-size: 11px; }
.food__nums { display: grid; gap: 1px; text-align: right; font-variant-numeric: tabular-nums; }
.food__kcal { font-weight: 600; font-size: 13px; }
.food__macros { color: var(--ink-3); font-size: 11px; }
.food__del {
  appearance: none; cursor: pointer; font: inherit; font-size: 18px; line-height: 1;
  width: 30px; height: 30px; flex: none;
  border: 1px solid var(--line); border-radius: 8px;
  background: transparent; color: var(--ink-3);
}
.food__del:hover { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, var(--line)); }
.food__addto { justify-self: start; margin-top: 2px; }

.food__recent { display: grid; gap: 6px; padding: 16px 0 4px; }
.food__recentlabel {
  font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.food__chips { display: flex; gap: 6px; flex-wrap: wrap; }

.food__form { display: grid; gap: 10px; padding-top: 16px; }
.food__formhead { display: flex; align-items: center; gap: 10px; }
.food__mealpick {
  font: inherit; font-size: 13px; padding: 6px 10px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px;
}
.food__qtyrow { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.food__macrorow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.food__formnote { color: var(--ink-3); font-size: 11px; margin-top: -4px; }
.field--tight { gap: 3px; }
@media (max-width: 420px) {
  .food__macrorow { grid-template-columns: repeat(2, 1fr); }
}

/* What PRO would be. A plain read: no numbers, so no grid - just a list that says the shape. */
.pro__lede { margin: 0 0 18px; color: var(--ink-2); line-height: 1.5; }
.pro__list { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 14px; }
.pro__item { display: grid; gap: 3px; padding-left: 12px; border-left: 2px solid var(--line); }
.pro__name { font-weight: 600; color: var(--ink); }
.pro__what { color: var(--ink-2); font-size: 13px; line-height: 1.45; }

.footer {
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 20px 18px 32px;
  color: var(--ink-3);
  font-size: 12px;
}

.loading { padding: 60px 0; text-align: center; color: var(--ink-2); }

/* ---------------------------------------------------------------- layout */

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap);
  padding: var(--gap);
  max-width: 1240px;
  margin: 0 auto;
  /* Two panels sharing a row match heights, so a pair never reads as one box being
     cut short. The panel is a flex column, so its content still sits at the top and
     only the trailing space grows. */
  align-items: stretch;
}

/* Two columns from tablet up. A large panel takes the whole row; two small panels share one,
   and a small panel left on its own is given span-2 by the layout code. */
@media (min-width: 720px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .span-1 { grid-column: span 1; }
  .span-2 { grid-column: span 2; }
}

@media (min-width: 1100px) {
  :root { --gap: 16px; }
}

/* ---------------------------------------------------------------- panels */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--pad);
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

.panel__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.panel__title {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.panel__note { font-size: 11px; color: var(--ink-3); }
/* A panel stretched to match its neighbour grows at the bottom, so its call to action has to
   be pinned there. Without this the taller panel's button floats mid-box and the pair no
   longer lines up - which is the same complaint the equal heights were meant to fix. */
.panel > .btn:last-child { margin-top: auto; }

.hero { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.hero__value { font-size: 40px; font-weight: 700; line-height: 1; letter-spacing: -.02em; }
.hero__unit { font-size: 15px; color: var(--ink-2); font-weight: 600; }
.hero__delta { font-size: 13px; font-weight: 600; margin-left: auto; }
.up { color: var(--fat); }
.down { color: var(--muscle); }
.flat { color: var(--ink-3); }

/* key/value rows */
.rows { display: grid; gap: 9px; }
.row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 14px; }
.row__key { color: var(--ink-2); }
.row__val { font-variant-numeric: tabular-nums; font-weight: 600; }
.row__val small { font-weight: 500; color: var(--ink-3); font-size: 11px; margin-left: 4px; }

/* composition / macro bars */
.bar { height: 9px; border-radius: 999px; background: var(--panel-2); overflow: hidden; display: flex; }
.bar__seg { height: 100%; }

.legend { display: grid; gap: 8px; }
.legend__item { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.legend__dot { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.legend__name { color: var(--ink-2); }
.legend__val { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 600; }
.legend__pct { color: var(--ink-3); font-size: 11px; min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; }

/* progress */
.progress { display: grid; gap: 7px; }
.progress__track { height: 7px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
.progress__fill { height: 100%; background: var(--accent); border-radius: 999px; }
.progress__meta { display: flex; justify-content: space-between; font-size: 12px; color: var(--ink-3); }

/* week pips */
.weeks { display: flex; gap: 5px; flex-wrap: wrap; }
.week {
  flex: 1 1 22px;
  min-width: 22px;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  padding: 6px 0;
  border-radius: 7px;
  background: var(--panel-2);
  color: var(--ink-3);
  border: 1px solid transparent;
  font-variant-numeric: tabular-nums;
}
.week--done { color: var(--ink-2); }
.week--now { background: color-mix(in srgb, var(--accent) 22%, var(--panel-2)); color: var(--ink); border-color: var(--accent); }
.week--deload { background: color-mix(in srgb, var(--fat) 18%, var(--panel-2)); color: var(--fat); }

/* session list */
.session { display: grid; gap: 8px; }
.slot {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--panel-2);
  border-radius: 10px;
  border: 1px solid transparent;
}
.slot__order {
  font-size: 11px; font-weight: 700; color: var(--ink-3);
  font-variant-numeric: tabular-nums; min-width: 18px;
}
.slot__body { min-width: 0; }
.slot__muscle { font-weight: 600; font-size: 14px; }
.slot__sets { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Met, in the same green the gym screen uses, so the two screens agree at a glance. */
.slot__sets.is-done { color: var(--muscle); }
/* Same three states as the gym screen, and the same blue for the same reason: a skipped row
   is short on purpose. Named on both selectors so it beats green whichever order they end up
   in - a row can be fully logged and then skipped, and the skip is the later fact. */
.slot__sets.is-skipped,
.slot__sets.is-done.is-skipped { color: var(--accent); }
.slot__sets small { font-weight: 500; color: var(--ink-3); font-size: 11px; margin-left: 3px; }

.empty {
  padding: 22px 14px;
  text-align: center;
  color: var(--ink-3);
  background: var(--panel-2);
  border-radius: 10px;
  font-size: 14px;
}
.empty strong { display: block; color: var(--ink-2); font-size: 15px; margin-bottom: 4px; }

/* volume table */
.vol { display: grid; gap: 7px; }
.vol__row { display: grid; grid-template-columns: minmax(84px, 148px) 1fr 26px 68px; align-items: center; gap: 9px; font-size: 13px; }

/* Focus stepper: two hit targets stacked into one row's height. Small on purpose - the
   chevrons are what you read, these are just how you move them. Used in the planner. */
.focus { display: grid; grid-template-rows: 1fr 1fr; gap: 2px; }
.focus__btn {
  appearance: none; border: 1px solid var(--line); background: var(--panel-2);
  color: var(--ink-2); border-radius: 4px; cursor: pointer;
  font-size: 7px; line-height: 1; padding: 0; height: 13px; width: 20px;
  display: flex; align-items: center; justify-content: center;
}
.focus__btn:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); color: #fff; }
.focus__btn:disabled { opacity: .3; cursor: not-allowed; }

/* The cap, as focus. Unlit rungs stay visible so the headroom is legible. */
.chev { display: inline-flex; align-items: baseline; gap: 2px; min-width: 68px; justify-content: flex-end; }
.chev__m { font-style: normal; font-size: 17px; font-weight: 700; line-height: 1; color: var(--line); }
.chev__m.is-on { color: var(--accent); }
.chev__m--star { font-size: 12px; margin-left: 3px; }


/* On a phone the bar has nowhere to go - it collapsed to about 20px, which reads as nothing.
   Drop it and give the width to the name and the chevrons. */
@media (max-width: 560px) {
  .vol__row { grid-template-columns: 1fr 26px 68px; }
  .vol__track { display: none; }
}
.vol__name { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vol__track { height: 7px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
.vol__fill { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
.vol__num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
.vol__num small { color: var(--ink-3); font-weight: 500; }

/* chart */
.chart { width: 100%; height: auto; display: block; overflow: visible; }
.chart__grid { stroke: var(--line); stroke-width: 1; }
.chart__axis { fill: var(--ink-3); font-size: 10px; font-family: var(--font); }
.chart__line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart__avg { fill: none; stroke: var(--ink-3); stroke-width: 1.5; stroke-dasharray: 4 4; }
.chart__area { fill: color-mix(in srgb, var(--accent) 14%, transparent); }
.chart__dot { fill: var(--accent); }

.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* --------------------------------------------------- dashboard layout edit */

.grid.is-editing .panel { border-style: dashed; }

.lay-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  flex-wrap: wrap;
  margin: calc(var(--pad) * -1) calc(var(--pad) * -1) 0;
  padding: 9px var(--pad);
  background: var(--panel-2);
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
}
.lay-name { font-size: 12px; font-weight: 600; }
/* The width read-out is also the control that changes it. */
.lay-size {
  margin-left: 8px; font: inherit; font-weight: 600; font-size: 10px;
  text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3);
  cursor: pointer; padding: 3px 8px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--line);
}
.lay-size.is-wide {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
.lay-size:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.lay-controls { display: flex; gap: 4px; }
.lay-btn {
  width: 30px; height: 30px; line-height: 1;
  font: inherit; font-size: 14px; cursor: pointer;
  background: var(--panel); color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 7px;
}
.lay-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.lay-btn:disabled { opacity: .3; cursor: not-allowed; }

/* ------------------------------------------------------------- regions */

.region-icon { display: block; flex: none; }

.region-badge { display: inline-flex; align-items: center; gap: 5px; }
.region-badge__label {
  font-size: 10px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3);
}

/* A coloured edge on the leading side of a card or row. */
.region-edge { position: relative; }
.region-edge::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; border-radius: 3px 0 0 3px;
  background: var(--region, var(--region-other));
}

.region--chest { --region: var(--region-chest); }
.region--back { --region: var(--region-back); }
.region--arms { --region: var(--region-arms); }
.region--legs { --region: var(--region-legs); }
.region--shoulders { --region: var(--region-shoulders); }
.region--core { --region: var(--region-core); }
.region--other { --region: var(--region-other); }

/* A small colour key, so the palette is learnable rather than guessed at. */
.region-key { display: flex; flex-wrap: wrap; gap: 7px 14px; padding: 2px 0; }
.region-key .region-badge__label { color: var(--ink-2); }

/* Every place a glyph sits beside a label. */
.entry__title,
.slot__muscle,
.vol__name,
.sore-sig__name,
.sore-row__name { display: flex; align-items: center; gap: 7px; min-width: 0; }

.vol__name, .sore-sig__name { overflow: hidden; }
.vol__name > :last-child,
.sore-sig__name > :nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The card edge sits inside the padding, so pull the content clear of it. */
.entry.region-edge { padding-left: calc(var(--pad) + 6px); }
.slot.region-edge { padding-left: 18px; }

/* --------------------------------------------------------- training log
   Used standing in a gym, one-handed. Big targets, no hover-only affordances. */

.sess { max-width: 760px; margin: 0 auto; padding: var(--gap); display: grid; gap: var(--gap); }

/* The header, the day's totals and the rest timer, frozen as one block. Ordinary flow at the
   top of the page, pinned the moment it would leave - which is what sticky already does, so
   nothing has to measure anything. The tint and the blur moved up here off .sess__head: the
   GAPS between the three panels belong to this box now, and a transparent gap would let a
   card scroll through the middle of it. The internal gap is tighter than the page gap on
   purpose - every pixel in here is a pixel of exercise you cannot see. */
.sess__top {
  position: sticky; top: 0; z-index: 5;
  display: grid; gap: 8px;
  padding-bottom: 10px;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
}

.sess__head {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 0;
  padding-top: max(12px, env(safe-area-inset-top));
}
.sess__title { display: grid; gap: 2px; min-width: 0; }
.sess__date { font-weight: 700; font-size: 15px; }
.sess__meta { font-size: 12px; color: var(--ink-3); }

.sess__progress {
  display: grid; gap: 8px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px var(--pad);
}
.sess__stats { display: flex; justify-content: space-between; font-size: 13px; color: var(--ink-2); }
.sess__stats strong { color: var(--ink); font-variant-numeric: tabular-nums; font-size: 15px; }

.sess__body { display: grid; gap: var(--gap); }

.sess__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 0 max(24px, env(safe-area-inset-bottom));
}
/* Previous week and Skip day: the only two controls that act on the whole day, kept together
   and kept away from the per-exercise menus. */
.sess__acts { display: flex; align-items: center; gap: 8px; flex: none; }
/* Sized and coloured as a ghost button, because that is what it behaves like. */
.add-ex {
  font: inherit; font-size: 12px; cursor: pointer;
  padding: 7px 8px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--panel); color: var(--ink-2);
  max-width: 10rem;
}
.add-ex:hover { border-color: var(--accent); color: var(--accent); }
.add-ex:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.sess.saving { opacity: .6; pointer-events: none; }

.entry {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--pad);
  display: grid; gap: 12px;
}
/* Not being done, by decision. Dashed and muted rather than tinted: it is settled the way a
   finished card is, but it is not an achievement and must not read as one. */
.entry--skipped {
  border-style: dashed;
  border-color: var(--line);
  background: color-mix(in srgb, var(--panel) 85%, var(--bg));
}
.entry--skipped .entry__muscle { color: var(--ink-3); }

/* Finished. Thick on three sides and nothing on the left: that edge already carries the
   muscle colour, and a done-border painted over it would put two different facts in the
   same place. */
.entry--done {
  border-color: color-mix(in srgb, var(--muscle) 45%, var(--line));
  border-width: 3px 3px 3px 0;
}

.entry__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.entry__muscle { font-weight: 700; font-size: 16px; }
.entry__slot { font-size: 11px; color: var(--ink-3); margin-left: 8px; }
/* The count is the card's state at a glance, and there are three of them:

     grey     nothing has happened here yet
     green    finished
     BLUE     skipped - decided against, not forgotten

   Blue rather than amber, which is what this was. Amber is the colour of something needing
   attention, and a skipped exercise needs none: a short count is normally the app telling you
   the day is unfinished, and this is you telling the app it is finished anyway. Blue is the
   accent every deliberate choice on this screen already uses. It wins over green even on a
   card whose sets were all logged before it was skipped - afterwards, "I decided against
   this" is the fact that matters. Colour is never alone: a skipped card is also dashed and a
   finished one has a thick border, so none of this depends on seeing hue. */
.entry__count { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink-2); }
.entry__count.is-done { color: var(--muscle); }
.entry--skipped .entry__count,
.entry--skipped .entry__count.is-done { color: var(--accent); }
.entry__count small { font-weight: 500; font-size: 11px; color: var(--ink-3); margin-left: 4px; }

.ex-select {
  font: inherit; font-size: 14px; width: 100%;
  padding: 11px 12px; min-height: 44px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 9px;
}
.ex-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.entry__last {
  font-size: 12px; color: var(--ink-2);
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  padding: 9px 11px; background: var(--panel-2); border-radius: 8px;
}
.entry__last-label { color: var(--ink-3); }
.entry__last--none { color: var(--ink-3); font-style: italic; }

.set-list { display: grid; gap: 6px; }
.set-row {
  display: grid; grid-template-columns: 22px 1fr auto 34px;
  align-items: center; gap: 10px;
  padding: 9px 11px; border-radius: 8px;
  background: var(--panel-2); font-size: 14px;
}
.set-row--warmup { opacity: .6; }
.set-row__n { font-size: 11px; font-weight: 700; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.set-row__load { font-weight: 600; font-variant-numeric: tabular-nums; }
.set-row__x { color: var(--ink-3); margin: 0 6px; }
.set-row__rir { font-size: 11px; color: var(--ink-3); white-space: nowrap; }

.icon-btn {
  width: 30px; height: 30px; line-height: 1;
  font-size: 17px; font-family: inherit;
  border-radius: 8px; border: 1px solid var(--line);
  background: transparent; color: var(--ink-3); cursor: pointer;
}
.icon-btn:hover { color: var(--warn); border-color: var(--warn); }

/* what to load next */
.next {
  display: grid; gap: 9px;
  padding: 11px 12px; border-radius: 10px;
  background: var(--panel-2);
  border: 1px solid transparent;
}
.next--caution { border-color: color-mix(in srgb, var(--fat) 40%, var(--line)); }

.next__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.next__from { font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.next__reason { margin: 0; font-size: 12px; color: var(--ink-2); line-height: 1.45; }
/* The picker on a lift that carries you is in BELT kilos while everything behind it is
   totals. This line carries that change of units, so it has to read as a statement of fact
   rather than as another suggestion - quieter than the reason above it, and never a chip. */
.next__unit {
  margin: 0;
  font-size: 11.5px;
  color: var(--ink-3);
  line-height: 1.4;
}
.next__unit strong { color: var(--ink-2); font-variant-numeric: tabular-nums; }

.next__ladder { display: flex; gap: 6px; flex-wrap: wrap; }
.rung {
  display: grid; gap: 1px; justify-items: center;
  min-width: 52px; padding: 7px 8px;
  font: inherit; cursor: pointer;
  background: var(--panel); color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 9px;
}
.rung__kg { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.rung__sub { font-size: 9px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.rung.is-current { border-color: var(--ink-3); color: var(--ink); }
.rung.is-picked { background: var(--accent); border-color: var(--accent); color: #fff; }
.rung.is-picked .rung__sub { color: rgba(255, 255, 255, .75); }
.rung.is-out {
  opacity: .4; cursor: not-allowed; text-decoration: line-through;
  text-decoration-thickness: 1px;
}
.rung:not(:disabled):hover { border-color: var(--accent); }

/* The one number you can act on now. Bigger than the reason under it, because the panel is
   read at a glance between sets and the glance has to land on the right line. */
.next__target {
  font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.next__target strong { font-size: 15px; color: var(--accent); font-weight: 700; }
.next__target small { font-size: 11px; color: var(--ink-3); }
/* Deliberately quiet, and deliberately not the accent: there is no number here to look at. */
.next__none { font-size: 13px; color: var(--ink-3); font-style: italic; }

/* Estimated past the range a rep-max formula holds over, so it came off the endurance curve
   instead. The tilde in the text is what actually says so - this only leans it, for readers
   who take the shape of a number in before they read it. Never colour alone. */
.next__from.is-rough, .rung__sub.is-rough { font-style: italic; }
.next__from.is-rough { cursor: help; }

.next__goal {
  font-size: 12px; font-weight: 600; color: var(--fat);
  font-variant-numeric: tabular-nums;
}
.next__goal small { font-weight: 500; color: var(--ink-3); }

.add-set { display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 8px; align-items: end; }
/* A bodyweight lift needs one more box: your weight, then what you added to it. */
.add-set--bw { grid-template-columns: 1fr 1fr 1fr 1fr auto; }
@media (max-width: 560px) {
  .add-set--bw { grid-template-columns: 1fr 1fr; }
  .add-set--bw button { grid-column: 1 / -1; padding: 12px; }
}

/* The pair that belongs together, marked so the wrong one does not get filled in: bodyweight
   accented as the day's figure, added kg dashed as the optional half. Colour alone would not
   do it - the border style survives a glance and a colourblind eye. */
.mini-field--bw .mini-field__label { color: var(--accent); }
.mini-field--bw input {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 7%, var(--panel-2));
}
.add-set--bw input.is-added { border-style: dashed; }
@media (max-width: 420px) {
  .add-set { grid-template-columns: 1fr 1fr 1fr; }
  .add-set button { grid-column: 1 / -1; padding: 12px; }
}

.mini-field { display: grid; gap: 4px; min-width: 0; }
.mini-field__label {
  font-size: 10px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3);
}
.mini-field input {
  padding: 10px; min-height: 44px; font-size: 16px; font-weight: 600;
  text-align: center; font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- planner */

.plan-form, .plan-summary, .plan-block, .plan-list {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--pad);
}
.plan-preview { display: grid; gap: var(--gap); }
.plan-block { display: grid; gap: 12px; }
.plan-block .panel__title { display: flex; align-items: center; gap: 10px; }

.plan-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 14px;
}
.plan-stat { display: grid; gap: 2px; }
.plan-stat__k {
  font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-3);
}
.plan-stat__v { font-size: 15px; font-weight: 700; }
.plan-stat__sub { font-size: 11px; color: var(--ink-3); }

.plan-warn {
  margin-top: 14px; padding: 11px 13px; border-radius: 9px; font-size: 13px;
  background: color-mix(in srgb, var(--fat) 14%, var(--panel-2));
  border: 1px solid color-mix(in srgb, var(--fat) 40%, var(--line));
}
.plan-warn strong { color: var(--fat); }
/* The same box, but for a warning you can act on rather than one you should merely notice. */
.plan-warn--danger {
  margin-top: 14px;
  background: color-mix(in srgb, var(--warn) 14%, var(--panel-2));
  border-color: color-mix(in srgb, var(--warn) 45%, var(--line));
}
.plan-warn--danger strong { color: var(--warn); }
/* The same warning, sitting directly under the control that resolves it. */
.plan-warn--inline { margin-top: 10px; }

/* the ramp: one bar per week, deload in a different colour */
.ramp { display: flex; align-items: flex-end; gap: 4px; height: 130px; }
.ramp__col {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; gap: 4px; height: 100%;
}
.ramp__n { font-size: 10px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.ramp__bar {
  width: 100%; border-radius: 5px 5px 0 0; background: var(--accent); min-height: 4px;
}
.ramp__bar--deload { background: var(--fat); }
.ramp__w { font-size: 10px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.ramp-table { border-collapse: collapse; font-size: 12px; width: 100%; min-width: 460px; }
.ramp-table th, .ramp-table td {
  padding: 6px 8px; text-align: right; font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--line); white-space: nowrap;
}
.ramp-table thead th { color: var(--ink-3); font-weight: 600; font-size: 11px; }
.ramp-table th[scope=row] { text-align: left; color: var(--ink-2); font-weight: 500; }
.ramp-table .is-deload { background: color-mix(in srgb, var(--fat) 12%, transparent); }
/* The cap column is the editor: chevrons, not a number. Give it room and pin it right. */
.ramp-table .is-cap { color: var(--ink-3); padding-left: 14px; }
/* The stepper column. Roomier than the dashboard's was: this is the screen where the levels
   actually get decided, and the rows are tall enough to afford it. */
.ramp-table td:first-child { padding: 3px 6px 3px 0; width: 30px; }
.ramp-table .focus__btn { height: 15px; width: 26px; font-size: 8px; }
.ramp-table .focus { gap: 3px; }
.ramp-table .is-total td:first-child { border-top: 1px solid var(--line); }
.ramp-table .chev { min-width: 72px; }

.plan-hint { color: var(--ink-3); font-size: 12px; line-height: 1.5; margin: 0; }

/* A muscle the split has no exercises for. Listed, because "not this block" is a decision
   worth seeing, but muted so it never reads as part of the week's work. */
.is-unprogrammed { opacity: .55; }
.is-unprogrammed .vol__num, .ramp-table .is-unprogrammed td { color: var(--ink-3); }
.ramp-table .is-total th, .ramp-table .is-total td {
  font-weight: 700; border-bottom: 0; border-top: 1px solid var(--line);
}

/* which weekdays are training days */
.pattern { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.pattern__day {
  display: grid; gap: 3px; justify-items: center;
  padding: 9px 2px; border-radius: 9px; background: var(--panel-2);
  border: 1px solid transparent;
}
.pattern__day.is-train {
  background: color-mix(in srgb, var(--accent) 16%, var(--panel-2));
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
}
.pattern__wd { font-size: 10px; color: var(--ink-3); }
.pattern__dot { font-size: 13px; color: var(--accent); line-height: 1; }
.pattern__day.is-rest .pattern__dot { color: var(--ink-3); }

/* the list of existing cycles */
.plan-list { display: grid; gap: 10px; }
.plan-row {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 10px; padding: 11px 13px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid transparent;
}
.plan-row.is-active { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.plan-row__main { display: grid; gap: 2px; min-width: 0; }
.plan-row__name { font-weight: 700; font-size: 14px; }
.plan-row__phase {
  font-weight: 500; font-size: 11px; color: var(--ink-3); margin-left: 8px;
  text-transform: uppercase; letter-spacing: .06em;
}
.plan-row__dates { font-size: 12px; color: var(--ink-2); }
.plan-row__cut { color: var(--warn); }
.plan-row__usage { font-size: 11px; color: var(--ink-3); }
.plan-row__actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.plan-actions { display: flex; gap: 8px; }

.btn:disabled { opacity: .45; cursor: not-allowed; }

/* ------------------------------------------------------- weigh-in sheet */

.sheet { position: fixed; inset: 0; z-index: 50; display: flex; }
.sheet__scrim { position: absolute; inset: 0; background: rgba(0, 0, 0, .55); }

.sheet__panel {
  position: relative;
  margin: auto auto 0;
  width: 100%;
  max-height: 92dvh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
  animation: sheet-in .18s ease-out;
}

@keyframes sheet-in { from { transform: translateY(14px); opacity: .6; } }

@media (min-width: 640px) {
  .sheet__panel {
    margin: auto;
    width: min(560px, calc(100% - 32px));
    border-radius: var(--radius);
    max-height: 88dvh;
  }
}

.sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px var(--pad); border-bottom: 1px solid var(--line);
}
.sheet__title { margin: 0; font-size: 17px; }

.sheet__body { padding: var(--pad); overflow-y: auto; display: grid; gap: 16px; }

.sheet__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px var(--pad);
  padding-bottom: max(14px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.sheet__hint { font-size: 12px; color: var(--ink-3); }
.sheet__error { margin: 0; color: var(--warn); font-size: 13px; }

.fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.field--wide, .field--lead { grid-column: 1 / -1; }
.field { border: 0; padding: 0; margin: 0; }
.field__label em { font-style: normal; color: var(--ink-3); text-transform: none; }

/* The one number that changes every week gets the big input. */
.field--lead input { font-size: 26px; font-weight: 700; padding: 12px; }

input[type=date] { min-height: 44px; }
input[type=number] { -moz-appearance: textfield; }
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.segmented { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.segmented label { position: relative; }
.segmented input { position: absolute; opacity: 0; pointer-events: none; }
.segmented span {
  display: block; text-align: center; padding: 10px 6px; font-size: 13px; font-weight: 600;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 9px;
  color: var(--ink-2); cursor: pointer;
}
.segmented input:checked + span { background: var(--accent); border-color: var(--accent); color: #fff; }
.segmented input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.preview {
  background: var(--panel-2); border-radius: 10px; padding: 14px;
  display: grid; gap: 9px;
}
.preview__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding-bottom: 9px; border-bottom: 1px solid var(--line);
}
.preview__cal { font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.preview__cal small { font-size: 12px; font-weight: 600; color: var(--ink-2); margin-left: 4px; }
.preview__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); gap: 9px; }
.preview__cell { display: grid; gap: 2px; }
.preview__k { font-size: 10px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); }
.preview__v { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }
.preview--invalid { opacity: .45; }

.btn--sm { padding: 7px 12px; font-size: 13px; }

.saving { opacity: .6; pointer-events: none; }

/* ------------------------------------------------------------- soreness */

.sore-panel { display: grid; gap: 12px; }
.sore-signal { display: grid; gap: 5px; }

.sore-sig {
  display: grid; grid-template-columns: 1fr auto auto auto;
  align-items: center; gap: 8px; font-size: 13px;
  padding: 5px 7px; border-radius: 7px;
}
.sore-sig.is-today { background: var(--panel-2); }
.sore-sig__name { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sore-sig__today {
  font-size: 9px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--accent); margin-left: 7px;
}
.sore-sig__level { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 12px; }
.sore-sig__age {
  font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums;
  min-width: 34px; text-align: right;
}
.sore-sig .chip { font-size: 9px; padding: 3px 7px; }

/* The logging sheet.

   Fourteen muscles at a 40px row was about 780px of list alone, so the sheet always opened
   scrolled and you could not see what you had already recorded. Three changes get it under
   one screen: the list runs in two columns once there is room, the rows are tighter, and the
   sheet itself is wider than the others. */
.sore-help { margin: 0; font-size: 12px; color: var(--ink-3); }
.sore-list { display: grid; gap: 2px 22px; }
.sore-row {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 10px;
  padding: 2px 0;
}
.sore-row__name { font-size: 13px; min-width: 0; }

.sore-scale { display: flex; gap: 5px; }
.sore-pip {
  width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600;
  background: var(--panel-2); color: var(--ink-3);
  border: 1px solid var(--line);
  /* The legend's keys are spans, not buttons, and a span does not centre its text the way a
     button does. Centring here rather than on the button keeps the two identical. */
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; flex: none;
}
.sore-pip.is-on { color: #fff; border-color: transparent; }
.sore-pip--0.is-on { background: var(--muscle); }
.sore-pip--1.is-on { background: #b8b23f; }
.sore-pip--2.is-on { background: var(--fat); }
.sore-pip--3.is-on { background: var(--warn); }
.sore-pip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* the legend: the same pips, coloured as if selected, so the key and the control match */
.sore-legend { display: grid; gap: 6px; }
.sore-legend__row { display: flex; gap: 9px; align-items: center; }
.sore-legend__text { font-size: 12px; color: var(--ink-2); line-height: 1.4; }
.sore-legend__text strong { color: var(--ink); }
.sore-pip.is-key { cursor: default; color: #fff; border-color: transparent; }
.sore-pip--1.is-key { background: #b8b23f; }
.sore-pip--2.is-key { background: var(--fat); }
.sore-pip--3.is-key { background: var(--warn); }

/* Everything below is about fitting fourteen muscles, a legend and a date picker on one
   screen without a scrollbar, on a laptop as well as a desktop. */
#soreness-sheet .sheet__body { gap: 11px; }
/* The date sits on its label's row rather than under it - a two-line field for one control */
#soreness-sheet .sheet__body > .field {
  grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 10px;
}
.sore-pip.is-key { width: 28px; height: 28px; font-size: 12px; }

/* Wider than the other sheets, because it is the only one with a two-column body. */
@media (min-width: 700px) {
  #soreness-sheet .sheet__panel { width: min(720px, calc(100% - 32px)); }
  .sore-list { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 380px) {
  .sore-pip { width: 32px; height: 34px; }
}

/* The week's prescribed effort, shown beside the set count in the gym screen. */
.rir-target { color: var(--ink-2); }
.rir-target strong { color: var(--fat); }

/* "you are off the suggested plan" markers in the Goal panel */
.row__val .is-off { color: var(--fat); font-weight: 500; }

/* The exercise picker and its history button share a row; the picker takes what is left. */
.entry__pick { display: flex; gap: 8px; align-items: stretch; }
.entry__pick .ex-select { flex: 1 1 auto; min-width: 0; }
.entry__history { flex: none; }

/* one logged session in the history sheet */
.hist {
  display: grid; gap: 7px; padding: 11px 0;
  border-top: 1px solid var(--line);
}
.hist:first-of-type { border-top: 0; }
.hist__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.hist__date { font-weight: 700; font-size: 14px; }
.hist__where { font-size: 12px; color: var(--ink-3); }
/* Phase, diet and the sets share one wrapping line - they describe the same session. */
.hist__row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.hist__bw { color: var(--ink-3); font-weight: 500; }
.hist__set {
  font-size: 13px; padding: 3px 8px; border-radius: 7px;
  background: var(--panel-2); border: 1px solid var(--line);
}
.hist__set small { color: var(--ink-3); }
.hist__set--warmup { opacity: .65; }

/* the exercise list editor */
.ex-groups { display: grid; gap: 6px; }
.ex-group { border: 1px solid var(--line); border-radius: 9px; overflow: hidden; }
.ex-group__head {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
  background: var(--panel-2); color: var(--ink); border: 0; text-align: left;
}
.ex-group.is-open .ex-group__head { border-bottom: 1px solid var(--line); }
.ex-group__name { display: flex; align-items: center; gap: 7px; min-width: 0; }
.ex-group__count { font-size: 12px; color: var(--ink-3); font-weight: 500; flex: none; }
.ex-group__body { display: grid; gap: 5px; padding: 9px 12px 11px; }

.ex-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto auto; gap: 8px; align-items: center; }
/* Which way the added weight goes. Words, not just a colour: '+ load' and '- assist' say it. */
.ex-row__sign.is-add { color: var(--muscle); border-color: color-mix(in srgb, var(--muscle) 45%, var(--line)); }
.ex-row__sign.is-assist { color: var(--fat); border-color: color-mix(in srgb, var(--fat) 45%, var(--line)); }
/* the bodyweight tick: a label so the whole thing is the hit target */
.ex-row__bw {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  font-size: 10px; font-weight: 700; letter-spacing: .06em; color: var(--ink-3);
  padding: 4px 8px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--line); white-space: nowrap;
}
.ex-row__bw.is-on {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
.ex-row__bw input { margin: 0; }
.ex-row__name {
  font: inherit; font-size: 13px; min-width: 0;
  padding: 7px 9px; border-radius: 7px;
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
}
.ex-row__name:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ex-row__meta { font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.ex-row__act { padding: 6px 10px; font-size: 12px; }
/* A retired exercise stays visible - it is the only way back - but reads as switched off. */
.ex-row--retired .ex-row__name { color: var(--ink-3); text-decoration: line-through; }
.ex-row--retired .ex-row__meta { opacity: .7; }

.ex-add { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; margin-top: 4px; }
.ex-add input {
  font: inherit; font-size: 13px; min-width: 0;
  padding: 7px 9px; border-radius: 7px;
  background: var(--panel); color: var(--ink); border: 1px dashed var(--line);
}

@media (min-width: 700px) {
  #exercises-sheet .sheet__panel { width: min(680px, calc(100% - 32px)); }
}

/* the diet phase control, which lives in Edit goal & targets */
.diet-phase { display: grid; gap: 7px; }
.diet-phase .sore-help { margin-top: 1px; }

/* the week / day picker on the session panel */
.daypick { display: grid; gap: 7px; }
/* One row, filled edge to edge. grid-auto-flow: column with 1fr columns divides the whole
   width between however many chips there are, so a 4-week block and a 12-week block both
   reach both edges instead of trailing off after the first inch. minmax(0, 1fr) rather than
   1fr, so a narrow phone shrinks the chips instead of overflowing the panel. */
.daypick__weeks, .daypick__days {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px;
}
.daypick__week, .daypick__day {
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  border-radius: 7px; border: 1px solid var(--line);
  background: var(--panel-2); color: var(--ink-3);
  display: inline-flex; align-items: center; justify-content: center;
}
/* No fixed widths: the grid above hands each chip its share of the row. */
.daypick__week { height: 26px; }
.daypick__day { height: 30px; padding: 0 4px; }
.daypick__week:disabled { opacity: .35; cursor: default; }
/* Where you are now, whether or not it is what you are looking at. */
.daypick__week.is-now, .daypick__day.is-today { border-color: var(--accent); color: var(--accent); }
/* What you are looking at. */
.daypick__week.is-on, .daypick__day.is-on {
  background: var(--accent); color: #fff; border-color: transparent;
}
/* A day already behind you reads quieter until you pick it. */
.daypick__day.is-past:not(.is-on) { opacity: .72; }
/* Sets it asked for and never got. A dot rather than a colour, because a short day can also
   be the selected one, and those are two different facts that both have to fit. Full opacity
   so the is-past fade cannot swallow the one mark worth noticing. */
.daypick__week.is-short, .daypick__day.is-short { position: relative; opacity: 1; }
.daypick__week.is-short::after, .daypick__day.is-short::after {
  content: ''; position: absolute; top: 3px; right: 3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--warn); box-shadow: 0 0 0 1.5px var(--panel-2);
}
.daypick__week.is-on.is-short::after, .daypick__day.is-on.is-short::after {
  box-shadow: 0 0 0 1.5px var(--accent);
}
.daypick__week:focus-visible, .daypick__day:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.panel__back { align-self: flex-start; padding: 6px 10px; font-size: 12px; }

/* exercise notes on the gym screen */
.entry__more { flex: none; padding: 7px 11px; font-size: 15px; line-height: 1; }
.notes { display: grid; gap: 5px; margin-top: 2px; }
.note { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 7px; align-items: center; }
.note__body {
  font: inherit; font-size: 13px; min-width: 0;
  padding: 6px 9px; border-radius: 7px;
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
}
.note__body:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* The pin is the label as well as the control: it says which kind of note this is. */
.note__pin {
  font: inherit; font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; cursor: pointer; white-space: nowrap;
  padding: 5px 9px; border-radius: 999px;
  background: var(--panel-2); color: var(--ink-3); border: 1px solid var(--line);
}
.note__pin.is-on {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 10%, var(--panel-2));
}
.note__pin--new { cursor: default; border-style: dashed; }
/* With the 3-dot menu shut the pin is a label, not a control - it still says which kind of
   note this is, it just cannot be clicked. Same for the note body: readable, not editable. */
.note__pin--static { cursor: default; }
.note__body[readonly] { background: var(--panel-2); border-color: transparent; }
.note__body[readonly]:focus-visible { outline: none; }
/* A pinned note is the standing setup, so it reads as the stronger of the two. */
.note--pinned .note__body { border-color: color-mix(in srgb, var(--accent) 30%, var(--line)); }
.note--draft .note__body { border-style: dashed; }
.note__del { padding: 5px 9px; font-size: 11px; }
.note__hint { font-size: 11px; color: var(--ink-3); white-space: nowrap; }

.set-row__bw { display: block; font-size: 10px; color: var(--ink-3); font-weight: 500; }

/* On a bodyweight movement, what the kg box actually means. */
.add-set__bw {
  grid-column: 1 / -1;
  margin: 2px 0 0; font-size: 11px; color: var(--ink-3);
}

/* --- OHT-33: a suggestion and a decision look different ---------------------
   Grey is the app talking. It goes solid on the first keystroke in that box, so the number
   in front of you always says whether it came from you or from your own history. Hitting
   Add Set with it still grey commits it - grey is a real value, not a placeholder. */
.mini-field input.is-suggested { color: var(--ink-3); font-style: italic; }

/* --- OHT-39: a finished exercise folds to its two header rows --------------- */
.entry__fold {
  flex: none; margin-left: 10px;
  padding: 2px 9px; font-size: 15px; font-weight: 700; line-height: 1.3;
  font-variant-numeric: tabular-nums;
}
.entry__count { margin-left: auto; }
.entry--shut { gap: 8px; }

/* --- OHT-38: what the 3-dot button opens ----------------------------------- */
.entry__menu { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.chip--action {
  cursor: pointer; appearance: none; font: inherit; font-size: 12px;
  background: var(--panel-2); color: var(--ink-2);
}
.chip--action:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.chip--action.is-on { color: var(--accent); border-color: var(--accent); }
/* Marked, not shouted: it sits in a menu you open on purpose, and the confirm is the real
   guard. Colour alone would fail in greyscale, so the word "Delete" does the work. */
/* A locked picker is still the label for what you are lifting, so it stays readable - dimming
   it to the usual disabled grey would make the exercise name the hardest thing on the card. */
.ex-select.is-locked { opacity: 1; color: var(--ink); cursor: not-allowed; border-style: dashed; }

.chip--danger { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, var(--line)); }
.chip--danger:hover {
  color: var(--warn); border-color: var(--warn);
  background: color-mix(in srgb, var(--warn) 14%, transparent);
}

/* The rest timer: label, five minute chips, and the countdown when one is running - all on
   one line. It rides in the sticky block at the top of the screen, because you rest from an
   exercise while looking at something else and it has to survive scrolling away from the card
   that started it. Everything on the row is sized
   to stay on the row: the whole point is one tap without hunting. */
.rest {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 9px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
.rest__label { font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.rest__presets { display: flex; gap: 4px; flex: none; }
.rest__preset {
  min-width: 26px; padding: 4px 0; text-align: center;
  font-size: 12px; font-variant-numeric: tabular-nums;
}
.rest__clock {
  font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--accent); white-space: nowrap;
}
.rest__track {
  flex: 1 1 auto; height: 6px; min-width: 24px;
  background: var(--panel-2); border-radius: 999px; overflow: hidden;
}
.rest__fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width .25s linear; }
.rest__btn { flex: none; padding: 4px 7px; font-size: 11px; }
.rest__label {
  appearance: none; cursor: pointer; font: inherit;
  padding: 2px 5px; margin: -2px -1px; border-radius: 6px;
  border: 1px solid transparent; background: transparent;
}
.rest__label:hover { color: var(--ink-2); border-color: var(--line); }
.rest__label:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.rest.is-running { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.rest.is-up { border-color: var(--muscle); }
.rest.is-up .rest__clock { color: var(--muscle); }
.rest.is-up .rest__fill { background: var(--muscle); }

/* --- OHT-53: the last five seconds, and the moment it lands -----------------
   Two states, and they have to be tellable apart from across a gym: the run-in BLINKS once
   a second, in step with the beep, and zero POPS. Colour carries both on its own, so the
   animations can be turned off for a reader who does not want movement without the cue
   disappearing with them. */
@keyframes rest-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .18; } }
@keyframes rest-pop {
  0% { transform: scale(1); }
  30% { transform: scale(1.35); }
  100% { transform: scale(1); }
}

.rest.is-final { border-color: var(--warn); }
.rest.is-final .rest__clock { color: var(--warn); animation: rest-blink 1s steps(1, end) infinite; }
.rest.is-final .rest__fill { background: var(--warn); }

/* The big face, over the exercises but not instead of them: they stay visible round the
   edge, so opening this is not the same as losing your place. */
.restbig__scrim {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(3px);
}
.restbig {
  position: relative;
  width: 75vw; max-width: 560px;
  height: 75vh; max-height: 620px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; padding: 20px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: calc(var(--radius) * 1.5);
  box-shadow: 0 18px 60px rgb(0 0 0 / .35);
}
.restbig__close {
  position: absolute; top: 10px; right: 10px;
  appearance: none; cursor: pointer; font: inherit; font-size: 15px; line-height: 1;
  width: 34px; height: 34px; border-radius: 50%;
  color: var(--ink-3); background: var(--panel-2); border: 1px solid var(--line);
}
.restbig__close:hover { color: var(--ink); border-color: var(--ink-3); }
.restbig__clock {
  font-size: clamp(56px, 18vw, 132px); font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--accent);
}
.restbig__track {
  width: 100%; height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--panel-2);
}
.restbig__fill {
  height: 100%; border-radius: 999px; background: var(--accent);
  transition: width .25s linear;
}
.restbig__presets { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.restbig__presets .chip { min-width: 42px; padding: 8px 0; text-align: center; font-size: 14px; }
.restbig__acts { display: flex; gap: 10px; }
.restbig__hint { margin: 0; font-size: 12px; color: var(--ink-3); }

.restbig.is-final .restbig__clock { color: var(--warn); animation: rest-blink 1s steps(1, end) infinite; }
.restbig.is-final .restbig__fill { background: var(--warn); }
.restbig.is-up .restbig__clock { color: var(--muscle); animation: rest-pop .55s ease-out 4; }
.restbig.is-up .restbig__fill { background: var(--muscle); }

/* Movement off, cue kept: the colours above are separate declarations and survive this. */
@media (prefers-reduced-motion: reduce) {
  .rest.is-final .rest__clock,
  .restbig.is-final .restbig__clock,
  .restbig.is-up .restbig__clock { animation: none; }
}

/* --- OHT-11: the training week, as seven buttons ---------------------------
   The row reads from the day the block starts, because that is the order you train it in.
   The marker above each column is the week's first day - it moves the start date rather than
   being a second setting that could disagree with it. */
.dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.dow__col { display: grid; gap: 3px; justify-items: stretch; min-width: 0; }
.dow__first {
  appearance: none; cursor: pointer; font: inherit;
  padding: 1px 0; font-size: 10px; font-weight: 700; line-height: 1.4;
  color: var(--ink-3); background: transparent;
  border: 1px solid transparent; border-radius: 5px;
}
.dow__first:hover:not(:disabled) { color: var(--ink-2); border-color: var(--line); }
.dow__first.is-on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.dow__day {
  appearance: none; cursor: pointer; font: inherit;
  padding: 9px 0; font-size: 12px; font-weight: 700;
  color: var(--ink-3); background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 8px;
}
.dow__day:hover:not(:disabled) { color: var(--ink-2); border-color: var(--ink-3); }
.dow__day.is-on { color: #fff; background: var(--accent); border-color: var(--accent); }
.dow__day:disabled, .dow__first:disabled { cursor: default; opacity: .55; }
.dow__hint { margin: 6px 0 0; font-size: 11px; color: var(--ink-3); }

/* --- OHT-28-F1: moving a card, from its own menu ---------------------------
   The same four controls the dashboard uses to rearrange its panels, so the gesture is one
   gesture across the app rather than two things that do the same job differently. */
.entry__move { margin-left: auto; }

/* --- OHT-36: joints, next to the muscles and visibly not among them --------
   The separation is the point. A sore muscle is the training working and a sore joint is the
   training going wrong, so the two readings must not be scanned as one list. */
.sore-joints {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line);
}
.sore-joints__head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.sore-joints__body { margin: 6px 0 0; font-size: 12px; color: var(--ink-2); }
.sore-joints__note { font-size: 11px; color: var(--ink-3); }
.sore-joints .sore-help { margin-top: 4px; }
/* Joints the exercise you just finished actually loads, listed first and labelled. Everything
   else stays on the list: a knee that hurts after a pressing day is exactly the reading you
   would not want filtered out. */
.sore-row--lead .sore-row__name { color: var(--ink); font-weight: 600; }
.sore-row__tag {
  margin-left: 6px; padding: 1px 6px; border-radius: 999px;
  font-size: 10px; font-weight: 600; color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
}

/* ------------------------------------------------------ sign-in attempts (OHT-63) */
/* Full-screen like the disclaimer, because the tables are wide and this is read, not
   glanced at. The tables scroll horizontally on a phone rather than wrapping an address
   onto two lines - a broken IP is worse than a scrollbar. */

.sec {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  /* minmax(0, 1fr), not the implicit auto track: an auto track sizes to its CONTENT, so the
     wide tables inside push the card past the viewport and the whole overlay scrolls sideways
     with the right-hand columns cut off. Pinned to the container, the card stays the width of
     the screen and the tables scroll inside themselves, which is the intent. */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  align-content: start;
  padding: 20px;
  overflow-y: auto;
  background: var(--bg);
}

.sec__card {
  min-width: 0;
  width: min(880px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  display: grid;
  /* And again here, for the same reason as .sec above: the card's own implicit track would
     size to the widest table's max-content - 539px inside a 335px card on a phone - and the
     tables would spill out of the card instead of scrolling inside it. */
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

.sec__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.sec__title { margin: 0; font-size: 20px; }
.sec__lead { margin: 0; color: var(--ink-2); font-size: 13.5px; }
.sec__sub {
  margin: 8px 0 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.sec__note { margin: 0; color: var(--ink-3); font-size: 12px; line-height: 1.5; }
.sec__error { margin: 0; color: var(--warn); font-size: 13px; }

.sec__empty {
  display: grid;
  gap: 4px;
  padding: 14px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  color: var(--ink-2);
  font-size: 13px;
}
.sec__empty strong { color: var(--ink); font-size: 13.5px; }

.sec__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  display: block;
  overflow-x: auto;
  white-space: nowrap;
}
.sec__table th {
  text-align: left;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0 12px 6px 0;
}
.sec__table td { padding: 7px 12px 7px 0; border-top: 1px solid var(--line); }
.sec__table code { font-size: 12.5px; color: var(--ink); }

.sec__row--warn td { background: color-mix(in srgb, var(--warn) 7%, transparent); }
.sec__read { color: var(--ink-3); font-size: 12px; }

.sec__state { font-weight: 600; }
.sec__state--perm { color: var(--warn); }
.sec__state--timed { color: var(--accent); }

.sec__out { font-size: 12.5px; }
.sec__out--fail { color: var(--ink-2); }
.sec__out--ok { color: var(--accent); }
.sec__out--blocked { color: var(--warn); }

/* A fingerprint, not a password. Monospaced and dimmed so it never reads as something
   anyone could type back in. */
.sec__hash code { color: var(--ink-2); letter-spacing: .02em; }
.sec__hash small { color: var(--ink-3); font-size: 11px; }
