/* ── COACH PORTAL STYLES ─────────────────────────────────────
   Matches MyBest24 dark design system.
   Scope: /coach/ — never loaded in the main app or landing page.
──────────────────────────────────────────────────────────── */

/* ── VARIABLES ──────────────────────────────────────────────── */
:root {
    --bg:              #090909;
    --bg-card:         #0f0f0f;
    --bg-card-2:       #131313;
    /* Used specifically for section header strips (.coach-section-header,
       .settings-section-header). Intentionally more contrast vs --bg-card
       than --bg-card-2 (which stays subtle for hover/alt states). */
    --bg-card-header:  #1f1f1f;
    --bg-input:        #111;
    --border:          #1c1c1c;
    --border-mid:      #282828;
    --accent:       #46a5ce;
    --accent-glow:  rgba(70,165,206,0.15);
    --accent-dim:   rgba(70,165,206,0.1);
    --text:         #efefef;
    --text-mid:     #888;
    --text-dim:     #5d5d5d;
    --green:        #3cba6c;
    --red:          #e05252;
    --yellow:       #d4a843;
    --font-head:    'Outfit', sans-serif;
    --font-body:    'DM Sans', system-ui, sans-serif;
    --radius:       10px;
    --sidebar-w:    240px;

    /* Admin impersonation — declared once, referenced in three places
       (banner height, body padding-top, sidebar offset) so a future
       breakpoint or extra-row banner only changes one number.
       Color: amber against the dark workspace, picked for unmistakable
       contrast — the existing palette has no warning-weight token. */
    --impersonation-banner-h:  48px;
    --banner-amber:            #d97706;
    --banner-amber-2:          #f59e0b;
    --banner-amber-text:       #1a0f00;
}

/* ── BASE ────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.95rem;
    line-height: 1.6;
    min-height: 100vh;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
img { display: block; max-width: 100%; }
button { cursor: pointer; font-family: inherit; }

/* ── UTILITIES ──────────────────────────────────────────────── */
.hidden { display: none !important; }
.accent { color: var(--accent); }
.text-mid { color: var(--text-mid); }
.text-dim { color: var(--text-dim); }

/* ── LOGO ───────────────────────────────────────────────────── */
.coach-logo {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 1.3rem;
    color: var(--text);
    letter-spacing: -0.5px;
}

/* ════════════════════════════════════════════════════════════
   AUTH SCREEN
════════════════════════════════════════════════════════════ */
#auth-screen {
    /* Copied from /app/auth.css → #auth-overlay.
       Previously `min-height: 100vh`, which on iOS Safari and mobile
       Chrome counts the address-bar height — so the flex-centered card
       sat below the visual centre whenever the bar was showing. Fixed
       positioning binds to the actual visible viewport instead. */
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.auth-card {
    width: 100%;
    max-width: 420px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
}
.auth-header {
    padding: 32px 32px 0;
    text-align: center;
}
.auth-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    margin-top: 28px;
}
.auth-tab {
    flex: 1;
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 12px;
    font-family: var(--font-head);
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text-mid);
    letter-spacing: 0.5px;
    transition: all 0.15s;
}
.auth-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.auth-tab:hover:not(.active) { color: var(--text); }
.auth-body { padding: 28px 32px 32px; }
.auth-tagline {
    font-size: 0.85rem;
    color: var(--text-mid);
    margin-bottom: 24px;
    text-align: center;
}

/* ── FORM ELEMENTS ──────────────────────────────────────────── */
.form-group { margin-bottom: 14px; }
.form-label {
    display: block;
    font-size: 0.78rem;
    font-weight: 700;
    font-family: var(--font-head);
    letter-spacing: 0.5px;
    color: var(--text-mid);
    margin-bottom: 6px;
    text-transform: uppercase;
}
.form-input {
    width: 100%;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 11px 14px;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.95rem;
    outline: none;
    transition: border-color 0.15s;
}
.form-input:focus { border-color: var(--accent); }
.form-input::placeholder { color: var(--text-dim); }
.form-hint {
    font-size: 0.78rem;
    color: var(--text-dim);
    margin-top: 5px;
}
.form-error {
    font-size: 0.82rem;
    color: var(--red);
    margin-top: 12px;
    text-align: center;
}

/* ── BUTTONS ────────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: none;
    border-radius: 8px;
    padding: 11px 20px;
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.9rem;
    transition: all 0.15s;
    text-decoration: none;
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { filter: brightness(1.1); transform: translateY(-1px); text-decoration: none; }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; filter: none; }
.btn-ghost {
    background: transparent;
    border: 1px solid var(--border-mid);
    color: var(--text-mid);
}
.btn-ghost:hover { border-color: var(--accent); color: var(--text); }
.btn-danger { background: var(--red); color: #fff; }
.btn-danger:hover { filter: brightness(1.1); }
.btn-full { width: 100%; }
.btn-sm { padding: 7px 14px; font-size: 0.8rem; }

.auth-forgot {
    display: block;
    text-align: right;
    font-size: 0.78rem;
    color: var(--text-dim);
    margin-bottom: 20px;
}
.auth-forgot:hover { color: var(--accent); }

/* ════════════════════════════════════════════════════════════
   APP SHELL (post-login)
════════════════════════════════════════════════════════════ */
#app-shell {
    display: flex;
    min-height: 100vh;
}

/* ── SIDEBAR ────────────────────────────────────────────────── */
.coach-sidebar {
    width: var(--sidebar-w);
    background: var(--bg-card);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    height: 100dvh;   /* dvh tracks the *visible* viewport so the panel never
                         extends behind the mobile browser's address/tool bar */
    overflow-y: auto; /* and if content ever exceeds it, the panel scrolls
                         instead of stranding items off-screen */
    z-index: 50;
    padding: 24px 0;
    padding-bottom: calc(24px + env(safe-area-inset-bottom));
}
.sidebar-brand {
    padding: 0 20px 24px;
    border-bottom: 1px solid var(--border);
}
/* Brand text on the left, the tappable initials avatar on the right. */
.sidebar-brand-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}
.sidebar-brand .coach-badge {
    font-size: 0.65rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--accent);
    background: var(--accent-dim);
    border: 1px solid rgba(70,165,206,0.25);
    border-radius: 4px;
    padding: 2px 7px;
    margin-top: 4px;
    display: inline-block;
}
/* Stacked brand: full-width logo with a divider under it → avatar on its own
   line → badge below it. (Was logo+badge on the left, avatar on the right in a
   flex row.) The block button sits content-width on the left; the badge, being
   the next block-flow element, drops onto its own line beneath the avatar. */
.sidebar-brand .coach-logo {
    padding-bottom: 18px;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border);
}
.sidebar-brand .sidebar-profile-toggle {
    display: block;
    width: fit-content;
}
.sidebar-nav {
    flex: 1;
    padding: 16px 0;
}
.sidebar-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 20px;
    color: var(--text-mid);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    border-left: 3px solid transparent;
    transition: all 0.12s;
    background: transparent;
    border-top: none;
    border-right: none;
    border-bottom: none;
    width: 100%;
    text-align: left;
}
.sidebar-nav-item:hover { color: var(--text); background: rgba(255,255,255,0.03); }
.sidebar-nav-item.active {
    color: var(--accent);
    border-left-color: var(--accent);
    background: var(--accent-dim);
}
.sidebar-nav-icon {
    width: 16px;
    height: 16px;
    opacity: 0.6;
    flex-shrink: 0;
}
.sidebar-nav-item.active .sidebar-nav-icon { opacity: 1; }
.sidebar-footer {
    padding: 16px 20px;
    border-top: 1px solid var(--border);
}

/* ── Profile menu (avatar toggle + dropdown) ────────────────────────────────
   The circular initials avatar (.sidebar-coach-avatar) inherits the
   .client-avatar look — accent circle + white initials; only its size is set
   here. Tapping it reveals the dropdown with name/email + Switch to App /
   Sign Out. */
.sidebar-profile-toggle {
    flex-shrink: 0;
    padding: 0;
    background: none;
    border: 2px solid transparent;
    border-radius: 50%;
    cursor: pointer;
    line-height: 0;
    transition: border-color 0.12s;
}
.sidebar-profile-toggle:hover,
.sidebar-profile-toggle[aria-expanded="true"] {
    border-color: var(--accent);
}
.sidebar-coach-avatar {
    width: 36px;
    height: 36px;
    font-size: 0.8rem;
}
/* Profile dropdown — mirrors the app's account menu: full-width flat rows
   (icon+text) separated by dividers. Lives in NORMAL FLOW as a sibling of
   .sidebar-brand, so revealing it pushes the nav items down rather than
   overlaying them. Full-width because the sidebar has no horizontal padding;
   the brand's border-bottom is the top divider, the rule below separates the
   menu from the nav. */
.sidebar-profile-menu {
    border-bottom: 1px solid var(--border);
    padding: 4px 0;
}
.sidebar-profile-user {
    padding: 10px 20px 8px;
}
.sidebar-profile-divider {
    height: 1px;
    background: var(--border);
}
.sidebar-profile-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 20px;   /* match .sidebar-nav-item height */
    background: none;
    border: none;
    color: var(--text-mid);
    font-size: 0.9rem;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.sidebar-profile-item:hover {
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
}
.sidebar-profile-item:last-child:hover {
    color: #ff6b6b;           /* sign-out: subtle red tint on hover, matches app */
}
.sidebar-profile-icon {
    width: 16px;
    text-align: center;
    opacity: 0.7;
    flex-shrink: 0;
}
.sidebar-coach-name {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 1px;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar-coach-email {
    font-size: 0.75rem;
    color: var(--text-dim);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar-legal-links {
    margin-top: 12px;
    font-size: 0.7rem;
    color: var(--text-dim);
    text-align: center;
}
.sidebar-legal-links a {
    color: var(--text-dim);
    text-decoration: none;
}
.sidebar-legal-links a:hover { text-decoration: underline; }
.sidebar-legal-links span { margin: 0 6px; }

/* ── Mobile hamburger ───────────────────────────────────────────── */
.coach-hamburger {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 36px;
    height: 36px;
    padding: 6px;
    background: none;
    border: none;
    cursor: pointer;
    flex-shrink: 0;
    margin-right: 8px;
}
.coach-hamburger span {
    display: block;
    width: 100%;
    height: 2px;
    background: var(--text, #fff);
    border-radius: 2px;
    transition: opacity 0.15s;
}
.coach-hamburger:hover span { opacity: 0.7; }

/* Overlay darkens content when mobile sidebar is open */
.coach-sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 49;
    backdrop-filter: blur(1px);
}
.coach-sidebar-overlay.active { display: block; }

/* ── MAIN CONTENT ───────────────────────────────────────────── */
.coach-main {
    margin-left: var(--sidebar-w);
    flex: 1;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow-x: hidden;
}
.coach-topbar {
    background: var(--bg-card);
    border-bottom: 1px solid var(--border);
    padding: 16px 32px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    z-index: 40;
}
.coach-topbar-title {
    font-family: var(--font-head);
    font-size: 1.1rem;
    font-weight: 800;
}
.coach-content {
    padding: 32px;
    flex: 1;
}

/* ── VIEW PANELS (routed by JS) ─────────────────────────────── */
.coach-view { display: none; }
.coach-view.active { display: block; }

/* ════════════════════════════════════════════════════════════
   CLIENT LIST (Dashboard view)
════════════════════════════════════════════════════════════ */
.client-list-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 24px;
    flex-wrap: wrap;
    gap: 12px;
}
.client-count {
    font-size: 0.82rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
}
.client-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.client-row {
    display: grid;
    grid-template-columns: 1fr 120px 120px 100px 90px 90px;
    align-items: center;
    gap: 16px;
    padding: 14px 20px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s;
}
.client-row:hover { border-color: var(--border-mid); background: var(--bg-card-2); }
.client-name {
    font-weight: 600;
    font-size: 0.95rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.client-email {
    font-size: 0.78rem;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Client avatar ──────────────────────────────────────────────────────────
   Small accent-blue circle with white initials, used in two places:
   - Dashboard list row (small, alternating opacity for visual rhythm)
   - Per-client detail header (large, full opacity, solo)
   Initials come from coachInitials() in coach-state.js. */

.client-avatar {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    user-select: none;
}
.client-avatar--sm {
    width: 32px;
    height: 32px;
    font-size: 0.78rem;
}
.client-avatar--lg {
    width: 48px;
    height: 48px;
    font-size: 1.05rem;
}

/* Alternate opacity inside the dashboard client list only. The :nth-child
   approach is intentional per spec — pure CSS, no JS bookkeeping. One known
   cosmetic regression: on mobile, when a row is tap-expanded, an
   .client-row-expanded-stats panel is inserted as a sibling, which shifts
   the :nth-child count for rows below it (alternation drifts after the
   first expand). Accepted tradeoff vs. a JS-driven .client-row--alt class
   that would survive the shift. The per-client detail view is unaffected
   because it lives outside .client-list. */
.client-list .client-row:nth-child(odd)  .client-avatar { opacity: 1; }
.client-list .client-row:nth-child(even) .client-avatar { opacity: 0.5; }

/* Subtle accent tint on odd rows reinforces the alternating-pair distinction
   (paired with the avatar opacity rules above). 8% accent is light enough
   not to compete with the row's content, dark enough to read as a band. */
.client-list .client-row:nth-child(odd) {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}

/* Flex wrappers for avatar + name+email layout, used in both views.
   min-width: 0 lets the inner text columns truncate via the existing
   .client-name / .client-dash-name text-overflow rules — without it,
   flex items default to min-content and ellipsis breaks. */
.client-name-cell,
.client-dash-name-cell {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.client-name-stack,
.client-dash-name-stack {
    min-width: 0;
    flex: 1;
}

.client-stat {
    font-size: 0.82rem;
    color: var(--text-mid);
    text-align: right;
}
.client-stat-val {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--text);
}
.client-stat-val.good  { color: var(--green); }
.client-stat-val.warn  { color: var(--yellow); }
.client-stat-val.bad   { color: var(--red); }
.client-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.72rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 100px;
    border: 1px solid;
}
.badge-active   { color: var(--green);  border-color: rgba(60,186,108,0.35); background: rgba(60,186,108,0.08); }
.badge-pending  { color: var(--yellow); border-color: rgba(212,168,67,0.35); background: rgba(212,168,67,0.08); }
.badge-expiring { color: var(--yellow); border-color: rgba(212,168,67,0.35); background: rgba(212,168,67,0.08); }
.badge-revoked  { color: var(--text-dim); border-color: var(--border); background: transparent; }

/* List header row */
.client-list-cols {
    display: grid;
    grid-template-columns: 1fr 120px 120px 100px 90px 90px;
    gap: 16px;
    padding: 8px 20px;
    margin-bottom: 6px;
}
.client-list-col-label {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    text-align: right;
}
.client-list-col-label:first-child { text-align: left; }

/* Empty state */
.empty-state {
    text-align: center;
    padding: 80px 24px;
    color: var(--text-mid);
}
.empty-state-icon { font-size: 2.5rem; margin-bottom: 16px; opacity: 0.3; }
.empty-state-title {
    font-family: var(--font-head);
    font-size: 1.2rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 8px;
}
.empty-state-desc { font-size: 0.9rem; color: var(--text-mid); margin-bottom: 28px; }

/* ════════════════════════════════════════════════════════════
   INVITE MODAL
════════════════════════════════════════════════════════════ */
.coach-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.8);
    backdrop-filter: blur(6px);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 40px 20px;
    z-index: 200;
    overflow-y: auto;
}
.coach-modal {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    width: 100%;
    max-width: 480px;
    margin: auto;
}
.coach-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 24px;
    border-bottom: 1px solid var(--border);
}
.coach-modal-title {
    font-family: var(--font-head);
    font-size: 1.1rem;
    font-weight: 800;
}
.coach-modal-close {
    background: transparent;
    border: none;
    color: var(--text-dim);
    font-size: 1.2rem;
    line-height: 1;
    padding: 0;
    transition: color 0.12s;
}
.coach-modal-close:hover { color: var(--text); }
.coach-modal-body { padding: 24px; }
.coach-modal-footer {
    padding: 16px 24px;
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: flex-end;
    gap: 10px;
}

