/* ============================================================
   OneToRun Design System — Theme Tokens
   Light theme (default) + Dark theme
   Builds on Tailwind v4 @theme tokens, overrides at runtime.
   Must load AFTER tailwind.css in the layout.
   ============================================================ */

/* ============================================================
   LIGHT THEME (default via :root)
   ============================================================ */
:root {
  /* --- Brand --- */
  --color-brand: #e6c619;
  --color-brand-hover: #d4b515;
  --color-brand-light: rgba(230, 198, 25, 0.1);
  --color-brand-rgb: 230, 198, 25;

  /* --- Accent (indigo) --- */
  --color-accent: #4f46e5;
  --color-accent-hover: #4338ca;
  --color-accent-light: #eef2ff;
  --color-border-focus: #e6c619;

  /* --- Surfaces --- */
  --color-panel-main: #ffffff;
  --color-panel-dark: #0f172a;
  --color-panel-muted: #f4f6f9;
  --color-panel-elevated: #ffffff;

  /* --- Borders --- */
  --color-border-light: #e2e8f0;
  --color-border-strong: #cbd5e1;

  /* --- Scrollbars --- */
  color-scheme: light;
  --color-scrollbar-thumb: #cbd5e1;
  --color-scrollbar-thumb-hover: #94a3b8;

  /* --- Text --- */
  --color-txt-main: #0f172a;
  --color-txt-muted: #64748b;
  --color-txt-dim: #94a3b8;
  --color-txt-on-brand: #0f172a;
  /* Rest-day icon/accent: dark on light theme, light on dark theme */
  --color-rest: #334155;

  /* --- Shadows (light-specific) --- */
  --shadow-card:
    0 1px 3px 0 rgba(15, 23, 42, 0.05),
    0 1px 2px -1px rgba(15, 23, 42, 0.05);
  --shadow-elevated:
    0 4px 16px rgba(15, 23, 42, 0.08),
    0 1px 4px rgba(15, 23, 42, 0.04);
  --shadow-popover:
    0 8px 32px rgba(15, 23, 42, 0.12),
    0 2px 8px rgba(15, 23, 42, 0.06);

  /* --- Radii --- */
  --radius-form: 0.75rem;
  --radius-btn: 0.5rem;
  --radius-sm: 0.375rem;
  --radius-lg: 0.875rem;
  --radius-xl: 1rem;

  /* --- Typography scale --- */
  --fs-display: 1.5rem;
  --fs-sub: 1.125rem;
  --fs-body: 0.875rem;
  --fs-small: 0.75rem;
  --fs-micro: 0.6875rem;

  /* ========================================================== */
  /*  CALENDAR-SPECIFIC TOKENS                                  */
  /* ========================================================== */

  /* Day cells */
  --cal-cell-bg: transparent;
  --cal-cell-border: #e2e8f0;
  --cal-cell-hover-bg: #f1f5f9;
  --cal-cell-radius: 0.5rem;
  --cal-cell-height: 120px;

  /* Today */
  --cal-today-bg: #e2e8f0;
  --cal-today-dot-bg: #64748b;
  --cal-today-dot-text: #ffffff;
  --cal-today-ring: #cbd5e1;

  /* Day number */
  --cal-day-num-color: #0f172a;
  --cal-day-num-size: 0.75rem;
  --cal-day-num-weight: 600;

  /* Day-of-week header */
  --cal-dow-color: #64748b;
  --cal-dow-size: 0.6875rem;
  --cal-dow-weight: 600;
  --cal-dow-spacing: 0.05em;

  /* Add workout button */
  --cal-add-border: #cbd5e1;
  --cal-add-color: #64748b;
  --cal-add-hover-border: #94a3b8;
  --cal-add-hover-color: #334155;
  --cal-add-hover-bg: #f1f5f9;

  /* Phase/meso markers */
  --cal-phase-dot-size: 8px;
  --cal-phase-text-size: 0.6875rem;
  --cal-phase-text-color: #64748b;

  /* Weather forecast overlay inside day cells. Two accents only: amber for
     temperature, blue for everything about water. */
  --cal-weather-text: #475569;
  --cal-weather-icon: #64748b;
  --cal-weather-temp: #b45309;
  --cal-weather-water: #2563eb;
  --cal-weather-water-soft: rgba(37, 99, 235, 0.12);
  --cal-weather-bg: rgba(148, 163, 184, 0.12);
  --cal-weather-bg-hover: rgba(148, 163, 184, 0.2);
  --cal-weather-bg-strong: rgba(37, 99, 235, 0.12);

  /* Scrollable grid */
  --cal-grid-max-height: calc(100vh - 420px);
  --cal-grid-max-height-fullscreen: calc(100vh - 140px);

  /* ========================================================== */
  /*  WORKOUT CARD TOKENS                                       */
  /* ========================================================== */
  --wkt-bg: #ffffff;
  --wkt-border: #e2e8f0;
  --wkt-border-hover: #cbd5e1;
  --wkt-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
  --wkt-shadow-hover:
    0 4px 16px rgba(15, 23, 42, 0.1),
    0 1px 4px rgba(15, 23, 42, 0.04);
  --wkt-radius: 0.5rem;
  --wkt-text: #0f172a;
  --wkt-text-muted: #475569;
  --wkt-muted-bg: #f1f5f9;
  --wkt-accent-bar: 3px;
  --wkt-hover-translate-y: -2px;

  /* Zone bar background (actual distribution bars) */
  --color-bar-bg: #e8ecf2;

  /* Planned metrics badge */
  --wkt-planned-bg: #f1f5f9;
  --wkt-planned-text: #0f172a;
  --wkt-planned-border: transparent;
  --wkt-planned-radius: 0.25rem;

  /* Comment unread highlight (light theme: dark = txt-main) */
  --color-comment-unread: #0f172a;

  /* Actual metrics badge */
  --wkt-actual-bg: #dcfce7;
  --wkt-actual-border: #86efac;
  --wkt-actual-text: #15803d;

  /* Hamburger menu */
  --wkt-menu-bg: #ffffff;
  --wkt-menu-border: #e2e8f0;
  --wkt-menu-shadow:
    0 8px 32px rgba(15, 23, 42, 0.14),
    0 2px 8px rgba(15, 23, 42, 0.06);
  --wkt-menu-item-hover: #f1f5f9;
  --wkt-menu-divider: #e2e8f0;

  /* FIT download badge */
  --wkt-fit-bg: #2563eb;
  --wkt-fit-text: #ffffff;
  --wkt-fit-hover-bg: #1d4ed8;

  /* Hidden-from-athlete badge (eye-off on a colored circle) */
  --wkt-hidden-bg: #f59e0b;
  --wkt-hidden-text: #0f172a;

  /* Race card */
  --race-card-bg: #ffffff;
  --race-card-border: #e2e8f0;

  /* ========================================================== */
  /*  HEADER / NAV TOKENS                                       */
  /* ========================================================== */
  --nav-bg: #ffffff;
  --nav-border: #e2e8f0;
  --nav-link-color: #64748b;
  --nav-link-hover-color: #0f172a;
  --nav-link-hover-bg: #f4f6f9;
  --nav-link-active-bg: rgba(230, 198, 25, 0.1);
  --nav-link-active-color: #e6c619;

  /* Theme toggle */
  /* Nav active state — dark bg + gold text, high contrast */
  --nav-active-bg: #0f172a;
  --nav-active-text: #e6c619;

  --theme-toggle-bg: #f4f6f9;
  --theme-toggle-border: #e2e8f0;
  --theme-toggle-color: #64748b;
  --theme-toggle-hover-bg: #e2e8f0;
  --theme-toggle-hover-color: #0f172a;
  --theme-toggle-icon-sun: #e6c619;
  --theme-toggle-icon-moon: #64748b;

  /* ========================================================== */
  /*  MOBILE BOTTOM NAV (below `sm` — 40rem)                     */
  /* ========================================================== */
  --mobile-nav-bg: #0f172a;
  --mobile-nav-border: rgba(255, 255, 255, 0.08);
  --mobile-nav-text: #94a3b8;
  --mobile-nav-active: #e6c619;
  /* Calendar medallion — rest state uses the app's light surface,
     the active state lights it up in the brand gold */
  --mobile-nav-medallion-bg: #ffffff;
  --mobile-nav-medallion-border: rgba(15, 23, 42, 0.08);
  --mobile-nav-medallion-text: #64748b;
  --mobile-nav-medallion-shadow: 0 4px 14px rgba(15, 23, 42, 0.12);
  --mobile-nav-medallion-active-bg: #e6c619;
  --mobile-nav-medallion-active-text: #0f172a;
  --mobile-nav-medallion-active-shadow: 0 6px 18px rgba(230, 198, 25, 0.35);

  /* ========================================================== */
  /*  INFO BARS (macrocycle, focus)                              */
  /* ========================================================== */
  --info-bar-text: #64748b;
  --info-bar-accent: #e6c619;
  --info-bar-radius: 0.625rem;

  /* Focus mode */
  --focus-bar-bg: rgba(230, 198, 25, 0.08);
  --focus-bar-border: rgba(230, 198, 25, 0.2);

  /* Date picker icon — dark icon on light bg */
  --date-icon-filter: none;
}

/* ============================================================
   DARK THEME — applied via [data-theme="dark"] on <html>
   ============================================================ */
[data-theme="dark"] {
  /* --- Brand (brighter gold for dark) --- */
  --color-brand: #f5d742;
  --color-brand-hover: #e6c619;
  --color-brand-light: rgba(245, 215, 66, 0.12);
  --color-brand-rgb: 245, 215, 66;

  /* --- Accent --- */
  --color-accent: #818cf8;
  --color-accent-hover: #6366f1;
  --color-accent-light: rgba(129, 140, 248, 0.12);
  --color-border-focus: #f5d742;

  /* --- Surfaces --- */
  --color-panel-main: #0e1017;
  --color-panel-dark: #06070a;
  --color-panel-muted: #181b25;
  --color-panel-elevated: #202438;

  /* --- Borders --- */
  --color-border-light: #2a2e45;
  --color-border-strong: #3d4260;

  /* --- Scrollbars --- */
  color-scheme: dark;
  --color-scrollbar-thumb: #3d4260;
  --color-scrollbar-thumb-hover: #52597e;

  /* --- Text --- */
  --color-txt-main: #f1f5f9;
  --color-txt-muted: #94a3b8;
  --color-txt-dim: #64748b;
  --color-txt-on-brand: #0f172a;
  /* Rest-day icon/accent: dark on light theme, light on dark theme */
  --color-rest: #e2e8f0;

  /* --- Shadows (dark — deeper, cooler) --- */
  --shadow-card:
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 1px 1px rgba(0, 0, 0, 0.2);
  --shadow-elevated:
    0 4px 16px rgba(0, 0, 0, 0.4),
    0 1px 4px rgba(0, 0, 0, 0.2);
  --shadow-popover:
    0 8px 32px rgba(0, 0, 0, 0.6),
    0 2px 8px rgba(0, 0, 0, 0.3);

  /* ========================================================== */
  /*  CALENDAR (dark)                                            */
  /* ========================================================== */
  --cal-cell-bg: transparent;
  --cal-cell-border: #2a2e45;
  --cal-cell-hover-bg: #1e293b;
  --cal-today-bg: #334155;
  --cal-today-dot-bg: #94a3b8;
  --cal-today-dot-text: #0f172a;
  --cal-today-ring: #475569;
  --cal-day-num-color: #f1f5f9;
  --cal-dow-color: #94a3b8;

  --cal-add-border: #475569;
  --cal-add-color: #94a3b8;
  --cal-add-hover-border: #cbd5e1;
  --cal-add-hover-color: #f1f5f9;
  --cal-add-hover-bg: #1e293b;

  /* Weather forecast overlay (see the light theme for what the tokens mean) */
  --cal-weather-text: #cbd5e1;
  --cal-weather-icon: #94a3b8;
  --cal-weather-temp: #fbbf24;
  --cal-weather-water: #60a5fa;
  --cal-weather-water-soft: rgba(96, 165, 250, 0.16);
  --cal-weather-bg: rgba(148, 163, 184, 0.1);
  --cal-weather-bg-hover: rgba(148, 163, 184, 0.18);
  --cal-weather-bg-strong: rgba(96, 165, 250, 0.14);

  /* ========================================================== */
  /*  WORKOUT CARD (dark)                                        */
  /* ========================================================== */
  --wkt-bg: #1a1d2e;
  --wkt-border: #2a2e45;
  --wkt-border-hover: #3d4260;
  --wkt-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  --wkt-shadow-hover:
    0 4px 16px rgba(0, 0, 0, 0.5),
    0 1px 4px rgba(0, 0, 0, 0.2);
  --wkt-text: #f1f5f9;
  --wkt-text-muted: #94a3b8;
  --wkt-muted-bg: #202438;

  --wkt-planned-bg: #202438;
  --wkt-planned-text: #f1f5f9;
  --wkt-planned-border: transparent;

  /* Comment unread highlight (dark theme: brand yellow) */
  --color-comment-unread: var(--color-brand);

  --color-bar-bg: #2a2e48;

  --wkt-actual-bg: rgba(5, 150, 105, 0.18);
  --wkt-actual-border: rgba(5, 150, 105, 0.45);
  --wkt-actual-text: #34d399;

  --wkt-menu-bg: #202438;
  --wkt-menu-border: #2a2e45;
  --wkt-menu-shadow:
    0 8px 32px rgba(0, 0, 0, 0.6),
    0 2px 8px rgba(0, 0, 0, 0.3);
  --wkt-menu-item-hover: #2a2e45;
  --wkt-menu-divider: #2a2e45;

  --wkt-fit-bg: #3b82f6;
  --wkt-fit-text: #ffffff;
  --wkt-fit-hover-bg: #2563eb;

  /* Hidden-from-athlete badge (eye-off on a colored circle) */
  --wkt-hidden-bg: #f59e0b;
  --wkt-hidden-text: #0f172a;

  --race-card-bg: #1a1d2e;
  --race-card-border: #2a2e45;

  /* ========================================================== */
  /*  HEADER / NAV (dark)                                        */
  /* ========================================================== */
  --nav-bg: #0e1017;
  --nav-border: #2a2e45;
  --nav-link-color: #94a3b8;
  --nav-link-hover-color: #f1f5f9;
  --nav-link-hover-bg: #181b25;
  --nav-link-active-bg: rgba(245, 215, 66, 0.1);
  --nav-link-active-color: #f5d742;

  /* Nav active state — subtle gold tint bg + gold text, distinct from header */
  --nav-active-bg: rgba(245, 215, 66, 0.1);
  --nav-active-text: #f5d742;

  --theme-toggle-bg: #181b25;
  --theme-toggle-border: #2a2e45;
  --theme-toggle-color: #94a3b8;
  --theme-toggle-hover-bg: #202438;
  --theme-toggle-hover-color: #f1f5f9;
  --theme-toggle-icon-sun: #94a3b8;
  --theme-toggle-icon-moon: #f5d742;

  /* ========================================================== */
  /*  MOBILE BOTTOM NAV (dark)                                   */
  /* ========================================================== */
  --mobile-nav-bg: #181b25;
  --mobile-nav-border: #2a2e45;
  --mobile-nav-text: #94a3b8;
  --mobile-nav-active: #f5d742;
  /* Calendar medallion — rest state uses the app's elevated dark
     surface, the active state lights it up in the brand gold */
  --mobile-nav-medallion-bg: #202438;
  --mobile-nav-medallion-border: #2a2e45;
  --mobile-nav-medallion-text: #94a3b8;
  --mobile-nav-medallion-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  --mobile-nav-medallion-active-bg: #f5d742;
  --mobile-nav-medallion-active-text: #0f172a;
  --mobile-nav-medallion-active-shadow: 0 6px 18px rgba(245, 215, 66, 0.35);

  /* ========================================================== */
  /*  INFO BARS (dark)                                           */
  /* ========================================================== */
  --info-bar-text: #94a3b8;
  --info-bar-accent: #f5d742;

  --focus-bar-bg: rgba(245, 215, 66, 0.1);
  --focus-bar-border: rgba(245, 215, 66, 0.25);

  /* Date picker icon — invert to white for dark bg */
  --date-icon-filter: invert(1) brightness(1.5);
}

/* ============================================================
   DARK THEME — HTML element background/text base
   ============================================================ */
[data-theme="dark"] body {
  background-color: var(--color-panel-main);
  color: var(--color-txt-main);
}

/* Smooth transition for theme changes — scoped to theme-switchable properties */
html[data-theme] *,
html[data-theme] *::before,
html[data-theme] *::after {
  transition: background-color 0.2s ease, border-color 0.2s ease,
    color 0.2s ease, box-shadow 0.2s ease;
}
@media (prefers-reduced-motion: reduce) {
  html[data-theme] *,
  html[data-theme] *::before,
  html[data-theme] *::after {
    transition: none;
  }
}

/* ============================================================
   CALENDAR COMPONENT STYLES
   Uses theme tokens above — no hardcoded colors in the templates.
   ============================================================ */

/* --- Calendar navigation --- */
.cal-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem 0.5rem;
  font-size: var(--fs-small);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
  color: var(--color-txt-muted);
  cursor: pointer;
  text-decoration: none;
  line-height: 1.4;
  transition: all 0.15s ease;
}
.cal-nav-btn:hover {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
  border-color: var(--color-border-light);
}

/* View toggle pills */
.cal-view-toggle {
  display: inline-flex;
  gap: 1px;
  padding: 2px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
}
.cal-view-link {
  padding: 0.25rem 0.75rem;
  font-size: var(--fs-small);
  border-radius: calc(var(--radius-btn) - 2px);
  text-decoration: none;
  color: var(--color-txt-muted);
  font-weight: 500;
  transition: all 0.15s ease;
}
.cal-view-link:hover {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}
.cal-view-link.active {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
  font-weight: 600;
}

/* --- Fullscreen toggle: hidden on phones ---
   Plain CSS (not a Tailwind utility) so it takes effect without a rebuild.
   `max-width: 40rem` hides at exactly 640px and below, matching the sm
   breakpoint boundary. The button stays in the markup and is shown again
   on larger screens (tablet toolbar / desktop bar). */
@media (max-width: 40rem) {
  [data-fullscreen-btn] {
    display: none;
  }
}

/* --- Merged-workout form: on phones keep only the Planned / Performed
   tabs — the "Planned + Actual" (split) view is cramped on small screens.
   Plain CSS, matching the sm breakpoint boundary (<= 40rem / 640px). --- */
@media (max-width: 40rem) {
  .view-mode-split {
    display: none;
  }
}

/* --- Workout view/edit modal on phones: full-bleed card ---
   Overrides the inline width:768px (planned view), the Tailwind max-w-* /
   mx-4 and the application.css calc(100% - 2rem) near-full-width rule so
   the modal spans the whole device width edge to edge. The Actual stats,
   Segment Breakdown, Stream Graphs and Structure blocks stretch to the
   full card width like the surrounding blocks. --- */
