/* Meso — AI strength-training program designer.
   Ported from the Meso.dc.html Claude Design prototype. The root container in
   the template carries the design tokens as CSS custom properties (--bg, --ink,
   --accent, ...); this file holds the global resets, fonts, scrollbar styling,
   and keyframes that the prototype declared in its <helmet>. */

* {
  box-sizing: border-box;
}

html,
body.meso {
  margin: 0;
  padding: 0;
  height: 100%;
}

body.meso {
  background: #f4f4f5;
  font-family: "Hanken Grotesk", system-ui, -apple-system, sans-serif;
}

/* Design tokens, re-pointed at the shared core token VALUES (design-system
   unification, PR 3) so Meso reads as part of Mastering Fitness: steel-blue
   accent #31759d (was an oklch blue-purple), shared neutrals, and the shared
   dark-nav colours that nav.css consumes. The designer also sets these inline
   on its root (so it stays self-contained); here they live on .meso so the
   standard pages inherit them without repeating the block. */
.meso {
  --bg: #f4f4f5;
  --surface: #ffffff;
  --rail: #fbfbfc;
  --ink: #0a0a0a;
  --dim: #6b7280;
  --line: #e4e4e7;
  --line-2: #f1f3f5;
  /* Perceptible neutral hover fill — clearly darker than --rail (#fbfbfc),
     which sat too close to white surfaces to read as a hover (issue #385). */
  --hover: #ebedf0;
  --radius: 8px;
  --pad: 14px;
  /* Accent points at the shared site token (base.css --accent, steel-blue) so
     Meso reads as part of Mastering Fitness — design-system unification PR 3.
     The soft/line/deep values mirror the site's hand-picked --accent-soft /
     --accent-line / --accent-deep rather than a color-mix, to match exactly. */
  --accent: #31759d;
  --accent-ink: #ffffff;
  --soft: #eaf2f7;
  --soft-line: #bcd6e4;
  --accent-deep: #1f516b;
  --warn: #b4541f;
  --warn-soft: #fbefe8;
  --ok: #2f8f56;
  /* Cadence signal's "stale" band (issue #482 — the recency pill replacing
     the current-week compliance meter): a third, more urgent tone than
     --warn so a lapsed athlete (>=10d) reads as a clear escalation, not the
     same amber as "a few days behind." */
  --danger: #b23434;
  --danger-soft: #fbeaea;
  /* shared dark site nav (PR 3) — same values as base.css :root */
  --nav-bg: #0a0a0a;
  --nav-fg: #ededed;
}

/* Hide Alpine-managed elements until Alpine initializes (avoids a flash). */
[x-cloak] {
  display: none !important;
}

.meso input,
.meso textarea {
  font-family: inherit;
}

.meso ::placeholder {
  color: #abb0b6;
}

/* A text input / textarea on a coach or account form — the roster invite
   field's look, as a class, so the settings and profile forms match it. */
.meso .meso-field {
  appearance: none;
  display: block;
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--rail);
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  padding: 8px 10px;
  outline: none;
}

.meso .meso-field:focus {
  border-color: var(--accent);
}

.meso textarea.meso-field {
  resize: vertical;
  line-height: 1.45;
}

/* 16px on a phone: iOS Safari zooms the page on focusing a smaller input. */
@media (max-width: 640px) {
  .meso .meso-field {
    font-size: 16px;
  }
}

.meso *::-webkit-scrollbar {
  width: 11px;
  height: 11px;
}

.meso *::-webkit-scrollbar-thumb {
  background: rgba(20, 24, 30, 0.16);
  border-radius: 7px;
  border: 3px solid transparent;
  background-clip: content-box;
}

.meso *::-webkit-scrollbar-thumb:hover {
  background: rgba(20, 24, 30, 0.28);
  border: 3px solid transparent;
  background-clip: content-box;
}

.meso *::-webkit-scrollbar-track {
  background: transparent;
}

