    /* ── ROSTER ── */
    .roster-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1rem}
    .ath-card{background:var(--s1);border:1px solid var(--b1);border-radius:var(--rl);padding:1.25rem;transition:all var(--ease);position:relative}
    .ath-card:hover{border-color:var(--b3)}
    .ath-card--speed{border-left:2px solid var(--lime)}
    .ath-card--perf{border-left:2px solid var(--blue)}
    .ath-card__top{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem}
    .ath-card__name{font-family:var(--fd);font-weight:700;font-size:1.3rem;letter-spacing:.02em;line-height:1;color:var(--text)}
    .ath-card__meta{font-family:var(--fb);font-size:.66rem;color:var(--t3);margin-top:.35rem;display:flex;gap:.6rem;flex-wrap:wrap}
    .ath-card__tag{font-family:var(--fb);font-size:.55rem;font-weight:700;letter-spacing:.1em;padding:.15rem .5rem;border-radius:4px}
    .tag--speed{background:var(--lime-d);color:var(--lime);border:1px solid rgba(170,255,0,.25)}
    .tag--perf{background:var(--blue-b);color:var(--blue);border:1px solid var(--blue-t)}
    .ath-card__prs{margin-top:1rem;padding-top:.9rem;border-top:1px solid var(--b1);display:flex;gap:1.25rem}
    .ath-card__pr .n{font-family:var(--fd);font-weight:800;font-size:1.15rem;color:var(--text);line-height:1}
    .ath-card__pr .l{font-family:var(--fb);font-size:.54rem;font-weight:700;letter-spacing:.1em;color:var(--t3);margin-top:.2rem}
    .ath-card__actions{display:flex;gap:.4rem;margin-top:1rem}
    .ovr-btn{margin-left:auto;flex-shrink:0;font-family:var(--fd);font-weight:800;font-size:.72rem;letter-spacing:.06em;background:var(--lime);color:var(--on-accent);border:none;border-radius:8px;padding:.42rem .6rem;transition:opacity var(--ease)}
    .ovr-btn:hover{opacity:.85}

    /* ── LOG PR RECENT ── */
    .log-table{width:100%;border-collapse:collapse;font-family:var(--fb)}
    .log-table th{font-size:.58rem;font-weight:700;letter-spacing:0;color:var(--t3);padding:.6rem .75rem;border-bottom:1px solid var(--b2);text-align:left}
    .log-table td{padding:.65rem .75rem;border-bottom:1px solid var(--b1);font-size:.8rem;color:var(--t2);vertical-align:middle}
    .log-table tr:hover td{background:var(--s2)}
    .log-table .ath{color:var(--text);font-weight:600;font-family:var(--fs);font-size:.85rem}
    .log-table .val{font-family:var(--fd);font-weight:800;font-size:.95rem;color:var(--text)}
    .pb-flag{font-family:var(--fb);font-size:.52rem;font-weight:700;letter-spacing:.1em;color:var(--lime);background:var(--lime-d);border:1px solid rgba(170,255,0,.3);padding:.12rem .45rem;border-radius:100px;margin-left:.5rem;vertical-align:middle}
    .del-x{width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;color:var(--t4);border-radius:9px;transition:all var(--ease);flex-shrink:0}
    .del-x:hover{color:var(--red);background:var(--s2)}
    .del-x .ic{width:16px;height:16px}
    .roster-topbar{display:flex;gap:.7rem;align-items:stretch;margin-bottom:.7rem}
    .roster-topbar .btn{flex-shrink:0}
    .roster-topbar .roster-search{flex:1;margin-bottom:0}
    .roster-topbar #wfMBar{flex-shrink:0}
    .roster-search{margin-bottom:1rem;padding-left:2.7rem;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238A8B94' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20.5 20.5L17 17'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:.95rem center}

    /* ── COMPACT ROSTER + ATTENDANCE ──
       .roster-panel is the single bordered container the reference draws around the whole roster:
       sort/expand controls in its header, then the program groups as flush sections beneath a
       hairline. The groups keep their <details class="acc"> markup and JS untouched — the panel
       just strips their individual card chrome (border/shadow/radius/margin) so they stack as
       sections of one surface instead of floating as separate cards on the page background. */
    /* No overflow:hidden here, however tempting: the last row's kebab menu is absolutely
       positioned inside the panel and opens past its bottom edge, and clipping it hid every item
       below the fold. The corners are kept clean by rounding whichever child actually lands on
       the panel's bottom edge instead. */
    .roster-panel{background:var(--s1);border:1px solid var(--b1);border-radius:var(--rl);box-shadow:var(--sh)}
    .roster-panel>#rosterList>.acc:last-child:not([open])>summary,
    .roster-panel>#rosterList>.acc:last-child .ath-row:last-child,
    .roster-panel>#rosterList>.acc:last-child .roster-group__viewall{border-bottom-left-radius:var(--rl);border-bottom-right-radius:var(--rl)}
    .roster-panel>#rosterList>.acc{border:none;border-radius:0;box-shadow:none;margin-bottom:0;background:transparent}
    .roster-panel>#rosterList>.acc + .acc{border-top:1px solid var(--b1)}
    .roster-panel>#rosterList>.acc[open]{background:var(--s1)}
    .roster-panel>#rosterList>.empty{border:none;background:transparent}
    /* last row of the last group sits on the panel's own bottom edge — no double hairline */
    .roster-panel>#rosterList>.acc:last-child .ath-row:last-child{border-bottom:none}

    .roster-sortbar{display:flex;align-items:center;gap:.65rem;padding:.7rem 1.15rem;border-bottom:1px solid var(--b1);flex-wrap:wrap}
    .roster-sortbar__label{font-family:var(--fb);font-size:.76rem;font-weight:500;letter-spacing:0;color:var(--t3);flex-shrink:0}
    /* Compact segmented control. The three options share one inset track with hairline dividers
       between them, so they read as one control with a current value rather than as three loose
       links. The selected option is a soft accent-tinted chip — green enough to find at a glance,
       quiet enough not to compete with the green Add Athlete button above it. */
    .seg--sort{display:inline-flex;gap:0;margin-bottom:0;padding:3px;background:var(--s2);border:1px solid var(--b1);border-radius:10px}
    .seg--sort .seg__btn{position:relative;padding:.34rem .8rem;border-radius:7px;font-size:.76rem;font-weight:500;color:var(--t3);background:transparent;white-space:nowrap}
    /* divider between adjacent unselected options; hidden either side of the selected chip so the
       chip never butts up against a stray hairline */
    .seg--sort .seg__btn + .seg__btn::before{content:'';position:absolute;left:0;top:25%;bottom:25%;width:1px;background:var(--b2)}
    .seg--sort .seg__btn.active::before,.seg--sort .seg__btn.active + .seg__btn::before{display:none}
    .seg--sort .seg__btn:hover{color:var(--t2)}
    .seg--sort .seg__btn.active{background:var(--lime-d);color:var(--lime-bright,var(--lime));font-weight:600;box-shadow:inset 0 0 0 1px var(--lime-g)}
    /* Expand All / Collapse All hold the right edge of the same row at every width the desktop
       bar is visible at. */
    .roster-sortbar .acc-allbar{margin-left:auto;flex-shrink:0}
    .roster-scroll{max-height:62vh;overflow-y:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--b1);border-radius:var(--rl);background:var(--s1)}
    .ath-row{position:relative;display:flex;align-items:center;gap:.85rem;padding:.9rem 1.15rem;border-bottom:1px solid var(--b1);transition:background var(--ease)}
    .ath-row:last-child{border-bottom:none}
    /* program-color accent — inset from the row's top/bottom edges so it reads as this row's
       own marker instead of bleeding into an unbroken stripe across every row in the group */
    .ath-row::before{content:'';position:absolute;left:0;top:8px;bottom:8px;width:2px;border-radius:1px;background:var(--row-accent,transparent)}
    .ath-row:hover{background:var(--s2)}
    .ath-row__rank{display:flex;align-items:center;justify-content:center;width:30px;height:30px;flex-shrink:0;border-radius:9px;background:var(--s2);border:1px solid var(--b1);font-family:var(--fb);font-weight:600;font-size:.82rem;color:var(--t3)}
    .ath-row__rank--top{color:var(--on-accent);background:var(--lime);border-color:transparent;font-weight:700}
    .ath-row__main{flex:1;min-width:0}
    .ath-row__name{font-family:var(--fs);font-weight:600;font-size:.95rem;letter-spacing:-.01em;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    /* Edit is reached by clicking the athlete's name. The reference's row menu is exactly five
       items (check-in, log session, access code, kiosk PIN, delete) with no edit entry, so the
       name carries it — dropping the menu item outright would have left no way to edit an
       athlete at all. */
    .ath-row__namebtn{font:inherit;color:inherit;background:none;border:none;padding:0;cursor:pointer;text-align:left}
    .ath-row__namebtn:hover{color:var(--lime)}
    .ath-row__namebtn:focus-visible{outline:2px solid var(--lime);outline-offset:2px;border-radius:4px}
    .ath-row__age{display:inline-block;margin-left:.4rem;font-family:var(--fb);font-size:.68rem;font-weight:500;color:var(--t2);background:var(--s2);border:1px solid var(--b1);border-radius:6px;padding:.08rem .38rem;vertical-align:middle}
    .ath-row__sex{display:inline-block;margin-left:.3rem;font-family:var(--fb);font-size:.68rem;font-weight:500;letter-spacing:0;color:var(--t2);background:var(--s2);border:1px solid var(--b1);border-radius:6px;padding:.08rem .38rem;vertical-align:middle}
    .ath-row__sex--none{color:var(--amber);border-color:var(--amber-t);background:var(--amber-b)}
    .ath-tag{display:inline-block;margin-left:.3rem;font-family:var(--fb);font-size:.68rem;font-weight:500;letter-spacing:0;border-radius:6px;padding:.08rem .4rem;vertical-align:middle}
    .ath-tag--trial{color:var(--blue);background:var(--blue-b);border:1px solid var(--blue-t)}
    .ath-tag--lapsed{color:var(--t3);background:var(--s2);border:1px solid var(--b2)}
    .ath-tag--sport{color:var(--t2);background:var(--s2);border:1px solid var(--b1)}
    .ath-tag--optout{color:var(--amber);background:var(--amber-b);border:1px solid var(--amber-t)}
    .ath-row--lapsed{opacity:.62}
    .ath-row__meta{font-family:var(--fb);font-size:.75rem;color:var(--t3);margin-top:.22rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    .ath-row__tf{color:var(--t4)}
    /* desktop-only stat columns (Overall Score / Last Check-In / Program Start) — hidden on
       mobile, where the compact meta line + kebab's "View Profile" cover the same ground */
    .ath-row__stats{display:flex;align-items:center;gap:2rem;flex-shrink:0;padding:0 .9rem}
    .ath-row__stat{display:flex;flex-direction:column;align-items:flex-start;gap:.15rem;min-width:72px}
    .ath-row__statlabel{font-family:var(--fb);font-size:.7rem;font-weight:500;letter-spacing:0;color:var(--t4)}
    .ath-row__statval{font-family:var(--fs);font-size:.85rem;font-weight:600;color:var(--text)}
    /* per-row actions are a kebab menu at every width, not just mobile — a row of bare icons
       wasn't self-explanatory, so the same tap-to-open, labeled-menu-item scheme used on
       mobile is used everywhere (Check In included, as the menu's first item); only the
       compact meta line (below) stays mobile-only */
    .ath-row__more{display:block;position:relative;flex-shrink:0}
    .ath-row__morebtn{width:34px;height:34px;display:flex;align-items:center;justify-content:center;color:var(--t3);border-radius:9px}
    .ath-row__morebtn .ic{width:17px;height:17px}
    .ath-row__morebtn:hover{background:var(--s2);color:var(--text)}
    .ath-row__menu{display:none;position:absolute;top:calc(100% + 4px);right:0;z-index:20;min-width:222px;background:var(--s1);border:1px solid var(--b2);border-radius:var(--r);box-shadow:0 10px 30px rgba(0,0,0,.18);padding:.35rem;flex-direction:column}
    .ath-row__more.open .ath-row__menu{display:flex}
    .ath-row__menuitem{display:flex;align-items:center;gap:.55rem;text-align:left;padding:.55rem .7rem;border-radius:7px;font-family:var(--fb);font-size:.82rem;font-weight:500;color:var(--text)}
    .ath-row__menuitem:hover{background:var(--s2)}
    .ath-row__menuitem--danger{color:var(--red)}
    .ath-row__menuitem .ic{width:15px;height:15px;flex-shrink:0;color:var(--t3)}
    .ath-row__menuitem--danger .ic{color:var(--red)}
    .ath-row__menuitem:hover .ic{color:var(--t2)}
    .ath-row__menuitem--danger:hover .ic{color:var(--red)}
    .ath-row__menusep{height:1px;background:var(--b1);margin:.3rem .35rem}
    /* program group cards — a bigger radius and a plain-text count instead of the pill badge
       other .acc accordions (Home, Log Session, Trials) use, so Roster's groups read as clean
       cards rather than another filter-style list */
    .roster-group{border-radius:var(--rl)}
    .roster-group>summary{padding:1rem 1.25rem}
    .roster-group__meta{margin-left:auto;display:flex;align-items:center;gap:1.25rem}
    .roster-group__count{font-family:var(--fb);font-weight:500;font-size:.8rem;color:var(--t3)}
    .roster-group .acc__chev{margin-left:.6rem}
    .roster-group__viewall{display:block;width:100%;padding:.75rem;text-align:center;font-family:var(--fs);font-weight:600;font-size:.85rem;color:var(--lime);background:none;border:none;border-top:1px solid var(--b1)}
    .roster-group__viewall:hover{background:var(--s2)}
    .roster-filter-group{display:flex;align-items:center;gap:.5rem}
    .acc__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

    /* ── SHARED FILTER TOOLBAR (Program + Filters button) — always visible, every width, now
       nested inside .roster-topbar right after Search ── #wfMBar reuses the same .roster-mbar
       flex-row look the Roster tab's own mobile sort bar uses, but is styled by ID here so it
       isn't limited to that bar's ≤640px-only visibility; Roster's #rosterMSortBar keeps the
       old mobile-only behavior untouched below. Program's own sizing stays split by breakpoint
       (desktop: compact fixed-width dropdown; mobile: stretches to fill, sized with
       .roster-mbar__prog .select further down) so it never fights the mobile rule on
       specificity. */
    #wfMBar{display:flex;align-items:stretch;gap:.5rem}
    .roster-mbar__filters{position:relative;flex-shrink:0;display:flex;align-items:center;gap:.35rem;padding:0 .9rem;border:1px solid var(--b2);border-radius:var(--r);background:var(--s2);color:var(--text);font-family:var(--fb);font-weight:700;font-size:.8rem;white-space:nowrap;cursor:pointer}
    .roster-mbar__filters .ic{width:14px;height:14px}
    .roster-mbar__badge{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;padding:0 4px;border-radius:100px;background:var(--lime);color:var(--on-accent);font-size:.62rem;font-weight:800;font-family:var(--fd)}
    .roster-mbar__badge[hidden]{display:none}
    @media(min-width:641px){
      #wfMBar .roster-mbar__prog .select{min-width:170px;font-size:.82rem}
    }

    .roster-mchips{display:none}
    .roster-mchips:not(:empty){display:flex;flex-wrap:wrap;gap:.45rem;margin-bottom:.9rem}
    .roster-chip{display:inline-flex;align-items:center;gap:.35rem;padding:.35rem .7rem;border-radius:100px;background:var(--s2);border:1px solid var(--b2);color:var(--t2);font-family:var(--fb);font-size:.72rem;font-weight:600;white-space:nowrap}
    .roster-chip__x{display:inline-flex;width:12px;height:12px}
    .roster-chip__x .ic{width:12px;height:12px}
    .roster-chip--clear{color:var(--t3);background:transparent;border-style:dashed}

    /* ── FILTERS PANEL (Sex/Sport/Timeframe) — a centered dialog on desktop, a bottom
       sheet on mobile; same markup and open/close behavior at every width. ── */
    .rsheet-overlay.open{display:flex;position:fixed;inset:0;z-index:9980;background:rgba(0,0,0,.45);align-items:flex-end;justify-content:center}
    .rsheet{width:100%;max-width:460px;max-height:82vh;display:flex;flex-direction:column;background:var(--s1);border-radius:20px 20px 0 0;box-shadow:0 -10px 40px rgba(0,0,0,.3)}
    .rsheet__head{display:flex;align-items:center;justify-content:space-between;padding:1.1rem 1.25rem .8rem;border-bottom:1px solid var(--b1);flex-shrink:0}
    .rsheet__title{font-family:var(--fd);font-weight:700;font-size:1.05rem;letter-spacing:.02em;color:var(--text)}
    .rsheet__close{width:32px;height:32px;display:flex;align-items:center;justify-content:center;color:var(--t3);border-radius:9px}
    .rsheet__close:hover{background:var(--s2);color:var(--text)}
    .rsheet__close .ic{width:16px;height:16px}
    .rsheet__body{overflow-y:auto;-webkit-overflow-scrolling:touch;padding:1rem 1.25rem;display:flex;flex-direction:column;gap:1rem}
    .rsheet__body .roster-filter-group{flex-direction:column;align-items:flex-start;gap:.5rem}
    .rsheet__body .select,.rsheet__body .seg--sub{width:100%}
    .rsheet__foot{flex-shrink:0;display:flex;gap:.6rem;padding:.9rem 1.25rem calc(.9rem + env(safe-area-inset-bottom));border-top:1px solid var(--b1);background:var(--s1)}
    .rsheet__foot .btn{flex:1;min-width:0;padding-left:.5rem;padding-right:.5rem;font-size:.82rem;text-align:center}
    @media(min-width:641px){
      .rsheet-overlay.open{align-items:center;padding:2rem}
      .rsheet{border-radius:16px;max-height:min(560px,80vh)}
    }

    /* ── MOBILE ROSTER (≈320–430px; applies up to 640px) ──
       Desktop markup/behavior above is untouched. Program/Sport/Sex/Check-Ins-In selects are
       the SAME elements as desktop — one source of truth for every filter value at every
       width. Only Sort (segmented control doesn't fit a narrow toolbar slot) and Expand/
       Collapse (two buttons collapse into one toggle) get mobile-specific replacement controls. */
    .roster-head{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin-bottom:1.1rem}
    .roster-head .page-title{margin-bottom:0}   /* no .page-desc follows here — the inherited margin was throwing off vertical centering against the Add Athlete button */
    .roster-head__addslot:empty{display:none}
    .roster-head__addslot .btn{display:inline-flex;align-items:center;justify-content:center;gap:.4rem;padding:.62rem 1.05rem;font-size:.82rem;white-space:nowrap}
    /* hidden by default; #wfMBar's own ID rule above always overrides this for that element
       specifically, while #rosterMSortBar (mobile-only Sort replacement) stays hidden until
       the same-specificity class rule inside the mobile media query below re-shows it */
    .roster-mbar,.roster-mexpand,.rsheet-overlay{display:none}

    @media(max-width:640px){
      .roster-topbar{flex-wrap:wrap;gap:1.1rem;margin-bottom:.7rem}
      .roster-topbar .roster-search{flex:1 1 100%}
      .roster-topbar #wfMBar{flex:1 1 100%}
      .roster-search{min-height:48px;padding-top:.85rem;padding-bottom:.85rem;margin-bottom:0}

      /* desktop filter row is fully relocated away at this width (Program/Sex/Sport/Time moved
         into the mobile toolbar/sheet, Sort+Allbar replaced) — collapse the now-empty shell */
      .roster-sortbar{display:none}

      .roster-mbar{display:flex;align-items:stretch;gap:.4rem;margin-bottom:.7rem}
      .roster-mbar__prog{flex:1.1;min-width:0}
      .roster-mbar__prog .select,.roster-mbar__sort{width:100%;min-width:0;font-size:.76rem;padding:0 1.5rem 0 .6rem;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;background-position:right .5rem center;background-size:10px}
      .roster-mbar__sort{flex:1}

      .roster-mchips:not(:empty){margin-bottom:.7rem}

      .roster-mexpand{display:flex;justify-content:flex-end;margin-bottom:.6rem}
      .roster-mexpand__btn{font-family:var(--fb);font-weight:700;font-size:.74rem;color:var(--lime);padding:.3rem .2rem}

      /* Sort + Expand are the panel's header at this width too — the desktop .roster-sortbar is
         hidden above, so these two carry its padding and hairline instead of sitting flush
         against the first program group. */
      .roster-panel #rosterMSortBar{margin:0;padding:.7rem .85rem 0}
      .roster-panel #rosterMExpandRow{margin:0;padding:.45rem .85rem .6rem;border-bottom:1px solid var(--b1)}

      /* compact program cards */
      #rosterList .acc>summary{padding:.7rem .85rem;min-height:44px}
      #rosterList .acc__body--flush{padding:0}
      .ath-row{padding:.6rem .85rem;min-height:44px;flex-wrap:nowrap}
      .ath-row__main{flex-basis:auto;min-width:0}
      /* Chips (age / sex / sport) are wider now that they are legible rather than micro-caps, so
         at phone width the name line wraps instead of clipping them behind an ellipsis. */
      .ath-row__name{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.35}
      .ath-row__meta{display:none}
      .ath-row__meta--compact{display:block;font-family:var(--fb);font-size:.68rem;color:var(--t3);margin-top:.15rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
      .ath-row__stats{display:none}
    }
    @media(min-width:641px){
      .ath-row__meta--compact{display:none}
    }