@media (max-width: 40rem) {
  .wkt-modal-wrapper > .bg-panel-main {
    width: 100% !important;
    max-width: none !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    border-radius: 0;
  }
  /* Performed tab: spread the actual distance / time / pace stats across
     the block instead of a narrow centered cluster. */
  .wkt-actual-stats {
    justify-content: space-evenly;
    gap: 0.5rem;
  }
  /* Performed + planned tabs: pin these shared chart blocks to the full
     card width (their chart CSS is loaded separately). */
  .segment-breakdown__chart,
  .stream-chart__canvas-wrapper,
  [data-activities-workout-blocks-target="visualization"] {
    width: 100%;
  }

  /* All inner blocks: the 24px card padding (p-6), the 16px block paddings
     and the wide value gaps leave little room for the data on phones.
     Shrink the horizontal spacing so every block stretches closer to the
     modal borders and the metrics get more width. */
  .wkt-modal-wrapper > .bg-panel-main {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }
  .wkt-modal-wrapper .p-4 {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }
  .wkt-modal-wrapper .p-3 {
    padding-left: 0.625rem;
    padding-right: 0.625rem;
  }
  .wkt-modal-wrapper .px-2\.5 {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  .wkt-modal-wrapper .gap-x-8 {
    column-gap: 0.75rem;
  }
  .wkt-modal-wrapper .mb-4 {
    margin-bottom: 0.75rem;
  }

  /* Duration (Длительность): on phones widen the planned-view field and
     keep the digit inputs wide enough for two digits. The strength workout
     keeps its compact row layout (label + clock on one line) — the
     strength-duration rules at the bottom of this file shrink the clock on
     phones instead of stacking the label above it. */
  .wkt-modal-wrapper [data-wk-metric="duration"] {
    width: 100%;
    max-width: 150px;
  }
  .wkt-modal-wrapper [data-wk-metric="duration"] > div {
    width: auto;
    flex-shrink: 0;
  }
  .wkt-modal-wrapper [data-wk-metric="duration"] input[data-wk-dur] {
    width: 2.25rem;
    min-width: 2.25rem;
  }
}

/* ── Form header: the way out of a workout / race form ──
   The header carries the exit on every viewport: a back chevron that returns to
   the calendar (workout form) or closes the modal (race form). It replaced the
   ✕ outright, so the comments button is the right-most control on desktop and on
   phones alike; on phones the header is also the fixed half of the sheet (see the
   media query below). */
.wkt-form-header {
  /* Space between the exit and what follows it — the name of a performed
     activity, or the actions pinned to the right edge. */
  gap: 0.75rem;
}

.wkt-form-actions {
  /* The row holds one control today (the comments button, or the change-sport
     link on a fresh workout). The gap is set here rather than in the markup so
     a second control inherits it on every viewport. */
  gap: 0.5rem;
}

/* The exit itself: a grey disc in both themes, with the chevron in the theme's
   own ink — near-black on the light theme, the brand's yellow on the dark one.
   Both pairs clear 9:1, and the disc keeps the control visible without a brand
   fill that would shout over the form it leaves. */
.wkt-form-back {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 2.125rem;
  height: 2.125rem;
  padding: 0;
  border: 0;
  border-radius: 9999px;
  background: var(--color-border-light);
  color: var(--color-txt-main);
  cursor: pointer;
  text-decoration: none;
  transition: background-color 0.15s ease;
}

[data-theme="dark"] .wkt-form-back {
  color: var(--color-brand);
}

.wkt-form-back svg {
  width: 1.375rem;
  height: 1.375rem;
}

.wkt-form-back:hover,
.wkt-form-back:active {
  background: var(--color-border-strong);
}

.wkt-form-back:focus-visible {
  /* The ink, not --color-border-focus: that token is the brand gold, and gold on
     a light grey disc (about 1.4:1) is no focus ring at all. */
  outline: 2px solid var(--color-txt-main);
  outline-offset: 2px;
}

@media (max-width: 40rem) {
  /* The sheet: a column whose second half scrolls. The card hands its top
     padding to the bar, so the bar sits flush with the top edge. */
  .wkt-modal-wrapper > .bg-panel-main {
    display: flex;
    flex-direction: column;
    padding-top: 0;
  }

  /* min-height: 0 on every link of the chain: without it the scroller refuses to
     shrink and the card scrolls as well, which is the double scrollbar. */
  .wkt-form-body:not(.hidden) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
  }

  .wkt-form-header {
    flex: 0 0 auto;
    margin-left: -0.75rem;
    margin-right: -0.75rem;
    /* A phone bar, not a desktop header: the padding only separates the row from
       the content sliding under it. Half a rem top and bottom keeps the fixed bar
       a touch taller than its own controls. */
    padding: 0.5rem 0.75rem;
    background: var(--color-panel-main);
    border-bottom: 1px solid var(--color-border-light);
  }

  .wkt-form-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
  }

  /* The comments button shares the bar with the exit: on a phone the glyph comes
     down to the bar's height, but not to a speck — 30px against the exit's 34px
     box keeps the two controls the same height. The desktop header keeps the
     36px icon and its padding. */
  .wkt-form-comments {
    padding: 0.125rem;
  }

  .wkt-form-comments svg {
    width: 1.875rem;
    height: 1.875rem;
  }
}

/* --- The workout sheet owns the phone screen ---
   The card already filled the device width, but the backdrop's py-4, the
   wrapper's inline 1rem margins and the card's inline max-height:90vh still
   left a strip of calendar above and below it. On phones the sheet runs edge to
   edge in both axes: the fixed form bar sits at the top, the body scrolls
   underneath it, and nothing of the calendar shows through. The marker class
   keeps the other modals that share turbo-frame#modal untouched.
   !important beats the inline margins / max-height the two forms set. --- */
@media (max-width: 40rem) {
  .wkt-modal-backdrop {
    padding-top: 0;
    padding-bottom: 0;
    align-items: stretch;
  }

  .wkt-modal-wrapper {
    height: 100%;
    margin-top: 0 !important;
    margin-bottom: 0 !important;
  }

  .wkt-modal-wrapper > .bg-panel-main {
    height: 100% !important;
    max-height: none !important;
    border: 0;
  }
}

/* --- Day-of-week header --- */
.cal-dow {
  padding-bottom: 0.5rem;
  font-size: var(--cal-dow-size);
  font-weight: var(--cal-dow-weight);
  letter-spacing: var(--cal-dow-spacing);
  text-transform: uppercase;
  color: var(--cal-dow-color);
  text-align: center;
}

/* --- Day cell --- */
.cal-cell {
  padding: 0.25rem;
  vertical-align: top;
  border: 1px solid var(--cal-cell-border);
  border-radius: var(--cal-cell-radius);
  background: var(--cal-cell-bg);
  height: var(--cal-cell-height);
  width: 14.28%;
  transition: background 0.15s ease;
}
.cal-cell:hover {
  background: var(--cal-cell-hover-bg);
}
.cal-cell--today {
  background: var(--cal-today-bg);
}
.cal-cell--today .cal-cell-date {
  background: var(--cal-today-dot-bg);
  color: var(--cal-today-dot-text);
  width: 1.5rem;
  height: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

/* --- Day number --- */
.cal-cell-date {
  font-size: var(--cal-day-num-size);
  font-weight: var(--cal-day-num-weight);
  color: var(--cal-day-num-color);
  line-height: 1;
}
.cal-cell-date--today {
  background: var(--cal-today-dot-bg);
  color: var(--cal-today-dot-text);
  width: 1.5rem;
  height: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}
/* Weekday label inside a day cell; hidden everywhere by default and
   shown only in the mobile (vertical) week view, where the sticky
   day-of-week header row is dropped. */
.cal-cell-weekday {
  display: none;
}
.cal-cell-month {
  font-size: 0.625rem;
  font-weight: 500;
  color: var(--color-txt-muted);
  margin-left: 2px;
}

/* --- Race day icon --- */
.cal-race-icon {
  color: var(--color-brand);
  opacity: 0.7;
}

/* --- Phase/week marker row --- */
.cal-phase-row {
  /* wrapper for phase markers between week rows */
}
.cal-phase-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.cal-phase-text {
  font-size: var(--cal-phase-text-size);
  font-weight: 500;
  color: var(--cal-phase-text-color);
}
.cal-phase-sep {
  font-size: 0.6875rem;
  color: var(--color-txt-dim);
  opacity: 0.5;
}
.cal-phase-week {
  font-size: 0.6875rem;
  color: var(--color-txt-dim);
  opacity: 0.6;
}

/* --- Add workout button --- */
.cal-add-wkt {
  opacity: 0;
  margin-top: 6px;
  transition: opacity 0.2s ease;
}
.cal-cell:hover .cal-add-wkt {
  opacity: 1;
}
.cal-add-wkt-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  width: 100%;
  padding: 0.25rem 0;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--cal-add-border);
  color: var(--cal-add-color);
  cursor: pointer;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.3px;
  transition: all 0.2s ease;
}
.cal-add-wkt-inner:hover {
  border-color: var(--cal-add-hover-border);
  color: var(--cal-add-hover-color);
  background: var(--cal-add-hover-bg);
}

/* --- Day-range selection (week/month views) ---
   Each day that holds a planned workout carries a checkbox control in its
   header. The coach clicks one day to anchor the selection and a second day
   to select the whole range between them; the selected cells get a brand
   ring and every batch action applies to their planned workouts. */
.cal-day-select {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: auto;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.cal-cell:hover .cal-day-select,
.cal-cell--selected .cal-day-select {
  opacity: 1;
}
.cal-day-select:hover {
  background: var(--cal-add-hover-bg);
  color: var(--color-txt-main);
}
.cal-day-select:focus-visible {
  opacity: 1;
  outline: 2px solid var(--color-brand);
  outline-offset: 1px;
}
/* Touch devices have no hover: keep the control visible. */
@media (hover: none) {
  .cal-day-select {
    opacity: 1;
  }
}

.cal-cell--selected,
.cal-cell--selected:hover {
  background: rgba(var(--color-brand-rgb), 0.08);
  border-color: var(--color-brand);
  /* outline (not box-shadow) — the cell may carry an inline box-shadow from
     the block/focus overlay, which would win over a CSS box-shadow. */
  outline: 2px solid var(--color-brand);
  outline-offset: -2px;
}
/* Only the last selected workout keeps its hamburger: its menu is the batch
   action menu for the whole selection. */
.cal-cell--selected .hamburger-btn {
  opacity: 0;
  pointer-events: none;
}
.cal-cell--selected .day-selection-last .hamburger-btn {
  opacity: 1;
  pointer-events: auto;
}

.cal-selection-bar {
  position: fixed;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  max-width: calc(100vw - 1.5rem);
  padding: 0.5rem 0.75rem;
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-popover);
}
.cal-selection-bar.hidden {
  display: none;
}
.cal-selection-summary {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-txt-muted);
  white-space: nowrap;
  text-align: center;
}
.cal-selection-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.375rem;
}
.cal-selection-btn {
  display: inline-flex;
  align-items: center;
  padding: 0.375rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.cal-selection-btn:hover {
  background: var(--cal-add-hover-bg);
  border-color: var(--color-border-strong);
}
.cal-selection-btn.hidden {
  display: none;
}
.cal-selection-btn--primary {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: var(--color-txt-on-brand);
}
.cal-selection-btn--primary:hover {
  background: var(--color-brand-hover);
  border-color: var(--color-brand-hover);
}
.cal-selection-btn--danger {
  color: #dc2626;
}
.cal-selection-btn--ghost {
  background: transparent;
  color: var(--color-txt-muted);
}
@media (max-width: 40rem) {
  .cal-selection-bar {
    left: 0.5rem;
    right: 0.5rem;
    bottom: calc(60px + env(safe-area-inset-bottom) + 0.5rem);
    transform: none;
    max-width: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
    padding: 0.5rem 0.625rem;
  }
  .cal-selection-summary {
    text-align: center;
  }
  /* Keep every action on one line; the row scrolls horizontally if the
     labels do not fit the phone width. */
  .cal-selection-actions {
    flex-wrap: nowrap;
    justify-content: safe center;
    gap: 0.375rem;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  .cal-selection-actions::-webkit-scrollbar {
    display: none;
  }
  .cal-selection-btn {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 0.3125rem 0.5rem;
    font-size: 0.6875rem;
  }
}

/* --- Workout-templates drawer (calendar, coach, desktop only) ---
   Opens from the section-tabs toggle; a fixed column on the right that pushes
   the calendar left (padding on .cal-root) so every day stays a drop target.
   The drawer hosts the shared templates browser in compact mode, so the
   drill-down (types -> groups -> subcategories), the search and the template
   cards behave exactly as on the templates page.

   Note: elements whose visibility is toggled with the `hidden` utility get no
   `display` rule here — themes.css loads after Tailwind, so a `display` from
   this file would win over `.hidden` and leave the panel always visible. */
.cal-templates-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 45;
  display: flex;
  flex-direction: column;
  width: min(50vw, 640px);
  background: var(--color-panel-main);
  border-left: 1px solid var(--color-border-light);
  box-shadow: var(--shadow-popover);
}
.cal-templates-drawer.hidden {
  display: none;
}
.cal-templates-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--color-border-light);
}
.cal-templates-drawer__header h3 {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--color-txt-main);
}
.cal-templates-drawer__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
}
.cal-templates-drawer__close:hover {
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
}

/* --- Browser --- */
.cal-templates-drawer__browser {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.cal-templates-drawer__body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
/* Both levels scroll; only one of them is visible at a time. */
.cal-templates-drawer__nav,
.cal-templates-drawer__content {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.cal-templates-drawer__search {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex: 0 0 auto;
  padding: 0.625rem 1rem;
  border-bottom: 1px solid var(--color-border-light);
}
.cal-templates-drawer__search-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.375rem 0.625rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
  color: var(--color-txt-main);
  font-size: 0.8125rem;
}
.cal-templates-drawer__search-input:focus {
  outline: none;
  border-color: var(--color-brand);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.25);
}
.cal-templates-drawer__search-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 0.4375rem 0.5625rem;
  border: none;
  border-radius: var(--radius-btn);
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.cal-templates-drawer__search-btn:hover {
  background: var(--color-brand-hover);
}
/* Type tabs: one scrolling row, the active tab keeps the browser's underline. */
.cal-templates-drawer__types {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex: 0 0 auto;
  padding: 0 1rem;
  background: var(--color-panel-muted);
  border-bottom: 1px solid var(--color-border-light);
  overflow-x: auto;
}

/* The browse controls of the templates top bar: what to show on the left, with
   the search in the right corner of the same row. */
.tmpl-target {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  flex: 0 1 auto;
  min-width: 0;
}

/* In the calendar's panel the same controls are a strip of their own, between
   the search and the type tabs. */
.cal-templates-drawer__target {
  padding: 0.375rem 1rem;
  background: var(--color-panel-muted);
  border-bottom: 1px solid var(--color-border-light);
}
.tmpl-target__label {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
.tmpl-target__chips {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  flex: 0 0 auto;
  padding: 0.125rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
}
.tmpl-target__chip {
  flex: 0 0 auto;
  padding: 0.25rem 0.625rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.tmpl-target__chip:hover {
  color: var(--color-txt-main);
}
.tmpl-target__chip.is-active {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
}
.tmpl-target__chip:focus-visible {
  outline: 2px solid var(--color-txt-main);
  outline-offset: 1px;
}
/* A control that stands on its own in the row (not inside the chip group), so
   it carries its own border. It may hold an icon and a label. */
.tmpl-target__chip--standalone {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  border: 1px solid var(--color-border-light);
  background: var(--color-panel-main);
}
.tmpl-target__chip--standalone.is-active {
  border-color: var(--color-brand);
}
.tmpl-target__athlete {
  flex: 0 0 auto;
  width: 100%;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
  color: var(--color-txt-main);
  font-size: 0.75rem;
}
/* The picker is a custom-select: what the coach sees is the wrapper the JS
   inserts next to the hidden <select>, so the width has to live on this box.
   A fifth of the row the control used to stretch across. */
.tmpl-target__athlete-field {
  flex: 0 0 auto;
  width: 11rem;
  min-width: 0;
}
.tmpl-target__athlete-field .custom-select {
  width: 100%;
}
.tmpl-target__athlete.hidden {
  display: none;
}

/* ── Compare mode: the two libraries of one subcategory side by side ──
   A card dragged onto the other pane is copied into that library (the source
   stays), and the pane under the pointer takes the brand ring. Falls back to a
   single column when there is no room for two. */
.tmpl-compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  align-items: start;
}
/* Two classes beat Tailwind's .grid (this file loads after the build). */
.tmpl-compare.hidden {
  display: none;
}
.tmpl-compare__title {
  margin: 0 0 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}
.tmpl-compare__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  min-height: 3.5rem;
  border-radius: var(--radius-btn);
  transition: box-shadow 0.15s ease, background-color 0.15s ease;
}
.tmpl-compare__grid.is-drop-target {
  box-shadow: inset 0 0 0 2px var(--color-brand);
  background: var(--color-panel-muted);
}
.tmpl-compare__hint {
  padding: 1rem;
  border: 1px dashed var(--color-border-light);
  border-radius: var(--radius-btn);
  color: var(--color-txt-muted);
  font-size: 0.8125rem;
  text-align: center;
}
.tmpl-compare-single.hidden {
  display: none;
}
@media (max-width: 63.99rem) {
  .tmpl-compare {
    grid-template-columns: 1fr;
  }
}

/* ── Filters of the templates top bar (tags, duration, distance) ──
   A filter is a chip that opens a panel of its own: inline in the row on
   desktop, where its chips wrap onto the next line, and a dropdown over the
   browser on phones. */
.tmpl-filter {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  min-width: 0;
}
.tmpl-filter__summary {
  margin-left: 0.25rem;
  font-variant-numeric: tabular-nums;
}
.tmpl-filter__summary.hidden {
  display: none;
}
.tmpl-filter__panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}
/* Two classes beat Tailwind's .hidden (this file loads after the build). */
.tmpl-filter__panel.hidden {
  display: none;
}
.tmpl-tags__count {
  margin-left: 0.25rem;
  font-variant-numeric: tabular-nums;
}
.tmpl-tags__count.hidden {
  display: none;
}

/* Range panels — "от [ 45 ] до [ 90 ] мин ×". */
.tmpl-range {
  gap: 0.375rem;
}
.tmpl-range__field {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}
.tmpl-range__label {
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
.tmpl-range__input {
  width: 4rem;
  padding: 0.25rem 0.375rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-sm);
  background: var(--color-panel-main);
  color: var(--color-txt-main);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}