/* Section toggles in invite modal */
.section-toggles {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}
.section-toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color 0.12s;
}
.section-toggle:hover { border-color: var(--border-mid); }
.section-toggle input[type="checkbox"] { accent-color: var(--accent); width: 15px; height: 15px; }
.section-toggle-label { font-size: 0.88rem; color: var(--text); flex: 1; }
.section-toggle-desc  { font-size: 0.75rem; color: var(--text-dim); }

/* ── LOADING SPINNER ────────────────────────────────────────── */
.coach-spinner {
    display: inline-block;
    width: 18px;
    height: 18px;
    border: 2px solid rgba(255,255,255,0.2);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.coach-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 80px;
    color: var(--text-dim);
    gap: 12px;
    font-size: 0.9rem;
}

/* ── TOASTS ─────────────────────────────────────────────────── */
#coach-toast {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(80px);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 100px;
    padding: 10px 20px;
    font-size: 0.85rem;
    color: var(--text);
    z-index: 999;
    transition: transform 0.3s ease-out, opacity 0.3s;
    opacity: 0;
    pointer-events: none;
    white-space: nowrap;
}
#coach-toast.show {
    transform: translateX(-50%) translateY(0);
    opacity: 1;
}
#coach-toast.toast-success { border-color: rgba(60,186,108,0.4); color: var(--green); }
#coach-toast.toast-error   { border-color: rgba(224,82,82,0.4);  color: var(--red); }

/* ── MOBILE ─────────────────────────────────────────────────── */
@media (max-width: 860px) {
    .coach-sidebar {
        transform: translateX(-100%);
        transition: transform 0.25s ease;
        z-index: 50;        /* above overlay */
    }
    .coach-sidebar.open { transform: translateX(0); }
    .coach-main { margin-left: 0; }
    .coach-content { padding: 20px 16px; }
    .client-topbar { padding: 14px 16px; }
    .client-list-cols { display: none; }

    /* Show hamburger on mobile */
    .coach-hamburger { display: flex; }

    /* Topbar: hamburger | title | actions */
    .coach-topbar {
        padding: 12px 16px;
        gap: 0;
    }

    /* Mobile client row — name | chevron */
    .client-row {
        grid-template-columns: 1fr auto;
        gap: 8px;
        align-items: center;
    }
    .client-stat { display: none; }

    /* Chevron */
    .client-row::after {
        content: '›';
        font-size: 1.3rem;
        color: var(--text-dim);
        transition: transform 0.2s;
        padding-left: 4px;
    }
    .client-row.expanded::after { transform: rotate(90deg); }

    /* Expanded stats panel */
    .client-row-expanded-stats {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        background: var(--bg-card-2);
        border: 1px solid var(--border);
        border-top: none;
        border-radius: 0 0 var(--radius) var(--radius);
        padding: 12px 16px;
        gap: 12px;
        margin-bottom: 4px;
    }
    .client-expanded-stat-label {
        font-size: 0.65rem;
        text-transform: uppercase;
        letter-spacing: 0.8px;
        color: var(--text-dim);
        font-family: var(--font-head);
        font-weight: 700;
        margin-bottom: 3px;
    }
    .client-expanded-stat-val {
        font-size: 0.9rem;
        font-weight: 700;
        color: var(--text);
    }
}

/* end mobile */

/* ════════════════════════════════════════════════════════════
   PER-CLIENT DASHBOARD
════════════════════════════════════════════════════════════ */

.client-dash-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    margin-bottom: 28px;
    flex-wrap: wrap;
    gap: 12px;
}
.client-dash-name {
    font-family: var(--font-head);
    font-size: 1.5rem;
    font-weight: 800;
    margin-bottom: 4px;
}
.client-dash-email { font-size: 0.85rem; color: var(--text-dim); }
.client-dash-updated {
    font-size: 0.75rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    padding-top: 4px;
}

.client-sections {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* ── SECTION CARD ───────────────────────────────────────────── */
.client-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px;
}
.client-section-header {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 20px;
}
.client-section-title {
    font-family: var(--font-head);
    font-size: 1rem;
    font-weight: 800;
    color: var(--text);
}
.client-section-label {
    font-size: 0.75rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
}
.client-section-subtitle {
    font-family: var(--font-head);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin: 30px 0 10px;
}
.client-section-empty {
    font-size: 0.85rem;
    color: var(--text-dim);
    margin-top: 12px;
}

/* ── LONGITUDINAL: PIE + BARS LAYOUT ─────────────────────────────────────────
   Pie on the left (~140px), bars on the right (flex-grow). Stacks vertically
   on mobile (≤600px) so neither half gets squeezed. The bars container is
   `min-width: 0` to let the inner grid columns truncate gracefully when the
   container shrinks — without it, the 75px+1fr+100px grid would force the
   parent to its content width and break wrapping.
   ─────────────────────────────────────────────────────────────────────── */
.coach-longitudinal-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 24px;
    margin-bottom: 12px;
}
.coach-longitudinal-pie {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.coach-longitudinal-bars {
    flex: 1 1 auto;
    min-width: 0;
}

@media (max-width: 600px) {
    .coach-longitudinal-row {
        flex-direction: column;
        gap: 16px;
        align-items: stretch;
    }
    .coach-longitudinal-pie {
        align-self: center;
    }
}

/* ── DONUT CHART ─────────────────────────────────────────────────────────────
   SVG <circle> stack with stroke-dasharray slices. Hole text in the center
   shows total hours + "this week" label. Empty state (no slices) renders
   an outlined ring + em-dash placeholder. Title elements on each slice give
   coaches an exact-hours tooltip on hover.
   ─────────────────────────────────────────────────────────────────────── */
.coach-donut {
    display: block;
}
.coach-donut-total {
    font-family: var(--font-head);
    font-size: 1.4rem;
    font-weight: 700;
    fill: var(--text);
}
.coach-donut-label {
    font-size: 0.62rem;
    fill: var(--text-mid);
    letter-spacing: 0.6px;
    text-transform: uppercase;
}

/* ── BAR CHARTS ─────────────────────────────────────────────── */
.coach-bar-chart {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.coach-bar-row {
    display: grid;
    /* Grid was 90px / 1fr / 70px pre-fix. Tightened the left label column
       from 90px to 75px (still fits "This week" comfortably at 0.82rem) to
       give the right value column +30px (70 → 100) so the new "X / Y unit"
       format ("1795 / 2095 cal") fits without wrapping. The bar track loses
       15px in the middle — minor; tracks were always flexible. */
    grid-template-columns: 75px 1fr 100px;
    align-items: center;
    gap: 10px;
}
.coach-bar-row--sub {
    opacity: 0.7;
    margin-top: -4px;
}
.coach-bar-row--sub .coach-bar-label { font-size: 0.72rem; }
.coach-bar-label {
    font-size: 0.82rem;
    color: var(--text-mid);
    font-family: var(--font-head);
    font-weight: 700;
    text-align: right;
    white-space: nowrap;
}
.coach-bar-track {
    height: 8px;
    background: #1a1a1a;
    border-radius: 4px;
    overflow: hidden;
}
.coach-bar-fill {
    height: 100%;
    background: var(--accent);
    border-radius: 4px;
    width: 0%;
}
.coach-bar-fill.bar-good  { background: var(--green); }
.coach-bar-fill.bar-warn  { background: var(--yellow); }
.coach-bar-fill.bar-bad   { background: var(--red); }

/* ── DAILY 7-DAY BARS (coach-pro v3.2 §4.3) ─────────────────────────────────
   Mirrors the food panel's .report-weekly-bars pattern — vertical 7-column
   chart, today rightmost, accent-ringed. Same visual language as what the
   client sees on their food panel "This Week" tab; coaches see the same
   chart shape on the per-client dashboard. CLAUDE.md invariant #188 governs
   color rules (calorie/protein asymmetry — protein never penalized for over-
   goal). bar-neutral handles goal=0/null/missing days where compliance is
   undefined; never use it as a "default pretty grey" elsewhere.
   ─────────────────────────────────────────────────────────────────────── */

.coach-daily-bars {
    display: flex;
    gap: 6px;
    align-items: flex-end;     /* columns bottom-align so labels share a baseline */
    justify-content: center;   /* center the strip on wide desktop viewports
                                  so columns don't sprawl across 1200+px;
                                  pairs with .coach-daily-col max-width below */
    padding: 8px 0 4px;
    margin-bottom: 12px;
    overflow-x: auto;          /* graceful when 360px viewport squeezes 7 cols */
    -webkit-overflow-scrolling: touch;
}

.coach-daily-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    min-width: 32px;           /* keeps bars finger-friendly on narrow phones */
    /* Cap column width on wide desktop — pre-cap, a 1200px-wide content
       area distributed 7 cols × ~160px each, leaving "giant gaps" between
       bars (per smoke-test feedback). 60px caps the column at ~3x mobile's
       natural width; with 22px bar + 6px gap, that's ~32px between bar
       edges on desktop vs ~10px on mobile. justify-content:center on the
       parent then centers the bounded strip instead of left-aligning it. */
    max-width: 60px;
    position: relative;
}

/* Today: 1px accent ring around the track so the eye lands on today
   without reading labels. Same treatment as food panel. */
.coach-daily-col--today .coach-daily-bar-track {
    box-shadow: 0 0 0 1px var(--accent, var(--accent-color));
}

.coach-daily-bar-track {
    width: 22px;
    height: 56px;
    background: color-mix(in srgb, var(--accent, var(--accent-color)) 50%, transparent);
    border-radius: 5px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;  /* fills grow up from bottom */
    overflow: hidden;
    position: relative;
}

.coach-daily-bar-fill {
    width: 100%;
    border-radius: 5px;
    /* height set inline by JS — Number.isFinite-guarded; never NaN/Infinity */
    transition: height 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: reduce) {
    .coach-daily-bar-fill { transition: none; }
}

/* Color modifier classes for the daily bars. Keep in sync with weekly
   .coach-bar-fill rules above. bar-neutral is only emitted by the daily
   path — weekly never produces a no-goal state. */
.coach-daily-bar-fill.bar-good     { background: var(--green); }
.coach-daily-bar-fill.bar-warn     { background: var(--yellow); }
.coach-daily-bar-fill.bar-bad      { background: var(--red); }
.coach-daily-bar-fill.bar-neutral  { background: var(--text-dim); opacity: 0.5; }

/* Empty-day placeholder — outlined bar shape sized identically to the track
   so the column lines up with non-empty siblings. No fill, no opacity:
   this is "didn't log" not "logged zero." */
.coach-daily-col--empty .coach-daily-bar-placeholder {
    width: 22px;
    height: 56px;
    border-radius: 5px;
    border: 1px solid color-mix(in srgb, var(--accent, var(--accent-color)) 50%, transparent);
}

/* Overage annotation — shown above bar when value > 115% of goal. Color
   inherited (or set inline) to match the bar's danger/warning treatment. */
.coach-daily-bar-overage {
    font-size: 0.58rem;
    font-weight: 600;
    /* Color set per .bar-{good|warn|bad|neutral} modifier below — inherits
       the bar's threshold so e.g. protein >115% reads green (the bar is
       bar-good per CLAUDE.md #188 asymmetry rule), not a contradicting red.
       Default fallback red preserved for any caller that forgets the
       modifier — fail loud, not silent grey. */
    color: var(--red);
    white-space: nowrap;
    line-height: 1;
    margin-bottom: 2px;
}

.coach-daily-bar-overage.bar-good     { color: var(--green); }
.coach-daily-bar-overage.bar-warn     { color: var(--yellow); }
.coach-daily-bar-overage.bar-bad      { color: var(--red); }
.coach-daily-bar-overage.bar-neutral  { color: var(--text-mid); }

/* Per-day under-bar text rows: weekday label, recorded value, target.
   Coach-pro is a data-rich surface — coaches need exact numbers alongside
   the bar's at-a-glance pattern. Hierarchy is via color, not size:
     - Value:  bright (#efefef ~94%, bold) — most important read
     - Day:    medium (#888 ~53%) — column anchor
     - Target: medium (#888 ~53%) — context for the value, slash prefix
                                    semantically separates it
   Font size 0.75rem across all three rows — tested at 100% browser zoom;
   readable without strain. tabular-nums ensures digits align column-to-
   column so a vertical scan reads cleanly across all 7 days. Always
   rendered (em-dash placeholder on empty/no-goal days) to keep the
   strip's vertical alignment consistent. */
.coach-daily-day-label,
.coach-daily-bar-value,
.coach-daily-bar-target {
    font-size: 0.75rem;
    line-height: 1.1;
    text-align: center;
    white-space: nowrap;
    font-feature-settings: "tnum";
    font-variant-numeric: tabular-nums;
}

.coach-daily-bar-value {
    font-size: 0.8rem;
}


.coach-daily-day-label {
    color: var(--text-mid, var(--text-muted));
    margin-top: 6px;
    padding-bottom: 6px;
}

.coach-daily-bar-value {
    color: var(--text);
    font-weight: 600;
    margin-top: 2px;
}

.coach-daily-bar-target {
    color: var(--text-mid, var(--text-muted));
    margin-top: 1px;
}
.coach-bar-val {
    font-family: var(--font-head);
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--text-mid);
    text-align: right;
}

