/* ============================================================
   Design tokens — "Electric" palette
   Change these and the rest of the app follows.
   Dark mode = same vars, overridden by [data-theme="dark"] below.
   ============================================================ */
:root {
  /* Surfaces */
  --bg:            #f8fafc;   /* page background */
  --surface:       #ffffff;   /* cards / panels */
  --surface-alt:   #f1f5f9;   /* table headers, secondary panels */
  --border:        #e2e8f0;   /* hairline dividers */
  --border-strong: #cbd5e1;   /* input borders, stronger lines */

  /* Text */
  --text:          #0f172a;   /* primary text */
  --text-muted:    #475569;   /* secondary / helper */
  --text-subtle:   #94a3b8;   /* placeholders, very quiet */
  --text-on-accent:#ffffff;   /* readable on the accent button */

  /* Semantic */
  --accent:        #2563eb;   /* primary action (Electric blue) */
  --accent-hover:  #1d4ed8;
  --success:       #16a34a;   /* sent / done */
  --warning:       #d97706;   /* partial / careful */
  --danger:        #dc2626;   /* delete / refute */

  /* Shape + motion */
  /* The focus ring is the accent at low alpha, so it reads as the same colour
     family as the control it is on rather than a browser default. */
  --focus-ring:    rgba(37, 99, 235, 0.35);

  /* The three workout sections. Categorical, so they stay distinguishable --
     but chosen against the light surface for contrast rather than picked to
     be loud, which is what #f39c12 / #9b59b6 / #3498db were. */
  --sec-warmup:    #b45309;
  --sec-offwall:   #7c3aed;
  --sec-onwall:    #2563eb;

  --radius:        12px;
  --radius-sm:     8px;
  --shadow-sm:     0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow:        0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);

  /* Header (was hard-coded slate) */
  --header-bg:     #0f172a;
  --header-text:   #ffffff;
  --footer-bg:     #1e293b;
}

/* Dark mode, reached two ways.
 *
 * The declarations below appear twice on purpose, and a test asserts the two
 * copies stay identical:
 *
 *   - the media query, for a visitor who has expressed no preference. Their OS
 *     setting decides, and it keeps working with no JavaScript at all.
 *   - the attribute, for a visitor who has chosen. It is outside the media
 *     query, so an explicit choice beats the OS in both directions.
 *
 * The media query excludes [data-theme="light"] so that choosing light on a
 * dark OS is honoured rather than immediately overruled. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:            #0b0e14;
    --surface:       #161b22;
    --surface-alt:   #1e242e;
    --border:        #27303d;
    --border-strong: #3a4555;

    --text:          #f1f5f9;
    --text-muted:    #94a3b8;
    --text-subtle:   #64748b;
    --text-on-accent:#ffffff;

    --accent:        #3b82f6;   /* slightly brighter blue, reads better on dark */
    --accent-hover:  #60a5fa;
    --success:       #22c55e;
    --warning:       #f59e0b;
    --danger:        #ef4444;

    --focus-ring:    rgba(96, 165, 250, 0.45);

    /* Lifted for the dark surface; the light values go muddy on it. */
    --sec-warmup:    #fbbf24;
    --sec-offwall:   #a78bfa;
    --sec-onwall:    #60a5fa;

    --shadow-sm:     0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow:        0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);

    --header-bg:     #050810;
    --header-text:   #f1f5f9;
    --footer-bg:     #050810;
  }
}

[data-theme="dark"] {
  --bg:            #0b0e14;
  --surface:       #161b22;
  --surface-alt:   #1e242e;
  --border:        #27303d;
  --border-strong: #3a4555;

  --text:          #f1f5f9;
  --text-muted:    #94a3b8;
  --text-subtle:   #64748b;
  --text-on-accent:#ffffff;

  --accent:        #3b82f6;   /* slightly brighter blue, reads better on dark */
  --accent-hover:  #60a5fa;
  --success:       #22c55e;
  --warning:       #f59e0b;
  --danger:        #ef4444;

  --focus-ring:    rgba(96, 165, 250, 0.45);

  /* Lifted for the dark surface; the light values go muddy on it. */
  --sec-warmup:    #fbbf24;
  --sec-offwall:   #a78bfa;
  --sec-onwall:    #60a5fa;

  --shadow-sm:     0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow:        0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);

  --header-bg:     #050810;
  --header-text:   #f1f5f9;
  --footer-bg:     #050810;
}

/* Smooth transitions when toggling theme */
html { transition: background-color 0.18s ease, color 0.18s ease; }
body, .card, .button { transition: background-color 0.18s ease, color 0.18s ease, border-color 0.18s ease; }

/* Reset and Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

/* `hidden` is an attribute, and the browser's own rule for it is the weakest
   kind there is: any author rule that sets `display` -- a class, or an inline
   style -- silently wins, and the element stays on screen however correctly the
   markup or a controller sets the attribute. That has now produced the same
   defect five separate times in this file, each patched one element at a time.
   This settles it for every element at once. */