.tmpl-range__input:focus {
  outline: none;
  border-color: var(--color-brand);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.15);
}
.tmpl-range__unit {
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
.tmpl-range__reset {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.125rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
}
.tmpl-range__reset:hover {
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
}

/* ── Card metrics ──
   Duration and distance, each behind its own mark, in tabular figures so the
   values line up down a column of cards and the eye compares them. A metric the
   template does not carry is absent — no zeroes. */
.tmpl-card__metrics {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0 1rem 0.5rem;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
.tmpl-card__metric {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--color-txt-main);
  font-variant-numeric: tabular-nums;
}
.tmpl-card__metric svg {
  flex: 0 0 auto;
  opacity: 0.6;
}
.tmpl-card__zone {
  padding: 0.125rem 0.375rem;
  border-radius: var(--radius-sm);
  background: var(--color-panel-muted);
  color: var(--color-txt-muted);
}
.tmpl-tags__chip {
  padding: 0.1875rem 0.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: 9999px;
  background: var(--color-panel-main);
  color: var(--color-txt-muted);
  font-size: 0.75rem;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.tmpl-tags__chip:hover {
  color: var(--color-txt-main);
  border-color: var(--color-border-strong);
}
.tmpl-tags__chip.is-active {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: var(--color-txt-on-brand);
}
.tmpl-tags__chip:focus-visible {
  outline: 2px solid var(--color-txt-main);
  outline-offset: 1px;
}
.tmpl-tags__empty {
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}

@media (max-width: 63.99rem) {
  .tmpl-filter__panel {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 0;
    z-index: 30;
    flex-direction: column;
    align-items: stretch;
    gap: 0.25rem;
    width: max(12rem, 60vw);
    max-height: 50vh;
    overflow-y: auto;
    padding: 0.5rem;
    background: var(--color-panel-main);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-btn);
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
  }
  .tmpl-tags__chip {
    text-align: left;
    border-radius: var(--radius-sm);
  }
  .tmpl-range__field {
    justify-content: space-between;
  }
}
/* The selection path; sticky so it stays readable while the cards scroll. */
.cal-templates-drawer__crumbs {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 0.75rem;
  background: var(--color-panel-muted);
  border-bottom: 1px solid var(--color-border-light);
}
.cal-templates-drawer__back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 0.25rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
}
.cal-templates-drawer__back:hover {
  color: var(--color-txt-main);
  background: var(--color-panel-main);
}
/* Two classes beat Tailwind's .hidden (this file loads after the build). */
.cal-templates-drawer__back.hidden {
  display: none;
}
.cal-templates-drawer__crumb {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.8125rem;
  color: var(--color-txt-muted);
}
/* One template per row: the card is as wide as the drawer, so its name, structure
   and description stay readable while dragging. */
.cal-templates-drawer__cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
}
.cal-templates-drawer__cards .card-template[draggable="true"] {
  cursor: grab;
}
.card-template--dragging {
  opacity: 0.5;
}
.cal-templates-drawer__loading {
  padding: 1.5rem 0.5rem;
  text-align: center;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
/* The templates panel toggle: the same mark in the desktop tabs bar and in the
   phone toolbar. The sheet stack keeps the library metaphor, the load bolt
   makes it a training library, and the brand yellow makes it the one bright
   icon in an otherwise muted row of chrome. */
.cal-templates-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 0.375rem;
  border: none;
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.cal-templates-toggle:hover {
  background: var(--color-panel-muted);
}
.cal-templates-toggle[aria-expanded="true"] {
  background: var(--color-brand-light);
}
.cal-templates-toggle__sheet {
  fill: rgba(var(--color-brand-rgb), 0.45);
}
.cal-templates-toggle__card {
  fill: var(--color-brand);
}
.cal-templates-toggle__bolt {
  fill: var(--color-txt-on-brand);
}

/* ============================================================
   WEATHER FORECAST OVERLAY (Coach · Calendar)
   A forecast toggle beside the templates toggle, and a compact
   instrument strip drawn at the top of a day cell: temperature
   range, wind, humidity, precipitation and the precipitation
   window. The strip wraps, so a narrow month cell shows one
   reading per row while a wide day cell fits all of them.
   ============================================================ */
.cal-weather-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 0.375rem;
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--cal-weather-icon);
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.cal-weather-toggle:hover {
  background: var(--color-panel-muted);
}
/* On while the forecast is drawn in the calendar. */
.cal-weather-toggle.is-active {
  background: var(--cal-weather-bg-strong);
}
.cal-weather-toggle:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}
.cal-weather-toggle__cloud {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.cal-weather-toggle__sun {
  fill: var(--cal-weather-icon);
  opacity: 0.55;
}
.cal-weather-toggle.is-active .cal-weather-toggle__sun {
  fill: var(--color-brand);
  opacity: 1;
}
.cal-weather-toggle.is-active .cal-weather-toggle__cloud {
  fill: var(--cal-weather-water-soft);
  stroke: var(--cal-weather-water);
}

/* The slot is the size container for the strip: a month cell is about 110px
   wide, a day cell hundreds, so the query measures the cell, not the viewport. */
.cal-weather-slot {
  container-type: inline-size;
}

/* A button: tapping the strip opens the same readings enlarged in a centered
   panel — that is how they are read where only the icons fit (phone month cells,
   see the detail levels below). */
.cal-weather {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1px 4px;
  width: 100%;
  margin-bottom: 2px;
  padding: 2px 3px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--cal-weather-bg);
  font: inherit;
  font-size: 0.625rem;
  line-height: 1.15;
  color: var(--cal-weather-text);
  text-align: left;
  cursor: pointer;
}
.cal-weather:hover {
  background: var(--cal-weather-bg-hover);
}
.cal-weather:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}
.cal-weather__item {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex: 0 1 auto;
  min-width: 0;
  /* An item never spills into the neighbouring day: it wraps to its own line
     first (flex-wrap above), and only a value wider than the whole cell would
     clip here. */
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
}
.cal-weather__icon {
  flex: 0 0 auto;
  color: var(--cal-weather-icon);
  transform-origin: 50% 50%;
}
.cal-weather__value {
  font-weight: 600;
  letter-spacing: 0.01em;
}
.cal-weather__unit {
  margin-left: 1px;
  font-size: 0.5625rem;
  font-weight: 500;
  color: var(--cal-weather-icon);
}
/* Temperature is the headline reading of the strip. */
.cal-weather__item--temp,
.cal-weather__item--temp .cal-weather__icon {
  color: var(--cal-weather-temp);
}
/* Humidity and precipitation share the water accent. */
.cal-weather__item--water .cal-weather__icon {
  color: var(--cal-weather-water);
}

/* ── Detail levels ─────────────────────────────────────────────────────────
   A wide cell shows every reading with its units and the full clock window; a
   narrow one keeps the units, shortens the window to hour numbers
   ("02-08, 17-20") and lets that list wrap; a phone month cell keeps the icons
   alone, where the strip becomes the tap target for the readings panel. The
   tooltips carry the precise value at every level, and the strip wraps rather
   than clipping. */
.cal-weather__window--full {
  display: none;
}

@container (min-width: 150px) {
  .cal-weather__window--full {
    display: inline;
  }
  .cal-weather__window--short {
    display: none;
  }
}

/* ── Phone month cells ─────────────────────────────────────────────────────
   About 43px per cell: only the icons fit, so the strip becomes the tap target
   for the readings panel (activities_weather_controller, one panel per page).
   Since the values are not drawn here at all, there is nothing to clip. */
@container (max-width: 96px) {
  .cal-weather {
    gap: 1px 3px;
    padding: 1px 2px;
  }
  .cal-weather__value {
    display: none;
  }
  .cal-weather__icon {
    width: 11px;
    height: 11px;
  }
}

/* ── Readings panel (opened from a day's weather strip) ─────────────────────
   The enlarged strip: values lead, labels stay quiet, and the two accents
   (amber for temperature, blue for water) carry over. Centered on screen, one
   panel per page — the controller fills it from the tapped strip. */
.cal-weather-panel {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(15, 23, 42, 0.45);
}
.cal-weather-panel[hidden] {
  display: none;
}
.cal-weather-panel__card {
  width: min(22rem, 100%);
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1.125rem 1.25rem;
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-popover);
}
.cal-weather-panel__head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.875rem;
}
.cal-weather-panel__title {
  margin: 0;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}
.cal-weather-panel__date {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--color-txt-main);
}
.cal-weather-panel__close {
  display: inline-flex;
  margin-left: auto;
  padding: 0.25rem;
  border: 0;
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
}
.cal-weather-panel__close:hover {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}
.cal-weather-panel__close:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}
.cal-weather-panel__list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cal-weather-panel__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--color-border-light);
  color: var(--cal-weather-icon);
}
/* The flex display above would otherwise beat the hidden attribute. */
.cal-weather-panel__row[hidden] {
  display: none;
}
.cal-weather-panel__row:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}
.cal-weather-panel__icon--wind {
  transform-origin: 50% 50%;
}
.cal-weather-panel__label {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
/* A right-aligned column: with several precipitation windows the value wraps,
   and right alignment keeps every line on the same edge as the single-line
   readings above it instead of drifting to the left. The minimum width sends a
   long label's value to its own line rather than squeezing it into a column
   narrow enough to break the clock ranges apart. */
.cal-weather-panel__value {
  flex: 1 1 auto;
  min-width: 8rem;
  margin-left: auto;
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.25;
  text-align: right;
  color: var(--color-txt-main);
}
.cal-weather-panel__row--temp,
.cal-weather-panel__row--temp .cal-weather-panel__value {
  color: var(--cal-weather-temp);
}
.cal-weather-panel__row--water {
  color: var(--cal-weather-water);
}
/* Drop target highlight while a workout card hovers the drawer. */
.cal-templates-drawer--drop {
  outline: 2px dashed var(--color-brand);
  outline-offset: -4px;
}
/* Subcategory row the dragged workout would be saved into. */
.cal-templates-drawer [data-subcategory-id].is-template-drop-target {
  background: rgba(var(--color-brand-rgb), 0.18);
  box-shadow: inset 2px 0 0 var(--color-brand);
}

@media (min-width: 48rem) {
  /* Reserve the drawer's width so the calendar compresses instead of hiding
     days behind it. */
  .cal-root--templates-open {
    padding-right: min(50vw, 640px);
  }
}
/* Phones: the panel is a full-screen sheet instead of a side column. Native
   drag & drop does not exist on touch, so there the panel schedules through the
   assign dialog (see the drawer's assign button). */
@media (max-width: 47.99rem) {
  .cal-templates-drawer {
    width: 100%;
  }
  /* The calendar behind the sheet must not scroll away under the finger. */
  body:has(.cal-templates-drawer:not(.hidden)) {
    overflow: hidden;
  }
}

/* --- Day-cell expand/collapse (week/month views) ---
   Cells show the first 5 items; the rest stay in the DOM hidden
   (.cal-day-extra) and are revealed by the "Show more" button.
   The control is a quiet ghost row in the same family as the dashed
   "Add workout" control; the chevron flip is the only motion cue. */
.cal-day-extra {
  display: none;
}
.cal-day-list.is-expanded .cal-day-extra {
  display: block;
}
.cal-day-more {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  width: 100%;
  margin-top: 0.25rem;
  padding: 0.1875rem 0.25rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.cal-day-more:hover,
.cal-day-more:focus-visible {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}
.cal-day-more svg {
  flex-shrink: 0;
  transition: transform 0.15s ease;
}
.cal-day-more.is-expanded svg {
  transform: rotate(180deg);
}

/* ============================================================
   MOBILE CALENDAR CARDS (<= sm / 40rem / 640px)
   Week view: the 7-column grid is flipped into a vertical list
   of full-width day blocks, so the workout name, the structure
   visualization and the general metrics (planned and performed)
   all fit. The sticky day-of-week header is dropped (each day
   block carries its own weekday label). Text description, goal,
   comments and the card menu stay hidden. Month view: icon-only
   column of sport icons, stacked in the day cell in render order.
   ============================================================ */
@media (max-width: 40rem) {
  /* ---- Week view: vertical day list ---- */
  .cal-root--week .cal-dow-table {
    display: none;
  }
  .cal-grid--week table,
  .cal-grid--week tbody,
  .cal-grid--week tr,
  .cal-grid--week td {
    display: block;
    width: 100%;
  }
  .cal-grid--week .cal-cell {
    height: auto;
    margin-bottom: 0.375rem;
  }
  /* Phone week view: one line with the date on the left, the short uppercase
     weekday centered and the selection control on the right. */
  .cal-root--week .cal-cell-header .cal-cell-date {
    order: 1;
  }
  .cal-root--week .cal-cell-header .cal-cell-weekday {
    display: block;
    order: 2;
    flex: 1 1 auto;
    text-align: center;
    font-size: var(--cal-dow-size);
    font-weight: var(--cal-dow-weight);
    letter-spacing: var(--cal-dow-spacing);
    text-transform: uppercase;
    color: var(--cal-dow-color);
    line-height: 1.1;
  }
  .cal-root--week .cal-cell-header .cal-day-select {
    order: 3;
  }

  /* ---- Week view: compact cards ---- */
  .cal-grid--week .wkt-desc .structure-desc,
  .cal-grid--week .wkt-desc .strength-desc,
  .cal-grid--week .wkt-goal,
  .cal-grid--week .wkt-comment-bar {
    display: none;
  }
  .cal-grid--week .wkt-card {
    padding: 0.25rem 0.375rem;
  }
  /* Phone-friendly pill sizes for both the planned and the performed
     metrics; wrap so they never overflow the card. */
  .cal-grid--week .wkt-metrics,
  .cal-grid--week .wkt-actual {
    font-size: 0.6875rem;
    padding: 0.0625rem 0.25rem;
    margin-bottom: 0.25rem;
    flex-wrap: wrap;
  }
  .cal-grid--week .wkt-metrics svg,
  .cal-grid--week .wkt-actual svg {
    width: 14px;
    height: 14px;
  }
  .cal-grid--week .wkt-icon {
    font-size: 1rem;
  }
  .cal-grid--week .wkt-icon svg {
    width: 16px;
    height: 16px;
  }
  /* Name size suited to the full-width rows of the vertical layout. */
  .cal-grid--week .wkt-name {
    font-size: 0.875rem;
    line-height: 1.2;
  }
  .cal-grid--week .wkt-desc .structure-mini {
    margin-top: 2px;
  }

  /* ---- Month view: centered icon-only column ---- */
  .cal-grid--month .wkt-metrics,
  .cal-grid--month .wkt-actual,
  .cal-grid--month .wkt-name,
  .cal-grid--month .wkt-desc,
  .cal-grid--month .wkt-goal,
  .cal-grid--month .wkt-comment-bar,
  .cal-grid--month .hamburger-btn,
  .cal-grid--month [data-workout-menu] {
    display: none;
  }
  .cal-grid--month .wkt-card {
    padding: 0.125rem 0;
    border: none;
    background: transparent;
    box-shadow: none;
  }
  .cal-grid--month .wkt-card::before {
    display: none;
  }
  .cal-grid--month .wkt-name-row {
    justify-content: center;
    padding-right: 0;
    margin-bottom: 0;
  }
  /* Larger centered icons: SVG sport icons at 20px, emoji icons match. */
  .cal-grid--month .wkt-icon {
    font-size: 1.25rem;
  }
  .cal-grid--month .wkt-icon svg {
    width: 20px;
    height: 20px;
  }
  /* Sport icons: standalone planned workouts are blue, workouts merged
     with an intervals.icu activity are green (same green as the inline
     merge icon on the workout card). */
  .cal-grid--month .wkt-icon {
    color: #2563eb;
  }
  .cal-grid--month .wkt-card[data-merged="true"] .wkt-icon {
    color: #047857;
  }
  /* Race cards in month view: icon-only (flag + sport type), mirroring
     the icon-only workout cards above. Name, meta, countdown, actual
     metrics and the priority badge are hidden. */
  .cal-grid--month .race-card__body,
  .cal-grid--month .race-card__badge {
    display: none;
  }
  .cal-grid--month .race-card {
    padding: 0.375rem 0;
    border: none;
    background: transparent;
    box-shadow: none;
    align-items: center;
    justify-content: center;
  }
  .cal-grid--month .race-card::before {
    display: none;
  }
}

/* --- Fullscreen adjustments --- */
.calendar-fullscreen .cal-grid-scroll {
  max-height: calc(100vh - 140px) !important;
}

/* ============================================================
   TRAINING LOAD CHART (Calendar · Month view)
   ============================================================ */

.tl-root {
  --tl-col-w: 36px;
  --tl-plot-h: 150px;
  --tl-months-h: 22px;
  --tl-race-lane-h: 0px;
  --tl-now-lane-h: 0px;
  --tl-actual-bg: #4f46e5;
  --tl-plan-line: #6366f1;
  --tl-plan-hatch: rgba(99, 102, 241, 0.18);
  position: relative;
  margin-bottom: 0.75rem;
  padding: 0.75rem;
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-lg);
}

/* Collapse handle: a pill sitting ON the chart's existing top border (not an
   extra row). Its width defaults to one month of the chart; the controller
   sets it to the current month's span (weeks x column width). */
.tl-collapse {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  width: calc(var(--tl-col-w) * 4);
  padding: 0.125rem 0.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: 9999px;
  background: var(--color-panel-muted);
  color: var(--color-txt-muted);
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transform: translate(-50%, -50%);
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.tl-collapse:hover {
  border-color: var(--color-border-strong);
  background: var(--color-panel-main);
  color: var(--color-txt-main);
}

.tl-collapse:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
}

.tl-collapse-chevron {
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

/* Collapsed: the card shrinks to its top border line, so the handle is the
   whole control. */
.tl-root.is-collapsed {
  padding: 0;
}

.tl-root.is-collapsed .tl-collapse-chevron {
  transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .tl-collapse-chevron {
    transition: none;
  }
}

/* The race lane only takes vertical space when races are actually shown. */
.tl-root.has-races {
  --tl-race-lane-h: 26px;
}

/* A little room under the bars for the current-week marker. */
.tl-root.has-current {
  --tl-now-lane-h: 15px;
}

[data-theme="dark"] .tl-root {
  --tl-actual-bg: #818cf8;
  --tl-plan-line: #a5b4fc;
  --tl-plan-hatch: rgba(165, 180, 252, 0.22);
}

.tl-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.tl-header-left {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.tl-header-right {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

/* Coach-only: open/close the chart for the athlete. Filled when the athlete
   can see the chart, quiet outline when it is hidden. */
.tl-share-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.375rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: all 0.15s ease;
}

.tl-share-btn:hover {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}

.tl-share-btn.is-on {
  border-color: var(--color-brand);
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
}

.tl-share-btn:disabled {
  opacity: 0.5;
  cursor: wait;
}

.tl-share-btn .tl-share-eye-off,
.tl-share-btn.is-on .tl-share-eye {
  display: none;
}

.tl-share-btn.is-on .tl-share-eye-off {
  display: inline-flex;
}

.tl-share-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.tl-sport-select {
  padding: 0.25rem 0.5rem;
  font-size: var(--fs-small);
  color: var(--color-txt-main);
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  cursor: pointer;
}

.tl-sport-select:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}

.tl-metric-toggle {
  display: inline-flex;
  gap: 1px;
  padding: 2px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
}

.tl-metric-btn {
  padding: 0.25rem 0.75rem;
  font-size: var(--fs-small);
  font-weight: 500;
  border: 0;
  border-radius: calc(var(--radius-btn) - 2px);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: all 0.15s ease;
}

.tl-metric-btn:hover {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}

.tl-metric-btn.is-active {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
  font-weight: 600;
}

.tl-gear-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.375rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: all 0.15s ease;
}

.tl-gear-btn:hover {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}

.tl-settings-popover {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 40;
  min-width: 180px;
  padding: 0.375rem;
  background: var(--color-panel-elevated);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-popover);
}