/* ── EXERCISE LOGS ──────────────────────────────────────────── */
.exercise-log-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.exercise-log-row {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-rows: auto auto;
    gap: 2px 12px;
    padding: 10px 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.exercise-log-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    grid-column: 1;
}
.exercise-log-name {
    font-weight: 600;
    font-size: 0.88rem;
    color: var(--text);
}
.exercise-log-date {
    font-size: 0.75rem;
    color: var(--text-dim);
}
.exercise-log-text {
    font-size: 0.82rem;
    color: var(--text-mid);
    grid-column: 1;
}
.exercise-log-stars {
    font-size: 0.8rem;
    color: var(--accent);
    grid-column: 2;
    grid-row: 1 / 3;
    align-self: center;
    letter-spacing: 1px;
}

/* ── Recent Set Logs (coach-pro v3.2 §3, redesigned May 2026) ───────────────
   Date-grouped rollup: one card per date, exercises stacked inside, each
   set rendered as a blue accent pill. Mirrors the visual language of the
   end-user spotlight-more "Today" view (.spotlight-more-set-pill in
   spotlight-more.css) and the coach-panel inline editor — coach sees the
   same pills the client used to log, no new visual vocabulary to learn.
   Different slot from activityLog (.exercise-log-* above) — both blocks
   render back-to-back in the Fitness Compliance section per CLAUDE.md
   invariant #173.
   ─────────────────────────────────────────────────────────────────────── */
.set-log-list {
    display: flex;
    flex-direction: column;
    /* Tighter inter-card gap — pre-tightening this was 12px which doubled
       up vertical real estate when stacked. 6px keeps cards visually
       distinct (border helps) without bleeding space. */
    gap: 6px;
}

/* One <details> per date — collapsed by default except the most recent day,
   which renders with `open` attr from JS so the coach immediately sees the
   latest activity. Native <details>/<summary> gives keyboard-accessible
   expand/collapse without JS event handlers. */
.set-log-day {
    padding: 0;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}
.set-log-day-header {
    cursor: pointer;
    user-select: none;
    list-style: none;          /* hide native triangle (Firefox) */
    display: flex;
    align-items: center;
    gap: 10px;
    /* Tightened 12px 14px → 8px 12px to reduce per-row height; with 14 days
       in the strip, the savings stack to ~100px vertical. */
    padding: 8px 12px;
    /* Font size tightened 0.88 → 0.82rem — still bold enough to read as
       a header against the dim count meta on the right. */
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text);
    letter-spacing: 0.2px;
}
/* Chrome/Safari native marker — hide so our chevron is the only indicator. */
.set-log-day-header::-webkit-details-marker { display: none; }

/* CSS-triangle chevron — points right when collapsed, rotates to point down
   when the day is expanded. Lighter weight than a unicode glyph or SVG. */
.set-log-day-chevron {
    display: inline-block;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 5px 0 5px 7px;
    border-color: transparent transparent transparent var(--text-mid);
    transition: transform 0.2s ease;
    flex-shrink: 0;
}
.set-log-day[open] > .set-log-day-header > .set-log-day-chevron {
    transform: rotate(90deg);
}

/* Push the count meta to the right of the date label. */
.set-log-day-date  { flex: 1; }
.set-log-day-count {
    font-size: 0.75rem;
    color: var(--text-dim);
    font-weight: 500;
}

/* Body wrapper — gives the exercises consistent inset from the header
   regardless of the <details> internal padding. Tightened 14px → 12px
   horizontal and 14px → 10px bottom to shave another ~6px off each
   expanded card. */
.set-log-day-body {
    padding: 0 12px 10px;
}

/* Exercise block within a day — name, then row of pills. */
.set-log-exercise {
    margin-top: 10px;
}
.set-log-exercise:first-of-type {
    margin-top: 0;
}
.set-log-exercise-name {
    font-size: 0.85rem;
    color: var(--text-mid);
    font-weight: 600;
    margin-bottom: 6px;
}

/* Pill row — flex-wraps to multiple lines when 4+ pills don't fit on one. */
.coach-set-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Set pill — color/sizing mirrored from .spotlight-more-set-pill in
   spotlight-more.css line 84 (read-only display, no cursor:pointer or
   hover state since these aren't interactive in the coach view). */
.coach-set-pill {
    display: inline-flex;
    align-items: center;
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    border: 1px solid var(--accent);
    color: var(--accent);
    border-radius: 20px;
    padding: 5px 12px;
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
}

/* ── WEIGHT ─────────────────────────────────────────────────── */
.weight-summary {
    display: flex;
    align-items: baseline;
    gap: 16px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}
.weight-current {
    font-family: var(--font-head);
    font-size: 2rem;
    font-weight: 800;
    color: var(--text);
}
.weight-delta {
    font-family: var(--font-head);
    font-size: 0.9rem;
    font-weight: 700;
}
.weight-sparkline { margin-bottom: 4px; }

/* viewBox width is computed in JS to match screen width exactly,
   so the SVG fills its container with ~1:1 px mapping.
   Height is fixed — only the x spacing grows on wider screens.
   vector-effect keeps stroke width crisp at any scale. */
.weight-sparkline-svg {
    display: block;
    width: 100%;
    height: 180px;
    overflow: visible;
}
.weight-labels {
    display: flex;
    justify-content: space-between;
    font-size: 0.7rem;
    color: var(--text-dim);
    font-family: var(--font-head);
}

/* ════════════════════════════════════════════════════════════
   PROGRAM BUILDER
════════════════════════════════════════════════════════════ */

/* ── Header ─────────────────────────────────────────────────── */
.prog-builder-header {
    margin-bottom: 24px;
}
.prog-builder-title-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 4px;
}
.prog-builder-title {
    font-family: var(--font-head);
    font-size: 1.4rem;
    font-weight: 800;
}
.prog-builder-meta {
    font-size: 0.8rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
}
.prog-builder-notes {
    font-size: 0.85rem;
    color: var(--text-mid);
    margin-top: 4px;
}

/* ── Week / Day grid ────────────────────────────────────────── */
.prog-weeks {
    display: flex;
    flex-direction: column;
    gap: 24px;
}
.prog-week-label {
    font-family: var(--font-head);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 10px;
}
.prog-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 8px;
    overflow-x: auto;
}

/* ── Day card ───────────────────────────────────────────────── */
.prog-day-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-height: 120px;
    min-width: 150px;
}
.prog-day-card--rest {
    opacity: 0.7;
}
.prog-day-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.prog-day-label {
    font-family: var(--font-head);
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text);
}
.prog-rest-toggle {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.72rem;
    color: var(--text-dim);
    cursor: pointer;
    user-select: none;
}
.prog-rest-toggle input { accent-color: var(--accent); }
.prog-rest-label {
    font-family: var(--font-head);
    font-size: 1.4rem;
    font-weight: 800;
    color: var(--text-mid);
    text-align: center;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    letter-spacing: -0.5px;
}

/* ── Exercise list in day card ──────────────────────────────── */
.prog-ex-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
}
.prog-ex-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.prog-ex-info { flex: 1; min-width: 0; }
.prog-ex-name {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.prog-ex-detail {
    font-size: 0.68rem;
    color: var(--text-dim);
    margin-top: 1px;
}
.prog-ex-remove {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 2px 4px;
    flex-shrink: 0;
    /* Icon is a child <span>, not text — flex centers the 14×14 icon
       inside the button's clickable padding box. color/font-size removed
       since there's no text content anymore; the icon's color is driven
       by background-color on .prog-ex-remove-icon below. */
    display: inline-flex;
    align-items: center;
}

/* Trash icon for the exercise-remove button. Uses mask-image rather than
   background-image (the pattern used by the Back/Assign buttons) because
   we need a two-color hover transition: text-dim → red. With mask-image,
   the visible colour is set by background-color, so a simple
   transitioned color swap on hover works. With background-image we'd be
   stuck with a single tinted PNG plus opacity tricks, which can't match
   --red precisely.
   Atlas geometry (total height + this row's Y) is the single source of truth
   in assets_art_and_animation.json; coach-state.js hydrates it into the CSS
   vars --ui-atlas-h and --ui-y-ui_trash_icon (see app/claude-ui-atlas.md).
   ui_trash_icon is currently row 20 → native y=320, atlas height 720. We
   render at 14×14 (slightly smaller than the atlas's intrinsic 16×16) to fit
   the existing 0.7rem button footprint without enlarging the row, so the mask
   is scaled by 14/16 = 0.875:
       mask-size:     14 × (atlas-h × 0.875)   → 14 × 630 today
       mask-position: 0 × −(trash-y × 0.875)   → 0 −280 today
   The var() fallbacks equal today's values, so this renders correctly even
   if the hydrate fetch fails; when the atlas changes, the vars track it.
   The -webkit-mask-* aliases are required for Safari (still treats
   mask-* as experimental on some versions). */
.prog-ex-remove-icon {
    display: inline-block;
    width: 14px;
    height: 14px;
    background-color: var(--text-dim);
    -webkit-mask-image: url('../app/assets_art/atlas_ui_icons.png');
            mask-image: url('../app/assets_art/atlas_ui_icons.png');
    -webkit-mask-size: 14px calc(var(--ui-atlas-h, 720px) * 0.875);
            mask-size: 14px calc(var(--ui-atlas-h, 720px) * 0.875);
    -webkit-mask-position: 0 calc(var(--ui-y-ui_trash_icon, 320px) * -0.875);
            mask-position: 0 calc(var(--ui-y-ui_trash_icon, 320px) * -0.875);
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    transition: background-color 0.12s;
}
.prog-ex-remove:hover .prog-ex-remove-icon { background-color: var(--red); }
.prog-add-ex-btn {
    background: transparent;
    border: 1px dashed var(--border-mid);
    border-radius: 6px;
    color: var(--text-dim);
    font-size: 0.75rem;
    font-family: var(--font-head);
    font-weight: 700;
    padding: 6px;
    cursor: pointer;
    transition: border-color 0.12s, color 0.12s;
    text-align: center;
    width: 100%;
}
.prog-add-ex-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

/* ── Exercise picker — floating draggable panel ─────────────── */
/*
 * Aug 2026: was a full-height sidebar (top:0; right:0; height:100vh) behind a
 * 50%-black .prog-picker-overlay scrim. Both were removed so it can behave like
 * every /app panel — floating, movable, and scrim-free so the day columns stay
 * readable and clickable while you pick exercises.
 *
 * ⚠️ DO NOT restore `height: 100vh`. /app/panel-drag.js clamps vertical travel
 * with `maxY = window.innerHeight - panel.offsetHeight`; at full height that is
 * 0, so the panel silently loses all vertical movement and only slides
 * sideways. The bounded max-height IS what makes dragging work.
 *
 * `top`/`right` here are only the OPENING position. Once dragged, panel-drag.js
 * writes inline left/top and sets right/bottom to auto, and the panel keeps
 * that spot for the rest of the session — same as /app.
 */
.prog-picker {
    position: fixed;
    top: 76px;
    right: 24px;
    width: 380px;
    max-height: calc(100dvh - 100px);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.45);
    z-index: 101;
    display: flex;
    flex-direction: column;
    /* NO `overflow: hidden` here — it would clip the ⠿ width-resizer, which is
       deliberately positioned OUTSIDE the panel at left:-12px. The bottom
       corners are kept clean by the matching radius on .prog-picker-results,
       whose own `overflow-y: auto` already clips its hovered rows. */
}
.prog-picker-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 18px 20px;
    border-bottom: 1px solid var(--border);
    /* Grab affordance — mirrors .panel-header in /app/panel.css. user-select
       stops the "Add Exercise" title highlighting as you drag. */
    cursor: grab;
    user-select: none;
    -webkit-user-select: none;
}
.prog-picker-header:active,
.prog-picker.is-dragging .prog-picker-header {
    cursor: grabbing;
}
/* Drag is desktop-only (panel-drag.js early-returns under 600px), so don't
   advertise a grab cursor on touch. */