/* The `hidden` attribute always wins inside Meso (#517). The UA's
   `[hidden] { display: none }` loses to any author `display`, whether an
   inline style or a class like .meso-btn's inline-flex, so an element the
   JS hid stayed on screen. */
.meso [hidden] {
  display: none !important;
}

@keyframes msgIn {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes blink {
  0%,
  80%,
  100% {
    opacity: 0.2;
  }
  40% {
    opacity: 1;
  }
}

@keyframes toastIn {
  from {
    opacity: 0;
    transform: translate(-50%, -10px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

/* Smooth the hover/press feedback so state changes read as intentional rather
   than snapping. Scoped to the interactive surfaces (issue #385). */
.meso-btn,
.meso-navlink,
.meso-seg-btn,
a.meso-row,
button.meso-row,
a.meso-card,
button.meso-card,
.meso-avatar--link,
.meso [data-hover] {
  transition:
    background-color 0.15s ease,
    border-color 0.15s ease,
    box-shadow 0.15s ease,
    color 0.15s ease,
    transform 0.12s ease,
    filter 0.15s ease;
}

@media (prefers-reduced-motion: reduce) {
  .meso-btn,
  .meso-navlink,
  .meso-seg-btn,
  a.meso-row,
  button.meso-row,
  a.meso-card,
  button.meso-card,
  .meso-avatar--link,
  .meso [data-hover] {
    transition: none;
  }
  /* Keep colour feedback, drop the motion. */
  a.meso-card:hover,
  button.meso-card:hover {
    transform: none;
  }
}

/* Hover/focus affordances that the prototype expressed as inline style-hover /
   style-focus attributes (not real CSS). Re-expressed here as real rules.

   Issue #385: the designer's data-hover elements set `background`/`border`/
   `color` INLINE, which outranks these attribute selectors — so the original
   background swaps never actually applied (only the `brighten` filter did, and
   only faintly). `!important` is used deliberately to override those inline
   resting styles; `filter` needs none since it is never set inline. The target
   values are also strengthened from near-white --rail to the on-brand --soft
   accent tint so the change is clearly visible. */
.meso [data-hover="rail"]:hover {
  background: var(--soft) !important;
  border-color: var(--soft-line) !important;
}
.meso [data-hover="brighten"]:hover {
  /* Darkens the filled steel-blue buttons noticeably (was a barely-there
     +6% brighten that washed them toward white). */
  filter: brightness(0.9);
}
.meso [data-hover="chip"]:hover {
  background: var(--soft) !important;
  border-color: var(--soft-line) !important;
}
.meso [data-hover="add"]:hover {
  background: var(--soft) !important;
  border-color: var(--soft-line) !important;
  color: var(--accent) !important;
}
.meso .meso-cell:focus {
  background: var(--soft);
  box-shadow: inset 0 0 0 1px var(--soft-line);
}
.meso .meso-phone-input:focus {
  border-color: var(--soft-line);
  background: var(--surface);
}
/* Parse-at-commit warn (5a, docs/meso/parse-at-commit-plan.md §8): a sub-line
   cell whose text looks like a set attempt but won't be logged. Derived on read
   (no stored flag) — see `models.sub_line_warn_reason` (and `parsing
   .cell_warn_reason`) and `_sub_lines` in presenters.py. Never rejected, tinted.

   Set via --cell-line/--cell-bg, NOT border-color/background: the sub-line
   input declares those two properties inline, and an inline declaration beats
   any class selector. The custom properties are not declared inline, so these
   win — which is what makes the tint visible at all. */
.meso .meso-phone-input--warn {
  --cell-line: color-mix(in srgb, var(--warn) 45%, var(--line));
  --cell-bg: var(--warn-soft);
}
.meso .meso-phone-input--warn:focus {
  --cell-line: var(--warn);
  --cell-bg: var(--warn-soft);
}
.meso .meso-composer:focus-within {
  border-color: var(--soft-line);
  box-shadow: 0 0 0 3px var(--soft);
}

/* Display helpers for elements toggled by x-show. Alpine resets style.display
   to "" when revealing, which would drop an inline `display` value; sourcing the
   display from a class makes that reset fall back to the intended value instead
   of the element default (block). */
.meso .meso-flex {
  display: flex;
}

/* Segmented controls (mode / view / period toggles). The prototype rendered an
   on + off variant per button; here one button styles itself via .is-on. */
.meso .meso-seg {
  display: inline-flex;
  background: var(--rail);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 3px;
  gap: 2px;
}
.meso .meso-seg-btn {
  appearance: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 550;
  letter-spacing: -0.01em;
  padding: 5px 12px;
  border-radius: 6px;
  background: transparent;
  color: var(--dim);
}
.meso .meso-seg-btn:hover:not(.is-on) {
  background: var(--surface);
  color: var(--ink);
}
.meso .meso-seg-btn.is-on {
  background: var(--surface);
  color: var(--ink);
  font-weight: 650;
  box-shadow: 0 1px 2px rgba(16, 18, 22, 0.09);
}
.meso .meso-seg-btn--v {
  font-size: 12.5px;
  padding: 5px 13px;
}
.meso .meso-seg-btn--p {
  font-size: 12px;
  padding: 4px 11px;
}

/* ==========================================================================
   Shared component layer for the spine screens (roster, profile, review,
   deliver, results). The designer is a full-viewport tool with its own chrome;
   these classes give the surrounding pages a consistent look built from the
   same tokens. Standard pages set --bg/--ink/etc. on body.meso and scroll
   normally (the designer locks the viewport instead).
   ========================================================================== */

.meso-app {
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font-family: "Hanken Grotesk", system-ui, -apple-system, sans-serif;
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/* --- top nav --- */
.meso-topnav {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 16px;
  height: 55px;
  padding: 0 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.meso-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--ink);
}
.meso-brand-mark {
  width: 23px;
  height: 23px;
  border-radius: 6px;
  background: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.meso-brand-mark i {
  width: 8px;
  height: 8px;
  background: var(--accent-ink);
  border-radius: 2px;
  transform: rotate(45deg);
}
.meso-brand b {
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.025em;
}
.meso-navlinks {
  display: flex;
  align-items: center;
  gap: 2px;
}
.meso-navlink {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--dim);
  text-decoration: none;
  padding: 6px 11px;
  border-radius: 7px;
}
.meso-navlink:hover {
  background: var(--hover);
  color: var(--ink);
}
.meso-navlink.is-active {
  color: var(--ink);
  background: var(--soft);
}
.meso-spacer {
  flex: 1;
}

/* Review card footer: the "Honors:" pill and the Approve/Reject control. The
   pill wraps (a long honors line must not shove the control past the card's
   edge) and the control drops beneath it when the row is too narrow. The
   compound selector is load-bearing: `.meso-badge` (later in this file) sets
   `white-space: nowrap` and would beat a lone class. */
.meso-review-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.meso-badge.meso-review-honors {
  min-width: 0;
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
  border-radius: 12px;
}
.meso-review-foot > .meso-seg {
  flex: 0 0 auto;
  margin-left: auto;
}

/* The Meso shell's shared site nav lives in the cross-site nav.css (loaded by
   _meso_base alongside meso.css) — design-system unification PR 3. The earlier
   Meso-only `.meso-sitenav` partial was retired in favour of that one nav. */

/* --- page scaffold --- */
.meso-page {
  max-width: 1120px;
  margin: 0 auto;
  padding: 26px 24px 64px;
}
.meso-page--narrow {
  max-width: 860px;
}
.meso-eyebrow {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 8px;
}
.meso-h1 {
  margin: 0 0 4px;
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.025em;
}
.meso-sub {
  margin: 0;
  font-size: 13px;
  color: var(--dim);
}
.meso-pagehead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 22px;
}
/* Landing-page hero (issue #415) — a modifier, not a change to .meso-pagehead
   itself, since that shared class is also every other page's plain title+actions
   header. Copy left, product screenshot right; one column once the two can no
   longer sit comfortably side by side (760px matches nav.css's own burger-menu
   breakpoint). */
.meso-pagehead--hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 460px);
  align-items: center;
  gap: 36px;
}
@media (max-width: 760px) {
  .meso-pagehead--hero {
    grid-template-columns: 1fr;
    gap: 20px;
  }
}
.meso-hero-shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  /* Product-chrome framing consistent with .meso-card, just a bit more lift
     since this is the hero rather than resting page content. */
  box-shadow: 0 10px 28px rgba(16, 18, 22, 0.12);
}
/* How-it-works card stills (issue #415 follow-up) — a lighter variant of
   .meso-hero-shot: smaller radius/shadow, since these are supporting
   texture below the hero + video, not the main event. A single fixed
   max-height (rather than width:100%) keeps the three cards' images the
   same visual weight even though their intrinsic aspect ratios differ (the
   deliver shot is a phone portrait, design/adapt are landscape) — each is
   centered at that shared height so the row of three cards still lines up. */