.tl-settings-popover.hidden {
  display: none;
}

.tl-setting {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.5rem;
  font-size: var(--fs-small);
  color: var(--color-txt-main);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.tl-setting:hover {
  background: var(--color-panel-muted);
}

.tl-chart {
  display: flex;
  align-items: flex-start;
}

.tl-yaxis {
  flex: 0 0 46px;
  position: relative;
}

.tl-axis-spacer {
  height: calc(var(--tl-months-h) + var(--tl-race-lane-h));
}

.tl-axis-area {
  position: relative;
  height: var(--tl-plot-h);
}

.tl-axis-label {
  position: absolute;
  right: 5px;
  transform: translateY(50%);
  font-size: 0.625rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-txt-muted);
  white-space: nowrap;
}

.tl-scroll {
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
}

.tl-plot {
  position: relative;
  width: max-content;
}

.tl-months {
  display: flex;
  height: var(--tl-months-h);
}

.tl-month {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
  white-space: nowrap;
}

.tl-month span {
  padding: 0 0.25rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tl-grid,
.tl-bands {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--tl-months-h) + var(--tl-race-lane-h));
  height: var(--tl-plot-h);
  pointer-events: none;
}

.tl-grid {
  z-index: 1;
}

.tl-bands {
  z-index: 2;
}

.tl-grid-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px solid var(--color-border-light);
}

/* Periodization, painted behind the bars: one mesocycle band per run of weeks
   (quiet fill + coloured top rule + name) and a per-week microcycle tint. */
.tl-band {
  position: absolute;
  top: 0;
  bottom: 0;
  border-top: 2px solid transparent;
  border-radius: 2px;
}

.tl-band-label {
  position: absolute;
  top: 3px;
  left: 3px;
  z-index: 3;
  max-width: calc(100% - 6px);
  overflow: hidden;
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.tl-micro {
  position: absolute;
  top: 2px;
  bottom: 0;
  border-top: 3px solid transparent;
  border-radius: 2px;
}

/* Race lane: keeps the flags clear of the bars. The marker is the bare pennant
   shape (no chip); a contrasting outline plus a soft shadow make it read on
   both themes. */
.tl-race-lane {
  position: relative;
  width: 100%;
  height: var(--tl-race-lane-h);
  overflow: hidden;
  pointer-events: none;
}

.tl-races {
  position: absolute;
  bottom: 3px;
  display: flex;
  justify-content: center;
  gap: 1px;
  pointer-events: none;
}

.tl-race {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  color: var(--tl-race-color, var(--color-brand));
  filter: drop-shadow(0 1px 2px rgba(15, 23, 42, 0.35));
}

.tl-race svg {
  width: 100%;
  height: 100%;
  paint-order: stroke;
  stroke: rgba(15, 23, 42, 0.45);
  stroke-width: 1.2;
}

[data-theme="dark"] .tl-race svg {
  stroke: rgba(255, 255, 255, 0.45);
}

.tl-race--a {
  --tl-race-color: #ef4444;
}

.tl-race--b {
  --tl-race-color: #f59e0b;
}

.tl-race--c {
  --tl-race-color: #3b82f6;
}

.tl-race--none {
  --tl-race-color: var(--color-brand);
}

[data-theme="dark"] .tl-race--a {
  --tl-race-color: #f87171;
}

[data-theme="dark"] .tl-race--b {
  --tl-race-color: #fbbf24;
}

[data-theme="dark"] .tl-race--c {
  --tl-race-color: #60a5fa;
}

.tl-cols {
  position: relative;
  z-index: 3;
  display: flex;
  height: var(--tl-plot-h);
}

/* Current-week marker: a short brand bar with a small chevron, sitting under
   the column it marks. */
.tl-now-lane {
  position: relative;
  width: 100%;
  height: var(--tl-now-lane-h);
  overflow: hidden;
  pointer-events: none;
}

.tl-now {
  position: absolute;
  bottom: 0;
  display: flex;
  justify-content: center;
}

.tl-now-bar {
  position: relative;
  width: 58%;
  height: 3px;
  border-radius: 2px;
  background: var(--color-brand);
}

.tl-now-bar::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 100%;
  transform: translateX(-50%);
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 5px solid var(--color-brand);
}

.tl-col {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: 100%;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

.tl-col:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: -2px;
}

.tl-bar-area {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 62%;
  height: 100%;
}

/* Planned load: translucent hatched outline drawn behind the performed bar. */
.tl-plan {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  border: 1px dashed var(--tl-plan-line);
  border-bottom: 0;
  border-radius: 2px 2px 0 0;
  background-image: repeating-linear-gradient(
    45deg,
    var(--tl-plan-hatch) 0 2px,
    transparent 2px 6px
  );
}

/* Performed load: dense bar overlaid on the plan. */
.tl-actual {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  background: var(--tl-actual-bg);
  border-radius: 2px 2px 0 0;
}

/* Top boundary of the plan. Only rendered when the performed bar reaches or
   exceeds the plan, i.e. when the plan's own dashed border is covered. Uses the
   panel colour so it contrasts with the bar in both themes. */
.tl-target {
  position: absolute;
  left: -2px;
  right: -2px;
  z-index: 3;
  height: 0;
  border-top: 2px dashed var(--color-panel-main);
  pointer-events: none;
}

.tl-tooltip {
  position: absolute;
  z-index: 60;
  min-width: 180px;
  max-width: 260px;
  padding: 0.5rem 0.625rem;
  font-size: 0.6875rem;
  line-height: 1.45;
  color: var(--color-txt-main);
  background: var(--color-panel-elevated);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-popover);
  transform: translateX(-50%);
  pointer-events: none;
}

.tl-tooltip[hidden] {
  display: none;
}

.tl-tt-title {
  margin-bottom: 0.375rem;
  font-weight: 700;
}

.tl-tt-week {
  margin-left: 0.25rem;
  font-weight: 500;
  color: var(--color-txt-muted);
}

.tl-tt-row,
.tl-tt-sport {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
}

.tl-tt-key {
  color: var(--color-txt-muted);
}

.tl-tt-val {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tl-tt-pct {
  margin-left: 0.25rem;
  font-weight: 600;
  color: var(--color-txt-muted);
}

.tl-tt-sep {
  height: 1px;
  margin: 0.375rem 0;
  background: var(--color-border-light);
}

.tl-tt-sub {
  margin-bottom: 0.25rem;
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}

@media (max-width: 40rem) {
  .tl-root {
    /* Extra room under the top border so the collapse handle never overlaps the
       header controls (sport select / metric toggle) on phones. */
    padding: 0.5rem;
    padding-top: 1rem;
  }

  .tl-root.has-races {
    --tl-race-lane-h: 24px;
  }

  .tl-root.has-current {
    --tl-now-lane-h: 13px;
  }

  .tl-yaxis {
    flex-basis: 40px;
  }

  /* Two flags must still fit inside one 30px week column. */
  .tl-race {
    width: 15px;
    height: 15px;
  }
}

/* ============================================================
   WORKOUT CARD COMPONENT
   ============================================================ */

.wkt-card {
  position: relative;
  padding: 0.25rem 0.5rem;
  background: var(--wkt-bg);
  border: 1px solid var(--wkt-border);
  border-radius: var(--wkt-radius);
  box-shadow: var(--wkt-shadow);
  cursor: pointer;
  transition: all 0.2s ease;
  line-height: 1.3;
}
.wkt-card:hover {
  border-color: var(--wkt-border-hover);
  box-shadow: var(--wkt-shadow-hover);
  translate: 0 var(--wkt-hover-translate-y);
  z-index: 30;
}

/* Left accent bar by type */
.wkt-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--wkt-accent-bar);
  border-radius: var(--wkt-radius) 0 0 var(--wkt-radius);
  transition: width 0.15s ease;
}
.wkt-card:hover::before {
  width: 4px;
}

/* Type-specific accent colors via data attribute */
.wkt-card[data-wkt-type="run"]::before       { background: #2563eb; }
.wkt-card[data-wkt-type="recovery"]::before   { background: #16a34a; }
.wkt-card[data-wkt-type="intervals"]::before  { background: #dc2626; }
.wkt-card[data-wkt-type="tempo"]::before      { background: #d97706; }
.wkt-card[data-wkt-type="long_run"]::before   { background: #7c3aed; }
.wkt-card[data-wkt-type="race"]::before       { background: #e6c619; }
.wkt-card[data-wkt-type="default"]::before    { background: #94a3b8; }
.wkt-card[data-wkt-type="rest"]::before       { background: var(--color-rest); }
.wkt-card[data-wkt-type="rest"] .wkt-icon     { color: var(--color-rest); }

/* Fallback: if no data-wkt-type, use color from part/phase */
.wkt-card:not([data-wkt-type])::before {
  background: var(--wkt-border);
}

/* --- Planned metrics badge --- */
.wkt-metrics {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.375rem;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--wkt-planned-text);
  background: var(--wkt-planned-bg);
  border: 1px solid var(--wkt-planned-border);
  border-radius: var(--wkt-planned-radius);
  width: fit-content;
}
.wkt-metrics-sep {
  opacity: 0.3;
  font-weight: 300;
}

/* --- Actual metrics badge --- */
.wkt-actual {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.375rem;
  margin-bottom: 0.375rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--wkt-actual-text);
  background: var(--wkt-actual-bg);
  border: 1px solid var(--wkt-actual-border);
  border-radius: var(--wkt-planned-radius);
  width: fit-content;
}
.wkt-actual-sep {
  opacity: 0.3;
  font-weight: 300;
}

/* --- Session clock (Distance & Time header, workout form and race performed
   side): start – end time of day. Sits a step below the block title so the
   range reads as a secondary annotation rather than competing with it. --- */
.session-time {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--color-txt-muted);
}
.session-time svg {
  flex-shrink: 0;
  opacity: 0.7;
}
.session-time__sep {
  opacity: 0.5;
  font-weight: 300;
}

/* --- Workout name row --- */
.wkt-name-row {
  display: flex;
  align-items: flex-start;
  gap: 0.25rem;
  width: 100%;
  margin-bottom: 0.125rem;
  padding-right: 1.25rem;
}
.wkt-icon {
  flex-shrink: 0;
  font-size: 0.875rem;
  opacity: 0.8;
  line-height: 1.3;
}

/* Hidden-from-athlete badge: eye-off icon on a colored circle, anchored to
   the top-right corner level with the hamburger button (right: 28px leaves
   4px gap after the 20px button). Stays below the menu dropdown. */
.wkt-hidden-badge {
  position: absolute;
  top: 0.25rem;
  right: 1.75rem;
  z-index: 30;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 9999px;
  background: var(--wkt-hidden-bg);
  color: var(--wkt-hidden-text);
}

/* Hidden cards keep the name clear of the corner badge (hamburger 1.25rem +
   badge 1.125rem + gap 0.25rem on top of the base 1.25rem reserved for the
   hamburger). */
.wkt-card[data-hidden="true"] .wkt-name-row {
  padding-right: 2.625rem;
}
.wkt-name {
  font-size: 1rem;
  font-weight: 500;
  color: var(--wkt-text);
  word-break: break-word;
  line-height: 1.25;
}
.wkt-fit-badge {
  flex-shrink: 0;
  margin-left: auto;
  padding: 0.125rem 0.375rem;
  border-radius: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 700;
  background: var(--wkt-fit-bg);
  color: var(--wkt-fit-text);
  text-decoration: none;
  transition: background 0.15s;
}
.wkt-fit-badge:hover {
  background: var(--wkt-fit-hover-bg);
}

/* --- Workout description --- */
.wkt-desc {
  color: var(--wkt-text);
  font-size: 0.6875rem;
  line-height: 1.3;
}

/* --- Goal section --- */
.wkt-goal {
  margin-top: 0.25rem;
  padding-top: 0.125rem;
  border-top: 1px solid var(--wkt-border);
  color: var(--wkt-text);
  font-size: 0.625rem;
  line-height: 1.2;
  word-break: break-word;
}
.wkt-goal-label {
  display: block;
  font-size: 0.53125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 0.125rem;
}

/* --- Hamburger menu button --- */
.wkt-menu-btn {
  position: absolute;
  top: 0.25rem;
  right: 0.25rem;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: background 0.12s ease;
  opacity: 0.5;
}
.wkt-card:hover .wkt-menu-btn {
  opacity: 1;
}
.wkt-menu-btn:hover {
  background: var(--wkt-muted-bg);
  color: var(--wkt-text);
}

/* --- Hamburger dropdown --- */
.wkt-menu-dropdown {
  display: none;
  position: absolute;
  left: 100%;
  top: 0;
  margin-left: 0.5rem;
  z-index: 50;
  min-width: 9rem;
  overflow: hidden;
  border-radius: 0.75rem;
  border: 1px solid var(--wkt-menu-border);
  background: var(--wkt-menu-bg);
  box-shadow: var(--wkt-menu-shadow);
}
.wkt-menu-dropdown.open {
  display: block;
}
.wkt-menu-item {
  display: flex;
  width: 100%;
  align-items: center;
  padding: 0.375rem 0.75rem;
  text-align: left;
  font-size: 0.75rem;
  color: var(--wkt-text);
  background: transparent;
  border: none;
  cursor: pointer;
  transition: background 0.1s ease;
}
.wkt-menu-item:hover {
  background: var(--wkt-menu-item-hover);
}
.wkt-menu-item:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.wkt-menu-item:disabled:hover {
  background: transparent;
}
.wkt-menu-item--icon {
  gap: 0.375rem;
}
.wkt-menu-divider {
  height: 1px;
  background: var(--wkt-menu-divider);
  margin: 0.125rem 0;
}

/* --- ICU (unlinked activity) card --- */
.wkt-card--icu::before {
  background: var(--color-txt-dim) !important;
}
.wkt-card--icu .wkt-icon {
  color: var(--color-txt-dim);
}

/* --- Merged workouts (planned + performed): accent bar matches the green
   highlight of the actual duration/distance metrics (wkt-actual token),
   adapting to light (dark green) and dark (bright emerald) themes --- */
.wkt-card[data-merged="true"]::before {
  background: var(--wkt-actual-text);
}
.wkt-card--icu[data-merged="true"]::before {
  background: var(--wkt-actual-text) !important;
}

/* ============================================================
   HAMBURGER MENU BUTTON — kept class name for JS compatibility
   ============================================================ */
.hamburger-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
  line-height: 1;
  padding: 0;
  opacity: 0.5;
}
.wkt-card .wkt-comment-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  width: 100%;
  padding: 0.25rem 0;
  margin-top: 0.25rem;
  border-top: 1px solid var(--color-border-light, #e2e8f0);
  background: transparent;
  border-left: none;
  border-right: none;
  border-bottom: none;
  cursor: pointer;
  color: var(--color-txt-muted);
  font-size: 0.75rem;
  transition: background 0.1s;
}
.wkt-card .wkt-comment-bar:hover {
  background: var(--color-panel-muted, #f8fafc);
}
.wkt-comment-bar-count {
  font-weight: 700;
  font-size: 0.75rem;
  line-height: 1;
}

.hamburger-btn:hover {
  background: var(--wkt-muted-bg);
  color: var(--wkt-text);
}

/* Menu dropdown positioned via JS - themed */
[data-workout-menu] {
  position: absolute;
  left: 100%;
  top: 0;
  margin-left: 0.25rem;
  z-index: 50;
  min-width: 9rem;
  overflow: hidden;
  border-radius: 0.75rem;
  border: 1px solid var(--wkt-menu-border);
  background: var(--wkt-menu-bg);
  box-shadow: var(--wkt-menu-shadow);
}
[data-workout-menu] .wkt-menu-item {
  display: flex;
  width: 100%;
  align-items: center;
  padding: 0.375rem 0.75rem;
  text-align: left;
  font-size: 0.75rem;
  color: var(--wkt-text);
  background: transparent;
  border: none;
  cursor: pointer;
  transition: background 0.1s ease;
}
[data-workout-menu] .wkt-menu-item:hover {
  background: var(--wkt-menu-item-hover);
}
[data-workout-menu] .wkt-menu-item--icon {
  gap: 0.375rem;
}
[data-workout-menu] .wkt-menu-divider {
  height: 1px;
  background: var(--wkt-menu-divider);
  margin: 0.125rem 0;
}

/* On phones the cards span (nearly) the full width, so a dropdown anchored
   at left: 100% would be pushed past the screen's right edge and become
   invisible. Open it to the left of the control instead. */
@media (max-width: 40rem) {
  [data-workout-menu] {
    left: auto;
    right: 100%;
    margin-left: 0;
    margin-right: 0.25rem;
  }
}

/* ============================================================
   RACE CARD COMPONENT (calendar)
   ============================================================ */

/* The card is a link; this shell holds it together with the control block, which
   cannot live inside the link itself. */
.race-card-shell {
  position: relative;
}

/* Control block of a merged race card, seated where the card has room: the
   priority badge owns the very corner, so the menu drops below it. It rides the
   card's hover lift, otherwise it would drift out of place on hover. */
.race-card__controls {
  position: absolute;
  top: 0.25rem;
  right: 0.25rem;
  z-index: 40;
  transition: translate 0.2s ease;
}

.race-card-shell:hover .race-card__controls {
  translate: 0 var(--wkt-hover-translate-y);
}

.race-card__controls--below-badge {
  top: 1.75rem;
}

.race-card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.375rem;
  padding: 0.3rem 0.5rem;
  background: var(--race-accent-soft, var(--race-card-bg));
  border: 1px solid var(--race-accent-border, var(--race-card-border));
  border-radius: var(--wkt-radius);
  box-shadow: var(--wkt-shadow);
  cursor: pointer;
  text-decoration: none;
  line-height: 1.25;
  transition: all 0.2s ease;
}
.race-card:hover {
  border-color: var(--race-accent);
  box-shadow: var(--wkt-shadow-hover);
  translate: 0 var(--wkt-hover-translate-y);
  z-index: 30;
}
.race-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  border-radius: var(--wkt-radius) 0 0 var(--wkt-radius);
  background: var(--race-accent);
}

.race-card--a,
.race-priority--a {
  --race-accent: #ef4444;
  --race-accent-soft: rgba(239, 68, 68, 0.08);
  --race-accent-border: rgba(239, 68, 68, 0.4);
}
.race-card--b,
.race-priority--b {
  --race-accent: #f59e0b;
  --race-accent-soft: rgba(245, 158, 11, 0.08);
  --race-accent-border: rgba(245, 158, 11, 0.4);
}
.race-card--c,
.race-priority--c {
  --race-accent: #3b82f6;
  --race-accent-soft: rgba(59, 130, 246, 0.08);
  --race-accent-border: rgba(59, 130, 246, 0.4);
}
.race-card--none,
.race-priority--none {
  --race-accent: var(--color-brand);
  --race-accent-soft: var(--color-brand-light);
  --race-accent-border: rgba(230, 198, 25, 0.4);
}

.race-card__badge {
  position: absolute;
  top: 0.3125rem;
  right: 0.3125rem;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.25rem;
  border-radius: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  color: #ffffff;
  background: var(--race-accent);
}

.race-card__icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 0.375rem;
  background: var(--race-accent);
  color: #ffffff;
}
.race-card--none .race-card__icon {
  color: var(--color-txt-on-brand);
}
.race-card__icon svg {
  width: 1.375rem;
  height: 1.375rem;
}

/* Sport discipline icon pinned to the bottom-right corner of the card */
.race-card__sport {
  position: absolute;
  right: 0.3125rem;
  bottom: 0.3125rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 9999px;
  background: var(--race-card-bg);
  color: var(--race-accent);
  box-shadow: 0 0 0 1px var(--race-accent-border);
}
.race-card__sport svg {
  width: 0.75rem;
  height: 0.75rem;
}

/* Drag & drop states */
.race-card--dragging {
  opacity: 0.45;
}
.cal-cell--drop {
  background: rgba(var(--color-brand-rgb), 0.08) !important;
  box-shadow: inset 0 0 0 2px rgba(var(--color-brand-rgb), 0.55);
}

.race-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
  flex: 1;
  padding-right: 1.75rem;
}