[hidden] { display: none !important; }

  body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    line-height: 1.6;
    color: var(--text);
    background-color: var(--bg);
  }
  
  /* Layout Structure */
  /* `body >` matters: <header> is an ordinary sectioning element, and pages use
     it for their own section headings. Unscoped, these rules painted those in
     the nav bar's near-black and, in the phone shell below, gave them the nav's
     `order: 2` -- which is why a day in the week calendar rendered its date
     underneath its exercises, on a dark strip. */
  body > header {
    background-color: var(--header-bg);
    color: var(--header-text);
    padding: 1rem 0;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  }
  
  main {
    max-width: 1200px;
    margin: 2rem auto;
    padding: 0 1rem;
    min-height: calc(100vh - 200px);
  }
  
  /* Override for Today's Task page - make it MUCH wider */
  main:has(.todays-task-container) {
    max-width: 90%;
  }
  
  footer {
    background-color: var(--footer-bg);
    color: var(--header-text);
    text-align: center;
    padding: 1.5rem;
    margin-top: 3rem;
  }
  
  /* Navigation */
  nav {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 1rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  /* The header is dark in both themes, so the wordmark is tuned once against
     it rather than swapped per theme. */
  .wordmark {
    display: inline-block;
    color: var(--header-text);
    text-decoration: none;
    font-size: 1.35rem;
    font-weight: 800;
    letter-spacing: -0.025em;
  }

  .wordmark__accent {
    color: #60a5fa;
  }
  
  .nav-links {
    display: flex;
    gap: 1rem;
    align-items: center;
  }
  
  .nav-links span {
    color: #ecf0f1;
  }
  
  .nav-links a {
    color: white;
    text-decoration: none;
    padding: 0.5rem 1rem;
    border-radius: 20px;
    transition: background-color 0.3s;
  }
  
  .nav-links a:hover {
    background-color: #34495e;
  }

  /* Which page you are on. The bar carried no mark of it at all. */
  .nav-links a[aria-current="page"] {
    background-color: var(--accent);
    color: var(--text-on-accent);
  }

  .nav-links a[aria-current="page"]:hover {
    background-color: var(--accent-hover);
  }

  /* Phone-only nav pieces (see the bottom-bar media query further down). */
  .nav-home,
  .nav-user-icon,
  .nav-admin-menu {
    display: none;
  }
  
  /* Flash Messages */
  .flash {
    padding: 1rem;
    margin-bottom: 1rem;
    border-radius: 20px;
    font-weight: 500;
  }
  
  .flash.notice {
    background-color: #d4edda;
    border: 1px solid #c3e6cb;
    color: #155724;
  }
  
  .flash.alert {
    background-color: #f8d7da;
    border: 1px solid #f5c6cb;
    color: #721c24;
  }
  
  /* Buttons and Links — one rule, every element renders the same */
  .button, input[type="submit"], button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.625rem 1.25rem;
    background-color: var(--accent);
    color: var(--text-on-accent);
    text-decoration: none;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font: inherit;
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.2;
    user-select: none;
    /* The grey flash iOS paints over a tapped control undoes the press state
       below; the control says what it is doing itself. */
    -webkit-tap-highlight-color: transparent;
    transition: background-color 0.18s ease, box-shadow 0.18s ease,
                transform 0.06s ease;
  }

  .button:hover, input[type="submit"]:hover, button:hover {
    background-color: var(--accent-hover);
    text-decoration: none;
  }

  /* A press worth feeling: the control gives under the finger and comes back.
     0.06s is below the threshold where it reads as an animation rather than
     as the button responding. */
  .button:active, input[type="submit"]:active, button:active {
    transform: translateY(1px);
  }

  /* :focus-visible, not :focus -- a ring on every mouse click is noise, but a
     keyboard or switch user has nothing else to go on. */
  .button:focus-visible, input[type="submit"]:focus-visible, button:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--focus-ring);
  }

  /* Variants */
  .button-secondary {
    background-color: transparent;
    color: var(--text);
    border: 1px solid var(--border-strong);
  }
  .button-secondary:hover {
    background-color: var(--surface-alt);
  }

  .button-danger {
    background-color: var(--danger);
  }
  .button-danger:hover {
    background-color: var(--danger);
    opacity: 0.9;
  }

  /* Size modifier */
  .button-small {
    padding: 0.35rem 0.85rem;
    font-size: 0.9rem;
  }

  /* button_to wraps in a form — make the wrapper invisible to layout */
  form.button_to {
    display: inline-flex;
    margin: 0;
  }
  
  a {
    color: #3498db;
    text-decoration: none;
  }
  
  a:hover {
    text-decoration: underline;
  }
  
  /* Typography */
  h1 {
    color: #2c3e50;
    margin-bottom: 1rem;
    font-size: 2rem;
  }
  
  h2 {
    color: #34495e;
    margin-bottom: 0.75rem;
    font-size: 1.5rem;
  }
  
  p {
    margin-bottom: 1rem;
  }
  
  /* Forms - Login/Signup Only */
  .sessions form,
  .users form {
    background-color: var(--surface);
    padding: 2rem;
    border-radius: 20px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    max-width: 500px;
    margin: 2rem auto;
  }
  
  .sessions form div,
  .users form div {
    margin-bottom: 1.5rem;
  }
  
  label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 600;
    color: var(--text);
  }
  
  /* Fields fill their row. Everything else about how they look -- border,
     radius, padding, colour -- is set once from the tokens further down; this
     block used to restate it with a 20px radius and a #ddd border that the
     token block then had to override. */
  input[type="email"],
  input[type="password"],
  input[type="text"],
  input[type="number"],
  input[type="date"],
  select {
    width: 100%;
  }
  
  .sessions form input[type="submit"],
  .users form input[type="submit"] {
    width: 100%;
    margin-top: 1rem;
  }
  
  /* Form Error Messages */
  .field_with_errors {
    display: inline;
  }
  
  .field_with_errors input {
    border-color: #e74c3c;
  }
  
  form .error {
    color: #e74c3c;
    background-color: #fadbd8;
    padding: 1rem;
    border-radius: 20px;
    margin-bottom: 1.5rem;
    border: 1px solid #e74c3c;
  }
  
  form .error h2 {
    color: #c0392b;
    font-size: 1.1rem;
    margin-bottom: 0.5rem;
  }
  
  form .error ul {
    margin-left: 1.5rem;
  }
  
  form .error li {
    margin-bottom: 0.25rem;
  }
  
  /* Textareas */
  textarea {
    width: 100%;
    padding: 0.75rem;
    border: 1px solid #ddd;
    border-radius: 20px;
    font-size: 1rem;
    min-height: 100px;
    font-family: inherit;
  }
  
  textarea:focus {
    outline: none;
    border-color: #3498db;
    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
  }
  
  /* Training Cycle Actions */
  .training-cycle-actions form {
    background: none;
    padding: 0;
    margin: 0;
    box-shadow: none;
    max-width: none;
    display: inline;
  }
  
  .training-cycle-actions a,
  .training-cycle-actions button {
    margin-right: 0.75rem;
  }
  
  /* Today's Task Page */
  .todays-task-container {
    max-width: 1100px;
    margin: 2rem auto;
  }

  /* A date, not a banner: page-title weight without page-title size. */
  .todays-task-date {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.25;
  }

  .todays-task-container form {
    background: none;
    padding: 0;
    margin: 0;
    box-shadow: none;
    max-width: none;
  }

  /* The three sections are cards, so the thing holding them is just a grid --
     a surface here would put a panel inside a panel. */
  .todays-task-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin: 0 auto;
  }

    .task-column {
    min-width: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    /* One coloured edge per section, and only one: the heading used to carry a
       second rule underneath it, in a blue that was the same on all three. */
    border-top: 3px solid var(--section);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
  }

  .task-column--warmup  { --section: var(--sec-warmup); }
  .task-column--offwall { --section: var(--sec-offwall); }
  .task-column--onwall  { --section: var(--sec-onwall); }

  .task-column h2 {
    margin: 0;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--section);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  
  .task-column textarea {
    min-height: 80px;
    font-size: 0.85rem;
  }
  
  .task-planned {
    margin-bottom: 0.75rem;
    font-size: 0.85rem;
  }

  .task-planned strong {
    display: block;
    margin-bottom: 0.25rem;
  }

  .activity-planned.is-completed strong,
  .activity-planned.is-completed > label > div > div {
    text-decoration: line-through;
    text-decoration-color: var(--text-muted);
    /* Keep full text color — strikethrough is the signal, not dimming */
  }

  /* Actual data styling - red text/border for differentiation from planned */
  .task-actual, .actual-data {
    color: #e74c3c;
  }

  .task-column textarea[id$="_actual"] {
    border-color: #e74c3c;
    color: #e74c3c;
  }

  .task-column textarea[id$="_actual"]:focus {
    border-color: #c0392b;
    box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1);
  }

  .task-column textarea[id$="_actual"]::placeholder {
    color: #e8a9a2;
  }

  /* Responsive — stack columns on narrow screens */
  @media (max-width: 700px) {
    .todays-task-grid {
      grid-template-columns: 1fr;
    }
  }

  /* Button row for forms — buttons size to content, not stretched */
.form-actions {
  display: flex;
  gap: 0.75rem;
  margin-top: 1.5rem;
  flex-wrap: wrap;
}

/* Drag-to-reorder activity items */
.activity-item {
  cursor: grab;
}

.activity-item:active {
  cursor: grabbing;
}

/* The "ghost" — semi-transparent placeholder shown where the item will land */
.sortable-ghost {
  opacity: 0.4;
  background: #ecf0f1 !important;
}

/* Don't make form inputs themselves grab — only the surrounding card */
.activity-item input,
.activity-item select,
.activity-item textarea,
.activity-item button {
  cursor: auto;
}

/* ============================================================
   Card — reusable surface utility.
   Use anywhere we want the "white panel with subtle shadow" look.
   Replaces the inline `background: white; padding: 1.5rem; border-radius: 20px;`
   pattern that's sprinkled across views.
   ============================================================ */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 1.5rem;
}

/* A card whose content reaches its edges -- a table, a list -- so it carries no
   padding of its own and clips its children to the corner radius. */
.card--flush {
  padding: 0;
  overflow: hidden;
}

/* Roomier than the default, for a page's main panel. */
.card--roomy {
  padding: 2rem;
}

/* One row in a list of them. Smaller in every dimension than a panel. */
.card-row {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
}
/* Form inputs adopt the palette too */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="url"],
select,
textarea {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.75rem;
  font: inherit;
  font-size: 0.95rem;
}
/* A date input is a native control: left to itself it sizes to its value
   rather than filling the row, and on iOS it sits at a different height from
   the text fields beside it. Stripping the native appearance lets it take the
   same box as every other field in the form. */
/* One focus treatment for every field, from the same token as the buttons. */
input[type="text"]:focus-visible,
input[type="email"]:focus-visible,
input[type="password"]:focus-visible,
input[type="number"]:focus-visible,
input[type="date"]:focus-visible,
input[type="url"]:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--focus-ring);
}

/* Checkboxes and radios are drawn by the OS. `accent-color` is the one hook
   into that drawing, and without it they stay the browser's default blue on
   every screen while the rest of the app follows the palette. */
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--accent);
}