.meso-card-shot {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 168px;
  margin: 0 auto 12px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: 0 4px 10px rgba(16, 18, 22, 0.08);
}
.meso-crumbs {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--dim);
  margin-bottom: 14px;
}
.meso-crumbs a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
}

/* --- cards --- */
.meso-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 1px 2px rgba(16, 18, 22, 0.03);
}
.meso-card--pad {
  padding: 18px 20px;
}
/* Cards used as links/buttons (e.g. a session card, the "Are you a coach?"
   entry) had no hover at all — just the pointer cursor (issue #385). Lift them
   with shadow + a small rise; box-shadow/transform survive the inline
   background/border some of these cards set, so the feedback always shows. */
a.meso-card,
button.meso-card {
  cursor: pointer;
}
a.meso-card:hover,
button.meso-card:hover {
  border-color: var(--soft-line);
  box-shadow: 0 4px 14px rgba(16, 18, 22, 0.1);
  transform: translateY(-2px);
}
.meso-grid {
  display: grid;
  gap: 14px;
}
.meso-grid--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.meso-grid--profile {
  grid-template-columns: 320px minmax(0, 1fr);
  align-items: start;
}

/* --- buttons --- */
.meso-btn {
  appearance: none;
  cursor: pointer;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 14px;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}
.meso-btn:hover {
  /* Was --rail (#fbfbfc) on a white --surface button — invisible. Now an
     on-brand steel-blue tint with a matching border + faint lift (issue #385). */
  background: var(--soft);
  border-color: var(--soft-line);
  color: var(--accent-deep);
  box-shadow: 0 1px 3px rgba(16, 18, 22, 0.1);
}
.meso-btn--primary {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: transparent;
  font-weight: 650;
  box-shadow: 0 1px 2px rgba(16, 18, 22, 0.12);
}
.meso-btn--primary:hover {
  /* Deepen the fill (was a barely-there +6% brighten) and lift it. Reset the
     border-color the base .meso-btn:hover would otherwise leak in. */
  background: var(--accent-deep);
  color: var(--accent-ink);
  border-color: transparent;
  box-shadow: 0 3px 8px rgba(31, 81, 107, 0.28);
}
.meso-btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--accent);
  padding-left: 0;
  padding-right: 0;
}
.meso-btn--ghost:hover {
  /* Text-only button: reset the border/shadow the base .meso-btn:hover adds. */
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--accent-deep);
  text-decoration: underline;
}