.race-card__name {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--wkt-text);
  word-break: break-word;
  line-height: 1.2;
}

.race-card__meta {
  font-size: 0.6875rem;
  color: var(--wkt-text-muted);
  line-height: 1.2;
  word-break: break-word;
}

.race-card__countdown {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  width: fit-content;
  padding: 0.125rem 0.5rem;
  border-radius: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--race-accent);
  background: var(--race-accent-soft);
}
.race-card__countdown svg {
  width: 0.75rem;
  height: 0.75rem;
}

.race-card:focus-visible {
  outline: 2px solid var(--race-accent);
  outline-offset: 1px;
}

/* Race form result boxes: hide native number spinners so values center cleanly */
.race-result-input::-webkit-inner-spin-button,
.race-result-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.race-result-input {
  -moz-appearance: textfield;
  appearance: textfield;
}

/* Race form event URL: quiet go-button tucked inside the input's right edge */
.race-url-btn {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0.375rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  border: none;
  border-radius: 0.25rem;
  background: transparent;
  color: var(--color-txt-dim);
  cursor: pointer;
}
.race-url-btn:hover {
  color: var(--color-brand);
}
.race-url-btn--active {
  color: var(--color-brand);
}

/* Quiet event link chip (saved URL) */
.race-event-link {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 100%;
  padding: 0.1875rem 0.625rem;
  border-radius: 9999px;
  background: var(--color-panel-muted);
  border: 1px solid var(--color-border-light);
  color: var(--color-txt-muted);
  font-size: 0.6875rem;
  text-decoration: none;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.race-event-link:hover {
  color: var(--color-brand);
  border-color: var(--color-border-strong);
}
.race-event-link span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 14rem;
}

.race-link-edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 0.25rem;
  padding: 0.25rem;
  border: none;
  border-radius: 0.25rem;
  background: transparent;
  color: var(--color-txt-dim);
  cursor: pointer;
}
.race-link-edit:hover {
  color: var(--color-brand);
}

/* Quiet "add link" affordance when no URL is set */
.race-add-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  padding: 0.25rem 0.5rem;
  border: 1px dashed var(--color-border-strong);
  border-radius: 0.375rem;
  background: transparent;
  color: var(--color-txt-muted);
  font-size: 0.75rem;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.race-add-link:hover {
  color: var(--color-brand);
  border-color: var(--color-brand);
}

/* Dark theme: brighter accents for readability on dark surfaces */
[data-theme="dark"] .race-card--a,
[data-theme="dark"] .race-priority--a {
  --race-accent: #f87171;
  --race-accent-soft: rgba(248, 113, 113, 0.12);
  --race-accent-border: rgba(248, 113, 113, 0.45);
}
[data-theme="dark"] .race-card--b,
[data-theme="dark"] .race-priority--b {
  --race-accent: #fbbf24;
  --race-accent-soft: rgba(251, 191, 36, 0.12);
  --race-accent-border: rgba(251, 191, 36, 0.45);
}
[data-theme="dark"] .race-card--c,
[data-theme="dark"] .race-priority--c {
  --race-accent: #60a5fa;
  --race-accent-soft: rgba(96, 165, 250, 0.12);
  --race-accent-border: rgba(96, 165, 250, 0.45);
}
[data-theme="dark"] .race-card--none,
[data-theme="dark"] .race-priority--none {
  --race-accent: var(--color-brand);
  --race-accent-soft: var(--color-brand-light);
  --race-accent-border: rgba(245, 215, 66, 0.45);
}

/* ============================================================
   GLOBAL: text on white/light backgrounds is always dark
   ============================================================ */

/* Light theme: `text-white` on white bg would be invisible */
.bg-panel-main.text-white,
.bg-panel-elevated.text-white,
.bg-white.text-white,
.bg-panel-muted.text-white {
  color: var(--color-txt-main);
}

/* Dark theme: `bg-white` elements use dark text (white bg is always light)
   Catches tabs with `bg-white text-txt-main` where `--color-txt-main`
   resolves to light gray in dark mode, making text invisible on white. */
[data-theme="dark"] .bg-white {
  color: var(--color-txt-on-brand);
}

/* ============================================================
   GLOBAL: text on brand-colored backgrounds is always dark
   ============================================================ */
.bg-brand.text-white,
.view-switcher-btn.active {
  color: var(--color-txt-on-brand);
}

/* ============================================================
   CRM — TASK SCOPE SEGMENTED CONTROL
   Distinct control family from .view-switcher-btn (view modes):
   pill-shaped, grouped on a muted track. The selected state uses
   an elevated surface pill (white in light theme, elevated dark
   in dark theme) — never the brand fill, so filters stay visually
   distinct from the gold "New task" button.
   ============================================================ */
.task-scope-group {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--color-border-light);
  border-radius: 999px;
  background: var(--color-panel-muted);
}

.task-scope-btn {
  display: inline-flex;
  align-items: center;
  padding: 0.375rem 0.875rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: var(--fs-body, 0.875rem);
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-txt-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.15s ease, color 0.15s ease,
    box-shadow 0.15s ease;
}

.task-scope-btn:hover {
  color: var(--color-txt-main);
  background: var(--color-brand-light);
}

.task-scope-btn:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
}

.task-scope-btn.active {
  background: var(--color-panel-elevated);
  color: var(--color-txt-main);
  border-color: var(--color-border-strong);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.task-scope-btn.active:hover {
  background: var(--color-panel-elevated);
  border-color: var(--color-border-strong);
}

/* Centers the scope pills between the edge buttons. The pills are
   absolutely centered on desktop; on small screens they drop to a
   centered row below so they never overlap the edge buttons. */
.task-scope-wrap {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

@media (max-width: 767px) {
  .task-scope-wrap {
    position: static;
    transform: none;
    display: flex;
    justify-content: center;
    margin-top: 0.75rem;
  }
}

/* ============================================================
   CRM CALENDAR — task mini-cards (month / week / day grids)
   Theme-aware card surface with a 3px priority accent on the
   left border and a completion checkbox on the right. The whole
   card is draggable; the checkbox toggles the task status.
   ============================================================ */
.crm-task-card {
  display: flex;
  align-items: flex-start;
  gap: 0.25rem;
  min-width: 0;
  margin-bottom: 0.25rem;
  padding: 0.125rem 0.375rem 0.125rem 0.25rem;
  border: 1px solid var(--color-border-light);
  border-left: 3px solid transparent;
  border-radius: 0.375rem;
  background: var(--color-panel-main);
  color: var(--color-txt-main);
  font-size: 0.6875rem;
  line-height: 1.3;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color 0.12s ease, border-color 0.12s ease, opacity 0.12s ease;
}
.crm-task-card:active {
  cursor: grabbing;
}
.crm-task-card:hover {
  background: var(--color-panel-muted);
}
.crm-task-card.is-completed {
  opacity: 0.55;
}
.crm-task-title {
  flex: 1;
  min-width: 0;
  font-weight: 500;
  /* Long titles wrap inside the fixed day column instead of widening it. */
  overflow-wrap: anywhere;
  word-break: break-word;
  white-space: normal;
  line-height: 1.3;
}
.crm-task-card.is-completed .crm-task-title {
  text-decoration: line-through;
}
.crm-task-time {
  flex-shrink: 0;
  margin-top: 0.0625rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.625rem;
  line-height: 1.25;
  color: var(--color-txt-muted);
}
.crm-task-check {
  flex-shrink: 0;
  width: 0.875rem;
  height: 0.875rem;
  margin: 0.0625rem 0 0;
  accent-color: var(--color-brand);
  cursor: pointer;
}
.crm-task-check:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}

/* ============================================================
   NAV / SIDEBAR ACTIVE STATE — theme-independent class
   Uses --nav-active-bg and --nav-active-text tokens that
   differ between light and dark themes.
   ============================================================ */
.nav-active {
  background-color: var(--nav-active-bg);
  color: var(--nav-active-text);
}

/* ============================================================
   SIDEBAR FRAME — how much room the menu takes from the page
   Expanded, the panel keeps a side gutter so its rows (the toggle
   and the links) stand off the panel edge. Collapsed, that gutter
   goes away: the rail is only as wide as its icon column (the
   sidebar controller sets the width), so the page takes back
   nearly the whole width the menu held.
   These gutters live here rather than in Tailwind utilities because
   this file loads after the build and the collapsed state has to
   override the expanded one.
   ============================================================ */
.app-sidebar {
  padding-inline: 0;
}

@media (min-width: 768px) {
  .app-sidebar {
    margin-left: 0.5rem;
    padding-inline: 0.5rem;
  }
}

/* Collapsed rail: no side padding, so nothing stands between the icon column
   and the page gutter. Two classes beat the rule above, media query included. */
.app-sidebar.is-collapsed {
  padding-inline: 0;
}

/* ============================================================
   SIDEBAR COLLAPSE / EXPAND TOGGLE
   Sits at the top of the coach sidebar (athlete pages and the
   payments section). A row exactly like the links below it, so
   its icon lines up with theirs; both state icons live in the
   button and the class the sidebar controller toggles decides
   which one shows.
   Colours come from the theme tokens only — the icon is drawn in
   the same muted/main text colours as every other app icon, so it
   stays legible on the light panel and in the dark theme (brand
   yellow would wash out on white).
   ============================================================ */
.sidebar-toggle {
  display: flex;
  align-items: center;
  /* Same row rhythm as the nav links below. */
  padding: 0.625rem 0.75rem;
  margin: 0 0 0.75rem;
  border: none;
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.sidebar-toggle:hover {
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
}
.sidebar-toggle:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
}
/* Collapsed rail: the toggle is its only row, so it centers there and reads a
   touch stronger than the links do when they are in view. */
.sidebar-toggle.is-collapsed {
  justify-content: center;
  padding-inline: 0;
  color: var(--color-txt-main);
}
/* Expanded rail: fold the panel away — the chevron points left. */
.sidebar-toggle__icon--expand {
  display: none;
}
/* Collapsed rail: bring it back — the chevron points right. */
.sidebar-toggle.is-collapsed .sidebar-toggle__icon--expand {
  display: block;
}
.sidebar-toggle.is-collapsed .sidebar-toggle__icon--collapse {
  display: none;
}

/* ============================================================
   FORM ELEMENTS — date picker icons, accent colors, focus
   ============================================================ */

/* Accent color for checkboxes, radio, range, progress */
input[type="checkbox"],
input[type="radio"],
input[type="range"] {
  accent-color: var(--color-brand);
}

/* Date picker calendar icon */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  opacity: 0.85;
  cursor: pointer;
  transition: opacity 0.15s ease;
  filter: var(--date-icon-filter, none);
}

input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}

/* Dark theme: gold calendar icon in the race date field (native black icon is hidden) */
[data-theme="dark"] input.themed-date-input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f5d742' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.5rem center;
  background-size: 1rem 1rem;
}
[data-theme="dark"] input.themed-date-input::-webkit-calendar-picker-indicator {
  opacity: 0;
}

/* Select element dropdown — themed appearance */
select {
  appearance: auto;
  background-color: var(--color-panel-main);
  color: var(--color-txt-main);
  border-color: var(--color-border-light);
}

/* Select dropdown listbox (WebKit/Blink: Chrome, Edge, Safari) */
select::-webkit-listbox {
  background-color: var(--color-panel-main);
  color: var(--color-txt-main);
}

/* Select option styling */
select option {
  background-color: var(--color-panel-main);
  color: var(--color-txt-main);
}

/* Selected/highlighted option
   — Firefox: fully supported (hover + selected uses brand gold)
   — Chromium/WebKit: selected state uses brand gold via :checked,
     but hover color is OS-native and cannot be overridden by CSS */
select option:checked {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
}

/* Firefox-only: hover highlight on options */
@supports (-moz-appearance: none) {
  select option:hover,
  select option:active,
  select option:focus {
    background: var(--color-brand);
    color: var(--color-txt-on-brand);
  }
}

/* Focus ring for all form elements */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}

/* ============================================================
   RPE — how hard the session felt, as ten discrete steps
   ============================================================ */

/* Fixed-column form table: planned/actual halves must be exactly 50/50 */
.wkt-form-table td {
  box-sizing: border-box;
}

/* The block has two shapes, sharing one set of children (markup in
   shared/_rpe_rating):

     expanded   the ten-step ladder, open while the athlete has not answered;
     collapsed  a single line stating the rating, with "Change" to reopen it.

   The ladder is a staircase, not a row of even buttons: step 1 is the shortest
   and step 10 the tallest, so effort is read from the shape before any colour is
   read. The compact line keeps a miniature of the same staircase, which is how
   a coach sees how high the athlete rated the session.

   It carries no frame and no panel of its own. Every neighbour on these screens
   is a boxed card, so the one bare line — and the ten steps it opens into — is
   what takes the eye. Callers own the spacing around it.

   A wrapping flex row is what makes both shapes possible: the steps take a line
   of their own while there is room to pick, and fold into a compact meter once
   the block is only reporting a value. */
.rpe {
  /* Hue of the rating on the effort ladder. The ten `data-rpe-value` rules
     below set it, and everything the block writes in colour derives from it, so
     the number, its wording and the action can never drift apart. 210 is a
     neutral fallback for the unrated state, which stays muted anyway. */
  --rpe-h: 210;
  --rpe-ink: hsl(var(--rpe-h), 60%, 34%);
  /* Height of one rung: step n stands `base + (n - 1) * rise` tall. Both shapes
     share the ramp and differ only in its scale, so the miniature stays honest. */
  --rpe-bar-base: 18px;
  --rpe-bar-rise: 3px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 10px;
  row-gap: 7px;
  padding: 6px 0;
}

[data-theme="dark"] .rpe {
  --rpe-ink: hsl(var(--rpe-h), 70%, 66%);
}

/* Effort ladder: 1 (very easy, green) → 10 (maximum, red). The root and the
   steps share the hues, so the picked step matches the value it stands for. */
.rpe[data-rpe-value="1"], .rpe__seg:nth-child(1) { --rpe-h: 120; }
.rpe[data-rpe-value="2"], .rpe__seg:nth-child(2) { --rpe-h: 107; }
.rpe[data-rpe-value="3"], .rpe__seg:nth-child(3) { --rpe-h: 93; }
.rpe[data-rpe-value="4"], .rpe__seg:nth-child(4) { --rpe-h: 80; }
.rpe[data-rpe-value="5"], .rpe__seg:nth-child(5) { --rpe-h: 67; }
.rpe[data-rpe-value="6"], .rpe__seg:nth-child(6) { --rpe-h: 53; }
.rpe[data-rpe-value="7"], .rpe__seg:nth-child(7) { --rpe-h: 40; }
.rpe[data-rpe-value="8"], .rpe__seg:nth-child(8) { --rpe-h: 27; }
.rpe[data-rpe-value="9"], .rpe__seg:nth-child(9) { --rpe-h: 13; }
.rpe[data-rpe-value="10"], .rpe__seg:nth-child(10) { --rpe-h: 0; }

/* Rung of the staircase, kept apart from the hues above: one axis per block, so
   either can be retuned without reading the other. */
.rpe__seg:nth-child(1)  { --rpe-rung: 1; }
.rpe__seg:nth-child(2)  { --rpe-rung: 2; }
.rpe__seg:nth-child(3)  { --rpe-rung: 3; }
.rpe__seg:nth-child(4)  { --rpe-rung: 4; }
.rpe__seg:nth-child(5)  { --rpe-rung: 5; }
.rpe__seg:nth-child(6)  { --rpe-rung: 6; }
.rpe__seg:nth-child(7)  { --rpe-rung: 7; }
.rpe__seg:nth-child(8)  { --rpe-rung: 8; }
.rpe__seg:nth-child(9)  { --rpe-rung: 9; }
.rpe__seg:nth-child(10) { --rpe-rung: 10; }

.rpe__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-txt-main);
}

.rpe__readout {
  display: flex;
  flex: 1 1 auto;
  align-items: baseline;
  justify-content: flex-end;
  gap: 7px;
  min-width: 0;
}

.rpe__value {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--rpe-ink);
}

/* The unrated state renders an empty number: it should take no room. */
.rpe__value:empty {
  display: none;
}

.rpe__desc {
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--rpe-ink);
}

/* A plain statement (a coach looking at an unrated session) is not a question,
   so it stays muted instead of taking the rating's colour. */
.rpe--no-value .rpe__value,
.rpe--no-value .rpe__desc {
  color: var(--color-txt-muted);
}

.rpe__prompt {
  display: none;
}

.rpe__bar {
  flex: 1 1 100%;
}

.rpe__segs {
  display: flex;
  /* Steps rise from a shared baseline, so the row reads as a staircase rather
     than as a line of pills. */
  align-items: flex-end;
  gap: 4px;
}