@media (max-width: 600px) {
    .prog-picker-header { cursor: default; }
}
.prog-picker-title {
    font-family: var(--font-head);
    font-size: 1rem;
    font-weight: 800;
}
.prog-picker-search {
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.prog-picker-filters {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}
.prog-filter-select {
    flex: 1;
    min-width: 100px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 8px;
    color: var(--text);
    font-size: 0.75rem;
    font-family: var(--font-body);
    outline: none;
}
.prog-filter-select:focus { border-color: var(--accent); }
.prog-picker-results {
    flex: 1;
    /* Required now that the panel is max-height bounded instead of 100vh: a
       flex item's default min-height:auto refuses to shrink below its content,
       so without this the list pushes the panel past its max-height and the
       inner scroll never engages. Same flex gotcha as invariant #208. */
    min-height: 0;
    overflow-y: auto;
    padding: 8px 0;
    /* Clips hovered rows to the panel's rounded bottom corners (this element's
       own overflow-y:auto provides the clipping context). 9px = the panel's
       10px radius minus its 1px border. */
    border-radius: 0 0 9px 9px;
}

/* Mobile: dock as a near-full-width sheet. Drag is desktop-only, and the
   380px floating panel would overflow a 360px phone. */
@media (max-width: 600px) {
    .prog-picker {
        top: 8px;
        left: 8px;
        right: 8px;
        width: auto;
        max-height: calc(100dvh - 16px);
    }
}
.prog-ex-result {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border);
    transition: background 0.1s;
}
.prog-ex-result:hover { background: var(--bg-card-2); }
.prog-ex-result-info { flex: 1; min-width: 0; }
.prog-ex-result-name {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.prog-ex-result-meta {
    display: flex;
    gap: 6px;
    margin-top: 2px;
}
.prog-ex-result-meta span {
    font-size: 0.68rem;
    color: var(--text-dim);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 1px 5px;
}

/* ── Animated exercise preview (Aug 2026) ───────────────────── */
/*
 * Mirrors /app's slice cards so the coach sees what the client sees. The icons
 * are painted by /app/sprites.js (loaded verbatim — see index.html), which sets
 * background-image + background-position on the <img> and animates it; the
 * element's own src is a transparent blank.gif. So: never set a background or a
 * width/height override on .prog-preview-icon here — sprites.js computes the
 * atlas scale from --icon-size and would be fighting this file.
 */
.prog-preview-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    margin-top: 8px;
    padding: 6px 8px;
    background: none;
    border: none;
    border-top: 1px solid var(--border);
    color: var(--text-dim);
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: color 0.12s;
}
.prog-preview-toggle:hover { color: var(--accent); }
.prog-preview-chev { font-size: 0.6rem; }

.prog-preview-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
    padding: 6px 0 2px;
}
/* Needed because the grid declares an explicit display — the browser's built-in
   [hidden]/.hidden rule would otherwise lose. Same class of bug as the
   .emoji-picker-grid / .spotlight-more-* overrides in /app. */
.prog-preview-grid.hidden { display: none !important; }

.prog-preview-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 8px 4px 6px;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 6px;
    min-width: 0;
}
/* The atlas art is grayscale; the colour comes entirely from this filter, which
   icon-tint.js writes onto :root (see programEnsureSpriteAssets). Matches how
   /app tints animated sprites — they can't use the canvas recolor path because
   they're CSS background-images. Falls back to `none` (raw gray, still legible)
   if icon-tint.js ever fails to load, rather than disappearing. */
.prog-preview-icon {
    filter: var(--icon-accent-filter, none);
}

.prog-preview-time {
    font-size: 0.62rem;
    color: var(--text-dim);
    align-self: flex-start;
    padding-left: 2px;
}
.prog-preview-name {
    font-size: 0.66rem;
    color: var(--text);
    text-align: center;
    line-height: 1.2;
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.prog-preview-card:hover .prog-preview-name {
    white-space: normal;
    word-break: break-word;
}

/* Narrow day columns can't fit two cards side by side. */
@media (max-width: 1100px) {
    .prog-preview-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
    /* sprites.js drives playback via the Web Animations API, so CSS can't stop
       it — this only softens the toggle. Honouring reduced-motion properly
       would mean pausing the animations in JS; noted, not done. */
    .prog-preview-toggle { transition: none; }
}

/* ── Program builder extra styles ───────────────────────────── */
.prog-week-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
}
.prog-week-header .prog-week-label { margin-bottom: 0; }

/* Template cards */
.prog-template-card {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px 24px;
    border-bottom: 1px solid var(--border);
    transition: background 0.1s;
}
.prog-template-card:last-child { border-bottom: none; }
.prog-template-card:hover { background: var(--bg-card-2); }
.prog-template-info { flex: 1; }
.prog-template-name {
    font-family: var(--font-head);
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 3px;
}
.prog-template-desc {
    font-size: 0.78rem;
    color: var(--text-mid);
    line-height: 1.4;
    margin-bottom: 4px;
}
.prog-template-meta {
    font-size: 0.7rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
}
.prog-ai-card {
    background: var(--accent-dim);
    border-top: 1px solid rgba(70,165,206,0.2);
}
.prog-ai-card:hover { background: rgba(70,165,206,0.12); }
.prog-ai-card .prog-template-name { color: var(--accent); }

/* ── Day focus label ────────────────────────────────────────── */
.prog-day-focus {
    font-size: 0.7rem;
    color: var(--accent);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    margin-top: 1px;
}

/* Override .btn-sm padding/font-size for the Back button so its rendered
   height matches .prog-assign-btn (which is sized independently of .btn).
   Without this the Back button is shorter and sits lower than Assign,
   even though both share the same flex row. Match the Assign values
   exactly — padding 10px 18px, font-size 0.88rem — so the two buttons
   align on a common baseline. */
#prog-back-btn.btn-sm { padding: 10px 18px; font-size: 0.88rem; }

/* ── Assign to client button ────────────────────────────────── */
.prog-assign-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--green);
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 10px 18px;
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.88rem;
    cursor: pointer;
    transition: filter 0.15s;
    /* Was margin-top: 24px — that pushed Assign below Back's baseline,
       creating a stair-step. Now that #prog-back-btn matches Assign's
       height, both buttons sit on the same y-axis with no offset. */
    margin-top: 0;
}
.prog-assign-btn:hover { filter: brightness(1.1); }

/* ── Atlas icons for Back / Assign buttons ──────────────────────────────────
   References the UI icon atlas maintained in /app/assets_art/. The /coach/
   portal doesn't ship its own copy of the atlas — single-source-of-truth
   lives in /app/, see app/claude-ui-atlas.md for the full system docs.
   Atlas geometry comes from assets_art_and_animation.json; coach-state.js
   hydrates it into CSS vars (--ui-atlas-h for the total height, --ui-y-<stem>
   per row) so these rules never hardcode the height again. Row offsets used:
       ui_back_icon    → y = 32   (row 2,  back/"Programs" button)
       ui_forward_icon → y = 448  (row 28, Assign button)
   var() fallbacks equal today's values (height 720), so the buttons render
   correctly even before the hydrate fetch lands or if it fails.
   We avoid Unicode arrow glyphs (← / ↗) here because iOS Safari falls
   through to the emoji font and renders them as oversized colored emoji
   that don't match the button typography. */

.prog-back-icon,
.prog-assign-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    background-image: url('../app/assets_art/atlas_ui_icons.png');
    background-size: 16px var(--ui-atlas-h, 720px);
    background-repeat: no-repeat;
    flex-shrink: 0;
}

/* Back button is .btn-ghost — text-mid (#888) at rest, text (#efefef) on
   hover. Approximate the same value progression for the icon via opacity
   on a brightness(0) invert(1) (force-white) source. */
.prog-back-icon {
    background-position: 0 calc(var(--ui-y-ui_back_icon, 32px) * -1);
    filter: brightness(0) invert(1);
    opacity: 0.65;
    transition: opacity 0.15s;
}
.btn-ghost:hover .prog-back-icon { opacity: 1; }

/* Assign button is white text on green — pure white icon. */
.prog-assign-icon {
    background-position: 0 calc(var(--ui-y-ui_forward_icon, 448px) * -1);
    filter: brightness(0) invert(1);
}

/* ── Days-per-week selector ─────────────────────────────────── */
.prog-days-selector {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}
.prog-days-selector-label {
    font-size: 0.72rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    margin-right: 4px;
}
.prog-days-selector-btn {
    width: 28px;
    height: 28px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-dim);
    font-size: 0.78rem;
    font-family: var(--font-head);
    font-weight: 700;
    cursor: pointer;
    transition: all 0.12s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.prog-days-selector-btn:hover { border-color: var(--accent); color: var(--text); }
.prog-days-selector-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* ── Picker drag handle ─────────────────────────────────────── */
.prog-picker-drag-handle {
    position: absolute;
    left: -12px;
    top: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 48px;
    background: var(--border-mid);
    border-radius: 4px 0 0 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: ew-resize;
    color: var(--text-dim);
    font-size: 0.7rem;
    transition: background 0.12s;
}
.prog-picker-drag-handle:hover { background: var(--accent); color: #fff; }

/* ── Exercise result name — show full on hover ──────────────── */
.prog-ex-result-name {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: default;
    transition: white-space 0.15s;
}
.prog-ex-result:hover .prog-ex-result-name {
    white-space: normal;
    word-break: break-word;
}

/* ── Exercise picker pagination ─────────────────────────────── */
.prog-picker-pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
    background: var(--bg-card);
    position: sticky;
    bottom: 0;
}
.prog-page-btn {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: 6px;
    color: var(--text);
    width: 32px;
    height: 32px;
    font-size: 0.9rem;
    cursor: pointer;
    transition: all 0.12s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.prog-page-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.prog-page-btn:disabled { opacity: 0.3; cursor: not-allowed; }

/* ── Focus selector strip (replaces Rest checkbox) ──────────────────── */
.prog-focus-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 6px;
}
.prog-focus-btn {
    padding: 3px 8px;
    border-radius: 100px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-dim);
    font-size: 0.65rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.3px;
    cursor: pointer;
    transition: all 0.12s;
    white-space: nowrap;
}
.prog-focus-btn:hover {
    border-color: var(--accent);
    color: var(--text);
}
.prog-focus-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}
/* Rest Day pill no longer gets a muted override — it inherits the default
   accent-blue active state above so the coach can clearly see when Rest is
   the current selection. The earlier muted treatment was reported as making
   Rest look unselected, undermining the prompt to flip away from it. The
   Off pill never had an override; both Rest and Off now render in accent
   blue when active, matching every other focus pill. See coach-pro.md
   April 27 2026. */

/* ── Google OAuth button ─────────────────────────────────────────────────── */
.btn-google {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 12px;
    background: #1a1a1a;
    color: #efefef;
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 8px;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
    margin-bottom: 4px;
}
.btn-google:hover { background: #252525; border-color: rgba(255,255,255,0.3); }

.auth-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 16px 0;
    color: var(--text-dim);
    font-size: 0.75rem;
}
.auth-divider::before,
.auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}

/* ════════════════════════════════════════════════════════════
   ADMIN IMPERSONATION — banner, admin view, break-glass modal
   See coach-admin-impersonation-prd.md §6 and coach/coach-admin.js.

   Banner geometry uses --impersonation-banner-h declared on :root.
   Three places reference the height: the banner itself, the body's
   padding-top compensation while impersonating, and the offset/height
   of the fixed sidebar so it doesn't vanish behind the amber bar.
════════════════════════════════════════════════════════════ */

/* ── Banner ─────────────────────────────────────────────────── */
.coach-impersonation-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--impersonation-banner-h);
    z-index: 100;                                /* above sidebar (50) and topbar (40) */
    background: linear-gradient(180deg, var(--banner-amber-2), var(--banner-amber));
    color: var(--banner-amber-text);
    border-bottom: 1px solid rgba(0, 0, 0, 0.25);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 20px;
    font-family: var(--font-body);
    font-size: 0.85rem;
    line-height: 1.2;
}
.coach-impersonation-banner__lens {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.coach-impersonation-banner__label {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.7rem;
    opacity: 0.78;
}
.coach-impersonation-banner__name {
    font-weight: 800;
    font-family: var(--font-head);
    font-size: 0.95rem;
}
.coach-impersonation-banner__email {
    opacity: 0.78;
    overflow: hidden;
    text-overflow: ellipsis;
}
.coach-impersonation-banner__countdown {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    opacity: 0.9;
    flex-shrink: 0;
}
.coach-impersonation-banner__end-btn {
    background: rgba(0, 0, 0, 0.85);
    color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.5);
    border-radius: 6px;
    padding: 6px 14px;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    flex-shrink: 0;
    transition: filter 0.12s, transform 0.12s;
}
.coach-impersonation-banner__end-btn:hover { filter: brightness(1.2); transform: translateY(-1px); }
.coach-impersonation-banner__end-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