/* --- badges / status pills --- */
.meso-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
}
.meso-badge i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.meso-badge--accent {
  color: var(--accent-deep);
  background: var(--soft);
  border: 1px solid var(--soft-line);
}
.meso-badge--warn {
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px solid color-mix(in srgb, var(--warn) 22%, #fff);
}
.meso-badge--ok {
  color: var(--ok);
  background: color-mix(in srgb, var(--ok) 12%, #fff);
  border: 1px solid color-mix(in srgb, var(--ok) 26%, #fff);
}
.meso-badge--muted {
  color: var(--dim);
  background: var(--rail);
  border: 1px solid var(--line);
}
.meso-badge--danger {
  color: var(--danger);
  background: var(--danger-soft);
  border: 1px solid color-mix(in srgb, var(--danger) 22%, #fff);
}
.meso-tag {
  display: inline-flex;
  padding: 4px 9px;
  border-radius: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 11.5px;
  font-weight: 500;
  white-space: nowrap;
}
.meso-tag--accent {
  background: var(--soft);
  border-color: var(--soft-line);
  color: var(--accent-deep);
  font-weight: 600;
}

/* --- avatars --- */
.meso-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-weight: 700;
  flex: 0 0 auto;
  background: #eef0f2;
  color: var(--dim);
  width: 38px;
  height: 38px;
  font-size: 13px;
}
.meso-avatar--accent {
  background: var(--soft);
  border: 1px solid var(--soft-line);
  color: var(--accent-deep);
}
.meso-avatar--sm {
  width: 28px;
  height: 28px;
  font-size: 11px;
}
.meso-avatar--lg {
  width: 48px;
  height: 48px;
  border-radius: 13px;
  font-size: 16px;
}
/* The topnav identity chip (issue #387) — the one avatar that's a link, so it
   must read as clickable where the decorative list monograms don't. */
.meso-avatar--link {
  text-decoration: none;
  cursor: pointer;
}
.meso-avatar--link:hover,
.meso-avatar--link:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 1px 6px rgba(49, 117, 157, 0.25);
}
/* The athlete PWA's chip is a link on a phone, so it meets the 44px tap target. */
@media (max-width: 640px) {
  .meso-avatar--tap {
    width: 44px;
    height: 44px;
    font-size: 13px;
  }
}

/* --- athlete rows / list --- */
.meso-row {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line-2);
  text-decoration: none;
  color: var(--ink);
}
.meso-row:last-child {
  border-bottom: 0;
}
/* Only the clickable rows (links/buttons) get a hover — the many static
   div.meso-row layout containers should not light up (issue #385). --soft is
   clearly visible where the old near-white --rail was not. */
a.meso-row:hover,
button.meso-row:hover {
  background: var(--soft);
}
.meso-row-name {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.meso-row-meta {
  font-size: 11.5px;
  color: var(--dim);
}

/* --- progress bar --- */
.meso-meter {
  height: 6px;
  border-radius: 4px;
  background: var(--line);
  overflow: hidden;
  flex: 1;
}
.meso-meter > span {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--accent);
}

/* --- divider + misc --- */
.meso-hr {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 16px 0;
}
.meso-muted {
  color: var(--dim);
}
.meso-mono {
  font-family: "IBM Plex Mono", monospace;
}

/* ==========================================================================
   Athlete pages on a phone (issue #508): the training home's block table and
   the session logger. Scoped by `.meso-athlete` on those two pages'
   `.meso-page`, so nothing here reaches the coach surfaces or the designer.
   Two breakpoints, both media-query-only (no JS branch), like the tour's
   bottom sheet in _tour.html:
   - 760px (nav.css's burger breakpoint) or any touch-first pointer: tap
     targets grow to 44px. A phone held sideways is wider than 760px but
     still a thumb, hence `pointer: coarse`.
   - 640px: the block table becomes stacked cards and the logger tightens.
   ========================================================================== */

/* Every input on an athlete page is 16px at every width: iOS Safari zooms the
   page when it focuses an input set smaller than that, landscape included.
   Zooming stays enabled (the viewport meta has no maximum-scale). */
.meso-athlete input,
.meso-athlete select,
.meso-athlete textarea {
  font-size: 16px;
}

/* --- block table (wide screens) --- */
/* Scrolls both ways inside its own box: a sticky header only pins inside its
   nearest scroll container, and overflow-x:auto makes this box one on both
   axes, so the cap on its height is what lets a long day keep its week
   labels in view. */
.meso-block-scroll {
  overflow: auto;
  max-height: 70vh;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--line);
  border-radius: 11px;
}
/* `separate` rather than `collapse`: a collapsed border stays behind when its
   sticky cell moves. */