.rpe__seg {
  /* A step carries its own hue from the rules above, so the ladder reads as the
     effort scale itself. These follow that step and not the rating: a given
     step must look the same whatever the current value happens to be. */
  --rpe-step-ink: hsl(var(--rpe-h), 60%, 34%);
  --rpe-step-wash: hsla(var(--rpe-h), 60%, 50%, 0.16);
  /* Deep enough to carry a white digit at every hue — the yellow steps are
     where a brighter fill would start failing the contrast. The meter borrows
     the same colour. */
  --rpe-step-fill: hsl(var(--rpe-h), 62%, 30%);
  --rpe-rung: 1;
  position: relative;
  flex: 1 1 0;
  /* Set by the rung rules above: the climb is the point of the control. */
  height: calc(var(--rpe-bar-base) + (var(--rpe-rung) - 1) * var(--rpe-bar-rise));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

[data-theme="dark"] .rpe__seg {
  --rpe-step-ink: hsl(var(--rpe-h), 70%, 66%);
  --rpe-step-wash: hsla(var(--rpe-h), 60%, 55%, 0.22);
}

/* A step is a real radio. The input is invisible but keeps the step's hit area
   and the focus ring, so pointer, tapping, tabbing and arrow keys all work
   without extra script. */
.rpe__seg-input {
  appearance: none;
  -webkit-appearance: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: inherit;
  background: transparent;
  cursor: pointer;
}

.rpe__seg-face {
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

/* Open ladder: every step shows its own colour and its own height, and the
   picked one lifts out of the row while the rest step back. */
.rpe--expanded .rpe__seg {
  background: var(--rpe-step-wash);
  color: var(--rpe-step-ink);
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease,
    box-shadow 0.15s ease, opacity 0.15s ease;
}

.rpe--expanded .rpe__seg:hover {
  background: hsla(var(--rpe-h), 62%, 50%, 0.3);
}

.rpe--expanded .rpe__seg.is-picked {
  background: var(--rpe-step-fill);
  color: #fff;
  /* The mark rises above the baseline it was set on: the effort climbing is the
     gesture the athlete is making. */
  transform: translateY(-4px);
  box-shadow: 0 3px 8px hsla(var(--rpe-h), 60%, 25%, 0.35);
}

/* An answer exists: the rest of the row recedes, so the rating is the one thing
   still in colour. */
.rpe--expanded .rpe__segs:has(.is-picked) .rpe__seg:not(.is-picked) {
  opacity: 0.5;
}

/* Answered: the same steps fold into a meter, digits dropped, the filled part
   keeping the effort gradient up to the rating. */
.rpe.rpe--collapsed {
  /* The staircase stays, at miniature scale: 4px rising to 13px. A coach reads
     the height of the climb, not only the number. */
  --rpe-bar-base: 4px;
  --rpe-bar-rise: 1px;
}

.rpe--collapsed .rpe__bar {
  flex: 0 0 78px;
}

.rpe--collapsed .rpe__segs {
  gap: 2px;
}

.rpe--collapsed .rpe__seg {
  border-radius: 2px;
  background: var(--color-border-light);
}

.rpe--collapsed .rpe__seg.is-on {
  background: var(--rpe-step-fill);
}

.rpe--collapsed .rpe__seg-face {
  display: none;
}

/* The scale's end words belong to the open ladder; the collapsed line says the
   rating in words already. */
.rpe--collapsed .rpe__foot {
  display: none;
}

/* The sliver can be 4px tall, so the input grows back the rest of a 24px
   target. */
.rpe--collapsed .rpe__seg-input {
  top: 50%;
  height: 24px;
  transform: translateY(-50%);
}

.rpe__foot {
  display: flex;
  flex: 1 1 100%;
  justify-content: space-between;
  gap: 8px;
  font-size: 10px;
  font-weight: 500;
  color: var(--color-txt-muted);
}

/* The action is a line of text carrying the rating's own colour: no box of its
   own to compete with the ladder. A permanent underline keeps it readable as
   something to press without drawing a frame around it. */
.rpe__change {
  display: none;
  flex: 0 0 auto;
  align-items: center;
  gap: 5px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--rpe-ink);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
}

.rpe--collapsed .rpe__change {
  display: inline-flex;
}

/* The underline sits on the label, not on the button: text decoration is not
   propagated into the items of a flex container. */
.rpe__change-label {
  text-decoration: underline;
  text-decoration-color: hsla(var(--rpe-h), 60%, 50%, 0.45);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s ease;
}

.rpe__change:hover .rpe__change-label {
  text-decoration-color: currentColor;
}

.rpe__change:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
  border-radius: 3px;
}

.rpe__error {
  flex: 1 1 100%;
  margin: 0;
  font-size: 11.5px;
  font-weight: 500;
  color: #ef4444;
}

.rpe__error:empty {
  display: none;
}

/* Unrated and the athlete's to rate. No frame and no tint to announce it: the
   question takes the first line on its own and breathes, and the steps take
   their strongest wash — a rising staircase of colour is the loudest thing on a
   page of grey cards. */
.rpe--invite .rpe__eyebrow {
  display: none;
}

.rpe--invite .rpe__readout {
  justify-content: flex-start;
}

.rpe--invite .rpe__prompt {
  display: block;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--color-txt-main);
  animation: rpe-ask 3.6s ease-in-out infinite;
}

.rpe--invite .rpe__value,
.rpe--invite .rpe__desc {
  display: none;
}

.rpe--invite .rpe__seg {
  background: hsla(var(--rpe-h), 68%, 50%, 0.3);
}

@keyframes rpe-ask {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}

@media (prefers-reduced-motion: reduce) {
  .rpe--invite .rpe__prompt {
    animation: none;
  }
}

/* A coach reads the athlete's effort; the block states it and never asks. */
.rpe--readonly .rpe__seg,
.rpe--readonly .rpe__seg-input {
  cursor: default;
}

.rpe--readonly .rpe__change {
  display: none;
}

@media (max-width: 420px) {
  .rpe--collapsed {
    column-gap: 8px;
  }

  .rpe--collapsed .rpe__bar {
    flex: 0 0 54px;
  }
}

/* Selection highlight */
::selection {
  background-color: rgba(var(--color-brand-rgb), 0.25);
  color: var(--color-txt-main);
}

/* ============================================================
   CUSTOM SELECT — full themed dropdown replacing native <select>
   Triggered by data-controller="custom-select"
   ============================================================ */
.custom-select {
  position: relative;
  width: 100%;
}

.custom-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  padding: 0.375rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  cursor: pointer;
  line-height: 1.4;
  text-align: left;
  transition: border-color 0.15s, box-shadow 0.15s;
  user-select: none;
}
.custom-select__trigger:hover {
  border-color: var(--color-border-strong);
}
.custom-select__trigger--open {
  border-color: var(--color-brand);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.15);
}

.custom-select__value {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-select__arrow {
  flex-shrink: 0;
  opacity: 0.5;
  transition: transform 0.2s ease;
}
.custom-select__trigger--open .custom-select__arrow {
  transform: rotate(180deg);
}

.custom-select__options {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 2px;
  z-index: 100;
  max-height: 200px;
  overflow-y: auto;
  background: var(--color-panel-elevated);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-popover);
}
.custom-select__options--open {
  display: block;
}

.custom-select__option {
  padding: 0.375rem 0.625rem;
  font-size: 0.75rem;
  color: var(--color-txt-main);
  cursor: pointer;
  transition: background 0.1s;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.custom-select__option:hover,
.custom-select__option--focused {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
}
.custom-select__option--selected {
  font-weight: 600;
  background: rgba(var(--color-brand-rgb), 0.1);
  color: var(--color-brand);
}
.custom-select__option--selected:hover {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
}
.custom-select__option--disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.custom-select__option--disabled:hover {
  background: transparent;
  color: var(--color-txt-main);
}

/* Optional search box (data-custom-select-search-value="true") — filters the
   options by name while typing. */
.custom-select__search {
  width: 100%;
  padding: 0.375rem 0.5rem;
  margin-bottom: 2px;
  font-size: 0.75rem;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  box-sizing: border-box;
}
.custom-select__search:focus {
  outline: none;
  border-color: var(--color-brand);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.15);
}
.custom-select__option--hidden {
  display: none;
}

/* ============================================================
   DISTANCE SELECT — themed combobox for the race distance field.
   Same visual language as custom-select, but stays a text input
   so custom distances can still be typed.
   ============================================================ */
.distance-select__trigger {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  padding: 0;
  color: var(--color-txt-muted);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color 0.15s;
}
.distance-select__trigger:hover {
  color: var(--color-txt-main);
}

.distance-select__arrow {
  opacity: 0.5;
  transition: transform 0.2s ease;
}
.distance-select__trigger--open .distance-select__arrow {
  transform: rotate(180deg);
}

.distance-select__options {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 2px;
  z-index: 100;
  max-height: 200px;
  overflow-y: auto;
  background: var(--color-panel-elevated);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-popover);
}
.distance-select__options--open {
  display: block;
}

.distance-select__option {
  padding: 0.375rem 0.625rem;
  font-size: 0.75rem;
  color: var(--color-txt-main);
  cursor: pointer;
  transition: background 0.1s;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.distance-select__option:hover,
.distance-select__option--focused {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
}

/* ============================================================
   THEME TOGGLE BUTTON
   ============================================================ */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-btn);
  border: 1px solid var(--theme-toggle-border);
  background: var(--theme-toggle-bg);
  color: var(--theme-toggle-color);
  cursor: pointer;
  transition: all 0.15s ease;
  padding: 0;
  line-height: 1;
}
.theme-toggle:hover {
  background: var(--theme-toggle-hover-bg);
  color: var(--theme-toggle-hover-color);
  border-color: var(--color-brand);
}

/* Segmented option buttons (theme / language pickers on the Appearance settings tab) */
.picker-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.375rem 1.25rem;
  font-size: var(--fs-small);
  border-radius: 9999px;
  border: 0;
  background: transparent;
  color: var(--color-txt-muted);
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.15s ease;
}
.picker-btn:hover {
  background: var(--color-panel-main);
  color: var(--color-txt-main);
}
.picker-btn.active {
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
  font-weight: 600;
}

/* ============================================================
   INFO / FOCUS BARS
   ============================================================ */
/* Compact plan ribbon: one hairline row, a color rail instead of a dot, and
   an ellipsis on the facts run so a long plan name never wraps the bar into
   a second line. */
.info-bar {
  --macro-color: var(--info-bar-accent);
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.375rem 0.25rem 0.625rem;
  margin-bottom: 0.5rem;
  border: 1px solid color-mix(in srgb, var(--macro-color) 28%, var(--color-border-light));
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--macro-color) 6%, var(--color-panel-main));
  font-size: var(--fs-micro);
  line-height: 1.5;
  color: var(--info-bar-text);
  overflow: hidden;
}
.info-bar::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--macro-color);
}
.info-bar-model {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 35%;
  font-weight: 600;
  /* Pulled toward the text colour so pale macrocycle colours stay readable;
     the rail keeps the plan's own colour untouched. */
  color: color-mix(in srgb, var(--macro-color) 55%, var(--color-txt-main));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.info-bar-facts {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.info-bar-sep {
  opacity: 0.5;
  margin: 0 0.125rem;
}
/* The main race: a flag in the priority color, the name in full-text color,
   so it is the one thing on the ribbon that reads as an event. */
.info-bar-race {
  flex: 0 1 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
  color: var(--race-accent, var(--color-brand));
}
.info-bar-race-name {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 600;
  color: var(--color-txt-main);
}
.info-bar-race-date {
  flex-shrink: 0;
  color: var(--color-txt-muted);
}
.info-bar-detach {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  margin-right: -0.125rem;
  padding: 0.25rem;
  border-radius: 0.25rem;
  color: var(--color-txt-muted);
  transition: color 0.15s ease, background-color 0.15s ease;
}
.info-bar-detach:hover {
  color: #ef4444;
  background: rgba(239, 68, 68, 0.12);
}
/* Inset ring: the ribbon clips overflow, so an outside outline would be cut. */
.info-bar-detach:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: -2px;
}
.info-bar-no-attach {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.5rem;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-sm);
  color: var(--color-txt-muted);
  font-size: var(--fs-micro);
}

/* Focus mode bar */
.focus-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  margin-bottom: 1rem;
  border: 1px solid var(--focus-bar-border);
  border-radius: var(--info-bar-radius);
  background: var(--focus-bar-bg);
  font-size: var(--fs-small);
}
.focus-bar-label {
  font-weight: 600;
  color: var(--color-brand);
}
.focus-bar-name {
  color: var(--color-txt-main);
}
.focus-bar-dates {
  color: var(--color-txt-muted);
}
.focus-bar-clear {
  margin-left: auto;
  color: var(--color-txt-muted);
  text-decoration: underline;
  font-size: var(--fs-small);
}
.focus-bar-clear:hover {
  color: var(--color-txt-main);
}

/* ============================================================
   MODAL WINDOW — darker overlay for dark theme
   Light theme relies on bg-black/30 overlay + default border.
   Dark theme darkens the overlay so the card stands out.
   ============================================================ */
[data-theme="dark"] turbo-frame#modal > .fixed.inset-0 {
  background: rgba(0, 0, 0, 0.8);
}

[data-theme="dark"] turbo-frame#race_form > .fixed.inset-0 {
  background: rgba(0, 0, 0, 0.8);
}

[data-theme="dark"] #create-template-modal > .fixed.inset-0 {
  background: rgba(0, 0, 0, 0.8);
}

/* ============================================================
   PERFORMANCE OVERVIEW — quick picture cards (dark theme)
   Override hardcoded Tailwind light colors for dark mode.
   ============================================================ */
[data-theme="dark"] .grid > a[class*="rounded-2xl"] {
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
[data-theme="dark"] .grid > a[class*="rounded-2xl"]:hover {
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* Goals card */
[data-theme="dark"] a[class*="from-blue-50"] {
  background: linear-gradient(to bottom, rgba(30, 64, 175, 0.55), var(--color-panel-muted)) !important;
}
[data-theme="dark"] a[class*="from-blue-50"] h3 {
  color: #93c5fd !important;
}
[data-theme="dark"] a[class*="from-blue-50"] p {
  color: rgba(147, 197, 253, 0.6) !important;
}
[data-theme="dark"] a[class*="from-blue-50"] [class*="border-t"] {
  border-color: rgba(59, 130, 246, 0.25) !important;
}
[data-theme="dark"] a[class*="from-blue-50"] [class*="text-blue-800"],
[data-theme="dark"] a[class*="from-blue-50"] [class*="text-blue-900"] {
  color: #bfdbfe !important;
}
[data-theme="dark"] a[class*="from-blue-50"] li span[class*="text-blue-900"] {
  color: rgba(191, 219, 254, 0.7) !important;
}
[data-theme="dark"] a[class*="from-blue-50"] [class*="text-blue-600/60"] {
  color: rgba(147, 197, 253, 0.5) !important;
}

/* Races card */
[data-theme="dark"] a[class*="from-emerald-50"] {
  background: linear-gradient(to bottom, rgba(6, 95, 70, 0.55), var(--color-panel-muted)) !important;
}
[data-theme="dark"] a[class*="from-emerald-50"] h3 {
  color: #6ee7b7 !important;
}
[data-theme="dark"] a[class*="from-emerald-50"] p {
  color: rgba(110, 231, 183, 0.6) !important;
}
[data-theme="dark"] a[class*="from-emerald-50"] [class*="border-t"] {
  border-color: rgba(16, 185, 129, 0.25) !important;
}
[data-theme="dark"] a[class*="from-emerald-50"] [class*="text-emerald-800"],
[data-theme="dark"] a[class*="from-emerald-50"] [class*="text-emerald-900"] {
  color: #a7f3d0 !important;
}
[data-theme="dark"] a[class*="from-emerald-50"] li span {
  color: rgba(167, 243, 208, 0.7) !important;
}
[data-theme="dark"] a[class*="from-emerald-50"] [class*="text-emerald-600/60"] {
  color: rgba(110, 231, 183, 0.5) !important;
}

/* Records card */
[data-theme="dark"] a[class*="from-violet-50"] {
  background: linear-gradient(to bottom, rgba(91, 33, 182, 0.55), var(--color-panel-muted)) !important;
}
[data-theme="dark"] a[class*="from-violet-50"] h3 {
  color: #c4b5fd !important;
}
[data-theme="dark"] a[class*="from-violet-50"] p {
  color: rgba(196, 181, 253, 0.6) !important;
}
[data-theme="dark"] a[class*="from-violet-50"] [class*="border-t"] {
  border-color: rgba(139, 92, 246, 0.25) !important;
}
[data-theme="dark"] a[class*="from-violet-50"] [class*="text-violet-800"],
[data-theme="dark"] a[class*="from-violet-50"] [class*="text-violet-900"] {
  color: #ddd6fe !important;
}
[data-theme="dark"] a[class*="from-violet-50"] li span {
  color: rgba(221, 214, 254, 0.7) !important;
}
[data-theme="dark"] a[class*="from-violet-50"] [class*="text-violet-600/60"] {
  color: rgba(196, 181, 253, 0.5) !important;
}

[data-theme="dark"] .grid > a:hover {
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* Dot indicators inside cards */
[data-theme="dark"] .grid .w-2.h-2.rounded-full {
  opacity: 0.9;
}

/* Icon boxes */
[data-theme="dark"] [class*="bg-gradient-to-br from-blue-400 to-blue-600"] {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8) !important;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
}
[data-theme="dark"] [class*="bg-gradient-to-br from-emerald-400 to-emerald-600"] {
  background: linear-gradient(135deg, #34d399, #059669) !important;
  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
}
[data-theme="dark"] [class*="bg-gradient-to-br from-violet-400 to-violet-600"] {
  background: linear-gradient(135deg, #a78bfa, #7c3aed) !important;
  box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);
}

/* ============================================================
   CRM TASKS — overdue row (dark theme)
   Dark theme makes text light by default, which blends into
   light-red overdue background. Force dark text so it’s readable.
   ============================================================ */
[data-theme="dark"] .overdue-row {
  background-color: rgba(239, 68, 68, 0.12) !important;
}
[data-theme="dark"] .overdue-row:hover {
  background-color: rgba(239, 68, 68, 0.2) !important;
}
[data-theme="dark"] .overdue-row td {
  color: #f1f5f9 !important;
}
[data-theme="dark"] .overdue-row td.text-red-600 {
  color: #dc2626 !important;
}

/* ============================================================
   TRAINING PARAMETERS — panel headers (dark theme)
   Light pastel header backgrounds + light text are invisible.
   Use richer dark-tint backgrounds + dark text for readability.
   ============================================================ */
[data-theme="dark"] .panel__header {
  color: #0f172a !important;
}
[data-theme="dark"] .panel--thresholds .panel__header {
  background: #c4b5fd !important;
}
[data-theme="dark"] .panel--zones .panel__header {
  background: #a5b4fc !important;
}
[data-theme="dark"] .panel--cardiovascular .panel__header {
  background: #fda4af !important;
}
[data-theme="dark"] .panel--recovery .panel__header {
  background: #6ee7b7 !important;
}
[data-theme="dark"] .panel--metabolism .panel__header {
  background: #fde68a !important;
}
[data-theme="dark"] .panel--biomechanics .panel__header {
  background: #67e8f9 !important;
}

/* ---- Templates browser: assign-to-calendar button ----
   The button lives in the card's description row (to the right of the
   description text) and is always visible. */

/* ---- Athletes list: hovered row becomes a highlighted band (theme-aware) ----
   Light theme: dark panel background + brand border, so the hover clearly
   reads against the white card. Text turns white, the calendar icon turns
   brand yellow. Dark theme: a slightly elevated surface keeps the band
   visible without the white-card contrast.
   The selectors stay on direct children so nested popovers (the unread
   comment trigger and its day menu) keep their own surface colors. */
.athlete-row {
  border: 1px solid transparent;
}
.athlete-row:hover {
  background: var(--color-panel-dark);
  border-color: var(--color-brand);
}
[data-theme="dark"] .athlete-row:hover {
  background: var(--color-panel-elevated);
}
/* Name link and deactivated badge: white on the dark band */
.athlete-row:hover > div > a {
  color: #ffffff;
}
.athlete-row:hover > div > span {
  color: #ffffff;
  border-color: rgba(255, 255, 255, 0.4);
}
/* Calendar icon: brand yellow */
.athlete-row:hover > div > a svg {
  color: var(--color-brand);
}
/* Unread-comment trigger inside a hovered row: same brand accent as the
   calendar icon, without the hover pill so it stays legible on the band. */
.athlete-row:hover .athlete-unread-comments-trigger,
.athlete-row:hover .athlete-unread-comments-trigger .athlete-unread-comments-count {
  color: var(--color-brand);
  background: transparent;
}
/* Unreviewed performed-workout trigger inside a hovered row: same treatment. */
.athlete-row:hover .athlete-unviewed-activities-trigger,
.athlete-row:hover .athlete-unviewed-activities-trigger .athlete-unviewed-activities-count {
  color: var(--color-brand);
  background: transparent;
}

/* ============================================================
   Athletes index, week mode (athletes/_week_view)
   ============================================================
   A board of athletes × Mon–Sun: one row per athlete, one column per
   weekday, so a coach runs down the athlete column and sees who has an
   empty week, and along a row to see where a training can be moved or
   copied. It is deliberately quieter than the calendar: hairline rules and
   plain surfaces, so the only solid objects are the training cards, which
   are the ones that move.

   Phone: the same board as a thumbnail strip (a filled square = planned,
   outline = free day), the way the month grid reads on a phone. Nothing is
   draggable there (see athletes_week_controller.js). */

/* ---- Week toolbar: navigation left, view toggle right ---- */
.ath-week-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
}

/* ---- Week navigation ---- */
.ath-week-nav {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.ath-week-nav__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 28px;
  color: var(--color-txt-muted);
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: 9999px;
  transition: color 0.15s, background-color 0.15s;
}
.ath-week-nav__btn:hover,
.ath-week-nav__btn:focus-visible {
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
}
.ath-week-nav__range {
  padding: 0 0.375rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-txt-main);
}
.ath-week-nav__dash {
  padding: 0 0.125rem;
  color: var(--color-txt-dim);
}

/* ---- Board frame: fills the content width, so the days get the room their
   cards need ---- */
.ath-week-board {
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-form);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.ath-week-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
}
.ath-week-col-athlete {
  width: 11rem;
}