/* Body modifier — applied/removed by coach-admin.js. Shifts the rest
   of the layout down so nothing hides behind the fixed amber bar. */
body.coach-impersonating { padding-top: var(--impersonation-banner-h); }
body.coach-impersonating .coach-sidebar {
    top: var(--impersonation-banner-h);
    height: calc(100vh - var(--impersonation-banner-h));
    height: calc(100dvh - var(--impersonation-banner-h));
}

/* ── Admin view (#view-admin) ───────────────────────────────── */
.admin-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px 24px;
    margin-bottom: 20px;
}
.admin-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 12px;
    gap: 12px;
}
.admin-section-title {
    font-family: var(--font-head);
    font-size: 1rem;
    font-weight: 800;
    margin-bottom: 12px;
}
.admin-section-head .admin-section-title { margin-bottom: 0; }
.admin-section-sub {
    font-size: 0.78rem;
    color: var(--text-dim);
}
.admin-search-input { width: 100%; }
.admin-search-results {
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.admin-search-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.admin-search-result-info { min-width: 0; }
.admin-search-result-name {
    font-weight: 600;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.admin-search-result-email {
    font-size: 0.78rem;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.admin-empty {
    color: var(--text-dim);
    font-size: 0.85rem;
    padding: 8px 0;
}

/* Audit log activity list */
.admin-activity {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.admin-activity-row {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.admin-activity-row > summary {
    list-style: none;
    cursor: pointer;
    padding: 8px 12px;
    display: grid;
    grid-template-columns: minmax(120px, max-content) auto 1fr auto;
    align-items: center;
    gap: 10px;
    font-size: 0.82rem;
}
.admin-activity-row > summary::-webkit-details-marker { display: none; }
.admin-activity-row[open] > summary { border-bottom: 1px solid var(--border); }
.admin-activity-action {
    font-weight: 600;
    color: var(--accent);
    font-family: var(--font-body);
}
.admin-activity-surface {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
    background: var(--bg-input);
    padding: 2px 6px;
    border-radius: 4px;
}
.admin-activity-target {
    color: var(--text);
    font-weight: 500;
}
.admin-activity-time {
    color: var(--text-dim);
    font-size: 0.75rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.admin-activity-payload {
    margin: 0;
    padding: 12px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    color: var(--text-mid);
    background: var(--bg-input);
    overflow-x: auto;
    white-space: pre;
}

/* ── Break-glass modal content (uses .coach-modal-* shell) ─── */
.impersonate-target-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
    margin-bottom: 6px;
}
.impersonate-target-display {
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 0.9rem;
}
.impersonate-target-display strong {
    font-weight: 700;
    margin-right: 8px;
}
.impersonate-target-email {
    color: var(--text-dim);
    font-size: 0.8rem;
}
.impersonate-examples {
    margin-top: 10px;
    font-size: 0.78rem;
}
.impersonate-examples-heading {
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.7rem;
    margin-bottom: 4px;
}
.impersonate-examples ul {
    margin: 0;
    padding-left: 18px;
    color: var(--text-mid);
    line-height: 1.6;
}
.form-help {
    margin-top: 6px;
    font-size: 0.75rem;
    color: var(--text-dim);
    line-height: 1.4;
}

/* ── Mobile (matches existing 860px breakpoint) ─────────────── */
@media (max-width: 860px) {
    .coach-impersonation-banner {
        padding: 0 12px;
        gap: 10px;
        font-size: 0.78rem;
    }
    .coach-impersonation-banner__email { display: none; }   /* keep name + countdown + end-btn on one line */
    .coach-impersonation-banner__name  { font-size: 0.85rem; }
    .coach-impersonation-banner__end-btn { padding: 5px 10px; font-size: 0.75rem; }

    .admin-section { padding: 16px; }
    .admin-activity-row > summary {
        grid-template-columns: 1fr auto;
        row-gap: 4px;
    }
    .admin-activity-surface, .admin-activity-time {
        grid-column: 2;
        justify-self: end;
    }
}


/* ── Referral Share Card (Phase 1 — Coach Partner Program referral mechanics) ── */
/* Renders at the top of the dashboard view; spec: monetize-coach-referral-spec.md v3 */

/* Referral link content inside the My Clients .coach-section card.
   The old standalone .referral-card flex wrapper is gone — the section
   card provides the outer styling now. These classes style the inner
   URL display, hint text, and the 3-button action row. */
.referral-card-url {
    font-family: monospace;
    font-size: 0.95rem;
    color: var(--accent, #46a5ce);
    cursor: pointer;
    word-break: break-all;
    line-height: 1.4;
    user-select: all;
}
.referral-card-url:hover { text-decoration: underline; }
.referral-card-hint {
    font-size: 0.82rem;
    color: var(--text-mid);
    margin-top: 10px;
    line-height: 1.5;
}
/* Action row — 3 buttons inline (Share / Test / + Invite Client).
   Wraps on narrow viewports so buttons don't overflow. */
.referral-card-actions {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 18px;
}
.referral-card-actions .btn {
    white-space: nowrap;
}
.referral-card-empty {
    padding: 14px 20px;
    margin: 0 0 18px;
    background: var(--bg-card, #1a1a1a);
    border: 1px dashed var(--border, rgba(255,255,255,0.08));
    border-radius: 10px;
    font-size: 0.85rem;
    color: var(--text-dim, #888);
    text-align: center;
    line-height: 1.5;
}
@media (max-width: 600px) {
    .referral-card-actions {
        gap: 6px;
    }
    .referral-card-actions .btn {
        flex: 1 1 calc(50% - 6px);   /* roughly 2 per row on tight screens */
    }
}

/* ── Programs Section (May 23 2026) ─────────────────────────────────────── */
/* Renders between Body Weight and Fitness Compliance on the client dashboard. */
/* Per-program: name + progress bar + completion counts + assigned/end dates. */
/* Visual conventions match existing .client-section / .coach-bar-* patterns. */

.coach-program-list {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.coach-program-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.coach-program-row-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
}
.coach-program-name {
    font-family: var(--font-head, inherit);
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-main, #fff);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.coach-program-stats {
    font-size: 0.8rem;
    color: var(--text-dim, #888);
    flex-shrink: 0;
    white-space: nowrap;
}
.coach-program-bar-track {
    /* Inherits .coach-bar-track height/background; just full-width inside the
       program row (no label/value flanking it like in compliance bars). */
    flex: none;
    width: 100%;
}
.coach-program-meta {
    font-size: 0.78rem;
    color: var(--text-dim, #888);
    letter-spacing: 0.2px;
}

@media (max-width: 600px) {
    .coach-program-row-head {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }
    .coach-program-name {
        font-size: 0.9rem;
    }
}

/* ════════════════════════════════════════════════════════════
   ADMIN — Recent account viewings session rows
   Each row pairs an impersonation start with its matching end,
   replacing the older per-event audit-log row format.
════════════════════════════════════════════════════════════ */

.admin-session-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 20px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 8px;
}
.admin-session-name {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text);
}
.admin-session-times {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.82rem;
    color: var(--text-mid);
    text-align: right;
}
.admin-session-time-row {
    white-space: nowrap;
}
.admin-session-time-label {
    color: var(--text-dim);
    font-weight: 600;
    margin-right: 6px;
}
.admin-session-time-active {
    color: var(--green);
    font-weight: 600;
}
@media (max-width: 600px) {
    .admin-session-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
        padding: 12px 16px;
    }
    .admin-session-times {
        text-align: left;
        width: 100%;
    }
}

/* ════════════════════════════════════════════════════════════
   COACH PANEL — shared section/card pattern
   Used by both Settings (Profile / Payouts / Account cards) and the
   My Clients dashboard (Referral link / Your clients cards). One
   visual language across the panel so every page feels consistent.
   .settings-section is an alias kept for backward compatibility.
════════════════════════════════════════════════════════════ */

.settings-page {
    max-width: 540px;
}
/* Section card — padding lives on the body now, not the card, so the header
   can have its own lighter bg that goes edge-to-edge inside the rounded card.
   overflow:hidden clips the header bg to the card's rounded corners. */
.coach-section,
.settings-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 20px;
}
/* Header strip — lighter bg + bottom border give clear visual separation
   from the body. Padding lives here (not on the section) so the bg fills
   the strip edge-to-edge. Uses --bg-card-header (dedicated header tone,
   ~12% lighter than card body) so the separation is clearly perceivable. */
.coach-section-header,
.settings-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 28px;
    background: var(--bg-card-header);
    border-bottom: 1px solid var(--border-mid);
}
/* Wraps icon + title together on the LEFT so they read as a group.
   Without this wrapper, justify-content:space-between would push the
   icon and title to opposite ends of the header — see the May 2026
   fix described in the Settings UI changelog. */
.settings-section-header-left,
.coach-section-header-left {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
/* Emojis must never receive the accent filter — they show true colors
   (same rule as .mood-face-img and emoji-picker icons across the app). */
.settings-section-icon {
    font-size: 1.3rem;
    line-height: 1;
    filter: none !important;
}
.coach-section-title,
.settings-section-title {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--text);
    letter-spacing: -0.3px;
}
/* Right-aligned subtle counter next to a section title (e.g. "Your clients
   · 1 CLIENT"). Sits opposite the title in the flex header row. */
.coach-section-count {
    font-size: 0.78rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}
/* Body — owns the inner padding. The section card itself has no padding
   so the header strip can sit flush against the card edges. */
.coach-section-body,
.settings-section-body {
    padding: 24px 28px;
}
/* Tertiary "soft accent" button — dim accent fill + accent border.
   Sits between btn-primary (filled accent) and btn-secondary (white outline)
   in visual weight. Used on the My Clients dashboard for + Invite Client
   so it reads as a third distinct action alongside Share / Test. */
.btn-accent-soft {
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    color: var(--text);
    border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
}
.btn-accent-soft:hover {
    background: color-mix(in srgb, var(--accent) 28%, transparent);
    border-color: var(--accent);
}
@media (max-width: 600px) {
    .coach-section,
    .settings-section {
        margin-bottom: 16px;
    }
    .coach-section-header,
    .settings-section-header {
        padding: 14px 18px;
    }
    .coach-section-body,
    .settings-section-body {
        padding: 20px 18px;
    }
}

/* ════════════════════════════════════════════════════════════
   EARNINGS VIEW
   Used by:
     - /coach/index.html   #view-earnings  (live tab)
     - /coach/earnings-demo.html           (preview / screenshots)
   Single source of truth — no inline duplicate styles.
════════════════════════════════════════════════════════════ */

.earnings-view { max-width: 880px; }

.earnings-kpi-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 36px 32px 28px;
    margin-bottom: 32px;
    position: relative;
    overflow: hidden;
}
.earnings-kpi-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: var(--accent);
}

/* ── Hero this-month KPI ─────────────────────────────────── */
.earnings-hero {
    text-align: center;
    padding-bottom: 28px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--border);
}
.earnings-hero-label {
    font-size: 0.72rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 12px;
}
.earnings-hero-value {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 4.2rem;
    line-height: 1;
    color: var(--accent);
    letter-spacing: -2px;
}
.earnings-hero-value .currency {
    font-size: 2.8rem;
    vertical-align: top;
    margin-right: 4px;
    letter-spacing: 0;
}
.earnings-hero-sub {
    font-size: 0.82rem;
    color: var(--text-mid);
    margin-top: 10px;
}

/* ── Secondary stats row ─────────────────────────────────── */
.earnings-secondary-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 32px;
    margin-bottom: 24px;
}
.earnings-stat {
    min-width: 0;
}
.earnings-stat-label {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 6px;
}
.earnings-stat-value {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.5rem;
    line-height: 1.1;
    color: var(--text);
}
.earnings-stat-helper {
    font-size: 0.74rem;
    color: var(--text-dim);
    margin-top: 4px;
    line-height: 1.4;
}

.earnings-disclosure {
    font-size: 0.82rem;
    color: var(--text-mid);
    line-height: 1.55;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.earnings-disclosure a { color: var(--accent); }

/* ── Payout-setup placeholder card ───────────────────────── */
.earnings-payout-card {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 22px;
    margin-bottom: 32px;
    display: flex;
    align-items: center;
    gap: 14px;
}
.earnings-payout-icon {
    font-size: 1.4rem;
    line-height: 1;
}
.earnings-payout-text {
    font-size: 0.92rem;
    color: var(--text);
    flex: 1;
    min-width: 0;
}
.earnings-payout-text .muted {
    display: block;
    font-size: 0.78rem;
    color: var(--text-dim);
    margin-top: 2px;
}

/* ── Subscriber list ─────────────────────────────────────── */
.earnings-section-label {
    font-size: 0.72rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 14px;
}

.earn-list-cols {
    display: grid;
    grid-template-columns: 1fr 90px 90px 100px 100px;
    gap: 16px;
    padding: 8px 20px;
    margin-bottom: 6px;
}
.earn-list-col-label {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    text-align: right;
}
.earn-list-col-label:first-child { text-align: left; }

.earn-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.earn-row {
    display: grid;
    grid-template-columns: 1fr 90px 90px 100px 100px;
    align-items: center;
    gap: 16px;
    padding: 14px 20px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    transition: border-color 0.12s, background 0.12s;
}
.earn-row:nth-child(odd) {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.earn-row:hover {
    border-color: var(--border-mid);
}

.earn-display-name {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.earn-cell {
    font-size: 0.85rem;
    color: var(--text-mid);
    text-align: right;
}
.earn-cell.right-val {
    color: var(--text);
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.88rem;
}

.earn-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 100px;
    border: 1px solid;
    justify-self: end;
}
.earn-badge--active   { color: var(--green);    border-color: rgba(60,186,108,0.35); background: rgba(60,186,108,0.08); }
.earn-badge--pastdue  { color: var(--red);      border-color: rgba(224,82,82,0.35);  background: rgba(224,82,82,0.08); }
.earn-badge--canceled { color: var(--text-dim); border-color: var(--border);          background: transparent; }
.earn-badge--test     { color: #f0c074;         border-color: rgba(217,119,6,0.55);  background: rgba(217,119,6,0.18); }

/* Test rows render dimmed so they're visually separate from real revenue.
   Pairs with the amber TEST badge in the status column. */
.earn-row--test {
    opacity: 0.55;
}
.earn-row--test:hover {
    opacity: 0.85;
}

/* ── Affiliate-gate empty state ──────────────────────────── */
.earnings-gate {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 56px 32px;
    text-align: center;
    max-width: 560px;
    margin: 24px auto;
}
.earnings-gate-icon {
    font-size: 2.4rem;
    margin-bottom: 16px;
}
.earnings-gate-title {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 1.4rem;
    color: var(--text);
    margin-bottom: 12px;
}
.earnings-gate-body {
    font-size: 0.95rem;
    color: var(--text-mid);
    line-height: 1.55;
    margin-bottom: 28px;
}
.earnings-gate-cta {
    display: inline-block;
}

/* ── Demo ribbon (preview page only) ─────────────────────── */
.demo-ribbon {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 100px;
    border: 1px solid var(--accent);
    color: var(--accent);
    background: var(--accent-dim);
}

/* ── Demo-data banner (live tab, while backend is pending) ─
   Removed once api/coach/earnings-summary.php is wired up.
   Amber on dark — purposefully louder than the accent-blue
   palette so a partner can't miss that these numbers aren't
   theirs.                                                    */
.earnings-demo-banner {
    background: rgba(217,119,6,0.12);
    border: 1px solid rgba(217,119,6,0.45);
    border-radius: var(--radius);
    padding: 12px 16px;
    margin-bottom: 24px;
    font-size: 0.85rem;
    color: #f0c074;
    line-height: 1.5;
}
.earnings-demo-banner strong {
    color: #ffd693;
}

@media (max-width: 720px) {
    .earnings-hero-value      { font-size: 3.2rem; }
    .earnings-hero-value .currency { font-size: 2rem; }
    .earnings-secondary-row   { grid-template-columns: 1fr; gap: 20px; }

    /* Mobile subscriber list — single-row layout (matches desktop).
       Compact columns + smaller fonts + short date format so all five
       cells fit on one line at iPhone-SE 375px width. Long subscriber
       names (e.g. @rickstevens24) truncate with ellipsis. */
    .earn-list-cols {
        grid-template-columns: minmax(0, 1fr) 52px 56px 62px 64px;
        gap: 6px;
        padding: 4px 10px;
        margin-bottom: 4px;
    }
    .earn-list-col-label {
        font-size: 0.58rem;
        letter-spacing: 0.4px;
    }
    .earn-row {
        grid-template-columns: minmax(0, 1fr) 52px 56px 62px 64px;
        grid-template-areas: none;   /* clear desktop areas, use direct columns */
        gap: 6px;
        padding: 12px 10px;
        row-gap: 0;
    }
    .earn-display-name {
        font-size: 0.85rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        grid-area: auto;             /* clear desktop grid-area assignment */
    }
    .earn-cell {
        font-size: 0.72rem;
    }
    .earn-row .earn-cell:nth-of-type(1),
    .earn-row .earn-cell:nth-of-type(2),
    .earn-row .earn-cell:nth-of-type(3) {
        grid-area: auto;
        text-align: right;
    }
    .earn-cell.right-val {
        font-size: 0.76rem;
    }
    .earn-badge {
        grid-area: auto;
        padding: 2px 6px;
        font-size: 0.55rem;
        letter-spacing: 0.2px;   /* override desktop's 0.5px so "Past due" fits in one line */
    }
}

/* ── Program builder extra styles ───────────────────────────── */
.prog-week-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
}
.prog-week-header .prog-week-label { margin-bottom: 0; }

/* Template cards */
.prog-template-card {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px 24px;
    border-bottom: 1px solid var(--border);
    transition: background 0.1s;
}
.prog-template-card:last-child { border-bottom: none; }
.prog-template-card:hover { background: var(--bg-card-2); }
.prog-template-info { flex: 1; }
.prog-template-name {
    font-family: var(--font-head);
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 3px;
}
.prog-template-desc {
    font-size: 0.78rem;
    color: var(--text-mid);
    line-height: 1.4;
    margin-bottom: 4px;
}
.prog-template-meta {
    font-size: 0.7rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
}
.prog-ai-card {
    background: var(--accent-dim);
    border-top: 1px solid rgba(70,165,206,0.2);
}
.prog-ai-card:hover { background: rgba(70,165,206,0.12); }
.prog-ai-card .prog-template-name { color: var(--accent); }

/* ── Day focus label ────────────────────────────────────────── */
.prog-day-focus {
    font-size: 0.7rem;
    color: var(--accent);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    margin-top: 1px;
}

/* Override .btn-sm padding/font-size for the Back button so its rendered
   height matches .prog-assign-btn (which is sized independently of .btn).
   Without this the Back button is shorter and sits lower than Assign,
   even though both share the same flex row. Match the Assign values
   exactly — padding 10px 18px, font-size 0.88rem — so the two buttons
   align on a common baseline. */
#prog-back-btn.btn-sm { padding: 10px 18px; font-size: 0.88rem; }

/* ── Assign to client button ────────────────────────────────── */
.prog-assign-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--green);
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 10px 18px;
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.88rem;
    cursor: pointer;
    transition: filter 0.15s;
    /* Was margin-top: 24px — that pushed Assign below Back's baseline,
       creating a stair-step. Now that #prog-back-btn matches Assign's
       height, both buttons sit on the same y-axis with no offset. */
    margin-top: 0;
}
.prog-assign-btn:hover { filter: brightness(1.1); }

/* ── Atlas icons for Back / Assign buttons ──────────────────────────────────
   References the UI icon atlas maintained in /app/assets_art/. The /coach/
   portal doesn't ship its own copy of the atlas — single-source-of-truth
   lives in /app/, see app/claude-ui-atlas.md for the full system docs.
   Atlas geometry comes from assets_art_and_animation.json; coach-state.js
   hydrates it into CSS vars (--ui-atlas-h for the total height, --ui-y-<stem>
   per row) so these rules never hardcode the height again. Row offsets used:
       ui_back_icon    → y = 32   (row 2,  back/"Programs" button)
       ui_forward_icon → y = 448  (row 28, Assign button)
   var() fallbacks equal today's values (height 720), so the buttons render
   correctly even before the hydrate fetch lands or if it fails.
   We avoid Unicode arrow glyphs (← / ↗) here because iOS Safari falls
   through to the emoji font and renders them as oversized colored emoji
   that don't match the button typography. */

.prog-back-icon,
.prog-assign-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    background-image: url('../app/assets_art/atlas_ui_icons.png');
    background-size: 16px var(--ui-atlas-h, 720px);
    background-repeat: no-repeat;
    flex-shrink: 0;
}