.meso-block-table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-size: 12px;
  white-space: nowrap;
}
.meso-block-table th,
.meso-block-table td {
  text-align: left;
  padding: 7px 10px;
}
.meso-block-table th {
  position: sticky;
  top: 0;
  z-index: 2;
  font-weight: 700;
  color: var(--dim);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.meso-block-table th.is-focused {
  color: var(--accent-deep);
  background: var(--soft);
}
.meso-block-table td {
  color: var(--ink);
  border-top: 1px solid var(--line);
}
.meso-block-table tbody tr:first-child td {
  border-top: 0;
}
.meso-block-table td.is-focused {
  background: var(--soft);
}
/* The exercise column pins left; its header cell pins both ways, above both
   the header row and the body. */
.meso-block-table th:first-child,
.meso-block-table td:first-child {
  position: sticky;
  left: 0;
  background: var(--surface);
}
.meso-block-table td:first-child {
  z-index: 1;
  font-weight: 700;
}
.meso-block-table th:first-child {
  z-index: 3;
  color: var(--dim);
}

/* --- block, stacked (phones): the focused week only --- */
.meso-block-stack,
.meso-block-stack-only {
  display: none;
}
.meso-block-stack {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--surface);
}
.meso-block-stack-row {
  padding: 10px 12px;
  border-top: 1px solid var(--line);
}
.meso-block-stack-row:first-child {
  border-top: 0;
}
.meso-block-stack-name {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 3px;
  overflow-wrap: anywhere;
}
.meso-block-stack-lines {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.meso-block-stack-off {
  font-size: 12.5px;
  color: var(--dim);
}

/* --- week chips (training home) --- */
.meso-week-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 7px 13px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
}
.meso-week-chip.is-focused {
  box-shadow: inset 0 0 0 1.5px var(--accent-deep);
  color: var(--accent-deep);
}