/* ---- Head row: weekday over the date ---- */
/* Deliberately not sticky: inside this clipped, rounded panel a pinned row is
   pushed down by its own inset and paints over the first group band, which
   reads as two empty header rows. The day labels scroll with the board. */
.ath-week-head {
  padding: 0.5rem 0.25rem 0.4375rem;
  text-align: center;
  vertical-align: bottom;
  background: var(--color-panel-main);
  border-bottom: 1px solid var(--color-border-light);
}
.ath-week-head__weekday {
  display: block;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}
.ath-week-head__date {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.0625rem;
}
.ath-week-head__day {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-txt-main);
}
/* Today's number is the calendar's own today chip (cal-cell-date--today) —
   same chip, same tokens, so "today" reads the same in both boards. */
.ath-week-head__day.is-today {
  background: var(--cal-today-dot-bg);
  color: var(--cal-today-dot-text);
}
.ath-week-head__month {
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--color-txt-muted);
}
.ath-week-head--athlete {
  padding-left: 0.75rem;
  text-align: left;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}
/* Today's column: the calendar's today surface (cal-cell--today), not a tinted
   brand wash — the brand yellow turned it a muddy brown. */
.ath-week-head.is-today {
  background: var(--cal-today-bg);
}

/* ---- Group band: separates one group's rows from the next ---- */
.ath-week-group__cell {
  padding: 0.5rem 0.75rem 0.25rem;
  text-align: left;
  background: var(--color-panel-muted);
  border-top: 1px solid var(--color-border-light);
  border-bottom: 1px solid var(--color-border-light);
}
.ath-week-group__name {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}
.ath-week-group__count {
  margin-left: 0.375rem;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--color-txt-dim);
}

/* ---- Athlete cell: name and its weekly coverage ("N/7") ---- */
.ath-week-athlete {
  padding: 0.4375rem 0.5rem 0.4375rem 0.75rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--color-border-light);
}
.ath-week-athlete__name {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-txt-main);
  text-decoration: none;
}
.ath-week-athlete__name:hover,
.ath-week-athlete__name:focus-visible {
  text-decoration: underline;
}
.ath-week-athlete__coverage {
  display: inline-block;
  margin-top: 0.125rem;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--color-txt-muted);
}
/* An athlete nobody planned for is the reason this mode exists: 0/7 is the
   one thing on the board allowed to shout (same tinted badge as a task
   due date). */
.ath-week-athlete__coverage.is-zero {
  padding: 0.0625rem 0.375rem;
  border-radius: 9999px;
  background: rgba(239, 68, 68, 0.14);
  color: #dc2626;
}

/* ---- Day cells ---- */
.ath-week-cell {
  padding: 0.25rem;
  vertical-align: top;
  border-bottom: 1px solid var(--color-border-light);
  border-left: 1px solid var(--color-border-light);
  /* The cell is a way into that day (athletes-week#openDay). */
  cursor: pointer;
}
/* Today's column: the calendar's today surface (cal-cell--today), not a tinted
   brand wash — the brand yellow turned it a muddy brown. */
.ath-week-cell.is-today {
  background: var(--cal-today-bg);
}
/* Hovering a day reads like hovering a day in the calendar (cal-cell:hover),
   and the focus ring makes the same target reachable from the keyboard. */
.ath-week-cell:hover {
  background-color: var(--cal-cell-hover-bg);
}
.ath-week-cell:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: -2px;
}
.ath-week-cell__cards {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
/* A free day shows the day's own hint on hover: the "+" is the way into that
   day's calendar page, where the training is planned. Pure CSS — the cell's
   is-empty class already follows the cards in and out. */
.ath-week-cell.is-empty .ath-week-cell__cards::after {
  content: "+";
  display: block;
  text-align: center;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.5rem;
  color: var(--color-txt-dim);
  opacity: 0;
  transition: opacity 0.15s;
}
.ath-week-cell.is-empty:hover .ath-week-cell__cards::after {
  opacity: 1;
}
/* Drop highlight: the receiving row and the receiving weekday light up as a
   crosshair, so the target of the drag is never in doubt. */
.ath-week-row.is-drop-row .ath-week-cell {
  background-color: rgba(var(--color-brand-rgb), 0.05);
}
.ath-week-cell.is-drop-column {
  background-color: rgba(var(--color-brand-rgb), 0.12);
}
.ath-week-row.is-drop-row .ath-week-cell.is-drop-column {
  background-color: rgba(var(--color-brand-rgb), 0.2);
  outline: 2px dashed var(--color-brand);
  outline-offset: -2px;
}

/* ---- Card: a start (race) or a planned workout ---- */
.ath-week-card {
  display: flex;
  align-items: flex-start;
  gap: 0.3125rem;
  padding: 0.1875rem 0.25rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.25rem;
  background: var(--color-panel-muted);
  cursor: grab;
}
.ath-week-card:active {
  cursor: grabbing;
}
.ath-week-card__icon {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  color: var(--color-txt-muted);
}
.ath-week-card__icon svg {
  width: 13px;
  height: 13px;
}
.ath-week-card__body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.ath-week-card__name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-txt-main);
}
.ath-week-card__meta {
  font-size: 0.6875rem;
  color: var(--color-txt-muted);
}
.ath-week-card__sep {
  padding: 0 0.125rem;
  color: var(--color-txt-dim);
}
.ath-week-card__badge {
  margin-left: auto;
  padding: 0 0.1875rem;
  border-radius: 0.1875rem;
  font-size: 0.5625rem;
  font-weight: 700;
  color: #ffffff;
  background: var(--race-accent-week);
}
.ath-week-card__hidden {
  display: inline-flex;
  align-items: center;
  margin-left: auto;
  color: var(--color-txt-muted);
}
/* A start is not a training to copy, and it keeps the calendar's race colors:
   the priority (A red, B amber, C blue) is what the coach plans a week around,
   and the flag marks the entry as something that stays put. */
.ath-week-race {
  --race-accent-week: #64748b;
  --race-accent-week-soft: rgba(100, 116, 139, 0.08);
  --race-accent-week-border: rgba(100, 116, 139, 0.4);
}
.ath-week-race--a {
  --race-accent-week: #ef4444;
  --race-accent-week-soft: rgba(239, 68, 68, 0.08);
  --race-accent-week-border: rgba(239, 68, 68, 0.4);
}
.ath-week-race--b {
  --race-accent-week: #f59e0b;
  --race-accent-week-soft: rgba(245, 158, 11, 0.08);
  --race-accent-week-border: rgba(245, 158, 11, 0.4);
}
.ath-week-race--c {
  --race-accent-week: #3b82f6;
  --race-accent-week-soft: rgba(59, 130, 246, 0.08);
  --race-accent-week-border: rgba(59, 130, 246, 0.4);
}
.ath-week-card--race {
  background: var(--race-accent-week-soft);
  border: 1px solid var(--race-accent-week-border);
  cursor: default;
}
.ath-week-card--race .ath-week-card__icon,
.ath-week-card--race .ath-week-card__name,
.ath-week-card--race .ath-week-card__meta {
  color: var(--race-accent-week);
}
/* Hidden from the athlete: still on the board (the day is planned) but drawn
   as a plan the athlete cannot see. */
.ath-week-card.is-hidden-plan {
  border-style: dashed;
  opacity: 0.72;
}
.ath-week-card--ghost {
  opacity: 0.3;
  background: rgba(var(--color-brand-rgb), 0.18);
}
.ath-week-card--drag {
  cursor: grabbing;
  box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.28);
}

/* "+N": the rest of the day, behind the day's own calendar page. */
.ath-week-cell__more {
  padding: 0.0625rem 0;
  border-radius: 0.25rem;
  text-align: center;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--color-txt-muted);
  text-decoration: none;
}
.ath-week-cell__more:hover,
.ath-week-cell__more:focus-visible {
  background: var(--color-panel-muted);
  color: var(--color-txt-main);
}
/* Cards beyond CARDS_PER_DAY (Athletes::WeekBoard) stay in the DOM behind
   "+N" — the controller appends a copy there, and this keeps the cell shape. */
.ath-week-cell__cards.is-capped .ath-week-card:nth-child(n + 4) {
  display: none;
}

/* ---- Drag intent: what the drop will do, where ---- */
.ath-week-intent {
  display: none;
  position: fixed;
  z-index: 80;
  transform: translate(0.875rem, 0.875rem);
  padding: 0.3125rem 0.5rem;
  border-radius: var(--radius-btn);
  background: var(--color-panel-dark);
  color: #ffffff;
  font-size: 0.75rem;
  font-weight: 600;
  pointer-events: none;
  box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.25);
}
.ath-week-intent.is-visible {
  display: block;
}
[data-theme="dark"] .ath-week-intent {
  background: var(--color-panel-elevated);
  color: var(--color-txt-main);
  border: 1px solid var(--color-border-strong);
}

/* ---- Hint: athletes the board cannot show (no group) ---- */
.ath-week-hint {
  margin-top: 0.75rem;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
.ath-week-hint a {
  font-weight: 600;
  color: var(--color-txt-main);
}

/* ---- Phone: the week as a thumbnail strip ---- */
.ath-week-cell__mini {
  display: none;
}
.ath-week-mini {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1.375rem;
  border-radius: 0.25rem;
  background: var(--color-accent);
  color: #ffffff;
  font-size: 0.625rem;
  font-weight: 700;
}
.ath-week-mini--empty {
  background: transparent;
  border: 1px dashed var(--color-border-strong);
}
/* A start owns its day: outlined, not filled, so the week's races stay visible
   in the thumbnail. */
.ath-week-mini--race {
  border: 2px solid var(--race-accent-week);
  background: var(--race-accent-week-soft);
  color: var(--race-accent-week);
}
.ath-week-mini.is-hidden {
  background: transparent;
  border: 1px dashed var(--color-border-strong);
  color: var(--color-txt-dim);
}

@media (max-width: 40rem) {
  .ath-week-col-athlete {
    width: 6.5rem;
  }
  .ath-week-head--athlete {
    font-size: 0.5625rem;
  }
  .ath-week-athlete {
    padding: 0.375rem 0.3125rem 0.375rem 0.5rem;
  }
  .ath-week-athlete__name {
    font-size: 0.75rem;
  }
  .ath-week-cell {
    padding: 0.1875rem;
  }
  /* Cards are the desktop reading; on a phone the same day is a square. */
  .ath-week-cell__cards {
    display: none;
  }
  .ath-week-cell__mini {
    display: block;
    text-decoration: none;
  }
}

/* ---- Strength workout form: compact duration ----
   The duration label and time clock sit on one line to save vertical space
   (added by activities-strength-form#applyDurationEditability). */
[data-wk-metric="duration"].strength-duration {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 0.5rem;
  width: auto;
  max-width: none;
}
[data-wk-metric="duration"].strength-duration label {
  margin-bottom: 0;
  text-align: left;
  white-space: nowrap;
}
/* Keep the h:m:s clock wide enough for two digits and stop flex shrinking. */
[data-wk-metric="duration"].strength-duration > div {
  flex-shrink: 0;
  width: auto;
}
[data-wk-metric="duration"].strength-duration input[data-wk-dur] {
  width: 2.5rem;
  min-width: 2.5rem;
}

/* Phones: the strength row (label + clock on one line) must fit narrow
   screens, so shrink the digit inputs and tighten the clock padding and
   the label gap. These rules come after the base strength-duration rules
   (and the wkt-modal-wrapper mobile rules) so they win at equal or lower
   specificity on small viewports. */
@media (max-width: 40rem) {
  [data-wk-metric="duration"].strength-duration {
    gap: 0.25rem;
  }
  [data-wk-metric="duration"].strength-duration > div {
    padding-left: 0.25rem;
    padding-right: 0.25rem;
  }
  [data-wk-metric="duration"].strength-duration input[data-wk-dur] {
    flex: 0 0 1.5rem;
    width: 1.5rem;
    min-width: 1.5rem;
  }
}

/* ============================================================
   STRENGTH WORKOUT BUILDER — blocks & exercises (spec 1.4)
   Blocks carry the brand (gold) accent; exercises inside a block
   use the indigo accent on a muted surface so they read as
   distinct interactive rows. Load parameters stay compact
   (smaller than exercises) but are grouped in a clearly marked
   strip with uppercase labels. All colors come from theme tokens.
   ============================================================ */

/* --- Block card: theme surface + brand left bar --- */
/* The "Workout structure" title heads the section's summary frame (markup in
   _strength_constructor). In the workout modal that frame follows the Creation
   mode card with no sibling spacing of its own — the form table gives its cells
   no vertical rhythm — so give it air. The template form lays its sections out
   with space-y-6 and needs nothing extra. */
.wkt-form-table .strength-structure__head {
  margin-top: 1rem;
}

/* The structure title reads as the frame's header: brand gold on the dark
   theme, plain ink on the light one. */
.strength-structure__title {
  margin: 0 0 0.25rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--color-txt-main);
}

[data-theme="dark"] .strength-structure__title {
  color: var(--color-brand);
}

.strength-block {
  border: 1px solid var(--color-border-light);
  border-left: 3px solid var(--color-brand);
  border-radius: 0.5rem;
  background: var(--color-panel-main);
  overflow: hidden;
}

.strength-block__header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding: 0.5rem 0.75rem;
  background: var(--color-panel-muted);
  border-bottom: 1px solid var(--color-border-light);
}

.strength-block__title {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--color-txt-main);
}

.strength-block__title::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 2px;
  background: var(--color-brand);
  flex-shrink: 0;
}

.strength-block__mode {
  height: 1.625rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.375rem;
  padding: 0 0.375rem;
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
  cursor: pointer;
}

.strength-block__body {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  padding: 0.625rem 0.75rem 0.75rem;
}

/* --- Compact load-parameter strip (visually smaller than exercises) --- */
.strength-params {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.625rem 1rem;
  padding: 0.5rem 0.625rem;
  border: 1px dashed var(--color-border-light);
  border-radius: 0.5rem;
  background: var(--color-panel-muted);
  background: color-mix(in srgb, var(--color-panel-muted) 50%, transparent);
}

.strength-param {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
}

.strength-param__label {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-txt-muted);
}

.strength-param__control {
  height: 1.75rem;
  min-width: 0;
  border: 1px solid var(--color-border-light);
  border-radius: 0.375rem;
  padding: 0 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
}

.strength-param__dur {
  width: 2.75rem;
  padding: 0 0.375rem;
  text-align: center;
}

.strength-param__select {
  padding-right: 1.5rem;
  cursor: pointer;
}

.strength-param__unit {
  font-size: 0.625rem;
  font-weight: 600;
  color: var(--color-txt-dim);
}

/* Hide number spinners inside the compact strip */
.strength-param__control::-webkit-outer-spin-button,
.strength-param__control::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.strength-param__control[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

/* --- Exercise rows: distinct from the block --- */
.strength-exercises {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.strength-exercise {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.375rem 0.5rem;
  background: var(--color-panel-muted);
  border-left: 3px solid var(--color-accent);
  border-radius: 0.375rem;
}

.strength-exercise__index {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 9999px;
  font-size: 0.625rem;
  font-weight: 700;
  color: var(--color-accent);
  background: var(--color-accent-light);
}

.strength-exercise__name {
  flex: 1;
  min-width: 0;
  /* Reads as the exercise's name on the row's solid background, not as an
     input box. The field affordance only appears on focus, where the coach can
     still add or rename an exercise. */
  border: 1px solid transparent;
  border-radius: 0.375rem;
  padding: 0.375rem 0.625rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--color-txt-main);
  background: transparent;
  resize: none;
  overflow: hidden;
}

.strength-exercise__name:focus {
  outline: none;
  border-color: var(--color-border-focus);
  background: var(--color-panel-main);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.15);
}

/* Read-only (athlete) name is not a field: a disabled control swallows clicks
   in the browser, so let them fall through to the row and toggle the details. */