input[type="date"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  /* Matches a text input: padding both sides plus one line of text. */
  min-height: calc(1.5em + 1rem + 2px);
}

/* iOS keeps the value in a shadow element with its own alignment and spacing,
   so the text drifts off the baseline the other fields share. */
input[type="date"]::-webkit-date-and-time-value {
  text-align: left;
  margin: 0;
  line-height: 1.5;
}

/* Keep the picker icon at the trailing edge rather than tight against the value. */
input[type="date"]::-webkit-calendar-picker-indicator {
  margin-inline-start: auto;
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="date"]:focus,
input[type="url"]:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* Link color */
a { color: var(--accent); }
a:hover { color: var(--accent-hover); }

/* Heading tightening */
h1, h2, h3, h4 { color: var(--text); }
h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.01em; }
h2 { font-size: 1.25rem; font-weight: 700; }
h3 { font-size: 1.05rem; font-weight: 600; }

/* The safety net that lived here matched inline styles by substring --
   [data-theme="dark"] [style*="background: white"] and friends -- and patched
   them for the dark theme only. That is precisely why the two themes drifted:
   the light theme kept the raw inline value while the dark theme got a
   corrected one, so they were never the same panel. Every one of those inline
   values is now a token, so there is nothing left to patch. */

/* Form inputs in dark mode — even with inline backgrounds, surface them */
[data-theme="dark"] input[type="text"],
[data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="date"],
[data-theme="dark"] input[type="email"],
[data-theme="dark"] input[type="password"],
[data-theme="dark"] input[type="url"],
[data-theme="dark"] select,
[data-theme="dark"] textarea {
  background: var(--surface) !important;
  color: var(--text) !important;
  border-color: var(--border-strong) !important;
}

/* --- Phone layout: bottom tab bar ------------------------------------ */
/* Covers Safari, the home-screen PWA, and the Hotwire Native shell alike. */

@media (max-width: 700px) {
  /* The phone layout is a shell exactly one viewport tall: the page itself
     never scrolls, only the content inside it does. A bar pinned with
     `position: fixed` instead rides the document, and iOS Safari re-places
     fixed elements only once a scroll gesture ends -- which is what made the
     bar drift away from the bottom mid-scroll. A shell that cannot scroll has
     nothing to drift against. */
  body {
    height: 100vh;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  /* Source order puts the nav first, for screen readers and for the desktop
     top bar. `order` moves it under the content without moving the markup.
     Scoped to the page's own header -- see the note on the base rule. */
  body > header {
    order: 2;
    flex: none;
    /* The inset is capped. Uncapped, iOS hands back up to 34px for the home
       indicator and the bar becomes a slab; the indicator only overlays a few
       pixels, so a small allowance clears it and the bar stays a bar. */
    padding: 0.25rem 0.5rem calc(0.25rem + min(env(safe-area-inset-bottom), 0.5rem));
    z-index: 100;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);
  }

  /* The one scrolling region. `min-height: 0` is what lets it shrink: a flex
     child defaults to min-height:auto, and the desktop `min-height` below
     would otherwise push the bar off the bottom of the shell. */
  main {
    order: 1;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
    /* Zero BOTH margins, and no `auto`. An auto margin on the cross axis of a
       flex item suppresses stretch, so `0 auto` left this sizing to its widest
       content instead of the viewport -- one wide table inside a week dragged
       the whole page 121px sideways, header and all. */
    margin: 0;
    width: 100%;
    padding-top: calc(1rem + env(safe-area-inset-top));
    padding-bottom: 1rem;
  }

  /* The signed-in home is this page, and it was using 319px of a 390px screen.
     `max-width: 90%` gave away 39px before anything was drawn, the gutters took
     32 more, and a 2rem margin pushed the first card down past the fold. On a
     phone the screen is the whole budget. */
  main:has(.todays-task-container) {
    max-width: 100%;
  }

  main {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }

  .todays-task-container {
    max-width: 100%;
    margin-top: 0;
  }

  /* Compact tab row: no brand, Home link instead, spread items evenly. */
  body > header .nav-brand,
  body > header .nav-admin,
  body > header .nav-user-name {
    display: none;
  }

  body > header .nav-home,
  body > header .nav-user-icon,
  .nav-admin-menu {
    display: inline;
  }

  body > header nav {
    padding: 0;
    max-width: 100%;
  }

  body > header .nav-links {
    width: 100%;
    justify-content: space-around;
    gap: 0.25rem;
  }

  /* Four labelled tabs plus the menu button have to share a phone width, so
     the labels are tightened and kept on one line rather than wrapping. */
  body > header .nav-links a {
    padding: 0.3rem 0.25rem;
    font-size: 0.72rem;
    /* Body copy is 1.6, which on a tab label is ~5px of air per row. */
    line-height: 1.2;
    white-space: nowrap;
  }

  /* A pill, but a tight one: five items share a 320px row on the smallest
     phone still in service, so the active tab can only afford a little more
     width than its neighbours. */
  body > header .nav-links a[aria-current="page"] {
    border-radius: 999px;
    padding: 0.3rem 0.5rem;
  }

  /* The menu glyph is what actually sets the bar's height: left at body size
     and 1.6 line-height it stands ~13px taller than the tab labels beside it. */
  body > header .nav-user-menu > summary {
    padding: 0.3rem 0.4rem !important;
    line-height: 1.2;
  }

  body > header .nav-user-icon {
    font-size: 0.95rem;
    line-height: 1.2;
  }

  /* Signed out, the only nav items are Log In and Sign Up, which the page
     itself already offers. Hiding the bar leaves one centred action. */
  body:not(.signed-in) > header {
    display: none;
  }

  body:not(.signed-in) main {
    padding-bottom: 1rem;
  }

  /* Open the account menu UPWARD from the bottom bar. */
  body > header .nav-user-menu > div {
    top: auto !important;
    bottom: calc(100% + 0.25rem) !important;
  }
}

/* ─────────────────────────────────────────────────────────────
   Training-plan drag-and-drop builder
   Phase 1: shell styling only (setup form + placeholders)
   ───────────────────────────────────────────────────────────── */
.builder-setup {
  background: var(--surface);
  padding: 1rem;
  border-radius: 12px;
  margin-bottom: 1rem;
}

.builder-setup__row {
  margin-bottom: 0.75rem;
}

.builder-setup__row:last-child {
  margin-bottom: 0;
}

.builder-setup__row--inline {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

.builder-setup label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-weight: 600;
}

.builder-setup label span {
  font-size: 0.85rem;
  color: var(--text-muted);
}

.builder-setup input {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 1rem;
  min-width: 12rem;
}

.builder-grid-placeholder,
.builder-library-placeholder,
.builder-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  margin-top: 1rem;
}

.builder-actions .button--muted {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
}

.builder-save {
  padding: 0.55rem 1.2rem;
  background: #27ae60;
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
}

.builder-save:disabled {
  opacity: 0.6;
  cursor: default;
}

.builder-setup__note {
  margin: 0.75rem 0 0 0;
  padding: 0.5rem 0.75rem;
  background: var(--surface-alt);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.builder-error {
  margin-top: 0.75rem;
  padding: 0.6rem 0.9rem;
  background: rgba(231, 76, 60, 0.15);
  border: 1px solid #e74c3c;
  border-radius: 6px;
  color: var(--text);
  font-size: 0.9rem;
}

.builder-error[hidden] { display: none; }

/* ── Week bar ───────────────────────────────────────────── */
.builder-week-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}

.builder-week-tabs {
  display: flex;
  gap: 0.25rem;
  flex-wrap: wrap;
}

.builder-week-tab {
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
}

.builder-week-tab--active {
  background: #3498db;
  border-color: #3498db;
  color: #fff;
}

/* ── Copy chooser ───────────────────────────────────────── */
.builder-copy-chooser {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  font-size: 0.9rem;
}

.builder-copy-chooser__label {
  font-weight: 600;
  color: var(--text-muted);
}