/* --- session logger --- */
/* The logger's inputs share one look. Border and background stay inline on
   each input: the sub-line's warn tint and the (existing) focus rules above
   depend on exactly that arrangement. No `font` shorthand here — it would
   reset the 16px above. */
.meso .meso-log-input {
  appearance: none;
  min-width: 0;
  font-family: "IBM Plex Mono", monospace;
  padding: 6px 8px;
  border-radius: 7px;
  outline: none;
  color: var(--ink);
}
/* A typed sub-line; its status note wraps under the input when both don't fit. */
.meso-sub-line-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 8px;
  row-gap: 2px;
  margin-bottom: 6px;
}
.meso-sub-line-row .meso-log-input {
  flex: 1 1 12em;
}
.meso-log-actions,
.meso-log-actions-buttons {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.meso-log-actions {
  margin-top: 16px;
}

/* --- tap targets: 44px on anything a thumb would press --- */
@media (max-width: 760px), (pointer: coarse) {
  /* Shared chrome: the Meso topnav sits on every page, coach pages too, and
     is 55px tall, so this grows the hit area without moving anything. */
  .meso-brand,
  .meso-navlink {
    min-height: 44px;
  }
  .meso-navlink {
    display: inline-flex;
    align-items: center;
  }
  .meso-athlete .meso-btn,
  .meso-athlete .meso-week-chip,
  .meso-athlete .meso-log-input,
  .meso-athlete input {
    min-height: 44px;
  }
  .meso-athlete .meso-btn {
    min-width: 44px;
    justify-content: center;
  }
  /* Inline text controls: grow the box to 44px, then take the growth back
     out of the layout with a negative margin, so the line doesn't get taller. */
  .meso-athlete .meso-crumbs a,
  .meso-athlete summary {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin-top: -13px;
    margin-bottom: -13px;
  }
}

/* --- phone layout --- */
@media (max-width: 640px) {
  .meso-athlete.meso-page {
    padding-left: 16px;
    padding-right: 16px;
  }
  .meso-athlete .meso-card--pad {
    padding: 16px;
  }
  .meso-athlete .meso-block-scroll {
    display: none;
  }
  .meso-athlete .meso-block-stack {
    display: block;
  }
  .meso-athlete .meso-block-stack-only {
    display: inline;
  }
  /* The Finish session button takes the full width, last on the page, where
     the thumb already is. */
  .meso-log-actions-buttons {
    flex: 1 1 100%;
    gap: 10px;
  }
  .meso-log-actions-buttons .meso-btn {
    flex: 1 1 0;
    justify-content: center;
  }
}

/* ==========================================================================
   Coach pages on a phone (issue #508, second slice): roster, results, the
   athlete profile, deliver, review and the template library. Scoped by
   `.meso-coach` on those pages' `.meso-page`, apart from the topnav, which is
   shared chrome like the tap-target rule above. One breakpoint, 760px
   (nav.css's burger breakpoint): multi-column grids go to one column and
   rows too wide for a phone wrap. Nothing here applies above 760px, so the
   desktop layouts don't move.

   The designer is the exception: it isn't editable on a phone, so under
   900px designer.html shows a message with links instead of the island (the
   last block below).
   ========================================================================== */

/* Layout that was inline on these pages, moved here so the breakpoint can
   override it. Same values as before. */
.meso-roster-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 312px;
  gap: 18px;
  align-items: start;
}
.meso-results-grid {
  display: grid;
  grid-template-columns:
    minmax(0, 1.5fr) minmax(0, 1.3fr) minmax(0, 1.1fr) 56px
    minmax(0, 1.3fr);
  gap: 10px;
}
/* A list row with no avatar (a template): the name takes the free width.
   Here rather than inline so the phone rule below can take it back. */