/* Back button is .btn-ghost — text-mid (#888) at rest, text (#efefef) on
   hover. Approximate the same value progression for the icon via opacity
   on a brightness(0) invert(1) (force-white) source. */
.prog-back-icon {
    background-position: 0 calc(var(--ui-y-ui_back_icon, 32px) * -1);
    filter: brightness(0) invert(1);
    opacity: 0.65;
    transition: opacity 0.15s;
}
.btn-ghost:hover .prog-back-icon { opacity: 1; }

/* Assign button is white text on green — pure white icon. */
.prog-assign-icon {
    background-position: 0 calc(var(--ui-y-ui_forward_icon, 448px) * -1);
    filter: brightness(0) invert(1);
}

/* ── Days-per-week selector ─────────────────────────────────── */
.prog-days-selector {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}
.prog-days-selector-label {
    font-size: 0.72rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    margin-right: 4px;
}
.prog-days-selector-btn {
    width: 28px;
    height: 28px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-dim);
    font-size: 0.78rem;
    font-family: var(--font-head);
    font-weight: 700;
    cursor: pointer;
    transition: all 0.12s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.prog-days-selector-btn:hover { border-color: var(--accent); color: var(--text); }
.prog-days-selector-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* ── Picker drag handle ─────────────────────────────────────── */
.prog-picker-drag-handle {
    position: absolute;
    left: -12px;
    top: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 48px;
    background: var(--border-mid);
    border-radius: 4px 0 0 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: ew-resize;
    color: var(--text-dim);
    font-size: 0.7rem;
    transition: background 0.12s;
}
.prog-picker-drag-handle:hover { background: var(--accent); color: #fff; }

/* ── Exercise result name — show full on hover ──────────────── */
.prog-ex-result-name {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: default;
    transition: white-space 0.15s;
}
.prog-ex-result:hover .prog-ex-result-name {
    white-space: normal;
    word-break: break-word;
}

/* ── Exercise picker pagination ─────────────────────────────── */
.prog-picker-pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
    background: var(--bg-card);
    position: sticky;
    bottom: 0;
}
.prog-page-btn {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: 6px;
    color: var(--text);
    width: 32px;
    height: 32px;
    font-size: 0.9rem;
    cursor: pointer;
    transition: all 0.12s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.prog-page-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.prog-page-btn:disabled { opacity: 0.3; cursor: not-allowed; }

/* ── Focus selector strip (replaces Rest checkbox) ──────────────────── */
.prog-focus-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 6px;
}
.prog-focus-btn {
    padding: 3px 8px;
    border-radius: 100px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-dim);
    font-size: 0.65rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.3px;
    cursor: pointer;
    transition: all 0.12s;
    white-space: nowrap;
}
.prog-focus-btn:hover {
    border-color: var(--accent);
    color: var(--text);
}
.prog-focus-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}
/* Rest Day pill no longer gets a muted override — it inherits the default
   accent-blue active state above so the coach can clearly see when Rest is
   the current selection. The earlier muted treatment was reported as making
   Rest look unselected, undermining the prompt to flip away from it. The
   Off pill never had an override; both Rest and Off now render in accent
   blue when active, matching every other focus pill. See coach-pro.md
   April 27 2026. */

/* ── Google OAuth button ─────────────────────────────────────────────────── */
.btn-google {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 12px;
    background: #1a1a1a;
    color: #efefef;
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 8px;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
    margin-bottom: 4px;
}
.btn-google:hover { background: #252525; border-color: rgba(255,255,255,0.3); }

.auth-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 16px 0;
    color: var(--text-dim);
    font-size: 0.75rem;
}
.auth-divider::before,
.auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}

/* ════════════════════════════════════════════════════════════
   ADMIN IMPERSONATION — banner, admin view, break-glass modal
   See coach-admin-impersonation-prd.md §6 and coach/coach-admin.js.

   Banner geometry uses --impersonation-banner-h declared on :root.
   Three places reference the height: the banner itself, the body's
   padding-top compensation while impersonating, and the offset/height
   of the fixed sidebar so it doesn't vanish behind the amber bar.
════════════════════════════════════════════════════════════ */

/* ── Banner ─────────────────────────────────────────────────── */
.coach-impersonation-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--impersonation-banner-h);
    z-index: 100;                                /* above sidebar (50) and topbar (40) */
    background: linear-gradient(180deg, var(--banner-amber-2), var(--banner-amber));
    color: var(--banner-amber-text);
    border-bottom: 1px solid rgba(0, 0, 0, 0.25);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 20px;
    font-family: var(--font-body);
    font-size: 0.85rem;
    line-height: 1.2;
}
.coach-impersonation-banner__lens {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.coach-impersonation-banner__label {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.7rem;
    opacity: 0.78;
}
.coach-impersonation-banner__name {
    font-weight: 800;
    font-family: var(--font-head);
    font-size: 0.95rem;
}
.coach-impersonation-banner__email {
    opacity: 0.78;
    overflow: hidden;
    text-overflow: ellipsis;
}
.coach-impersonation-banner__countdown {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    opacity: 0.9;
    flex-shrink: 0;
}
.coach-impersonation-banner__end-btn {
    background: rgba(0, 0, 0, 0.85);
    color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.5);
    border-radius: 6px;
    padding: 6px 14px;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    flex-shrink: 0;
    transition: filter 0.12s, transform 0.12s;
}
.coach-impersonation-banner__end-btn:hover { filter: brightness(1.2); transform: translateY(-1px); }
.coach-impersonation-banner__end-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

/* Body modifier — applied/removed by coach-admin.js. Shifts the rest
   of the layout down so nothing hides behind the fixed amber bar. */
body.coach-impersonating { padding-top: var(--impersonation-banner-h); }
body.coach-impersonating .coach-sidebar {
    top: var(--impersonation-banner-h);
    height: calc(100vh - var(--impersonation-banner-h));
    height: calc(100dvh - var(--impersonation-banner-h));
}