.strength-exercise__name:disabled {
  pointer-events: none;
}

/* --- Per-exercise weight ---
   Offered only while the block itself carries no kg: then every exercise gets
   its own load. A block-wide kg supersedes these, so JS hides them in place. */
.strength-exercise__weight {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  align-self: center;
}

/* This file loads after the Tailwind build, so the display rule above would
   otherwise beat Tailwind's .hidden — the explicit two-class rule keeps the
   field hidden while the block has a kg of its own. */
.strength-exercise__weight.hidden {
  display: none;
}

.strength-exercise__weight-input {
  width: 3.25rem;
  height: 1.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.375rem;
  padding: 0 0.375rem;
  font-size: 0.75rem;
  font-weight: 600;
  text-align: right;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
}

/* Hide number spinners, like the block parameter strip does. */
.strength-exercise__weight-input::-webkit-outer-spin-button,
.strength-exercise__weight-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.strength-exercise__weight-input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

.strength-exercise__weight-unit {
  font-size: 0.625rem;
  font-weight: 700;
  color: var(--color-txt-muted);
}

.strength-exercise__weight--readonly {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-txt-main);
}

/* --- Buttons --- */
.strength-add-block {
  width: 100%;
  border: 1px dashed var(--color-brand);
  border-radius: 0.5rem;
  padding: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-brand);
  background: transparent;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.strength-add-block:hover {
  background: var(--color-brand-light);
}

.strength-add-exercise {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 0.25rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.375rem;
  padding: 0.25rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-brand);
  background: var(--color-panel-main);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.strength-add-exercise:hover {
  background: var(--color-brand-light);
  border-color: var(--color-brand);
}

.strength-block__remove,
.strength-exercise__remove {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 0;
  border-radius: 0.375rem;
  background: transparent;
  color: var(--color-txt-muted);
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.strength-block__remove:hover,
.strength-exercise__remove:hover {
  color: #ef4444;
  background: rgba(239, 68, 68, 0.1);
}

/* Block-level toggle: expands/collapses the details (description/media) of
   every exercise in the block at once. Shares one bright, tappable chip with
   the block-level play button so both read as the block's actions — the play
   chip carries the same plain play triangle the exercise videos use, drawn in
   the chip's own theme color. */
.strength-block__details-toggle,
.strength-block__play-all {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid rgba(var(--color-brand-rgb), 0.35);
  border-radius: 0.5rem;
  background: var(--color-brand-light);
  color: var(--color-brand);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.strength-block__details-toggle:hover,
.strength-block__play-all:hover {
  color: var(--color-txt-on-brand);
  background: var(--color-brand);
  border-color: var(--color-brand);
}

/* --- Expandable library exercises: toggle + inline details (media, description) --- */
.strength-exercise--expandable {
  cursor: pointer;
}

.strength-exercise__toggle {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 0;
  border-radius: 0.375rem;
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, transform 0.15s ease;
}

.strength-exercise__toggle:hover {
  color: var(--color-brand);
  background: var(--color-brand-light);
}

.strength-exercise__toggle--open {
  transform: rotate(180deg);
}

.strength-exercise__details {
  width: 100%;
  margin-top: 0.25rem;
  padding: 0.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.375rem;
  background: var(--color-panel-main);
}

.strength-exercise__desc {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--color-txt-muted);
  white-space: pre-wrap;
}

.strength-exercise__media {
  margin-bottom: 0.5rem;
  border-radius: 0.375rem;
  overflow: hidden;
}

.strength-exercise__media-poster {
  position: relative;
  display: block;
  width: 100%;
  min-height: 12rem;
  padding: 0;
  border: 0;
  border-radius: 0.375rem;
  overflow: hidden;
  background: #000;
  cursor: pointer;
}

/* Override Tailwind's .hidden: this file loads after the Tailwind build, so
   the display rule above would otherwise keep the poster visible when the
   embedded player replaces it (same swap as the exercise library). */
.strength-exercise__media-poster.hidden {
  display: none;
}

.strength-exercise__media-img {
  display: block;
  width: 100%;
  height: 12rem;
  object-fit: contain;
  background: var(--color-panel-main);
}

.strength-exercise__play {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  color: #fff;
}

.strength-exercise__play-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.strength-exercise__play-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 9999px;
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
}

.strength-exercise__iframe {
  display: block;
  width: 100%;
  /* Same box the poster occupied: the video plays inline within the existing
     media size instead of resizing the layout when the player replaces the
     poster. The player (YouTube IFrame API) mounts into this container. */
  height: 12rem;
  border: 0;
  background: #000;
}

.strength-exercise__image-btn {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0.375rem;
  overflow: hidden;
  background: var(--color-panel-main);
  cursor: zoom-in;
}

.strength-exercise__media-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* --- Read-only (athlete) view: values stay readable, no interaction --- */
.strength-param__control:disabled,
.strength-block__mode:disabled,
.strength-exercise__name:disabled {
  opacity: 0.8;
  cursor: default;
}

/* Read-only (athlete) view: dropdowns become plain value text — no select
   arrows, so they never read as editable controls. */
.strength-block__mode--readonly,
.strength-param__control--readonly {
  display: inline-flex;
  align-items: center;
  border-color: transparent;
  background: transparent;
  color: var(--color-txt-main);
  font-weight: 600;
  cursor: default;
}

/* ── Exercise library side panel (workout modal) ───────────────────────────
   Opens next to the strength form; the wrapper switches to a flex row and the
   card + panel each take half of the available width on desktop. On phones the
   panel becomes a full-screen overlay. */

/* Exercise-library toggle — the only way into the library from the strength
   form, so it reads as a control instead of a grey glyph: the same brand chip
   the block actions use, with a bookshelf in it. */
.strength-library-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 1px solid rgba(var(--color-brand-rgb), 0.35);
  border-radius: 0.5rem;
  background: var(--color-brand-light);
  color: var(--color-brand);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.strength-library-toggle:hover {
  color: var(--color-txt-on-brand);
  background: var(--color-brand);
  border-color: var(--color-brand);
}

.strength-library-toggle:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
}

/* This file loads after the Tailwind build, so the display rule above would
   otherwise beat Tailwind's .hidden — the explicit two-class rule keeps the
   toggle hidden until JS removes the class. */
.strength-library-toggle.hidden {
  display: none;
}

.wkt-modal-wrapper.strength-library-open {
  display: flex;
  gap: 1.25rem;
  align-items: stretch;
  width: min(96vw, 1600px);
  max-width: min(96vw, 1600px);
}

/* Half-and-half split: the modal card and the library panel are the wrapper's
   two flex children, so each takes exactly half of the available width.
   align-items: stretch gives them the same height, and the card is pinned to
   the top by resetting the self-centering and margins it carries on the
   closed-state markup (e.g. the template modal's self-center my-4).
   !important beats the card's inline width:768px. */
.wkt-modal-wrapper.strength-library-open > .bg-panel-main {
  width: 50% !important;
  max-width: none !important;
  flex: 1 1 50%;
  min-width: 0;
  margin: 0 !important;
  align-self: stretch;
}

.strength-library-panel {
  display: flex;
  flex-direction: column;
  width: 50%;
  flex: 1 1 50%;
  min-width: 0;
  max-height: 90vh;
  min-height: 0;
  overflow: hidden;
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: 0.75rem;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}

/* Explicit override (two classes beat Tailwind's .hidden). */
.strength-library-panel.hidden {
  display: none;
}

.strength-library-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--color-border-light);
  background: var(--color-panel-muted);
}

.strength-library-header h3 {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--color-txt-main);
}

.strength-library-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: 0.5rem;
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.strength-library-close:hover {
  color: var(--color-txt-main);
  background: var(--color-panel-main);
}

.strength-library-header-actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

/* "Expand all" action: a quiet text button that expands every card's details
   at once, mirroring the exercise library page's button. */
.strength-library-expand-all {
  border: 0;
  background: transparent;
  color: var(--color-txt-muted);
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.25rem 0.5rem;
  border-radius: 0.5rem;
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.strength-library-expand-all:hover {
  color: var(--color-brand);
  background: var(--color-panel-main);
}

/* This file loads after the Tailwind build, so the display rule above would
   otherwise beat Tailwind's .hidden — the explicit two-class rule keeps the
   button hidden until the loaded list has something to expand. */
.strength-library-expand-all.hidden {
  display: none;
}

.strength-library-toolbar {
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--color-border-light);
}

.strength-library-search {
  flex: 1;
  min-width: 0;
  height: 2.25rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.5rem;
  padding: 0 0.625rem;
  font-size: 0.8125rem;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
}

.strength-library-search:focus {
  outline: none;
  border-color: var(--color-border-focus);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.15);
}

/* Category filter field: holds the native select and the dropdown the
   custom-select controller builds after it. */
.strength-library-category-field {
  flex: 1 1 12rem;
  min-width: 0;
  max-width: 12rem;
}

/* Match the search box so the toolbar reads as one row of controls. */
.strength-library-category-field .custom-select__trigger {
  height: 2.25rem;
  padding: 0 0.625rem;
  font-size: 0.8125rem;
  border-radius: 0.5rem;
}

.strength-library-category {
  max-width: 12rem;
  height: 2.25rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.5rem;
  padding: 0 0.5rem;
  font-size: 0.8125rem;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
  cursor: pointer;
}

.strength-library-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 1rem;
}

.strength-library-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.625rem;
}

.strength-library-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-height: 3.5rem;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.5rem;
  background: var(--color-panel-main);
  cursor: grab;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}

.strength-library-card:hover {
  border-color: var(--color-brand);
  box-shadow: 0 2px 8px rgba(var(--color-brand-rgb), 0.15);
}

.strength-library-card--dragging {
  opacity: 0.4;
}

.strength-library-card__top {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.strength-library-card__check {
  flex-shrink: 0;
  width: 1rem;
  height: 1rem;
  margin: 0;
  accent-color: var(--color-brand);
  cursor: pointer;
}

.strength-library-card__name {
  flex: 1;
  min-width: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-txt-main);
}

.strength-library-card__category {
  font-size: 0.6875rem;
  color: var(--color-txt-muted);
}

.strength-library-card__media {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  border-radius: 0.375rem;
  background: var(--color-panel-muted);
  color: var(--color-txt-muted);
}

.strength-library-card__toggle {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 0;
  border-radius: 0.375rem;
  background: transparent;
  color: var(--color-txt-muted);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, transform 0.15s ease;
}

.strength-library-card__toggle:hover {
  color: var(--color-brand);
  background: var(--color-brand-light);
}

.strength-library-card--expanded .strength-library-card__toggle {
  transform: rotate(180deg);
}

.strength-library-card__details {
  width: 100%;
  margin-top: 0.375rem;
  padding: 0.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: 0.375rem;
  background: var(--color-panel-main);
}

/* Override Tailwind's .hidden (this file loads after the build). */
.strength-library-card__details.hidden {
  display: none;
}

.strength-library-empty {
  padding: 2.5rem 1rem;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--color-txt-muted);
}

.strength-library-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.625rem 1rem;
  border-top: 1px solid var(--color-border-light);
  background: var(--color-panel-muted);
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}

.strength-library-drag-hint {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-width: 0;
}

.strength-library-add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  flex-shrink: 0;
  padding: 0.4375rem 0.875rem;
  border: 1px solid var(--color-brand);
  border-radius: 0.5rem;
  background: var(--color-brand);
  color: var(--color-txt-on-brand);
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s ease, opacity 0.15s ease;
}

.strength-library-add-btn:hover:not(:disabled) {
  background: var(--color-brand-hover);
}

.strength-library-add-btn:disabled {
  border-color: var(--color-border-light);
  background: var(--color-panel-main);
  color: var(--color-txt-muted);
  cursor: default;
  opacity: 0.6;
}

/* Drop targets inside the strength constructor: the highlighted block or
   exercise row an exercise would land on. */
.strength-block.strength-drop-target {
  border-color: var(--color-brand);
  box-shadow: 0 0 0 2px rgba(var(--color-brand-rgb), 0.25);
}

.strength-exercise.strength-drop-target {
  border-left-color: var(--color-brand);
  outline: 2px dashed var(--color-brand);
  outline-offset: 1px;
}

/* Drag handles on the constructor blocks and exercise rows. */
.strength-block__drag,
.strength-exercise__drag {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.125rem;
  border-radius: 0.25rem;
  color: var(--color-txt-dim);
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}

.strength-block__drag:hover,
.strength-exercise__drag:hover {
  color: var(--color-brand);
  background: var(--color-brand-light);
}

.strength-block__drag:active,
.strength-exercise__drag:active {
  cursor: grabbing;
}

/* The dragged source stays visible but faded while the ghost follows the
   pointer. */
.strength-drag-source {
  opacity: 0.5;
}

/* ── Exercise form: removable image thumbnail ───────────────────────────────
   The "x" on the thumbnail marks the attached image for removal (hidden
   remove_image flag); a fresh pick preview uses the same wrap/button. */

.exercise-image-wrap {
  position: relative;
  display: inline-block;
}

/* This file loads after the Tailwind build, so the display rule above would
   otherwise beat Tailwind's .hidden — the explicit two-class rule keeps the
   removed thumbnail hidden until a replacement is picked. */
.exercise-image-wrap.hidden {
  display: none;
}

.exercise-image-remove {
  position: absolute;
  top: -0.5rem;
  right: -0.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 1px solid var(--color-border-light);
  border-radius: 9999px;
  background: var(--color-panel-main);
  color: var(--color-txt-muted);
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  transition: color 0.15s ease, background-color 0.15s ease;
}

.exercise-image-remove:hover {
  color: #ef4444;
  background: var(--color-panel-muted);
}

/* Tablets and phones: the 50/50 split is too cramped, so the panel covers the
   whole viewport as an overlay with its own close button. Drag & drop is not
   practical there, so the add button becomes the primary (full-width) action
   and the drag hint is hidden. */
@media (max-width: 63.99rem) {
  .wkt-modal-wrapper.strength-library-open {
    width: 100%;
    max-width: 100%;
  }

  .wkt-modal-wrapper.strength-library-open > .bg-panel-main {
    width: 100% !important;
  }

  .strength-library-panel {
    position: fixed;
    inset: 0;
    width: 100%;
    max-width: none;
    max-height: none;
    z-index: 60;
    border-radius: 0;
    border: 0;
  }

  .strength-library-grid {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  }

  .strength-library-drag-hint {
    display: none;
  }

  .strength-library-footer {
    justify-content: center;
  }

  .strength-library-add-btn {
    width: 100%;
    padding: 0.625rem;
  }
}

/* ============================================================
   ENVIRONMENT & GEAR (Profile · training location)
   One block holds the location and its search: the summary is the
   header row and the action, the panel below is the search. The
   disclosure is a native <details>, so it needs no JavaScript, and
   every colour comes from theme tokens (light and dark).
   ============================================================ */
.env-location {
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-form);
  box-shadow: var(--shadow-card);
}
.env-location__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  padding: 1.25rem;
  cursor: pointer;
  list-style: none;
}
/* Hide the native disclosure marker (Safari needs the pseudo-element). */
.env-location__head::-webkit-details-marker {
  display: none;
}
.env-location__head:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: -2px;
  border-radius: var(--radius-form);
}
.env-location__info {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.env-location__title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-txt-main);
}
.env-location__value {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-txt-main);
}
.env-location__value svg {
  color: var(--color-txt-muted);
}
.env-location__coords {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--color-txt-muted);
}
/* A configured value on this tab (location, time zone). Shaped and filled like
   the app's read-only fields — muted surface, hairline border, form radius — so
   it reads as "the value of this setting" rather than as a brand action, and
   stays neutral in both themes. */
.env-value {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  width: fit-content;
  max-width: 100%;
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-form);
}
.env-location__hint {
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
.env-location__action,
.env-timezone__action {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 0.375rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
  background: var(--color-panel-main);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-txt-main);
}
.env-location__head:hover .env-location__action,
.env-location[open] .env-location__action,
.env-timezone__head:hover .env-timezone__action,
.env-timezone[open] .env-timezone__action {
  background: var(--color-panel-muted);
}
/* The chevron points at where the picker opens. */
.env-location[open] .env-location__action svg,
.env-timezone[open] .env-timezone__action svg {
  transform: rotate(180deg);
}
.env-location__panel {
  padding: 0 1.25rem 1.25rem;
}
/* OpenWeatherMap credit: it belongs to the location block (the forecast is what
   comes from OpenWeatherMap), so it hugs that card rather than floating at the
   bottom of the tab, where it would read as part of the time zone block. */
.env-location__attribution {
  margin: 0.5rem 0 0;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}

/* ============================================================
   ENVIRONMENT & GEAR (Profile · time zone)
   Same card and the same disclosure pattern as the location block
   above: the header row is a summary, the zone list lives in the
   panel. The clock is the read-out the picked zone is checked
   against.
   ============================================================ */
.env-timezone {
  margin-top: 0.75rem;
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-form);
  box-shadow: var(--shadow-card);
}
.env-timezone__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  padding: 1.25rem;
  cursor: pointer;
  list-style: none;
}
.env-timezone__head::-webkit-details-marker {
  display: none;
}
.env-timezone__head:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: -2px;
  border-radius: var(--radius-form);
}
.env-timezone__info {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.env-timezone__title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-txt-main);
}
.env-timezone__unset {
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
/* The "(GMT+02:00)" half of the picked zone: secondary to the name inside the
   chip, but always shown, so the selected value is unambiguous. */
.env-timezone__offset {
  font-weight: 500;
  color: var(--color-txt-muted);
}
/* Clock and the change action travel together on the right. */
.env-timezone__side {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  flex: 0 0 auto;
}
/* Current time at the location. Tabular figures keep the width steady as the
   minute rolls over, so the clock does not twitch while it ticks. */
.env-timezone__clock {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
  padding: 0.5rem 0.75rem;
  font-size: 1.125rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--color-txt-main);
  background: var(--color-panel-muted);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-btn);
}
.env-timezone__clock svg {
  flex-shrink: 0;
  color: var(--color-txt-muted);
}
.env-timezone__panel {
  padding: 0 1.25rem 1.25rem;
}
.env-timezone__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
/* Holds the native select, and the themed dropdown the controller builds after
   it — .custom-select fills whatever this gives it. */
.env-timezone__field {
  flex: 1 1 18rem;
  min-width: 0;
}
/* The themed dropdown the controller builds after the select: its trigger is
   sized for table cells, so match it to the Save button and to the app's form
   fields instead. */
.env-timezone__field .custom-select__trigger {
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  border-radius: var(--radius-form);
}
.env-timezone__field .custom-select__option {
  font-size: 0.875rem;
}
.env-timezone__select {
  width: 100%;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  color: var(--color-txt-main);
  background: var(--color-panel-main);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-form);
  outline: none;
}
.env-timezone__select:focus-visible {
  border-color: var(--color-border-focus);
  box-shadow: 0 0 0 1px var(--color-border-focus);
}
.env-timezone__hint {
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--color-txt-muted);
}