.meso-row > .meso-row-main:first-child {
  flex: 1;
}
/* A page's topnav buttons: laid out as if they were the bar's own children
   on a wide screen, their own row on a phone. */
.meso-topnav-actions {
  display: contents;
}

@media (max-width: 760px) {
  /* --- topnav: brand, links and avatar on the first row; the page's buttons
     (e.g. "Adjust next week →") wrap onto a second row instead of pushing
     the page wider than the phone. Links that don't fit wrap inside their
     own box. --- */
  .meso-topnav {
    flex-wrap: wrap;
    height: auto;
    min-height: 55px;
    column-gap: 12px;
    row-gap: 0;
    padding: 0 16px;
  }
  /* Keeps the first row at the bar's usual 55px once the bar can grow. */
  .meso-topnav > .meso-brand {
    min-height: 55px;
  }
  .meso-topnav > .meso-spacer {
    display: none;
  }
  .meso-navlinks {
    flex: 1 1 0;
    min-width: 0;
    flex-wrap: wrap;
  }
  .meso-topnav-actions {
    display: flex;
    order: 1;
    flex: 1 1 100%;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 8px;
    padding-bottom: 10px;
  }
  .meso-topnav-actions:empty {
    display: none;
  }

  /* --- page scaffold --- */
  .meso-coach.meso-page {
    padding-left: 16px;
    padding-right: 16px;
    /* A long unbroken name (an athlete with no name shows their email's
       local part) breaks rather than widening the page. `anywhere`, not
       `break-word`, so it also lowers the minimum width of the flex items it
       sits in, which is what would otherwise push them past the screen. */
    overflow-wrap: anywhere;
  }
  /* Badges and tags carry names too (a block's title, a goal), and are
     nowrap everywhere else. */
  .meso-coach .meso-badge,
  .meso-coach .meso-tag {
    white-space: normal;
  }
  /* A select is as wide as its longest option (an athlete's name); let it,
     and the list-row column it sits in, shrink to the screen. */
  .meso-coach select,
  .meso-coach .meso-row form {
    min-width: 0;
    max-width: 100%;
  }
  .meso-coach .meso-pagehead,
  .meso-coach .meso-crumbs {
    flex-wrap: wrap;
  }
  /* Inline-flex rows marked for it wrap instead of overflowing; a primary
     button that wraps keeps to the right edge, where it sits on desktop. */
  .meso-coach .meso-phone-wrap {
    flex-wrap: wrap;
  }
  .meso-coach .meso-phone-wrap > .meso-btn--primary {
    margin-left: auto;
  }
  /* A button label longer than the phone (a long athlete name or email)
     wraps; `anywhere` so a flex row can shrink it past one unbroken word. */
  .meso-coach .meso-btn {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .meso-coach .meso-card--pad {
    padding: 16px;
  }

  /* --- one column --- */
  .meso-coach .meso-roster-split,
  .meso-coach .meso-grid--profile {
    grid-template-columns: minmax(0, 1fr);
  }

  /* --- list rows (roster, templates): the name keeps the line beside its
     avatar; badges and buttons wrap to a second line, lined up under the
     name by the row's spacer (the avatar's 38px plus the row's gap). --- */
  .meso-coach .meso-row {
    flex-wrap: wrap;
    row-gap: 8px;
  }
  .meso-coach .meso-row > * {
    min-width: 0;
  }
  .meso-coach .meso-row > .meso-row-main {
    flex: 1 1 calc(100% - 51px);
  }
  .meso-coach .meso-row > .meso-spacer {
    flex: 0 0 38px;
  }
  /* A row with no avatar (a template): the name takes the whole line. */
  .meso-coach .meso-row > .meso-row-main:first-child {
    flex-basis: 100%;
  }
  /* The roster list's header: "Individuals" on its own line, then the count
     and the links together, instead of one link stranded on a line. */
  .meso-coach .meso-roster-head > .meso-eyebrow {
    flex-basis: 100%;
  }
  .meso-coach .meso-roster-head > .meso-spacer {
    display: none;
  }

  /* --- results: the three stats stack as short lines; each exercise row
     stacks its cells under the name, each labelled from its data-label. --- */
  .meso-coach .meso-stats {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }
  .meso-coach .meso-stats > .meso-card {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 12px 16px;
  }
  .meso-results-head {
    display: none;
  }
  .meso-results-row {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 4px;
  }
  .meso-results-row > [data-label] {
    display: flex;
    align-items: baseline;
    gap: 10px;
  }
  .meso-results-row > [data-label]::before {
    content: attr(data-label);
    flex: 0 0 52px;
    /* The RPE cell centres its badge on desktop; its label mustn't follow. */
    text-align: left;
    font-family: "Hanken Grotesk", system-ui, -apple-system, sans-serif;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--dim);
  }
}