/* ── Admin view (#view-admin) ───────────────────────────────── */
.admin-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px 24px;
    margin-bottom: 20px;
}
.admin-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 12px;
    gap: 12px;
}
.admin-section-title {
    font-family: var(--font-head);
    font-size: 1rem;
    font-weight: 800;
    margin-bottom: 12px;
}
.admin-section-head .admin-section-title { margin-bottom: 0; }
.admin-section-sub {
    font-size: 0.78rem;
    color: var(--text-dim);
}
.admin-search-input { width: 100%; }
.admin-search-results {
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.admin-search-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.admin-search-result-info { min-width: 0; }
.admin-search-result-name {
    font-weight: 600;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.admin-search-result-email {
    font-size: 0.78rem;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.admin-empty {
    color: var(--text-dim);
    font-size: 0.85rem;
    padding: 8px 0;
}

/* Audit log activity list */
.admin-activity {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.admin-activity-row {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.admin-activity-row > summary {
    list-style: none;
    cursor: pointer;
    padding: 8px 12px;
    display: grid;
    grid-template-columns: minmax(120px, max-content) auto 1fr auto;
    align-items: center;
    gap: 10px;
    font-size: 0.82rem;
}
.admin-activity-row > summary::-webkit-details-marker { display: none; }
.admin-activity-row[open] > summary { border-bottom: 1px solid var(--border); }
.admin-activity-action {
    font-weight: 600;
    color: var(--accent);
    font-family: var(--font-body);
}
.admin-activity-surface {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
    background: var(--bg-input);
    padding: 2px 6px;
    border-radius: 4px;
}
.admin-activity-target {
    color: var(--text);
    font-weight: 500;
}
.admin-activity-time {
    color: var(--text-dim);
    font-size: 0.75rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.admin-activity-payload {
    margin: 0;
    padding: 12px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    color: var(--text-mid);
    background: var(--bg-input);
    overflow-x: auto;
    white-space: pre;
}

/* ── Break-glass modal content (uses .coach-modal-* shell) ─── */
.impersonate-target-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-dim);
    margin-bottom: 6px;
}
.impersonate-target-display {
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 0.9rem;
}
.impersonate-target-display strong {
    font-weight: 700;
    margin-right: 8px;
}
.impersonate-target-email {
    color: var(--text-dim);
    font-size: 0.8rem;
}
.impersonate-examples {
    margin-top: 10px;
    font-size: 0.78rem;
}
.impersonate-examples-heading {
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.7rem;
    margin-bottom: 4px;
}
.impersonate-examples ul {
    margin: 0;
    padding-left: 18px;
    color: var(--text-mid);
    line-height: 1.6;
}
.form-help {
    margin-top: 6px;
    font-size: 0.75rem;
    color: var(--text-dim);
    line-height: 1.4;
}

/* ── Mobile (matches existing 860px breakpoint) ─────────────── */
@media (max-width: 860px) {
    .coach-impersonation-banner {
        padding: 0 12px;
        gap: 10px;
        font-size: 0.78rem;
    }
    .coach-impersonation-banner__email { display: none; }   /* keep name + countdown + end-btn on one line */
    .coach-impersonation-banner__name  { font-size: 0.85rem; }
    .coach-impersonation-banner__end-btn { padding: 5px 10px; font-size: 0.75rem; }

    .admin-section { padding: 16px; }
    .admin-activity-row > summary {
        grid-template-columns: 1fr auto;
        row-gap: 4px;
    }
    .admin-activity-surface, .admin-activity-time {
        grid-column: 2;
        justify-self: end;
    }
}


/* ── Referral Share Card (Phase 1 — Coach Partner Program referral mechanics) ── */
/* Renders at the top of the dashboard view; spec: monetize-coach-referral-spec.md v3 */

/* Referral link content inside the My Clients .coach-section card.
   The old standalone .referral-card flex wrapper is gone — the section
   card provides the outer styling now. These classes style the inner
   URL display, hint text, and the 3-button action row. */
.referral-card-url {
    font-family: monospace;
    font-size: 0.95rem;
    color: var(--accent, #46a5ce);
    cursor: pointer;
    word-break: break-all;
    line-height: 1.4;
    user-select: all;
}
.referral-card-url:hover { text-decoration: underline; }
.referral-card-hint {
    font-size: 0.82rem;
    color: var(--text-mid);
    margin-top: 10px;
    line-height: 1.5;
}
/* Action row — 3 buttons inline (Share / Test / + Invite Client).
   Wraps on narrow viewports so buttons don't overflow. */
.referral-card-actions {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 18px;
}
.referral-card-actions .btn {
    white-space: nowrap;
}
.referral-card-empty {
    padding: 14px 20px;
    margin: 0 0 18px;
    background: var(--bg-card, #1a1a1a);
    border: 1px dashed var(--border, rgba(255,255,255,0.08));
    border-radius: 10px;
    font-size: 0.85rem;
    color: var(--text-dim, #888);
    text-align: center;
    line-height: 1.5;
}
@media (max-width: 600px) {
    .referral-card-actions {
        gap: 6px;
    }
    .referral-card-actions .btn {
        flex: 1 1 calc(50% - 6px);   /* roughly 2 per row on tight screens */
    }
}

/* ── Programs Section (May 23 2026) ─────────────────────────────────────── */
/* Renders between Body Weight and Fitness Compliance on the client dashboard. */
/* Per-program: name + progress bar + completion counts + assigned/end dates. */
/* Visual conventions match existing .client-section / .coach-bar-* patterns. */

.coach-program-list {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.coach-program-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.coach-program-row-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
}
.coach-program-name {
    font-family: var(--font-head, inherit);
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-main, #fff);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.coach-program-stats {
    font-size: 0.8rem;
    color: var(--text-dim, #888);
    flex-shrink: 0;
    white-space: nowrap;
}
.coach-program-bar-track {
    /* Inherits .coach-bar-track height/background; just full-width inside the
       program row (no label/value flanking it like in compliance bars). */
    flex: none;
    width: 100%;
}
.coach-program-meta {
    font-size: 0.78rem;
    color: var(--text-dim, #888);
    letter-spacing: 0.2px;
}

@media (max-width: 600px) {
    .coach-program-row-head {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }
    .coach-program-name {
        font-size: 0.9rem;
    }
}

/* ════════════════════════════════════════════════════════════
   ADMIN — Recent account viewings session rows
   Each row pairs an impersonation start with its matching end,
   replacing the older per-event audit-log row format.
════════════════════════════════════════════════════════════ */

.admin-session-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 20px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 8px;
}
.admin-session-name {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text);
}
.admin-session-times {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.82rem;
    color: var(--text-mid);
    text-align: right;
}
.admin-session-time-row {
    white-space: nowrap;
}
.admin-session-time-label {
    color: var(--text-dim);
    font-weight: 600;
    margin-right: 6px;
}
.admin-session-time-active {
    color: var(--green);
    font-weight: 600;
}
@media (max-width: 600px) {
    .admin-session-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
        padding: 12px 16px;
    }
    .admin-session-times {
        text-align: left;
        width: 100%;
    }
}

/* ════════════════════════════════════════════════════════════
   COACH PANEL — shared section/card pattern
   Used by both Settings (Profile / Payouts / Account cards) and the
   My Clients dashboard (Referral link / Your clients cards). One
   visual language across the panel so every page feels consistent.
   .settings-section is an alias kept for backward compatibility.
════════════════════════════════════════════════════════════ */

.settings-page {
    max-width: 540px;
}
/* Section card — padding lives on the body now, not the card, so the header
   can have its own lighter bg that goes edge-to-edge inside the rounded card.
   overflow:hidden clips the header bg to the card's rounded corners. */
.coach-section,
.settings-section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 20px;
}
/* Header strip — lighter bg + bottom border give clear visual separation
   from the body. Padding lives here (not on the section) so the bg fills
   the strip edge-to-edge. Uses --bg-card-header (dedicated header tone,
   ~12% lighter than card body) so the separation is clearly perceivable. */
.coach-section-header,
.settings-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 28px;
    background: var(--bg-card-header);
    border-bottom: 1px solid var(--border-mid);
}
/* Wraps icon + title together on the LEFT so they read as a group.
   Without this wrapper, justify-content:space-between would push the
   icon and title to opposite ends of the header — see the May 2026
   fix described in the Settings UI changelog. */
.settings-section-header-left,
.coach-section-header-left {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
/* Emojis must never receive the accent filter — they show true colors
   (same rule as .mood-face-img and emoji-picker icons across the app). */
.settings-section-icon {
    font-size: 1.3rem;
    line-height: 1;
    filter: none !important;
}
.coach-section-title,
.settings-section-title {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--text);
    letter-spacing: -0.3px;
}
/* Right-aligned subtle counter next to a section title (e.g. "Your clients
   · 1 CLIENT"). Sits opposite the title in the flex header row. */
.coach-section-count {
    font-size: 0.78rem;
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}
/* Body — owns the inner padding. The section card itself has no padding
   so the header strip can sit flush against the card edges. */
.coach-section-body,
.settings-section-body {
    padding: 24px 28px;
}
/* Tertiary "soft accent" button — dim accent fill + accent border.
   Sits between btn-primary (filled accent) and btn-secondary (white outline)
   in visual weight. Used on the My Clients dashboard for + Invite Client
   so it reads as a third distinct action alongside Share / Test. */
.btn-accent-soft {
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    color: var(--text);
    border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
}
.btn-accent-soft:hover {
    background: color-mix(in srgb, var(--accent) 28%, transparent);
    border-color: var(--accent);
}
@media (max-width: 600px) {
    .coach-section,
    .settings-section {
        margin-bottom: 16px;
    }
    .coach-section-header,
    .settings-section-header {
        padding: 14px 18px;
    }
    .coach-section-body,
    .settings-section-body {
        padding: 20px 18px;
    }
}

/* ════════════════════════════════════════════════════════════
   EARNINGS VIEW
   Used by:
     - /coach/index.html   #view-earnings  (live tab)
     - /coach/earnings-demo.html           (preview / screenshots)
   Single source of truth — no inline duplicate styles.
════════════════════════════════════════════════════════════ */

.earnings-view { max-width: 880px; }

.earnings-kpi-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 36px 32px 28px;
    margin-bottom: 32px;
    position: relative;
    overflow: hidden;
}
.earnings-kpi-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: var(--accent);
}

/* ── Hero this-month KPI ─────────────────────────────────── */
.earnings-hero {
    text-align: center;
    padding-bottom: 28px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--border);
}
.earnings-hero-label {
    font-size: 0.72rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 12px;
}
.earnings-hero-value {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 4.2rem;
    line-height: 1;
    color: var(--accent);
    letter-spacing: -2px;
}
.earnings-hero-value .currency {
    font-size: 2.8rem;
    vertical-align: top;
    margin-right: 4px;
    letter-spacing: 0;
}
.earnings-hero-sub {
    font-size: 0.82rem;
    color: var(--text-mid);
    margin-top: 10px;
}

/* ── Secondary stats row ─────────────────────────────────── */
.earnings-secondary-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 32px;
    margin-bottom: 24px;
}
.earnings-stat {
    min-width: 0;
}
.earnings-stat-label {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 6px;
}
.earnings-stat-value {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.5rem;
    line-height: 1.1;
    color: var(--text);
}
.earnings-stat-helper {
    font-size: 0.74rem;
    color: var(--text-dim);
    margin-top: 4px;
    line-height: 1.4;
}