.builder-copy-chooser__radio {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.builder-copy-chooser__count {
  width: 3.5rem;
  padding: 0.2rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: 4px;
}

.builder-copy-chooser__apply {
  padding: 0.35rem 0.9rem;
  background: #2c3e50;
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  cursor: pointer;
}

/* ── Grid ───────────────────────────────────────────────── */
.builder-grid {
  display: block;
  overflow-x: auto;             /* scroll horizontally on narrow screens */
  background: var(--surface);
  border-radius: 12px;
  padding: 0.5rem;
  margin-bottom: 1rem;
}

.builder-grid__row {
  display: grid;
  grid-template-columns: 8rem repeat(7, minmax(9rem, 1fr));
  gap: 0.3rem;
}

.builder-grid__row + .builder-grid__row {
  margin-top: 0.25rem;
}

.builder-grid__row--header .builder-grid__day-header {
  padding: 0.35rem 0.5rem;
  text-align: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  line-height: 1.1;
}

.builder-grid__day-name {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.builder-grid__day-date {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--text-subtle);
}

.builder-grid__row--header .builder-grid__day-header:hover .builder-grid__day-name {
  color: var(--text);
}
.builder-grid__row--header .builder-grid__day-header:hover {
  border-color: var(--border);
}

.builder-grid__row--header .builder-grid__day-header--selected {
  background: rgba(52, 152, 219, 0.15);
  border-color: #3498db;
}
.builder-grid__day-header--selected .builder-grid__day-name,
.builder-grid__day-header--selected .builder-grid__day-date {
  color: #3498db;
}

.builder-grid__row--header .builder-grid__day-header--today {
  background: rgba(37, 99, 235, 0.12);
  border-color: var(--accent);
}
.builder-grid__day-header--today .builder-grid__day-name {
  color: var(--accent);
}
.builder-grid__day-header--today .builder-grid__day-date {
  color: var(--accent);
  font-weight: 700;
}

.builder-grid__corner {
  /* Empty top-left cell above the row labels. */
}

.builder-grid__row-label {
  display: flex;
  align-items: center;
  padding: 0.5rem 0.75rem;
  font-weight: 600;
  font-size: 0.85rem;
  background: var(--surface-alt);
  color: var(--text);
  border-radius: 6px;
}

.builder-grid__cell {
  min-height: 4rem;
  padding: 0.5rem;
  background: var(--surface-alt);
  border: 1px dashed var(--border);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.builder-grid__cell--empty {
  align-items: center;
  justify-content: center;
}

/* Highlight for a whole column when its day is selected for swap. */
.builder-grid__cell--selected {
  background: rgba(52, 152, 219, 0.08);
  border-color: #3498db;
  border-style: solid;
}

.builder-grid__empty-hint {
  color: var(--text-subtle);
  font-size: 0.75rem;
  font-style: italic;
}

.builder-tile {
  position: relative;
  padding: 0.35rem 1.6rem 0.35rem 0.55rem;   /* right pad reserved for × */
  background: #eaf4fb;
  border: 1px solid #3498db;
  border-radius: 6px;
  font-size: 0.78rem;
  font-weight: 600;
  color: #2c3e50;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  cursor: grab;
  user-select: none;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}

.builder-tile:hover {
  box-shadow: 0 2px 6px rgba(52, 152, 219, 0.2);
  transform: translateY(-1px);
}

.builder-tile:active {
  cursor: grabbing;
  transform: none;
}

.builder-tile__title {
  line-height: 1.15;
}

.builder-tile__meta {
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--text-muted);
}

/* Compact × pinned to the right so it never overlaps the body copy. */
.builder-tile__remove {
  position: absolute;
  top: 50%;
  right: 3px;
  transform: translateY(-50%);
  width: 1.25rem;
  height: 1.25rem;
  padding: 0;
  border: none;
  background: rgba(0,0,0,0.06);
  color: var(--text-muted);
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.builder-tile__remove:hover {
  background: #e74c3c;
  color: #fff;
}

/* Editing state — takes over the whole cell width visually. */
.builder-tile--editing {
  cursor: default;
  padding: 0.5rem;
  background: var(--surface);
  border: 2px solid #f39c12;
  gap: 0.4rem;
}

.builder-tile--editing:active { cursor: default; }

.builder-tile__fields {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 0.3rem;
}

.builder-tile__field {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.builder-tile__field input {
  padding: 0.25rem 0.35rem;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  text-transform: none;
  letter-spacing: normal;
  min-width: 0;         /* prevent 3-col grid overflow on narrow screens */
}

.builder-tile__actions {
  display: flex;
  gap: 0.3rem;
  justify-content: flex-end;
}

.builder-tile__actions button {
  padding: 0.25rem 0.7rem;
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 4px;
  border: none;
  cursor: pointer;
}

.builder-tile__save {
  background: #27ae60;
  color: #fff;
}

.builder-tile__cancel {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border) !important;
}

/* SortableJS drag helpers — ghost = placeholder in the source, chosen = tile
   under the pointer while dragging. */
.builder-tile.sortable-ghost,
.builder-library__tile.sortable-ghost {
  opacity: 0.35;
}

.builder-tile.sortable-chosen,
.builder-library__tile.sortable-chosen {
  box-shadow: 0 4px 10px rgba(0,0,0,0.15);
}

/* Drop target highlight while a drag is over it. Sortable adds a
   generic class we can target. */
.builder-grid__cell.sortable-drag-hover,
.builder-grid__cell.sortable-drag {
  background: rgba(52, 152, 219, 0.08);
  border-color: #3498db;
}

/* ── Exercise library ────────────────────────────────────── */
.builder-library {
  background: var(--surface);
  border-radius: 12px;
  padding: 1rem;
  margin-bottom: 1rem;
  color: var(--text);
}

.builder-library__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.builder-library__header h3 {
  margin: 0;
  font-size: 1rem;
}

.builder-library__manage {
  font-size: 0.85rem;
  color: var(--text-muted);
  text-decoration: none;
}

.builder-library__manage:hover {
  color: var(--text);
  text-decoration: underline;
}

.builder-library__header-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.builder-library__new-btn {
  padding: 0.35rem 0.75rem;
  background: transparent;
  color: var(--text);
  border: 1px dashed var(--border-strong);
  border-radius: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
}

.builder-library__new-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Inline "add new exercise" form. */
.builder-new-exercise {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.75rem;
  margin-bottom: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.builder-new-exercise[hidden] {
  display: none;
}

.builder-new-exercise__row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.builder-new-exercise__col {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  flex: 1;
  min-width: 5rem;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.builder-new-exercise__col--name { flex: 3; min-width: 12rem; }

.builder-new-exercise__col input,
.builder-new-exercise__col select {
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text);
  background: var(--surface);
  text-transform: none;
  letter-spacing: normal;
}

.builder-new-exercise__actions {
  display: flex;
  gap: 0.4rem;
  justify-content: flex-end;
}

.builder-new-exercise__save {
  padding: 0.35rem 0.9rem;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.builder-new-exercise__cancel {
  padding: 0.35rem 0.9rem;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.builder-new-exercise__error {
  padding: 0.4rem 0.7rem;
  background: rgba(231, 76, 60, 0.15);
  border: 1px solid #e74c3c;
  border-radius: 4px;
  color: var(--text);
  font-size: 0.85rem;
}

.builder-new-exercise__error[hidden] { display: none; }

.builder-library__groups {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.builder-library__group {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
  background: var(--surface-alt);
}

.builder-library__group summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--text);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.builder-library__group summary::-webkit-details-marker { display: none; }

.builder-library__group summary::before {
  content: "▸";
  font-size: 0.75rem;
  color: var(--text-muted);
  transition: transform 0.15s ease;
}

.builder-library__group[open] summary::before {
  transform: rotate(90deg);
}

.builder-library__count {
  color: var(--text-muted);
  font-weight: 400;
  font-size: 0.8rem;
}

.builder-library__tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.6rem;
}

.builder-library__tile {
  padding: 0.35rem 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text);
  cursor: grab;                    /* hint DnD coming in Phase 4 */
  user-select: none;
}

.builder-library__tile:hover {
  border-color: #3498db;
  color: #3498db;
}

.builder-library__tile:active {
  cursor: grabbing;
}

/* ── Protocols ─────────────────────────────────────────── */
.builder-protocols {
  background: var(--surface);
  border-radius: 12px;
  padding: 1rem;
  margin-bottom: 1rem;
  color: var(--text);
}

.builder-protocols__header {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.builder-protocols__header h3 {
  margin: 0;
  font-size: 1rem;
}

.builder-protocols__hint {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-style: italic;
}

.builder-protocols__groups {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.builder-protocols__group {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
  background: var(--surface-alt);
}

.builder-protocols__group summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--text);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.builder-protocols__group summary::-webkit-details-marker { display: none; }

.builder-protocols__group summary::before {
  content: "▸";
  font-size: 0.75rem;
  color: var(--text-muted);
  transition: transform 0.15s ease;
}

.builder-protocols__group[open] summary::before {
  transform: rotate(90deg);
}

.builder-protocols__count {
  color: var(--text-muted);
  font-weight: 400;
  font-size: 0.8rem;
}

.builder-protocols__tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.6rem;
}

.builder-protocols__tile {
  padding: 0.35rem 0.75rem;
  background: rgba(155, 89, 182, 0.08);
  border: 1px solid #9b59b6;
  border-radius: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text);
  cursor: grab;
  user-select: none;
}

.builder-protocols__tile:hover {
  background: rgba(155, 89, 182, 0.16);
}

.builder-protocols__tile:active {
  cursor: grabbing;
}

/* Highlight when held (matches library tile-held style but purple). */
.builder-protocols__tile.builder-library__tile--held {
  background: #f39c12;
  border-color: #f39c12;
  color: #fff;
  box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.25);
}

/* ── Groupings ─────────────────────────────────────────── */
.builder-groups {
  background: var(--surface);
  border-radius: 12px;
  padding: 1rem;
  margin-bottom: 1rem;
  color: var(--text);
}

.builder-groups__header {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.builder-groups__header h3 {
  margin: 0;
  font-size: 1rem;
}

.builder-groups__hint {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-style: italic;
}

.builder-groups__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  min-height: 1rem;                /* small so Sortable has something to hover */
  margin-bottom: 0.75rem;
}

/* Group tile — a single, larger tile representing multiple exercises. */
.builder-group-tile {
  position: relative;
  padding: 0.55rem 2rem 0.55rem 0.75rem;
  background: rgba(155, 89, 182, 0.12);   /* purple to distinguish from library/tiles */
  border: 1px solid #9b59b6;
  border-radius: 8px;
  color: var(--text);
  cursor: grab;
  user-select: none;
  min-width: 8rem;
}

.builder-group-tile:active { cursor: grabbing; }

.builder-group-tile__name {
  font-weight: 600;
  font-size: 0.85rem;
  line-height: 1.15;
}

.builder-group-tile__count {
  font-size: 0.7rem;
  color: var(--text-muted);
}

.builder-group-tile__remove {
  position: absolute;
  top: 50%;
  right: 3px;
  transform: translateY(-50%);
  width: 1.25rem;
  height: 1.25rem;
  padding: 0;
  border: none;
  background: rgba(0,0,0,0.06);
  color: var(--text-muted);
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.builder-group-tile__remove:hover {
  background: #e74c3c;
  color: #fff;
}

.builder-group-tile--held {
  background: #f39c12;
  border-color: #f39c12;
  color: #fff;
  box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.25);
}

.builder-group-tile--held .builder-group-tile__count {
  color: rgba(255,255,255,0.85);
}

/* + New grouping button */
.builder-groups__new {
  padding: 0.4rem 0.8rem;
  background: transparent;
  color: var(--text);
  border: 1px dashed var(--border-strong);
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.builder-groups__new:hover {
  border-color: #9b59b6;
  color: #9b59b6;
}

/* Draft form */
.builder-group-draft {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.75rem;
  margin-bottom: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.builder-group-draft__name {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.builder-group-draft__name input {
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text);
  background: var(--surface);
  text-transform: none;
  letter-spacing: normal;
}

.builder-group-draft__label {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.builder-group-draft__zone {
  min-height: 3rem;
  padding: 0.5rem;
  background: var(--surface);
  border: 2px dashed var(--border-strong);
  border-radius: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}

.builder-group-draft__zone--empty {
  justify-content: center;
}

.builder-group-draft__empty-hint {
  color: var(--text-subtle);
  font-style: italic;
  font-size: 0.85rem;
}

.builder-group-draft__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.4rem 0.25rem 0.6rem;
  background: rgba(155, 89, 182, 0.1);
  border: 1px solid #9b59b6;
  border-radius: 999px;
  font-size: 0.8rem;
  color: var(--text);
}

.builder-group-draft__chip-remove {
  width: 1.05rem;
  height: 1.05rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  border-radius: 999px;
}

.builder-group-draft__chip-remove:hover {
  background: #e74c3c;
  color: #fff;
}

.builder-group-draft__actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.4rem;
}

.builder-group-draft__save {
  padding: 0.35rem 0.9rem;
  background: #9b59b6;
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.builder-group-draft__cancel {
  padding: 0.35rem 0.9rem;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

/* Highlighted state when the tile is "held" for click-and-paste. */
.builder-library__tile--held {
  background: #f39c12;
  border-color: #f39c12;
  color: #fff;
  box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.25);
}

.builder-library__tile--held:hover {
  color: #fff;
  border-color: #f39c12;
}

/* Sticky banner shown while a tile is held. */
.builder-hold-banner {
  position: sticky;
  top: 0.5rem;
  z-index: 5;
  background: #f39c12;
  color: #fff;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
  box-shadow: 0 4px 10px rgba(0,0,0,0.15);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

/* `display: flex` above beats the `hidden` attribute's default,
   so make hidden explicit. */
.builder-hold-banner[hidden] {
  display: none;
}

/* Top-of-grid toolbar (undo + swap chooser). */
.builder-toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.builder-undo {
  padding: 0.35rem 0.85rem;
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
}

.builder-undo:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}

.builder-undo:disabled {
  opacity: 0.4;
  cursor: default;
}

/* Swap-days toolbar — appears above the grid when day columns are selected. */
.builder-swap-tools {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding: 0.4rem 0.8rem;
  margin-bottom: 0.5rem;
  background: rgba(52, 152, 219, 0.1);
  border: 1px solid #3498db;
  border-radius: 8px;
  font-size: 0.85rem;
  color: var(--text);
}

.builder-swap-tools[hidden] {
  display: none;
}

.builder-swap-tools__label {
  color: var(--text-muted);
}

.builder-swap-tools__hint {
  color: var(--text-muted);
  font-style: italic;
  font-size: 0.8rem;
}

.builder-swap-tools__swap {
  padding: 0.3rem 0.9rem;
  background: #3498db;
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.builder-swap-tools__delete {
  padding: 0.3rem 0.9rem;
  background: var(--danger);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.builder-swap-tools__delete:hover {
  filter: brightness(1.08);
}

.builder-swap-tools__clear {
  padding: 0.3rem 0.7rem;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.8rem;
  cursor: pointer;
  margin-left: auto;
}

.builder-hold-banner__clear {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255,255,255,0.25);
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}

.builder-hold-banner__clear:hover {
  background: rgba(255,255,255,0.45);
}

.builder-hold-banner kbd {
  background: rgba(255,255,255,0.25);
  padding: 0.05rem 0.4rem;
  border-radius: 4px;
  font-family: inherit;
  font-size: 0.8rem;
}

/* While holding, cells hint that they're click-to-drop targets. */
.builder--holding .builder-grid__cell {
  cursor: copy;
  border-color: #f39c12;
  background: rgba(243, 156, 18, 0.06);
}

.builder--holding .builder-grid__cell:hover {
  background: rgba(243, 156, 18, 0.16);
}

/* ============================================================
   Training-cycle overview (show page)
   ============================================================ */

.cycle-header {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.25rem;
  box-shadow: var(--shadow);
  color: var(--text);
}

.cycle-header__top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.cycle-header__title {
  margin: 0 0 0.25rem 0;
  font-size: 1.5rem;
  line-height: 1.15;
}

.cycle-header__dates {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.cycle-header__badges {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.cycle-header__edit {
  padding: 0.35rem 0.9rem;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  text-decoration: none;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 600;
}

.cycle-header__edit:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.cycle-badge {
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.cycle-badge--active    { background: var(--success); color: #fff; }
.cycle-badge--upcoming  { background: var(--accent);  color: #fff; }
.cycle-badge--completed { background: var(--text-subtle); color: #fff; }

/* Progress bar */
.cycle-progress__bar {
  height: 8px;
  background: var(--surface-alt);
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: 0.5rem;
}

.cycle-progress__fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--success));
  border-radius: 999px;
  transition: width 0.4s ease;
}

.cycle-progress__stats {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  font-size: 0.9rem;
  color: var(--text-muted);
}

.cycle-progress__stats strong {
  color: var(--text);
}

.cycle-progress__compliance {
  color: var(--success);
  font-weight: 600;
}

.cycle-header__today {
  display: inline-block;
  margin-top: 0.85rem;
  padding: 0.5rem 1rem;
  background: var(--accent);
  color: #fff;
  border-radius: 8px;
  text-decoration: none;
  font-weight: 600;
  font-size: 0.9rem;
}

.cycle-header__today:hover {
  background: var(--accent-hover);
}

/* ── Cards (goals, etc.) ────────────────────────────────── */
.cycle-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.25rem;
  color: var(--text);
  box-shadow: var(--shadow);
}

.cycle-card__title {
  margin: 0 0 1rem 0;
  font-size: 1.05rem;
}

.cycle-goals {
  padding-left: 1.25rem;
  margin: 0 0 1rem 0;
}

.cycle-goals li {
  margin-bottom: 0.4rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.cycle-empty {
  color: var(--text-muted);
  margin: 0;
}

.cycle-add-goal summary {
  cursor: pointer;
  display: inline-block;
  padding: 0.5rem 0.85rem;
  background: var(--accent);
  color: #fff;
  border-radius: 6px;
  list-style: none;
  font-size: 0.9rem;
  font-weight: 600;
}

.cycle-add-goal summary::-webkit-details-marker { display: none; }

.cycle-add-goal__form { margin-top: 0.75rem; }

.cycle-add-goal__row {
  display: flex;
  gap: 0.5rem;
  align-items: flex-end;
  flex-wrap: wrap;
}

.cycle-add-goal__col { display: flex; flex-direction: column; gap: 0.2rem; }
.cycle-add-goal__col--wide { flex: 4; min-width: 12rem; }
.cycle-add-goal__col       { flex: 1; min-width: 6rem;  }

.cycle-add-goal__col input {
  padding: 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
}

/* ── Week groups ────────────────────────────────────────── */
.cycle-weeks {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.cycle-week {
  background: var(--surface);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
}

.cycle-week__header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1.25rem;
  cursor: pointer;
  color: var(--text);
  background: var(--surface);
  list-style: none;
  border-bottom: 1px solid transparent;
}

.cycle-week__header::-webkit-details-marker { display: none; }

.cycle-week__header::before {
  content: "▸";
  color: var(--text-muted);
  font-size: 0.8rem;
  transition: transform 0.15s ease;
}

.cycle-week[open] .cycle-week__header::before {
  transform: rotate(90deg);
}

.cycle-week[open] .cycle-week__header {
  border-bottom-color: var(--border);
}

.cycle-week__header--active {
  background: linear-gradient(90deg, rgba(37, 99, 235, 0.12), transparent 60%);
}

.cycle-week__num {
  font-weight: 700;
  font-size: 1rem;
}

.cycle-week__dates {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.cycle-week__summary {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 500;
}

.cycle-week__avg {
  color: var(--success);
  font-weight: 700;
}

.cycle-week__body {
  overflow-x: auto;
}

/* ── Table ──────────────────────────────────────────────── */
.cycle-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  color: var(--text);
}

.cycle-table th {
  padding: 0.6rem 0.75rem;
  text-align: left;
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
}

.cycle-table td {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.cycle-table__st      { width: 2rem; text-align: center; }
.cycle-table__date    { width: 6rem;  font-weight: 600; white-space: nowrap; }
.cycle-table__actions { width: 3rem;  text-align: right; white-space: nowrap; }

.cycle-table__col--warmup { border-left: 3px solid #f39c12; }
.cycle-table__col--on     { border-left: 3px solid #3498db; }
.cycle-table__col--off    { border-left: 3px solid #9b59b6; }
.cycle-table__col--body   { border-left: 3px solid #16a34a; }

/* Row status states */
.cycle-row--all_done td { opacity: 0.6; }
.cycle-row--rest    td { color: var(--text-muted); }
.cycle-row--today {
  background: rgba(37, 99, 235, 0.06);
}
.cycle-row--today td:first-child {
  box-shadow: inset 3px 0 0 var(--accent);
}

.cycle-status {
  display: inline-block;
  min-width: 1rem;
  font-weight: 700;
  font-size: 0.9rem;
}

.cycle-status--done    { color: var(--success); }
.cycle-status--skipped { color: var(--text-subtle); }
.cycle-status--today   { color: var(--accent); }
.cycle-status--rest    { font-size: 0.85rem; }

.cycle-today-tag {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.05rem 0.4rem;
  background: var(--accent);
  color: #fff;
  border-radius: 4px;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  vertical-align: middle;
}

.cycle-rest {
  text-align: center;
  color: var(--text-muted);
  font-style: italic;
}

/* ── Activity summary chips inside a cell ───────────────── */
.cycle-activity {
  margin-bottom: 0.35rem;
}

.cycle-activity:last-child { margin-bottom: 0; }

.cycle-activity__title {
  font-weight: 600;
  line-height: 1.15;
}

.cycle-activity__check {
  color: var(--success);
  margin-right: 0.15rem;
}

.cycle-activity--done .cycle-activity__title {
  text-decoration: line-through;
  color: var(--text-muted);
}

.cycle-activity__meta {
  color: var(--text-muted);
  font-size: 0.75rem;
}

/* ============================================================
   Stats tab
   ============================================================ */

.stats-subtitle {
  margin: 0 0 1.5rem 0;
  color: var(--text-muted);
}

.stats-empty {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 2rem 1.5rem;
  text-align: center;
  color: var(--text-muted);
  box-shadow: var(--shadow);
}

.stats-empty p {
  margin: 0 0 1rem 0;
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  margin-bottom: 1rem;
}

.stats-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 1.5rem 1.25rem;
  text-align: center;
  color: var(--text);
  box-shadow: var(--shadow);
  border-top: 4px solid var(--accent);
}

.stats-card__label {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 0.5rem;
}

.stats-card__number {
  font-size: 2.75rem;
  font-weight: 800;
  line-height: 1;
  color: var(--text);
  margin-bottom: 0.35rem;
}

.stats-card__sub {
  font-size: 0.8rem;
  color: var(--text-muted);
}

/* Shared gym-filter chip (Stats + Tracking pages). */
.gym-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-sm);
}

.gym-filter__label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
  margin: 0;
}

.gym-filter__select {
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  max-width: 14rem;
}

.stats-section-label {
  margin: 1.5rem 0 0.75rem 0;
  font-size: 1rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
}

.stats-empty-row {
  margin: 0 0 0.5rem 0;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-style: italic;
  box-shadow: var(--shadow);
}

/* Stat card as a link — indicate clickability without changing the layout. */
.stats-card--link {
  text-decoration: none;
  color: inherit;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
  cursor: pointer;
}

.stats-card--link:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 14px rgba(15, 23, 42, 0.08);
  border-top-color: var(--success);
}

/* Pyramid row hover — subtle background shift so it's obviously clickable. */
.pyramid-row:hover {
  background: rgba(52, 152, 219, 0.06);
}

/* --- Climb tags: angle / hold type / style ---------------------------- */
.tag-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.25rem;
}

.tag-picker__option {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.9rem;
  cursor: pointer;
  user-select: none;
}

.tag-picker__option:has(:checked) {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.tag-picker__option input {
  margin: 0;
}

.climb-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-left: 0.35rem;
  vertical-align: middle;
}

.climb-tag {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--surface-alt);
  color: var(--text-muted);
  font-size: 0.75rem;
}

/* --- Auth screens: log in + sign up ----------------------------------- */
.auth {
  display: flex;
  justify-content: center;
  padding-block: 2rem;
}

.auth-card {
  width: 100%;
  max-width: 22rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 1.75rem 1.5rem;
  box-shadow: var(--shadow);
}

.auth-title {
  margin: 0 0 1.25rem;
  text-align: center;
  font-size: 1.5rem;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  /* Beat the legacy .sessions/.users form rules, which centre and pad again. */
  background: none;
  padding: 0;
  margin: 0;
  box-shadow: none;
  max-width: none;
}

.auth-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0;
}

.auth-field label {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
}

.auth-field input {
  width: 100%;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
}

/* The only checkbox row here; centred so it lines up under the fields. */
.auth-remember {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text-muted);
  cursor: pointer;
}

.auth-remember input {
  width: auto;
  margin: 0;
}

.auth-submit {
  width: 100%;
  margin: 0;
  padding: 0.7rem 1rem;
  font-size: 1rem;
  font-weight: 600;
}

/* Secondary action: smaller, quieter, and always under the primary one. */
.auth-alt {
  margin: 1.25rem 0 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.auth-alt__link {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}

.auth-alt__link:hover {
  text-decoration: underline;
}

.auth-errors {
  margin-bottom: 1rem;
  padding: 0.6rem 0.8rem;
  border: 1px solid #e74c3c;
  border-radius: 8px;
  background: rgba(231, 76, 60, 0.12);
  font-size: 0.85rem;
}

.auth-errors ul {
  margin: 0;
  padding-left: 1.1rem;
}

/* --- Calendar month grid ---------------------------------------------- */
/* The month and the day drawer sat in a hard-coded two-column grid with no
   breakpoint, so on a phone each day cell was about 20px wide and effectively
   untappable. Stacking gives the grid the full width and puts the drawer
   directly under the day you tapped. */
.calendar-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  align-items: start;
}

@media (max-width: 900px) {
  .calendar-layout {
    grid-template-columns: 1fr;
  }
}

.calendar-dow,
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.calendar-dow {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 4px;
  text-align: center;
}

.calendar-day {
  display: block;
  min-height: 60px;
  padding: 0.4rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  /* Removes the 300ms tap delay some mobile browsers still apply. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(37, 99, 235, 0.2);
}

.calendar-day:active {
  background: var(--surface-alt);
}

.calendar-day--outside {
  opacity: 0.4;
}

.calendar-day--today {
  outline: 2px solid var(--accent);
}

.calendar-day__num {
  font-weight: 600;
  font-size: 0.85rem;
}

.calendar-day__marks {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin-top: 4px;
}

@media (max-width: 700px) {
  .calendar-dow,
  .calendar-grid {
    gap: 3px;
  }

  /* Still a comfortable tap target once the grid has the full width. */
  .calendar-day {
    min-height: 3rem;
    padding: 0.3rem 0.2rem;
  }

  .calendar-day__num {
    font-size: 0.8rem;
  }
}

/* --- Per-section add-exercise control --------------------------------- */
.task-column__head {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.7rem 0.85rem;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
  /* The card no longer clips, so the head rounds its own top corners. */
  border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0;
}

.task-column__head h2 {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}

/* One exercise per row, divided rather than floating in shared space. */
.task-planned {
  margin: 0;
  padding: 0 0.85rem 0.85rem;
  font-size: 0.85rem;
}

.task-planned .activity-planned {
  margin-top: 0;
  padding-top: 0.85rem;
}

.task-planned .activity-planned + .activity-planned {
  border-top: 1px solid var(--border);
}

/* Static, so the panel below measures against the header rather than this. */
.add-activity {
  position: static;
  flex: none;
}

/* A plus sign, not a sentence: the section it sits in already says what it
   adds, and the type is taken from that section. */
.add-activity__toggle {
  display: grid;
  place-items: center;
  width: 1.65rem;
  height: 1.65rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  list-style: none;
  user-select: none;
  touch-action: manipulation;
}

.add-activity__toggle::-webkit-details-marker {
  display: none;
}

.add-activity__toggle:hover {
  background: var(--surface-alt);
}

.add-activity[open] .add-activity__toggle {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
}

.add-activity__fields {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.5rem;
  padding: 0.6rem;
  /* Out of the header's flex row. In it, an open panel grew the row and the
     heading -- nowrap with an ellipsis -- collapsed to nothing while the +
     slid across to make space. */
  position: absolute;
  top: calc(100% + 0.3rem);
  left: 0.6rem;
  right: 0.6rem;
  z-index: 20;
  box-shadow: var(--shadow);
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-alt);
}

.add-activity__row {
  display: flex;
  gap: 0.4rem;
}

.add-activity__input {
  width: 100%;
  min-width: 0;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.9rem;
}

.add-activity__submit {
  width: 100%;
}

/* --- Style breakdown: one donut per group + send rates ----------------- */
/* Series colours are the first three categorical slots, validated against
   both surfaces for colour-vision separation. Identity is never colour alone:
   every slice is named in the legend beside it. */
.style-groups {
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .style-groups {
    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
  }
}

:root[data-theme="dark"] .style-groups {
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
}

.style-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem;
}

.style-group__title {
  margin: 0 0 0.85rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.style-group__empty {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.style-split {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.style-donut {
  flex: none;
  width: 6.5rem;
  height: 6.5rem;
  /* The ring starts at 12 o'clock and fills clockwise. */
  transform: rotate(-90deg);
}

.style-donut__track,
.style-donut__seg {
  fill: none;
  stroke-width: 13;
}

.style-donut__track {
  stroke: var(--surface-alt);
}

/* One colour per tag slot, keyed to the tag rather than to draw order, so
   the donut and the legend can never disagree about which colour is which. */
.style-donut__seg.style-series--1 { stroke: var(--series-1); }
.style-donut__seg.style-series--2 { stroke: var(--series-2); }
.style-donut__seg.style-series--3 { stroke: var(--series-3); }

.style-legend__swatch.style-series--1 { background: var(--series-1); }
.style-legend__swatch.style-series--2 { background: var(--series-2); }
.style-legend__swatch.style-series--3 { background: var(--series-3); }

/* Counter-rotates the label so the ring can start at the top. */
.style-donut__total {
  transform: rotate(90deg);
  transform-origin: 50% 50%;
  fill: var(--text);
  font-size: 19px;
  font-weight: 700;
}

.style-legend {
  flex: 1 1 11rem;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}

.style-legend__row {
  display: grid;
  grid-template-columns: 0.6rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 0.8rem;
}

.style-legend__row--none {
  opacity: 0.5;
}

.style-legend__swatch {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 3px;
  align-self: center;
}

.style-legend__name {
  color: var(--text);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.style-legend__share {
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Send rate sits on its own line so the share column stays aligned. */
.style-legend__rate {
  grid-column: 2 / -1;
  color: var(--text-muted);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.style-legend__count {
  color: var(--text-subtle);
}

/* --- Calendar: view switcher, week strip, day detail ------------------- */
.calendar-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.calendar-bar__title {
  margin: 0;
}

.calendar-views {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-alt);
}

.calendar-views__opt {
  padding: 0.3rem 0.85rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  touch-action: manipulation;
}

.calendar-views__opt--on {
  background: var(--accent);
  color: var(--text-on-accent);
}

/* Week: seven columns on a desktop, stacked rows once that would squeeze the
   text, which is the mistake the month grid made before. */
.calendar-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.5rem;
}

@media (max-width: 900px) {
  .calendar-week {
    grid-template-columns: 1fr;
  }
}

.calendar-week__day {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  min-height: 7rem;
  padding: 0.6rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
}

.calendar-week__day--today {
  outline: 2px solid var(--accent);
}

.calendar-week__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.4rem;
}

.calendar-week__date {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  color: var(--text);
  text-decoration: none;
}

.calendar-week__dow {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.calendar-week__num {
  font-size: 1.05rem;
  font-weight: 700;
}

.calendar-week__tag {
  font-size: 0.68rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  background: var(--text-muted);
  color: var(--surface);
}

.calendar-week__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.calendar-week__item {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  font-size: 0.78rem;
  line-height: 1.3;
}

.calendar-week__grade {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.calendar-week__check,
.calendar-week__sent {
  color: var(--text-muted);
}

/* Titles vary wildly in length; let them wrap rather than widen the column. */
.calendar-week__name {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--text-muted);
}

.calendar-week__item--activity .calendar-week__name {
  color: var(--text);
}

.calendar-week__empty {
  margin: 0;
  color: var(--text-subtle);
}

/* Day: one date, so nothing has to be abbreviated. */
.calendar-detail {
  padding: 1.25rem;
}

.calendar-detail__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.calendar-detail__title {
  margin: 0;
  font-size: 1.25rem;
}

.calendar-detail__section + .calendar-detail__section {
  margin-top: 1.5rem;
}

.calendar-detail__label {
  margin: 0 0 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.calendar-detail__quiet {
  margin: 0 0 0.5rem;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.calendar-detail__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.calendar-detail__row {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
}

.calendar-detail__check,
.calendar-detail__grade {
  flex: none;
  min-width: 2.25rem;
  font-weight: 700;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.calendar-detail__meta {
  font-size: 0.82rem;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

/* --- Attached media list on the climb form ---------------------------- */
.media-hint {
  margin: 0.4rem 0 0;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.media-existing {
  margin: 0.6rem 0 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.media-existing legend {
  padding: 0 0.35rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.media-existing__row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  font-size: 0.85rem;
  font-weight: 400;
  cursor: pointer;
}

.media-existing__row input {
  width: auto;
  margin: 0;
}

.media-existing__name {
  overflow-wrap: anywhere;
}

.media-existing__size {
  margin-left: auto;
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

.auth-intro {
  margin: -0.5rem 0 1rem;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-muted);
}

/* --- Grade entry: scale toggle + per-scale dropdown -------------------- */
.grade-scale {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.25rem 0 0.5rem;
}

.grade-scale__option {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
}

.grade-scale__option:has(:checked) {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
}

.grade-scale__option input {
  width: auto;
  margin: 0;
}

.grade-select {
  width: 100%;
}

/* Filters sit on one row and wrap together on a phone. */
.stats-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}


/* --- Timer: stopwatch + intervals ------------------------------------- */
.timer-mode {
  display: flex;
  gap: 0.5rem;
  margin: 1rem 0;
}

.timer-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: var(--shadow);
  padding: 1.5rem 1rem;
  text-align: center;
}

.timer-phase {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Tabular figures, so the digits do not shuffle sideways every tick. */
.timer-display {
  margin: 0.25rem 0;
  font-size: clamp(3rem, 18vw, 5rem);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.timer-display--work { color: var(--success); }
.timer-display--rest { color: var(--warning); }
.timer-display--done { color: var(--text-muted); }

.timer-round-chip {
  display: inline-block;
  margin: 0.25rem 0 0;
  padding: 0.2rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.8rem;
  color: var(--text);
}

.timer-total {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.timer-controls {
  display: flex;
  gap: 0.5rem;
  margin-top: 1rem;
}

.timer-controls button { flex: 1; }

.timer-settings {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1rem;
  padding: 1rem;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 12px;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.timer-settings input[type="number"] {
  width: 4.5rem;
  padding: 0.4rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
}

.timer-unit { margin-left: 0.2rem; }

.timer-sound {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  align-self: flex-end;
}

.timer-sound input { width: auto; }

.timer-note {
  margin-top: 0.75rem;
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* --- Add-a-gym fields ------------------------------------------------- */
/* Each caption belongs to the box under it, so it is tied to it rather than
   left to float on the page's 1.6 line-height. */
.gym-new__field {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.gym-new__label {
  /* The global label rule adds a bottom margin, which is what pushed the
     caption away from its box in the first place. */
  margin: 0;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* --- Signed-out home ---------------------------------------------------- */
/* One action, centred on the page. Signing up and signing in used to sit side
   by side as equal buttons, which asks a first-time visitor to choose between
   two things before they know what either is. */
/* This is the whole screen, not a block at the top of one. On a phone the
   signed-out header is hidden, so `main` is the entire shell and the hero
   fills it and centres in it -- which is what "bigger" actually meant; the
   type was never the problem, the empty three-quarters below it was. */
.home-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  min-height: 100%;
  max-width: 30rem;
  margin: 0 auto;
  padding-block: 2rem;
  text-align: center;
}

.home-hero__title {
  margin: 0;
  font-size: clamp(2.9rem, 11vw, 3.9rem);
  line-height: 1.08;
}

/* On the page itself the wordmark sits on --bg, not on the dark header, so it
   takes the page's own ink and the accent from the palette. */
.wordmark--hero {
  color: var(--text);
  font-weight: 800;
  letter-spacing: -0.03em;
}

.wordmark--hero .wordmark__accent {
  color: var(--accent);
}

.home-hero__tagline {
  margin: 0;
  font-size: 1.15rem;
  color: var(--text-muted);
}

.home-hero__cta {
  margin-top: 0.9rem;
  padding: 1rem 3rem;
  font-size: 1.12rem;
}

.home-hero__alt {
  margin: 0;
  font-size: 0.95rem;
  color: var(--text-muted);
}

/* --- Workout section rows ---------------------------------------------- */
/* These two were #555 and #666, which sit almost on top of the dark surface. */
.activity-planned__meta {
  color: var(--text-muted);
}

.activity-planned__note {
  color: var(--text-muted);
  font-size: 0.82rem;
}

/* Aligned with the exercise title rather than pinned to the row's very top,
   where the row padding left them floating over the divider above. */
.activity-planned__actions {
  position: absolute;
  top: 0.85rem;
  right: 0;
  display: flex;
  gap: 0.1rem;
}

.activity-actual {
  display: flex;
  gap: 0.35rem;
  margin-top: 0.45rem;
  margin-left: 1.5rem;
}

.activity-actual__field {
  width: 100%;
  min-width: 0;
  padding: 0.3rem 0.5rem;
  font-size: 0.8rem;
}

/* A completed exercise recedes; the strikethrough alone left it as loud as
   the work still to do. */
.activity-planned.is-completed .activity-actual {
  opacity: 0.6;
}

/* Removed, edited or added on the page but not yet saved (#134). */
.activity-planned__pending {
  display: block;
  font-size: 0.75rem;
  color: var(--text-muted);
  font-style: italic;
}

/* Only when shown: an author display rule beats the [hidden] attribute. */
.activity-planned__removed:not([hidden]) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  color: var(--text-muted);
}

.activity-planned__discard {
  position: absolute;
  top: 0.85rem;
  right: 0;
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.1rem 0.35rem;
}

.task-planned:not(:has(.activity-planned)) {
  padding-bottom: 0;
}

/* --- Workout day: date navigation --------------------------------------- */
.date-nav {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 1rem;
  /* A safety net for the narrowest phones: the row is sized to fit, but if it
     ever cannot, the plan link wraps to a second line rather than sliding off
     the right-hand edge where it cannot be seen or tapped. */
  flex-wrap: wrap;
}

/* Sized to fit four items across the narrowest phone in one row. */
.date-nav .button {
  white-space: nowrap;
  padding: 0.3rem 0.6rem;
  font-size: 0.8rem;
}

/* The ends of the plan. Dimmed and inert rather than removed, so the row does
   not change width as you step through the days. */
.date-nav__end {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}

.date-nav__plan {
  margin-left: auto;
  white-space: nowrap;
  font-size: 0.8rem;
}

/* --- Training plan on a phone ------------------------------------------- */
@media (max-width: 700px) {
  /* Week, dates and the tally were three columns fighting over 390px, and each
     one wrapped. The tally takes its own line instead. */
  .cycle-week__header {
    flex-wrap: wrap;
    gap: 0.3rem 0.6rem;
    padding: 0.7rem 0.9rem;
  }

  .cycle-week__summary {
    margin-left: 0;
    flex-basis: 100%;
  }

  /* The table is wider than a phone and scrolls on its own. Say so, rather
     than leaving it to be discovered. */
  .cycle-week__body {
    overscroll-behavior-x: contain;
  }
}

/* The running cycle, marked with the palette's own success colour rather than
   an inline #27ae60. */
.training-cycle-actions.is-active {
  border-left: 4px solid var(--success);
}