/* --- designer: a message instead of the island under 900px --- */
/* The island's mount. It used to carry `min-width:1240px; overflow:hidden`
   inline, which clipped everything past the first screen on a narrow
   window; the island's own root keeps the 1240px floor and this box scrolls
   it instead, so nothing is unreachable if the message below is bypassed
   (e.g. a phone's "desktop site", which renders about 980px wide). */
.meso-designer-mount {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: auto;
}
.meso-designer-fallback {
  display: none;
}
/* Server messages over the designer (#605). Fixed so they never push the
   100vh mount into a page scroll; they fade out on their own because the
   island has no control to dismiss them. */
.meso-designer-flash {
  position: fixed;
  top: 66px;
  right: 16px;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 360px;
  animation: meso-designer-flash 8s forwards;
}
.meso-designer-flash-item {
  padding: 11px 14px;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 9px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.meso-designer-flash-item.is-error {
  border-left-color: var(--warn);
}
@keyframes meso-designer-flash {
  0%,
  85% {
    opacity: 1;
    visibility: visible;
  }
  100% {
    opacity: 0;
    visibility: hidden;
  }
}
@media (max-width: 900px) {
  .meso-designer-mount {
    display: none;
  }
  .meso-designer-fallback {
    display: block;
  }
  /* Shown up to 900px, past the coach pages' 760px rules, so it carries
     its own: a long unbroken plan title or athlete email wraps rather than
     widening the page. */
  .meso-designer-fallback .meso-page {
    padding-left: 16px;
    padding-right: 16px;
    overflow-wrap: break-word;
  }
  .meso-designer-fallback .meso-btn {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}
.meso-designer-fallback-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}