.earnings-disclosure {
    font-size: 0.82rem;
    color: var(--text-mid);
    line-height: 1.55;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.earnings-disclosure a { color: var(--accent); }

/* ── Payout-setup placeholder card ───────────────────────── */
.earnings-payout-card {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 22px;
    margin-bottom: 32px;
    display: flex;
    align-items: center;
    gap: 14px;
}
.earnings-payout-icon {
    font-size: 1.4rem;
    line-height: 1;
}
.earnings-payout-text {
    font-size: 0.92rem;
    color: var(--text);
    flex: 1;
    min-width: 0;
}
.earnings-payout-text .muted {
    display: block;
    font-size: 0.78rem;
    color: var(--text-dim);
    margin-top: 2px;
}

/* ── Subscriber list ─────────────────────────────────────── */
.earnings-section-label {
    font-size: 0.72rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 14px;
}

.earn-list-cols {
    display: grid;
    grid-template-columns: 1fr 90px 90px 100px 100px;
    gap: 16px;
    padding: 8px 20px;
    margin-bottom: 6px;
}
.earn-list-col-label {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    text-align: right;
}
.earn-list-col-label:first-child { text-align: left; }

.earn-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.earn-row {
    display: grid;
    grid-template-columns: 1fr 90px 90px 100px 100px;
    align-items: center;
    gap: 16px;
    padding: 14px 20px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    transition: border-color 0.12s, background 0.12s;
}
.earn-row:nth-child(odd) {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.earn-row:hover {
    border-color: var(--border-mid);
}

.earn-display-name {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.earn-cell {
    font-size: 0.85rem;
    color: var(--text-mid);
    text-align: right;
}
.earn-cell.right-val {
    color: var(--text);
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.88rem;
}

.earn-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 100px;
    border: 1px solid;
    justify-self: end;
}
.earn-badge--active   { color: var(--green);    border-color: rgba(60,186,108,0.35); background: rgba(60,186,108,0.08); }
.earn-badge--pastdue  { color: var(--red);      border-color: rgba(224,82,82,0.35);  background: rgba(224,82,82,0.08); }
.earn-badge--canceled { color: var(--text-dim); border-color: var(--border);          background: transparent; }
.earn-badge--test     { color: #f0c074;         border-color: rgba(217,119,6,0.55);  background: rgba(217,119,6,0.18); }

/* Test rows render dimmed so they're visually separate from real revenue.
   Pairs with the amber TEST badge in the status column. */
.earn-row--test {
    opacity: 0.55;
}
.earn-row--test:hover {
    opacity: 0.85;
}

/* ── Affiliate-gate empty state ──────────────────────────── */
.earnings-gate {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 56px 32px;
    text-align: center;
    max-width: 560px;
    margin: 24px auto;
}
.earnings-gate-icon {
    font-size: 2.4rem;
    margin-bottom: 16px;
}
.earnings-gate-title {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 1.4rem;
    color: var(--text);
    margin-bottom: 12px;
}
.earnings-gate-body {
    font-size: 0.95rem;
    color: var(--text-mid);
    line-height: 1.55;
    margin-bottom: 28px;
}
.earnings-gate-cta {
    display: inline-block;
}

/* ── Demo ribbon (preview page only) ─────────────────────── */
.demo-ribbon {
    font-size: 0.7rem;
    font-family: var(--font-head);
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 100px;
    border: 1px solid var(--accent);
    color: var(--accent);
    background: var(--accent-dim);
}

/* ── Demo-data banner (live tab, while backend is pending) ─
   Removed once api/coach/earnings-summary.php is wired up.
   Amber on dark — purposefully louder than the accent-blue
   palette so a partner can't miss that these numbers aren't
   theirs.                                                    */
.earnings-demo-banner {
    background: rgba(217,119,6,0.12);
    border: 1px solid rgba(217,119,6,0.45);
    border-radius: var(--radius);
    padding: 12px 16px;
    margin-bottom: 24px;
    font-size: 0.85rem;
    color: #f0c074;
    line-height: 1.5;
}
.earnings-demo-banner strong {
    color: #ffd693;
}

@media (max-width: 720px) {
    .earnings-hero-value      { font-size: 3.2rem; }
    .earnings-hero-value .currency { font-size: 2rem; }
    .earnings-secondary-row   { grid-template-columns: 1fr; gap: 20px; }

    /* Mobile subscriber list — single-row layout (matches desktop).
       Compact columns + smaller fonts + short date format so all five
       cells fit on one line at iPhone-SE 375px width. Long subscriber
       names (e.g. @rickstevens24) truncate with ellipsis. */
    .earn-list-cols {
        grid-template-columns: minmax(0, 1fr) 52px 56px 62px 64px;
        gap: 6px;
        padding: 4px 10px;
        margin-bottom: 4px;
    }
    .earn-list-col-label {
        font-size: 0.58rem;
        letter-spacing: 0.4px;
    }
    .earn-row {
        grid-template-columns: minmax(0, 1fr) 52px 56px 62px 64px;
        grid-template-areas: none;   /* clear desktop areas, use direct columns */
        gap: 6px;
        padding: 12px 10px;
        row-gap: 0;
    }
    .earn-display-name {
        font-size: 0.85rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        grid-area: auto;             /* clear desktop grid-area assignment */
    }
    .earn-cell {
        font-size: 0.72rem;
    }
    .earn-row .earn-cell:nth-of-type(1),
    .earn-row .earn-cell:nth-of-type(2),
    .earn-row .earn-cell:nth-of-type(3) {
        grid-area: auto;
        text-align: right;
    }
    .earn-cell.right-val {
        font-size: 0.76rem;
    }
    .earn-badge {
        grid-area: auto;
        padding: 2px 6px;
        font-size: 0.55rem;
        letter-spacing: 0.2px;   /* override desktop's 0.5px so "Past due" fits in one line */
    }
}

/* ══ Today's Session card — SINGLE consolidated block ══════════════════
 * ⚠️ This section existed TWICE in this file (two '/* ── Today's Session
 * card' headers). The later copy silently overrode the earlier one by
 * cascade, which is why the set table kept reflowing to stacked rows on
 * mobile no matter what the earlier rules said. Consolidated 2026-08-08.
 * Keep it as ONE block — do not append another today-* section.
 */

.today-session { padding: 16px; }

.today-session-loading,
.today-session-none {
    color: var(--text-dim);
    font-size: 0.82rem;
}
/* One muted line when there's nothing to log, so Body Weight is effectively
   still the first real section on non-training days (§7.1). */
.today-session-none { padding: 2px 0; }

.today-session-head { margin-bottom: 10px; }
.today-session-sub  { color: var(--text-dim); font-size: 0.78rem; margin-top: 2px; }

.today-session-list { display: flex; flex-direction: column; gap: 6px; }

.today-ex {
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}
.today-ex.is-open { border-color: var(--accent); }

.today-ex-head {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "name chev" "meta chev";
    gap: 0 10px;
    width: 100%;
    /* 44px+ tap target — thumb-sized, per the mobile-first constraint. */
    min-height: 48px;
    padding: 10px 12px;
    background: var(--bg-card-2);
    border: none;
    color: var(--text);
    font-family: var(--font-body);
    text-align: left;
    cursor: pointer;
}
.today-ex-name { grid-area: name; font-size: 0.86rem; font-weight: 600; }
.today-ex-meta { grid-area: meta; font-size: 0.72rem; color: var(--text-dim); }
.today-ex-chev { grid-area: chev; align-self: center; color: var(--text-dim); }

.today-ex-sets { padding: 8px 10px 10px; display: flex; flex-direction: column; gap: 8px; }

/* Phone: two rows per set so the input never gets squeezed and nothing
   scrolls sideways. Desktop collapses this to a single row below. */
/* ── Set table: FOUR REAL COLUMNS, on mobile too ──────────────────────────
 *
 * ⚠️ These stay a 5-column grid at EVERY width. An earlier version reflowed to
 * stacked rows under 700px, which destroyed the one thing that makes tabular
 * data scannable — you could no longer read down a column. Columns are how this
 * is read; do not "reflow for mobile" by stacking them again. Widths are fixed
 * and small so all four fit at 360px; only Previous flexes.
 *
 * Legibility: values use --text, not --text-dim. An earlier pass had the
 * numbers at dim + 0.7 opacity and they were genuinely hard to read on a phone
 * in a gym. Only the LABELS and placeholders are allowed to recede.
 */
.today-set-head,
.today-set-row {
    display: grid;
    /* EVERY column is a fixed width, including the last (Save). That last one is
       load-bearing: the header and the rows are two SEPARATE grids, so an `auto`
       Save column resolved to 0px in the header (its cell is an empty span) and
       ~50px in the rows. That difference pushed the whole header track set right
       by the button's width, and Reps/Lbs sat off-centre over their inputs. */
    /* Column order is Set · Previous · LBS · REPS · Save. Lbs leads because it is
       the input the coach fills first — you don't know the reps until the weight
       is on the bar — and it matches the set table everywhere else in the app.
       Lbs also takes the wider track: weights run to three digits, reps to two. */
    grid-template-columns: 22px minmax(0, 1fr) 58px 52px 56px;
    gap: 6px;
    align-items: center;
}

/* Headers are CENTRED over their columns to match the inputs below, which are
   width:100% + text-align:center. Same grid cell + same anchor = the label sits
   exactly on the value's centreline, which is what makes a column scannable.
   No padding here — even 2px would knock the label off that centreline. */
.today-set-reps-head,
.today-set-lbs-head { text-align: center; }

.today-set-head {
    padding: 4px 0 6px;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-dim);
}

.today-set-row { padding: 3px 0; }

.today-set-key {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-dim);
    text-align: center;
}
/* Previous is reference data the coach reads constantly — legible, not faint. */
.today-set-prev {
    /* Gap from the Set number. Without it "1" and "55 × 10 reps" ran together
       and read as one field instead of two columns. */
    padding-left: 10px;
    font-size: 0.78rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.today-set-reps,
.today-set-lbs {
    /* 16px is load-bearing: below it iOS Safari zooms the viewport on focus and
       the coach has to pinch back out mid-set. */
    font-size: 16px;
    min-height: 40px;
    padding: 6px 8px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text);
    font-family: var(--font-body);
    text-align: center;
    outline: none;
    width: 100%;
    box-sizing: border-box;
}
.today-set-reps:focus,
.today-set-lbs:focus { border-color: var(--accent); }
/* Readable, but clearly not entered data. */
.today-set-reps::placeholder,
.today-set-lbs::placeholder { color: var(--text-dim); opacity: 1; }

/* Save is a confirmation, not the hero of the row. Compact and outlined —
   full-width filled buttons made the table unreadable by dominating every row. */
.today-set-save {
    min-height: 40px;
    /* Fills its fixed column, so the label flipping to "…" mid-save can't
       resize the button and jog the columns. */
    width: 100%;
    box-sizing: border-box;
    padding: 6px 10px;
    background: transparent;
    border: 1px solid var(--accent);
    border-radius: 6px;
    color: var(--accent);
    font-family: var(--font-body);
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}
.today-set-save:hover:not(:disabled) { background: var(--accent); color: #fff; }
.today-set-save:disabled { opacity: 0.6; cursor: default; }
.today-set-save.is-error { border-color: var(--red, #c0392b); color: var(--red, #c0392b); }
/* Filled = this coach logged it. Attribution without stealing a column. */
.today-set-save.is-mine { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Slightly roomier once there is space; the column structure is identical. */
@media (min-width: 700px) {
    .today-set-head,
    .today-set-row { grid-template-columns: 34px minmax(0, 1fr) 90px 80px 64px; gap: 10px; }
    .today-set-prev { font-size: 0.82rem; }
}

/* Narrow day columns can't fit two cards side by side. */
@media (max-width: 1100px) {
    .prog-preview-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
    /* sprites.js drives playback via the Web Animations API, so CSS can't stop
       it — this only softens the toggle. Honouring reduced-motion properly
       would mean pausing the animations in JS; noted, not done. */
    .prog-preview-toggle { transition: none; }
}

/* ── Today's Session: the plan picker (2026-08-06) ──────────── */
/* Mirrors the app coach panel's Full Plan list so coach and client share one
   mental model of "pick the day I'm actually doing". Mobile-first like the rest
   of this card — rows are ≥48px so they're thumb-sized at the gym. */
.today-plan { display: flex; flex-direction: column; gap: 4px; }

/* Collapsed program header — the default state. Carries enough to choose
   without opening: name, progress, assigned date. */
.today-prog-head {
    display: grid;
    grid-template-columns: 16px 1fr;
    grid-template-areas: "chev name" "chev meta";
    gap: 0 8px;
    width: 100%;
    min-height: 48px;          /* thumb-sized, per the mobile-first rule */
    margin-top: 8px;
    padding: 10px 12px;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
    font-family: var(--font-body);
    text-align: left;
    cursor: pointer;
}
.today-prog-head:first-child { margin-top: 0; }
.today-prog-head:hover  { border-color: var(--accent); }
.today-prog-head.is-open { border-color: var(--accent); background: var(--bg-card); }
.today-prog-chev { grid-area: chev; align-self: center; color: var(--text-dim); font-size: 0.7rem; }
.today-prog-name { grid-area: name; font-size: 0.86rem; font-weight: 700; }
.today-prog-meta { grid-area: meta; font-size: 0.7rem; color: var(--text-dim); }

/* Days sit visually inside their program while it is open. */
.today-prog-head.is-open + .today-plan-week,
.today-prog-head.is-open ~ .today-plan-row { margin-left: 0; }
.today-plan-week {
    font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--text-dim); margin: 6px 0 2px;
}

.today-plan-row {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "day badge" "meta badge";
    gap: 0 10px;
    align-items: center;
    width: 100%;
    min-height: 48px;
    padding: 8px 12px;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
    font-family: var(--font-body);
    text-align: left;
    cursor: pointer;
}
.today-plan-row:hover:not(:disabled) { border-color: var(--accent); }
.today-plan-row:disabled { opacity: 0.5; cursor: default; }

.today-plan-day   { grid-area: day;  font-size: 0.84rem; font-weight: 600; }
.today-plan-meta  { grid-area: meta; font-size: 0.7rem; color: var(--text-dim); }
.today-plan-badge { grid-area: badge; font-size: 0.7rem; color: var(--text-dim); }
.today-plan-badge.is-done { color: var(--green, #2ecc71); }
.today-plan-go    { grid-area: badge; font-size: 0.78rem; font-weight: 600; color: var(--accent); }

.today-session-head { display: flex; align-items: flex-start; gap: 10px; }
.today-back {
    background: none; border: 1px solid var(--border); border-radius: 6px;
    color: var(--text-dim); font-family: var(--font-body); font-size: 0.75rem;
    min-height: 36px; padding: 6px 10px; cursor: pointer; flex-shrink: 0;
}
.today-back:hover { color: var(--accent); border-color: var(--accent); }

/* Inline diagnostic — only rendered when the plan is empty AND workouts exist,
   i.e. when the screen contradicts itself. Never shown in normal use. */
.today-session-diag {
    margin-top: 10px; padding: 10px 12px;
    background: var(--bg-card-2); border: 1px dashed var(--border);
    border-radius: 6px; color: var(--text-dim);
    font-size: 0.72rem; line-height: 1.5; font-family: var(--font-body);
}

/* ── Add New Set ─────────────────────────────────────────────── */
/* Replaces always-rendering Set 4 + Custom, which were empty rows on most
   exercises. Rows now start from the prescription and grow on demand. */
.today-add-set {
    align-self: flex-start;
    margin-top: 2px;
    padding: 8px 4px;
    min-height: 40px;
    background: none;
    border: none;
    color: var(--accent);
    font-family: var(--font-body);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}
.today-add-set:hover { text-decoration: underline; }

