  :root {
    --bg: #ffffff;
    --bg-soft: #f5f6f7;
    --panel-dark: #2c3036;
    --panel-darker: #25282d;
    /* Slightly-lighter panel surface — derived from --panel-dark so it follows
       the team's chosen panel color (used by sidebar tab active state, etc.). */
    --panel-accent: color-mix(in srgb, var(--panel-dark) 86%, white);
    --border: #d8dce1;
    --border-soft: #e6e8eb;
    --text: #2c3036;
    --text-dim: #6b7280;
    --red: #d4302b;
    --blue: #2864c8;
    --green: #1f9e5a;
    --tool-active: #e23a35;
    /* Team-branded accents. Default to the standard Coachly red/blue and get
       overridden per-team by an inline <style> block in layout.php when the
       active team has a primary/secondary color saved on its profile. */
    --brand-primary: #d4302b;
    --brand-secondary: #2864c8;
  }

  /* Dark mode — opt-in via the user's preference toggle on /account.
     A head-inline script in layout.php adds `dark-mode` to <html> BEFORE
     first paint to avoid a bright flash. The body picks up the same
     class on DOM ready (kept in sync by page_account.js when toggled).
     Most surfaces inherit via CSS variables; the rink IMG / canvas
     intentionally stay bright so drill diagrams keep their familiar
     contrast (a dark rink would be illegible). */
  html.dark-mode,
  body.dark-mode {
    --bg: #1a1d22;
    --bg-soft: #232930;
    --border: #3a414a;
    --border-soft: #2c333b;
    --text: #e8eaee;
    --text-dim: #98a0aa;
  }
  /* Surfaces that hardcoded white instead of var(--bg) — flip them in
     dark mode so cards, modals, and dropdowns aren't blinding islands. */
  body.dark-mode .card,
  body.dark-mode .modal,
  body.dark-mode .drill-card,
  body.dark-mode .login-card,
  body.dark-mode .rink-menu,
  body.dark-mode .nav-drawer,
  body.dark-mode .team-menu,
  body.dark-mode .topbar,
  body.dark-mode .canvas-wrap,
  body.dark-mode .sidebar,
  body.dark-mode .toolbar,
  body.dark-mode .line-picker,
  body.dark-mode .drill-tabs,
  body.dark-mode .drill-tab,
  body.dark-mode input[type="text"],
  body.dark-mode input[type="email"],
  body.dark-mode input[type="password"],
  body.dark-mode input[type="number"],
  body.dark-mode select,
  body.dark-mode textarea,
  body.dark-mode .notes-area,
  body.dark-mode .readonly-field {
    background-color: var(--bg-soft);
    color: var(--text);
  }
  body.dark-mode .lp-options { background: var(--bg); }
  body.dark-mode .drill-tab.active { background: var(--bg); }
  * { box-sizing: border-box; }
  html, body {
    margin: 0; padding: 0;
    height: 100%;
    background: var(--bg);
    color: var(--text);
    /* Geist is the new UI body font — cleaner than Roboto and pairs well
     * with Instrument Sans for headlines. The system fallbacks ensure
     * we don't FOIT (flash of invisible text) if Google Fonts is slow.
     * Font-feature-settings turn on the more refined kerning + ligatures
     * that Geist ships with. */
    font-family: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'cv11', 'ss01', 'ss03';
    font-size: 14px;
  }
  body { overflow: auto; }
  body.route-drill { overflow: hidden; }
  .app { display: grid; grid-template-rows: auto 1fr auto; height: 100%; min-width: 0; max-width: 100%; overflow-x: hidden; }
  .footer {
    background: var(--brand-secondary);
    color: white;
    text-align: center;
    padding: 8px 12px;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 1px;
    text-transform: uppercase;
  }
  .hidden { display: none !important; }

  /* ============ LOGIN SCREEN ============ */
  .login-screen {
    position: fixed; inset: 0;
    background: linear-gradient(135deg, #1c2026 0%, #2c3036 100%);
    display: grid;
    place-items: center;
    z-index: 1000;
  }
  .login-card {
    background: white;
    border-radius: 12px;
    padding: 32px 36px;
    width: 380px;
    max-width: 90vw;
    box-shadow: 0 20px 60px rgba(0,0,0,.4);
    /* Card eases up + fades in on first paint. @starting-style runs
       the moment the element joins the DOM — no JS, no useEffect. */
    transform: translateY(0);
    opacity: 1;
    transition:
      transform 320ms cubic-bezier(0.23, 1, 0.32, 1),
      opacity 280ms ease-out;
  }
  @starting-style {
    .login-card { transform: translateY(8px); opacity: 0; }
  }
  @media (prefers-reduced-motion: reduce) {
    .login-card { transition: opacity 200ms ease-out; transform: none; }
    @starting-style { .login-card { transform: none; } }
  }
  .login-card .logo {
    text-align: center;
    margin-bottom: 24px;
  }
  .login-card .logo .mark {
    width: 64px; height: 64px;
    margin: 0 auto 12px;
    border-radius: 50%;
    background: var(--brand-primary);
    display: grid;
    place-items: center;
    color: white;
    font-weight: 700;
    font-size: 32px;
    overflow: hidden;
  }
  .login-card .logo .mark img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
  }
  .login-card h1 {
    margin: 0;
    font-size: 22px;
    text-align: center;
    color: var(--text);
  }
  .login-card .sub {
    text-align: center;
    color: var(--text-dim);
    margin: 4px 0 24px;
    font-size: 13px;
  }
  .login-tabs {
    display: flex;
    border-bottom: 1px solid var(--border-soft);
    margin-bottom: 18px;
  }
  .login-tab {
    flex: 1;
    text-align: center;
    padding: 10px 0;
    cursor: pointer;
    font-weight: 500;
    color: var(--text-dim);
    border-bottom: 2px solid transparent;
    transition: color 150ms ease-out, border-color 150ms ease-out;
  }
  .login-tab.active {
    color: var(--brand-primary);
    border-bottom-color: var(--brand-primary);
  }
  .login-form input {
    width: 100%;
    border: 1px solid var(--border);
    padding: 10px 12px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 14px;
    margin-bottom: 10px;
    outline: none;
  }
  .login-form input:focus { border-color: var(--blue); }
  .login-form button {
    width: 100%;
    background: var(--brand-primary);
    color: white;
    border: none;
    padding: 11px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    margin-top: 6px;
    transition: filter .15s;
  }
  .login-form button:hover { filter: brightness(0.92); }
  .login-error {
    color: var(--red);
    font-size: 12px;
    margin-top: 8px;
    min-height: 18px;
  }
  .login-success {
    color: var(--green, #1f9e5a);
    font-size: 13px;
    margin-top: 8px;
    background: #e7f8ee;
    border-radius: 6px;
    padding: 8px 10px;
    line-height: 1.4;
  }
  .login-footer-link {
    text-align: center;
    margin-top: 10px;
    font-size: 12.5px;
  }
  .login-footer-link a {
    color: var(--blue, #2864c8);
    text-decoration: none;
  }
  .login-footer-link a:hover { text-decoration: underline; }
  /* "Continue with Google" button — Google's brand guidance: white
     background, 1px border, the official multi-color G mark, and
     Roboto-ish label. */
  .google-signin-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border: 1px solid #dadce0;
    border-radius: 8px;
    background: #fff;
    color: #3c4043;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    transition:
      box-shadow 160ms cubic-bezier(0.23, 1, 0.32, 1),
      background 160ms ease-out,
      transform 140ms ease-out;
  }
  .google-signin-btn:hover {
    background: #f8f9fa;
    box-shadow: 0 1px 3px rgba(60,64,67,0.16);
  }
  .google-signin-btn:active {
    transform: scale(0.98);
  }
  .google-signin-btn svg { flex-shrink: 0; }
  .login-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 14px 0 6px;
    color: var(--text-dim);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
  }
  .login-divider::before,
  .login-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border-soft);
  }
  .login-existing {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border-soft);
  }
  .login-existing .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-dim);
    margin-bottom: 8px;
  }
  .existing-user {
    padding: 8px 12px;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    margin-bottom: 6px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Emil: specific properties, custom ease-out, never `all`. */
    transition:
      background 140ms ease-out,
      border-color 140ms ease-out,
      transform 120ms ease-out;
    /* Stagger entry — each row settles 40ms after the previous. The
       `both` fill-mode keeps the initial offset visible until the
       delay elapses. */
    animation: existing-user-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
  }
  @keyframes existing-user-in {
    from { opacity: 0; transform: translateY(4px) scale(0.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
  }
  .existing-user:nth-of-type(1) { animation-delay: 40ms; }
  .existing-user:nth-of-type(2) { animation-delay: 80ms; }
  .existing-user:nth-of-type(3) { animation-delay: 120ms; }
  .existing-user:nth-of-type(4) { animation-delay: 160ms; }
  .existing-user:nth-of-type(5) { animation-delay: 200ms; }
  .existing-user:hover { background: var(--bg-soft); border-color: var(--border); }
  /* Press feedback — subtle so the row doesn't feel jumpy. */
  .existing-user:active { transform: scale(0.98); }
  .existing-user .nm { font-weight: 500; }
  .existing-user .del {
    background: transparent;
    border: none;
    color: var(--text-dim);
    cursor: pointer;
    padding: 2px;
    width: auto;
    margin: 0;
    transition: color 140ms ease-out, transform 120ms ease-out;
  }
  .existing-user .del:hover { color: var(--red); background: transparent; }
  .existing-user .del:active { transform: scale(0.92); }
  @media (prefers-reduced-motion: reduce) {
    .existing-user { animation: none; transition: background 120ms ease-out, border-color 120ms ease-out; }
    .existing-user:active,
    .existing-user .del:active { transform: none; }
  }

  /* ============ TOP BAR ============ */
  .topbar {
    /* `!important` is defensive — Ian reported the topbar disappearing on
     * iPad refresh, and we couldn't reproduce in preview. If any future
     * media query / utility-class layer tries to `display: none` this
     * bar, it stays visible. */
    display: flex !important;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background: var(--bg);
    border-bottom: 1px solid var(--border-soft);
    /* Don't push the layout wider than its parent on narrow phones. */
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    /* Ensure the bar never collapses to zero height (which would look
     * like it had disappeared) — explicit min-height + position:relative
     * keeps it locked in the layout above the canvas. */
    min-height: 48px;
    position: relative;
    z-index: 1;
  }
  .topbar::-webkit-scrollbar { display: none; }
  .topbar-left, .topbar-right {
    display: flex; align-items: center; gap: 8px;
    flex-shrink: 0;
  }
  .topbar-center {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-width: 0;
  }
  .topbar input[type="text"], .topbar select {
    border: 1px solid var(--border);
    background: #fff;
    padding: 7px 12px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    outline: none;
  }
  .topbar input[type="text"]:focus, .topbar select:focus { border-color: var(--blue); }

  /* Topbar grouping + dividers (2026-05-26 visual polish). The center
     bar used to be a flat row of ten icon buttons with no spacing
     hierarchy; we now group them logically and separate the groups
     with thin vertical dividers so the eye can find related actions. */
  .topbar-group {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
  }
  .topbar-group--title { gap: 8px; }
  .topbar-divider {
    width: 1px;
    height: 22px;
    background: var(--border-soft);
    margin: 0 4px;
    flex-shrink: 0;
  }

  /* Drill name + Mins styled as a title pair, not generic form inputs.
     Borderless + transparent in the resting state so it reads as the
     active drill's title; hover reveals an outline; focus shows a full
     editing affordance. (2026-05-26) */
  .drill-name {
    width: 320px;
    max-width: 40vw;
    border: 1px solid transparent !important;
    background: transparent !important;
    font-size: 16px !important;
    font-weight: 600 !important;
    color: var(--text);
    padding: 6px 10px !important;
    transition: background .12s, border-color .12s;
  }
  .drill-name::placeholder {
    color: var(--text-dim);
    font-weight: 500;
  }
  .drill-name:hover {
    background: var(--bg-soft) !important;
    border-color: var(--border-soft) !important;
  }
  .drill-name:focus {
    background: white !important;
    border-color: var(--border) !important;
  }
  .mins {
    width: 78px;
    cursor: pointer;
    border: 1px solid transparent !important;
    background: transparent !important;
    color: var(--text-dim);
    font-size: 13px !important;
    padding: 6px 8px !important;
    transition: background .12s, border-color .12s, color .12s;
  }
  .mins:hover {
    background: var(--bg-soft) !important;
    border-color: var(--border-soft) !important;
    color: var(--text);
  }
  .mins:focus {
    background: white !important;
    border-color: var(--border) !important;
    color: var(--text);
  }

  /* Animation button — primary action, gets a brand-coloured fill so
     it stands out from the file/save/output siblings. (2026-05-26) */
  .top-icon-btn--accent {
    background: color-mix(in srgb, var(--brand-secondary) 12%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
  }
  .top-icon-btn--accent:hover {
    background: color-mix(in srgb, var(--brand-secondary) 22%, white);
  }
  .top-icon-btn--accent.active {
    background: var(--brand-secondary) !important;
    color: white !important;
  }
  /* 2026-05-26: rink button moved from topbar-left into the title group
     next to drill-name + mins. Was a dark panel pill; now a light
     borderless button that matches the .mins accessory styling so the
     three elements (Title, Mins, Surface) read as one cohesive
     drill-identity row. */
  .rink-btn {
    background: transparent;
    color: var(--text-dim);
    border: 1px solid transparent;
    padding: 6px 10px;
    border-radius: 6px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    position: relative;
    transition: background .12s, border-color .12s, color .12s;
  }
  .rink-btn:hover {
    background: var(--bg-soft);
    border-color: var(--border-soft);
    color: var(--text);
  }
  .rink-btn[aria-expanded="true"],
  .rink-btn.is-open {
    background: var(--bg-soft);
    border-color: var(--border);
    color: var(--text);
  }
  .rink-btn svg { color: var(--text-dim); }
  .rink-btn:hover svg { color: var(--text); }
  .rink-menu {
    /* Fixed so the menu escapes topbar's overflow context (which would
       otherwise clip a dropdown extending below the topbar). Top/left are
       set by JS at toggle time. */
    position: fixed;
    top: 0; left: 0;
    background: white;
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0,0,0,.15);
    min-width: 230px;
    display: none;
    z-index: 1000;
    padding: 4px;
  }
  .rink-menu.show { display: block; }
  .rink-menu .item {
    display: flex; align-items: center; gap: 10px;
    padding: 6px 10px;
    border-radius: 4px;
    cursor: pointer;
    color: var(--text);
    font-size: 13px;
    transition: background .12s;
    text-align: left;
  }
  .rink-menu .item:hover { background: var(--bg-soft); }
  .rink-menu .item.active { background: var(--bg-soft); font-weight: 500; color: var(--red); }
  .rink-menu .rink-thumb {
    flex: 0 0 auto;
    width: 56px; height: 32px;
    object-fit: contain;
    background: #fff;
    border: 1px solid var(--border-soft);
    border-radius: 3px;
    pointer-events: none;
  }
  .rink-menu .item > span { flex: 1; }
  .top-icon-btn {
    background: transparent;
    border: none;
    color: var(--text);
    padding: 7px 8px;
    cursor: pointer;
    border-radius: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .15s;
    position: relative;
    /* iPad/iOS Safari: the topbar has overflow-x: auto, and on touch
     * devices a scroll-vs-tap ambiguity can swallow clicks. Combined with
     * the SVG-absorbs-tap quirk below, the save/print/download icons end
     * up feeling dead. These two properties remove both ambiguities. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0.08);
  }
  .top-icon-btn:hover { background: var(--bg-soft); }
  .top-icon-btn svg { width: 18px; height: 18px; pointer-events: none; }
  /* Realism toggle: active state matches the team's brand red so it reads
     as "on" without looking like a destructive action. */
  .top-icon-btn.active {
    background: var(--brand-primary, #d4302b);
    color: #fff;
  }
  .top-icon-btn.active:hover { background: var(--brand-primary, #d4302b); filter: brightness(1.05); }
  .top-spacer { width: 6px; }
  .user-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-soft);
    padding: 5px 12px 5px 5px;
    border-radius: 20px;
    cursor: pointer;
    transition: background .15s;
  }
  .user-chip:hover { background: #e8eaed; }
  .user-chip .avatar {
    width: 26px; height: 26px;
    border-radius: 50%;
    background: var(--red);
    color: white;
    display: grid;
    place-items: center;
    font-size: 11px;
    font-weight: 700;
  }
  .user-chip .name {
    font-size: 13px;
    font-weight: 500;
    max-width: 100px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .user-menu {
    position: absolute;
    top: 100%; right: 0;
    margin-top: 6px;
    background: white;
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0,0,0,.15);
    min-width: 180px;
    display: none;
    z-index: 80;
  }
  .user-menu.show { display: block; }
  .user-menu .item {
    padding: 10px 14px;
    cursor: pointer;
    font-size: 13px;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 8px;
    border-bottom: 1px solid var(--border-soft);
  }
  .user-menu .item:last-child { border-bottom: none; }
  .user-menu .item:hover { background: var(--bg-soft); }
  .user-menu .item.danger { color: var(--red); }
  .user-menu .item svg { width: 14px; height: 14px; }

  /* ============ MAIN ============ */
  main {
    display: grid;
    /* minmax(0, 1fr) lets the middle column shrink below its content's min-content
       size, which is what we want — otherwise the canvas pushes the layout wider
       than the viewport on narrow phones. */
    grid-template-columns: 108px minmax(0, 1fr) 300px;
    /* Row 1 is the drill-tabs strip in the canvas column; the toolbar and
       right sidebar span both rows so their TOOLS / DRILLS headers sit at the
       same vertical level as the tab strip. */
    grid-template-rows: 34px minmax(0, 1fr);
    overflow: hidden;
    min-width: 0;
  }
  main > .toolbar          { grid-column: 1; grid-row: 1 / 3; }
  main > .drill-tabs       { grid-column: 2; grid-row: 1;     }
  main > .canvas-wrap      { grid-column: 2; grid-row: 2;     }
  main > .collapse-strip.left  { grid-column: 1; grid-row: 1 / 3; }
  main > .collapse-strip.right { grid-column: 3; grid-row: 1 / 3; }
  main > .sidebar          { grid-column: 3; grid-row: 1 / 3; }

  /* LEFT TOOLBAR */
  .toolbar {
    background: var(--bg);
    border-right: 1px solid var(--border-soft);
    display: flex;
    flex-direction: column;
    /* Was `overflow: hidden`, which clipped the bottom tools (line-dot,
     * hook, goalie tray) on iPad landscape and on any browser window
     * shorter than ~700px. Now scrolls inside the toolbar when its
     * content is taller than the grid cell. Thin scrollbar so it
     * doesn't eat the narrow 108px column. */
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
    /* CSS Grid items default to `min-height: auto`, which expands the
     * item to fit its content — that means overflow-y: auto never has
     * anything to scroll because the toolbar quietly grows past its
     * cell. Pinning min-height: 0 forces it to respect the grid cell
     * height; combined with overflow-y: auto, the bottom tools become
     * reachable via scroll on iPad landscape and short windows. */
    min-height: 0;
    /* Momentum-scroll on iOS Safari (legacy property, still respected
     * by current versions and a no-op elsewhere). Without this, scroll
     * inside the toolbar on iPad feels sticky / snaps back on release. */
    -webkit-overflow-scrolling: touch;
  }
  .toolbar::-webkit-scrollbar { width: 6px; }
  .toolbar::-webkit-scrollbar-track { background: transparent; }
  .toolbar::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 3px;
  }
  .toolbar::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
  .toolbar-header {
    background: var(--panel-dark);
    color: white;
    padding: 8px 10px;
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 1px;
  }
  /* 2026-05-26 sidebar refactor — three grouped tool sections.
     Originally had "Draw / Players / Equipment" headers above each
     section; Ian asked for those removed in favour of just a thin
     divider between sections (the icon affinity within each group is
     visual enough on its own). The .tool-section-label class is left
     defined below for backwards compat but no longer rendered in the
     drill view. */
  .tool-section {
    padding: 6px 0;
    border-top: 1px solid var(--border-soft);
  }
  .tool-section:first-of-type {
    border-top: none;
    padding-top: 4px;
  }
  .tool-section-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--text-dim);
    padding: 8px 10px 4px;
  }

  .tool-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
    padding: 4px;
  }
  /* The first .tool-grid keeps overflow-y for legacy reasons (the
     original single-grid layout). With the new sectioned layout the
     parent `.toolbar` owns scroll, so individual grids stay static. */
  .tool {
    aspect-ratio: 1;
    background: #fff;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    color: var(--text);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background .12s, border-color .12s, transform .08s, box-shadow .12s;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    padding: 0;
  }
  .tool:hover {
    background: var(--bg-soft);
    border-color: var(--border);
    transform: translateY(-1px);
  }
  .tool:active { transform: translateY(0); }
  .tool.active {
    background: var(--tool-active);
    border-color: var(--tool-active);
    color: white;
    box-shadow: 0 4px 12px -4px color-mix(in srgb, var(--tool-active) 60%, transparent);
  }
  .tool svg { width: 22px; height: 22px; pointer-events: none; }
  .tool.active svg { stroke: white !important; }
  .tool.active svg [fill="currentColor"] { fill: white; }

  /* Legacy separator (used by the old single-grid layout). Kept so
     plans page tool grids that still emit it don't break visually,
     but it's no longer used in the drill sidebar. */
  .tool-separator {
    grid-column: 1 / -1;
    height: 1px;
    background: var(--border-soft);
    margin: 6px 0;
    border-radius: 0;
  }
  .goalie-section {
    background: var(--panel-dark);
    color: white;
    padding: 12px 16px;
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 1px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    user-select: none;
    transition: filter .15s;
  }
  .goalie-section:hover, .goalie-section:focus { background: var(--panel-dark); filter: brightness(0.9); }
  .goalie-section svg { transition: transform .25s ease; }
  .goalie-section.collapsed svg { transform: rotate(-90deg); }
  .goalie-grid {
    flex: 0 0 auto;
    max-height: 600px;
    overflow: hidden;
    transition: max-height .3s ease, padding .3s ease;
  }
  .goalie-grid.collapsed {
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
  }
  /* Multi-sport: hide the hockey-specific goalie tray for sports that don't
     have hockey-style goalie stamps (basketball, football, etc.). The body
     class is toggled by canvas.js syncGoalieGate() from sports.hasGoalieTools. */
  body:not(.has-goalie-tools) .goalie-section,
  body:not(.has-goalie-tools) .goalie-grid { display: none !important; }
  .player-toolbar {
    padding: 8px 12px;
    display: flex;
    gap: 6px;
    border-bottom: 1px solid var(--border-soft);
  }
  .player-toolbar input {
    flex: 1;
    border: 1px solid var(--border);
    padding: 6px 10px;
    border-radius: 3px;
    font-size: 13px;
    outline: none;
    font-family: inherit;
  }
  .player-toolbar select {
    border: 1px solid var(--border);
    padding: 6px 8px;
    border-radius: 3px;
    font-size: 12px;
    background: white;
    cursor: pointer;
    font-family: inherit;
  }
  .player-list {
    flex: 1;
    overflow-y: auto;
    padding: 4px;
  }
  .player-card {
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    margin-bottom: 6px;
    overflow: hidden;
  }
  .player-card .head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    cursor: pointer;
    transition: background .12s;
  }
  .player-card .head:hover { background: var(--bg-soft); }
  .player-card.expanded .head { border-bottom: 1px solid var(--border-soft); background: var(--bg-soft); }
  .player-jersey {
    background: var(--red);
    color: white;
    width: 32px; height: 32px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-weight: 700;
    font-size: 13px;
    flex-shrink: 0;
  }
  .player-jersey.empty { background: var(--text-dim); }
  .player-info { flex: 1; min-width: 0; }
  .player-name {
    font-weight: 500;
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .player-meta {
    font-size: 11px;
    color: var(--text-dim);
    margin-top: 2px;
    display: flex;
    gap: 6px;
    align-items: center;
  }
  .player-meta .pos-badge {
    background: var(--blue);
    color: white;
    padding: 1px 6px;
    border-radius: 3px;
    font-weight: 500;
  }
  .player-overall {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
  }
  .player-overall .num {
    font-weight: 700;
    color: var(--text);
    font-size: 14px;
  }
  .player-overall .max {
    color: var(--text-dim);
    font-size: 11px;
  }
  .player-card .body { display: none; padding: 10px 12px; background: #fafafa; }
  .player-card.expanded .body { display: block; }
  .rating-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 0;
    border-bottom: 1px dashed var(--border-soft);
    font-size: 12px;
  }
  .rating-row:last-child { border-bottom: none; }
  .rating-row .label { color: var(--text); }
  .rating-stars {
    display: flex;
    gap: 1px;
  }
  .rating-stars .star {
    width: 16px; height: 16px;
    cursor: pointer;
    color: #d8dce1;
    transition: color .1s;
  }
  .rating-stars .star.filled { color: #ffb43a; }
  .rating-stars .star:hover { color: #ffb43a; }
  .player-card .notes-block {
    margin-top: 8px;
    padding: 8px;
    background: white;
    border-radius: 3px;
    border-left: 3px solid var(--blue);
    font-size: 12px;
    line-height: 1.45;
  }
  .player-card .notes-block.strength { border-left-color: var(--green); }
  .player-card .notes-block.weakness { border-left-color: #ffb43a; }
  .player-card .notes-block .h {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 1px;
    font-weight: 700;
    color: var(--text-dim);
    margin-bottom: 4px;
  }
  .player-card .actions {
    display: flex;
    gap: 6px;
    margin-top: 10px;
  }
  .player-card .actions button {
    flex: 1;
    background: white;
    border: 1px solid var(--border);
    color: var(--text);
    padding: 5px 10px;
    border-radius: 3px;
    font-size: 12px;
    cursor: pointer;
    font-family: inherit;
  }
  .player-card .actions button:hover { background: white; border-color: var(--blue); color: var(--blue); }

  /* Player rating section in modal */
  #player-ratings {
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    padding: 8px 12px;
    background: var(--bg-soft);
    margin-bottom: 4px;
  }
  #player-ratings .modal-rating-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 5px 0;
    border-bottom: 1px dashed var(--border);
    font-size: 13px;
  }
  #player-ratings .modal-rating-row:last-child { border-bottom: none; }
  #player-ratings .rating-stars .star { width: 22px; height: 22px; }

  /* Category management */
  .category-list {
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 14px;
  }
  .category-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-soft);
    background: white;
  }
  .category-item:last-child { border-bottom: none; }
  .category-item input {
    border: none;
    outline: none;
    background: transparent;
    font-size: 14px;
    flex: 1;
    margin-right: 8px;
    font-family: inherit;
    padding: 2px 4px;
  }
  .category-item input:focus {
    background: var(--bg-soft);
    border-radius: 3px;
  }
  .category-item button {
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--text-dim);
    padding: 4px;
    border-radius: 3px;
  }
  .category-item button:hover { color: var(--red); background: var(--bg-soft); }

  /* Drill rating modal list */
  #drill-rating-list {
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    max-height: 50vh;
    overflow-y: auto;
  }
  .drill-rating-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border-soft);
    background: white;
  }
  .drill-rating-item:last-child { border-bottom: none; }
  .drill-rating-item .player-jersey { width: 26px; height: 26px; font-size: 11px; }
  .drill-rating-item .pname { flex: 1; margin-left: 10px; font-size: 13px; }
  .drill-rating-item .rating-stars .star { width: 20px; height: 20px; }

  .line-picker {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 4px;
    padding: 4px 10px;
    background: var(--bg-soft);
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    overflow-x: auto;
    flex-shrink: 0;
    /* Hide the horizontal scrollbar entirely — its appear/disappear was
       causing the bar to change height and bump the canvas. Users can still
       scroll the bar with trackpad swipe / touch / shift+wheel. */
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .line-picker::-webkit-scrollbar { display: none; }
  .line-picker-group {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
  }
  .line-picker-divider {
    width: 1px;
    height: 24px;
    background: var(--border);
    flex-shrink: 0;
  }
  .lp-label {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.8px;
    color: var(--text-dim);
    flex-shrink: 0;
  }
  .lp-options {
    display: flex;
    gap: 1px;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    padding: 1px;
  }
  .lp-btn {
    background: transparent;
    border: none;
    padding: 3px 5px;
    cursor: pointer;
    border-radius: 3px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background .12s;
    color: var(--text);
    /* iOS Safari interprets touches inside `overflow-x: auto` containers
     * (the parent `.line-picker`) as potential horizontal-scroll gestures
     * and delays / swallows the click event. `touch-action: manipulation`
     * tells iOS "this is a tap target — don't wait for a scroll to start"
     * so the click fires immediately, which fixes the dead-feeling style
     * buttons reported on iPad. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0.08);
    /* Stop iOS Safari from painting its native button gradient/highlight
     * over our explicit background. Without this, after a tap iOS can
     * leave the button looking grey even when the .active class set the
     * red background — making it look like nothing changed. */
    -webkit-appearance: none;
    appearance: none;
  }
  .lp-btn:hover { background: var(--bg-soft); }
  .lp-btn.active {
    background: var(--tool-active);
    color: white;
  }
  .lp-btn svg {
    width: 42px; height: 14px; display: block;
    /* Same iOS fix as the img below: without this, the inline SVG inside
     * the button absorbs the tap on iPad/iOS Safari and the parent
     * button's click handler never fires. With pointer-events: none on
     * the SVG, the touch falls through to the button as expected. */
    pointer-events: none;
  }
  .lp-btn img {
    width: 42px;
    height: 16px;
    object-fit: contain;
    display: block;
    pointer-events: none;
    image-rendering: -webkit-optimize-contrast;
  }
  /* When the button is active (red bg), invert + bump brightness so dark icons
     read as white. Works for the monochrome line previews. */
  .lp-btn.active img { filter: brightness(0) invert(1); }

  /* Inline color swatches inside the style bar */
  .lp-swatches { display: flex; gap: 4px; }
  .lp-swatches .swatch {
    width: 22px; height: 22px;
    border-radius: 50%;
    cursor: pointer;
    border: 2px solid transparent;
    transition: transform .12s, box-shadow .12s;
    padding: 0;
    /* Same iOS-scroll-conflict fix as .lp-btn — colour swatches live in
     * the same overflow-x: auto .line-picker container. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0.08);
    /* iOS Safari paints a default gradient/highlight on native buttons.
     * Explicitly opt out so our inline background colour is the only
     * thing showing — otherwise the swatch can look "grey" after tap
     * even when state.color updated correctly. */
    -webkit-appearance: none;
    appearance: none;
  }
  .lp-swatches .swatch:hover { transform: scale(1.1); }
  /* Active swatch: bigger, with both a white inset (so the dot reads
   * clearly against any colour) AND a coloured outer ring (so it's
   * obvious-at-a-glance which colour is currently selected, especially
   * on iPad where users were missing the previous subtle 1px inset). */
  .lp-swatches .swatch.active {
    border-color: var(--blue);
    box-shadow: 0 0 0 1px white inset, 0 0 0 3px rgba(40, 100, 200, 0.55);
    transform: scale(1.15);
  }

  /* Inline size slider */
  .lpg-size input[type=range] {
    width: 110px;
    accent-color: var(--blue);
    margin: 0;
  }
  .lpg-size .size-val {
    font-size: 12px;
    color: var(--text-dim);
    min-width: 22px;
    text-align: right;
  }

  /* Style bar height is fixed — its minimum content (color + size) is always shown
     so the canvas underneath doesn't jump when switching tools. Only the line-style
     and line-ending groups (which don't apply to many tools) get hidden. */
  body[data-tool-kind="none"]  .lpg-style,
  body[data-tool-kind="none"]  .lpg-ending,
  body[data-tool-kind="none"]  .lpd-style,
  body[data-tool-kind="none"]  .lpd-color,
  body[data-tool-kind="shape"] .lpg-style,
  body[data-tool-kind="shape"] .lpg-ending,
  body[data-tool-kind="shape"] .lpd-style,
  body[data-tool-kind="shape"] .lpd-color,
  body[data-tool-kind="text"]  .lpg-style,
  body[data-tool-kind="text"]  .lpg-ending,
  body[data-tool-kind="text"]  .lpd-style,
  body[data-tool-kind="text"]  .lpd-color,
  body[data-tool-kind="stamp"] .lpg-style,
  body[data-tool-kind="stamp"] .lpg-ending,
  body[data-tool-kind="stamp"] .lpd-style,
  body[data-tool-kind="stamp"] .lpd-color { visibility: hidden; }
  body[data-tool-kind="stamp"] .lpg-style,
  body[data-tool-kind="stamp"] .lpg-ending,
  body[data-tool-kind="stamp"] .lpg-size,
  body[data-tool-kind="stamp"] .lpd-style,
  body[data-tool-kind="stamp"] .lpd-size { display: none; }

  /* Position labels (F/C/LW/RW/D/LD/RD/G): same hide list as stamp, plus
     surface the number-badge picker (lpg-pos-num) so a 1-5 badge can be
     toggled on the next-placed label. */
  body[data-tool-kind="position"] .lpg-style,
  body[data-tool-kind="position"] .lpg-ending,
  body[data-tool-kind="position"] .lpd-style,
  body[data-tool-kind="position"] .lpd-color { visibility: hidden; }
  body[data-tool-kind="position"] .lpg-style,
  body[data-tool-kind="position"] .lpg-ending,
  body[data-tool-kind="position"] .lpg-size,
  body[data-tool-kind="position"] .lpd-style,
  body[data-tool-kind="position"] .lpd-size { display: none; }
  /* lpg-pos-num is only shown when the active tool is a position label. */
  body:not([data-tool-kind="position"]) .lpg-pos-num,
  body:not([data-tool-kind="position"]) .lpd-pos-num { display: none; }
  .pos-num-btn {
    width: 32px; height: 28px;
    padding: 2px;
    color: #111;
  }
  .pos-num-btn svg { width: 100%; height: 100%; display: block; }
  .pos-num-btn.active { color: var(--red, #d4302b); }
  /* The number badge (the "1/2/3/4/5" outside the white circle) uses
     currentColor by default — which in the active state becomes red and
     vanishes against the red button background. Force it to white when
     active so it stays legible. The inner letter + circle stroke stay red
     because they sit on the white circle fill and are perfectly readable
     there. */
  .pos-num-btn.active .pos-num-badge { fill: white; }

  /* Line context menu */
  .line-ctx-menu {
    position: fixed;
    background: white;
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 8px 24px rgba(0,0,0,.18);
    padding: 6px;
    min-width: 200px;
    display: none;
    z-index: 90;
    font-size: 13px;
  }
  .line-ctx-menu.show { display: block; }
  .line-ctx-section {
    padding: 4px 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
    color: var(--text-dim);
    border-bottom: 1px solid var(--border-soft);
    margin-bottom: 4px;
  }
  .line-ctx-row {
    display: flex;
    gap: 2px;
    margin-bottom: 4px;
    flex-wrap: wrap;
  }
  .line-ctx-row .lp-btn { padding: 4px; border: 1px solid var(--border-soft); }
  .line-ctx-delete {
    width: 100%;
    margin-top: 6px;
    background: white;
    border: 1px solid var(--border);
    color: var(--red);
    padding: 6px;
    border-radius: 3px;
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
  }
  .line-ctx-delete:hover { background: #fff0f0; }

  .player-label { font-weight: 700; font-size: 13px; line-height: 1; }
  .player-label .sub { font-size: 9px; font-weight: 700; vertical-align: super; }

  /* CANVAS */
  .canvas-wrap {
    background: var(--bg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 6px 10px 8px;
  }
  .canvas-stage {
    flex: 1;
    display: grid;
    place-items: center;
    min-height: 0;
    position: relative;
  }
  .canvas-frame {
    position: relative;
    background: white;
    overflow: visible; /* explicit — child canvases extend outside before CSS-rotate */
    /* Force 3D compositing on the frame so child canvas transforms are
       processed as part of the 3D layer pipeline instead of the 2D
       paint-then-transform pipeline. iOS Safari + some Blink versions
       are flaky when 2D-transforming a canvas with a heavy bitmap. */
    transform-style: preserve-3d;
    -webkit-transform-style: preserve-3d;
    /* width/height set by fitCanvas() in rink.js to fit the stage while preserving rink aspect */
  }
  .canvas-frame > * {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
  }
  #rink-image { object-fit: fill; user-select: none; pointer-events: none; }
  #rink { pointer-events: none; }
  #drawing { cursor: crosshair; touch-action: none; }
  /* Team logo at center ice (full rink only). Faded so it never competes with
     the drill overlay. Sized as a fraction of the frame so it tracks any rink-fit. */
  #rink-team-logo {
    inset: auto;
    top: 50%; left: 50%;
    width: 22%; height: 24%;
    transform: translate(-50%, -50%);
    object-fit: contain;
    opacity: 0.16;
    pointer-events: none;
    user-select: none;
  }
  /* `.canvas-frame > *` above sets `display: block` and outweighs the
     UA `[hidden] { display: none }` rule (class+universal vs attribute
     selector), so rink.js setting `logoEl.hidden = true` for half-rink /
     no-logo teams was failing — an empty `<img src="">` rendered as the
     broken-image icon at center ice. Belt-and-suspenders: respect both
     [hidden] and an empty src. (Ian: "there is a broken image on the
     surface ... custom image") */
  #rink-team-logo[hidden],
  #rink-team-logo:not([src]),
  #rink-team-logo[src=""] { display: none; }

  /* Animation playback overlay */
  /* --------------------------------------------------------------
     ANIMATION EDITOR PANEL  (replaces .line-picker when anim mode is on)
     --------------------------------------------------------------
     Sibling of .canvas-stage / .line-picker inside .canvas-wrap. When
     body.anim-active is set, the line-picker hides and #anim-panel
     takes its slot. The panel hosts: a toolbar row (play / loop /
     speed / add / dup / delete / counter / close) and a horizontal
     thumbnail strip (#anim-timeline) of frame chips.

     Re-uses the route-schedule's --rb-* tokens (defined elsewhere) so
     the panel matches the rest of the redesigned chrome.
  */
  /* Style bar STAYS visible during animation mode — coaches still need to
   * change line styles / endings / colours / position numbers while editing
   * a frame. The anim-panel just stacks below it. */
  body.route-drill .anim-panel.hidden { display: none; }
  .anim-panel {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 4px;
    padding: 8px 10px;
    background: var(--bg-soft);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    flex-shrink: 0;
    --rb-ice:      #1e6fbf;
    --rb-ice-soft: rgba(30, 111, 191, 0.10);
    --rb-ice-glow: rgba(30, 111, 191, 0.20);
    --rb-loss:     #d94929;
    --rb-loss-soft:rgba(217, 73, 41, 0.08);
    --rb-warm:     #e89043;
  }

  /* Toolbar row */
  .anim-toolbar {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
  }
  .anim-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 10px;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background-color .12s, border-color .12s, color .12s;
    -webkit-appearance: none;
    appearance: none;
  }
  .anim-btn:hover { background: var(--bg-soft); border-color: var(--border); }
  .anim-btn svg { width: 14px; height: 14px; }
  .anim-btn-label { font-size: 12px; }
  .anim-btn.primary {
    background: var(--rb-ice);
    color: white;
    border-color: var(--rb-ice);
    /* Slightly chunkier so the play button reads as the anchor of the bar. */
    padding: 8px 12px;
  }
  .anim-btn.primary:hover { background: #1759a3; border-color: #1759a3; }
  .anim-btn.primary svg { width: 16px; height: 16px; }
  .anim-btn.danger { color: var(--rb-loss); border-color: rgba(217, 73, 41, 0.30); }
  .anim-btn.danger:hover { background: var(--rb-loss-soft); border-color: var(--rb-loss); }
  .anim-btn.anim-toggle.active {
    background: var(--rb-ice);
    color: white;
    border-color: var(--rb-ice);
  }
  .anim-btn.anim-toggle.active:hover { background: #1759a3; border-color: #1759a3; }

  .anim-speed {
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    padding: 6px 8px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    /* Custom chevron — keeps it consistent across iOS / desktop. */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2398a0aa' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 6px center;
    background-size: 10px 10px;
    padding-right: 22px;
  }
  .anim-divider {
    width: 1px;
    height: 22px;
    background: var(--border);
    margin: 0 2px;
  }
  .anim-spacer { flex: 1; }
  .anim-counter {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    color: var(--text-dim);
    padding: 0 6px;
  }

  /* Per-frame duration input — how many seconds this frame holds before
   * playback transitions to the next frame. Compact "Time [ 1.0 ] s" layout. */
  .anim-duration-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    color: var(--text-dim);
    cursor: text;
  }
  .anim-duration-text { letter-spacing: 0.05em; }
  .anim-duration {
    width: 44px;
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    text-align: right;
    -moz-appearance: textfield;
  }
  .anim-duration::-webkit-outer-spin-button,
  .anim-duration::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }
  .anim-duration:focus { outline: none; }
  .anim-duration-label:focus-within {
    border-color: var(--rb-ice);
    box-shadow: 0 0 0 3px rgba(30, 111, 191, 0.12);
  }
  .anim-duration-unit { color: var(--text-dim); }

  /* Timeline strip — horizontal scrollable list of frame thumbnails */
  .anim-timeline {
    display: flex;
    align-items: center;
    gap: 8px;
    overflow-x: auto;
    padding: 4px 2px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
    -webkit-overflow-scrolling: touch;
  }
  .anim-timeline::-webkit-scrollbar { height: 6px; }
  .anim-timeline::-webkit-scrollbar-track { background: transparent; }
  .anim-timeline::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

  .anim-chip {
    position: relative;
    display: inline-flex;
    align-items: flex-end;
    justify-content: flex-start;
    width: 88px;
    height: 56px;
    padding: 0;
    border: 2px solid var(--border-soft);
    border-radius: 7px;
    background: white;
    cursor: pointer;
    flex-shrink: 0;
    transition: border-color .12s, transform .12s, box-shadow .12s;
    overflow: hidden;
    -webkit-appearance: none;
    appearance: none;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0.08);
  }
  .anim-chip:hover { border-color: var(--border); transform: translateY(-1px); }
  .anim-chip.active {
    border-color: var(--rb-ice);
    box-shadow: 0 0 0 3px var(--rb-ice-soft);
    transform: translateY(-1px);
  }
  .anim-chip-thumb {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
    pointer-events: none;
  }
  .anim-chip-num {
    position: relative;
    z-index: 1;
    padding: 1px 5px;
    margin: 4px;
    background: rgba(255, 255, 255, 0.92);
    border-radius: 4px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 10px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.2;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  }
  .anim-chip.active .anim-chip-num {
    background: var(--rb-ice);
    color: white;
  }
  .anim-chip-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 56px;
    border: 2px dashed var(--border);
    border-radius: 7px;
    background: transparent;
    color: var(--text-dim);
    cursor: pointer;
    flex-shrink: 0;
    transition: border-color .12s, color .12s, background-color .12s;
    -webkit-appearance: none;
    appearance: none;
  }
  .anim-chip-add svg { width: 20px; height: 20px; }
  .anim-chip-add:hover {
    border-color: var(--rb-ice);
    color: var(--rb-ice);
    background: var(--rb-ice-soft);
  }

  /* On iPad widths reuse the same compaction the line-picker got — keep
     buttons but drop the verbose labels so the toolbar fits a single row. */
  @media (max-width: 1024px) {
    .anim-btn-label { display: none; }
  }

  .meta-fields { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; flex-shrink: 0; }
  .meta-fields.meta-row {
    margin-top: 6px;
    flex-direction: row;
    gap: 6px;
  }
  .meta-fields.meta-row input { flex: 1; margin-bottom: 0; padding: 6px 10px; font-size: 13px; }
  .meta-fields.meta-row input#select-age { flex: 0 0 110px; }
  .meta-fields.meta-row .tags-input { flex: 1; min-width: 0; }

  /* ---------- Tag chip input ---------- */
  .tags-input {
    position: relative;
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: #fff;
    padding: 4px 6px;
    min-height: 34px;
  }
  .tags-input:focus-within { border-color: var(--blue); }
  .tag-chips { display: contents; }
  .tag-chip {
    display: inline-flex; align-items: center; gap: 4px;
    background: #eef3ff;
    color: #1e3a8a;
    border: 1px solid #b8c8ee;
    border-radius: 12px;
    padding: 2px 4px 2px 8px;
    font-size: 12px;
    line-height: 1.4;
    white-space: nowrap;
  }
  .tag-chip .tag-remove {
    background: transparent; border: 0;
    color: #1e3a8a;
    padding: 0 4px;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    border-radius: 50%;
  }
  .tag-chip .tag-remove:hover { background: rgba(30, 58, 138, .15); }
  #tag-entry {
    flex: 1; min-width: 80px;
    border: 0; outline: none;
    padding: 4px 4px;
    font-size: 13px;
    background: transparent;
  }
  .tag-autocomplete {
    position: absolute;
    top: calc(100% + 4px); left: 0; right: 0;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 4px;
    box-shadow: 0 6px 20px rgba(0,0,0,.08);
    z-index: 60;
    max-height: 200px;
    overflow-y: auto;
    padding: 4px;
  }
  .tag-autocomplete button {
    display: block; width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    padding: 6px 10px;
    border-radius: 3px;
    font-size: 13px;
    cursor: pointer;
    color: var(--text);
  }
  .tag-autocomplete button:hover,
  .tag-autocomplete button.active { background: var(--bg-soft); }

  /* ---------- Notes editor ---------- */
  .notes-editor {
    position: relative;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: #fff;
    /* Important: do NOT clip — the icon picker popover lives inside this box. */
    overflow: visible;
  }
  .notes-editor:focus-within { border-color: var(--blue); }
  .notes-toolbar {
    display: flex; align-items: center; gap: 2px;
    padding: 4px;
    border-bottom: 1px solid var(--border-soft);
    background: var(--bg-soft);
  }
  .notes-toolbar button {
    background: transparent;
    border: 0;
    padding: 4px 8px;
    border-radius: 3px;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
  }
  .notes-toolbar button:hover { background: rgba(0,0,0,.06); }
  .notes-toolbar { position: relative; }
  .notes-toolbar-spacer { flex: 1; }
  /* Picker grid is positioned against the toolbar (full editor width) rather
     than the small button, so it never overflows the editor on narrow viewports. */
  .notes-icon-picker { position: static; }
  .icon-grid {
    position: absolute;
    /* Open ABOVE the toolbar so the popover never covers the text area. */
    bottom: calc(100% + 4px); top: auto;
    left: 0;
    display: grid;
    grid-template-columns: repeat(6, 38px);
    gap: 6px;
    padding: 8px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 -6px 20px rgba(0,0,0,.12);
    z-index: 60;
    max-height: 240px;
    overflow-y: auto;
  }
  @media (max-width: 540px) {
    .icon-grid { grid-template-columns: repeat(5, 38px); }
  }
  /* `.icon-grid { display: grid }` ties with the user-agent `[hidden] { display: none }`
     rule on specificity, so this explicit override is needed to make the [hidden]
     attribute actually hide the popover. */
  .icon-grid[hidden] { display: none; }
  .icon-grid button {
    background: #fff;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    padding: 6px;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
  }
  .icon-grid button:hover { background: var(--bg-soft); }
  .icon-grid img { width: 26px; height: 26px; object-fit: contain; }
  .notes-area {
    min-height: 70px;
    max-height: 200px;
    overflow-y: auto;
    padding: 8px 10px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text);
    outline: none;
  }
  .notes-area:empty::before {
    content: attr(data-placeholder);
    color: var(--text-dim);
    pointer-events: none;
  }
  .notes-area img.inline-icon {
    height: 1.5em; width: auto;
    vertical-align: -4px;
    margin: 0 2px;
  }
  /* List styles inside the notes editor — execCommand inserts native ul/ol
     elements; browser defaults often strip padding, so reset them here so
     bullets and numbers are actually visible. */
  .notes-area ul,
  .notes-area ol {
    margin: 4px 0 6px;
    padding-left: 22px;
  }
  .notes-area ul { list-style: disc outside; }
  .notes-area ol { list-style: decimal outside; }
  .notes-area li { margin: 1px 0; }
  .notes-area li::marker { color: var(--text-dim); }
  /* Skinny vertical divider between toolbar button groups. */
  .notes-toolbar-divider {
    width: 1px;
    align-self: stretch;
    background: var(--border-soft, #e6e8eb);
    margin: 4px 2px;
  }
  .meta-fields input {
    width: 100%;
    border: 1px solid var(--border);
    padding: 9px 12px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    background: #fff;
    outline: none;
  }
  .meta-fields input:focus { border-color: var(--blue); }
  .meta-fields textarea {
    width: 100%;
    border: 1px solid var(--border);
    padding: 9px 12px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 13px;
    color: var(--text);
    background: #fff;
    outline: none;
    resize: vertical;
    min-height: 50px;
  }
  .meta-fields textarea:focus { border-color: var(--blue); }

  /* RIGHT SIDEBAR */
  .sidebar {
    background: var(--bg);
    border-left: 1px solid var(--border-soft);
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  .sidebar-tabs {
    display: flex;
    background: var(--panel-dark);
    border-bottom: 1px solid #1a1d22;
  }
  .sidebar-tab {
    flex: 1;
    text-align: center;
    padding: 12px 8px;
    cursor: pointer;
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 1px;
    color: rgba(255,255,255,.65);
    border-bottom: 3px solid transparent;
    transition: all .15s;
  }
  .sidebar-tab.active {
    color: white;
    border-bottom-color: var(--brand-primary);
    background: var(--panel-accent);
  }
  .sidebar-tab:hover:not(.active) { color: white; }
  .sidebar-panel {
    display: none;
    flex: 1;
    flex-direction: column;
    overflow: hidden;
  }
  .sidebar-panel.active { display: flex; }
  .search-row { padding: 8px 12px; border-bottom: 1px solid var(--border-soft); }
  .search-row input {
    width: 100%;
    border: 1px solid var(--border);
    padding: 7px 12px;
    border-radius: 3px;
    font-family: inherit;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text);
    background: #fff;
    outline: none;
  }
  /* Scope tabs (Personal | Team) at the top of the drill panel. */
  .drill-scope-tabs {
    display: flex;
    gap: 4px;
    padding: 6px 8px 0;
  }
  .drill-scope-tab {
    flex: 1;
    background: transparent;
    border: 1px solid transparent;
    border-bottom: 2px solid transparent;
    color: var(--text-dim);
    padding: 6px 8px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    cursor: pointer;
    border-radius: 4px 4px 0 0;
  }
  .drill-scope-tab:hover { color: var(--text); }
  .drill-scope-tab.active {
    color: var(--brand-primary);
    border-bottom-color: var(--brand-primary);
  }

  .drill-list {
    flex: 1;
    overflow-y: auto;
    padding: 4px;
  }
  .drill-folder-group { margin-bottom: 8px; }
  /* Folder header — now larger than the drill titles below it so the
     section hierarchy reads correctly (was 11px uppercase, which sat
     visually BELOW the 14px drill names). 2026-05-24 bump.
     The 2026-05-24 refinement adds:
       - More vertical padding (was 10/6, now 14/12) for breathing room.
       - A hairline bottom border so folders read as separate sections.
       - Dark-nav background when the folder is open, mirroring the
         top nav's --panel-dark — keeps the visual link between the
         "drawer" and the "main nav" while clearly marking which folder
         is currently expanded.
     `border-radius` clips the corners; padding-x stays tight so the
     drill cards underneath line up with the header text. */
  .drill-folder-head {
    display: flex; align-items: center; gap: 8px;
    padding: 14px 10px;
    color: var(--text);
    font-size: 16px;
    font-weight: 700;
    letter-spacing: 0;
    user-select: none;
    cursor: pointer;
    border-bottom: 1px solid var(--border-soft);
    border-radius: 6px;
    transition: background .15s, color .15s, border-color .15s, border-radius .15s;
  }
  /* Collapsed hover — subtle grey so the header feels clickable. */
  .drill-folder-group.collapsed > .drill-folder-head:hover {
    background: var(--bg-soft);
  }
  /* OPEN state — match the top nav's dark background. Inherited
     currentColor flips the chev + icon to white. The bottom border
     softens to a subtle inner-shadow line on dark so it still reads.
     Bottom corners squared off so the head visually "connects" into
     the folder body below. */
  .drill-folder-group:not(.collapsed) > .drill-folder-head {
    background: var(--panel-dark);
    color: #fff;
    border-bottom-color: rgba(255, 255, 255, 0.12);
    border-radius: 6px 6px 0 0;
  }
  .drill-folder-group:not(.collapsed) > .drill-folder-head:hover {
    /* Slight lift on hover even when open, so the open state still
       responds to interaction without losing its identity. */
    background: color-mix(in srgb, var(--panel-dark) 88%, #ffffff);
  }
  .drill-folder-head .chev {
    transition: transform .15s;
    display: inline-flex;
  }
  .drill-folder-group.collapsed .chev { transform: rotate(-90deg); }
  .drill-folder-group.collapsed .drill-folder-body { display: none; }
  /* Open folder body sits flush with the dark header above. A subtle
     side border ties it visually to the head's full-width band. */
  .drill-folder-group:not(.collapsed) > .drill-folder-body {
    padding: 8px 0 12px;
  }
  /* Drill-count badge — small pill on the right of the folder head.
     Adapts background tint to the head state (light on collapsed,
     translucent-white on open dark bg). Stays inside the same row via
     margin-left:auto. */
  .drill-folder-count {
    margin-left: auto;
    flex-shrink: 0;
    background: var(--bg-soft);
    color: var(--text-dim);
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    padding: 3px 8px;
    border-radius: 999px;
    letter-spacing: 0.2px;
  }
  .drill-folder-group:not(.collapsed) > .drill-folder-head .drill-folder-count {
    background: rgba(255, 255, 255, 0.14);
    color: rgba(255, 255, 255, 0.92);
  }
  /* Recent virtual folder — distinct accent when collapsed (brand red on
     light bg). When opened it adopts the same dark-nav treatment as
     normal folders for consistency, so the only difference visible is
     the clock icon inside the head. */
  .drill-folder-recent.collapsed .drill-folder-head { color: var(--brand-primary, var(--red)); }
  .drill-folder-recent-icon { flex-shrink: 0; }

  /* Scope radio toggle in the save modal */
  .scope-toggle {
    display: flex; gap: 16px;
    margin-bottom: 10px;
  }
  .scope-toggle label {
    display: inline-flex; align-items: center; gap: 6px;
    cursor: pointer;
    font-size: 13px;
    color: var(--text);
    font-weight: 400;
  }
  /* 2026-05-24 redesign: drill cards stack vertically — title on top,
     large full-width thumbnail, then meta (duration + tags), then a
     compact action row. The previous horizontal layout had a 72×40
     thumbnail that was too small to actually read the diagram. */
  .drill-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: all .12s;
    background: white;
  }
  .drill-card:hover { background: var(--bg-soft); border-color: var(--border); }
  /* Active = drill is currently loaded in the canvas. Was a faint
     border + 8% tint; that didn't read on a sidebar with 20 cards.
     Now: stronger 14% tint, 2px border, and a 3px left accent bar
     in brand-secondary that runs the full card height so you can
     spot it from anywhere on screen. */
  .drill-card.active {
    border-color: var(--brand-secondary);
    background: color-mix(in srgb, var(--brand-secondary) 14%, #ffffff);
    position: relative;
    overflow: hidden;
  }
  .drill-card.active::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--brand-secondary);
  }
  /* Thumb wrap holds the img + an optional "Animated" badge overlay.
   * Full width of the card now (was 72×40); aspect-ratio keeps it
   * proportional regardless of card width. */
  .drill-card .thumb-wrap {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    flex-shrink: 0;
  }
  .drill-card .thumb {
    width: 100%;
    height: 100%;
    background: #fff;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    /* contain (not cover) so the entire rink + shapes are visible — at
       72×40 cover-cropping was fine, but with a full-width thumbnail
       cropping the rink edges off looks broken. */
    object-fit: contain;
    display: block;
  }
  /* "Animated drill" indicator — small ice-blue pill in the thumb's
   * top-right showing a play icon + frame count. Identifies multi-frame
   * drills at a glance from the drawer list. */
  .anim-badge {
    position: absolute;
    top: 3px;
    right: 3px;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 5px 2px 4px;
    background: rgba(30, 111, 191, 0.95);
    color: #fff;
    border-radius: 8px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 9px;
    font-weight: 700;
    line-height: 1;
    pointer-events: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  }
  .anim-badge svg { width: 8px; height: 8px; }
  /* Loading state — when the drill's thumb hasn't been fetched yet
     (folder collapsed or fetch in flight). Flat light-grey background
     plus a spinning Coachly-puck logo via the .thumb-wrap pseudo
     element. Replaced with the real thumb the moment loadFolderThumbs
     swaps img.src and removes the loading class. */
  .drill-card .thumb--loading {
    background: #f4f5f7;
  }
  /* `:has(.thumb--loading)` triggers the spinner only while the img
     still carries the loading flag — same lifecycle as the old
     diagonal-stripes background. Modern Safari/Chrome (and the iPad
     PWA) all support :has(); older browsers degrade to the flat grey
     above. Pointer-events: none so the spinner can't intercept the
     card's drag/tap.

     The spinner itself: a 3/4 red ring (270° arc, stroke only, no fill)
     drawn as inline SVG. The CSS animation rotates the whole image so
     the open quadrant chases around the circle — classic loading-ring
     look. No puck silhouette anymore. */
  .drill-card .thumb-wrap:has(.thumb--loading)::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
      center / 20px 20px no-repeat
      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='9' fill='none' stroke='%23e7e9ec' stroke-width='2.5'/><path d='M12 3 a 9 9 0 0 1 9 9' fill='none' stroke='%23d4302b' stroke-width='2.5' stroke-linecap='round'/></svg>");
    animation: drill-thumb-spin 0.8s linear infinite;
    pointer-events: none;
    z-index: 1;
  }
  @keyframes drill-thumb-spin {
    to { transform: rotate(360deg); }
  }

  /* Drill drawer boot placeholder. The drawer's #drill-list starts
     empty in the markup, with a span of dead air between page-load and
     pc:ready (when api.me() resolves and renderDrills() finally paints).
     This spinner fills that gap so the coach gets immediate feedback
     instead of an empty rail. The whole element gets replaced by
     renderDrills() — no JS hide-on-ready needed. */
  .drill-list-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 48px 16px;
    color: var(--text-dim);
    font-size: 12.5px;
  }
  .drill-list-loading-spinner {
    width: 28px;
    height: 28px;
    background:
      center / 28px 28px no-repeat
      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='9' fill='none' stroke='%23e7e9ec' stroke-width='2.5'/><path d='M12 3 a 9 9 0 0 1 9 9' fill='none' stroke='%23d4302b' stroke-width='2.5' stroke-linecap='round'/></svg>");
    animation: drill-thumb-spin 0.8s linear infinite;
  }
  .drill-list-loading-label {
    text-transform: uppercase;
    letter-spacing: 0.6px;
    font-weight: 600;
  }
  /* `.info` is no longer in the markup after the 2026-05-24 vertical
     redesign — title + meta sit as direct children of `.drill-card`.
     Keeping the legacy selector is harmless if any old cached HTML
     somewhere still wraps them. */
  .drill-card .info { min-width: 0; }
  .drill-card .nm {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.3;
  }
  /* Meta row: minutes badge + tag chips, single line. Tags wrap into
     `.dc-tags` which can overflow with an ellipsis on tight widths. */
  .drill-card .meta {
    font-size: 11px;
    color: var(--text-dim);
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
  }
  .drill-card .dc-mins {
    flex-shrink: 0;
    background: var(--bg-soft);
    padding: 2px 7px;
    border-radius: 10px;
    font-weight: 600;
    color: var(--text);
    font-size: 11px;
  }
  .drill-card .dc-tags {
    display: flex;
    gap: 4px;
    overflow: hidden;
    min-width: 0;
  }
  .drill-card .dc-tag {
    flex-shrink: 0;
    background: color-mix(in srgb, var(--brand-secondary) 12%, #ffffff);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000000);
    padding: 2px 7px;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100px;
  }
  .drill-card .dc-tag--more {
    background: var(--bg-soft);
    color: var(--text-dim);
    max-width: none;
  }
  /* Acts row is now horizontal, anchored to the right edge of the card. */
  .drill-card .acts {
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
    gap: 4px;
    flex-shrink: 0;
    margin-top: 2px;
  }
  /* Favourite star — top-right of the card, separate from the action
     row so it remains glanceable. Off-state is hollow grey; on-state is
     a filled red star with a slight glow. (2026-05-26) */
  .drill-card .fav {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 2;
    background: rgba(255, 255, 255, 0.88);
    backdrop-filter: blur(2px);
    border: none;
    border-radius: 999px;
    width: 26px;
    height: 26px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-dim);
    cursor: pointer;
    transition: color .15s, transform .15s, background .15s;
  }
  .drill-card .fav:hover { color: var(--red); transform: scale(1.08); }
  .drill-card .fav.fav--on {
    color: var(--red, #d4302b);
    background: rgba(255, 255, 255, 0.96);
  }
  /* The active card has its own ::before accent bar — we already use that
     to mark the open drill. The fav button sits ON the thumbnail's
     top-right corner; need position:relative on the card for it to
     anchor correctly. */
  .drill-card { position: relative; }

  /* Footer meta row — "Used in N plans" + "edited X ago". Sits below the
     main meta line as a smaller, dimmer accessory row so the primary tag
     chips stay prominent. Hidden entirely when both badges are empty. */
  .drill-card .dc-foot-row {
    display: flex;
    gap: 8px;
    align-items: center;
    font-size: 10.5px;
    color: var(--text-dim);
    margin-top: -2px;
  }
  .drill-card .dc-foot {
    display: inline-flex;
    align-items: center;
    line-height: 1;
    white-space: nowrap;
  }
  .drill-card .dc-foot--plans {
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000000);
    font-weight: 600;
  }
  .drill-card .dc-foot--time {
    color: var(--text-dim);
  }

  /* Sort popover — replaces the old native <select>. Sits inline with
     the search input. Trigger button is a small pill with the current
     mode's short label; tapping it opens an anchored popover menu.
     2026-05-26. */
  .search-row { display: flex; align-items: center; gap: 6px; }
  .search-row input { flex: 1; min-width: 0; }
  .drill-sort-wrap {
    position: relative;
    flex-shrink: 0;
  }
  .drill-sort-trigger {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    background: white;
    color: var(--text);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    line-height: 1;
    transition: background .12s, border-color .12s;
  }
  .drill-sort-trigger:hover { background: var(--bg-soft); border-color: var(--border); }
  .drill-sort-trigger[aria-expanded="true"] {
    background: var(--bg-soft);
    border-color: var(--border);
  }
  .drill-sort-trigger svg { flex-shrink: 0; color: var(--text-dim); }
  .drill-sort-trigger-label { letter-spacing: 0.2px; }
  /* Popover menu anchored under the trigger. Floats above the drill
     list — z-index above the folder headers (which sit at default 0). */
  .drill-sort-menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 180px;
    background: white;
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    padding: 4px;
    z-index: 50;
  }
  .drill-sort-option {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    border: none;
    background: transparent;
    text-align: left;
    font-size: 13px;
    color: var(--text);
    border-radius: 4px;
    cursor: pointer;
  }
  .drill-sort-option:hover { background: var(--bg-soft); }
  .drill-sort-option.is-active {
    background: color-mix(in srgb, var(--brand-secondary) 10%, #ffffff);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000000);
    font-weight: 600;
  }
  /* Checkmark via ::before on the active option keeps the layout stable
     between active/inactive states (each row stays the same width). */
  .drill-sort-option::before {
    content: '';
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    display: inline-block;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 14px 14px;
  }
  .drill-sort-option.is-active::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231e6fbf' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
  }

  /* Empty-folder state inside an open folder body. */
  .drill-folder-empty {
    padding: 12px 14px;
    color: var(--text-dim);
    font-size: 12px;
    font-style: italic;
    text-align: center;
  }
  /* Favourites variant — slightly taller with the star icon stacked above
     a two-line hint so the empty state reads as intentional, not broken. */
  .drill-folder-empty--fav {
    padding: 18px 14px;
    font-style: normal;
    line-height: 1.5;
  }
  .drill-folder-empty--fav svg { color: var(--text-dim); }
  .drill-folder-empty-hint {
    font-size: 11px;
    color: var(--text-dim);
    opacity: 0.85;
    margin-top: 2px;
  }

  /* Favourites virtual folder — gold-tinted icon when collapsed, same
     dark-nav treatment as other folders when open. */
  .drill-folder-favorites.collapsed .drill-folder-head {
    color: #b8860b; /* dark goldenrod */
  }
  .drill-folder-favorites .drill-folder-favorites-icon { flex-shrink: 0; }
  .drill-card .acts button {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 3px;
    color: var(--text-dim);
    border-radius: 3px;
  }
  .drill-card .acts button:hover { color: var(--text); background: var(--bg-soft); }
  .drill-card .acts .del:hover { color: var(--red); }
  .empty-state {
    padding: 30px 16px;
    text-align: center;
    color: var(--text-dim);
    font-size: 13px;
  }
  .empty-state .icon { font-size: 36px; margin-bottom: 6px; opacity: .3; }

  /* Plans panel */
  .plan-toolbar {
    display: flex;
    gap: 6px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-soft);
  }
  .plan-btn {
    flex: 1;
    background: var(--brand-secondary);
    color: white;
    border: none;
    padding: 8px 12px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 13px;
    cursor: pointer;
    font-weight: 500;
    transition: filter .15s;
  }
  .plan-btn:hover, .plan-btn:focus { filter: brightness(0.9); }
  .plan-btn.secondary {
    background: white;
    color: var(--text);
    border: 1px solid var(--border);
  }
  .plan-btn.secondary:hover { background: var(--bg-soft); }
  .plan-list {
    flex: 1;
    overflow-y: auto;
    padding: 4px;
  }
  /* Practice Plans grid (2026-05-26 polish — matches dashboard widget
     idiom). #plan-grid is rendered by page_plans.js as a flat list of
     .plan-card items; we lay them out as a responsive CSS grid so they
     sit side-by-side on desktop instead of stacking. The earlier
     stacked-stack layout made the page look like a long form. */
  #plan-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
  }
  @media (min-width: 720px) {
    #plan-grid { grid-template-columns: repeat(2, 1fr); }
  }
  @media (min-width: 1080px) {
    #plan-grid { grid-template-columns: repeat(3, 1fr); }
  }

  .plan-card {
    border: 1px solid var(--border-soft);
    border-radius: 14px;
    margin-bottom: 0;
    background: white;
    overflow: hidden;
    transition: box-shadow .15s, transform .15s, border-color .15s;
    position: relative;
    display: flex;
    flex-direction: column;
  }
  .plan-card:hover {
    box-shadow: 0 12px 28px -12px rgba(0, 0, 0, 0.14);
    transform: translateY(-2px);
  }
  /* Top accent ribbon — green when attached to an upcoming practice
     (active), brand-secondary otherwise. Mirrors the colour treatment
     used on dashboard widgets so the visual language is shared. */
  .plan-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: var(--brand-secondary, #1e6fbf);
  }
  .plan-card.has-upcoming::before { background: var(--green, #1f9e5a); }
  .plan-card.is-visible-to-players::before { background: var(--brand-secondary, #1e6fbf); }

  .plan-card .head {
    display: flex;
    align-items: flex-start;
    padding: 16px 18px 12px;
    cursor: pointer;
    justify-content: space-between;
    gap: 10px;
    transition: background .12s;
  }
  .plan-card .head:hover { background: var(--bg-soft); }
  .plan-card.expanded .head { background: var(--bg-soft); border-bottom: 1px solid var(--border-soft); }
  /* The grid card variant doesn't use .card-head + .name/.summary —
     page_plans.js renders <h2> directly inside .plan-card-head-info. */
  .plan-card .plan-card-head-info { flex: 1; min-width: 0; }
  .plan-card h2 {
    margin: 0 0 4px;
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.01em;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-card .sub {
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.4;
  }
  .plan-card .plan-card-head-actions { display: flex; gap: 4px; flex-shrink: 0; }
  .plan-card .btn-icon {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 6px;
    color: var(--text-dim);
    border-radius: 6px;
    transition: color .12s, background .12s;
  }
  .plan-card .btn-icon:hover { color: var(--text); background: var(--bg-soft); }
  .plan-card .btn-icon.del:hover { color: var(--red); background: color-mix(in srgb, var(--red) 10%, white); }
  /* Legacy .acts wrapper (some flows still emit it) */
  .plan-card .head .acts { display: flex; gap: 4px; }
  .plan-card .head .acts button {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 6px;
    color: var(--text-dim);
    border-radius: 6px;
  }
  .plan-card .head .acts button:hover { color: var(--text); background: var(--bg-soft); }
  .plan-card .head .acts .del:hover { color: var(--red); }
  /* Body — drill list + Run Practice action. Visible by default on the
     grid view (no longer click-to-expand); cards are short enough now
     that everything fits. */
  .plan-card .plan-body {
    padding: 0 18px 14px;
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
  /* Legacy .body class kept for any older render paths */
  .plan-card .body { display: none; padding: 8px 12px; background: #fafafa; }
  .plan-card.expanded .body { display: block; }
  .plan-drill {
    display: flex;
    gap: 10px;
    padding: 7px 10px;
    background: var(--bg-soft);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    margin-bottom: 0;
    cursor: pointer;
    align-items: center;
    transition: background .12s, border-color .12s;
  }
  .plan-drill:hover {
    background: white;
    border-color: var(--border);
  }
  .plan-drill .idx {
    width: 22px; height: 22px;
    background: var(--brand-secondary, #1e6fbf);
    color: white;
    border-radius: 50%;
    font-size: 11px;
    font-weight: 700;
    display: grid;
    place-items: center;
    flex-shrink: 0;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
  }
  .plan-drill .nm {
    flex: 1;
    font-size: 13px;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-drill .mins {
    font-size: 11px;
    color: var(--text-dim);
    background: white;
    padding: 2px 8px;
    border-radius: 999px;
    font-weight: 600;
    flex-shrink: 0;
  }
  .plan-drill-overflow {
    padding: 4px 10px;
    font-size: 11px;
    color: var(--text-dim);
    font-style: italic;
  }
  .plan-actions {
    margin-top: 8px;
    display: flex;
    gap: 6px;
  }
  .plan-actions .run {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 9px 14px;
    border-radius: 8px;
    font-weight: 600;
    font-size: 13px;
  }
  /* Small chips inside the plan card head (upcoming / private / visible). */
  .plan-upcoming-chip,
  .plan-private-badge,
  .plan-visible-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 6px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
  }
  .plan-upcoming-chip {
    background: color-mix(in srgb, var(--green, #1f9e5a) 12%, white);
    color: color-mix(in srgb, var(--green, #1f9e5a) 75%, #000);
  }
  .plan-private-badge {
    background: var(--bg-soft);
    color: var(--text-dim);
  }
  .plan-visible-badge {
    background: color-mix(in srgb, var(--brand-secondary, #1e6fbf) 14%, white);
    color: color-mix(in srgb, var(--brand-secondary, #1e6fbf) 80%, #000);
  }
  .plan-drill .rm {
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--text-dim);
    padding: 2px;
  }
  .plan-drill .rm:hover { color: var(--red); }
  .plan-drill .rate {
    background: transparent;
    border: none;
    cursor: pointer;
    color: #ffb43a;
    padding: 2px;
    margin-right: 2px;
  }
  .plan-drill .rate:hover { opacity: 0.7; }
  .plan-actions {
    display: flex;
    gap: 6px;
    margin-top: 8px;
  }
  .plan-actions button {
    flex: 1;
    background: white;
    color: var(--text);
    border: 1px solid var(--border);
    padding: 6px 10px;
    border-radius: 3px;
    font-size: 12px;
    cursor: pointer;
  }
  .plan-actions button:hover { background: var(--bg-soft); }
  .plan-actions button.primary {
    background: var(--green);
    color: white;
    border-color: var(--green);
  }
  .plan-actions button.primary:hover { background: #197a47; }

  /* Run Practice — full-screen modal, light theme with brand accents */
  .run-screen {
    position: fixed; inset: 0;
    background: var(--bg-soft, #f4f5f7);
    display: none;
    flex-direction: column;
    z-index: 500;
    color: var(--text);
  }
  .run-screen.show { display: flex; }

  /* Top bar: exit | plan title + meta | progress dots | total elapsed */
  .run-topbar {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    gap: 20px;
    align-items: center;
    padding: 14px 24px;
    background: #fff;
    border-bottom: 1px solid var(--border-soft, #e6e8eb);
  }
  .run-exit {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px 8px 10px;
    background: #fff;
    border: 1px solid var(--border, #d8dce1);
    border-radius: 8px;
    color: var(--text);
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
  }
  .run-exit:hover {
    background: color-mix(in srgb, var(--brand-primary, var(--red)) 8%, #fff);
    border-color: var(--brand-primary, var(--red));
    color: var(--brand-primary, var(--red));
  }
  .run-exit svg { width: 16px; height: 16px; }
  .run-topbar-meta { min-width: 0; }
  .run-plan-name {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: 0.2px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .run-plan-sub {
    font-size: 12px;
    color: var(--text-dim);
    margin-top: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .run-progress {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .run-progress::-webkit-scrollbar { display: none; }
  .run-progress-dot {
    min-width: 28px; height: 28px;
    padding: 0 8px;
    background: var(--bg-soft, #f4f5f7);
    border: 1px solid var(--border-soft, #e6e8eb);
    color: var(--text-dim);
    border-radius: var(--r-pill, 999px);
    font-size: 11.5px;
    font-weight: 700;
    cursor: pointer;
    font-variant-numeric: tabular-nums;
    transition: background var(--t-fast, 120ms) var(--ease, ease);
  }
  .run-progress-dot:hover { background: #fff; border-color: var(--border, #d8dce1); color: var(--text); }
  .run-progress-dot.is-done {
    background: color-mix(in srgb, var(--green, #1f9e5a) 12%, #fff);
    border-color: color-mix(in srgb, var(--green, #1f9e5a) 40%, transparent);
    color: var(--green, #1f9e5a);
  }
  .run-progress-dot.is-current {
    background: var(--brand-primary, var(--red));
    border-color: var(--brand-primary, var(--red));
    color: #fff;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-primary, var(--red)) 22%, transparent);
  }
  .run-elapsed-box { text-align: right; }
  .run-elapsed {
    font-size: 18px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.5px;
    line-height: 1;
    color: var(--text);
  }
  .run-elapsed-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-top: 3px;
  }

  /* Body: 2-col grid (drill detail | side panel). The grid needs an explicit
     1fr row so the cells fill the available flex height — without it, rows
     fall back to content size and .run-main collapses to a sliver. */
  .run-body {
    flex: 1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    grid-template-rows: 1fr;
    min-height: 0;
    overflow: hidden;
  }
  /* Grid layout: drill header (content), rink (fills available vertical
     space), description (content-sized + capped + internal scroll).
     The rink ALWAYS fills the middle row so its visibility is guaranteed
     regardless of how tall the description gets or which surface the drill
     uses — half-ice, cross-ice, etc. each fit cleanly via object-fit. */
  .run-main {
    min-height: 0;
    overflow: hidden;
    padding: 20px 28px;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 14px;
  }
  .run-drill-eyebrow {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--brand-primary, var(--red));
  }
  .run-drill-title {
    margin: 4px 0 0;
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -0.3px;
    line-height: 1.15;
    color: var(--text);
  }
  .run-drill-meta {
    margin-top: 4px;
    font-size: 12.5px;
    color: var(--text-dim);
    letter-spacing: 0.3px;
  }
  .run-rink-wrap {
    position: relative;
    background: #fff;
    border: 1px solid var(--border-soft, #e6e8eb);
    border-radius: 10px;
    padding: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    /* min-height: 0 so the rink wrap shrinks into the grid cell instead of
       being driven by the image's intrinsic size. Combined with the explicit
       width/height: 100% on .run-rink below, object-fit: contain can do its
       job and every surface aspect (full / half / cross / zone / …) fits. */
    min-height: 0;
    overflow: hidden;
  }
  .run-rink {
    display: block;
    width: 100%;
    height: 100%;
    /* `object-fit: contain` only takes effect when both width and height are
       set (not auto) — that's the change vs. before, which caused half-ice
       thumbs to render at their intrinsic size and overflow. */
    object-fit: contain;
  }
  .run-rink-empty {
    color: var(--text-dim);
    font-size: 13px;
    font-style: italic;
  }
  /* Key Points panel — sits below the rink, scrolls its own body when the
     content overflows so the rink above stays visible. Header is a clickable
     toggle (collapsed on mobile by default). Capped at 35vh so the rink
     never gets crowded out, regardless of how much description text exists. */
  .run-desc-wrap {
    min-height: 0;
    max-height: 35vh;
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--border-soft, #e6e8eb);
    border-radius: 10px;
    overflow: hidden;
  }
  .run-desc-wrap.is-collapsed { max-height: none; }   /* toggle row only — no body to cap */
  .run-desc-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 12px 16px;
    background: transparent;
    border: 0;
    cursor: pointer;
    font: inherit;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-dim);
    text-align: left;
    flex-shrink: 0;
  }
  .run-desc-toggle:hover { background: var(--bg-soft, #f4f5f7); color: var(--text); }
  .run-desc-chev {
    width: 14px; height: 14px;
    flex-shrink: 0;
    transition: transform var(--t-fast, 120ms) var(--ease, ease);
  }
  .run-desc-wrap.is-collapsed .run-desc-chev { transform: rotate(-90deg); }
  .run-desc-wrap.is-collapsed .run-desc { display: none; }
  .run-desc {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 18px 16px;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--text);
  }
  .run-desc p { margin: 0 0 8px; }
  .run-desc p:last-child { margin-bottom: 0; }
  .run-desc ul, .run-desc ol { margin: 6px 0 8px; padding-left: 22px; }
  .run-desc ul { list-style: disc outside; }
  .run-desc ol { list-style: decimal outside; }
  .run-desc li { margin: 2px 0; }
  .run-desc li::marker { color: var(--text-dim); }
  .run-desc img.inline-icon {
    height: 1.1em; width: auto; vertical-align: -2px; margin: 0 2px;
  }

  /* Side panel: timer + up next */
  .run-side {
    min-height: 0;
    overflow-y: auto;
    padding: 24px;
    background: #fff;
    border-left: 1px solid var(--border-soft, #e6e8eb);
    display: flex;
    flex-direction: column;
    gap: 22px;
  }
  .run-timer-card {
    background: var(--bg-soft, #f4f5f7);
    border: 1px solid var(--border-soft, #e6e8eb);
    border-radius: 14px;
    padding: 20px;
    text-align: center;
  }
  .run-timer-label {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--text-dim);
  }
  .run-timer-display {
    margin-top: 6px;
    font-size: 70px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -3px;
    line-height: 1;
    color: var(--text);
  }
  .run-timer-display.warning { color: #d68a18; }
  .run-timer-display.expired { color: var(--red); animation: pulse 1s infinite; }
  @keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
  }
  .run-timer-bar {
    height: 6px;
    background: var(--border-soft, #e6e8eb);
    border-radius: var(--r-pill, 999px);
    margin: 14px 0 16px;
    overflow: hidden;
  }
  .run-timer-fill {
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg, var(--brand-primary, var(--red)), color-mix(in srgb, var(--brand-primary, var(--red)) 65%, #ff8a4a));
    transition: width 1s linear;
  }
  .run-timer-controls {
    display: flex; gap: 8px; align-items: center; justify-content: center;
  }
  .run-timer-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 18px;
    border-radius: 8px;
    border: 0;
    cursor: pointer;
    font: inherit;
    font-size: 13.5px;
    font-weight: 700;
    transition: filter var(--t-fast, 120ms) var(--ease, ease), background var(--t-fast, 120ms) var(--ease, ease);
  }
  .run-timer-btn svg { width: 14px; height: 14px; }
  .run-timer-btn.primary {
    background: var(--brand-primary, var(--red));
    color: #fff;
  }
  .run-timer-btn.primary:hover:not(:disabled) { filter: brightness(0.92); }
  .run-timer-btn.primary:disabled { opacity: 0.5; cursor: not-allowed; }
  .run-timer-btn.ghost {
    background: #fff;
    color: var(--text);
    border: 1px solid var(--border, #d8dce1);
    padding: 10px 12px;
  }
  .run-timer-btn.ghost:hover { background: var(--bg-soft, #f4f5f7); border-color: var(--text-dim); }
  /* Swap icon visibility based on data-state. */
  .run-timer-btn .icon-pause { display: none; }
  .run-timer-btn[data-state="pause"] .icon-play { display: none; }
  .run-timer-btn[data-state="pause"] .icon-pause { display: inline; }

  /* Practice Mode v2 toggle row — Phase 8c 2026-06-14. Two pill toggles
     (Voice, Auto-next) under the main timer buttons. Active state lights
     up with the brand secondary color so the coach can tell at a glance
     which assists are armed. */
  .run-mode-toggles {
    display: flex;
    gap: 8px;
    margin-top: 10px;
  }
  .run-mode-toggle {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px 10px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 999px;
    color: rgba(255, 255, 255, 0.7);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.3px;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
  }
  .run-mode-toggle:hover {
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
  }
  .run-mode-toggle[data-on="1"] {
    background: color-mix(in srgb, var(--brand-secondary) 30%, transparent);
    border-color: color-mix(in srgb, var(--brand-secondary) 65%, transparent);
    color: #fff;
  }
  .run-mode-toggle .run-voice-waves { opacity: 0.4; }
  .run-mode-toggle[data-on="1"] .run-voice-waves { opacity: 1; }

  /* Practice Mode v2: energy zone color coding on the progress dots.
     Each drill row carries a data-zone attribute derived from its tags
     (warm-up, skill, scrimmage, cooldown). The current/done dots get a
     left-bar accent in the zone color so the coach sees the practice's
     intensity arc at a glance. */
  .run-progress-dot[data-zone="warmup"]   { box-shadow: inset 3px 0 0 #6dd3ff; }
  .run-progress-dot[data-zone="skill"]    { box-shadow: inset 3px 0 0 #5cdd9b; }
  .run-progress-dot[data-zone="battle"]   { box-shadow: inset 3px 0 0 #f3744c; }
  .run-progress-dot[data-zone="scrimmage"]{ box-shadow: inset 3px 0 0 #e74c3c; }
  .run-progress-dot[data-zone="cooldown"] { box-shadow: inset 3px 0 0 #b69dff; }

  /* Practice Mode v2: visual flash when a voice cue fires — gives
     hearing-impaired coaches the same warning. 1.2s sweep, no layout
     shift. */
  @keyframes run-cue-flash {
    0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand-secondary) 70%, transparent); }
    50%  { box-shadow: 0 0 0 12px color-mix(in srgb, var(--brand-secondary) 0%, transparent); }
    100% { box-shadow: 0 0 0 0 transparent; }
  }
  .run-timer-display.is-cued { animation: run-cue-flash 1200ms ease-out; }

  .run-upnext-label {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 8px;
  }
  .run-upnext-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
  .run-upnext-item {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr);
    gap: 10px;
    align-items: center;
    padding: 8px 10px;
    background: var(--bg-soft, #f4f5f7);
    border: 1px solid var(--border-soft, #e6e8eb);
    border-radius: 8px;
    cursor: pointer;
    transition: background var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
  }
  .run-upnext-item:hover {
    background: #fff;
    border-color: var(--brand-primary, var(--red));
  }
  .run-upnext-item.is-past { opacity: 0.5; }
  .run-upnext-num {
    width: 26px; height: 26px;
    display: grid; place-items: center;
    background: #fff;
    border: 1px solid var(--border-soft, #e6e8eb);
    border-radius: 50%;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-dim);
  }
  .run-upnext-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .run-upnext-mins {
    font-size: 11px;
    color: var(--text-dim);
    margin-top: 2px;
  }

  /* Bottom footer with Previous / Next */
  .run-footer {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    padding: 14px 24px;
    background: #fff;
    border-top: 1px solid var(--border-soft, #e6e8eb);
  }
  .run-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px 18px;
    background: #fff;
    border: 1px solid var(--border, #d8dce1);
    border-radius: 10px;
    color: var(--text);
    font: inherit;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    transition: background var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
  }
  .run-nav-btn svg { width: 18px; height: 18px; }
  .run-nav-btn:hover:not(:disabled) {
    background: color-mix(in srgb, var(--brand-primary, var(--red)) 6%, #fff);
    border-color: var(--brand-primary, var(--red));
    color: var(--brand-primary, var(--red));
  }
  .run-nav-btn:disabled { opacity: 0.4; cursor: not-allowed; }
  .run-nav-next {
    background: var(--brand-primary, var(--red));
    border-color: var(--brand-primary, var(--red));
    color: #fff;
  }
  .run-nav-next:hover:not(:disabled) {
    filter: brightness(0.92);
    background: var(--brand-primary, var(--red));
    border-color: var(--brand-primary, var(--red));
    color: #fff;
  }
  .run-nav-next.is-finish {
    background: var(--green, #1f9e5a);
    border-color: var(--green, #1f9e5a);
  }
  .run-nav-next.is-finish:hover { background: var(--green, #1f9e5a); border-color: var(--green, #1f9e5a); color: #fff; }

  @media (max-width: 980px) {
    .run-body { grid-template-columns: 1fr; }
    .run-side { border-left: 0; border-top: 1px solid var(--border-soft, #e6e8eb); }
  }
  @media (max-width: 720px) {
    .run-topbar { grid-template-columns: auto 1fr auto; padding: 10px 14px; gap: 10px; }
    .run-progress { display: none; } /* re-shown via Up Next list */
    .run-elapsed { font-size: 15px; }
    .run-main { padding: 14px 14px; gap: 10px; }
    .run-drill-title { font-size: 22px; }
    .run-side { padding: 14px; }
    .run-timer-display { font-size: 56px; letter-spacing: -2px; }
    .run-footer { padding: 10px 14px; }
    .run-nav-btn { padding: 12px 14px; font-size: 13px; }
  }

  /* Style FAB & popover */
  .fab {
    position: fixed;
    bottom: 22px;
    right: 320px;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--blue);
    color: white;
    display: grid;
    place-items: center;
    box-shadow: 0 4px 12px rgba(0,0,0,.18);
    cursor: pointer;
    border: none;
    transition: transform .15s;
    z-index: 50;
  }
  .fab:hover { transform: scale(1.05); }
  .fab svg { width: 22px; height: 22px; }
  .style-popover {
    position: fixed;
    bottom: 80px;
    right: 320px;
    background: white;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px;
    box-shadow: 0 8px 28px rgba(0,0,0,.18);
    width: 220px;
    display: none;
    z-index: 60;
  }
  .style-popover.show { display: block; }
  .style-popover h4 {
    margin: 0 0 8px 0;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-dim);
  }
  .color-row { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
  .swatch {
    width: 22px; height: 22px;
    border-radius: 50%;
    cursor: pointer;
    border: 2px solid transparent;
    transition: transform .12s;
  }
  .swatch:hover { transform: scale(1.1); }
  .swatch.active { border-color: var(--blue); box-shadow: 0 0 0 1px white inset; }
  .size-row { display: flex; align-items: center; gap: 8px; }
  .size-row input[type=range] { flex: 1; accent-color: var(--blue); }
  .size-row .v { font-size: 12px; min-width: 22px; text-align: right; }

  /* Modal */
  .modal-bg {
    position: fixed; inset: 0;
    background: rgba(0,0,0,.4);
    display: none;
    place-items: center;
    z-index: 100;
  }
  .modal-bg.show { display: grid; }
  .modal {
    background: white;
    border-radius: 8px;
    padding: 24px;
    width: 420px;
    max-width: 90vw;
    box-shadow: 0 12px 40px rgba(0,0,0,.25);
  }
  .modal h3 { margin: 0 0 14px 0; font-size: 18px; }
  .modal label {
    display: block;
    font-size: 12px;
    color: var(--text-dim);
    margin-bottom: 4px;
    margin-top: 10px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }
  .modal input, .modal select, .modal textarea {
    width: 100%;
    border: 1px solid var(--border);
    padding: 10px 12px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 14px;
    outline: none;
  }
  .modal input:focus, .modal select:focus, .modal textarea:focus { border-color: var(--blue); }
  .modal textarea { resize: vertical; min-height: 80px; }
  .modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 18px; }
  /* Folder checkbox picker inside the save modal. Scrollable when there
     are lots of folders; max-height keeps the modal a sensible height
     even with 50+ folders. Each row is a full-width clickable label so
     tapping anywhere on the row toggles the checkbox. */
  .modal-folders {
    max-height: 200px;
    overflow-y: auto;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    padding: 4px;
    background: #fff;
    margin-bottom: 6px;
  }
  .modal-folder-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 8px;
    border-radius: 3px;
    cursor: pointer;
    font-size: 13px;
    user-select: none;
  }
  .modal-folder-row:hover { background: var(--bg-soft); }
  .modal-folder-row input[type="checkbox"] {
    margin: 0;
    flex-shrink: 0;
    cursor: pointer;
  }
  .modal-folder-row span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .modal-folders-empty {
    padding: 10px 8px;
    color: var(--text-dim);
    font-size: 12px;
    font-style: italic;
  }
  #modal-new-folder {
    margin-bottom: 4px;
  }

  /* ------------------------------------------------------------------
     Drill Preview Modal (Quick Look) — 2026-05-26
     ------------------------------------------------------------------
     A wider modal than the save dialog (max 720px) so the big
     thumbnail has room to breathe. Stacks vertically: header / thumb
     / tags / folders / description / actions. Closes via the × button
     in the top-right, click on backdrop, or Escape key. */
  .drill-preview-modal-body {
    width: 720px;
    max-width: 92vw;
    max-height: 90vh;
    overflow-y: auto;
    position: relative;
    padding: 24px;
  }
  .modal-close {
    position: absolute;
    top: 12px;
    right: 12px;
    background: transparent;
    border: none;
    width: 32px;
    height: 32px;
    border-radius: 999px;
    font-size: 22px;
    line-height: 1;
    color: var(--text-dim);
    cursor: pointer;
    transition: background .15s, color .15s;
  }
  .modal-close:hover { background: var(--bg-soft); color: var(--text); }
  .drill-preview-header {
    margin-bottom: 14px;
    padding-right: 36px; /* clear the close button */
  }
  .drill-preview-header h2 {
    margin: 0 0 6px;
    font-size: 22px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.25;
  }
  .drill-preview-meta {
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.6;
  }
  .drill-preview-meta .dot { margin: 0 6px; color: var(--border); }
  /* Big preview thumbnail — full width of modal, 16:9. */
  .drill-preview-thumb {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    overflow: hidden;
    background: #f4f5f7;
    margin-bottom: 14px;
  }
  .drill-preview-thumb img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
  }
  .drill-preview-thumb .anim-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    font-size: 11px;
    padding: 4px 8px;
  }
  .drill-preview-tags,
  .drill-preview-folders {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 10px;
  }
  .drill-preview-tags .dc-tag,
  .drill-preview-folders .dc-tag {
    max-width: none; /* allow full tag names in the preview, not clipped */
    font-size: 12px;
    padding: 3px 10px;
  }
  .dc-tag--folder {
    background: var(--bg-soft) !important;
    color: var(--text) !important;
  }
  .drill-preview-description {
    border-top: 1px solid var(--border-soft);
    padding-top: 14px;
    margin-bottom: 18px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text);
    max-height: 40vh;
    overflow-y: auto;
  }
  .drill-preview-description p:first-child { margin-top: 0; }
  .drill-preview-description p:last-child  { margin-bottom: 0; }
  .drill-preview-empty-hint {
    color: var(--text-dim);
    font-size: 12px;
    font-style: italic;
  }

  /* ------------------------------------------------------------------
     Practice Mode — single-drill rink presentation (2026-05-26 rebuild)
     ------------------------------------------------------------------
     The original implementation was a dark projector-style overlay.
     Replaced with the same LIGHT theme + layout idiom as Run Practice
     (on the Plans page) so the two modes feel like siblings. We reuse
     all the .run-* class styles from page_plans — the markup uses
     .run-topbar / .run-body / .run-main / .run-timer-card / etc. —
     and this rule just provides the outer overlay positioning. */
  .practice-mode {
    position: fixed;
    inset: 0;
    z-index: 500;
    background: var(--bg-soft, #f4f5f7);
    color: var(--text);
    display: flex;
    flex-direction: column;
    font-family: inherit;
  }
  .practice-mode[hidden] { display: none; }
  body.practice-mode-open { overflow: hidden; }
  /* Hide the frame-indicator slot when JS hasn't populated it (single
     static drill). Run Practice fills its progress-dot slot per drill;
     for one-drill Practice Mode we only show it when animated. */
  .practice-mode .run-progress:empty { display: none; }
  .practice-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: 18px 24px 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }
  .practice-header-left { flex: 1; min-width: 0; }
  .practice-header h1 {
    margin: 0 0 8px;
    font-size: 32px;
    font-weight: 700;
    line-height: 1.2;
    color: #ffffff;
    letter-spacing: -0.01em;
  }
  .practice-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .practice-tag {
    font-size: 13px;
    padding: 3px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.12);
    color: #e6eaf2;
  }
  .practice-close {
    background: rgba(255, 255, 255, 0.08);
    border: none;
    color: #ffffff;
    width: 44px;
    height: 44px;
    border-radius: 999px;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    transition: background .15s;
    flex-shrink: 0;
    margin-left: 16px;
  }
  .practice-close:hover { background: rgba(255, 255, 255, 0.16); }

  .practice-body {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: 1fr 340px;
    gap: 20px;
    padding: 20px 24px 24px;
  }
  /* Vertically narrow viewports (or iPad portrait) — stack rink above
     sidebar so the rink stays the dominant element. */
  @media (max-width: 900px), (orientation: portrait) {
    .practice-body {
      grid-template-columns: 1fr;
      grid-template-rows: minmax(0, 1fr) auto;
    }
  }

  .practice-rink {
    position: relative;
    background: #1a1d22;
    border-radius: 12px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    min-height: 0;
  }
  .practice-rink img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
  }
  .practice-frame-indicator {
    position: absolute;
    top: 14px;
    right: 14px;
    background: rgba(0, 0, 0, 0.6);
    color: #ffffff;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px;
    font-weight: 600;
    padding: 4px 10px;
    border-radius: 999px;
    letter-spacing: 0.4px;
  }

  .practice-side {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-height: 0;
  }
  .practice-timer-card,
  .practice-description-card {
    background: #1a1d22;
    border-radius: 12px;
    padding: 18px 20px;
  }
  .practice-timer-label,
  .practice-description-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.4px;
    color: rgba(255, 255, 255, 0.45);
    margin-bottom: 10px;
  }
  .practice-timer {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 64px;
    font-weight: 700;
    line-height: 1;
    color: #ffffff;
    margin-bottom: 14px;
    font-variant-numeric: tabular-nums;
  }
  .practice-timer-card.practice-timer--done {
    background: var(--red, #d4302b);
    transition: background 0.3s;
  }
  .practice-timer-card.practice-timer--done .practice-timer { color: #fff; }
  .practice-controls {
    display: flex;
    gap: 8px;
  }
  .practice-btn {
    flex: 1;
    padding: 12px 16px;
    border: none;
    border-radius: 8px;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    background: var(--brand-secondary, #1e6fbf);
    color: #ffffff;
    transition: filter .15s, background .15s;
  }
  .practice-btn:hover { filter: brightness(1.1); }
  .practice-btn--ghost {
    background: rgba(255, 255, 255, 0.08);
  }
  .practice-btn--ghost:hover { background: rgba(255, 255, 255, 0.16); }

  .practice-description-card {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .practice-description {
    overflow-y: auto;
    flex: 1;
    font-size: 16px;
    line-height: 1.55;
    color: #e6eaf2;
  }
  .practice-description p:first-child { margin-top: 0; }
  .practice-description em { color: rgba(255, 255, 255, 0.5); }

  /* AI "Auto-write" button in the description editor toolbar — small
     pill-shaped button with a star glyph + "AI" label so it visually
     distinguishes from the format buttons next to it. (2026-05-26) */
  .notes-ai-btn {
    display: inline-flex !important;
    align-items: center;
    gap: 4px;
    padding: 4px 10px !important;
    background: color-mix(in srgb, var(--brand-secondary) 12%, #ffffff) !important;
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000000) !important;
    border-radius: 10px !important;
    font-weight: 600;
    font-size: 11px;
    letter-spacing: 0.3px;
  }
  .notes-ai-btn:hover {
    background: color-mix(in srgb, var(--brand-secondary) 20%, #ffffff) !important;
  }
  .notes-ai-btn:disabled {
    opacity: 0.6;
    cursor: progress;
  }
  .notes-ai-btn--loading svg {
    animation: notes-ai-spin 1s linear infinite;
  }
  @keyframes notes-ai-spin { to { transform: rotate(360deg); } }
  .notes-ai-label { line-height: 1; }

  /* AI Coach "Adapt for age" popover — anchored under the Adapt button.
     Light card with chip-style age picker. (Phase 8b 2026-06-14) */
  .notes-ai-adapt-wrap { position: relative; display: inline-block; }
  .notes-ai-adapt-pop {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 60;
    background: #fff;
    border: 1px solid color-mix(in srgb, var(--brand-secondary) 25%, #d6dae2);
    border-radius: 12px;
    padding: 10px 12px;
    box-shadow: 0 8px 24px rgba(20, 22, 30, 0.12);
    min-width: 220px;
  }
  .notes-ai-adapt-title {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: color-mix(in srgb, var(--brand-secondary) 70%, #000);
    margin-bottom: 8px;
  }
  .notes-ai-adapt-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .notes-ai-adapt-chip {
    padding: 5px 10px;
    background: color-mix(in srgb, var(--brand-secondary) 8%, #f4f6fa);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    border: 1px solid color-mix(in srgb, var(--brand-secondary) 18%, #d6dae2);
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background 120ms ease, transform 120ms ease;
  }
  .notes-ai-adapt-chip:hover {
    background: color-mix(in srgb, var(--brand-secondary) 18%, #ffffff);
    transform: translateY(-1px);
  }
  .notes-ai-adapt-chip:disabled {
    opacity: 0.5;
    cursor: progress;
    transform: none;
  }

  /* AI Coach: Plan critique modal — Phase 8b 2026-06-14
     Four labeled sections (summary, strengths, gaps, suggestions) with
     accent-colored bullets. Modal sized for two columns of content but
     collapses to single column on narrow viewports. */
  .plan-editor-critique-btn { color: color-mix(in srgb, var(--brand-secondary) 80%, #000); }
  .plan-editor-critique-btn:hover { background: color-mix(in srgb, var(--brand-secondary) 12%, #fff); }
  .plan-critique-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
  }
  .plan-critique-name {
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-dim);
  }
  .plan-critique-loading {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 24px 8px;
    color: var(--text-dim);
  }
  .plan-critique-result { display: flex; flex-direction: column; gap: 16px; }
  .plan-critique-summary {
    padding: 12px 14px;
    background: color-mix(in srgb, var(--brand-secondary) 8%, #f4f6fa);
    border-left: 3px solid var(--brand-secondary);
    border-radius: 6px;
    line-height: 1.4;
  }
  .plan-critique-section {
    border: 1px solid #e3e6ec;
    border-radius: 10px;
    padding: 12px 14px;
  }
  .plan-critique-section h4 {
    margin: 0 0 8px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-dim);
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .plan-critique-section h4::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--brand-secondary);
  }
  .plan-critique-section--gaps h4::before { background: #e3a83a; }
  .plan-critique-section--suggestions h4::before { background: #22c55e; }
  .plan-critique-section ul {
    margin: 0;
    padding-left: 18px;
    line-height: 1.5;
  }
  .plan-critique-section li { margin-bottom: 4px; }
  .plan-critique-error {
    padding: 12px 14px;
    background: #fde8e6;
    color: #8a2a26;
    border-radius: 6px;
  }

  /* ------------------------------------------------------------------
     Coach Dashboard — 2026-05-26 (visual overhaul)
     ------------------------------------------------------------------
     Hero band with a soft ice-blue gradient holds the greeting + AI
     input as the page's clear focal point. Below the band: calendar
     (above) and widget grid (below) on a clean white canvas with
     accent-coloured iconography so each widget reads as its own
     thing rather than yet-another-grey-box. */
  .dashboard-app {
    min-height: calc(100vh - 52px); /* leave room for the top nav */
    padding: 0 0 80px;
    background: #ffffff;
  }
  .dashboard-wrap {
    max-width: 1240px;
    margin: 0 auto;
    padding: 0 24px;
  }

  /* Hero band — gradient backdrop. Bleeds full-width via negative
     horizontal margin equal to the wrap padding, then re-applies its
     own inner padding so the AI card sits inside a generous frame. */
  .dashboard-hero {
    position: relative;
    margin: 0 -24px 36px;
    padding: 56px 24px 40px;
    background:
      radial-gradient(circle at 20% 0%, color-mix(in srgb, var(--brand-secondary) 18%, white) 0%, transparent 55%),
      radial-gradient(circle at 90% 100%, color-mix(in srgb, var(--brand-secondary) 12%, white) 0%, transparent 50%),
      linear-gradient(180deg, color-mix(in srgb, var(--brand-secondary) 10%, white) 0%, #ffffff 100%);
    border-bottom: 1px solid var(--border-soft);
  }
  /* Bleeds the hero band to viewport edges on wider screens so it
     reads as a real banner, not a centered card. Updated 2026-05-26
     when the wrap grew from 880 → 1080 to accommodate the 3-up
     widget row. */
  @media (min-width: 1288px) {
    .dashboard-hero {
      margin-left: calc((100vw - 1240px) / -2 + -24px);
      margin-right: calc((100vw - 1240px) / -2 + -24px);
      padding-left: calc((100vw - 1240px) / 2 + 24px);
      padding-right: calc((100vw - 1240px) / 2 + 24px);
    }
  }

  .dashboard-header {
    text-align: center;
    margin-bottom: 24px;
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
  }
  .dashboard-header h1 {
    font-size: 38px;
    font-weight: 700;
    color: var(--text);
    margin: 0 0 12px;
    letter-spacing: -0.025em;
    line-height: 1.15;
  }
  .dashboard-sub {
    font-size: 17px;
    color: color-mix(in srgb, var(--text) 75%, white);
    margin: 0;
    line-height: 1.5;
    font-weight: 400;
  }

  .dashboard-ai-card {
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 16px;
    padding: 28px 28px 24px;
    box-shadow: 0 10px 30px -10px rgba(30, 111, 191, 0.18),
                0 4px 12px -2px rgba(0, 0, 0, 0.06);
    max-width: 720px;
    margin: 0 auto;
    transition: box-shadow .2s;
  }
  .dashboard-ai-card:focus-within {
    box-shadow: 0 14px 40px -8px rgba(30, 111, 191, 0.28),
                0 6px 16px -2px rgba(0, 0, 0, 0.08);
  }
  .dashboard-ai-card textarea {
    width: 100%;
    border: none;
    outline: none;
    font-family: inherit;
    font-size: 17px;
    line-height: 1.55;
    color: var(--text);
    resize: none;
    padding: 4px 4px 12px;
    background: transparent;
    letter-spacing: -0.005em;
  }
  .dashboard-ai-card textarea::placeholder { color: var(--text-dim); }
  .dashboard-ai-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 12px;
    padding-top: 16px;
    border-top: 1px solid var(--border-soft);
  }
  .dashboard-ai-duration {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-dim);
  }
  .dashboard-ai-duration select {
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    padding: 6px 8px;
    font-size: 13px;
    color: var(--text);
    background: white;
    cursor: pointer;
  }
  .dashboard-ai-submit {
    border: none;
    background: var(--brand-secondary, #1e6fbf);
    color: white;
    padding: 10px 20px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: filter .12s;
  }
  .dashboard-ai-submit:hover:not(:disabled) { filter: brightness(1.08); }
  .dashboard-ai-submit:disabled { opacity: 0.7; cursor: progress; }

  .dashboard-ai-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 16px auto 0;
    justify-content: center;
    max-width: 720px;
  }
  .dashboard-ai-chip {
    background: rgba(255, 255, 255, 0.7);
    backdrop-filter: blur(8px);
    border: 1px solid color-mix(in srgb, var(--brand-secondary) 18%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    padding: 7px 14px;
    border-radius: 999px;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    transition: background .12s, border-color .12s, transform .12s;
  }
  .dashboard-ai-chip:hover {
    background: white;
    border-color: var(--brand-secondary);
    transform: translateY(-1px);
  }

  .dashboard-ai-loading {
    margin-top: 24px;
    text-align: center;
    color: var(--text-dim);
    font-size: 14px;
  }
  .dashboard-ai-spinner {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 3px solid var(--border-soft);
    border-top-color: var(--brand-secondary, #1e6fbf);
    margin: 0 auto 10px;
    animation: dashboard-ai-spin 0.8s linear infinite;
  }
  @keyframes dashboard-ai-spin { to { transform: rotate(360deg); } }

  .dashboard-ai-error {
    margin-top: 24px;
    padding: 12px 16px;
    background: color-mix(in srgb, var(--red) 8%, white);
    border: 1px solid color-mix(in srgb, var(--red) 40%, white);
    color: color-mix(in srgb, var(--red) 80%, #000);
    border-radius: 8px;
    font-size: 14px;
  }

  /* Generated plan result */
  .dashboard-ai-result {
    margin-top: 28px;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 12px;
    padding: 24px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  }
  .dashboard-ai-result-head { margin-bottom: 8px; }
  .dashboard-ai-result-head h2 {
    margin: 0 0 4px;
    font-size: 22px;
    font-weight: 700;
    color: var(--text);
  }
  .dashboard-ai-result-meta {
    font-size: 13px;
    color: var(--text-dim);
  }
  .dashboard-ai-result-summary {
    font-size: 14px;
    line-height: 1.55;
    color: var(--text);
    margin: 14px 0 18px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border-soft);
  }
  .dashboard-ai-result-drills {
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .dashboard-ai-drill {
    background: var(--bg-soft);
    border-radius: 8px;
    padding: 14px 16px;
  }
  .dashboard-ai-drill-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
  }
  .dashboard-ai-drill-num {
    background: var(--brand-secondary, #1e6fbf);
    color: white;
    border-radius: 999px;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    flex-shrink: 0;
  }
  .dashboard-ai-drill-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    flex: 1;
    min-width: 0;
  }
  .dashboard-ai-drill-mins {
    font-size: 11px;
    font-weight: 600;
    padding: 3px 8px;
    background: white;
    border-radius: 999px;
    color: var(--text-dim);
    flex-shrink: 0;
  }
  .dashboard-ai-drill-objective,
  .dashboard-ai-drill-desc {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text);
    margin-bottom: 6px;
  }
  .dashboard-ai-drill-cues {
    margin: 6px 0 0;
    padding-left: 20px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text);
  }
  .dashboard-ai-result-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--border-soft);
  }

  /* Library-search results (replaces the older generated-plan view).
     Two grouped sections: matched plans on top, matched drills below.
     Each match is a clickable card linking back into /drill?open=ID or
     /plans?open=ID. Empty state lives at the bottom with a fallback CTA.
     2026-05-26 (dashboard revision). */
  .dashboard-ai-hint {
    font-size: 12px;
    color: var(--text-dim);
  }
  .dashboard-results { margin-top: 24px; }
  .dashboard-results-summary {
    font-size: 16px;
    line-height: 1.5;
    color: var(--text);
    margin-bottom: 16px;
    font-weight: 500;
  }
  .dashboard-results-group { margin-bottom: 20px; }
  .dashboard-results-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    font-weight: 700;
    color: var(--text-dim);
    margin: 0 0 10px;
  }
  .dashboard-results-count {
    background: var(--bg-soft);
    color: var(--text-dim);
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0;
  }
  .dashboard-results-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px;
  }
  .dash-result-card {
    display: flex;
    gap: 12px;
    padding: 10px;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    cursor: pointer;
    transition: transform .12s, box-shadow .12s, border-color .12s;
    overflow: hidden;
  }
  .dash-result-card:hover {
    transform: translateY(-1px);
    border-color: var(--border);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
  }
  .dash-result-thumb {
    position: relative;
    width: 96px;
    height: 56px;
    flex-shrink: 0;
    border-radius: 6px;
    overflow: hidden;
    background: #f4f5f7;
  }
  .dash-result-thumb img {
    width: 100%; height: 100%;
    object-fit: contain;
    display: block;
  }
  .dash-anim-badge {
    position: absolute;
    top: 4px; right: 4px;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 5px;
    background: rgba(30, 111, 191, 0.95);
    color: white;
    border-radius: 8px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 9px;
    font-weight: 700;
    line-height: 1;
  }
  .dash-result-plan-icon {
    width: 56px;
    height: 56px;
    flex-shrink: 0;
    background: color-mix(in srgb, var(--brand-secondary) 12%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .dash-result-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .dash-result-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .dash-result-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 11px;
    color: var(--text-dim);
  }
  .dash-mins,
  .dash-age {
    background: var(--bg-soft);
    padding: 1px 7px;
    border-radius: 999px;
    font-weight: 600;
    color: var(--text);
  }
  .dash-time { color: var(--text-dim); font-weight: 500; padding: 1px 0; }
  .dash-result-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
  }
  .dash-tag {
    background: color-mix(in srgb, var(--brand-secondary) 12%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 110px;
  }
  .dashboard-results-suggestion {
    margin-top: 16px;
    padding: 12px 14px;
    background: color-mix(in srgb, var(--brand-secondary) 6%, white);
    border-left: 3px solid var(--brand-secondary);
    border-radius: 4px;
    font-size: 13px;
    line-height: 1.55;
    color: var(--text);
  }
  .dashboard-results-empty {
    margin-top: 16px;
    padding: 32px 20px;
    text-align: center;
    background: white;
    border: 1px dashed var(--border);
    border-radius: 10px;
  }
  .dashboard-results-empty-icon {
    font-size: 32px;
    margin-bottom: 10px;
  }
  .dashboard-results-empty-title {
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 6px;
  }
  .dashboard-results-empty-sub {
    font-size: 13px;
    color: var(--text-dim);
    line-height: 1.5;
    margin-bottom: 16px;
    max-width: 460px;
    margin-left: auto;
    margin-right: auto;
  }

  /* ---- Drill Library page (/library/drills) — 2026-05-26 ----
     Full-page browse view. Same .page wrapper as Plans (max-width
     1240). Layout: left rail with folder navigation + right column
     with search → sort row → roomy responsive card grid. Same visual
     language as dashboard widgets so the product feels coherent. */
  .library-layout {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 28px;
    align-items: start;
  }
  @media (max-width: 880px) {
    .library-layout { grid-template-columns: 1fr; gap: 18px; }
  }
  .lib-sidebar {
    display: flex;
    flex-direction: column;
    gap: 18px;
    position: sticky;
    top: 24px;
    align-self: start;
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    padding-right: 4px; /* room for scrollbar without crowding items */
  }
  @media (max-width: 880px) {
    .lib-sidebar {
      position: static;
      max-height: none;
      flex-direction: row;
      overflow-x: auto;
      overflow-y: hidden;
      gap: 8px;
      padding-right: 0;
      -webkit-overflow-scrolling: touch;
    }
  }
  .lib-side-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  @media (max-width: 880px) {
    .lib-side-group {
      flex-direction: row;
      gap: 6px;
      flex-shrink: 0;
    }
    .lib-side-group + .lib-side-group::before {
      content: '';
      display: inline-block;
      width: 1px;
      align-self: stretch;
      background: var(--border-soft);
      margin: 4px 4px;
    }
  }
  .lib-side-heading {
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--text-dim);
    padding: 8px 8px 4px;
  }
  @media (max-width: 880px) {
    .lib-side-heading { display: none; }
  }
  .lib-side-item {
    appearance: none;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    padding: 8px 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text);
    cursor: pointer;
    text-align: left;
    transition: background .12s, color .12s, border-color .12s;
    font-family: inherit;
    width: 100%;
  }
  .lib-side-item:hover {
    background: var(--bg-soft);
  }
  .lib-side-item.is-active {
    background: color-mix(in srgb, var(--brand-secondary) 12%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    font-weight: 600;
  }
  .lib-side-item--fav { color: var(--red); }
  .lib-side-item--anim { color: color-mix(in srgb, #1e6fbf 80%, #000); }
  .lib-side-item.is-active.lib-side-item--fav,
  .lib-side-item.is-active.lib-side-item--anim {
    /* Keep the brand-tinted background for actives, regardless of the
       per-row text colour. */
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
  }
  .lib-side-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
  }
  .lib-side-count {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-dim);
    background: var(--bg-soft);
    border-radius: 999px;
    padding: 1px 8px;
    min-width: 22px;
    text-align: center;
    flex-shrink: 0;
  }
  .lib-side-item.is-active .lib-side-count {
    background: white;
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
  }
  @media (max-width: 880px) {
    .lib-side-item {
      flex-shrink: 0;
      padding: 6px 12px;
      font-size: 12.5px;
      border-radius: 999px;
      border: 1px solid var(--border-soft);
      background: white;
    }
    .lib-side-item.is-active {
      background: var(--brand-secondary);
      border-color: var(--brand-secondary);
      color: white;
    }
    .lib-side-item.is-active .lib-side-count {
      background: rgba(255, 255, 255, 0.25);
      color: white;
    }
  }
  .lib-side-empty {
    font-size: 12px;
    color: var(--text-dim);
    padding: 4px 10px 8px;
  }
  @media (max-width: 880px) {
    .lib-side-empty { display: none; }
  }
  .lib-active-label {
    font-size: 18px;
    font-weight: 600;
    color: var(--text);
    flex: 1;
  }

  .library-page .lib-controls {
    margin-bottom: 24px;
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .lib-search {
    position: relative;
  }
  .lib-search input {
    width: 100%;
    padding: 12px 14px 12px 42px;
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    background: white;
    font-size: 15px;
    font-family: inherit;
    color: var(--text);
    outline: none;
    transition: border-color .12s, box-shadow .12s;
  }
  .lib-search input:focus {
    border-color: var(--brand-secondary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-secondary) 12%, transparent);
  }
  .lib-search-icon {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    color: var(--text-dim);
    pointer-events: none;
  }
  .lib-controls-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
  }
  .lib-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .lib-filter {
    padding: 7px 14px;
    border: 1px solid var(--border-soft);
    background: white;
    color: var(--text);
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    font-family: inherit;
  }
  .lib-filter:hover {
    background: var(--bg-soft);
    border-color: var(--border);
  }
  .lib-filter.is-active {
    background: var(--brand-secondary);
    border-color: var(--brand-secondary);
    color: white;
  }
  .lib-sort {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--text-dim);
    flex-shrink: 0;
  }
  .lib-sort-label {
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.6px;
  }
  .lib-sort-select {
    padding: 7px 10px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    background: white;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
    font-family: inherit;
  }

  /* Card grid — responsive 4-column max on widescreen, scales down. */
  .lib-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 18px;
  }
  @media (min-width: 560px) { .lib-grid { grid-template-columns: repeat(2, 1fr); } }
  @media (min-width: 880px) { .lib-grid { grid-template-columns: repeat(3, 1fr); } }
  /* Capped at 3 columns by request (2026-05-26) — at 4 cols the
     thumbnails got too small to read drill diagrams at a glance. */

  .lib-card {
    display: flex;
    flex-direction: column;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 14px;
    overflow: hidden;
    text-decoration: none;
    color: var(--text);
    transition: box-shadow .15s, transform .15s, border-color .15s;
    position: relative;
  }
  .lib-card:hover {
    box-shadow: 0 14px 32px -14px rgba(0, 0, 0, 0.16);
    transform: translateY(-2px);
    border-color: var(--border);
  }
  .lib-card-thumb {
    position: relative;
    aspect-ratio: 16 / 10;
    background: var(--bg-soft);
    overflow: hidden;
  }
  .lib-card-thumb img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
  }
  .lib-card-thumb--loading {
    background: #f4f5f7;
  }
  .lib-card-thumb--loading::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
      center / 22px 22px no-repeat
      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='9' fill='none' stroke='%23e7e9ec' stroke-width='2.5'/><path d='M12 3 a 9 9 0 0 1 9 9' fill='none' stroke='%23d4302b' stroke-width='2.5' stroke-linecap='round'/></svg>");
    animation: drill-thumb-spin 0.8s linear infinite;
    pointer-events: none;
  }
  .lib-card-anim {
    position: absolute;
    top: 10px;
    left: 10px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    background: rgba(30, 111, 191, 0.95);
    color: white;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    line-height: 1;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  }
  .lib-card-fav {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 32px;
    height: 32px;
    border-radius: 999px;
    border: none;
    background: rgba(255, 255, 255, 0.92);
    color: var(--text-dim);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    backdrop-filter: blur(4px);
    transition: color .12s, background .12s, transform .12s;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  }
  .lib-card-fav:hover { color: var(--red); transform: scale(1.08); }
  .lib-card-fav--on { color: var(--red); }

  /* Selection checkbox — top-left, mirrors the fav star on the right.
     Fades in on hover or whenever the card is selected so unselected
     cards stay visually clean. */
  .lib-card-check {
    position: absolute;
    top: 8px;
    left: 8px;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    border: none;
    background: rgba(255, 255, 255, 0.92);
    color: var(--text-dim);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    backdrop-filter: blur(4px);
    transition: opacity .12s, color .12s, background .12s, transform .12s;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
    opacity: 0;
  }
  .lib-card:hover .lib-card-check,
  .lib-card-check--on,
  .lib-card.is-selected .lib-card-check {
    opacity: 1;
  }
  .lib-card-check:hover { transform: scale(1.08); }
  .lib-card-check--on {
    background: var(--brand-secondary);
    color: white;
  }
  .lib-card.is-selected {
    border-color: var(--brand-secondary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand-secondary) 35%, transparent);
  }
  .lib-card.is-selected:hover {
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand-secondary) 50%, transparent),
                0 14px 32px -14px rgba(0, 0, 0, 0.16);
  }

  /* Floating bottom action bar — appears when at least one drill is
     selected. Shows the count + Clear + "Open in Drill Board" CTA. */
  .lib-selection-bar {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: var(--text);
    color: white;
    border-radius: 999px;
    box-shadow: 0 12px 40px -10px rgba(0, 0, 0, 0.45);
    z-index: 100;
    animation: lib-sel-bar-in 0.18s ease-out;
  }
  @keyframes lib-sel-bar-in {
    from { opacity: 0; transform: translate(-50%, 14px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
  }
  .lib-selection-count {
    font-size: 13.5px;
    font-weight: 600;
    padding: 0 6px;
  }
  .lib-selection-bar .btn {
    padding: 7px 14px;
    font-size: 13px;
    border-radius: 999px;
  }
  .lib-selection-bar .btn-secondary {
    background: rgba(255, 255, 255, 0.12);
    color: white;
    border: 1px solid rgba(255, 255, 255, 0.18);
  }
  .lib-selection-bar .btn-secondary:hover {
    background: rgba(255, 255, 255, 0.22);
  }
  .lib-selection-bar .btn-primary {
    background: var(--brand-secondary);
    border: none;
  }

  /* Add-to-plan modal — list of existing plans + an inline "new plan"
     creator. Sized for a comfortable browse of ~6 plans before scrolling. */
  .lib-addplan-modal {
    width: 480px;
    max-width: 92vw;
  }
  .lib-addplan-new {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
  }
  .lib-addplan-new input {
    flex: 1;
    padding: 10px 12px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    font-size: 14px;
    font-family: inherit;
    color: var(--text);
    outline: none;
  }
  .lib-addplan-new input:focus {
    border-color: var(--brand-secondary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-secondary) 12%, transparent);
  }
  .lib-addplan-new .btn-primary {
    flex-shrink: 0;
    white-space: nowrap;
  }
  .lib-addplan-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 6px 0 12px;
    color: var(--text-dim);
    font-size: 11.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.6px;
  }
  .lib-addplan-divider::before,
  .lib-addplan-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border-soft);
  }
  .lib-addplan-list {
    max-height: 340px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 4px;
  }
  .lib-addplan-row {
    appearance: none;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    padding: 12px 14px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    transition: background .12s, border-color .12s;
  }
  .lib-addplan-row:hover {
    background: var(--bg-soft);
    border-color: var(--border);
  }
  .lib-addplan-row-name {
    font-size: 14.5px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.3;
  }
  .lib-addplan-row-meta {
    font-size: 12px;
    color: var(--text-dim);
    margin-top: 2px;
  }
  .lib-addplan-overlap {
    font-size: 11px;
    color: var(--text-dim);
    background: var(--bg-soft);
    border-radius: 999px;
    padding: 3px 9px;
    font-weight: 600;
    flex-shrink: 0;
  }
  .lib-addplan-empty {
    padding: 24px 14px;
    text-align: center;
    color: var(--text-dim);
    font-size: 13px;
  }
  .lib-card-info {
    padding: 14px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
  }
  .lib-card-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .lib-card-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    font-size: 11px;
    color: var(--text-dim);
  }
  .lib-mins,
  .lib-age {
    background: var(--bg-soft);
    padding: 2px 8px;
    border-radius: 999px;
    font-weight: 600;
    color: var(--text);
  }
  .lib-plans {
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    font-weight: 600;
  }
  .lib-time { color: var(--text-dim); font-weight: 500; }
  .lib-card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 2px;
  }
  .lib-tag {
    background: color-mix(in srgb, var(--brand-secondary) 12%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 500;
    line-height: 1.5;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 120px;
  }
  .lib-tag--more {
    background: var(--bg-soft);
    color: var(--text-dim);
    max-width: none;
  }

  .lib-empty {
    text-align: center;
    padding: 60px 20px;
  }
  .lib-empty-icon {
    font-size: 40px;
    margin-bottom: 12px;
  }
  .lib-empty-title {
    font-size: 17px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 6px;
  }
  .lib-empty-sub {
    font-size: 13px;
    color: var(--text-dim);
  }

  /* ---- 7-day calendar strip (2026-05-26, visual overhaul) ---- */
  /* Calendar sits ABOVE the hero — first thing the coach sees. Each day
     cell is taller now, with the day-of-week label tucked at the top in
     muted weight and the date number as the dominant glyph. Today's
     cell gets a brand-coloured fill (not a stroke) so it pops; days
     with events show a tinted bottom rail in the event's colour. */
  .dash-cal {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    /* Roomier gutters between day cells — was 8px, felt cramped on
       wider screens where each cell is taller. (2026-05-26) */
    gap: 14px;
    padding: 32px 8px 8px;
    margin-bottom: 0;
    /* Stacking-context lift — the hero band below has its own
       stacking context (background gradient + position:relative) and
       was painting OVER the absolutely-positioned tooltips that
       extend out of calendar cells. Putting the calendar on its own
       higher z-index plane makes its tooltips render above siblings.
       (2026-05-26 fix.) */
    position: relative;
    z-index: 10;
  }
  .dash-cal-day {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 4px 8px;
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 12px;
    color: var(--text);
    text-decoration: none;
    transition: background .12s, border-color .12s, transform .12s, box-shadow .12s;
    position: relative;
    /* overflow:visible (not hidden) so the absolutely-positioned
       .dash-cal-tip tooltip can extend below the cell on hover. */
    overflow: visible;
  }
  .dash-cal-day:hover {
    background: var(--bg-soft);
    border-color: var(--border);
    transform: translateY(-2px);
    box-shadow: 0 6px 16px -6px rgba(0, 0, 0, 0.12);
  }
  .dash-cal-day.is-today {
    background: var(--brand-secondary, #1e6fbf);
    border-color: var(--brand-secondary, #1e6fbf);
    box-shadow: 0 8px 20px -8px rgba(30, 111, 191, 0.55);
  }
  .dash-cal-day.is-today .dash-cal-dow,
  .dash-cal-day.is-today .dash-cal-num {
    color: white;
  }
  .dash-cal-day.is-today:hover {
    transform: translateY(-3px);
    filter: brightness(1.05);
  }
  .dash-cal-dow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--text-dim);
  }
  .dash-cal-num {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.05;
    color: var(--text);
    letter-spacing: -0.02em;
  }
  .dash-cal-dots {
    display: flex;
    gap: 3px;
    height: 6px;
    margin-top: 4px;
  }
  .dash-cal-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--text-dim);
  }
  .dash-cal-dot--game     { background: var(--red, #d4302b); }
  .dash-cal-dot--practice { background: var(--brand-secondary, #1e6fbf); }
  .dash-cal-dot--event    { background: #94a3b8; }
  /* When today has events, swap the dots for white so they show on
     the blue background. */
  .dash-cal-day.is-today .dash-cal-dot {
    background: rgba(255, 255, 255, 0.85);
  }

  /* Calendar tooltip — hover-only affordance for desktop, surfacing the
     date + event list without forcing a navigation. iPad coaches tap to
     navigate to /schedule for the same info, since hover-only tooltips
     are unreliable under touch. position: absolute against the day cell;
     side modifiers nudge the leftmost / rightmost cells' tooltips inward
     so they don't clip off the viewport. */
  .dash-cal-tip {
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%) translateY(-4px);
    min-width: 200px;
    max-width: 280px;
    padding: 12px 14px;
    background: var(--panel-dark, #2c3036);
    color: #f5f7fa;
    border-radius: 10px;
    box-shadow: 0 12px 28px -8px rgba(0, 0, 0, 0.35);
    opacity: 0;
    pointer-events: none;
    transition: opacity .15s, transform .15s;
    /* High z-index lifts the tooltip above sibling stacking contexts
       below (the hero band). Combined with `.dash-cal` having its own
       z-index:10, this guarantees the tooltip paints over the hero. */
    z-index: 100;
    text-align: left;
    line-height: 1.4;
    /* Small arrow pointing up at the day cell. */
  }
  .dash-cal-tip::before {
    content: '';
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-bottom-color: var(--panel-dark, #2c3036);
  }
  .dash-cal-day:hover .dash-cal-tip,
  .dash-cal-day:focus-visible .dash-cal-tip {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  /* Left-edge cell — pin tooltip to the left edge of the cell + move
     the arrow accordingly so it stays visible. */
  .dash-cal-day--tip-left .dash-cal-tip {
    left: 0;
    transform: translateX(0) translateY(-4px);
  }
  .dash-cal-day--tip-left:hover .dash-cal-tip,
  .dash-cal-day--tip-left:focus-visible .dash-cal-tip {
    transform: translateX(0) translateY(0);
  }
  .dash-cal-day--tip-left .dash-cal-tip::before {
    left: 18px;
    transform: translateX(0);
  }
  .dash-cal-day--tip-right .dash-cal-tip {
    left: auto;
    right: 0;
    transform: translateX(0) translateY(-4px);
  }
  .dash-cal-day--tip-right:hover .dash-cal-tip,
  .dash-cal-day--tip-right:focus-visible .dash-cal-tip {
    transform: translateX(0) translateY(0);
  }
  .dash-cal-day--tip-right .dash-cal-tip::before {
    left: auto;
    right: 18px;
    transform: translateX(0);
  }
  .dash-cal-tip-head {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
    margin-bottom: 6px;
  }
  .dash-cal-tip-empty {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.55);
    font-style: italic;
  }
  .dash-cal-tip-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .dash-cal-tip-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: #f5f7fa;
  }
  .dash-cal-tip-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
    background: rgba(255, 255, 255, 0.5);
  }
  .dash-cal-tip-dot--game     { background: var(--red, #d4302b); }
  .dash-cal-tip-dot--practice { background: var(--brand-secondary, #1e6fbf); }
  .dash-cal-tip-dot--event    { background: #94a3b8; }
  .dash-cal-tip-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
  }
  .dash-cal-tip-time {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.7);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-weight: 600;
    flex-shrink: 0;
  }

  /* ---- Widget grid — accent-coloured per widget for personality ----
     Stack on narrow viewports; force a 3-up row on tablet+ widths so
     the three widgets sit side-by-side across the page like Ian asked
     (auto-fit was happy to wrap when content nudged past min-width).
     2026-05-26. */
  .dash-widgets {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
    margin-top: 8px;
    margin-bottom: 8px;
  }
  @media (min-width: 720px) {
    .dash-widgets { grid-template-columns: repeat(3, 1fr); }
  }
  .dash-widget {
    background: white;
    border: 1px solid var(--border-soft);
    border-radius: 14px;
    padding: 18px 18px 14px;
    transition: box-shadow .15s, transform .15s, border-color .15s;
    position: relative;
    overflow: hidden;
  }
  .dash-widget:hover {
    box-shadow: 0 12px 28px -12px rgba(0, 0, 0, 0.14);
    transform: translateY(-2px);
  }
  /* Top accent ribbon — 3px coloured strip flush with the top of the
     card, scoped per widget so each one reads as its own thing. */
  .dash-widget::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: var(--text-dim);
    opacity: 0.7;
  }
  .dash-widget--recent::before { background: var(--brand-secondary, #1e6fbf); }
  .dash-widget--fav::before    { background: #f5a524; }
  .dash-widget--upnext::before { background: var(--red, #d4302b); }

  .dash-widget-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
  }
  .dash-widget-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 6px;
    flex-shrink: 0;
  }
  .dash-widget--recent .dash-widget-icon {
    background: color-mix(in srgb, var(--brand-secondary) 14%, white);
    color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
  }
  .dash-widget--fav .dash-widget-icon {
    background: color-mix(in srgb, #f5a524 18%, white);
    color: color-mix(in srgb, #f5a524 75%, #000);
  }
  .dash-widget--upnext .dash-widget-icon {
    background: color-mix(in srgb, var(--red) 12%, white);
    color: color-mix(in srgb, var(--red) 80%, #000);
  }
  .dash-widget-head h3 {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    font-weight: 700;
    color: var(--text);
    margin: 0;
    flex: 1;
  }
  .dash-widget-more {
    font-size: 11px;
    color: var(--text-dim);
    text-decoration: none;
    font-weight: 600;
    transition: color .12s;
  }
  .dash-widget-more:hover { color: var(--brand-secondary); text-decoration: underline; }
  .dash-widget-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .dash-widget-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 8px;
    border-radius: 8px;
    text-decoration: none;
    color: var(--text);
    transition: background .12s, transform .12s;
  }
  .dash-widget-row:hover {
    background: var(--bg-soft);
    transform: translateX(2px);
  }
  /* Thumbnails were 36×24 — too small to actually read. Bumped to a
     proper 16:9 preview so coaches can recognise a drill at a glance
     from the dashboard widgets. (2026-05-26) */
  .dash-widget-thumb {
    width: 80px;
    height: 50px;
    border-radius: 6px;
    object-fit: contain;
    background: var(--bg-soft);
    flex-shrink: 0;
    border: 1px solid var(--border-soft);
  }
  .dash-widget-row-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .dash-widget-row-mins {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-dim);
    flex-shrink: 0;
    padding: 2px 8px;
    background: var(--bg-soft);
    border-radius: 999px;
  }
  .dash-widget-cal-icon {
    width: 50px;
    height: 50px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    font-weight: 700;
    color: white;
    background: var(--text-dim);
    flex-shrink: 0;
  }
  .dash-widget-cal-icon--game     { background: var(--red, #d4302b); }
  .dash-widget-cal-icon--practice { background: var(--brand-secondary, #1e6fbf); }
  .dash-widget-cal-icon--event    { background: #888; }
  .dash-widget-empty {
    padding: 8px 8px 4px;
    font-size: 12px;
    color: var(--text-dim);
    font-style: italic;
    line-height: 1.4;
  }
  .btn {
    border: 1px solid var(--border);
    background: white;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-family: inherit;
    font-size: 14px;
  }
  .btn:hover { background: var(--bg-soft); }
  .btn-primary { background: var(--brand-secondary); color: white; border-color: var(--brand-secondary); }
  .btn-primary:hover { filter: brightness(0.92); }
  .btn-danger { background: var(--red); color: white; border-color: var(--red); transition: filter .15s; }
  /* Restate the background on hover/focus so the generic `.btn:hover` rule above
     can't repaint the button to var(--bg-soft) — that would defeat the filter. */
  .btn-danger:hover, .btn-danger:focus { background: var(--red); filter: brightness(0.9); }
  /* All primary buttons get the same darken-on-hover treatment. */
  .btn-primary, .login-form button, .goalie-section, .plan-btn, .nav-drawer-link.active, .topnav-link.active {
    transition: filter .15s, background .15s;
  }
  .btn-primary:hover, .btn-primary:focus { background: var(--brand-secondary); filter: brightness(0.9); }
  .login-form button:hover, .login-form button:focus { background: var(--brand-primary); filter: brightness(0.9); }
  .nav-drawer-link.active:hover, .nav-drawer-link.active:focus { background: var(--brand-primary); filter: brightness(0.9); }
  .topnav-link.active:hover, .topnav-link.active:focus { background: var(--brand-primary); filter: brightness(0.9); }

  /* Drill picker for plan */
  .drill-picker {
    max-height: 320px;
    overflow-y: auto;
    border: 1px solid var(--border-soft);
    border-radius: 4px;
    margin: 8px 0;
  }
  .drill-picker .pick-item {
    padding: 8px 12px;
    cursor: pointer;
    display: flex;
    gap: 10px;
    align-items: center;
    border-bottom: 1px solid var(--border-soft);
  }
  .drill-picker .pick-item:hover { background: var(--bg-soft); }
  .drill-picker .pick-item:last-child { border-bottom: none; }
  .drill-picker .pick-item img {
    width: 60px; height: 32px;
    border: 1px solid var(--border-soft);
    border-radius: 3px;
  }
  .drill-picker .pick-item .nm { flex: 1; font-size: 13px; }

  /* Toast — Emil polish: explicit properties + custom ease-out curve,
     subtle scale on entry so it materializes rather than just slides. */
  .toast {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(20px) scale(0.96);
    background: var(--panel-dark);
    color: white;
    padding: 10px 18px;
    border-radius: 4px;
    font-size: 13px;
    opacity: 0;
    transition:
      transform 220ms cubic-bezier(0.23, 1, 0.32, 1),
      opacity 220ms ease-out;
    z-index: 200;
    pointer-events: none;
    box-shadow: 0 6px 18px rgba(0,0,0,.2);
  }
  .toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
  @media (prefers-reduced-motion: reduce) {
    .toast { transition: opacity 180ms ease-out; transform: translateX(-50%) translateY(0); }
    .toast.show { transform: translateX(-50%) translateY(0); }
  }

  ::-webkit-scrollbar { width: 8px; height: 8px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
  ::-webkit-scrollbar-thumb:hover { background: #b0b6bd; }

  @media (max-width: 1100px) {
    main { grid-template-columns: 120px 1fr 280px; }
    .drill-name { width: 220px; }
  }
  @media (max-width: 800px) {
    /* On non-drill pages (Plans, Eval, Team, etc.), narrow screens drop
       the docked sidebar entirely and let the page take the full width.
       Drill pages need to keep their sidebar (it's the drill drawer)
       and have their own narrow-window layout defined elsewhere. */
    body:not(.route-drill) main { grid-template-columns: 110px 1fr; }
    body:not(.route-drill) .sidebar { display: none; }
    .fab { right: 24px; }
    .style-popover { right: 24px; }
  }

/* ============================================================
   PHASE 4 — TOP NAV + MULTI-PAGE CHROME
   ============================================================ */
.topnav {
  display: flex; align-items: center; gap: 18px;
  /* Inset by env(safe-area-inset-*) so the bar respects the notch /
     Dynamic Island in landscape iOS, and the rounded corners on
     Android. Padding-left + right matter most in landscape; top
     handles a status-bar overlap if the app is ever in fullscreen. */
  padding:
    env(safe-area-inset-top, 0)
    calc(16px + env(safe-area-inset-right, 0))
    0
    calc(16px + env(safe-area-inset-left, 0));
  height: calc(52px + env(safe-area-inset-top, 0));
  background: var(--panel-dark);
  color: #fff;
  border-bottom: 1px solid #1a1d22;
  position: sticky; top: 0; z-index: 90;
}
.topnav .brand {
  display: inline-flex; align-items: center; gap: 8px;
  color: #fff; text-decoration: none;
  font-weight: 700; letter-spacing: 0.4px;
}
.topnav .brand-mark {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--brand-primary);
  display: grid; place-items: center;
  font-weight: 700; font-size: 14px;
  overflow: hidden;
  color: #fff;
}
.topnav .brand-mark img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.topnav .brand-text { font-size: 15px; }
.topnav-links { display: flex; gap: 2px; flex: 1; overflow-x: auto; }
.topnav-link {
  padding: 8px 14px;
  color: #d6d9de;
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  border-radius: 6px;
  white-space: nowrap;
  transition: background .12s, color .12s;
}
.topnav-link:hover { background: rgba(255,255,255,.06); color: #fff; }
.topnav-link.active { background: var(--brand-primary); color: #fff; }
.topnav-right { display: flex; align-items: center; gap: 10px; }
.team-chip {
  position: relative;
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255,255,255,.08);
  color: #fff;
  padding: 6px 12px;
  border-radius: 16px;
  font-size: 13px;
  cursor: pointer;
  user-select: none;
}
.team-chip:hover { background: rgba(255,255,255,.14); }
.team-chip .team-name { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.team-menu {
  position: absolute; top: 100%; right: 0; margin-top: 6px;
  background: #fff; color: var(--text);
  border-radius: 6px;
  box-shadow: 0 8px 28px rgba(0,0,0,.25);
  min-width: 220px;
  display: none;
  z-index: 95;
}
.team-menu.show { display: block; }
.team-menu .item {
  padding: 10px 14px;
  cursor: pointer;
  font-size: 13px;
  display: flex; align-items: center; justify-content: space-between;
}
.team-menu .item:hover { background: var(--bg-soft); }
.team-menu .item.active { font-weight: 600; color: var(--red); }
.team-menu .item.action { color: var(--blue); }
.team-menu .badge {
  background: var(--bg-soft);
  color: var(--text-dim);
  font-size: 10px;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 8px;
}
.team-menu .divider { height: 1px; background: var(--border-soft); margin: 4px 0; }
.logout-btn {
  background: transparent; color: #d6d9de;
  border: 1px solid rgba(255,255,255,.18);
  padding: 6px 12px; border-radius: 6px;
  font-size: 12px; cursor: pointer;
}
.logout-btn:hover { background: rgba(255,255,255,.08); color: #fff; }

/* Main page container (everything that isn't the drill route) */
.page-main { min-height: calc(100vh - 52px); }
body.route-drill .page-main { height: calc(100vh - 52px); }

/* Give the canvas most of the visible viewport, then let tags + notes spill
   below the fold. Scroll inside .canvas-wrap to reach them. The 220px chrome
   allowance covers the drill-tabs strip + the style bar + .canvas-wrap padding;
   tweak if any of those grow. Mobile keeps its own rules in the @media block. */
body.route-drill .canvas-wrap { overflow-y: auto; overflow-x: hidden; }
body.route-drill .canvas-stage { min-height: calc(100vh - 220px); }

/* Generic content shells for the non-drill pages */
.page {
  max-width: 1240px;
  margin: 0 auto;
  padding: 32px 24px 60px;
}
.page-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 28px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border-soft);
}
.page-header h1 {
  margin: 0;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.page-header .sub {
  color: var(--text-dim);
  font-size: 14px;
  margin-top: 6px;
  line-height: 1.5;
}
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.page-actions .btn { font-size: 13px; }

.card {
  background: #fff;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 12px;
  box-shadow: 0 1px 2px rgba(0,0,0,.03);
}
.card .card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.card h2 { margin: 0; font-size: 15px; font-weight: 600; }

.empty {
  text-align: center;
  padding: 56px 20px;
  color: var(--text-dim);
}
.empty .icon { font-size: 36px; margin-bottom: 8px; }

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
table.data-table th, table.data-table td {
  text-align: left;
  padding: 9px 10px;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}
table.data-table th {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-size: 11px;
  color: var(--text-dim);
  background: var(--bg-soft);
}
table.data-table tr:hover td { background: #fafbfc; }
table.data-table input[type="number"], table.data-table input[type="text"] {
  width: 100%; padding: 4px 6px; font-size: 13px;
  border: 1px solid var(--border-soft); border-radius: 4px;
}
table.data-table input[type="number"]:focus, table.data-table input[type="text"]:focus {
  border-color: var(--blue); outline: none;
}

.pos-group { margin-bottom: 18px; }
.pos-group h3 {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.8px;
  color: var(--text-dim); margin: 6px 0 6px;
}

.kv { display: grid; grid-template-columns: 120px 1fr; gap: 8px 12px; font-size: 13px; }
.kv .k { color: var(--text-dim); }

/* Page-specific tweaks */
body.route-drill .topnav { /* already correct */ }
body:not(.route-drill) .fab { display: none; }

/* ============================================================
   SHOT TRACKER
   ============================================================ */
.shot-modal-content {
  width: min(1500px, 98vw) !important;
  max-height: 94vh;
  display: flex;
  flex-direction: column;
}
.shot-modal-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.shot-modal-header h3 { margin: 0; }
.shot-modal-header .sub { font-size: 12px; color: var(--text-dim); }
.shot-modal-toolbar {
  display: flex; gap: 16px; align-items: center;
  padding: 10px 12px;
  background: var(--bg-soft);
  border-radius: 6px;
  margin-bottom: 12px;
}
.shot-mode-toggle {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2px;
}
.shot-mode-toggle .mode-btn {
  background: transparent;
  border: none;
  padding: 6px 18px;
  border-radius: 16px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  color: var(--text-dim);
}
.shot-mode-toggle .mode-btn.active {
  background: var(--red);
  color: #fff;
}
.shot-mode-toggle .mode-btn[data-mode="goal"].active { background: var(--green); }
.shot-period { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
.shot-period select { padding: 4px 6px; }
.shot-counts {
  display: inline-flex; gap: 14px; margin-left: auto;
  font-size: 13px;
}
.shot-counts .count b { font-size: 16px; color: var(--text); margin-right: 4px; }
.shot-counts .goals b { color: var(--green); }
.shot-modal-body {
  display: grid;
  grid-template-columns: 1fr 240px;
  gap: 14px;
  min-height: 0;
  flex: 1;
}
.shot-rink-wrap { display: flex; flex-direction: column; min-width: 0; }
.shot-rink-stage {
  position: relative;
  background: #fff;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  overflow: hidden;
  cursor: crosshair;
}
.shot-rink-stage canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}
.shot-rink-stage canvas#shot-overlay { z-index: 2; }
.shot-hint {
  font-size: 12px; color: var(--text-dim);
  margin-top: 8px;
}
.shot-players {
  display: flex; flex-direction: column;
  min-height: 0;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  overflow: hidden;
}
.shot-players-head {
  background: var(--panel-dark);
  color: #fff;
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.shot-players-help {
  border-top: 1px solid var(--border-soft);
  padding: 8px 12px;
  font-size: 11px;
  color: var(--text-dim);
}
#shot-player-list { flex: 1; overflow-y: auto; }
.shot-player {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  background: #fff;
  border: none;
  border-bottom: 1px solid var(--border-soft);
  padding: 8px 12px;
  font-size: 13px;
  cursor: pointer;
  text-align: left;
}
.shot-player:hover { background: var(--bg-soft); }
.shot-player.active {
  background: var(--red);
  color: #fff;
}
.shot-player.active .pos { color: rgba(255,255,255,.8); }
.shot-player .num {
  display: inline-grid; place-items: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--bg-soft);
  color: var(--text);
  font-weight: 700;
  font-size: 12px;
  flex-shrink: 0;
}
.shot-player.active .num { background: #fff; color: var(--red); }
.shot-player .nm { flex: 1; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shot-player .pos {
  font-size: 11px;
  color: var(--text-dim);
}

/* Shot tracker — Us/Them, scoreboard */
.shot-scoreboard {
  display: inline-flex; align-items: center; gap: 12px;
  background: var(--panel-dark);
  color: #fff;
  padding: 8px 16px;
  border-radius: 8px;
  margin-left: auto;
}
.shot-scoreboard .side { display: flex; flex-direction: column; align-items: center; }
.shot-scoreboard .lbl {
  font-size: 10px; text-transform: uppercase; letter-spacing: 1px;
  color: rgba(255,255,255,.7);
}
.shot-scoreboard .num { font-size: 26px; font-weight: 700; line-height: 1; }
.shot-scoreboard .vs { font-size: 22px; color: rgba(255,255,255,.4); }

.shot-period-tabs {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2px;
}
.shot-period-tabs .period-btn {
  background: transparent;
  border: none;
  padding: 6px 14px;
  border-radius: 16px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  color: #5b6068;
}
.shot-period-tabs .period-btn:hover { color: #111; }
.shot-period-tabs .period-btn.active {
  background: var(--red, #d4302b);
  color: #fff;
}
/* All shot-tracker toolbar controls share the same 32px height so they
   sit on a clean baseline regardless of which has labels / icons / text. */
.shot-modal-toolbar > * { height: 32px; box-sizing: border-box; }
.shot-modal-toolbar .shot-counts { height: auto; }

/* "We attack" group: inline label + arrow toggle, all at 32px. */
.shot-attack-group { display: inline-flex; align-items: center; gap: 6px; }
.shot-attack-label {
  font-size: 11px; font-weight: 600;
  color: var(--text-dim, #5b6068);
  text-transform: uppercase; letter-spacing: 0.4px;
  white-space: nowrap;
}
.shot-attack-toggle {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 16px;
  padding: 2px;
  align-items: center;
}
.shot-attack-toggle .attack-btn {
  background: transparent; border: none;
  padding: 0 12px;
  height: 24px;
  border-radius: 12px;
  font-size: 14px; font-weight: 700; line-height: 1;
  cursor: pointer; color: #5b6068;
}
.shot-attack-toggle .attack-btn.active { background: var(--red, #d4302b); color: #fff; }

/* Plain icon — no border or background, just the glyph + tooltip. */
.shot-modal-toolbar .icon-btn-plain {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border: none;
  background: transparent;
  font-size: 18px; line-height: 1;
  cursor: pointer; color: #5b6068;
  padding: 0;
}
.shot-modal-toolbar .icon-btn-plain:hover { color: #111; }
.shot-modal-toolbar .icon-btn-plain:disabled { opacity: 0.35; cursor: not-allowed; }
#shot-lock-period.is-locked { color: var(--red, #d4302b); }
/* Locked period tabs get a thin ring so the lock state is glanceable. */
.shot-period-tabs .period-btn.is-locked { box-shadow: inset 0 0 0 2px var(--red, #d4302b); }
.shot-period-tabs .period-btn.is-locked::after { content: " 🔒"; font-size: 10px; }
/* When the active period is locked, dim & block the rink stage so the user
   can't even attempt a tap. The toolbar still works so the period can be
   unlocked. */
.shot-rink-stage.is-locked { opacity: 0.55; pointer-events: none; }

/* ============================================================
   Schedule: view-mode toggle + calendar grid
   ============================================================ */
.schedule-view-toggle {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 16px;
  padding: 2px;
}
.schedule-view-toggle .view-tab {
  background: transparent; border: none;
  padding: 5px 12px;
  border-radius: 12px;
  font-size: 12px; font-weight: 600;
  cursor: pointer; color: #5b6068;
  line-height: 1;
}
.schedule-view-toggle .view-tab:hover { color: #111; }
.schedule-view-toggle .view-tab.active { background: var(--red, #d4302b); color: #fff; }

.calendar-toolbar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 4px;
}
.calendar-toolbar .cal-title {
  font-size: 16px; font-weight: 700; margin-left: 6px;
}
.calendar-toolbar .cal-nav { padding: 4px 10px; font-size: 14px; }

.calendar-grid { border-top: 1px solid var(--border, #d4d7dc); }
.cal-row.cal-head {
  display: grid; grid-template-columns: repeat(7, 1fr);
  background: #fafafa;
  border-bottom: 1px solid var(--border, #d4d7dc);
}
.cal-dow {
  padding: 6px 8px;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-dim, #5b6068);
  text-align: left;
}
.cal-row.cal-body {
  display: grid; grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(100px, auto);
}
.cal-cell {
  border-right: 1px solid var(--border, #d4d7dc);
  border-bottom: 1px solid var(--border, #d4d7dc);
  padding: 4px 6px 6px 6px;
  min-height: 100px;
  background: #fff;
  display: flex; flex-direction: column; gap: 4px;
  overflow: hidden;
}
.cal-cell:nth-child(7n) { border-right: none; }
.cal-cell.out { background: #fafafa; color: #b3b6bb; }
.cal-cell.today .cal-day-num {
  background: var(--red, #d4302b); color: #fff;
  border-radius: 999px;
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
}
.cal-day-num {
  font-size: 12px; font-weight: 600;
  color: #111;
  align-self: flex-start;
}
.cal-cell.out .cal-day-num { color: #b3b6bb; }
.cal-entries { display: flex; flex-direction: column; gap: 3px; }
.cal-entry {
  display: flex; align-items: center; gap: 4px;
  text-align: left;
  background: #f1f3f6;
  border: 1px solid transparent;
  border-left: 3px solid #5b6068;
  border-radius: 4px;
  padding: 2px 6px;
  font-size: 11px;
  line-height: 1.3;
  cursor: pointer;
  color: #1f2227;
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
}
.cal-entry:hover { background: #e7eaef; }
.cal-entry.type-game     { border-left-color: var(--red, #d4302b); }
.cal-entry.type-practice { border-left-color: #2563eb; }
.cal-entry.type-event    { border-left-color: #16a34a; }
.cal-entry-icon { flex: 0 0 auto; }
.cal-entry-time { flex: 0 0 auto; font-weight: 700; }
.cal-entry-text { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 720px) {
  .cal-row.cal-body { grid-auto-rows: minmax(70px, auto); }
  .cal-cell { min-height: 70px; padding: 3px 4px; }
  .cal-entry-text { display: none; }
}

/* ============================================================
   Day view — single date, entries stacked + sorted by time
   ============================================================ */
.cal-day {
  border-top: 1px solid var(--border, #d4d7dc);
  padding: 20px;
  background: #fff;
}
.cal-day-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 720px;
  margin: 0 auto;
}
.cal-day-list .cal-entry {
  font-size: 14px;
  padding: 10px 14px;
  gap: 10px;
}
.cal-day-empty {
  text-align: center;
  padding: 60px 20px;
  color: var(--text-dim);
  font-size: 14px;
}

/* ============================================================
   Week view — 7 columns side by side, entries vertically stacked
   ============================================================ */
.cal-week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-top: 1px solid var(--border, #d4d7dc);
  border-left: 1px solid var(--border, #d4d7dc);
}
.cal-week-col {
  border-right: 1px solid var(--border, #d4d7dc);
  border-bottom: 1px solid var(--border, #d4d7dc);
  min-height: 280px;
  background: #fff;
  display: flex;
  flex-direction: column;
}
.cal-week-col.today { background: #fff7e6; }
.cal-week-col-head {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-soft, #e9ebef);
  background: #f7f8fa;
  position: sticky; top: 0;
  z-index: 1;
}
.cal-week-col.today .cal-week-col-head { background: #fef3c7; }
.cal-week-dow {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-dim);
  font-weight: 700;
}
.cal-week-num {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  margin-top: 2px;
}
.cal-week-entries {
  padding: 6px 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
}
.cal-week-empty {
  color: #d4d7dc;
  text-align: center;
  font-size: 14px;
  padding: 8px 0;
}
@media (max-width: 720px) {
  .cal-week {
    grid-template-columns: 1fr;
  }
  .cal-week-col { min-height: 0; }
  .cal-week-col-head { display: flex; align-items: baseline; gap: 8px; }
  .cal-week-num { margin-top: 0; font-size: 15px; }
}

/* ============================================================
   Year view — 12 mini month grids in a 4×3 (or 3×4) layout
   ============================================================ */
.cal-year {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
  padding: 20px;
  background: #fff;
  border-top: 1px solid var(--border, #d4d7dc);
}
@media (max-width: 1200px) { .cal-year { grid-template-columns: repeat(3, minmax(0,1fr)); } }
@media (max-width: 880px)  { .cal-year { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 540px)  { .cal-year { grid-template-columns: 1fr; } }
.cal-yr-month {
  font-size: 11px;
}
.cal-yr-month-head {
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 6px;
  color: var(--text);
}
.cal-yr-dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  font-size: 10px;
  color: var(--text-dim);
  letter-spacing: 0.4px;
}
.cal-yr-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  margin-top: 2px;
}
.cal-yr-cell {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  background: #f5f6f7;
  position: relative;
  cursor: pointer;
  transition: background 120ms ease-out, transform 100ms ease-out;
}
.cal-yr-cell:active:not(.blank) { transform: scale(0.94); }
.cal-yr-cell.blank { background: transparent; cursor: default; }
.cal-yr-cell.today { outline: 2px solid var(--brand-secondary, #1f5fff); outline-offset: -2px; }
.cal-yr-cell.has-entries { color: white; font-weight: 700; }
.cal-yr-cell.has-game     { background: var(--red, #d4302b); }
.cal-yr-cell.has-practice { background: #2563eb; }
.cal-yr-cell.has-event    { background: #16a34a; }
/* Multi-type day: blend via diagonal */
.cal-yr-cell.has-game.has-practice {
  background: linear-gradient(135deg, var(--red, #d4302b) 50%, #2563eb 50%);
}
.cal-yr-cell.has-game.has-event {
  background: linear-gradient(135deg, var(--red, #d4302b) 50%, #16a34a 50%);
}
.cal-yr-cell.has-practice.has-event {
  background: linear-gradient(135deg, #2563eb 50%, #16a34a 50%);
}
.cal-yr-num {
  font-size: 10px;
  line-height: 1;
}

/* ============================================================
   Custom date range — from/to pickers + filtered list
   ============================================================ */
.cal-range-toolbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 14px;
  background: #f7f8fa;
  border-top: 1px solid var(--border, #d4d7dc);
}
.cal-range-input {
  display: flex;
  align-items: center;
  gap: 8px;
}
.cal-range-input label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  font-weight: 700;
}
.cal-range-input input[type="date"] {
  font: inherit;
  font-size: 14px;
  padding: 6px 10px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 6px;
  background: white;
}
.cal-range-count {
  margin-left: auto;
  font-size: 13px;
  color: var(--text-dim);
  font-weight: 500;
}
.cal-range-list {
  display: flex;
  flex-direction: column;
  background: #fff;
}
.cal-range-row {
  display: grid;
  grid-template-columns: 130px 90px 28px 1fr;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border-soft, #e9ebef);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 140ms ease-out, transform 120ms ease-out;
}
.cal-range-row:hover { background: #f5f6f7; }
.cal-range-row:active { transform: scale(0.99); }
.cal-range-row:last-child { border-bottom: none; }
.cal-range-date { font-weight: 600; font-size: 13px; }
.cal-range-time { font-weight: 700; color: var(--text-dim); font-size: 13px; }
.cal-range-icon { display: flex; align-items: center; justify-content: center; }
.cal-range-text { font-size: 14px; }
.cal-range-row.type-game     .cal-range-icon { color: var(--red, #d4302b); }
.cal-range-row.type-practice .cal-range-icon { color: #2563eb; }
.cal-range-row.type-event    .cal-range-icon { color: #16a34a; }
@media (max-width: 540px) {
  .cal-range-toolbar { flex-wrap: wrap; gap: 10px; }
  .cal-range-row {
    grid-template-columns: 1fr auto;
    grid-template-rows: auto auto;
    gap: 4px 10px;
  }
  .cal-range-date { grid-column: 1; grid-row: 1; }
  .cal-range-time { grid-column: 2; grid-row: 1; text-align: right; }
  .cal-range-icon { grid-column: 1; grid-row: 2; }
  .cal-range-text { grid-column: 2; grid-row: 2; }
}

/* ID selector to beat the generic `.modal select` rule (which sets width:100%
   + padding:10px 12px and would otherwise clip the text vertically and make
   the dropdown stretch across the toolbar). */
#shot-goalie-select {
  padding: 5px 12px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 6px;
  font-size: 13px;
  background: #fff;
  width: auto;
  min-width: 170px;
}

.shot-side-toggle {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2px;
}
.shot-side-toggle .side-btn {
  background: transparent;
  border: none;
  padding: 6px 14px;
  border-radius: 16px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  color: var(--text-dim);
}
.shot-side-toggle .side-btn.active {
  background: var(--blue);
  color: #fff;
}
.shot-counts .them {
  color: var(--text-dim);
}

#shot-player-list.disabled {
  pointer-events: none;
  opacity: .35;
  position: relative;
}
#shot-player-list.disabled::after {
  content: 'Switch to Our Team to pick a shooter';
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--text-dim);
  font-size: 12px;
  padding: 12px;
  text-align: center;
  pointer-events: auto;
}

/* ============================================================
   COLLAPSIBLE LEFT TOOLBAR + RIGHT SIDEBAR
   ============================================================ */
.collapse-btn {
  background: transparent;
  border: 1px solid rgba(255,255,255,.25);
  color: rgba(255,255,255,.85);
  width: 22px; height: 22px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0;
  display: inline-grid;
  place-items: center;
  margin-left: auto;
}
.toolbar-header { display: flex; align-items: center; gap: 8px; }
.toolbar-header .collapse-btn { margin-left: auto; }
.sidebar-tabs { position: relative; }
.sidebar-tabs .collapse-btn.right {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
}
.collapse-btn:hover { background: rgba(255,255,255,.12); color: #fff; }

/* Re-expand strips — narrow vertical bars shown when their panel is collapsed */
.collapse-strip {
  display: none;
  width: 22px;
  background: var(--panel-dark);
  color: #fff;
  border: none;
  cursor: pointer;
  font-size: 18px;
  font-weight: 700;
  padding: 0;
  align-self: stretch;
  border-left: 1px solid #1a1d22;
  border-right: 1px solid #1a1d22;
}
.collapse-strip:hover { background: var(--panel-accent); }

/* When collapsed, the toolbar / sidebar disappear and the strip takes their column. */
body.route-drill .app main { transition: grid-template-columns .15s ease; }
body.tools-collapsed .app main {
  grid-template-columns: 22px minmax(0, 1fr) 300px;
}
body.sidebar-collapsed .app main {
  grid-template-columns: 108px minmax(0, 1fr) 22px;
}
body.tools-collapsed.sidebar-collapsed .app main {
  grid-template-columns: 22px minmax(0, 1fr) 22px;
}
body.tools-collapsed   .toolbar { display: none; }
body.tools-collapsed   .collapse-strip.left  { display: block; }
body.sidebar-collapsed .sidebar { display: none; }
body.sidebar-collapsed .collapse-strip.right { display: block; }

/* Drag-and-drop drill cards from the sidebar onto the rink to load them
   into the current tab. The card is the drag source; the IMG inside is
   non-draggable so the browser doesn't initiate an image-drag instead. */
.drill-card[draggable="true"] { cursor: grab; }
.drill-card[draggable="true"]:active { cursor: grabbing; }
.drill-card .thumb {
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}
.drop-target {
  outline: 3px dashed var(--brand-primary, #2864c8);
  outline-offset: -6px;
  background: rgba(40, 100, 200, 0.06);
}

/* Tablet-range responsive tweak — slightly tightens the side columns.
 * Scoped to MIN-width 769px so it doesn't override the mobile drill
 * layout (the mobile rule lives in the max-width:768px block below and
 * has lower specificity than this one's :not()-chain). Also uses
 * minmax(0, 1fr) so the middle column can shrink below its content's
 * intrinsic min-content size — without this, a wide rink in the
 * canvas-frame would blow the column out past the viewport. */
@media (min-width: 769px) and (max-width: 1100px) {
  body:not(.tools-collapsed):not(.sidebar-collapsed) .app main {
    grid-template-columns: 96px minmax(0, 1fr) 260px;
  }
}

/* ============================================================
   ROTATED RINK (portrait / narrow viewports)
   ============================================================
   When the frame rotates into portrait mode, EVERY child rotates as
   one unit: the rink IMG, the team-logo IMG, and both canvases. If
   the canvases stay landscape while the IMG rotates, the canvas's
   landscape pixel buffer gets squashed into the portrait CSS box,
   producing stretched-looking strokes/stamps AND mismatched
   tap-to-canvas coordinates. width/height are set inline by fitCanvas
   to the pre-rotation (landscape) size for all four; CSS then rotates
   them -90° together so the rendered content keeps its aspect ratio
   and the canvas's design coords stay aligned with the IMG. */
.canvas-frame.rotated > #rink-image,
.canvas-frame.rotated > #rink-team-logo,
.canvas-frame.rotated > #rink,
.canvas-frame.rotated > #drawing {
  inset: auto !important;
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%) rotate(-90deg) !important;
  transform-origin: center center !important;
}

/* ============================================================
   ICON NORMALIZATION — crisper, consistent UI icons
   ============================================================ */
/* Rendering hints applied to all icon SVGs in the chrome. */
.tool svg,
.top-icon-btn svg,
.collapse-btn svg,
.rink-btn svg,
.topnav svg,
.user-menu svg,
.rink-menu svg,
.team-chip svg,
.team-menu svg,
.shot-modal-header svg,
.shot-modal-toolbar svg,
.modal-actions svg,
.plan-card svg,
.drill-card svg,
.player-card svg,
.category-item svg,
.acts svg,
.del svg,
.edit svg,
.rate svg,
.rm svg {
  shape-rendering: geometricPrecision;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Standardise stroke weight on 24x24 line icons so the whole UI reads at one density.
   The line-style preview buttons (.lp-btn) keep their original strokes — they're
   miniature previews of the actual brush widths and need to vary. */
.tool svg[viewBox="0 0 24 24"],
.top-icon-btn svg[viewBox="0 0 24 24"],
.collapse-btn svg[viewBox="0 0 24 24"],
.rink-btn svg[viewBox="0 0 24 24"],
.user-menu svg[viewBox="0 0 24 24"],
.rink-menu svg[viewBox="0 0 24 24"],
.team-chip svg[viewBox="0 0 24 24"],
.team-menu svg[viewBox="0 0 24 24"],
.acts svg[viewBox="0 0 24 24"],
.plan-card svg[viewBox="0 0 24 24"],
.drill-card svg[viewBox="0 0 24 24"],
.player-card svg[viewBox="0 0 24 24"],
.category-item svg[viewBox="0 0 24 24"],
.del svg[viewBox="0 0 24 24"],
.edit svg[viewBox="0 0 24 24"],
.rate svg[viewBox="0 0 24 24"],
.rm svg[viewBox="0 0 24 24"] {
  stroke-width: 2;
}

/* Consistent display sizes */
.tool > svg          { width: 22px; height: 22px; display: block; }
.top-icon-btn > svg  { width: 20px; height: 20px; display: block; }
.collapse-btn svg    { width: 14px; height: 14px; }

/* Crisper text-bearing icons (R/H, V/H goalie stamps + jersey labels) */
.tool text { text-rendering: geometricPrecision; }
.player-label, .player-label .sub { -webkit-font-smoothing: antialiased; }

/* ============================================================
   iOS / TOUCH POLISH
   ============================================================ */
* {
  -webkit-tap-highlight-color: transparent;
}
button,
.tool,
.lp-btn,
.swatch,
.collapse-btn,
.collapse-strip,
.topnav-link,
.team-chip,
.sidebar-tab,
.shot-player,
.mode-btn,
.side-btn {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/* Drawing canvas should not bubble touch as scroll/zoom (we set this already
   for the drill canvas; also apply to overlay canvases used in modals). */
#shot-overlay, #shot-rink, #drawing, #rink {
  touch-action: none;
}

/* On touch-only devices iOS Safari "sticks" :hover after a tap, so a
 * button that briefly highlights stays in its hover background forever.
 * For our style-bar buttons that means a light-grey :hover bg keeps
 * showing even when the .active class never landed — easy to confuse
 * for "I selected this" when really the tap didn't register at all.
 * Disable the hover background entirely on hover-less devices so a tap
 * either flashes-then-clears (no selection) or shows the actual .active
 * red/blue treatment (selection took). */
@media (hover: none) {
  /* CRITICAL: scope to :not(.active) so the .active state's red
   * background isn't clobbered by this rule. Without :not(.active),
   * iPad shows .active buttons as flat-white because sticky :hover
   * + this transparent override wins over .active (same specificity,
   * later source order). */
  .tool:hover:not(.active),
  .lp-btn:hover:not(.active),
  .top-icon-btn:hover,
  .lp-swatches .swatch:hover:not(.active) { background: transparent; transform: none; }
  .tool:hover:not(.active) { border-color: var(--border-soft); }
}

/* iPad + smaller laptops: the bottom style bar (.line-picker) doesn't
 * fit all of style+ending+colour+size+pos-num in one horizontal row on
 * narrower viewports, and iOS users were asking why they had to swipe
 * horizontally to reach a swatch or position-number. Wrap to multiple
 * rows on screens narrower than typical desktop so everything is
 * tap-reachable without scrolling. The bar grows taller; canvas-stage
 * (flex:1 sibling) shrinks to absorb that and the canvas re-fits on
 * next resize via fitCanvas() in rink.js. 1366px breakpoint covers
 * every current iPad in both portrait and landscape. */
@media (max-width: 1366px) {
  .line-picker {
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: 4px;
    column-gap: 8px;
    padding: 4px 8px;
  }
  /* Vertical dividers look out-of-place once wrapping puts groups on
   * different rows — wrap itself separates groups visually. */
  .line-picker-divider { display: none; }
  /* Drop the STYLE / ENDING / COLOR / # / SIZE captions on tighter
   * viewports — the buttons themselves are recognizable enough and
   * the labels were eating ~20-30px per group. */
  .line-picker .lp-label { display: none; }
  .line-picker-group { gap: 4px; }
  /* Compact, squarish lp-btn so each group (line styles / endings /
   * pos-nums) fits its full set on a single sub-row. The internal
   * SVG/img line preview is shrunk to match — these are hint-icons,
   * not measurements. */
  .lp-btn {
    min-width: 32px;
    min-height: 32px;
    padding: 3px;
  }
  .lp-btn svg,
  .lp-btn img {
    width: 24px;
    height: 14px;
  }
  .lp-options { padding: 1px; gap: 1px; }
  /* Position-number badges keep their square aspect but get the
   * same tighter sizing as their lp-btn siblings. */
  .lp-btn.pos-num-btn { min-width: 32px; min-height: 32px; padding: 2px; }
  .lp-btn.pos-num-btn svg { width: 26px; height: 26px; }
  /* Swatches: shrink a touch and tighten the row gap to match. */
  .lp-swatches { gap: 3px; }
  .lp-swatches .swatch { width: 24px; height: 24px; }
}

/* iOS Safari 100vh fix. iOS computes vh from the *largest* viewport
 * (URL bar hidden), so any layout sized to 100vh while the URL bar
 * is visible has its bottom edge below the visible area. On iPad
 * landscape this was hiding the style bar even though the layout
 * thought it was on-screen. `dvh` (dynamic viewport height, iOS
 * 15.4+) updates as the chrome shows/hides, so 100dvh is always
 * what the user can actually see. @supports keeps older iOS on the
 * vh fallback. */
@supports (height: 100dvh) {
  body.route-drill .page-main {
    height: calc(100dvh - 52px - env(safe-area-inset-top));
  }
  body.route-drill:has(.billing-banner) .page-main {
    height: calc(100dvh - 88px - env(safe-area-inset-top));
  }
}

/* iPad: the desktop canvas-stage min-height (100vh - 220px) was sized for
 * a single-row line-picker. With the wrap-to-rows rule above the line-
 * picker is ~140-160px tall instead of ~50px, so the stage min-height
 * shoves the line-picker below the visible viewport. Lower the stage's
 * minimum on tablet-ish widths and use dvh so the calc is accurate to
 * what the user can actually see. Meta tags + notes still live below
 * the line-picker and remain reachable via canvas-wrap's overflow scroll.
 * In anim mode the anim-panel takes another ~140px, so shrink the stage
 * further so the timeline strip stays on-screen. */
@media (max-width: 1366px) {
  body.route-drill .canvas-stage {
    min-height: calc(100vh - 320px);  /* fallback for pre-dvh iOS */
  }
  body.route-drill.anim-active .canvas-stage {
    min-height: calc(100vh - 460px);
  }
}
@supports (height: 100dvh) {
  @media (max-width: 1366px) {
    body.route-drill .canvas-stage {
      min-height: calc(100dvh - 320px);
    }
    body.route-drill.anim-active .canvas-stage {
      min-height: calc(100dvh - 460px);
    }
  }
}

/* Safe-area insets — keep the top nav clear of the iPhone notch */
.topnav {
  padding-top:    env(safe-area-inset-top);
  padding-left:   max(16px, env(safe-area-inset-left));
  padding-right:  max(16px, env(safe-area-inset-right));
  height: calc(52px + env(safe-area-inset-top));
}
body.route-drill .page-main {
  height: calc(100vh - 52px - env(safe-area-inset-top));
}
.page-main {
  padding-bottom: env(safe-area-inset-bottom);
}

/* iOS auto-zooms on focus if input font-size < 16px. Pin to 16px on small screens. */
@media (max-width: 768px) {
  input[type="text"],
  input[type="number"],
  input[type="password"],
  input[type="date"],
  select,
  textarea {
    font-size: 16px !important;
  }
  /* Bigger tap targets on small screens (Apple HIG ≥ 44pt) */
  .tool { min-height: 48px; }
  .lp-btn { min-height: 36px; min-width: 50px; }
  .lp-swatches .swatch { width: 28px; height: 28px; }
  .top-icon-btn { padding: 10px; }
  .top-icon-btn svg { width: 22px; height: 22px; }
}

/* Modals: don't overflow narrow screens */
.modal {
  max-width: 96vw;
  max-height: 90vh;
  overflow: auto;
}

/* Top nav: let links scroll horizontally on narrow viewports instead of wrapping */
.topnav-links {
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.topnav-links::-webkit-scrollbar { display: none; }

/* ---------- Mobile hamburger + nav drawer ---------- */
.nav-hamburger {
  display: none;
  background: transparent;
  border: 0;
  color: #fff;
  padding: 6px;
  cursor: pointer;
  border-radius: 4px;
}
.nav-hamburger:hover { background: rgba(255,255,255,.08); }

.nav-drawer-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  z-index: 89;
}
.nav-drawer {
  display: none;
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(300px, 86vw);
  background: var(--panel-dark);
  color: #fff;
  z-index: 90;
  flex-direction: column;
  padding: 14px 14px max(14px, env(safe-area-inset-bottom));
  box-shadow: -8px 0 28px rgba(0,0,0,.35);
  overflow-y: auto;
}
body.nav-drawer-open .nav-drawer { display: flex; }
body.nav-drawer-open .nav-drawer-backdrop { display: block; }
.nav-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px;
  font-size: 11px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: rgba(255,255,255,.55);
}
.nav-drawer-close {
  background: transparent; border: 0; color: #fff;
  padding: 6px; cursor: pointer; border-radius: 4px;
}
.nav-drawer-close:hover { background: rgba(255,255,255,.08); }
.nav-drawer-links { display: flex; flex-direction: column; gap: 2px; }
.nav-drawer-link {
  display: block;
  padding: 12px 12px;
  border-radius: 6px;
  color: #fff;
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  width: 100%;
}
.nav-drawer-link:hover { background: rgba(255,255,255,.08); }
.nav-drawer-link.active { background: var(--brand-primary); }
.nav-drawer-section {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,.1);
}
.nav-drawer-label {
  font-size: 10px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: rgba(255,255,255,.45);
  margin-bottom: 6px;
}
.nav-drawer-team { font-size: 14px; font-weight: 500; padding: 4px 0; }
.nav-drawer-team-btn {
  display: block; width: 100%; text-align: left;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.1);
  color: #fff;
  padding: 10px 12px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
  margin-top: 4px;
}
.nav-drawer-team-btn:hover { background: rgba(255,255,255,.12); }
.nav-drawer-signout { color: #ff8a85; }

@media (max-width: 768px) {
  .topnav {
    gap: 8px;
    padding-left: max(10px, env(safe-area-inset-left));
    padding-right: max(10px, env(safe-area-inset-right));
  }
  .topnav .brand-text { display: none; }            /* keep the R mark, drop the word */
  .topnav-link { padding: 8px 10px; font-size: 12px; }
  .team-chip .team-name { max-width: 70px; }
  .logout-btn { padding: 6px 8px; font-size: 11px; }
  /* On mobile, swap the inline nav + chip/signout for a hamburger that opens
     the drawer above. Brand stays at the left. */
  .nav-hamburger { display: inline-flex; margin-left: auto; }
  .topnav-links,
  .topnav-right { display: none; }

  /* Mobile drill layout:
     - Toolbar stays visible (no auto-collapse), sized down a touch
     - Sidebar is removed from the grid and becomes a slide-in DRAWER overlay,
       defaults to closed (JS adds `sidebar-collapsed` on init).
     The right strip is the handle to slide it open. */
  body.route-drill .app main { position: relative; }
  /* Wider strip on mobile — 22px is below Apple's 44pt touch target and the
     rotated canvas overlaps it. Bump to 36px and give it a higher z-index
     so no canvas-rotation overflow can steal taps on the handle. */
  body.route-drill .app main,
  body.route-drill.sidebar-collapsed .app main {
    grid-template-columns: 88px minmax(0, 1fr) 36px;
  }
  body.route-drill.tools-collapsed .app main,
  body.route-drill.tools-collapsed.sidebar-collapsed .app main {
    grid-template-columns: 36px minmax(0, 1fr) 36px;
  }
  /* Sidebar = overlay drawer */
  body.route-drill .sidebar {
    position: absolute;
    top: 0; right: 0; bottom: 0;
    width: min(320px, 88vw);
    z-index: 50;
    box-shadow: -8px 0 28px rgba(0,0,0,.18);
    transform: translateX(0);
    transition: transform .25s ease;
    display: flex;          /* override default-flex-when-not-collapsed without touching .show class */
  }
  body.route-drill.sidebar-collapsed .sidebar {
    transform: translateX(100%);
    pointer-events: none;
  }
  /* Right strip is the "DRILLS" handle on mobile — only shown when the
     drawer is CLOSED (sidebar-collapsed). When the drawer is open, the
     drawer itself covers the strip, so we hide it to avoid the visual
     duplication and the dead tappable area behind the drawer.
     Explicit z-index + pointer-events so the rotated canvas (which can
     have overflow visible) can't sit on top of the handle. Stacks a
     vertical "DRILLS" label below the chevron so the handle is
     unmistakable — a bare 22px-wide strip with a `‹` is too easy to
     miss on a phone. */
  body.route-drill.sidebar-collapsed .collapse-strip.right {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    z-index: 51;
    position: relative;
    pointer-events: auto;
    font-size: 20px;
    width: 100%;  /* fill the 36px grid column (override base .collapse-strip { width: 22px }) */
    background: var(--brand-primary, var(--panel-dark));
  }
  body.route-drill:not(.sidebar-collapsed) .collapse-strip.right {
    display: none;
  }
  body.route-drill.sidebar-collapsed .collapse-strip.right::after {
    content: 'DRILLS';
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    letter-spacing: 0.18em;
    font-size: 11px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
  }
  /* Left strip only shows when tools are explicitly collapsed (default = toolbar visible). */
  body.route-drill .collapse-strip.left { display: none; }
  body.route-drill.tools-collapsed .collapse-strip.left {
    display: block;
    z-index: 51;
    position: relative;
    pointer-events: auto;
    font-size: 22px;
    width: 100%;
  }
  body.route-drill.tools-collapsed .toolbar { display: none; }

  /* Tighter toolbar widths on mobile so the rink gets more room */
  .toolbar-header { padding: 6px 8px; font-size: 11px; }
  .tool-grid { padding: 3px; gap: 2px; }
  .tool { min-height: 40px; }     /* still tappable; HIG says ≥44pt but our buttons are dense */

  /* Backdrop behind the open drawer — tap outside the sidebar to close it. */
  body.route-drill:not(.sidebar-collapsed) .canvas-wrap::after {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(0,0,0,.18);
    z-index: 40;
    pointer-events: auto;
  }

  /* Plans/Evals/Roster/Games/Team pages: shrink the inner page padding */
  .page { padding: 16px 12px 40px; }
  .page-header { gap: 10px; }
  .page-header h1 { font-size: 18px; }

  /* Mobile drill page: let the page scroll vertically so the rink can take a
     bigger slice and the style bar / tags / notes flow underneath. */
  html, body { overflow-y: auto; }
  body.route-drill { height: auto; min-height: 100%; }
  body.route-drill .app { height: auto; min-height: 100vh; overflow-x: hidden; overflow-y: visible; }
  /* The desktop drill layout caps .page-main to the viewport height (so the
     rink fits in one screen). On mobile we explicitly opt out — the content
     is taller than the viewport, and the user scrolls. */
  body.route-drill .page-main { height: auto; min-height: calc(100vh - 52px - env(safe-area-inset-top)); }
  body.route-drill .app main {
    overflow: visible;
    /* Give the rink ~85% of the viewport height so the style bar / meta / notes
       sit below the fold and scroll into view. */
    min-height: calc(100vh - 130px);
  }
  body.route-drill .canvas-wrap { overflow: visible; padding-bottom: 12px; }
  body.route-drill .canvas-stage { min-height: calc(100vh - 200px); }
  body.route-drill .toolbar { max-height: calc(100vh - 130px); overflow-y: auto; }
  /* On mobile the canvas needs full gesture control — pan-y was letting
     every vertical drawing motion become a page scroll, so users couldn't
     draw vertical lines or down-swiping strokes. The page is still
     scrollable: just touch the topbar, tab strip, style bar, notes, or
     drill sidebar above/below the canvas to scroll. */
  #drawing, #rink { touch-action: none; }
}

/* The very narrow phone / portrait orientation: stack the topbar on the drill page
   so it doesn't crowd out the rink. */
@media (max-width: 540px) {
  .topbar-center .drill-name { width: 100%; }
  .topbar-left { flex-shrink: 0; }
  .topbar { gap: 4px; padding: 6px 8px; }
}

/* ===================== AI result blocks (plan / suggest drills) ===================== */
.ai-result {
  margin: 12px 0;
  padding: 12px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: #fafbfc;
  max-height: 50vh;
  overflow-y: auto;
  font-size: 13px;
}
.ai-result .ai-plan-name { font-size: 15px; margin-bottom: 4px; }
.ai-result .ai-plan-summary { font-style: italic; color: var(--text-dim); margin: 4px 0 8px; }
.ai-result ol.ai-plan-drills { margin: 8px 0 0 18px; padding: 0; }
.ai-result ol.ai-plan-drills > li { margin-bottom: 10px; }
.ai-result ul { margin: 4px 0 0 18px; color: var(--text-dim); font-size: 12px; }

/* ===================== Team profile page ===================== */
.page-team .page-header-actions { display: flex; gap: 8px; }
.page-team .field {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--text-dim);
}
.page-team .field > span { font-weight: 500; }
.page-team .field input[type="text"],
.page-team .field input[type="email"],
.page-team .field input[type="tel"],
.page-team .field input[type="url"],
.page-team .field textarea {
  width: 100%; padding: 8px 10px;
  border: 1px solid var(--border-soft); border-radius: 6px;
  font-size: 14px; color: var(--text); background: #fff;
  font-family: inherit;
}
.page-team .field input:focus,
.page-team .field textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.page-team .field-wide { grid-column: 1 / -1; }

/* ── Create-team wizard modal (global — opened from the team switcher) ── */
.create-team-modal { width: 560px; max-width: 94vw; max-height: 90vh; overflow-y: auto; }
.create-team-modal h3 { margin: 0 0 2px; }
.create-team-modal .modal-sub { margin: 0 0 16px; font: 400 13px/1.5 Geist, system-ui, sans-serif; color: var(--text-dim); }
.create-team-modal .field { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--text-dim); margin-bottom: 12px; }
.create-team-modal .field > span { font-weight: 600; }
.create-team-modal .field input,
.create-team-modal .field select {
  width: 100%; padding: 9px 11px; border: 1px solid var(--border-soft, #e3e6ea); border-radius: 8px;
  font: 400 14px/1.3 Geist, system-ui, sans-serif; color: var(--text); background: #fff;
}
.create-team-modal .field input:focus,
.create-team-modal .field select:focus { outline: 2px solid var(--brand-primary, #d4302b); outline-offset: -1px; border-color: transparent; }
.create-team-modal .ct-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 14px; }
.create-team-modal .ct-wide { grid-column: 1 / -1; }
@media (max-width: 560px) { .create-team-modal .ct-grid { grid-template-columns: 1fr; } }

.profile-grid {
  display: grid; grid-template-columns: 200px 1fr; gap: 24px; align-items: start;
}
.profile-logo-block { display: flex; flex-direction: column; gap: 8px; }
.logo-preview {
  width: 180px; height: 180px;
  border-radius: 12px;
  border: 1px dashed var(--border-soft);
  background: var(--bg-soft) center/contain no-repeat;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-dim); font-size: 13px;
}
.logo-placeholder { opacity: 0.6; }
.logo-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.logo-actions .btn { cursor: pointer; }
.profile-logo-block .hint { font-size: 11px; color: var(--text-dim); }

.field-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.field-grid .color-row {
  display: flex; gap: 8px; align-items: center;
}
.field-grid .color-row input[type="color"] {
  width: 44px; height: 36px; padding: 2px; border: 1px solid var(--border-soft); border-radius: 6px; background: #fff;
}
.field-grid .color-row input[type="text"] { flex: 1; font-family: ui-monospace, Menlo, monospace; text-transform: uppercase; }

.social-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.coach-list { display: flex; flex-direction: column; gap: 12px; }
.coach-row {
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 12px;
  background: #fcfcfd;
  display: flex; flex-direction: column; gap: 10px;
}
.coach-row-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.coach-row-actions { display: flex; justify-content: flex-end; }

.btn.btn-ghost {
  background: transparent; border-color: var(--border-soft); color: var(--text-dim);
}

.ai-key-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ai-key-row input {
  flex: 1; min-width: 220px;
  padding: 8px 10px;
  border: 1px solid var(--border-soft); border-radius: 6px;
  font-family: ui-monospace, Menlo, monospace; font-size: 13px;
}

code.invite-code {
  font-family: ui-monospace, Menlo, monospace;
  padding: 4px 10px; background: var(--bg-soft); border-radius: 4px;
  font-size: 13px; letter-spacing: 1px;
}

@media (max-width: 768px) {
  .profile-grid { grid-template-columns: 1fr; }
  .logo-preview { width: 160px; height: 160px; }
  .field-grid, .social-grid, .coach-row-grid { grid-template-columns: 1fr; }
}

/* ============ Associations pages ============ */
.page-associations .join-association { margin-bottom: 18px; }
.page-associations .join-form { display: flex; gap: 8px; }
.page-associations .join-form input {
  flex: 1; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: ui-monospace, Menlo, monospace; font-size: 13px; letter-spacing: .5px;
  text-transform: uppercase;
}
.assoc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.assoc-card {
  display: block;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 10px;
  padding: 16px 18px;
  text-decoration: none;
  color: inherit;
  transition: transform .12s, box-shadow .12s, border-color .12s;
}
.assoc-card:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0,0,0,.08); border-color: #aab0b8; }
.assoc-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.assoc-card-head h3 { margin: 0; font-size: 16px; }
.assoc-card-meta { font-size: 13px; color: #5b6068; }
.empty-state { padding: 24px 0; color: #5b6068; font-size: 14px; }

.chip {
  display: inline-block;
  font-size: 11px; font-weight: 600;
  padding: 2px 8px; border-radius: 100px;
  background: #e7e9ec; color: #5b6068;
  text-transform: uppercase; letter-spacing: .5px;
}
.chip-admin { background: var(--red, #d4302b); color: #fff; }
.chip-owner { background: #ffb43a; color: #2c3036; }

/* ============ Association detail page ============ */
.page-association .assoc-header { align-items: center; gap: 16px; }
.assoc-header-main { display: flex; align-items: center; gap: 14px; }
.assoc-logo {
  width: 56px; height: 56px; border-radius: 8px;
  background: #2c3036 center/cover no-repeat;
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 22px;
}
.tabs {
  display: flex; gap: 4px;
  border-bottom: 1px solid var(--border, #d4d7dc);
  margin: 14px 0 18px;
}
.tabs .tab {
  background: transparent; border: none; padding: 10px 14px;
  font-size: 14px; font-weight: 500; color: #5b6068;
  border-bottom: 2px solid transparent;
  cursor: pointer;
}
.tabs .tab:hover { color: #111; }
.tabs .tab.active { color: var(--red, #d4302b); border-bottom-color: var(--red, #d4302b); }
.tab-panel[hidden] { display: none; }
.panel-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.panel-toolbar .sub { font-size: 12.5px; color: #777; }
.team-row, .member-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 8px;
  margin-bottom: 8px;
}
.team-row-name, .member-row-name { font-weight: 600; font-size: 14px; }
.team-row-link {
  color: #111;
  text-decoration: none;
  cursor: pointer;
}
.team-row-link:hover { color: var(--red, #d4302b); text-decoration: underline; }
.team-row-meta, .member-row-meta { font-size: 12.5px; color: #5b6068; margin-top: 2px; }
.team-row-actions, .member-row-actions { display: flex; align-items: center; gap: 8px; }
.role-select { padding: 4px 6px; border-radius: 4px; border: 1px solid var(--border); font-size: 12.5px; }
.btn-sm { padding: 4px 10px; font-size: 12px; }
.invite-block { display: inline-flex; align-items: center; gap: 8px; padding: 6px 10px; background: #f5f6f7; border-radius: 6px; }
.invite-block .lbl { font-size: 12px; color: #5b6068; text-transform: uppercase; letter-spacing: .3px; }
.invite-block code { font-family: ui-monospace, Menlo, monospace; font-size: 13px; letter-spacing: .8px; }

/* Attach-team modal */
.attach-mode-tabs { display: flex; gap: 2px; background: #f0f2f4; padding: 2px; border-radius: 6px; margin: 10px 0; }
.mode-tab {
  flex: 1; padding: 7px 10px; border: none; background: transparent;
  border-radius: 4px; font-size: 12.5px; font-weight: 500; cursor: pointer; color: #5b6068;
}
.mode-tab.active { background: #fff; color: #111; box-shadow: 0 1px 2px rgba(0,0,0,.08); }

.danger-card { margin-top: 18px; border-left: 4px solid var(--red, #d4302b); }
.btn-danger { background: var(--red, #d4302b); color: #fff; border: none; }
.btn-danger:hover { background: #b8281f; }

.full-row { display: block; }
.full-row textarea { width: 100%; padding: 10px 12px; border: 1px solid var(--border); border-radius: 4px; font-family: inherit; font-size: 13px; }

/* Member title inline editor on Team page */
.title-input {
  width: 100%;
  padding: 5px 8px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 4px;
  font-size: 13px;
  background: #fff;
}
.title-input:focus {
  border-color: var(--red, #d4302b);
  outline: none;
}

/* ============ Schedule page (was Games) ============ */
.schedule-type-tabs {
  display: flex; gap: 2px;
  background: #eef0f3;
  padding: 2px;
  border-radius: 6px;
}
.schedule-type-tabs .type-tab {
  padding: 6px 12px;
  border: none;
  background: transparent;
  border-radius: 4px;
  font-size: 12.5px;
  font-weight: 500;
  color: #5b6068;
  cursor: pointer;
}
.schedule-type-tabs .type-tab:hover { color: #111; }
.schedule-type-tabs .type-tab.active {
  background: #fff;
  color: #111;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
}

/* Type radios inside the schedule entry modal */
.entry-type-row { display: flex; gap: 6px; margin-bottom: 14px; }
.entry-type-opt {
  flex: 1;
  display: flex; align-items: center; gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 6px;
  font-size: 13px; font-weight: 500;
  cursor: pointer;
  background: #fff;
}
.entry-type-opt:has(input:checked) {
  border-color: var(--red, #d4302b);
  background: #fff7f6;
  color: #111;
}
.entry-type-opt input { margin: 0; }

/* ============ Drill sharing ============ */
.inbox-link,
.account-link {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  margin-right: 6px;
  border-radius: 6px;
  color: inherit; text-decoration: none;
  transition: background 0.12s;
}
.inbox-link:hover,
.account-link:hover { background: rgba(255,255,255,0.10); }
.inbox-badge {
  position: absolute; top: 2px; right: 2px;
  min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--red, #d4302b); color: #fff;
  border-radius: 100px;
  font-size: 10px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
}
.inbox-badge[hidden] { display: none !important; }

.drill-card .acts .share,
.drill-card .acts .offline {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 4px; border: none; background: transparent; cursor: pointer;
  color: #5b6068; border-radius: 4px;
}
.drill-card .acts .share:hover,
.drill-card .acts .offline:hover { background: rgba(0,0,0,0.06); color: #111; }
/* Pinned-for-offline state — filled cloud-check icon in the brand color
 * so it's distinct from the outlined "unpinned" default. */
.drill-card .acts .offline.offline--active { color: var(--brand-primary, #16a34a); }
.drill-card .acts .offline.offline--active:hover { color: var(--brand-primary, #16a34a); background: rgba(22,163,74,0.10); }

/* Legacy selectors kept for compatibility outside share modal; share
   modal overrides below scope to .share-modal and ID #share-modal. */
.share-tabs {
  display: flex; gap: 2px;
  background: #eef0f3; padding: 2px;
  border-radius: 6px;
  margin-bottom: 12px;
}
.share-tab {
  flex: 1; padding: 7px 10px; border: none; background: transparent;
  border-radius: 4px; font-size: 12.5px; font-weight: 500; cursor: pointer; color: #5b6068;
}
.share-tab.active { background: #fff; color: #111; box-shadow: 0 1px 2px rgba(0,0,0,0.06); }
.share-link-row { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
.share-link-row input {
  flex: 1;
  padding: 9px 12px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 6px;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 12px;
}

/* ============================================================
   Share modal — premium pass.
   Polished tabs, refined inputs, brand-gradient CTA, dialogue
   chrome that matches the rest of Coachly.
   ============================================================ */
.share-modal {
  padding: 0 !important;
  border-radius: 18px;
  overflow: hidden;
}
.share-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 22px 24px 18px;
  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
  background: linear-gradient(180deg, rgba(108, 92, 231, 0.04), transparent);
}
.share-modal-head-main {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.share-modal-icon {
  width: 38px; height: 38px;
  border-radius: 11px;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  box-shadow: 0 4px 12px rgba(108, 92, 231, 0.28);
  flex-shrink: 0;
}
.share-modal-icon svg { width: 18px; height: 18px; }
.share-modal h3#share-modal-title {
  margin: 0 0 2px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text, #0f172a);
  line-height: 1.25;
}
.share-modal-sub {
  font-size: 12.5px;
  color: rgba(15, 23, 42, 0.55);
  line-height: 1.4;
}
.share-modal-x {
  width: 32px; height: 32px;
  border: 0;
  background: rgba(15, 23, 42, 0.04);
  color: rgba(15, 23, 42, 0.55);
  border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 150ms, color 150ms;
  flex-shrink: 0;
}
.share-modal-x:hover { background: rgba(15, 23, 42, 0.08); color: var(--text, #0f172a); }
.share-modal-x svg { width: 14px; height: 14px; }

/* Tab strip — refined segmented pill, brand-tinted active state. */
#share-modal .share-tabs {
  display: flex;
  gap: 2px;
  margin: 16px 24px 0;
  padding: 4px;
  background: rgba(15, 23, 42, 0.04);
  border-radius: 11px;
  border: 1px solid rgba(15, 23, 42, 0.04);
}
#share-modal .share-tab {
  flex: 1;
  padding: 9px 12px;
  border: 0;
  background: transparent;
  border-radius: 8px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.6);
  cursor: pointer;
  transition: background 150ms, color 150ms, box-shadow 150ms;
}
#share-modal .share-tab:hover { color: var(--text, #0f172a); }
#share-modal .share-tab.active {
  background: #fff;
  color: var(--text, #0f172a);
  box-shadow:
    0 1px 0 rgba(108, 92, 231, 0.06) inset,
    0 1px 3px rgba(15, 23, 42, 0.08),
    0 0 0 1px rgba(108, 92, 231, 0.12);
}

/* Pane container — consistent padding around content */
#share-modal .share-pane {
  padding: 18px 24px 22px;
}
.share-pane-hint {
  margin: 0 0 14px;
  font-size: 13px;
  color: rgba(15, 23, 42, 0.6);
  line-height: 1.5;
}
.share-field-label {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(15, 23, 42, 0.5);
  margin: 14px 0 6px;
}
.share-field-label:first-child { margin-top: 0; }
.share-field-optional {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: rgba(15, 23, 42, 0.35);
  margin-left: 4px;
  text-transform: none;
}

/* Inputs / textarea / select — softer, brand focus ring. */
#share-modal input[type="text"],
#share-modal input[type="email"],
#share-modal textarea,
#share-modal select {
  width: 100%;
  padding: 11px 14px;
  font: inherit;
  font-size: 13.5px;
  border: 1px solid rgba(15, 23, 42, 0.10);
  border-radius: 10px;
  background: #fafbff;
  color: var(--text, #0f172a);
  transition: border-color 150ms, box-shadow 150ms, background 150ms;
  outline: 0;
  box-sizing: border-box;
}
#share-modal input[type="text"]:focus,
#share-modal input[type="email"]:focus,
#share-modal textarea:focus,
#share-modal select:focus {
  border-color: #6c5ce7;
  background: #fff;
  box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.14);
}
#share-modal textarea { resize: vertical; min-height: 60px; }

/* Action row + primary CTA — Coachly gradient with shimmer hover */
.share-pane-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 18px;
}
.share-cta-btn {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 20px;
  border: 0;
  border-radius: 11px;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.25) inset,
    0 6px 18px -4px rgba(108, 92, 231, 0.42),
    0 2px 6px rgba(108, 92, 231, 0.18);
  transition: transform 160ms cubic-bezier(.3, .9, .4, 1.1),
              box-shadow 160ms cubic-bezier(.3, .9, .4, 1.1);
  overflow: hidden;
  isolation: isolate;
}
.share-cta-btn::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(120deg, transparent 35%, rgba(255,255,255,0.28) 50%, transparent 65%);
  transform: translateX(-120%);
  transition: transform 580ms cubic-bezier(.3, .9, .4, 1.1);
  pointer-events: none;
  z-index: -1;
}
.share-cta-btn:hover {
  transform: translateY(-1px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.35) inset,
    0 10px 24px -6px rgba(108, 92, 231, 0.52),
    0 3px 8px rgba(108, 92, 231, 0.22);
}
.share-cta-btn:hover::before { transform: translateX(120%); }
.share-cta-btn:active { transform: translateY(0); }
.share-cta-btn:disabled { opacity: 0.55; cursor: progress; filter: saturate(0.55); }
.share-cta-btn:focus-visible {
  outline: 3px solid rgba(108, 92, 231, 0.4);
  outline-offset: 2px;
}
.share-cta-btn svg { width: 15px; height: 15px; }

/* My-teams list — brand-tinted hover replaces the red */
#share-modal .push-to-teams-list { max-height: 320px; overflow-y: auto; }
#share-modal .push-team-row {
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 13.5px;
  margin-bottom: 6px;
  background: #fff;
}
#share-modal .push-team-row:hover {
  background: rgba(108, 92, 231, 0.05);
  border-color: rgba(108, 92, 231, 0.30);
}
#share-modal .push-team-row input[type="checkbox"] {
  width: 16px; height: 16px;
  accent-color: #6c5ce7;
}

/* Link tab — URL row + Copy/Regen */
#share-modal .share-link-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
  margin-top: 8px;
}
#share-modal .share-link-row input {
  flex: 1;
  padding: 11px 14px;
  border: 1px solid rgba(15, 23, 42, 0.10);
  border-radius: 10px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  background: #fafbff;
  color: rgba(15, 23, 42, 0.85);
}
#share-modal .share-link-row input:focus { border-color: #6c5ce7; background: #fff; }
.share-link-copy-btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 0 16px;
  border: 0;
  border-radius: 10px;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 4px 12px -2px rgba(108, 92, 231, 0.35);
  transition: transform 150ms, box-shadow 150ms, filter 150ms;
}
.share-link-copy-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 16px -3px rgba(108, 92, 231, 0.45); }
.share-link-copy-btn svg { width: 14px; height: 14px; }
.share-link-copy-btn--copied { filter: saturate(0.8) brightness(1.05); }

#share-modal .share-link-regen {
  width: 42px;
  padding: 0;
  border: 1px solid rgba(15, 23, 42, 0.10);
  background: #fafbff;
  color: rgba(15, 23, 42, 0.55);
  border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 150ms, color 150ms, transform 200ms;
  flex-shrink: 0;
}
#share-modal .share-link-regen svg { width: 14px; height: 14px; }
#share-modal .share-link-regen:hover {
  background: #fff;
  color: #6c5ce7;
  transform: rotate(45deg);
}

/* Expiry segmented picker */
#share-modal .share-link-expiry {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 12px;
}
#share-modal .share-link-expiry-label {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(15, 23, 42, 0.5);
}
#share-modal .share-link-expiry-segs {
  display: inline-flex;
  background: rgba(15, 23, 42, 0.05);
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
}
#share-modal .share-link-expiry-seg {
  border: 0; background: transparent;
  padding: 6px 12px;
  border-radius: 999px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.6);
  cursor: pointer;
  transition: background 150ms, color 150ms, box-shadow 150ms;
}
#share-modal .share-link-expiry-seg:hover { color: var(--text, #0f172a); }
#share-modal .share-link-expiry-seg[aria-pressed="true"] {
  background: #fff;
  color: var(--text, #0f172a);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.10);
}

/* Stats panel (link tab) */
#share-modal .share-link-stats {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid rgba(15, 23, 42, 0.06);
}
#share-modal .share-link-stats-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
}
#share-modal .share-link-stat {
  background: rgba(15, 23, 42, 0.03);
  border: 1px solid rgba(15, 23, 42, 0.04);
  border-radius: 12px;
  padding: 12px 14px;
  text-align: center;
}
#share-modal .share-link-stat:first-child {
  background: linear-gradient(135deg, rgba(108, 92, 231, 0.08), rgba(0, 206, 201, 0.08));
  border-color: rgba(108, 92, 231, 0.18);
}
#share-modal .share-link-stat-num {
  display: block;
  font-size: 22px;
  font-weight: 800;
  color: var(--text, #0f172a);
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
#share-modal .share-link-stat:first-child .share-link-stat-num {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
#share-modal .share-link-stat-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(15, 23, 42, 0.5);
  margin-top: 4px;
  display: inline-block;
}
#share-modal .share-link-stat-expiry .share-link-stat-num { font-size: 17px; }

@media (max-width: 600px) {
  .share-modal { width: 96vw !important; }
  .share-modal-head { padding: 18px 18px 14px; }
  #share-modal .share-tabs { margin: 14px 18px 0; }
  #share-modal .share-pane { padding: 16px 18px 20px; }
  #share-modal .share-link-stats-row { grid-template-columns: 1fr; }
  #share-modal .share-link-expiry { flex-wrap: wrap; }
}

/* Inbox rows (used in both topnav modal and /inbox page) */
.inbox-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 8px;
  margin-bottom: 8px;
}
.inbox-thumb {
  width: 64px; height: 64px;
  border-radius: 4px;
  background: #f5f6f7;
  object-fit: cover;
  flex: 0 0 auto;
}
.inbox-main { flex: 1; min-width: 0; }
.inbox-name { font-weight: 600; font-size: 14px; color: #111; }
.inbox-meta { font-size: 12.5px; color: #5b6068; margin-top: 2px; }
.inbox-message { font-size: 13px; color: #2c3036; margin-top: 4px; font-style: italic; }
.inbox-actions { display: flex; gap: 6px; flex-direction: column; }
.inbox-actions .btn { padding: 5px 10px; font-size: 12.5px; }

.inbox-status-tabs { display: flex; gap: 2px; background: #eef0f3; padding: 2px; border-radius: 6px; }
.inbox-status-tabs .status-tab {
  padding: 6px 12px; border: none; background: transparent;
  border-radius: 4px; font-size: 12.5px; font-weight: 500; color: #5b6068; cursor: pointer;
}
.inbox-status-tabs .status-tab.active { background: #fff; color: #111; box-shadow: 0 1px 2px rgba(0,0,0,0.06); }

.share-card .share-card-grid {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 18px;
}
.share-thumb {
  width: 100%; aspect-ratio: 1.5 / 1;
  background: #f5f6f7;
  border-radius: 6px;
  object-fit: cover;
}
.share-meta h2 { margin: 0 0 6px 0; }
.share-meta-row { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.share-description { font-size: 13px; color: #2c3036; }
.share-owner { margin-top: 10px; }

/* ============ Attendance modal (schedule entry) ============ */
.attendance-bulk-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 8px 0 12px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border-soft, #eef0f3);
}
.attendance-table .att-status {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 4px;
  font-size: 12.5px;
  background: #fff;
}
.attendance-table .att-row.status-going     { background: rgba(34,197,94,.08); }
.attendance-table .att-row.status-maybe     { background: rgba(255,180,58,.10); }
.attendance-table .att-row.status-not_going { background: rgba(212,48,43,.08); }
.attendance-table .att-row.status-attended  { background: rgba(40,100,200,.07); }
.attendance-table .att-row.status-absent    { background: rgba(212,48,43,.12); }

/* ============ Bulk-setup AI modal ============ */
.bulk-modal { width: 560px; max-width: 92vw; }
.bulk-label {
  display: block;
  font-size: 12px; font-weight: 600;
  color: var(--text-dim, #5b6068);
  text-transform: uppercase; letter-spacing: .5px;
  margin-bottom: 6px;
}
#bulk-text {
  width: 100%;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 6px;
  padding: 10px 12px;
  font-family: inherit; font-size: 13px;
  resize: vertical; min-height: 110px;
}
.bulk-csv-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bulk-csv-row .sub { font-size: 12.5px; color: #5b6068; }

.bulk-loading { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 28px 12px; text-align: center; }
.bulk-loading .busy-spinner { width: 38px; height: 38px; }

.bulk-review-list { display: flex; flex-direction: column; gap: 6px; max-height: 380px; overflow-y: auto; padding: 2px; }
.bulk-review-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  background: #f5f6f7;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.bulk-review-row.selected { background: #fff; border-color: var(--red, #d4302b); }
.bulk-review-row input[type="checkbox"] { flex: 0 0 auto; }
.bulk-review-main { flex: 1; min-width: 0; }
.bulk-review-name { font-weight: 600; font-size: 14px; color: #111; }
.bulk-review-meta { display: flex; gap: 12px; flex-wrap: wrap; font-size: 12.5px; color: #5b6068; margin-top: 2px; }

/* Photo-import settings popover (model toggle). */
.import-photo-group { position: relative; display: inline-flex; align-items: center; gap: 2px; }
.import-photo-settings svg { width: 14px; height: 14px; }
.import-photo-settings { padding: 4px 5px !important; }
.import-photo-menu {
  /* Fixed so the menu escapes the topbar's overflow-x (which implicitly clips
     the Y axis). JS sets top/left based on the gear button's viewport rect. */
  position: fixed;
  top: 0; left: 0;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,.18);
  padding: 10px 12px;
  min-width: 280px;
  z-index: 1500;
  font-size: 13px;
  color: #2c3036;
}
.import-photo-menu[hidden] { display: none; }
.import-photo-menu-title { font-weight: 600; font-size: 12px; color: #555; letter-spacing: .3px; text-transform: uppercase; margin-bottom: 6px; }
.import-photo-menu-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 4px;
  cursor: pointer;
}
.import-photo-menu-row:hover { background: #f5f6f7; border-radius: 4px; }
.import-photo-menu-row input[type="radio"] { margin: 0; }
.import-photo-menu-row .muted { color: #888; font-size: 11.5px; margin-left: auto; }
.import-photo-menu-hint { font-size: 11.5px; color: #777; margin-top: 6px; line-height: 1.3; }

/* Full-viewport busy overlay (used by the photo-import flow; reusable for
   any long-running operation that needs to block the canvas). */
/* Busy overlay — Emil polish: opacity-based show/hide so we can transition
   the entry/exit. Card scales from 0.96 + opacity 0 so it materializes
   instead of popping. Spinner is 0.7s — a hair faster than the previous
   0.9s, which makes loading feel snappier.
   iPad fix (2026-05-30): added `visibility: hidden` so iOS Safari truly
   skips hit-testing on the overlay when it's not visible. Without this,
   backdrop-filter creates a stacking context that intercepts ALL touches
   in the viewport — including the style bar at the bottom of the drill
   board — even with pointer-events: none. The `transition: visibility
   0s linear 200ms` delay keeps the element rendered through the fade-out. */
.busy-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 22, 26, 0.5);
  z-index: 2000;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 200ms ease-out,
    visibility 0s linear 200ms;
}
.busy-overlay.show {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  /* Only apply the backdrop-filter when actually visible — on iOS Safari
     a transparent backdrop-filter STILL captures input even with
     visibility: hidden, so we conditionally enable it via .show. */
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  /* Override the visibility-delay transition so it shows instantly. */
  transition: opacity 200ms ease-out;
}
.busy-overlay .busy-card {
  background: #fff;
  padding: 28px 36px;
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  max-width: 340px;
  text-align: center;
  transform: scale(0.96);
  opacity: 0;
  transition:
    transform 260ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity 220ms ease-out;
}
.busy-overlay.show .busy-card {
  transform: scale(1);
  opacity: 1;
}
.busy-overlay .busy-spinner {
  width: 44px;
  height: 44px;
  border: 4px solid #e7e9ec;
  border-top-color: #d4302b;
  border-radius: 50%;
  animation: busy-spin 0.7s linear infinite;
}
@keyframes busy-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .busy-overlay,
  .busy-overlay .busy-card {
    transition: opacity 180ms ease-out;
    transform: none;
  }
  .busy-overlay.show .busy-card { transform: none; }
}

/* ============================================================
   AUTO LIST-LOADING SPINNERS
   ============================================================
   These content containers start empty in the server-rendered HTML
   and get populated by JS once api.me() returns. To avoid showing a
   blank area during that gap (~300-500ms typical, longer on first
   load via the Cloudflare tunnel), we use the :empty pseudo-class
   to render a spinner inside any of these containers automatically
   — and it disappears the moment JS inserts any child node.

   No JS changes needed. Add a container's id/class here if it
   suffers the same "blank during boot" symptom.
   ============================================================ */
#drill-list:empty::before,
#plan-list:empty::before,
#plan-grid:empty::before,
#game-list:empty::before,
#drill-picker:empty::before,
#inbox-list:empty::before {
  content: '';
  display: block;
  width: 28px;
  height: 28px;
  margin: 36px auto 8px;
  border: 3px solid #e7e9ec;
  border-top-color: var(--brand-primary, #d4302b);
  border-radius: 50%;
  animation: busy-spin 0.9s linear infinite;
}
#drill-list:empty::after,
#plan-list:empty::after,
#plan-grid:empty::after,
#game-list:empty::after,
#drill-picker:empty::after,
#inbox-list:empty::after {
  content: 'Loading…';
  display: block;
  text-align: center;
  font-size: 12px;
  color: var(--text-dim);
  letter-spacing: 0.3px;
  margin-bottom: 24px;
}
.busy-overlay .busy-message {
  font-size: 15px;
  font-weight: 600;
  color: #2c3036;
  letter-spacing: 0.2px;
}
.busy-overlay .busy-submessage {
  font-size: 13px;
  color: #5b6068;
  line-height: 1.4;
}

/* Drill tabs strip — lives in row 1 of the canvas column (grid placement
   handled in the main rule). Light theme so tabs read like a browser tab bar. */
.drill-tabs {
  display: flex;
  align-items: stretch;
  gap: 2px;
  padding: 0 4px;
  background: #e7e9ec;
  border-bottom: 1px solid #c9ccd1;
  min-height: 34px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}
.drill-tab-list {
  display: flex;
  align-items: stretch;
  gap: 2px;
  flex: 0 0 auto;
}
.drill-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px 0 12px;
  background: #d4d7dc;
  color: #3a3f46;
  border-radius: 6px 6px 0 0;
  font-size: 12.5px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  height: 30px;
  margin-top: 4px;
  border: 1px solid transparent;
  border-bottom: none;
  max-width: 200px;
  user-select: none;
}
.drill-tab:hover { background: #c8ccd1; }
.drill-tab.active {
  background: #ffffff;
  color: #111;
  border-color: #c9ccd1;
}
.drill-tab-name {
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 160px;
}
.drill-tab-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  padding: 0;
  margin-right: -4px;
  border: none;
  background: transparent;
  border-radius: 50%;
  color: inherit;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}
.drill-tab-close:hover {
  background: rgba(0,0,0,0.1);
  opacity: 1;
}
.drill-tab-add {
  align-self: center;
  width: 26px; height: 26px;
  margin-left: 6px;
  border: none;
  background: transparent;
  color: #555a62;
  font-size: 18px;
  line-height: 1;
  border-radius: 4px;
  cursor: pointer;
}
.drill-tab-add:hover { background: #d4d7dc; color: #111; }

/* Custom hover tooltip (see tooltip.js) */
.pc-tooltip {
  position: fixed;
  top: 0; left: 0;
  pointer-events: none;
  background: rgba(24, 26, 32, 0.96);
  color: #fff;
  padding: 5px 9px;
  border-radius: 5px;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
  max-width: 280px;
  box-shadow: 0 4px 14px rgba(0,0,0,0.18);
  letter-spacing: 0.2px;
  z-index: 10000;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 110ms ease, transform 110ms ease;
}
.pc-tooltip.show {
  opacity: 1;
  transform: translateY(0);
}

/* ============================================================
   MODERN UI REFRESH
   Token additions + surgical overrides for the highest-traffic
   shared surfaces (buttons, modals, inputs, cards, login, page
   header, tables, menus). Doesn't touch the drill-page toolbar,
   the schedule calendar, or other surfaces that already feel
   right — those stay untouched.
   ============================================================ */

:root {
  /* Radii */
  --r-xs:   3px;
  --r-sm:   4px;
  --r:      6px;
  --r-md:   8px;
  --r-lg:   12px;
  --r-pill: 999px;
  /* Layered shadows (low-opacity for a modern flat-with-depth feel). */
  --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 1px rgba(15, 23, 42, 0.03);
  --shadow-sm: 0 4px 12px -2px rgba(15, 23, 42, 0.06), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
  --shadow:    0 10px 25px -5px rgba(15, 23, 42, 0.10), 0 4px 8px -4px rgba(15, 23, 42, 0.06);
  --shadow-lg: 0 24px 48px -12px rgba(15, 23, 42, 0.18), 0 8px 16px -8px rgba(15, 23, 42, 0.10);
  /* Standard focus ring — soft blue halo, accessible AA contrast. */
  --ring: 0 0 0 3px rgba(40, 100, 200, 0.22);
  --ring-danger: 0 0 0 3px rgba(212, 48, 43, 0.22);
  /* Motion */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --t-fast: 120ms;
  --t: 180ms;
}

/* Typography polish — subtle, system-wide. */
/* Headlines use Instrument Sans for a slight display contrast against the
 * Geist body font. Same fallback chain so we degrade gracefully if Google
 * Fonts is slow. Letter-spacing is tightened slightly on display text. */
h1, h2, h3, h4 {
  font-family: 'Instrument Sans', 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;
  letter-spacing: -0.015em;
}
.page-header h1 { font-size: 24px; font-weight: 700; }
.page-header .sub { font-size: 13px; color: var(--text-dim); margin-top: 4px; }

/* Buttons — softer corners, subtle shadow on primary, smooth transitions,
   accessible focus rings. */
.btn {
  border-radius: var(--r);
  font-weight: 500;
  transition: background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
  box-shadow: var(--shadow-xs);
}
.btn:focus-visible { outline: none; box-shadow: var(--shadow-xs), var(--ring); }
.btn:active { transform: translateY(0.5px); }
.btn-primary {
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.btn-primary:focus-visible { box-shadow: 0 1px 0 rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.10), var(--ring); }
.btn-danger:focus-visible { box-shadow: 0 1px 0 rgba(0,0,0,0.08), var(--ring-danger); }

/* Inputs — consistent radii, soft focus ring instead of just a colour swap. */
.modal input, .modal select, .modal textarea,
.field input, .field select, .field textarea,
.login-form input,
.topbar input[type="text"], .topbar select {
  border-radius: var(--r);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.modal input:focus, .modal select:focus, .modal textarea:focus,
.field input:focus, .field select:focus, .field textarea:focus,
.login-form input:focus,
.topbar input[type="text"]:focus, .topbar select:focus {
  border-color: var(--brand-secondary);
  box-shadow: var(--ring);
  outline: none;
}

/* Cards — cleaner border + layered shadow. */
.card {
  border-radius: var(--r-md);
  border-color: var(--border-soft);
  box-shadow: var(--shadow-xs);
  padding: 20px;
  margin-bottom: 16px;
  transition: box-shadow var(--t) var(--ease);
}
.card h2 { font-size: 16px; font-weight: 600; letter-spacing: -0.005em; }
.card .card-head { margin-bottom: 12px; }

/* Modals — softer shadow + slightly rounder corners + better breathing room. */
.modal {
  border-radius: var(--r-lg);
  padding: 28px;
  box-shadow: var(--shadow-lg);
}
.modal h3 { font-size: 19px; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 16px 0; }
.modal-actions { margin-top: 24px; gap: 10px; }
/* Soft fade on the backdrop. */
.modal-bg {
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

/* Tables — quieter zebra-free hover, slightly larger row padding. */
table.data-table th, table.data-table td { padding: 11px 12px; }
table.data-table th { font-size: 10.5px; letter-spacing: 0.6px; }
table.data-table tr:hover td { background: rgba(40, 100, 200, 0.03); }

/* Empty states — bigger but quieter, more deliberate hierarchy. */
.empty, .empty-state {
  padding: 72px 24px;
}
.empty .icon, .empty-state .icon {
  font-size: 40px;
  opacity: 0.5;
  margin-bottom: 12px;
  line-height: 1;
}
.empty, .empty-state { font-size: 14px; line-height: 1.5; }

/* Login screen — softer, brand-tinted dark backdrop instead of a hard
   diagonal gradient. Modern card with reduced shadow. */
.login-screen {
  background:
    radial-gradient(800px circle at 15% 10%, rgba(212, 48, 43, 0.18), transparent 55%),
    radial-gradient(700px circle at 85% 90%, rgba(40, 100, 200, 0.16), transparent 55%),
    #15171c;
}
.login-card {
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: 36px 36px 32px;
}
.login-card h1 { font-size: 24px; font-weight: 700; letter-spacing: -0.015em; }
.login-card .logo .mark {
  box-shadow: 0 6px 16px -6px rgba(212, 48, 43, 0.45);
}

/* Topnav links — quieter inactive state, tighter spacing. */
.topnav-link {
  border-radius: var(--r);
  transition: background var(--t-fast), color var(--t-fast);
}

/* User chip — slightly tighter, with a modern focus ring. */
.user-chip { transition: background var(--t-fast); }
.user-chip:focus-visible { outline: none; box-shadow: var(--ring); }

/* Toast — float a touch more, smoother corners. */
.toast {
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
  font-weight: 500;
  letter-spacing: 0.1px;
}

/* Drill folders / sidebar items — subtle hover, tighter corners. */
.drill-card { transition: background var(--t-fast), box-shadow var(--t-fast); }
.drill-card:hover { box-shadow: var(--shadow-xs); }

/* Generic dropdown menu shadow softening (rink menu, import menu, etc.). */
.rink-menu, .import-photo-menu, .line-ctx-menu {
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
}

/* Result badges (W / L / OTL) — neater pill shape if you happen to use them. */
.result-w, .result-l, .result-otl, .result-t {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.result-w  { background: rgba(31, 158, 90, 0.12);  color: #157a45; }
.result-l  { background: rgba(212, 48, 43, 0.12);  color: var(--red); }
.result-otl,
.result-t  { background: rgba(40, 100, 200, 0.12); color: var(--blue); }

/* Small inline SVG icons used in JS-rendered cells (schedule type, attendance).
   Keeps stroke crisp + matches body text color so they don't shout. */
.icon-inline {
  display: inline-block;
  width: 18px; height: 18px;
  vertical-align: -3px;
  color: var(--text);
}
.icon-inline.dim { color: var(--text-dim); }

/* Size adjustments for the inline SVG icons in different contexts. */
.btn .icon-inline,
.icon-btn .icon-inline { width: 15px; height: 15px; vertical-align: -2px; }
.cal-entry .icon-inline { width: 13px; height: 13px; vertical-align: -1px; }
table.data-table .icon-inline { vertical-align: -4px; }

/* ============================================================
   Goal-details modal extras (strength, shot type, goalie target)
   ============================================================ */
.strength-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-top: 4px;
}
.strength-opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: var(--r, 6px);
  background: #fff;
  font-size: 12px;
  cursor: pointer;
  user-select: none;
  text-transform: none !important;
  letter-spacing: 0 !important;
  color: var(--text);
}
.strength-opt:hover { background: var(--bg-soft, #f5f6f7); }
.strength-opt input[type="radio"] { margin: 0; }
.strength-opt:has(input:checked) {
  background: rgba(40, 100, 200, 0.10);
  border-color: var(--brand-secondary, #2864c8);
  color: var(--brand-secondary, #2864c8);
}

.goal-net-header {
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.goal-net-target {
  position: relative;
  margin-top: 6px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: var(--r-md, 8px);
  background: #fff;
  cursor: crosshair;
  overflow: hidden;
  line-height: 0;
}
.goal-net-target #goal-net-image {
  display: block;
  width: 100%;
  height: auto;
  background: #fff;
  user-select: none;
  -webkit-user-drag: none;
}
.goal-net-grid {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}
.goal-net-grid line {
  stroke: rgba(255, 255, 255, 0.55);
  stroke-width: 0.5;
  stroke-dasharray: 2 2;
}
.goal-net-marker {
  position: absolute;
  display: none;            /* hidden until JS adds `.placed` */
  width: 28px;
  height: 28px;
  margin-left: -14px;
  margin-top: -14px;
  background: #111;
  border: 3px solid #fff;
  border-radius: 50%;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.45);
  pointer-events: none;     /* clicks pass through to the image */
  z-index: 2;
}
.goal-net-marker.placed { display: block; }
.goal-net-zone-label {
  margin-top: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  min-height: 18px;
}
.goal-net-zone-label:empty::before {
  content: "Click the net to mark a zone";
  color: var(--text-dim);
  font-weight: 400;
  font-style: italic;
}
.goal-net-clear {
  position: absolute;
  top: 6px; right: 6px;
  font-size: 11px;
  padding: 3px 8px;
  border: 1px solid var(--border, #d4d7dc);
  background: #fff;
  border-radius: var(--r, 6px);
  cursor: pointer;
  font-weight: 500;
  line-height: 1.2;
}
.goal-net-clear:hover { background: var(--bg-soft, #f5f6f7); }

/* ============================================================
   Game Center modal (Schedule → Game Center)
   ============================================================ */
.gc-topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px 24px;
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 2;
}
.gc-topbar h3 { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
#game-center-body { padding: 24px; }

/* Header */
.gc-header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: 20px 24px;
  border-radius: var(--r-lg, 12px);
  background:
    linear-gradient(to right, color-mix(in srgb, var(--brand-primary) 8%, transparent), transparent 35%, transparent 65%, color-mix(in srgb, var(--brand-secondary) 8%, transparent));
  border: 1px solid var(--border-soft, #e6e8eb);
  margin-bottom: 24px;
}
.gc-team-name {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.005em;
}
.gc-team-left  { text-align: left; }
.gc-team-right { text-align: right; }
.gc-score-block { text-align: center; }
.gc-score-line {
  display: inline-flex;
  align-items: baseline;
  gap: 16px;
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
}
.gc-score-dash {
  font-size: 24px;
  font-weight: 400;
  color: var(--text-dim);
  position: relative;
  top: -4px;
}
.gc-meta {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-dim);
  letter-spacing: 0.2px;
}

/* Sections */
.gc-section { margin-bottom: 28px; }
.gc-section-title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-dim);
  margin: 0 0 12px 0;
}
.gc-empty {
  padding: 16px;
  background: var(--bg-soft, #f5f6f7);
  border-radius: var(--r-md, 8px);
  color: var(--text-dim);
  font-size: 13px;
}

/* Scoring Summary */
.gc-period { margin-bottom: 12px; }
.gc-period-title {
  font-size: 13px;
  font-weight: 700;
  margin: 0 0 8px 0;
}
.gc-goal-row {
  display: grid;
  grid-template-columns: 60px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 16px;
  margin-bottom: 8px;
  background: #fff;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-left: 4px solid var(--accent, var(--red));
  border-radius: var(--r-md, 8px);
  box-shadow: var(--shadow-xs, none);
}
.gc-goal-time { font-weight: 600; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.gc-goal-title { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; font-weight: 600; }
.gc-scorer { font-weight: 700; }
.gc-shot-type { color: var(--text-dim); font-weight: 500; font-size: 12px; }
.gc-assists { font-size: 12px; color: var(--text-dim); margin-top: 2px; }
.gc-goal-score {
  font-weight: 700;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  min-width: 50px;
  text-align: right;
}
.gc-strength {
  display: inline-block;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  border-radius: var(--r-pill, 999px);
  background: var(--bg-soft);
  color: var(--text-dim);
}
.gc-strength-pp { background: rgba(40, 100, 200, 0.14); color: var(--blue); }
.gc-strength-sh { background: rgba(212, 48, 43, 0.14); color: var(--red); }
.gc-strength-en { background: rgba(31, 158, 90, 0.14); color: var(--green); }

/* Team Stats */
.gc-stats-head {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  align-items: center;
  margin-bottom: 12px;
}
.gc-stats-team {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.005em;
}
.gc-stats-team-left { text-align: left; }
.gc-stats-team-right { text-align: right; }
.gc-stat-row {
  display: grid;
  grid-template-columns: 60px 1fr 60px;
  align-items: center;
  padding: 8px 0 4px;
}
.gc-stat-num {
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.gc-stat-num-left { text-align: left; }
.gc-stat-num-right { text-align: right; }
.gc-stat-label {
  text-align: center;
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.6px;
  color: var(--text-dim);
  font-weight: 600;
}
.gc-bar-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 0 0 10px;
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
  margin-bottom: 4px;
}
.gc-bar {
  height: 4px;
  border-radius: var(--r-pill, 999px);
}
.gc-bar-left  { background: var(--brand-primary, var(--red));   margin-left: auto; }
.gc-bar-right { background: var(--brand-secondary, var(--blue)); margin-right: auto; }

@media (max-width: 640px) {
  .gc-header { grid-template-columns: 1fr; gap: 8px; text-align: center; }
  .gc-team-left, .gc-team-right { text-align: center; }
  .gc-goal-row { grid-template-columns: 50px 1fr auto; gap: 8px; }
}

/* Game Center — Player Stats section */
.gc-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.gc-section-head .gc-section-title { margin: 0; }
.gc-player-table { font-size: 13px; }
.gc-player-table .gc-dim { color: var(--text-dim); }
.gc-stats-hint {
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-dim);
}

/* ============================================================
   Game Center — rich header, logos, highlights row
   ============================================================ */
.gc-header-rich {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: 24px;
  border-radius: var(--r-lg, 12px);
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--brand-primary) 14%, transparent), transparent 50%),
    linear-gradient(225deg, color-mix(in srgb, var(--brand-secondary) 14%, transparent), transparent 50%),
    #fff;
  border: 1px solid var(--border-soft, #e6e8eb);
  margin-bottom: 12px;
}
.gc-side { display: flex; align-items: center; gap: 16px; }
.gc-side-us  { justify-content: flex-start; }
.gc-side-opp { justify-content: flex-end; }
.gc-side-info { flex: 1; min-width: 0; }
.gc-side-opp .gc-side-info { text-align: right; }
.gc-side-name {
  font-size: 18px; font-weight: 700; letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gc-side-sub {
  margin-top: 2px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.gc-side-score {
  font-size: 52px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 1;
  min-width: 64px;
  text-align: center;
}
.gc-side-score-us  { color: var(--brand-primary, var(--red)); }
.gc-side-score-opp { color: var(--brand-secondary, var(--blue)); }

.gc-logo {
  width: 56px; height: 56px;
  object-fit: contain;
  border-radius: var(--r-md, 8px);
  background: #fff;
  padding: 2px;
  box-shadow: var(--shadow-xs, 0 1px 2px rgba(0,0,0,.06));
}
.gc-logo-placeholder {
  display: grid; place-items: center;
  color: #fff;
  font-weight: 800;
  font-size: 22px;
  letter-spacing: -0.01em;
}
.gc-logo-us  { background: var(--brand-primary,   var(--red)); }
.gc-logo-opp { background: var(--brand-secondary, var(--blue)); }

.gc-divider {
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.gc-divider-status {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-dim);
}
.gc-divider-date {
  font-size: 12px;
  color: var(--text);
}

/* Highlights row — sits right under the header, compact key stats per team. */
.gc-highlights {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 24px;
}
.gc-highlight {
  padding: 10px 16px;
  border-radius: var(--r-md, 8px);
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  display: flex;
  gap: 6px;
  align-items: center;
}
.gc-highlight-us  { background: color-mix(in srgb, var(--brand-primary)   12%, #fff); text-align: left;  }
.gc-highlight-opp { background: color-mix(in srgb, var(--brand-secondary) 12%, #fff); text-align: right; justify-content: flex-end; }
.gc-highlight-num { font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.gc-highlight-us  .gc-highlight-num { color: var(--brand-primary, var(--red)); }
.gc-highlight-opp .gc-highlight-num { color: var(--brand-secondary, var(--blue)); }
.gc-highlight-sep { color: var(--text-dim); margin: 0 4px; }

/* Mini logo (24px) — used on scoring rows + team-stats header. */
.gc-mini-logo {
  width: 24px; height: 24px;
  flex: 0 0 auto;
  object-fit: contain;
  border-radius: var(--r-sm, 4px);
  background: #fff;
}
.gc-mini-logo-placeholder {
  display: grid; place-items: center;
  color: #fff;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: -0.01em;
}
.gc-mini-us  { background: var(--brand-primary,   var(--red)); }
.gc-mini-opp { background: var(--brand-secondary, var(--blue)); }

/* Scoring rows — add a badge column and tint the background subtly per team. */
.gc-goal-row {
  display: grid;
  grid-template-columns: 56px 28px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 14px;
  margin-bottom: 8px;
  background: #fff;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-left: 4px solid var(--brand-primary, var(--red));
  border-radius: var(--r-md, 8px);
  box-shadow: var(--shadow-xs, none);
}
.gc-goal-us  { border-left-color: var(--brand-primary,   var(--red));  background: linear-gradient(90deg, color-mix(in srgb, var(--brand-primary)   5%, #fff), #fff 50%); }
.gc-goal-opp { border-left-color: var(--brand-secondary, var(--blue)); background: linear-gradient(90deg, color-mix(in srgb, var(--brand-secondary) 5%, #fff), #fff 50%); }

/* Team stats header — team labels with logos flanking the comparison. */
.gc-stats-team { display: flex; align-items: center; gap: 8px; }
.gc-stats-team-left  { justify-content: flex-start; }
.gc-stats-team-right { justify-content: flex-end; }

/* Mobile — let the header stack cleanly. */
@media (max-width: 700px) {
  .gc-header-rich { grid-template-columns: 1fr; }
  .gc-side, .gc-side-opp { flex-wrap: wrap; }
  .gc-side-score { font-size: 40px; }
  .gc-highlights { grid-template-columns: 1fr; }
  .gc-highlight-opp { text-align: left; justify-content: flex-start; }
}

/* Team-menu — association grouping with collapsible headers. */
.team-menu-group {
  border-top: 1px solid var(--border-soft, rgba(255,255,255,.06));
  margin-top: 4px;
  padding-top: 4px;
}
.team-menu-group:first-of-type { border-top: none; margin-top: 0; padding-top: 0; }
.team-menu-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-dim, #6b7280);
  cursor: pointer;
  user-select: none;
}
.team-menu-group-head:hover { background: rgba(255,255,255,.04); }
.team-menu-group-head .chev { transition: transform .15s var(--ease, ease); }
.team-menu-group.collapsed .chev { transform: rotate(-90deg); }
.team-menu-group-count {
  margin-left: auto;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.team-menu-group-body {
  overflow: hidden;
  max-height: 999px;
  transition: max-height .2s var(--ease, ease);
}
.team-menu-group.collapsed .team-menu-group-body { max-height: 0; }
.team-menu-group-body .item { padding-left: 28px; }

/* ============================================================
   Practice plan clipboards
   Each plan-card is styled to look like a coach's wall clipboard:
   team-color frame, metal clip at the top, line-ruled drill list.
   ============================================================ */
#plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 44px 24px;
  align-items: stretch;
  padding-top: 38px; /* leave room for the clip + lever bump that pokes above the card */
  overflow: visible;
}

/* Override the generic .card look just for plan-cards. */
.plan-card {
  position: relative;
  background: #fff;
  border: 5px solid var(--brand-primary, var(--red));
  border-radius: 6px;
  padding: 22px 18px 16px;
  margin: 0;
  box-shadow: 0 6px 16px -8px rgba(0,0,0,.18), 0 2px 4px -2px rgba(0,0,0,.08);
  display: flex; flex-direction: column;
  min-height: 320px;
  transition: transform var(--t-fast, 120ms) var(--ease, ease), box-shadow var(--t, 180ms) var(--ease, ease);
}
.plan-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -10px rgba(0,0,0,.22), 0 4px 10px -4px rgba(0,0,0,.10);
}

/* The metal clip at the top of the clipboard. */
.plan-card::before {
  content: "";
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  width: 78px;
  height: 24px;
  border-radius: 4px 4px 3px 3px;
  background:
    linear-gradient(180deg, #f4f5f7 0%, #cdd2d8 38%, #a9aeb6 70%, #c4c9d0 100%);
  border: 1px solid #8b9099;
  box-shadow: 0 2px 4px rgba(0,0,0,.15);
}
/* Tiny lever bump on top of the clip. */
.plan-card::after {
  content: "";
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  width: 26px;
  height: 10px;
  border-radius: 2px 2px 1px 1px;
  background: linear-gradient(180deg, #e8eaed 0%, #b7bcc4 100%);
  border: 1px solid #8b9099;
  border-bottom: none;
}

/* Header inside the clipboard: plan name + actions. Header text is centered
   to match how a real clipboard label sits at the top. Icons float to the
   right corner via absolute positioning so they don't push the title off
   center. */
.plan-card .card-head {
  position: relative;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--brand-primary, var(--red));
  display: block;        /* drop the flex layout from .card .card-head */
  text-align: center;
}
.plan-card-head-info { padding: 0 56px; }   /* leave room for the two icons */
.plan-card h2 {
  font-size: 17px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--brand-primary, var(--red));
  line-height: 1.2;
  margin: 0;
}
.plan-card .card-head .sub {
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-dim);
  font-weight: 500;
  letter-spacing: 0.3px;
}
.plan-card-head-actions {
  position: absolute;
  top: 0;
  right: 0;
  display: flex;
  gap: 2px;
}
.btn-icon {
  background: transparent;
  border: none;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm, 4px);
  color: var(--text-dim);
  cursor: pointer;
  padding: 0;
  transition: background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease);
}
.btn-icon:hover { background: color-mix(in srgb, var(--brand-primary, var(--red)) 8%, transparent); color: var(--text); }
.btn-icon.del:hover { background: color-mix(in srgb, var(--red) 10%, transparent); color: var(--red); }
.btn-icon .icon-inline { width: 16px; height: 16px; }

/* Body: drill list as ruled lines. */
.plan-card .plan-body {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.plan-card .plan-drill {
  display: grid;
  grid-template-columns: 26px 1fr auto auto;
  gap: 8px;
  align-items: center;
  padding: 7px 2px;
  font-size: 13px;
  border-bottom: 1px dashed color-mix(in srgb, var(--brand-primary, var(--red)) 22%, transparent);
}
.plan-card .plan-drill:last-of-type { border-bottom: 1px dashed color-mix(in srgb, var(--brand-primary, var(--red)) 22%, transparent); }
.plan-card .plan-drill .idx {
  width: 22px; height: 22px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand-primary, var(--red));
  color: #fff;
  font-weight: 700;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.plan-card .plan-drill .nm { font-weight: 600; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plan-card .plan-drill .mins {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  padding: 2px 6px;
  border-radius: var(--r-pill, 999px);
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 8%, transparent);
}
.plan-card .plan-drill .rm {
  background: transparent;
  border: none;
  padding: 4px;
  color: var(--text-dim);
  cursor: pointer;
  border-radius: var(--r-sm, 4px);
}
.plan-card .plan-drill .rm:hover { background: color-mix(in srgb, var(--red) 10%, transparent); color: var(--red); }

/* Footer actions inside the clipboard, pushed to the bottom. */
.plan-card .plan-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 14px;
}
.plan-card .plan-actions .btn {
  padding: 6px 10px;
  font-size: 12px;
  flex: 1;
}
.plan-card .plan-actions .btn-primary {
  flex: 1.5;
  background: var(--brand-primary, var(--red));
  border-color: var(--brand-primary, var(--red));
  /* Force white on text + icon — the old ▶ glyph rendered as a colored emoji
     against the red, which read as "black text on red". */
  color: #fff !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.plan-card .plan-actions .btn-primary .icon-inline { color: #fff; width: 13px; height: 13px; }

@media (max-width: 600px) {
  #plan-list { grid-template-columns: 1fr; gap: 32px; }
  .plan-card { min-height: 0; }
}

/* ============================================================
   Practice Plans — inline editor + tab strip
   ============================================================ */
/* Plan tabs follow the same Chrome-style design as the drill page's
   .drill-tab tabs — grey when inactive, white when active, top-rounded so
   they appear to sit on the page below. Sits inside the dark edit-bar. */
.plan-tab-strip {
  display: flex;
  align-items: stretch;
  gap: 2px;
  flex: 0 0 auto;
}
.plan-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px 0 12px;
  background: #d4d7dc;
  color: #3a3f46;
  border-radius: 6px 6px 0 0;
  font-size: 12.5px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  height: 30px;
  margin-top: 4px;
  border: 1px solid transparent;
  border-bottom: none;
  max-width: 200px;
  user-select: none;
}
.plan-tab:hover { background: #c8ccd1; }
.plan-tab.active {
  background: #ffffff;
  color: #111;
  border-color: #c9ccd1;
}
.plan-tab-name {
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 160px;
}
.plan-tab-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  padding: 0;
  margin-right: -4px;
  border: none;
  background: transparent;
  border-radius: 50%;
  color: inherit;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}
.plan-tab-close:hover {
  background: rgba(0,0,0,0.1);
  opacity: 1;
}

/* Inline editor surface. Matches the page width and uses team color for the
   active accents but doesn't try to LOOK like a clipboard — the clipboard
   metaphor stays in the list grid. */
.plan-editor {
  background: #fff;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-top: 4px solid var(--brand-primary, var(--red));
  border-radius: var(--r-md, 8px);
  padding: 22px 24px;
  margin-bottom: 24px;
  box-shadow: var(--shadow-sm);
}
.plan-editor-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 200px 180px;
  gap: 12px;
  margin-bottom: 14px;
}
.plan-editor-book {
  font-size: 13px !important;
  color: var(--text-dim);
  border: 1px solid var(--border) !important;
  border-radius: var(--r, 6px) !important;
  padding: 6px 10px !important;
}
.plan-editor-book:focus { color: var(--text); }
.plan-editor-name {
  font-size: 22px !important;
  font-weight: 700 !important;
  border: none !important;
  border-bottom: 2px solid transparent !important;
  border-radius: 0 !important;
  padding: 4px 0 !important;
  background: transparent !important;
  letter-spacing: -0.01em;
}
.plan-editor-name:focus { border-bottom-color: var(--brand-primary, var(--red)) !important; outline: none !important; box-shadow: none !important; }
.plan-editor-date {
  font-size: 13px !important;
  text-align: right;
  color: var(--text-dim);
  border: 1px solid var(--border) !important;
  border-radius: var(--r, 6px) !important;
  padding: 6px 10px !important;
}
.plan-editor-notes-label,
.plan-editor-drill-head h3 {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-dim);
  margin: 0 0 6px 0;
}
.plan-editor-notes {
  width: 100%;
  border: 1px solid var(--border, #d8dce1);
  border-radius: var(--r, 6px);
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  min-height: 70px;
  margin-bottom: 0;
  resize: vertical;
}

/* Notes block — collapsed by default to save vertical space; click the
   header row to expand. The header shows a chevron, the "Notes" label, and
   a short preview of the existing notes (or placeholder if empty). */
.plan-editor-notes-block { margin: 4px 0 18px; }
.plan-editor-notes-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}
.plan-editor-notes-chev {
  width: 14px; height: 14px;
  color: var(--text-dim);
  flex-shrink: 0;
  transition: transform var(--t-fast, 120ms) var(--ease, ease);
}
.plan-editor-notes-block:not(.is-collapsed) .plan-editor-notes-chev { transform: rotate(90deg); }
.plan-editor-notes-toggle .plan-editor-notes-label { margin: 0; }
.plan-editor-notes-preview {
  flex: 1;
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 400;
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  letter-spacing: 0;
  text-transform: none;
}
.plan-editor-notes-preview.is-empty::before {
  content: 'Add notes for this plan…';
  opacity: 0.6;
}
.plan-editor-notes-block .plan-editor-notes { margin-top: 6px; }
.plan-editor-notes-block.is-collapsed .plan-editor-notes { display: none; }
.plan-editor-drill-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}
.plan-editor-drill-head h3 { margin-right: 4px; }
.plan-editor-summary {
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 500;
  margin-left: auto;
}

/* Toggle next to the Drills heading — collapses or expands every drill block
   in the active plan in one click. */
.plan-editor-collapse-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px 4px 8px;
  background: transparent;
  border: 1px solid var(--border, #d8dce1);
  border-radius: var(--r-pill, 999px);
  color: var(--text-dim);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  cursor: pointer;
  transition: background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
}
.plan-editor-collapse-all svg {
  width: 14px;
  height: 14px;
  transition: transform var(--t-fast, 120ms) var(--ease, ease);
}
.plan-editor-collapse-all[data-state="collapsed"] svg { transform: rotate(180deg); }
.plan-editor-collapse-all:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 8%, transparent);
  border-color: var(--brand-primary, var(--red));
  color: var(--brand-primary, var(--red));
}
.plan-editor-collapse-all:focus-visible {
  outline: 2px solid var(--brand-primary, var(--red));
  outline-offset: 2px;
}
.plan-editor-drill-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}
/* Legacy single-row layout (kept around in case any older view references it).
   Real drill rows now use .ped-block below. */
.ped-row {
  display: grid;
  grid-template-columns: 32px 250px minmax(0, 1fr) auto auto;
  gap: 14px;
  align-items: center;
  padding: 10px 12px;
  background: var(--bg-soft, #f5f6f7);
  border-radius: var(--r, 6px);
  border: 1px solid transparent;
  transition: border-color var(--t-fast) var(--ease);
}
.ped-row:hover { border-color: var(--border, #d8dce1); }

/* New drill block — heading bar at the top (drag handle + title + actions),
   collapsible body below (thumb + description). Background uses the team's
   secondary brand color at low opacity so each block reads as its own card. */
.ped-block {
  border-radius: var(--r-md, 8px);
  border: 1px solid color-mix(in srgb, var(--brand-secondary, #2864c8) 18%, var(--border-soft, #e6e8eb));
  background: color-mix(in srgb, var(--brand-secondary, #2864c8) 7%, #fff);
  overflow: hidden;
  transition: box-shadow var(--t-fast, 120ms) var(--ease, ease), opacity var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
}
.ped-block + .ped-block { margin-top: 8px; }
.ped-block.is-dragging { opacity: 0.45; }
.ped-block.drop-above  { box-shadow: 0 -3px 0 0 var(--brand-primary, var(--red)); }
.ped-block.drop-below  { box-shadow:  0  3px 0 0 var(--brand-primary, var(--red)); }

.ped-block-head {
  display: grid;
  grid-template-columns: 28px 32px minmax(0, 1fr) auto auto auto auto;
  gap: 10px;
  align-items: center;
  padding: 8px 12px;
  /* Primary brand color so each drill block reads as a distinct, branded
     section. Index badge, title, and icons go white. */
  background: var(--brand-primary, var(--red));
  color: #fff;
  border-bottom: 1px solid color-mix(in srgb, #000 18%, var(--brand-primary, var(--red)));
  cursor: grab;
  user-select: none;
}
.ped-block-head:active { cursor: grabbing; }
.ped-block.is-collapsed .ped-block-head { border-bottom-color: transparent; }
/* Index badge sits inside the heading now — flip it to white-on-transparent
   so it reads on the dark primary background. */
.ped-block-head .ped-idx {
  background: rgba(255,255,255,0.18);
  color: #fff;
}

.ped-drag-handle {
  display: inline-grid; place-items: center;
  width: 22px; height: 22px;
  color: rgba(255,255,255,0.75);
  cursor: grab;
}
.ped-drag-handle svg { width: 18px; height: 18px; }
.ped-drag-handle:hover { color: #fff; }
.ped-block-head:active .ped-drag-handle { cursor: grabbing; }

.ped-block-title {
  font-weight: 700;
  font-size: 14px;
  color: #fff;
  letter-spacing: 0.2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Collapse chevron — points up by default, rotates when collapsed. */
.ped-block-collapse {
  width: 28px; height: 28px;
  display: inline-grid; place-items: center;
  padding: 0; margin: 0;
  background: transparent;
  border: 0;
  border-radius: var(--r-sm, 4px);
  color: rgba(255,255,255,0.8);
  cursor: pointer;
  transition: background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease);
}
.ped-block-collapse svg { width: 16px; height: 16px; transition: transform var(--t-fast, 120ms) var(--ease, ease); }
.ped-block.is-collapsed .ped-block-collapse svg { transform: rotate(180deg); }
.ped-block-collapse:hover { background: rgba(255,255,255,0.14); color: #fff; }

/* Generic icon button for expand/remove in the heading. */
.ped-block-icon {
  width: 28px; height: 28px;
  display: inline-grid; place-items: center;
  padding: 0; margin: 0;
  background: transparent;
  border: 0;
  border-radius: var(--r-sm, 4px);
  color: rgba(255,255,255,0.8);
  cursor: pointer;
  transition: background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease);
}
.ped-block-icon svg { width: 15px; height: 15px; }
.ped-block-icon:hover { background: rgba(255,255,255,0.14); color: #fff; }
.ped-block-icon-danger:hover { background: rgba(255,255,255,0.22); color: #fff; }

/* The plan-number badge label inside the dark heading needs no extra tint. */
.ped-mins {
  /* When a drill row's mins pill sits in the dark heading, flip its colors so
     it pops on the brand-color background instead of disappearing into it. */
}
.ped-block-head .ped-mins {
  background: rgba(255,255,255,0.22);
  color: #fff;
}

/* Body: thumb + description side by side. Collapsible.
   Thumb takes ~55% of the body width; description gets the rest. */
.ped-block-body {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 14px;
  align-items: start;
  padding: 12px;
}
.ped-block.is-collapsed .ped-block-body { display: none; }
/* No-thumb drills (quick-add stubs) collapse to a single column so the notes
   sit flush with the left edge of the body — no empty thumbnail gutter. */
.ped-block.no-thumb .ped-block-body { grid-template-columns: 1fr; }
.ped-block-body .ped-thumb,
.ped-block-body .ped-thumb-btn { background: transparent; }
.ped-block-body .ped-info {
  padding-top: 4px;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.ped-desc-empty { font-style: italic; opacity: 0.7; }

@media (max-width: 720px) {
  .ped-block-body { grid-template-columns: 1fr; }
}

/* Responsive thumb — fills its grid column. Aspect-ratio matches the old
   250×150 box (5:3) so the rink letterboxes the same as before regardless of
   how wide the editor canvas is. */
.ped-block-body .ped-thumb,
.ped-block-body .ped-thumb-btn,
.ped-block-body .ped-thumb-placeholder {
  width: 100%;
  height: auto;
  aspect-ratio: 5 / 3;
  max-width: none;
}
.ped-block-body .ped-thumb { object-fit: contain; }

/* Description preserves rich-text formatting from the drill notes editor
   (lists, bold, inline icons). Capped to the thumb's rendered height via JS;
   a fade mask + Read more button reveal the rest when it overflows. */
.ped-desc {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  overflow: hidden;
  position: relative;
}
.ped-desc p { margin: 0 0 6px; }
.ped-desc p:last-child { margin-bottom: 0; }
.ped-desc ul,
.ped-desc ol { margin: 4px 0 6px; padding-left: 22px; }
.ped-desc ul { list-style: disc outside; }
.ped-desc ol { list-style: decimal outside; }
.ped-desc li { margin: 1px 0; }
.ped-desc li::marker { color: var(--text-dim); }
.ped-desc h1,
.ped-desc h2,
.ped-desc h3 { font-size: 14px; font-weight: 700; margin: 6px 0 4px; }
.ped-desc img.inline-icon {
  height: 1.1em;
  width: auto;
  vertical-align: -2px;
  margin: 0 2px;
}
/* Fade-out at the bottom when truncated (but not when expanded). */
.ped-desc.is-overflow:not(.is-expanded) {
  -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
}

.ped-read-more {
  align-self: flex-start;
  margin-top: 4px;
  background: transparent;
  border: 0;
  padding: 3px 0;
  font-size: 12px;
  font-weight: 700;
  color: var(--brand-primary, var(--red));
  cursor: pointer;
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease);
}
.ped-read-more:hover { border-bottom-color: currentColor; }
.ped-read-more[hidden] { display: none; }
.ped-idx {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--brand-primary, var(--red));
  color: #fff;
  font-weight: 700;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.ped-thumb {
  width: 250px; height: 150px;
  /* `contain` so the entire rink shows — no cropping. Transparent letterbox
     blends with whatever the row's background is. */
  object-fit: contain;
  border-radius: var(--r-sm, 4px);
  background: transparent;
  border: 0;
}
.ped-thumb-placeholder { display: block; }
.ped-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0; /* let text truncate inside grid 1fr column */
}
.ped-name {
  font-weight: 700;
  font-size: 15px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
}
.ped-desc {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ped-mins {
  font-size: 11px; font-weight: 700;
  padding: 2px 7px;
  border-radius: var(--r-pill, 999px);
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 10%, transparent);
  color: var(--brand-primary, var(--red));
}
.ped-actions { display: inline-flex; gap: 2px; }
.ped-btn {
  width: 24px; height: 24px;
  border: 1px solid var(--border, #d8dce1);
  background: #fff;
  cursor: pointer;
  border-radius: var(--r-sm, 4px);
  font-size: 10px;
  color: var(--text-dim);
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
.ped-btn:hover:not([disabled]) { color: var(--text); border-color: var(--text-dim); }
.ped-btn[disabled] { opacity: 0.4; cursor: not-allowed; }
.ped-rm:hover { color: var(--red); border-color: var(--red); }

.plan-editor-add-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 6px 0 18px;
}
/* Outlined "card" style add button — icon on the left, title + subtitle stacked
   on the right. Primary variant uses the team's brand color for emphasis. */
.plan-add-btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  background: #fff;
  border: 1.5px dashed var(--border, #d8dce1);
  border-radius: var(--r-md, 8px);
  color: var(--text);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: border-color var(--t-fast, 120ms) var(--ease, ease), background var(--t-fast, 120ms) var(--ease, ease), transform var(--t-fast, 120ms) var(--ease, ease);
}
.plan-add-btn:hover {
  border-style: solid;
  border-color: var(--brand-primary, var(--red));
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 5%, #fff);
  transform: translateY(-1px);
}
.plan-add-btn:focus-visible {
  outline: 2px solid var(--brand-primary, var(--red));
  outline-offset: 2px;
}
.plan-add-btn-icon {
  display: inline-grid; place-items: center;
  width: 36px; height: 36px;
  border-radius: var(--r-sm, 6px);
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 10%, #fff);
  color: var(--brand-primary, var(--red));
  flex-shrink: 0;
}
.plan-add-btn-icon svg { width: 20px; height: 20px; }
.plan-add-btn-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.plan-add-btn-title {
  font-weight: 700;
  font-size: 14px;
  line-height: 1.2;
}
.plan-add-btn-sub {
  font-size: 11.5px;
  color: var(--text-dim);
  line-height: 1.3;
}
/* Primary variant — slightly more saturated so the library option reads as
   the default action. */
.plan-add-btn-primary { border-style: solid; }
.plan-add-btn-primary .plan-add-btn-icon {
  background: var(--brand-primary, var(--red));
  color: #fff;
}

@media (max-width: 640px) {
  .plan-editor-add-row { grid-template-columns: 1fr; }
}

/* Attach-to-practice modal — list of practices the coach can link this plan to. */
.attach-practice-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 360px;
  overflow-y: auto;
  margin: 0 0 12px;
}
.attach-practice-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-sm, 6px);
  background: #fff;
  cursor: pointer;
  transition: border-color var(--t-fast, 120ms) var(--ease, ease), background var(--t-fast, 120ms) var(--ease, ease);
}
.attach-practice-item:hover {
  border-color: var(--brand-primary, var(--red));
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 6%, #fff);
}
.attach-practice-item.is-current {
  border-color: var(--brand-primary, var(--red));
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 10%, #fff);
  cursor: default;
}
.attach-practice-main { min-width: 0; }
.attach-practice-title {
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.attach-practice-meta {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.attach-practice-current {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 4px;
}

/* Top action toolbar — visibility toggles on the left, action icon buttons
   on the right. Sits between the plan name/date row and the notes field. */
.plan-editor-toolbar {
  display: flex;
  gap: 16px;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding: 10px 12px;
  background: var(--bg-soft, #f4f5f7);
  border-radius: var(--r-md, 8px);
}
.plan-editor-toolbar-left {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
.plan-editor-toolbar-right {
  display: flex;
  align-items: center;
  gap: 6px;
}
/* Compact toggles inside the toolbar (override the looser .plan-visibility-row
   spacing used elsewhere). */
.plan-editor-toolbar .plan-visibility-toggle { margin: 0; font-size: 12.5px; }

/* Icon-only action buttons in the toolbar. Square 36×36 tap target, ghost
   style by default. Browser-native `title` provides the hover tooltip. */
.plan-toolbar-icon-btn {
  width: 36px; height: 36px;
  padding: 0;
  background: #fff;
  border: 1px solid var(--border, #d8dce1);
  border-radius: var(--r-sm, 6px);
  color: var(--text-dim);
  display: inline-grid; place-items: center;
  cursor: pointer;
  transition: background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
}
.plan-toolbar-icon-btn svg { width: 18px; height: 18px; }
.plan-toolbar-icon-btn:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 10%, #fff);
  border-color: var(--brand-primary, var(--red));
  color: var(--brand-primary, var(--red));
}
.plan-toolbar-icon-btn:focus-visible {
  outline: 2px solid var(--brand-primary, var(--red));
  outline-offset: 2px;
}

/* Inline indicator that sits left of the Attach button when the plan is
   linked to an upcoming practice. Hidden via [hidden] when unused. */
.plan-attachment-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 5px 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--brand-primary, var(--red));
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--brand-primary, var(--red)) 30%, transparent);
  border-radius: var(--r-pill, 999px);
  margin-right: 4px;
  cursor: default;
}
.plan-attachment-indicator::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--brand-primary, var(--red));
}
/* `display: inline-flex` on the class beats UA `[hidden] { display: none }` at
   equal specificity, so re-assert the hide. Same pattern as .icon-grid[hidden]
   and .plans-edit-shell[hidden] elsewhere. */
.plan-attachment-indicator[hidden] { display: none; }
/* The history block has display:block by default, but it also gets toggled via
   the hidden attribute — be explicit for consistency. */
.plan-attachment-history[hidden] { display: none; }

/* History block under the Delete button — every practice (past + upcoming)
   this plan has been linked to. */
.plan-attachment-history {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft, #e6e8eb);
}
.plan-attachment-history-head {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-dim);
}
.plan-attachment-history-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.plan-attachment-history-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  font-size: 12.5px;
  color: var(--text);
  background: var(--bg-soft, #f4f5f7);
  border-radius: var(--r-sm, 6px);
  border-left: 3px solid transparent;
}
.plan-attachment-history-item.is-upcoming {
  border-left-color: var(--brand-primary, var(--red));
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 5%, #fff);
}
.plan-attachment-history-date {
  font-weight: 700;
  min-width: 100px;
}
.plan-attachment-history-title {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plan-attachment-history-meta {
  font-size: 11.5px;
  color: var(--text-dim);
  margin-left: auto;
  white-space: nowrap;
}
.plan-attachment-history-badge {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: var(--r-pill, 999px);
  background: var(--brand-primary, var(--red));
  color: #fff;
}

/* The Run Practice primary action keeps its label + a play icon. */
.plan-toolbar-run-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  font-weight: 600;
  background: var(--brand-primary, var(--red)) !important;
  border-color: var(--brand-primary, var(--red)) !important;
  color: #fff !important;
  border-radius: var(--r-sm, 6px);
}
.plan-toolbar-run-btn svg { width: 14px; height: 14px; }
.plan-toolbar-run-btn:hover { filter: brightness(0.94); }
.plan-editor-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  padding-top: 16px;
  border-top: 1px solid var(--border-soft, #e6e8eb);
}
.plan-editor-actions .btn-primary {
  background: var(--brand-primary, var(--red));
  border-color: var(--brand-primary, var(--red));
  color: #fff !important;
}

@media (max-width: 640px) {
  .plan-editor-head { grid-template-columns: 1fr; }
  .plan-editor-date { text-align: left; }
  .plan-editor-book { text-align: left; }
  .ped-row { grid-template-columns: 28px 1fr auto; }
  .ped-thumb { display: none; }
}

/* Schedule row: chip showing a Practice's attached plan. */
.schedule-plan-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 600;
  color: var(--brand-primary, var(--red));
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 10%, transparent);
  border-radius: var(--r-pill, 999px);
}
.schedule-plan-chip .icon-inline { width: 13px; height: 13px; vertical-align: -2px; }

/* Plan editor — visibility toggle (CSS-only switch). */
.plan-visibility-toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 18px;
  cursor: pointer;
  user-select: none;
  font-size: 13px;
  color: var(--text);
}
.plan-visibility-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.plan-visibility-track {
  width: 36px; height: 20px;
  background: var(--border, #d8dce1);
  border-radius: var(--r-pill, 999px);
  position: relative;
  transition: background var(--t-fast, 120ms) var(--ease, ease);
  flex: 0 0 auto;
}
.plan-visibility-thumb {
  position: absolute;
  top: 2px; left: 2px;
  width: 16px; height: 16px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
  transition: transform var(--t-fast, 120ms) var(--ease, ease);
}
.plan-visibility-toggle input:checked + .plan-visibility-track { background: var(--green, #1f9e5a); }
.plan-visibility-toggle input:checked + .plan-visibility-track .plan-visibility-thumb { transform: translateX(16px); }
.plan-visibility-toggle input:focus-visible + .plan-visibility-track { box-shadow: var(--ring); }
.plan-visibility-text { font-weight: 600; }

/* Clipboard badge — small pill at the bottom of the head block. */
.plan-visible-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  padding: 3px 9px;
  background: color-mix(in srgb, var(--green, #1f9e5a) 14%, #fff);
  color: var(--green, #1f9e5a);
  border-radius: var(--r-pill, 999px);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.plan-visible-badge .icon-inline { width: 13px; height: 13px; }

/* Side-by-side share + visibility toggles inside the plan editor. */
.plan-visibility-row {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  margin: 6px 0 18px;
}
.plan-visibility-row .plan-visibility-toggle { margin: 0; }

/* Clipboard chip: "📅 Oct 12 · Skating & Edges" — shown on a plan card when
   the plan is attached to an upcoming practice on the schedule. */
.plan-upcoming-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  padding: 3px 9px;
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 12%, #fff);
  color: var(--brand-primary, var(--red));
  border: 1px solid color-mix(in srgb, var(--brand-primary, var(--red)) 28%, transparent);
  border-radius: var(--r-pill, 999px);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.plan-upcoming-chip .icon-inline { width: 13px; height: 13px; }
/* Subtle highlight on the whole card when a plan has a scheduled practice. */
.plan-card.has-upcoming {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--brand-primary, var(--red)) 24%, transparent),
              0 6px 16px -8px rgba(0,0,0,.18),
              0 2px 4px -2px rgba(0,0,0,.08);
}

/* Sidebar version — same visual treatment as the date `.badge` in the meta
   row so plan attachments don't shout. Neutral grey background, dim text. */
.plan-side-upcoming {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
  padding: 1px 6px;
  background: var(--bg-soft);
  color: var(--text-dim);
  border-radius: 3px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0;
  max-width: 100%;
  overflow: hidden;
}
.plan-side-upcoming svg { width: 11px; height: 11px; flex-shrink: 0; opacity: 0.8; }
.plan-side-upcoming span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Clipboard badge for plans the current coach hasn't shared with their staff. */
.plan-private-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  margin-right: 4px;
  padding: 3px 9px;
  background: color-mix(in srgb, var(--text-dim) 14%, #fff);
  color: var(--text-dim);
  border-radius: var(--r-pill, 999px);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.plan-private-badge .icon-inline { width: 13px; height: 13px; }

/* Clickable thumbnail in plan-editor rows — wraps the existing .ped-thumb img
   and overlays a magnifier on hover so the expand affordance is discoverable. */
.ped-thumb-btn {
  position: relative;
  display: block;
  width: 250px; height: 150px;
  padding: 0; margin: 0;
  border: 0;
  background: transparent;
  cursor: zoom-in;
  border-radius: var(--r-sm, 4px);
  overflow: hidden;
}
.ped-thumb-btn .ped-thumb {
  display: block;
  width: 100%; height: 100%;
  /* keep contain inside the button wrapper so the whole rink stays visible */
  object-fit: contain;
  transition: transform var(--t-fast, 120ms) var(--ease, ease);
}
.ped-thumb-btn:hover .ped-thumb { transform: scale(1.04); }
.ped-thumb-zoom {
  position: absolute;
  inset: 0;
  display: grid; place-items: center;
  background: rgba(0,0,0,0.32);
  color: #fff;
  opacity: 0;
  transition: opacity var(--t-fast, 120ms) var(--ease, ease);
  pointer-events: none;
}
.ped-thumb-zoom svg { width: 22px; height: 22px; }
.ped-thumb-btn:hover .ped-thumb-zoom,
.ped-thumb-btn:focus-visible .ped-thumb-zoom { opacity: 1; }
.ped-thumb-btn:focus-visible { outline: 2px solid var(--brand-primary, var(--red)); outline-offset: 2px; }

/* Drill preview modal — large image + description, opened from a row's
   magnifier button. */
.drill-preview-modal { padding: 22px 24px; }
.drill-preview-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
}
.drill-preview-head .sub {
  font-size: 12px;
  color: var(--text-dim);
}
.drill-preview-body {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
.drill-preview-image-wrap {
  background: var(--bg-soft, #f4f5f7);
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-md, 8px);
  padding: 8px;
  display: grid; place-items: center;
  min-height: 240px;
}
.drill-preview-image-wrap img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: contain;
  border-radius: var(--r-sm, 4px);
}
.drill-preview-description {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text);
}
.drill-preview-description p { margin: 0 0 10px; }
.drill-preview-description ul,
.drill-preview-description ol { padding-left: 22px; margin: 0 0 10px; }
.drill-preview-description li { margin: 2px 0; }
.drill-preview-description h1,
.drill-preview-description h2,
.drill-preview-description h3,
.drill-preview-description h4 { margin: 10px 0 6px; font-size: 14px; font-weight: 700; }

@media (max-width: 720px) {
  .drill-preview-body { grid-template-columns: 1fr; }
  .drill-preview-image-wrap { min-height: 0; }
}

/* ============================================================
   Plans page — split layout
   Mirrors the rinkboard shell: editor takes the main area on the
   left, a compact plan list lives in a right-side sidebar.
   ============================================================ */
.page-plans-split { display: flex; flex-direction: column; min-height: 0; }
.plans-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 20px;
  align-items: start;
  margin-top: 12px;
}
.plans-main { min-width: 0; }
.plans-sidebar {
  position: sticky;
  top: 12px;
  background: var(--panel, #fff);
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-md, 8px);
  overflow: hidden;
  max-height: calc(100vh - 140px);
  display: flex;
  flex-direction: column;
}
.plans-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
  background: var(--bg-soft, #f4f5f7);
}
.plans-sidebar-count {
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--r-pill, 999px);
  background: var(--brand-primary, var(--red));
  color: #fff;
  min-width: 22px;
  text-align: center;
  letter-spacing: 0;
}
.plans-sidebar #plan-list {
  overflow-y: auto;
  flex: 1;
  padding: 6px;
}
.plans-sidebar-empty {
  padding: 24px 16px;
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.5;
}

/* Compact plan row in the sidebar (mirrors the drill-list pattern). */
.plan-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
  padding: 10px 12px;
  border-radius: var(--r-sm, 6px);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
}
.plan-item + .plan-item { margin-top: 2px; }
.plan-item:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 6%, transparent);
  border-color: color-mix(in srgb, var(--brand-primary, var(--red)) 20%, transparent);
}
.plan-item.active {
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 12%, transparent);
  border-color: var(--brand-primary, var(--red));
}
.plan-item-main { min-width: 0; }
.plan-item-title {
  font-weight: 700;
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.plan-item-meta {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.plan-item-flags {
  display: inline-flex;
  gap: 4px;
  margin-top: 4px;
}
.plan-item-flag {
  display: inline-grid; place-items: center;
  width: 18px; height: 18px;
  border-radius: var(--r-sm, 4px);
  background: var(--bg-soft, #f4f5f7);
  color: var(--text-dim);
}
.plan-item-flag.visible { background: color-mix(in srgb, var(--green, #1f9e5a) 14%, #fff); color: var(--green, #1f9e5a); }
.plan-item-flag.private { background: color-mix(in srgb, var(--text-dim) 14%, #fff); color: var(--text-dim); }
.plan-item-flag .icon-inline { width: 12px; height: 12px; }
.plan-item-del {
  background: transparent;
  border: 0;
  width: 28px; height: 28px;
  border-radius: var(--r-sm, 6px);
  color: var(--text-dim);
  display: inline-grid; place-items: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-fast, 120ms) var(--ease, ease), background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease);
}
.plan-item:hover .plan-item-del,
.plan-item:focus-within .plan-item-del,
.plan-item.active .plan-item-del { opacity: 1; }
.plan-item-del:hover { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); }
.plan-item-del .icon-inline { width: 14px; height: 14px; }

/* Empty-state shown in the main area when no plan is open. */
.plans-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 60px 24px;
  min-height: 420px;
  border: 2px dashed var(--border-soft, #e6e8eb);
  border-radius: var(--r-md, 8px);
  color: var(--text-dim);
}
.plans-empty-icon svg { width: 56px; height: 56px; color: var(--text-dim); opacity: 0.7; }
.plans-empty h2 {
  margin: 14px 0 6px;
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
}
.plans-empty p { margin: 0; font-size: 14px; max-width: 360px; line-height: 1.55; }
.plans-empty b { color: var(--brand-primary, var(--red)); }

/* Editor sits in the main area now — give it a panel surround so it visually
   reads as a "view" rather than free-floating content. */
.page-plans-split .plan-editor {
  background: var(--panel, #fff);
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-md, 8px);
  padding: 20px;
}

/* Sidebar collapses below the editor on narrower viewports. */
@media (max-width: 980px) {
  .plans-split { grid-template-columns: 1fr; }
  .plans-sidebar { position: static; max-height: 360px; }
}

/* ============================================================
   Plans EDIT shell — full-bleed view mirroring the rinkboard
   layout (drill page). Activated when at least one plan is open
   in a tab; the clipboard grid view is hidden during this state.
   ============================================================ */
.plans-edit-shell {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 52px);
  background: var(--bg, #fff);
  color: var(--text);
}
/* `.plans-edit-shell { display: flex }` ties with the UA `[hidden] { display:none }`
   at the same specificity (1 class vs 1 attr), so the later page-CSS wins and the
   element would render even with `hidden`. Force the hide here. Same pattern for
   the grid view since it gets toggled too. */
.plans-edit-shell[hidden],
#plans-grid-view[hidden] { display: none; }
body.plans-edit-mode .page-main { height: calc(100vh - 52px); overflow: hidden; }

.plans-edit-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  /* Light background so it visually separates from the dark .topnav above it
     (mirrors the drill-page .topbar pattern). */
  background: var(--bg, #fff);
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
  flex: 0 0 auto;
  min-height: 52px;
}
.plans-edit-bar-spacer { flex: 1; }
.plans-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 1px solid var(--border, #d8dce1);
  color: var(--text);
  padding: 6px 12px 6px 8px;
  border-radius: var(--r-sm, 6px);
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: background var(--t-fast, 120ms) var(--ease, ease), border-color var(--t-fast, 120ms) var(--ease, ease);
}
.plans-back-btn:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 8%, transparent);
  border-color: var(--brand-primary, var(--red));
  color: var(--brand-primary, var(--red));
}
.plans-back-btn svg { width: 16px; height: 16px; }
.plans-edit-bar .plan-tab-strip {
  flex: 0 1 auto;
  margin: 0;
  background: transparent;
  border: 0;
  padding: 0;
}

.plans-edit-main {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  grid-template-rows: 1fr;   /* row fills the flex height — without this the
                                row is auto-sized to content (~56px) and the
                                editor only shows a sliver */
  min-height: 0;
  background: var(--bg-soft, #f4f5f7);
  position: relative;
}
/* Collapse strip — sits flush against the right edge of the main area when
   the plans sidebar is hidden. Click it to expand the sidebar back in. */
.plans-collapse-strip {
  position: absolute;
  top: 0;
  right: 0;
  width: 18px;
  height: 100%;
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--panel-dark, #2c3036);
  color: rgba(255, 255, 255, 0.75);
  border: 0;
  cursor: pointer;
  z-index: 4;
  transition: background var(--t-fast, 120ms) var(--ease, ease), color var(--t-fast, 120ms) var(--ease, ease);
}
.plans-collapse-strip:hover {
  background: var(--brand-primary, var(--red));
  color: #fff;
}
.plans-collapse-strip svg { width: 14px; height: 14px; }

/* Collapsed state */
body.plans-sidebar-collapsed .plans-edit-main { grid-template-columns: 1fr; }
body.plans-sidebar-collapsed .plans-edit-sidebar { display: none; }
body.plans-sidebar-collapsed .plans-collapse-strip { display: flex; }
body.plans-sidebar-collapsed .plans-edit-canvas { padding-right: 18px; } /* leave room for the strip */
.plans-edit-canvas {
  overflow-y: auto;
  min-width: 0;
  min-height: 0;             /* lets the auto-scrolling work inside the grid */
  background: var(--panel, #fff);
  /* Stack the editor and the sticky add-bar vertically so we can pin the bar
     to the bottom regardless of editor height. */
  display: flex;
  flex-direction: column;
}
.plans-edit-canvas > .plan-editor { flex: 1 0 auto; }
/* Sticky bottom bar inside the scrolling canvas — always visible without
   scrolling, even on plans with many drills. */
.plan-editor-add-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  background: #fff;
  border-top: 1px solid var(--border-soft, #e6e8eb);
  box-shadow: 0 -6px 14px -10px rgba(0,0,0,0.18);
  padding: 12px 24px;
  margin-top: auto; /* push to the bottom when the editor is short */
}
.plan-editor-add-bar .plan-editor-add-row { margin: 0; }
/* Editor stretches edge-to-edge across the canvas column (viewport width minus
   the 320px Plans sidebar). Drops all the card chrome since the canvas itself
   is the surface now — no border, no rounded corners, no horizontal padding so
   inputs and drill rows touch the sidebar edge. Vertical padding only. */
.plans-edit-canvas .plan-editor {
  width: 100%;
  max-width: none;
  margin: 0;
  background: transparent;
  border: 0 !important;
  border-radius: 0;
  padding: 20px 0;
  box-shadow: none;
}
/* Inside the canvas, push each editor row to the canvas edges with a thin
   inset so text doesn't crash into the sidebar border. */
.plans-edit-canvas .plan-editor > * {
  padding-left: 24px;
  padding-right: 24px;
}
.plans-edit-canvas .plan-editor-drill-list { padding-left: 24px; padding-right: 24px; }

/* Right sidebar — reuses .sidebar / .sidebar-tabs / .drill-list scaffolding so
   it matches the rinkboard look exactly. */
.plans-edit-sidebar {
  background: var(--bg);
  border-left: 1px solid var(--border-soft);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}
.plans-edit-sidebar .sidebar-tabs {
  display: flex;
  background: var(--panel-dark);
  border-bottom: 1px solid #1a1d22;
}
.plans-edit-sidebar .sidebar-tab {
  flex: 1;
  text-align: center;
  padding: 12px 8px;
  cursor: default;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 1px;
  color: rgba(255,255,255,.65);
  border-bottom: 3px solid transparent;
}
.plans-edit-sidebar .sidebar-tab.active {
  color: #fff;
  border-bottom-color: var(--brand-primary, var(--red));
}
.plans-edit-sidebar .sidebar-panel { display: flex; flex: 1; flex-direction: column; overflow: hidden; }
.plans-edit-sidebar .search-row { padding: 8px 12px; border-bottom: 1px solid var(--border-soft); }
.plans-edit-sidebar .search-row input {
  width: 100%;
  border: 1px solid var(--border, #d8dce1);
  padding: 7px 12px;
  border-radius: 3px;
  font-family: inherit;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text);
  background: #fff;
  outline: none;
}
.plans-edit-sidebar .drill-list {
  flex: 1;
  overflow-y: auto;
  padding: 6px;
}
/* Sidebar plan cards stay neutral grey/light-grey — no brand color tint on
   hover or when active. The chip(s) inside (upcoming-practice etc.) still
   carry color for status, but the card itself blends with the panel. */
.plan-side-card {
  border-color: var(--border-soft, #e6e8eb) !important;
  background: #fff !important;
}
.plan-side-card:hover {
  background: var(--bg-soft, #f4f5f7) !important;
  border-color: var(--border, #d8dce1) !important;
}
/* Active plan = solid red card with white text. Inverts the chip and badge
   colors so they stay legible against the red surface. */
.plan-side-card.active {
  background: var(--red) !important;
  border-color: var(--red) !important;
  color: #fff !important;
}
.plan-side-card.active .nm,
.plan-side-card.active .info { color: #fff !important; }
.plan-side-card.active .meta { color: rgba(255, 255, 255, 0.88) !important; }
.plan-side-card.active .meta .badge {
  background: rgba(255, 255, 255, 0.20) !important;
  color: #fff !important;
}
.plan-side-card.active .acts button {
  color: rgba(255, 255, 255, 0.85) !important;
}
.plan-side-card.active .acts button:hover {
  background: rgba(255, 255, 255, 0.15) !important;
  color: #fff !important;
}
/* The "Added to practice…" chip matches the date `.badge` override on an
   active card — translucent white on the red background, white text. */
.plan-side-card.active .plan-side-upcoming {
  background: rgba(255, 255, 255, 0.20) !important;
  color: #fff !important;
}
.plan-side-card.active .plan-side-upcoming svg { opacity: 1; }
.plan-side-card .meta { flex-wrap: wrap; }
.plan-side-card .meta .badge { font-weight: 600; }

/* Books — collapsible groups of plans in the sidebar. Mirrors the
   .drill-folder-group pattern from the rinkboard's drill list. */
.plan-book-group { margin-bottom: 6px; }
.plan-book-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 8px 6px;
  cursor: pointer;
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  user-select: none;
  border-radius: var(--r-sm, 4px);
}
.plan-book-head:hover { background: var(--bg-soft, #f4f5f7); color: var(--text); }
.plan-book-head .chev {
  transition: transform var(--t-fast, 120ms) var(--ease, ease);
  flex-shrink: 0;
}
.plan-book-group.collapsed .plan-book-head .chev { transform: rotate(-90deg); }
/* "Current" book = the one containing the active plan. Uses the topnav's
   panel-dark color so the book the user is working inside is visually
   anchored to the page chrome. Also bumped a notch larger than the normal
   book heading. */
.plan-book-group.is-current .plan-book-head {
  background: var(--panel-dark, #2c3036);
  color: #fff;
  font-size: 13px;
  letter-spacing: 0.5px;
  padding: 11px 12px 10px;
}
.plan-book-group.is-current .plan-book-head:hover {
  background: var(--panel-dark, #2c3036);
  color: #fff;
}
.plan-book-group.is-current .plan-book-head .chev { width: 12px; height: 12px; }
.plan-book-group.is-current .plan-book-count {
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
  font-size: 11.5px;
  padding: 2px 9px;
}
.plan-book-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plan-book-count {
  background: var(--bg-soft, #f4f5f7);
  color: var(--text-dim);
  padding: 1px 7px;
  border-radius: var(--r-pill, 999px);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0;
}
.plan-book-group.collapsed .plan-book-body { display: none; }

/* Overflow indicator for the clipboard grid when a plan has > 8 drills. */
.plan-drill-overflow {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  padding: 6px 4px 2px;
  text-align: right;
  font-style: italic;
}

@media (max-width: 860px) {
  .plans-edit-main { grid-template-columns: 1fr; }
  .plans-edit-sidebar { display: none; }
  .plans-edit-bar { flex-wrap: wrap; }
}

/* "Add personal drill to my teams" picker — list of checkboxes inside the
   push-to-teams modal. */
.push-to-teams-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 320px;
  overflow-y: auto;
  margin-bottom: 12px;
}
.push-team-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-sm, 6px);
  cursor: pointer;
  font-size: 13px;
  transition: border-color var(--t-fast, 120ms) var(--ease, ease), background var(--t-fast, 120ms) var(--ease, ease);
}
.push-team-row:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--red)) 6%, #fff);
  border-color: var(--brand-primary, var(--red));
}
.push-team-row input[type="checkbox"] { width: 16px; height: 16px; flex-shrink: 0; }
.push-team-name { flex: 1; font-weight: 600; }
.push-team-row .badge {
  background: var(--bg-soft, #f4f5f7);
  color: var(--text-dim);
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

/* ============================================================
   Add Drill to Plan — redesigned picker modal
   Wider modal, card grid with bigger thumbs, scope tabs, search,
   popularity badge, "in plan" pill, per-card mins override.
   ============================================================ */
.modal.add-drill-modal {
  width: 1200px;
  max-width: 96vw;
  /* Definite height (not just max-height) — flex children inside need a
     concrete parent height to allocate space correctly. Without this the
     picker's flex: 1 falls back to content size and the grid rows squish. */
  height: 88vh;
  max-height: 88vh;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.add-drill-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
}
.add-drill-head h3 { margin: 0; font-size: 18px; }
.add-drill-toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border-soft, #e6e8eb);
  background: var(--bg-soft, #f4f5f7);
}
.add-drill-toolbar input[type="text"] {
  flex: 1;
  padding: 8px 12px;
  border: 1px solid var(--border, #d8dce1);
  border-radius: var(--r-sm, 6px);
  font-size: 13px;
  background: #fff;
  outline: none;
}
.add-drill-toolbar input[type="text"]:focus {
  border-color: var(--brand-primary, var(--red));
}
.add-drill-scope {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-pill, 999px);
  padding: 2px;
  gap: 2px;
  flex-shrink: 0;
}
.add-drill-scope button {
  padding: 5px 14px;
  font-size: 12px;
  font-weight: 600;
  background: transparent;
  border: 0;
  border-radius: var(--r-pill, 999px);
  cursor: pointer;
  color: var(--text-dim);
  letter-spacing: 0.2px;
}
.add-drill-scope button.active {
  background: var(--brand-primary, var(--red));
  color: #fff;
}
.add-drill-scope button:hover:not(.active) { color: var(--text); }

/* View toggle (Grid / Compact / Detail) — icon-only pill group. */
.add-drill-view {
  display: inline-flex;
  background: #fff;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-sm, 6px);
  overflow: hidden;
  flex-shrink: 0;
}
.add-drill-view button {
  width: 32px; height: 30px;
  display: inline-grid; place-items: center;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--text-dim);
  padding: 0;
}
.add-drill-view button svg { width: 16px; height: 16px; }
.add-drill-view button:hover { color: var(--text); background: var(--bg-soft, #f4f5f7); }
.add-drill-view button.active {
  background: var(--text);
  color: #fff;
}
.add-drill-view button + button { border-left: 1px solid var(--border-soft, #e6e8eb); }

/* Flex-wrap layout (NOT CSS Grid). CSS Grid was distributing the picker's
   vertical space across rows once the modal hit its max-height — every card
   got 1/N of available height instead of holding its 290px content height.
   Flex-wrap rows are content-sized: each row is exactly as tall as the
   tallest card in it, and the picker scrolls when total height exceeds it. */
#drill-picker {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  align-items: flex-start;
  gap: 14px;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  padding: 16px 20px;
  margin: 0;
  border: 0;
  max-height: none;
  background: var(--panel, #fff);
}
/* Grid view — three cards per row (responsive: 2 on narrow, 1 on tiny). */
#drill-picker .pick-card { flex: 0 0 calc((100% - 28px) / 3); }
@media (max-width: 900px) { #drill-picker .pick-card { flex-basis: calc((100% - 14px) / 2); } }
@media (max-width: 640px) { #drill-picker .pick-card { flex-basis: 100%; } }

/* Compact list view — small thumb on the left, name + meta + actions on a
   single line. One drill per row. */
#drill-picker.pick-view-compact {
  /* Keep flex-direction: row + flex-wrap: wrap from the base rule. With each
     card at flex: 0 0 100% (below), wrapping happens vertically — top-to-
     bottom rows. Setting flex-direction: column here would combine with the
     inherited flex-wrap: wrap to create LEFT-TO-RIGHT column flow (cards
     stack down, then wrap rightward) which causes horizontal scroll. */
  gap: 4px;
}
#drill-picker.pick-view-compact .pick-card {
  flex: 0 0 100%;     /* one drill per row in compact view */
  flex-direction: row;
  align-items: center;
  min-height: 58px;   /* matches the fixed-width thumb height */
}
#drill-picker.pick-view-compact .pick-card-thumb {
  width: 96px;
  height: 58px;        /* 96 × 3/5, fixed (padding-bottom % is relative to
                          parent width, so use explicit height instead). */
  padding-bottom: 0;
  flex-shrink: 0;
}
#drill-picker.pick-view-compact .pick-card-thumb-empty { font-size: 10px; }
#drill-picker.pick-view-compact .pick-card-added-pill,
#drill-picker.pick-view-compact .pick-card-pop {
  font-size: 10px;
  padding: 2px 6px;
}
#drill-picker.pick-view-compact .pick-card-added-pill svg,
#drill-picker.pick-view-compact .pick-card-pop svg { width: 10px; height: 10px; }
#drill-picker.pick-view-compact .pick-card-body {
  flex: 1;
  flex-direction: row;
  align-items: center;
  gap: 14px;
  padding: 10px 14px;
  min-width: 0;
}
#drill-picker.pick-view-compact .pick-card-name { flex: 0 1 auto; font-size: 13.5px; }
#drill-picker.pick-view-compact .pick-card-meta { flex: 1; font-size: 12px; }
#drill-picker.pick-view-compact .pick-card-actions { margin-top: 0; }

/* Detail row view — bigger thumb + meta + description preview, one per row. */
#drill-picker.pick-view-detail {
  /* Same fix as compact view — keep flex-direction: row from the base rule
     so flex-wrap: wrap creates vertical rows of full-width cards. */
  gap: 10px;
}
#drill-picker.pick-view-detail .pick-card {
  flex: 0 0 100%;     /* one drill per row in detail view */
  flex-direction: row;
  align-items: stretch;
  min-height: 192px;   /* matches the fixed-width thumb height */
}
#drill-picker.pick-view-detail .pick-card-thumb {
  width: 320px;
  height: 192px;       /* 320 × 3/5, fixed for the same reason as compact. */
  padding-bottom: 0;
  flex-shrink: 0;
}
#drill-picker.pick-view-detail .pick-card-body {
  flex: 1;
  padding: 14px 18px;
  gap: 6px;
  min-width: 0;
}
#drill-picker.pick-view-detail .pick-card-name { font-size: 16px; }
#drill-picker.pick-view-detail .pick-card-meta { font-size: 13px; }
.pick-card-desc {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-dim);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 4px 0;
}
#drill-picker.pick-view-detail .pick-card-actions { margin-top: auto; }
.pick-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: 32px 16px;
  color: var(--text-dim);
  font-size: 13px;
}
/* Load-more footer — spans the full grid row / flex column, gives count
   feedback and a click target if scroll-detection misfires. */
.pick-more {
  grid-column: 1 / -1;
  text-align: center;
  padding: 18px 12px;
  color: var(--text-dim);
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.pick-more-btn {
  background: var(--brand-primary, var(--red));
  border: 0;
  border-radius: var(--r-sm, 6px);
  color: #fff;
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
.pick-more-btn:hover { filter: brightness(0.94); }

/* Drill card — bigger thumb, name + meta, popularity badge, mins override.
   `align-self: start` keeps each card hugging its content height instead of
   stretching to whatever's tallest in the grid row — grid items default to
   stretch which was forcing every card to a single 60-ish-px row. */
.pick-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border-soft, #e6e8eb);
  border-radius: var(--r-md, 8px);
  background: #fff;
  overflow: hidden;
  align-self: start;
  min-height: 290px;
  transition: border-color var(--t-fast, 120ms) var(--ease, ease), box-shadow var(--t-fast, 120ms) var(--ease, ease), transform var(--t-fast, 120ms) var(--ease, ease);
}
/* Compact + detail views need their own height behavior (one-row layout). */
#drill-picker.pick-view-compact .pick-card,
#drill-picker.pick-view-detail  .pick-card { min-height: 0; align-self: stretch; }
.pick-card:hover {
  border-color: var(--brand-primary, var(--red));
  box-shadow: 0 6px 16px -8px rgba(0,0,0,0.12);
  transform: translateY(-1px);
}
.pick-card.is-added {
  border-color: color-mix(in srgb, var(--green, #1f9e5a) 50%, transparent);
  background: color-mix(in srgb, var(--green, #1f9e5a) 5%, #fff);
}
/* Thumb sizing uses an explicit pixel height to avoid aspect-ratio /
   padding-bottom edge cases inside flex+grid parents that have been
   silently collapsing the box. Image inside letterboxes via object-fit. */
.pick-card-thumb {
  position: relative;
  width: 100%;
  height: 180px;
  background: var(--bg-soft, #f4f5f7);
  overflow: hidden;
  flex-shrink: 0;
}
.pick-card-thumb > img {
  display: block;
  width: 100%; height: 100%;
  object-fit: contain;
}
.pick-card-thumb-empty {
  position: absolute;
  inset: 0;
  display: grid; place-items: center;
  font-size: 11px;
  color: var(--text-dim);
  font-style: italic;
}
.pick-card-pop {
  position: absolute;
  top: 8px; right: 8px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 8px;
  background: color-mix(in srgb, var(--brand-secondary, #2864c8) 14%, #fff);
  color: var(--brand-secondary, #2864c8);
  border-radius: var(--r-pill, 999px);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2px;
  border: 1px solid color-mix(in srgb, var(--brand-secondary, #2864c8) 25%, transparent);
}
.pick-card-pop svg { width: 11px; height: 11px; }
.pick-card-added-pill {
  position: absolute;
  top: 8px; left: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  background: var(--green, #1f9e5a);
  color: #fff;
  border-radius: var(--r-pill, 999px);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.pick-card-added-pill svg { width: 12px; height: 12px; }
.pick-card-body {
  padding: 10px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
}
.pick-card-name {
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pick-card-meta {
  font-size: 12px;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pick-card-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
}
.pick-card-mins {
  position: relative;
  flex: 0 0 86px;
}
.pick-card-mins input {
  width: 100%;
  padding: 6px 28px 6px 10px;
  font-size: 12px;
  border: 1px solid var(--border, #d8dce1);
  border-radius: var(--r-sm, 6px);
  background: #fff;
  outline: none;
}
.pick-card-mins input:focus { border-color: var(--brand-primary, var(--red)); }
.pick-card-mins span {
  position: absolute;
  right: 10px; top: 50%;
  transform: translateY(-50%);
  font-size: 10.5px;
  color: var(--text-dim);
  pointer-events: none;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.pick-card-actions .btn {
  flex: 1;
  padding: 7px 10px;
  font-size: 12.5px;
  font-weight: 700;
}

@media (max-width: 720px) {
  .modal.add-drill-modal { width: 100%; height: 100%; max-height: 100%; max-width: 100%; border-radius: 0; }
  .add-drill-toolbar { flex-wrap: wrap; }
  .add-drill-scope { width: 100%; justify-content: space-between; }
  #drill-picker { grid-template-columns: 1fr; }
}

/* ============================================================
   BILLING — trial banner + paywall modal
   ============================================================ */

/* Trial banner: thin strip below the topnav. Friendly tone for the
   countdown; switches to urgent red when the trial has expired. */
.billing-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 8px 16px;
  background: linear-gradient(180deg, #fff7e0 0%, #ffeaa6 100%);
  border-bottom: 1px solid #e6c860;
  color: #6a4a00;
  font-size: 13px;
  font-weight: 600;
  flex-wrap: wrap;
}
.billing-banner--expired {
  background: linear-gradient(180deg, #fff0f0 0%, #ffcccc 100%);
  border-bottom-color: #d4302b;
  color: #7a1612;
}
.billing-banner-text { line-height: 1.35; }

/* "READ ONLY" pill on the expired banner — visually distinct so the
   coach catches at a glance that the team is in read-only mode (not
   just "you have a banner"). Uppercase, brand red, monospace tracking. */
.billing-banner-pill {
  display: inline-flex;
  align-items: center;
  margin-right: 10px;
  padding: 3px 8px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 1.2px;
  background: #d4302b;
  color: #fff;
  border-radius: 4px;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}
.billing-banner-btn {
  background: var(--brand-primary, #d4302b);
  color: #fff;
  border: 0;
  border-radius: 6px;
  padding: 6px 14px;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  transition: filter .12s ease;
}
.billing-banner-btn:hover { filter: brightness(1.08); }
.billing-banner-close {
  background: transparent;
  border: 0;
  color: inherit;
  opacity: 0.55;
  cursor: pointer;
  padding: 4px 6px;
  margin-left: 4px;
  display: inline-grid;
  place-items: center;
  border-radius: 4px;
  transition: opacity .12s ease, background .12s ease;
}
.billing-banner-close:hover { opacity: 1; background: rgba(0,0,0,0.06); }

/* Offline mode — pill in topnav appears only when body.is-offline is set
   (init.js toggles based on navigator.onLine + boot fallback). */
.offline-pill {
  display: none;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: #fde2e2;
  color: #7a1612;
  border: 1px solid #f5b8b8;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  cursor: default;
  user-select: none;
}
.offline-pill svg { display: block; }
body.is-offline .offline-pill { display: inline-flex; }
/* Faint pulse on the page so the user feels they're in a different mode. */
body.is-offline .topnav { box-shadow: inset 0 -2px 0 0 #f5b8b8; }

/* When the banner is showing, the route-drill page-main height calc needs
   to reserve 36px for it. layout.php and body.route-drill .page-main use
   100vh - 52px; with the banner we subtract another 36px. */
body.route-drill:has(.billing-banner) .page-main { height: calc(100vh - 88px); }

/* Paywall modal — shown when a 402 comes back from the server. */
.paywall-modal-bg {
  display: none;
  position: fixed; inset: 0;
  background: rgba(20, 22, 26, 0.62);
  z-index: 10000;
  align-items: center;
  justify-content: center;
}
.paywall-modal-bg.show { display: flex; }
.paywall-modal {
  background: #fff;
  width: 100%;
  max-width: 460px;
  border-radius: 14px;
  padding: 28px 28px 22px;
  box-shadow: 0 16px 48px rgba(0,0,0,0.32);
}
.paywall-modal h2 {
  margin: 0 0 8px;
  font-size: 22px;
  font-weight: 800;
  color: var(--text);
}
.paywall-modal .sub {
  margin: 0 0 18px;
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.45;
}
.paywall-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 12px;
}
.paywall-option {
  border: 2px solid var(--border);
  background: #fff;
  border-radius: 10px;
  padding: 14px 12px;
  cursor: pointer;
  text-align: center;
  transition: border-color .12s, transform .08s;
}
.paywall-option:hover { border-color: var(--brand-primary, #d4302b); }
.paywall-option:active { transform: scale(0.985); }
.paywall-option-cadence { font-size: 11px; font-weight: 700; color: var(--text-dim); letter-spacing: 1.2px; text-transform: uppercase; }
.paywall-option-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 6px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.8px;
  color: #0d6033;
  background: #d8f3df;
  border-radius: 4px;
  vertical-align: middle;
}
.paywall-option-price { font-size: 22px; font-weight: 800; color: var(--text); margin-top: 4px; }
.paywall-option-sub { font-size: 12px; color: var(--text-dim); margin-top: 4px; }
.paywall-option--annual { border-color: #1f9e5a; }
.paywall-option--annual::before {
  content: 'Best value';
  display: inline-block;
  background: #1f9e5a;
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.5px;
  padding: 2px 6px;
  border-radius: 4px;
  margin-bottom: 4px;
}
.paywall-modal-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
}
.paywall-modal-close {
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  padding: 6px 10px;
}
.paywall-modal-close:hover { color: var(--text); }

/* Billing section on the Team settings page (M4). */
.billing-card {
  background: #fff;
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  padding: 18px 20px;
  margin-top: 16px;
}
.billing-card h3 { margin: 0 0 6px; font-size: 16px; font-weight: 700; }
.billing-card .meta {
  font-size: 13px;
  color: var(--text-dim);
  margin-bottom: 14px;
  line-height: 1.5;
}
.billing-card .actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.billing-card .pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  vertical-align: middle;
}
.billing-card .pill--trial    { background: #fff7e0; color: #6a4a00; }
.billing-card .pill--active   { background: #e7f8ee; color: #135f31; }
.billing-card .pill--expired,
.billing-card .pill--canceled,
.billing-card .pill--past_due { background: #fde2e2; color: #7a1612; }

/* Prominent billing facts (Plan / Next bill) — flat tiles, brand-accent date */
.billing-card .billing-facts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }
.billing-card .bf {
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 14px; min-width: 130px;
  border: 1px solid #e5e7eb; border-radius: 10px; background: #f8fafc;
}
.billing-card .bf-label {
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: #64748b;
}
.billing-card .bf-value { font-size: 17px; font-weight: 800; color: #0f172a; line-height: 1.1; }
.billing-card .bf-date { color: var(--brand-primary, #2563eb); }
.billing-card .billing-portal-hint { display: block; margin-top: 6px; font-size: 12px; color: #64748b; }

/* Billing history (in-app invoice list) */
.billing-history-card h3 { margin: 0 0 8px; font-size: 16px; font-weight: 700; }
.billing-invoices { display: flex; flex-direction: column; }
.billing-invoices .bi-loading,
.billing-invoices .bi-empty { font-size: 13px; color: #64748b; padding: 6px 0; }
.bi-row { display: flex; align-items: center; gap: 12px; padding: 10px 2px; border-bottom: 1px solid #eef2f7; }
.bi-row:last-child { border-bottom: 0; }
.bi-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.bi-date { font-weight: 700; color: #0f172a; font-size: 14px; }
.bi-num { font-size: 11px; color: #94a3b8; }
.bi-amt { font-weight: 700; color: #0f172a; font-size: 14px; white-space: nowrap; }
.bi-status { font-size: 11px; font-weight: 700; text-transform: capitalize; padding: 2px 9px; border-radius: 999px; background: #f1f5f9; color: #475569; }
.bi-status--paid { background: #e7f8ee; color: #135f31; }
.bi-status--open, .bi-status--uncollectible { background: #fde2e2; color: #7a1612; }
.bi-link { font-size: 13px; font-weight: 700; color: var(--brand-primary, #2563eb); text-decoration: none; white-space: nowrap; }
.bi-link:hover { text-decoration: underline; }
.billing-invoices .link-btn { background: none; border: 0; padding: 0; color: var(--brand-primary, #2563eb); font: inherit; cursor: pointer; text-decoration: underline; }

/* Public legal pages (Terms / Privacy) */
.legal-page { max-width: 760px; margin: 0 auto; padding: 36px 24px 80px; color: #1f2937; line-height: 1.65; }
.legal-page h1 { font-size: 30px; font-weight: 800; margin: 4px 0 2px; color: #0f172a; }
.legal-page h2 { font-size: 18px; font-weight: 700; margin: 26px 0 6px; color: #0f172a; }
.legal-page p, .legal-page li { font-size: 15px; }
.legal-page ul { padding-left: 20px; margin: 6px 0; }
.legal-page li { margin: 4px 0; }
.legal-page a { color: var(--brand-primary, #2563eb); }
.legal-updated { color: #64748b; font-size: 13px; margin: 0 0 18px; }
.legal-back { display: inline-block; font-size: 13px; font-weight: 600; color: #64748b; text-decoration: none; margin-bottom: 8px; }
.legal-back:hover { color: var(--brand-primary, #2563eb); }
.legal-foot { margin-top: 32px; padding-top: 16px; border-top: 1px solid #e5e7eb; font-size: 13px; color: #64748b; }
/* Login consent line */
.login-legal { margin-top: 14px; text-align: center; font-size: 12px; color: #94a3b8; }
.login-legal a { color: #94a3b8; text-decoration: underline; }

/* ============================================================
   ACCOUNT PAGE
   ============================================================ */
.page-account .account-form {
  display: grid;
  gap: 12px;
  max-width: 480px;
}
.page-account .field input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 14px;
  background: #fff;
}
.page-account .field input:focus {
  outline: none;
  border-color: var(--blue, #2864c8);
  box-shadow: 0 0 0 2px rgba(40,100,200,0.15);
}
.page-account .readonly-field {
  padding: 10px 12px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: var(--bg-soft);
  color: var(--text-dim);
  font-size: 14px;
}
.page-account .account-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 6px;
}
.page-account .account-msg {
  font-size: 13px;
  min-height: 18px;
}
.page-account .account-msg--ok  { color: var(--green, #1f9e5a); }
.page-account .account-msg--err { color: var(--red,   #d4302b); }
.page-account .account-danger { border-color: #f5b8b8; }
.page-account .account-danger .btn:hover { background: #fde2e2; color: #7a1612; }

/* Preference rows on the Account page — used for the dark-mode toggle. */
.page-account .pref-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  cursor: pointer;
}
.page-account .pref-row > span:first-child { flex: 1; min-width: 0; }
/* Toggle-switch styling for a plain checkbox. WebKit lets us appearance:none
 * and roll our own without bringing in a dependency. */
.page-account .pref-switch {
  appearance: none;
  -webkit-appearance: none;
  width: 44px;
  height: 24px;
  border-radius: 999px;
  background: var(--border);
  position: relative;
  cursor: pointer;
  transition: background .15s;
  flex-shrink: 0;
  margin: 0;
}
.page-account .pref-switch::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: #ffffff;
  transition: left .15s;
  box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.page-account .pref-switch:checked { background: var(--brand-primary, #d4302b); }
.page-account .pref-switch:checked::after { left: 22px; }

/* ============================================================
   SCHEDULE REDESIGN (route /games) — 2026-05-21
   ============================================================
   Stats strip + new schedule-table styling matching the mockup at
   ~/Downloads/app-schedule-light.html. Scoped to body.route-schedule
   so existing .data-table styles elsewhere are unaffected. Uses
   existing CSS vars (--bg-soft, --border, --text, etc.) where it
   can so dark mode picks up automatically; introduces a few new
   accent vars locally for the W/L/T pills and the "ice" blue. */
body.route-schedule,
body.route-roster {
  --rb-ice:      #1e6fbf;
  --rb-ice-soft: rgba(30, 111, 191, 0.06);
  --rb-ice-glow: rgba(30, 111, 191, 0.12);
  --rb-mint:     #22a06b;
  --rb-mint-soft:rgba(34, 160, 107, 0.10);
  --rb-loss:     #d94929;
  --rb-loss-soft:rgba(217, 73, 41, 0.08);
  --rb-warm:     #e89043;
  --rb-warm-soft:rgba(232, 144, 67, 0.10);
  /* Legacy schedule-specific aliases — earlier .schedule-* rules
   * reference --sched-* tokens. Keep them mapped to the shared
   * --rb-* palette so a renaming pass can happen separately. */
  --sched-ice:      var(--rb-ice);
  --sched-ice-soft: var(--rb-ice-soft);
  --sched-ice-glow: var(--rb-ice-glow);
  --sched-mint:     var(--rb-mint);
  --sched-mint-soft:var(--rb-mint-soft);
  --sched-loss:     var(--rb-loss);
  --sched-loss-soft:var(--rb-loss-soft);
  --sched-warm:     var(--rb-warm);
  --sched-warm-soft:var(--rb-warm-soft);
}
html.dark-mode body.route-schedule,
html.dark-mode body.route-roster {
  --rb-ice-soft: rgba(30, 111, 191, 0.14);
  --rb-ice-glow: rgba(30, 111, 191, 0.22);
  --rb-mint-soft:rgba(34, 160, 107, 0.18);
  --rb-loss-soft:rgba(217, 73, 41, 0.16);
  --rb-warm-soft:rgba(232, 144, 67, 0.16);
}

/* Stats strip */
body.route-schedule .stats-strip, body.route-roster .stats-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 32px;
}
body.route-schedule .stat-card, body.route-roster .stat-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px;
  position: relative;
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s, transform .15s;
  box-shadow: 0 1px 2px rgba(15, 30, 60, 0.04), 0 2px 8px rgba(15, 30, 60, 0.03);
}
body.route-schedule .stat-card:hover, body.route-roster .stat-card:hover {
  border-color: var(--border);
  box-shadow: 0 4px 16px rgba(15, 30, 60, 0.08), 0 2px 8px rgba(15, 30, 60, 0.04);
  transform: translateY(-1px);
}
body.route-schedule .stat-card::before, body.route-roster .stat-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--sched-ice), transparent);
  opacity: 0.5;
}
body.route-schedule .stat-card-label, body.route-roster .stat-card-label {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}
body.route-schedule .stat-card-label svg, body.route-roster .stat-card-label svg {
  width: 12px; height: 12px;
  color: var(--sched-ice);
}
body.route-schedule .stat-card-value, body.route-roster .stat-card-value {
  font-family: 'Instrument Sans', 'Geist', sans-serif;
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1;
  margin-bottom: 6px;
  color: var(--text);
}
body.route-schedule .stat-card-value em, body.route-roster .stat-card-value em {
  font-style: italic;
  color: var(--sched-ice);
  font-weight: 500;
  font-size: 18px;
  margin-left: 4px;
}
body.route-schedule .stat-card-sub, body.route-roster .stat-card-sub {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--text-dim);
}
body.route-schedule .stat-card-sub .up, body.route-roster .stat-card-sub .up { color: var(--sched-mint); }
body.route-schedule .stat-card-sub .down, body.route-roster .stat-card-sub .down { color: var(--sched-loss); }

/* Schedule table card */
body.route-schedule .table-card, body.route-roster .table-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(15, 30, 60, 0.04), 0 12px 32px -8px rgba(15, 30, 60, 0.08);
  margin-bottom: 24px;
}
body.route-schedule .table-card .card-head, body.route-roster .table-card .card-head {
  padding: 24px 24px 20px;
  border-bottom: none;
}
body.route-schedule .schedule-table {
  width: 100%;
  border-collapse: collapse;
}
body.route-schedule .schedule-table thead {
  background: var(--bg-soft);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
body.route-schedule .schedule-table th {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  text-align: left;
  padding: 12px 16px;
  white-space: nowrap;
}
body.route-schedule .schedule-table th:first-child { padding-left: 24px; }
body.route-schedule .schedule-table th:last-child { padding-right: 24px; text-align: right; }
body.route-schedule .schedule-table tbody tr {
  border-bottom: 1px solid var(--border-soft);
  transition: background-color .12s;
}
body.route-schedule .schedule-table tbody tr:last-child { border-bottom: none; }
body.route-schedule .schedule-table tbody tr:hover { background: var(--bg-soft); }
body.route-schedule .schedule-table tbody tr.upcoming-row {
  background: var(--sched-ice-soft);
  border-left: 3px solid var(--sched-ice);
}
body.route-schedule .schedule-table td {
  padding: 16px;
  font-size: 14px;
  vertical-align: middle;
  color: var(--text);
}
body.route-schedule .schedule-table td:first-child { padding-left: 24px; }
body.route-schedule .schedule-table td:last-child { padding-right: 24px; text-align: right; }

/* Date cell */
body.route-schedule .date-cell { display: flex; align-items: center; gap: 12px; }
body.route-schedule .date-cell .date-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  background: var(--sched-ice-soft);
  border: 1px solid var(--sched-ice-glow);
  display: flex; align-items: center; justify-content: center;
  color: var(--sched-ice);
  flex-shrink: 0;
}
body.route-schedule .date-cell .date-icon svg { width: 14px; height: 14px; }
body.route-schedule .date-cell .date-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.route-schedule .date-cell .date-main {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
body.route-schedule .date-cell .date-day {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
body.route-schedule .status-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  margin-right: 6px;
}
body.route-schedule .status-dot.upcoming { background: var(--sched-ice); }
body.route-schedule .status-dot.completed { background: var(--text-dim); }

body.route-schedule .time-cell {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px;
  color: var(--text);
  font-weight: 500;
}

body.route-schedule .opponent-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
body.route-schedule .opponent-cell .opponent-name {
  font-family: 'Instrument Sans', 'Geist', sans-serif;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--text);
}
body.route-schedule .opponent-cell .opponent-venue {
  font-size: 12px;
  color: var(--text-dim);
}

/* H/A badge */
body.route-schedule .ha-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 24px;
  border-radius: 6px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
}
body.route-schedule .ha-badge.home {
  background: var(--sched-ice-soft);
  color: var(--sched-ice);
  border: 1px solid var(--sched-ice-glow);
}
body.route-schedule .ha-badge.away {
  background: var(--sched-loss-soft);
  color: var(--sched-loss);
  border: 1px solid rgba(217, 73, 41, 0.2);
}

/* Score */
body.route-schedule .score-cell {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 15px;
  font-weight: 600;
}
body.route-schedule .score-cell .score-dash { color: var(--text-dim); }
body.route-schedule .score-cell.loss .score-our { color: var(--text-dim); }
body.route-schedule .score-cell.unplayed { color: var(--text-dim); font-weight: 500; }

/* Result badge */
body.route-schedule .result-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 24px;
  padding: 0 8px;
  border-radius: 6px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
}
body.route-schedule .result-badge.w {
  background: var(--sched-mint-soft);
  color: var(--sched-mint);
  border: 1px solid rgba(34, 160, 107, 0.3);
}
body.route-schedule .result-badge.l {
  background: var(--sched-loss-soft);
  color: var(--sched-loss);
  border: 1px solid rgba(217, 73, 41, 0.25);
}
body.route-schedule .result-badge.t {
  background: var(--sched-warm-soft);
  color: var(--sched-warm);
  border: 1px solid rgba(232, 144, 67, 0.3);
}
body.route-schedule .result-empty {
  color: var(--text-dim);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 14px;
}

/* Action buttons */
body.route-schedule .actions-cell, body.route-roster .actions-cell {
  display: flex;
  gap: 6px;
  justify-content: flex-end;
  align-items: center;
  flex-wrap: wrap;
}
body.route-schedule .action-btn, body.route-roster .action-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background-color .12s, border-color .12s, color .12s;
  font-weight: 500;
}
body.route-schedule .action-btn:hover, body.route-roster .action-btn:hover {
  background: var(--bg-soft);
  color: var(--text);
}
body.route-schedule .action-btn svg, body.route-roster .action-btn svg { width: 12px; height: 12px; }
body.route-schedule .action-btn.primary, body.route-roster .action-btn.primary {
  color: var(--sched-ice);
  border-color: rgba(30, 111, 191, 0.3);
  background: var(--sched-ice-soft);
  font-weight: 600;
}
body.route-schedule .action-btn.primary:hover, body.route-roster .action-btn.primary:hover {
  background: var(--sched-ice-glow);
  border-color: var(--sched-ice);
}

/* Mobile */
@media (max-width: 1024px) {
  body.route-schedule .stats-strip, body.route-roster .stats-strip { grid-template-columns: repeat(2, 1fr); }
  body.route-schedule .schedule-table th:nth-child(4),
  body.route-schedule .schedule-table td:nth-child(4),
  body.route-schedule .schedule-table th:nth-child(5),
  body.route-schedule .schedule-table td:nth-child(5) { display: none; }
}
@media (max-width: 640px) {
  body.route-schedule .stats-strip, body.route-roster .stats-strip { grid-template-columns: 1fr; }
  body.route-schedule .schedule-table th:nth-child(6),
  body.route-schedule .schedule-table td:nth-child(6) { display: none; }
}

/* ============================================================
   iPad toolbar scroll — explicit max-height so overflow engages
   ============================================================
   The base .toolbar uses overflow-y: auto + min-height: 0, which works
   on desktop Safari/Chrome but iOS Safari doesn't reliably pin the
   grid-item to its cell height, so the toolbar grows to fit content
   and there's nothing to scroll. Explicit max-height forces the
   issue — once the box is a fixed size, overflow-y: auto produces a
   real scroll region.
   The calc reserves room for: topnav 52 + topbar ~48 + drill-tabs 34
   + ~8 padding = ~142px of chrome above the toolbar. Uses dvh so iOS
   Safari's URL-bar-aware viewport height is honoured (vh would over-
   shoot when the URL bar is visible).
*/
@media (max-width: 1366px) {
  body.route-drill .toolbar {
    max-height: calc(100vh - 142px);   /* fallback for pre-dvh iOS */
  }
}
@supports (height: 100dvh) {
  @media (max-width: 1366px) {
    body.route-drill .toolbar {
      max-height: calc(100dvh - 142px);
    }
  }
}

/* ============================================================
   ROSTER REDESIGN (route /roster) — 2026-05-21
   ============================================================
   Shares the --rb-* palette and the stats-strip/table-card/action-btn
   primitives with the schedule. Adds roster-specific bits: a jersey
   disc on each row (colour matches the player's position group),
   a position pill, and a star-rating preview. */
body.route-roster .roster-group { padding: 0; }
body.route-roster .roster-group + .roster-group {
  border-top: 1px solid var(--border-soft);
}
body.route-roster .roster-group-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 18px 24px 10px;
  font-family: 'Instrument Sans', 'Geist', sans-serif;
  font-size: 18px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text);
}
body.route-roster .roster-group-head .count {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

body.route-roster .roster-table {
  width: 100%;
  border-collapse: collapse;
}
body.route-roster .roster-table tbody tr {
  border-top: 1px solid var(--border-soft);
  transition: background-color .12s;
}
body.route-roster .roster-table tbody tr:hover { background: var(--bg-soft); }
body.route-roster .roster-table td {
  padding: 14px 16px;
  font-size: 14px;
  vertical-align: middle;
  color: var(--text);
}
body.route-roster .roster-table td:first-child { padding-left: 24px; }
body.route-roster .roster-table td:last-child { padding-right: 24px; text-align: right; }

/* Jersey disc — number in a coloured circle. Colour comes from the
 * player's position group via .pos-fwd / .pos-def / .pos-gk. */
body.route-roster .jersey-disc {
  width: 36px; height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  flex-shrink: 0;
  background: var(--text-dim);
}
body.route-roster .jersey-disc.pos-fwd { background: var(--rb-ice); }
body.route-roster .jersey-disc.pos-def { background: var(--rb-loss); }
body.route-roster .jersey-disc.pos-gk  { background: var(--rb-mint); }
body.route-roster .jersey-disc.no-number {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* Player name cell — same visual rhythm as the schedule's opponent-cell. */
body.route-roster .player-cell {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
body.route-roster .player-cell .player-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
body.route-roster .player-cell .player-name {
  font-family: 'Instrument Sans', 'Geist', sans-serif;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--text);
}
body.route-roster .player-cell .player-sub {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--text-dim);
}

/* Position pill — small badge in the position-group colour. */
body.route-roster .pos-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 22px;
  padding: 0 8px;
  border-radius: 6px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
}
body.route-roster .pos-pill.pos-fwd {
  background: var(--rb-ice-soft);
  color: var(--rb-ice);
  border: 1px solid var(--rb-ice-glow);
}
body.route-roster .pos-pill.pos-def {
  background: var(--rb-loss-soft);
  color: var(--rb-loss);
  border: 1px solid rgba(217, 73, 41, 0.2);
}
body.route-roster .pos-pill.pos-gk {
  background: var(--rb-mint-soft);
  color: var(--rb-mint);
  border: 1px solid rgba(34, 160, 107, 0.3);
}
body.route-roster .pos-pill.pos-none {
  background: var(--bg-soft);
  color: var(--text-dim);
  border: 1px solid var(--border-soft);
}

/* Shoots badge — single-char L/R indicator. */
body.route-roster .shoots-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 5px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 700;
  background: var(--bg-soft);
  color: var(--text);
  border: 1px solid var(--border-soft);
}
body.route-roster .shoots-empty {
  color: var(--text-dim);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px;
}

/* Star-rating preview — average across categories shown as 5 stars +
 * numeric. Filled stars warm-orange, empty stars border-grey. */
body.route-roster .star-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
body.route-roster .star-row .stars {
  display: inline-flex;
  gap: 1px;
  color: var(--rb-warm);
}
body.route-roster .star-row svg { width: 12px; height: 12px; }
body.route-roster .star-row svg.empty { color: var(--border); }
body.route-roster .star-row .rating-num {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--text-dim);
}
body.route-roster .star-row.empty {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px;
  color: var(--text-dim);
}

/* Search input inside the roster table header */
/* Player count chip beside the "Team Roster" title. */
body.route-roster .roster-count {
  font: 600 14px/1 Geist, system-ui, sans-serif;
  color: var(--text-dim);
  margin-left: 8px;
  vertical-align: middle;
}
body.route-roster .page-actions { align-items: center; }

body.route-roster .roster-search {
  position: relative;
  display: inline-flex;
  align-items: center;
}
body.route-roster .roster-search svg {
  position: absolute;
  left: 10px;
  width: 14px; height: 14px;
  color: var(--text-dim);
  pointer-events: none;
}
body.route-roster .roster-search input {
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 8px 12px 8px 32px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
  width: 240px;
  transition: border-color .15s, background-color .15s;
}
body.route-roster .roster-search input:focus {
  outline: none;
  border-color: var(--rb-ice);
  background: var(--bg);
  box-shadow: 0 0 0 3px var(--rb-ice-soft);
}

/* Mobile: hide ratings + shoots so the row stays readable */
@media (max-width: 1024px) {
  body.route-roster .roster-table th:nth-child(4),
  body.route-roster .roster-table td:nth-child(4),
  body.route-roster .roster-table th:nth-child(5),
  body.route-roster .roster-table td:nth-child(5) { display: none; }
}

/* ============================================================
   /admin/ads — platform-admin sponsor CRUD. Two-column layout:
   list of ads on the left, inline edit drawer on the right.
   ============================================================ */
body.route-admin-ads .admin-ads-layout {
  display: grid;
  grid-template-columns: 1fr 460px;
  gap: 24px;
  align-items: start;
}
@media (max-width: 1100px) {
  body.route-admin-ads .admin-ads-layout { grid-template-columns: 1fr; }
}
body.route-admin-ads .admin-ads-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
body.route-admin-ads .admin-ads-empty {
  padding: 48px 20px;
  border: 1px dashed var(--border-soft);
  border-radius: 14px;
  text-align: center;
  color: var(--text-dim);
}
body.route-admin-ads .admin-ads-row {
  appearance: none;
  background: white;
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 14px;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition: background .12s, border-color .12s, transform .12s;
}
body.route-admin-ads .admin-ads-row:hover {
  background: var(--bg-soft);
  border-color: var(--border);
}
body.route-admin-ads .admin-ads-row-logo {
  width: 48px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--bg-soft);
  border-radius: 6px;
  overflow: hidden;
}
body.route-admin-ads .admin-ads-row-logo img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
body.route-admin-ads .admin-ads-row-main { flex: 1; min-width: 0; }
body.route-admin-ads .admin-ads-row-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.route-admin-ads .admin-ads-row-meta {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 2px;
}
body.route-admin-ads .admin-ads-pill {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  background: var(--bg-soft);
  color: var(--text-dim);
  padding: 3px 9px;
  border-radius: 999px;
}
body.route-admin-ads .admin-ads-pill--on {
  background: color-mix(in srgb, var(--brand-secondary) 14%, white);
  color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
}
body.route-admin-ads .admin-ads-edit {
  position: sticky;
  top: 24px;
  background: white;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 20px;
}
@media (max-width: 1100px) {
  body.route-admin-ads .admin-ads-edit { position: static; }
}
body.route-admin-ads .admin-ads-edit-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}
body.route-admin-ads .admin-ads-edit-head h2 { margin: 0; font-size: 17px; }
body.route-admin-ads .admin-ads-edit .field { display: block; margin-bottom: 12px; }
body.route-admin-ads .admin-ads-edit .field > span {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  margin-bottom: 4px;
}
body.route-admin-ads .admin-ads-edit .field input,
body.route-admin-ads .admin-ads-edit .field select {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  font-size: 13.5px;
  font-family: inherit;
  background: white;
  color: var(--text);
}
body.route-admin-ads .admin-ads-edit .field input:focus,
body.route-admin-ads .admin-ads-edit .field select:focus {
  outline: none;
  border-color: var(--brand-secondary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-secondary) 12%, transparent);
}
body.route-admin-ads .admin-ads-edit .field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
body.route-admin-ads .admin-ads-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
}
body.route-admin-ads .admin-ads-actions .btn-danger {
  background: var(--red);
  color: white;
  border: none;
}

/* Logo upload — preview swatch on the left, buttons + hint on the
   right, external-URL paste-in below. Both feed the same hidden
   #ad-logo field (the canonical submitted value). */
body.route-admin-ads .admin-ads-logo-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 8px;
}
body.route-admin-ads .admin-ads-logo-preview {
  flex-shrink: 0;
  width: 88px;
  height: 56px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background:
    repeating-conic-gradient(#f3f4f6 0% 25%, #ffffff 0% 50%) 0 0 / 12px 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
body.route-admin-ads .admin-ads-logo-preview img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
body.route-admin-ads .admin-ads-logo-placeholder {
  font-size: 11px;
  color: var(--text-dim);
}
body.route-admin-ads .admin-ads-logo-controls {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
body.route-admin-ads .admin-ads-logo-controls .btn {
  padding: 6px 12px;
  font-size: 12.5px;
}
body.route-admin-ads .admin-ads-logo-hint {
  font-size: 11px;
  color: var(--text-dim);
}

/* Aggregate stats baked into each list row (lifetime totals). */
body.route-admin-ads .admin-ads-row-stats {
  display: flex;
  gap: 10px;
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 6px;
}

/* Edit-drawer performance panel. */
body.route-admin-ads .admin-ads-stats {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
}
body.route-admin-ads .admin-ads-stats-head {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  margin-bottom: 10px;
}
body.route-admin-ads .admin-ads-stats-totals {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}
body.route-admin-ads .admin-ads-stat {
  background: var(--bg-soft);
  border-radius: 8px;
  padding: 10px 12px;
  text-align: left;
}
body.route-admin-ads .admin-ads-stat-n {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.1;
}
body.route-admin-ads .admin-ads-stat-l {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 2px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
body.route-admin-ads .admin-ads-stats-chart {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 70px;
  margin-bottom: 6px;
  overflow-x: auto;
}
body.route-admin-ads .admin-ads-bar {
  position: relative;
  flex: 1 0 14px;
  min-width: 14px;
  max-width: 28px;
  height: 100%;
  display: flex;
  flex-direction: column-reverse;
  align-items: stretch;
  border-radius: 3px 3px 0 0;
  background: linear-gradient(to top, var(--bg-soft) 0%, var(--bg-soft) 100%);
}
body.route-admin-ads .admin-ads-bar-imp {
  width: 100%;
  background: color-mix(in srgb, var(--brand-secondary) 30%, white);
  border-radius: 3px 3px 0 0;
  min-height: 1px;
}
body.route-admin-ads .admin-ads-bar-clk {
  width: 100%;
  background: var(--brand-secondary);
  border-radius: 3px 3px 0 0;
  position: absolute;
  bottom: 0;
  left: 0;
  min-height: 1px;
}
body.route-admin-ads .admin-ads-bar-day {
  position: absolute;
  bottom: -16px;
  left: 0;
  right: 0;
  font-size: 9px;
  color: var(--text-dim);
  text-align: center;
  line-height: 1;
}
body.route-admin-ads .admin-ads-stats-sub {
  margin-top: 18px;
  font-size: 11px;
  color: var(--text-dim);
}
body.route-admin-ads .admin-ads-stats-empty {
  width: 100%;
  text-align: center;
  font-size: 12px;
  color: var(--text-dim);
  padding: 18px;
}

/* ============================================================
   "Powered by" sponsor pill — shared across every placement.
   Slot wrappers position the pill; .pc-ad styles the pill itself.
   Slot is empty (zero height) until ads.js fills it; that prevents
   layout shift when there's nothing to render for a team.
   2026-05-26.
   ============================================================ */
.pc-ad-slot {
  /* Empty until populated — the .pc-ad-slot--filled class is added by
     ads.js once an ad lands so we don't bake in vertical space for
     teams in regions with no inventory. */
  min-height: 0;
}
.pc-ad-slot--filled {
  /* Just enough padding for the pill to breathe without crowding the
     surrounding UI. Page-specific placements can override. */
  padding: 6px 0;
}
/* Base .pc-ad — neutral layout + transitions. Colors come from the
   on-light / on-dark variants below; ads.js stamps the appropriate
   class on the slot after reading the effective background luminance.
   This keeps the pill legible whether it sits on a white dashboard
   card or a team-branded topbar in literally any colour the coach
   has picked. */
.pc-ad {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 12.5px;
  text-decoration: none;
  transition: background .15s, border-color .15s, transform .15s, color .15s;
  font-family: inherit;
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
}
.pc-ad:hover { transform: translateY(-1px); }
.pc-ad-label {
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  flex-shrink: 0;
}
.pc-ad-logo {
  height: 20px;
  width: auto;
  max-width: 80px;
  object-fit: contain;
  flex-shrink: 0;
}
.pc-ad-sponsor {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Light-background variant — dark text reads on white-ish surfaces
   like the dashboard hero, share page, and any light card. This is
   the default until JS finishes the contrast check; default avoids a
   flash-of-invisible text on the common case (most pages are light). */
.pc-ad-slot--on-light .pc-ad,
.pc-ad-slot:not(.pc-ad-slot--on-dark) .pc-ad {
  background: rgba(255, 255, 255, 0.78);
  border-color: var(--border-soft);
  color: var(--text);
}
.pc-ad-slot--on-light .pc-ad:hover,
.pc-ad-slot:not(.pc-ad-slot--on-dark) .pc-ad:hover {
  background: white;
  border-color: var(--border);
}
.pc-ad-slot--on-light .pc-ad-label,
.pc-ad-slot:not(.pc-ad-slot--on-dark) .pc-ad-label {
  color: var(--text-dim);
}
.pc-ad-slot--on-light .pc-ad-sponsor,
.pc-ad-slot:not(.pc-ad-slot--on-dark) .pc-ad-sponsor {
  color: var(--text);
}

/* Dark-background variant — light text. Activated when the slot's
   computed background is dark (luminance < 0.55), e.g. the drill
   board topbar's team panel_color. Pill background stays mostly
   transparent so the team brand colour shows through. */
.pc-ad-slot--on-dark .pc-ad {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.18);
  color: rgba(255, 255, 255, 0.92);
}
.pc-ad-slot--on-dark .pc-ad:hover {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.32);
}
.pc-ad-slot--on-dark .pc-ad-label { color: rgba(255, 255, 255, 0.6); }
.pc-ad-slot--on-dark .pc-ad-sponsor { color: white; }

/* Dashboard slot: centered between the hero and the widget grid. */
.dash-sponsor.pc-ad-slot--filled {
  display: flex;
  justify-content: center;
  margin: 8px 0 16px;
}

/* Share page slot: centered under the share card. */
.share-sponsor.pc-ad-slot--filled {
  display: flex;
  justify-content: center;
  margin-top: 24px;
}

/* Drill board slot — compact sizing inside the dense topbar; colors
   are inherited from whichever on-light/on-dark variant ads.js picks. */
#ad-slot-drillboard.pc-ad-slot--filled {
  padding: 0;
  display: flex;
  align-items: center;
}
#ad-slot-drillboard .pc-ad {
  padding: 4px 10px;
  font-size: 11.5px;
}
#ad-slot-drillboard .pc-ad-logo { height: 16px; }

/* ============================================================
   Plans v3 — bookshelf of clipboard-style plan cards.
   2026-05-26. Replaces the old `.plan-card` grid (which is still
   styled higher up in this file and used by the editor sidebar /
   PDF preview — leave those rules alone).
   ============================================================ */

/* Toolbar (search + book filter chips + sort) */
.plans-page .plans-toolbar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 22px;
}
.plans-page .plans-search {
  position: relative;
}
.plans-page .plans-search input {
  width: 100%;
  padding: 11px 14px 11px 42px;
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  background: white;
  font-size: 14.5px;
  font-family: inherit;
  color: var(--text);
  outline: none;
  transition: border-color .12s, box-shadow .12s;
}
.plans-page .plans-search input:focus {
  border-color: var(--brand-secondary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-secondary) 12%, transparent);
}
.plans-page .plans-search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 17px;
  height: 17px;
  color: var(--text-dim);
  pointer-events: none;
}
.plans-page .plans-toolbar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.plans-page .plans-book-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.plans-page .plans-book-chip {
  padding: 6px 12px;
  border: 1px solid var(--border-soft);
  background: white;
  color: var(--text);
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background .12s, border-color .12s, color .12s;
}
.plans-page .plans-book-chip:hover {
  background: var(--bg-soft);
  border-color: var(--border);
}
.plans-page .plans-book-chip.is-active {
  background: var(--brand-secondary);
  border-color: var(--brand-secondary);
  color: white;
}
.plans-page .plans-book-chip-count {
  font-size: 10.5px;
  font-weight: 700;
  background: var(--bg-soft);
  color: var(--text-dim);
  padding: 1px 7px;
  border-radius: 999px;
  min-width: 20px;
  text-align: center;
}
.plans-page .plans-book-chip.is-active .plans-book-chip-count {
  background: rgba(255, 255, 255, 0.22);
  color: white;
}
.plans-page .plans-sort {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--text-dim);
  flex-shrink: 0;
}
.plans-page .plans-sort-label {
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: 0.6px;
}
.plans-page .plans-sort-select {
  padding: 7px 10px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: white;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
}

/* Override the legacy `#plan-grid` (which was a CSS grid for the old
   .plan-card layout). Plans v3 lays shelves out as a vertical stack, so
   we need plain block flow here. */
.plans-page #plan-grid {
  display: block;
}

/* Bookshelf — each `.plans-shelf` is one book worth of clipboards. */
.plans-shelf {
  margin-bottom: 36px;
  position: relative;
}
.plans-shelf-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 18px;
}
.plans-shelf-title {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  margin: 0;
  letter-spacing: -0.005em;
}
.plans-shelf-count {
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 600;
}
.plans-shelf-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 24px 18px;
  align-items: end;
}
/* The "shelf floor" — a thin horizontal rule below each row that
   suggests a physical shelf without going full wood-grain. Subtle
   gradient hints at depth so the clipboards feel like they're
   resting on something. */
.plans-shelf-floor {
  height: 6px;
  margin-top: 14px;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--text-dim) 35%, transparent) 0%,
    color-mix(in srgb, var(--text-dim) 14%, transparent) 35%,
    transparent 100%
  );
  border-radius: 3px 3px 0 0;
}

/* The clipboard — paper-feeling card with a clip detail at the top
   and the first drill's thumbnail as the cover. Skeuomorphic but
   restrained: no wood-grain background, no 3D clip, just enough
   metaphor for a hockey coach to recognise. */
.plan-clip {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #fbfaf6;             /* off-white paper tone */
  border: 1px solid #d8d5cc;       /* subtle paper edge */
  border-radius: 4px 4px 8px 8px;  /* sharper top, rounded bottom */
  padding-top: 22px;               /* space for the clip band */
  cursor: pointer;
  box-shadow: 0 4px 0 -2px #d8d5cc,
              0 8px 18px -8px rgba(0, 0, 0, 0.18);
  transition: transform .15s ease, box-shadow .15s ease;
  outline: none;
}
.plan-clip:hover {
  transform: translateY(-3px);
  box-shadow: 0 6px 0 -2px #d8d5cc,
              0 16px 28px -10px rgba(0, 0, 0, 0.22);
}
.plan-clip:focus-visible {
  border-color: var(--brand-secondary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-secondary) 22%, transparent),
              0 6px 0 -2px #d8d5cc,
              0 16px 28px -10px rgba(0, 0, 0, 0.22);
}

/* Top band — the metal/paper clip. A thin gradient strip with a
   small notch in the centre. Reads as a clip without the cartoonish
   3D dome of the MyDrillBook clipboards. */
.plan-clip-top {
  position: absolute;
  top: -6px;
  left: 0;
  right: 0;
  height: 18px;
  display: flex;
  justify-content: center;
  pointer-events: none;
  z-index: 2;
}
.plan-clip-clip {
  width: 64px;
  height: 18px;
  background: linear-gradient(
    180deg,
    #cfd2d8 0%, #aaaeb6 40%, #898d96 70%, #6f7380 100%
  );
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(0, 0, 0, 0.18),
    0 2px 4px -1px rgba(0, 0, 0, 0.3);
  position: relative;
}
.plan-clip-clip::after {
  /* The pin-hole / spring detail in the middle of the clip */
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 8px; height: 8px;
  background: #4d505b;
  border-radius: 50%;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

/* The "page" — text-centric clipboard surface. Plan title is the
   dominant element; age + drill count + total min sit below; a small
   abstract hockey diagram sits at the bottom as decoration (not a
   thumbnail of the actual drill — coaches asked for the
   MyDrillBook-style generic graphic instead). */
.plan-clip-page {
  position: relative;
  margin: 0 8px;
  aspect-ratio: 16 / 13;     /* tall-ish so the title has room */
  background: white;
  border: 1px solid #e9e7df;
  border-radius: 3px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 14px 14px 0;
}
.plan-clip-page-title {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.22;
  color: var(--text);
  letter-spacing: -0.005em;
  /* Two-line clamp so titles stay readable even when long. */
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
.plan-clip-page-title > span {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
.plan-clip-page-meta {
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--text-dim);
  font-weight: 600;
  letter-spacing: 0.2px;
}
.plan-clip-page-diagram {
  margin-top: auto;          /* pin to bottom of the page */
  padding-top: 8px;
  opacity: 0.78;
}
.plan-clip-page-diagram svg {
  width: 100%;
  height: auto;
  display: block;
}
.plan-clip-upcoming {
  position: absolute;
  top: 8px;
  left: 8px;
  background: var(--green, #1f9e5a);
  color: white;
  font-size: 10.5px;
  font-weight: 700;
  padding: 3px 8px 3px 6px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  letter-spacing: 0.3px;
}
.plan-clip-upcoming svg { width: 11px; height: 11px; }

/* Hover-revealed action overlay on the page. Run is the primary
   action and gets brand red; share + delete are neutral. */
.plan-clip-actions {
  position: absolute;
  bottom: 8px;
  right: 8px;
  display: flex;
  gap: 6px;
  opacity: 0;
  transition: opacity .15s;
}
.plan-clip:hover .plan-clip-actions,
.plan-clip:focus-within .plan-clip-actions {
  opacity: 1;
}
.plan-clip-action {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.95);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
  transition: transform .12s, background .12s, color .12s;
}
.plan-clip-action:hover { transform: scale(1.06); }
.plan-clip-action svg { width: 14px; height: 14px; }
.plan-clip-action--run { background: var(--red, #d4302b); color: white; }
.plan-clip-action--del:hover { background: var(--red, #d4302b); color: white; }

/* Footer — date / book context. Only rendered when one is present;
   plan name + age + drill count live ON the page above. */
.plan-clip-foot {
  padding: 10px 12px 12px;
}
.plan-clip-meta {
  font-size: 11.5px;
  color: var(--text-dim);
  line-height: 1.4;
}
.plan-clip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.plan-clip-dot--visible { background: var(--brand-secondary, #1e6fbf); }
.plan-clip-dot--private { background: #b59500; }

/* Upcoming plans get a subtle green hint on the paper edge */
.plan-clip--upcoming {
  border-color: color-mix(in srgb, var(--green, #1f9e5a) 50%, #d8d5cc);
}
.plan-clip--shared {
  border-color: color-mix(in srgb, var(--brand-secondary, #1e6fbf) 35%, #d8d5cc);
}

/* Mobile / narrow viewport — clipboards shrink, shelves keep their
   rhythm but rows allow wrapping. */
@media (max-width: 720px) {
  .plans-shelf-row {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 18px 12px;
  }
  .plan-clip-foot { padding: 10px 10px 12px; }
  .plan-clip-title { font-size: 13px; }
  .plan-clip-meta { font-size: 11px; }
}

/* ============================================================
   /vault — coach-facing browse for platform-curated content.
   Phase 1: drills only. Card design borrows from /library/drills
   but adds claim affordances + featured/popular badges.
   2026-05-26.
   ============================================================ */
body.route-vault .vault-toolbar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 24px;
}
body.route-vault .vault-search {
  position: relative;
}
body.route-vault .vault-search input {
  width: 100%;
  padding: 11px 14px 11px 42px;
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  background: white;
  font-size: 14.5px;
  font-family: inherit;
  color: var(--text);
  outline: none;
  transition: border-color .12s, box-shadow .12s;
}
body.route-vault .vault-search input:focus {
  border-color: var(--brand-secondary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-secondary) 12%, transparent);
}
body.route-vault .vault-search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 17px;
  height: 17px;
  color: var(--text-dim);
  pointer-events: none;
}
body.route-vault .vault-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
body.route-vault .vault-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
body.route-vault .vault-chip {
  padding: 6px 12px;
  border: 1px solid var(--border-soft);
  background: white;
  color: var(--text);
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: background .12s, border-color .12s, color .12s;
}
body.route-vault .vault-chip:hover {
  background: var(--bg-soft);
  border-color: var(--border);
}
body.route-vault .vault-chip.is-active {
  background: var(--brand-secondary);
  border-color: var(--brand-secondary);
  color: white;
}
body.route-vault .vault-sort {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--text-dim);
}
body.route-vault .vault-sort-label {
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: 0.6px;
}
body.route-vault .vault-sort-select {
  padding: 7px 10px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: white;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
}

body.route-vault .vault-section { margin-bottom: 36px; }
body.route-vault .vault-section-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 16px;
}
body.route-vault .vault-section-title {
  font-size: 17px;
  font-weight: 700;
  margin: 0;
  color: var(--text);
}
body.route-vault .vault-section-sub {
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 500;
}
body.route-vault .vault-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 18px;
}
body.route-vault .vault-card {
  appearance: none;
  background: white;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  overflow: hidden;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  padding: 0;
  font-family: inherit;
  transition: box-shadow .15s, transform .15s, border-color .15s;
}
body.route-vault .vault-card:hover {
  box-shadow: 0 14px 32px -14px rgba(0, 0, 0, 0.16);
  transform: translateY(-2px);
  border-color: var(--border);
}
body.route-vault .vault-card.is-claimed {
  border-color: color-mix(in srgb, var(--brand-secondary) 50%, var(--border-soft));
}
body.route-vault .vault-card-thumb {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--bg-soft);
  overflow: hidden;
}
body.route-vault .vault-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
body.route-vault .vault-card-thumb--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  font-size: 11px;
}
body.route-vault .vault-card-featured {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: #ffd64a;
  color: #5a4400;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
body.route-vault .vault-card-claimed {
  position: absolute;
  bottom: 8px;
  right: 8px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  background: var(--brand-secondary);
  color: white;
  padding: 3px 8px;
  border-radius: 999px;
  text-transform: uppercase;
}
body.route-vault .vault-card-body {
  padding: 12px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
}
body.route-vault .vault-card-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.route-vault .vault-card-ages {
  font-size: 11.5px;
  color: var(--text-dim);
  font-weight: 600;
}
body.route-vault .vault-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 2px;
}
body.route-vault .vault-card-tag {
  background: color-mix(in srgb, var(--brand-secondary) 12%, white);
  color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 500;
}
body.route-vault .vault-card-claimcount {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 4px;
}

body.route-vault .vault-empty {
  text-align: center;
  padding: 60px 20px;
  color: var(--text-dim);
}
body.route-vault .vault-empty-icon { font-size: 40px; margin-bottom: 12px; }
body.route-vault .vault-empty-title { font-size: 16px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
body.route-vault .vault-empty-sub   { font-size: 13px; }

/* Detail modal */
.vault-modal { display: none; }
.vault-modal:not([hidden]) { display: grid; place-items: center; }
.vault-modal-card {
  width: 600px;
  max-width: 92vw;
  max-height: 88vh;
  overflow-y: auto;
  position: relative;
}
.vault-modal-close {
  position: absolute;
  top: 10px; right: 14px;
  background: none;
  border: none;
  font-size: 28px;
  color: var(--text-dim);
  cursor: pointer;
  line-height: 1;
}
.vault-modal-close:hover { color: var(--text); }
.vault-modal-thumb {
  width: 100%;
  max-height: 360px;
  object-fit: contain;
  background: var(--bg-soft);
  border-radius: 10px;
  margin-bottom: 14px;
}
.vault-modal-name { margin: 6px 0 4px !important; }
.vault-modal-meta {
  font-size: 12.5px;
  color: var(--text-dim);
  font-weight: 600;
}
.vault-modal-desc {
  margin-top: 14px;
  font-size: 13.5px;
  color: var(--text);
  line-height: 1.5;
}
.vault-modal-actions {
  margin-top: 22px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}
.vault-modal-actions .btn,
.vault-modal-actions .btn-primary {
  align-self: flex-end;
}
.vault-claim-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 16px;
  background: color-mix(in srgb, var(--brand-secondary) 7%, white);
  border: 1px solid color-mix(in srgb, var(--brand-secondary) 18%, transparent);
  border-radius: 10px;
}
.vault-claim-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text);
  cursor: pointer;
}
.vault-claim-opt input[type="checkbox"] {
  width: 16px; height: 16px;
  accent-color: var(--brand-secondary);
  cursor: pointer;
}
.vault-claim-opt.is-disabled {
  color: var(--text-dim);
  cursor: not-allowed;
}
.vault-claim-opt.is-disabled input { cursor: not-allowed; }
body.route-vault .vault-card-claimed--team {
  background: color-mix(in srgb, var(--brand-primary, #1f5fff) 80%, #000);
}
body.route-vault .vault-card-claimed--both {
  background: linear-gradient(135deg,
    var(--brand-secondary) 0 50%,
    color-mix(in srgb, var(--brand-primary, #1f5fff) 80%, #000) 50% 100%);
}
.vault-modal-loading,
.vault-modal-error {
  padding: 30px;
  text-align: center;
  color: var(--text-dim);
}

/* Type tabs (Drills | Plans) — shared by /vault and /admin/vault */
body.route-vault .vault-type-tabs,
body.route-admin-vault .vault-type-tabs {
  display: flex;
  gap: 4px;
  margin: -8px 0 18px;
  border-bottom: 1px solid var(--border, #e5e5ea);
  padding-bottom: 0;
}
body.route-vault .vault-type-tab,
body.route-admin-vault .vault-type-tab {
  appearance: none;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  padding: 12px 18px 11px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-dim);
  cursor: pointer;
  margin-bottom: -1px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: color 120ms, border-color 120ms;
}
body.route-vault .vault-type-tab:hover,
body.route-admin-vault .vault-type-tab:hover {
  color: var(--text);
}
body.route-vault .vault-type-tab.is-active,
body.route-admin-vault .vault-type-tab.is-active {
  color: var(--brand-secondary);
  border-bottom-color: var(--brand-secondary);
}
body.route-vault .vault-type-count,
body.route-admin-vault .vault-type-count {
  font-size: 11.5px;
  padding: 2px 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--brand-secondary) 10%, transparent);
  color: var(--text-dim);
  min-width: 18px;
  text-align: center;
}
body.route-vault .vault-type-tab.is-active .vault-type-count,
body.route-admin-vault .vault-type-tab.is-active .vault-type-count {
  background: var(--brand-secondary);
  color: white;
}

/* Plan card — text-first clipboard look */
body.route-vault .vault-plan-card .vault-plan-clip {
  background: linear-gradient(180deg, #fff 0%, #fafaf6 100%);
  border: 1px solid color-mix(in srgb, var(--brand-secondary) 22%, #d8d4c4);
  border-top: 6px solid color-mix(in srgb, var(--brand-secondary) 70%, #b8a050);
  padding: 30px 16px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  position: relative;
  min-height: 170px;
  border-radius: 6px 6px 0 0;
}
/* Push the featured ★ out to the corner so it doesn't overlap the eyebrow. */
body.route-vault .vault-plan-card .vault-card-featured {
  top: 12px;
  left: 12px;
  position: absolute;
  z-index: 2;
}
body.route-vault .vault-plan-clip-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  padding-left: 30px;
}
body.route-vault .vault-plan-clip-eyebrow {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--brand-secondary) 75%, #000);
}
body.route-vault .vault-plan-clip-age {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--brand-secondary) 8%, white);
  padding: 2px 8px;
  border-radius: 999px;
}
body.route-vault .vault-plan-clip-name {
  font-size: 17px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text);
  margin-top: 2px;
}
body.route-vault .vault-plan-clip-meta {
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 600;
  margin-top: auto;
  padding-top: 8px;
}

/* Plan detail modal: drill list */
.vault-plan-drills {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid var(--border, #e5e5ea);
  padding-top: 14px;
}
.vault-plan-drill {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 4px;
}
.vault-plan-drill-num {
  width: 22px; height: 22px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--brand-secondary) 14%, white);
  color: color-mix(in srgb, var(--brand-secondary) 85%, #000);
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.vault-plan-drill-thumb {
  width: 64px; height: 40px;
  object-fit: cover;
  border-radius: 4px;
  background: var(--bg-soft);
}
.vault-plan-drill-thumb--empty {
  background: repeating-linear-gradient(45deg, #f0eee5, #f0eee5 6px, #e8e6dc 6px, #e8e6dc 12px);
}
.vault-plan-drill-meta { flex: 1; min-width: 0; }
.vault-plan-drill-name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vault-plan-drill-sub {
  font-size: 11.5px;
  color: var(--text-dim);
}
.vault-modal-notes {
  margin-top: 14px;
  padding: 12px 14px;
  background: color-mix(in srgb, var(--brand-secondary) 6%, white);
  border-left: 3px solid var(--brand-secondary);
  border-radius: 4px;
  font-size: 13px;
  color: var(--text);
  line-height: 1.5;
}
.vault-modal-notes strong {
  display: block;
  font-size: 11px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 4px;
}
.vault-claim-opt-readonly {
  font-size: 13px;
  color: var(--text);
  padding: 4px 0 4px;
}

/* --- Loading states ------------------------------------------ */
/* Single keyframe powers skeletons + per-card thumb spinner. */
@keyframes vault-pulse {
  0%   { opacity: 0.55; }
  50%  { opacity: 1; }
  100% { opacity: 0.55; }
}
@keyframes vault-spin {
  to { transform: rotate(360deg); }
}

/* Skeleton card (gridded placeholder while we wait for /list to return) */
body.route-vault .vault-card-skeleton {
  pointer-events: none;
  cursor: default;
  background: var(--card-bg, white);
  border: 1px solid var(--border, #e5e5ea);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
body.route-vault .vault-card-skeleton .vault-skel-thumb {
  aspect-ratio: 16 / 10;
  background: linear-gradient(90deg, #ececec 0%, #f5f5f5 50%, #ececec 100%);
  background-size: 200% 100%;
  animation: vault-skel-shimmer 1.4s ease-in-out infinite;
}
body.route-vault .vault-card-skeleton.vault-plan-card .vault-skel-thumb {
  /* Plan cards don't have a thumb area — substitute a tall block */
  aspect-ratio: 16 / 9;
}
body.route-vault .vault-skel-line {
  height: 10px;
  border-radius: 6px;
  background: linear-gradient(90deg, #ececec 0%, #f5f5f5 50%, #ececec 100%);
  background-size: 200% 100%;
  animation: vault-skel-shimmer 1.4s ease-in-out infinite;
  margin: 6px 0;
}
body.route-vault .vault-skel-line--name { width: 75%; height: 14px; }
body.route-vault .vault-skel-line--meta { width: 50%; }
@keyframes vault-skel-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Per-card thumb spinner — visible while the batched /thumbs request
 * is in flight. The <img> is hidden until its src is set. */
body.route-vault .vault-card-thumb--loading .vault-card-thumb-img {
  display: none;
}
body.route-vault .vault-card-thumb-spinner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(45deg, #f4f4f0, #f4f4f0 8px, #ececec 8px, #ececec 16px);
  background-size: 22px 22px;
  animation: vault-pulse 1.2s ease-in-out infinite;
}
body.route-vault .vault-card-thumb-spinner::after {
  content: '';
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2.5px solid color-mix(in srgb, var(--brand-secondary) 28%, #e5e5ea);
  border-top-color: var(--brand-secondary);
  animation: vault-spin 0.85s linear infinite;
  background: white;
}
/* Once the image loads, the slot drops the loading class — hide spinner. */
body.route-vault .vault-card-thumb:not(.vault-card-thumb--loading) .vault-card-thumb-spinner {
  display: none;
}

/* Generic vault spinner (used in the detail modal "Loading…" state) */
.vault-spinner {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--brand-secondary) 25%, #e5e5ea);
  border-top-color: var(--brand-secondary);
  animation: vault-spin 0.85s linear infinite;
  margin: 0 auto 12px;
}
.vault-modal-loading {
  padding: 40px 30px;
  text-align: center;
}
.vault-modal-loading-text {
  color: var(--text-dim);
  font-size: 13px;
}

/* --- /admin/vault curator page ------------------------------- */
body.route-admin-vault .av-toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 14px;
}
body.route-admin-vault #av-search {
  flex: 1;
  padding: 9px 12px;
  border: 1px solid var(--border, #e5e5ea);
  border-radius: 8px;
  font-size: 13.5px;
}
body.route-admin-vault .av-show-inactive {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
}
body.route-admin-vault .av-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
body.route-admin-vault .av-row {
  display: grid;
  grid-template-columns: 80px 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 10px 12px;
  background: var(--card-bg, white);
  border: 1px solid var(--border, #e5e5ea);
  border-radius: 8px;
}
body.route-admin-vault .av-row.is-inactive { opacity: 0.55; }
body.route-admin-vault .av-row-thumb {
  width: 80px; height: 52px;
  object-fit: contain;
  background: var(--bg-soft, #f5f5f5);
  border-radius: 4px;
}
body.route-admin-vault .av-row-thumb--empty {
  background: repeating-linear-gradient(45deg, #f4f4f0, #f4f4f0 6px, #e8e6dc 6px, #e8e6dc 12px);
}
body.route-admin-vault .av-row-thumb--plan {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  background: color-mix(in srgb, var(--brand-secondary) 10%, #fafaf6);
}
body.route-admin-vault .av-row-main { min-width: 0; }
body.route-admin-vault .av-row-name {
  font-size: 14px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 6px;
}
body.route-admin-vault .av-featured-pin { color: #d4a700; }
body.route-admin-vault .av-deleted-pill {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  background: #d33;
  color: white;
  padding: 2px 6px;
  border-radius: 4px;
  margin-left: 4px;
}
body.route-admin-vault .av-row-meta {
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 2px;
}
body.route-admin-vault .av-row-tags {
  margin-top: 4px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
body.route-admin-vault .av-tag {
  background: color-mix(in srgb, var(--brand-secondary) 12%, white);
  color: color-mix(in srgb, var(--brand-secondary) 80%, #000);
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10.5px;
}
body.route-admin-vault .av-row-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}
body.route-admin-vault .av-empty {
  text-align: center;
  padding: 60px 20px;
  color: var(--text-dim);
}
body.route-admin-vault .av-empty-title { font-weight: 600; color: var(--text); margin-bottom: 4px; }

/* Edit form */
.av-form { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }
.av-field { display: flex; flex-direction: column; gap: 4px; }
.av-field > span {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.av-field input[type="text"],
.av-field input[type="number"],
.av-field textarea {
  padding: 8px 10px;
  border: 1px solid var(--border, #e5e5ea);
  border-radius: 6px;
  font: inherit;
  width: 100%;
  box-sizing: border-box;
}
.av-field textarea { resize: vertical; }
.av-field-row { display: flex; gap: 12px; }
.av-field-half {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.av-field-half > span {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* Promote-to-Vault button (per-card on library / plans page).
 * Positioned absolutely in the bottom-left corner of the card so it
 * doesn't fight the existing fav-star (top-right) or animate-chip. */
.send-to-vault-btn {
  position: absolute;
  bottom: 6px;
  left: 6px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  background: linear-gradient(135deg, #d4a700, #b8950a);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 1px 3px rgba(0,0,0,0.18);
  z-index: 5;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 120ms, transform 120ms;
}
/* Show on hover or when the card is already in the vault (so admins
 * can spot what's curated at a glance). */
.lib-card:hover .send-to-vault-btn,
.drill-card:hover .send-to-vault-btn,
.plan-clip:hover .send-to-vault-btn,
.send-to-vault-btn.is-in-vault,
.send-to-vault-btn:focus {
  opacity: 1;
  transform: translateY(0);
}
.send-to-vault-btn:hover { filter: brightness(1.08); }
.send-to-vault-btn.is-in-vault {
  background: linear-gradient(135deg, #2a8f3c, #1d7530);
  color: white;
}
/* On plan clips, the bottom-left has the "share/run/delete" action row.
 * Park the button at the top-right instead. */
.plan-clip .send-to-vault-btn {
  top: 8px;
  bottom: auto;
  left: auto;
  right: 8px;
}

/* Touch devices have no hover state — the reveal-on-hover pattern
 * makes Send-to-Vault and Revert buttons invisible on iPad/phone.
 * Force them visible when the primary pointer is coarse + no hover. */
@media (hover: none) and (pointer: coarse) {
  .send-to-vault-btn,
  .vault-revert-btn {
    opacity: 1;
    transform: none;
  }
}

/* "↩ Revert from Vault" button — appears on cards whose underlying
 * drill/plan was claimed from the Vault. Same hover-reveal pattern as
 * .send-to-vault-btn but positioned bottom-right so they don't fight. */
.vault-revert-btn {
  position: absolute;
  bottom: 6px;
  right: 6px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  background: rgba(0, 0, 0, 0.75);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
  z-index: 5;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 120ms, transform 120ms;
}
.lib-card:hover .vault-revert-btn,
.drill-card:hover .vault-revert-btn,
.plan-clip:hover .vault-revert-btn,
.vault-revert-btn:focus {
  opacity: 1;
  transform: translateY(0);
}
.vault-revert-btn:hover { background: rgba(0, 0, 0, 0.9); }
/* Park the plan-clip revert button bottom-left so it doesn't fight the
 * existing share/run/delete action row at the bottom-right. */
.plan-clip .vault-revert-btn {
  bottom: 8px;
  right: auto;
  left: 8px;
}

/* Revert confirm modal — same Emil polish family as the corner-confirm modal. */
.vault-revert-modal { display: none; }
.vault-revert-modal:not([hidden]) {
  display: grid;
  place-items: center;
  transition: opacity 200ms ease-out;
}
@starting-style {
  .vault-revert-modal:not([hidden]) { opacity: 0; }
}
.vault-revert-card {
  width: 460px;
  max-width: 92vw;
  padding: 24px 26px;
  transform-origin: center;
  transition:
    transform 240ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity 220ms ease-out;
}
@starting-style {
  .vault-revert-card { transform: scale(0.96); opacity: 0; }
}
.vault-revert-actions .btn {
  transition: transform 120ms ease-out, background 120ms ease-out;
}
.vault-revert-actions .btn:active {
  transform: scale(0.97);
}
@media (prefers-reduced-motion: reduce) {
  .vault-revert-modal:not([hidden]),
  .vault-revert-card { transition: opacity 180ms ease-out; transform: none; }
  .vault-revert-actions .btn:active { transform: none; }
}

/* --- Onboarding tour ------------------------------------------ */
/* Three-piece UI: full-screen overlay (dimmed), spotlight (a window
   through the overlay onto the highlighted element), and the floating
   card with copy + controls. The overlay + spotlight + card all fade
   together when the tour opens / closes / advances. */
.pc-tour {
  position: fixed;
  inset: 0;
  z-index: 5000;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 220ms ease-out,
    visibility 0s linear 220ms;
}
.pc-tour--open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 220ms ease-out;
}
.pc-tour-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15, 18, 22, 0.55);
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
}
/* Spotlight uses a massive outset box-shadow as the dim layer — the
   element itself stays bright while everything around it is dark.
   Positions are mutated via inline style from JS as steps advance. */
.pc-tour-spotlight {
  position: absolute;
  border-radius: 10px;
  box-shadow: 0 0 0 9999px rgba(15, 18, 22, 0.62);
  pointer-events: none;
  /* Smooth glide between steps so the spotlight doesn't snap. */
  transition:
    left 320ms cubic-bezier(0.23, 1, 0.32, 1),
    top 320ms cubic-bezier(0.23, 1, 0.32, 1),
    width 320ms cubic-bezier(0.23, 1, 0.32, 1),
    height 320ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity 200ms ease-out;
}
/* When there's no spotlight target, hide the dim layer above so the
   centered "Welcome" / "You're set" card sits over just the overlay. */
.pc-tour-spotlight[style*="opacity: 0"] { box-shadow: none; }

.pc-tour-card {
  position: absolute;
  width: 340px;
  max-width: calc(100vw - 36px);
  background: white;
  border-radius: 12px;
  padding: 22px 24px 18px;
  box-shadow: 0 18px 48px rgba(0,0,0,0.35);
  transition:
    left 320ms cubic-bezier(0.23, 1, 0.32, 1),
    top 320ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity 200ms ease-out;
}
/* On phones, shrink padding + tighten the card so it doesn't dwarf the
   spotlight. The card still respects max-width: calc(100vw - 36px). */
@media (max-width: 480px) {
  .pc-tour-card {
    padding: 18px 18px 14px;
    width: calc(100vw - 36px);
  }
  .pc-tour-title { font-size: 16px; }
  .pc-tour-body { font-size: 13px; margin-bottom: 16px; }
}
.pc-tour-card[data-placement="center"] {
  transform: translate(-50%, -50%);
  transition:
    opacity 220ms ease-out,
    transform 280ms cubic-bezier(0.23, 1, 0.32, 1);
}
.pc-tour--open .pc-tour-card {
  /* No-op selector — keeps the linter happy and reserves space for
     future per-state tweaks. */
}
.pc-tour-step {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 8px;
}
.pc-tour-title {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
.pc-tour-body {
  margin: 0 0 20px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text);
}
.pc-tour-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.pc-tour-nav { display: flex; gap: 8px; }
.pc-tour-skip,
.pc-tour-back,
.pc-tour-next {
  border: none;
  font: inherit;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  padding: 8px 14px;
  border-radius: 6px;
  transition: background 140ms ease-out, transform 120ms ease-out, opacity 140ms ease-out;
}
.pc-tour-skip {
  background: transparent;
  color: var(--text-dim);
  padding-left: 4px;
  padding-right: 4px;
}
.pc-tour-skip:hover { color: var(--text); }
.pc-tour-back {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border, #e5e5ea);
}
.pc-tour-back:hover { background: var(--bg-soft); color: var(--text); }
.pc-tour-back:disabled { opacity: 0.35; cursor: default; }
.pc-tour-next {
  background: var(--brand-secondary, #1f5fff);
  color: white;
  box-shadow: 0 1px 3px rgba(0,0,0,0.14);
}
.pc-tour-next:hover { filter: brightness(1.06); }
/* Emil press feedback on all three controls. */
.pc-tour-skip:active,
.pc-tour-back:not(:disabled):active,
.pc-tour-next:active { transform: scale(0.97); }
@media (prefers-reduced-motion: reduce) {
  .pc-tour,
  .pc-tour-spotlight,
  .pc-tour-card { transition: opacity 180ms ease-out; }
  .pc-tour-skip:active,
  .pc-tour-back:active,
  .pc-tour-next:active { transform: none; }
}

/* --- Drag-to-reorder library cards (#47) ----------------------
   Active only when activeSort === 'custom'. Cards get a subtle
   grab cursor + lift on hover; the dragged card dims; drop targets
   show a vertical accent bar on the side the cursor is on. */
.lib-card.is-draggable {
  cursor: grab;
  /* Prevent the browser from scrolling/zooming the page when the
     coach starts dragging on touch — the JS handles the gesture. */
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.lib-card.is-draggable:active { cursor: grabbing; }
.lib-card.lib-card--dragging {
  opacity: 0.4;
  /* No transform during drag — the browser handles the drag image. */
}
/* Drop indicator — vertical accent bar on the chosen side. */
.lib-card--drop-before,
.lib-card--drop-after {
  position: relative;
}
.lib-card--drop-before::before,
.lib-card--drop-after::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--brand-secondary, #1f5fff);
  border-radius: 2px;
  /* Soft glow so the indicator pops even on busy backgrounds. */
  box-shadow: 0 0 0 1px rgba(255,255,255,0.6), 0 0 8px rgba(31,95,255,0.5);
  pointer-events: none;
}
.lib-card--drop-before::before { left: -5px; }
.lib-card--drop-after::after  { right: -5px; }
@media (prefers-reduced-motion: reduce) {
  .lib-card.lib-card--dragging { opacity: 0.5; }
}
.vault-revert-card h2 {
  font-size: 18px;
  margin: 0 0 12px;
}
.vault-revert-card p {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text);
  margin: 0 0 10px;
}
.vault-revert-card .vault-revert-warn {
  font-size: 12.5px;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--brand-secondary) 8%, white);
  border-left: 3px solid var(--brand-secondary);
  padding: 8px 12px;
  border-radius: 4px;
}
.vault-revert-actions {
  margin-top: 18px;
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

/* --- Manual corner-adjustment modal for image import ----------
   Emil polish: backdrop fades in via @starting-style; card scales up
   from 0.96 with a custom ease-out; handles stagger in 40ms apart so
   they read as a deliberate sequence rather than a script firing.
   The modal is added fresh to the DOM each open so @starting-style
   fires reliably; the polygon + handle attributes mutate during drag
   without re-rendering (see confirmRinkCorners in page_drill.js). */
.rink-corners-modal {
  display: grid;
  place-items: center;
  /* Backdrop fades 200ms when the element is added to the DOM. */
  background: rgba(20, 22, 26, 0.5);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  transition: opacity 200ms ease-out;
}
@starting-style {
  .rink-corners-modal { opacity: 0; }
}
.rink-corners-card {
  width: 920px;
  max-width: 96vw;
  padding: 22px 24px;
  transform-origin: center; /* Modal exception: stays centered, not anchored to a trigger. */
  transition:
    transform 260ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity 240ms ease-out;
}
@starting-style {
  .rink-corners-card {
    transform: scale(0.96);
    opacity: 0;
  }
}
.rink-corners-card h2 {
  margin: 0 0 8px;
  font-size: 18px;
}
.rink-corners-card p {
  margin: 0 0 14px;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.5;
}
.rink-corners-canvas-wrap {
  position: relative;
  max-height: 60vh;
  overflow: visible;
  background: #000;
  border-radius: 6px;
  padding-top: 28px; /* room for TL/TR labels above the handles */
}
.rink-corners-img {
  display: block;
  max-width: 100%;
  max-height: 60vh;
  margin: 0 auto;
  user-select: none;
  -webkit-user-drag: none;
}
.rink-corners-svg {
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  touch-action: none;
}
.rink-corner-poly {
  fill: rgba(212, 167, 0, 0.18);
  stroke: #d4a700;
  stroke-width: 2;
  pointer-events: none;
}
.rink-corner-handle {
  cursor: grab;
  /* Anchor scale at the handle's own center (it's translated by `transform`
     on the <g>; the visual scale here applies to its children). */
  transform-box: fill-box;
  transform-origin: center;
  /* Stagger entry — each handle's animation-delay set per :nth-of-type below.
     animation runs once, sets the final state. */
  animation: rink-corner-handle-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
  /* The handle's own visual scale (separate from the translate on its <g>
     transform attribute, which we mutate during drag). */
  transition: scale 140ms ease-out;
}
.rink-corner-handle:active { cursor: grabbing; }
@keyframes rink-corner-handle-in {
  from { opacity: 0; scale: 0.6; }
  to   { opacity: 1; scale: 1; }
}
.rink-corner-handle:nth-of-type(1) { animation-delay: 60ms; }
.rink-corner-handle:nth-of-type(2) { animation-delay: 100ms; }
.rink-corner-handle:nth-of-type(3) { animation-delay: 140ms; }
.rink-corner-handle:nth-of-type(4) { animation-delay: 180ms; }
/* Touch devices fire fake hover on tap → gate the hover-scale so dragged
   handles don't stay scaled after a drag on iPad. */
@media (hover: hover) and (pointer: fine) {
  .rink-corner-handle:hover { scale: 1.08; }
}
.rink-corner-handle-bg {
  fill: rgba(212, 167, 0, 0.25);
  stroke: #d4a700;
  stroke-width: 2;
}
.rink-corner-handle-dot {
  fill: #d4a700;
  stroke: white;
  stroke-width: 2;
}
.rink-corner-handle-label {
  fill: white;
  font: bold 11px sans-serif;
  text-anchor: middle;
  paint-order: stroke;
  stroke: rgba(0,0,0,0.7);
  stroke-width: 3;
}
.rink-corners-actions {
  margin-top: 18px;
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
/* Universal button press feedback — Emil's rule: every pressable element
   must respond to press. 120ms is short enough to feel instant. */
.rink-corners-actions .btn {
  transition: transform 120ms ease-out, background 120ms ease-out;
}
.rink-corners-actions .btn:active {
  transform: scale(0.97);
}
@media (prefers-reduced-motion: reduce) {
  .rink-corners-modal,
  .rink-corners-card { transition: opacity 180ms ease-out; transform: none; }
  .rink-corner-handle { animation: none; opacity: 1; scale: 1; }
  .rink-corner-handle:hover { scale: 1; }
  .rink-corners-actions .btn:active { transform: none; }
}

/* ============================================================
   /dev/smoke — iPad regression checklist page
   ============================================================
   Big tap targets (44px+), clear pass/fail state, sticky summary.
   Designed for one-handed iPad use. */
.page--dev-smoke { max-width: 880px; margin: 0 auto; }
.page--dev-smoke .page-header-actions { display: flex; gap: 8px; }

.smoke-summary {
  position: sticky; top: 60px; z-index: 5;
  display: flex; gap: 14px; align-items: baseline;
  padding: 10px 14px;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 10px;
  font-size: 13px;
  margin-bottom: 16px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.smoke-summary b { font-size: 17px; font-weight: 700; margin-right: 2px; }
.smoke-summary-pass b { color: #16a34a; }
.smoke-summary-fail b { color: #d4302b; }
.smoke-summary-todo b { color: #6b7280; }
.smoke-summary-total { color: var(--text-dim); margin-left: auto; }

.smoke-group { margin-bottom: 24px; }
.smoke-group-h {
  font-size: 15px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.5px; color: var(--text-dim);
  margin: 0 0 8px; padding: 0 4px;
}

.smoke-item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 10px 12px;
  background: #fff;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 10px;
  margin-bottom: 8px;
  transition: background 140ms ease-out, border-color 140ms ease-out;
}
.smoke-item.is-pass { background: #f0fdf4; border-color: #86efac; }
.smoke-item.is-fail { background: #fef2f2; border-color: #fca5a5; }

.smoke-item-buttons {
  display: flex; gap: 6px; flex: 0 0 auto;
}
.smoke-btn {
  width: 44px; height: 44px;
  border: 1.5px solid var(--border, #d4d7dc);
  border-radius: 10px;
  background: #fff; color: var(--text-dim);
  font-size: 22px; font-weight: 800; line-height: 1;
  cursor: pointer; -webkit-appearance: none;
  transition: transform 100ms ease-out, background 140ms, color 140ms, border-color 140ms;
}
.smoke-btn:active { transform: scale(0.92); }
.smoke-pass:hover { background: #f0fdf4; }
.smoke-fail:hover { background: #fef2f2; }
.smoke-item.is-pass .smoke-pass { background: #16a34a; color: #fff; border-color: #16a34a; }
.smoke-item.is-fail .smoke-fail { background: #d4302b; color: #fff; border-color: #d4302b; }

.smoke-item-body { flex: 1; min-width: 0; }
.smoke-item-label {
  font-size: 15px; font-weight: 500; color: var(--text);
  line-height: 1.4;
}
.smoke-item-actions {
  display: flex; gap: 14px; margin-top: 4px;
  font-size: 12px;
}
.smoke-item-link {
  color: var(--brand-secondary, #1f5fff);
  text-decoration: none; font-weight: 600;
}
.smoke-item-link:hover { text-decoration: underline; }
.smoke-note-toggle {
  background: none; border: none; padding: 0;
  color: var(--text-dim); cursor: pointer;
  font: inherit; font-size: 12px;
}
.smoke-note-toggle:hover { color: var(--text); }
.smoke-note {
  width: 100%; margin-top: 6px;
  padding: 8px 10px;
  border: 1px solid var(--border, #d4d7dc);
  border-radius: 8px;
  font: inherit; font-size: 13px;
  resize: vertical;
}

.smoke-footnote {
  color: var(--text-dim); font-size: 12px;
  margin-top: 24px; text-align: center;
}

@media (max-width: 540px) {
  .smoke-summary { font-size: 12px; gap: 10px; }
  .smoke-summary b { font-size: 15px; }
}

/* =================================================================
   Drillboard redesign R1 — Bottom dock (light)
   2026-06-14  pivot from dark Figma chrome to a floating bottom dock
   =================================================================
   Reference: ~/Downloads/rinkboard-bottom-dock-light.html
   Pattern: centered floating tool pill + context strip, bottom-left
   mode switch (Draw / Anim / Play). The legacy left toolbar is hidden
   and the existing tool buttons stay in the DOM as forwarding targets
   so canvas.js wiring keeps working. */

body.route-drill {
  --dock-canvas:    #ffffff;
  --dock-panel:     #ffffff;
  --dock-panel-2:   #f1f2f4;
  --dock-line:      #e2e4e8;
  --dock-line-soft: #edeef1;
  --dock-text:      #1b1e25;
  --dock-text-mid:  #5c6470;
  --dock-text-faint:#9097a1;
  --dock-blue:      #0d99ff;
  --dock-shadow:    0 14px 40px rgba(17, 20, 26, 0.14);
  --dock-shadow-sm: 0 10px 30px rgba(17, 20, 26, 0.12);
}

/* ---------- Topbar: HIDDEN. Its contents (surface, time, undo/redo,
   save/print/etc.) are moved at boot into the tabs bar and the
   left rail by page_drill.js. (R6, 2026-06-14) ---------- */
body.route-drill .topbar { display: none !important; }
/* App grid-template-rows was `auto 1fr auto` — when topbar:none drops
   out of the grid, main auto-flows into the AUTO row and sizes to its
   content (only ~440px) instead of filling the viewport. Collapse the
   grid to a single 1fr row so main fills the full height under the
   nav. (Fixes the wrap being too short to center the rink.) */
body.route-drill #app { grid-template-rows: 1fr; }
body.route-drill .topbar-mode-hint {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--dock-text-faint);
  border: 1px solid var(--dock-line);
  border-radius: 20px;
  padding: 4px 10px;
  white-space: nowrap;
}

/* ---------- Tabs bar: now also carries action buttons on the right ---------- */
body.route-drill #drill-tabs {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--dock-panel);
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
  padding: 4px 12px 4px 6px;
  min-height: 38px;
}
body.route-drill #drill-tabs { overflow: hidden; }
/* Tab list scrolls independently — actions stay pinned to the right.
   Without this, when the tab strip overflowed the WHOLE row scrolled
   horizontally and pushed the Share button etc. off-screen. The fade
   mask on the right edge hints there are more tabs to scroll to.
   (Ian: "how should i handle tabs and the bar when they overlap?") */
body.route-drill #drill-tab-list {
  flex: 1 1 0;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 18px), transparent 100%);
          mask-image: linear-gradient(to right, black calc(100% - 18px), transparent 100%);
}
/* Tighter scrollbar for the tab track (WebKit). */
body.route-drill #drill-tab-list::-webkit-scrollbar { height: 4px; }
body.route-drill #drill-tab-list::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 2px;
}
body.route-drill #drill-tab-list::-webkit-scrollbar-track { background: transparent; }
/* Progressive collapse of right-side actions as the viewport narrows
   so the tab list always has somewhere to live. Mirrors the UX pattern
   in browser address bars: drop low-value chrome first. Ordered by
   priority — least essential collapses first. */
@media (max-width: 1200px) {
  body.route-drill #ad-slot-drillboard { display: none; }
}
@media (max-width: 1080px) {
  body.route-drill #save-status .save-status-label { display: none; }
  body.route-drill #save-status { padding: 4px 6px; }
}
@media (max-width: 980px) {
  body.route-drill #drill-tabs-slot-undo,
  body.route-drill #drill-tabs-slot-redo,
  body.route-drill #drill-tabs-actions .drill-tabs-divider { display: none; }
}
@media (max-width: 880px) {
  body.route-drill #drill-tabs-fullscreen { display: none; }
}
@media (max-width: 780px) {
  body.route-drill #drill-tabs-slot-time { display: none; }
}
body.route-drill .drill-tabs-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  margin-left: auto;
}
body.route-drill .drill-tabs-divider {
  width: 1px;
  height: 18px;
  background: var(--dock-line);
}
/* Buttons that get MOVED into the tabs actions take dock-mini styling. */
body.route-drill .drill-tabs-actions .top-icon-btn,
body.route-drill .drill-tabs-actions .rink-btn,
body.route-drill .drill-tabs-actions select.mins {
  background: var(--dock-panel);
  border: 1px solid var(--dock-line);
  color: var(--dock-text);
  border-radius: 6px;
  font-size: 11px;
  padding: 3px 8px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
}
body.route-drill .drill-tabs-actions .top-icon-btn:hover,
body.route-drill .drill-tabs-actions .rink-btn:hover { background: var(--dock-panel-2); }
body.route-drill .drill-tabs-actions .top-icon-btn { width: 28px; padding: 0; justify-content: center; }
body.route-drill .drill-tabs-actions .top-icon-btn svg { width: 13px; height: 13px; }
body.route-drill .drill-tabs-actions select.mins { padding-right: 16px; }
/* Share button gets the brand accent */
body.route-drill #drill-tabs-slot-share .top-icon-btn,
body.route-drill #drill-tabs-slot-share > * {
  background: var(--fg-accent, #d4302b);
  border-color: var(--fg-accent, #d4302b);
  color: #fff;
  padding: 0 10px;
  width: auto;
}
body.route-drill #drill-tabs-slot-share .top-icon-btn:hover { background: #b8231f; }
body.route-drill #drill-tabs-slot-share .top-icon-btn::after {
  content: 'Share';
  font-size: 11px;
  font-weight: 500;
  margin-left: 4px;
}

/* ---------- Legacy left toolbar: forced collapsed via body class
     toggle in JS init. The dock replaces it, so hide the expand-strip
     too. (Existing body.tools-collapsed CSS handles the column resize
     to 22px and toolbar display:none.) ---------- */
body.route-drill .collapse-strip.left { display: none !important; }
/* Drill-tabs strip — span columns 1 + 2 (skip the right collapse-strip
   in column 3). Starts flush at x=0 on the left, stops where the right
   sidebar's "›" chevron lives so the Drills launcher stays visible.
   (Ian: "share / full ice / time is over the drills tab — should be
   visible") */
body.route-drill main > .drill-tabs {
  grid-column: 1 / 3;
  padding-left: 0;
}

/* ---------- Canvas surround: soft gray + dot grid ---------- */
body.route-drill main {
  background: var(--dock-canvas);
}
body.route-drill .canvas-wrap {
  background: var(--dock-canvas);
  position: relative;
  /* The dock + style bar are now position:fixed (anchored to viewport,
     not the scroll container). The padding-bottom only needs to keep
     the LAST inline child (notes editor / tag input) from scrolling
     under the dock. 180px = dock area (~94px) + breathing room. */
  padding-bottom: 180px;
  /* Reserve space on the left so the rink can't slide under the
     floating DRAW/ANIM/PLAY mode rail (which lives at left:18px,
     56px wide → 74px footprint, +12px breathing room = 86px).
     (Ian: "make sure it doesn't overlap the surface") */
  padding-left: 86px;
  /* Vertically center the rink in the available space between the
     tabs bar and the floating style bar. (Ian: "can the surface be
     placed more centered vertically?") */
  justify-content: center;
}
/* When the drills sidebar is collapsed (narrow DRILLS strip on the right
   only), mirror the left rail's reservation on the right so the rink
   visually centers in the available area. With the sidebar open, the
   300px panel already balances the visual weight. (Ian: "feels weird
   when the drills tab is collapsed and the rink isn't centered") */
body.route-drill.sidebar-collapsed .canvas-wrap {
  padding-right: 86px;
}
@media (max-width: 900px) {
  body.route-drill .canvas-wrap { padding-left: 60px; }
}

/* ---------- Resizable sidebar (Ian: "make the panel wider") ----------
   The drill drawer's right column was a fixed 300px. Now it reads from
   a CSS custom property the user can change by dragging the handle on
   the sidebar's left edge. Clamped 280-640px, persisted in localStorage.
   The override only fires when the sidebar is open (not collapsed). */
body.route-drill { --sidebar-w: 300px; }
body.route-drill:not(.sidebar-collapsed):not(.tools-collapsed) .app main {
  grid-template-columns: 108px minmax(0, 1fr) var(--sidebar-w);
}
body.route-drill.tools-collapsed:not(.sidebar-collapsed) .app main {
  grid-template-columns: 22px minmax(0, 1fr) var(--sidebar-w);
}
body.route-drill aside.sidebar { position: relative; }
body.route-drill .sidebar-resize-handle {
  position: absolute;
  left: -3px;
  top: 0;
  width: 6px;
  height: 100%;
  cursor: ew-resize;
  z-index: 5;
  background: transparent;
  transition: background 120ms ease;
  touch-action: none;
}
body.route-drill .sidebar-resize-handle:hover,
body.route-drill .sidebar-resize-handle.dragging {
  background: rgba(13, 153, 255, 0.35);
}
body.route-drill .sidebar-resize-handle::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 2px;
  height: 28px;
  border-radius: 2px;
  background: var(--dock-line, #e2e4e8);
}
body.route-drill .sidebar-resize-handle:hover::before,
body.route-drill .sidebar-resize-handle.dragging::before {
  background: var(--dock-blue, #0d99ff);
}
/* Draw mode: meta-fields are hidden, so the wrap doesn't need to
   reserve 180px below for them — but it DOES need ~130px so the
   rink centers in the VISIBLE area (above the floating style bar +
   dock) rather than behind them. (Ian: "more centered vertically") */
body.drill-mode-draw.route-drill .canvas-wrap { padding-bottom: 130px; }
/* Shrink the canvas-stage so the rink doesn't extend down under the
   floating dock + style bar. Overrides the existing min-height that
   sized for the legacy in-flow style bar (220px). The new chrome
   needs ~330px reserved below the rink. (Ian: "make the rink smaller
   so the style bar isn't over top of the rink") */
body.route-drill .canvas-stage {
  /* Reserve top/bottom slack so the rink isn't pinned to the top of
     the canvas-wrap. (Ian: "can the surface be placed more centered
     vertically?" + "make the surface a little bit bigger" ×2) */
  min-height: calc(100vh - 280px) !important;
  max-height: calc(100vh - 170px);
  margin-top: auto;
  margin-bottom: auto;
  flex: 0 0 auto;
}
/* ============================================================
   R7 (final): Notes lives as a tab inside the drill drawer's sidebar.
   The meta-fields get MOVED into #panel-notes when the user clicks
   the NOTES tab. When they live inside the panel, they render as a
   normal stacked column — no floating, no fixed positioning.
   (Ian: "I want notes in the drills panel")
   ============================================================ */
/* Default in canvas-wrap (their original parent) — hidden. */
body.route-drill .canvas-wrap > .meta-fields,
body.route-drill .canvas-wrap > .meta-fields.meta-row { display: none; }
/* When relocated into the sidebar's notes panel — show as block. */
body.route-drill #panel-notes .meta-fields {
  display: block;
  position: static;
  width: auto;
  max-height: none;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: var(--dock-panel-2);
  border: 1px solid var(--dock-line);
  border-radius: 10px;
  box-shadow: none;
}
/* Tags + Age live inside `.meta-fields.meta-row` — render them as TWO
   separate labelled cards in the notes panel so the user can tell at a
   glance which is which. (Ian: "can we separate tags and ages — looks
   like it's one field") */
body.route-drill #panel-notes .meta-fields.meta-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 0 12px;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
}
body.route-drill #panel-notes .meta-fields.meta-row .tags-input {
  position: relative;
  padding: 22px 8px 8px;
  background: var(--dock-panel-2);
  border: 1px solid var(--dock-line);
  border-radius: 10px;
  min-height: 48px;
}
body.route-drill #panel-notes .meta-fields.meta-row .tags-input::before {
  position: absolute;
  top: 6px;
  left: 10px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #6b7280);
  pointer-events: none;
}
body.route-drill #panel-notes #tags-input::before { content: "Tags"; }
body.route-drill #panel-notes #age-input::before { content: "Age groups"; }
body.route-drill #panel-notes {
  padding: 14px 12px;
  overflow-y: auto;
}
/* Notes editor format toolbar — go icon-only when inside the sidebar
   so all the buttons fit at any sensible panel width. Hides the AI
   action labels ("Write" / "Cues" / "Adapt") and tightens spacing.
   (Ian: "the toolbar is hidden, think we need to have just icons") */
body.route-drill #panel-notes .notes-toolbar { flex-wrap: wrap; gap: 2px; padding: 4px; }
body.route-drill #panel-notes .notes-toolbar button { padding: 4px 6px; min-width: 28px; }
body.route-drill #panel-notes .notes-ai-label { display: none; }
body.route-drill #panel-notes .notes-ai-btn { padding: 4px 6px !important; }
body.route-drill #panel-notes .notes-ai-btn svg { width: 14px; height: 14px; }
/* When the notes editor is mounted inside the sidebar panel, flip the
   inline-icon picker to open DOWNWARD. The default opens UP above the
   toolbar (so it doesn't cover the text area), but in the sidebar that
   means it pops up into the DRILLS / NOTES tab header and gets clipped
   by `#panel-notes { overflow-y: auto }`. Opening downward keeps it
   inside the scroll viewport. (Ian: "the panel is hidden behind the
   drills header") */
body.route-drill #panel-notes .icon-grid {
  top: calc(100% + 4px);
  bottom: auto;
  /* Wider columns so the grid fits the narrower sidebar width without
     clipping the right edge against the panel border. */
  grid-template-columns: repeat(5, 36px);
}

/* ============================================================
   R4: Animate mode — Photoshop-style timeline.
   Full-width strip pinned to the viewport bottom, like the Photoshop
   animation panel. The drawing dock + style bar float ABOVE it so the
   user can edit while scrubbing frames. (Ian: "treat it like the
   timeline panel in photoshop")
   ============================================================ */
body.drill-mode-animate .anim-panel { display: flex !important; }
body.drill-mode-animate.route-drill .anim-panel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  transform: none;
  width: 100vw;
  max-width: 100vw;
  z-index: 36;
  background: var(--dock-panel);
  border: none;
  border-top: 1px solid rgba(0, 0, 0, 0.10);
  border-radius: 0;
  box-shadow: 0 -10px 30px rgba(17, 20, 26, 0.10);
  padding: 10px 16px;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
/* Lift the drawing dock + style bar ABOVE the bottom timeline. */
body.drill-mode-animate.route-drill .drill-dock   { bottom: 160px; }
body.drill-mode-animate.route-drill .line-picker  { bottom: 226px; }
/* Stop the mode switch from sitting in front of the strip on short
   viewports — move it up so it clears the timeline. */
body.drill-mode-animate.route-drill .drill-mode-switch { top: calc(50% - 70px); }
/* Shrink the rink in animate mode so it doesn't slip behind the
   tools or the bottom timeline. */
body.drill-mode-animate.route-drill .canvas-stage {
  min-height: calc(100vh - 380px) !important;
  max-height: calc(100vh - 320px);
}
/* Bottom Photoshop timeline overlays the bottom edge of the viewport.
   The drills + notes sidebar panels are scroll containers — pad their
   bottom so card lists / textareas scroll above the timeline strip
   instead of running beneath it.
   NOTE: do NOT use `bottom:` on `aside.sidebar` — it's position:relative
   inside the grid, so `bottom` shifts it upward (top: -140px layout
   bug). Pad the inner scroll panels instead. */
body.drill-mode-animate.route-drill #panel-drills,
body.drill-mode-animate.route-drill #panel-notes {
  padding-bottom: 140px;
}

/* ============================================================
   R5: Drill drawer launcher — make the right `›` chevron a clear
   "Drills" pill so users see they can open the drawer. (2026-06-14)
   ============================================================ */
body.route-drill.sidebar-collapsed .collapse-strip.right {
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 8px 0 0 8px;
  box-shadow: var(--dock-shadow-sm);
  color: var(--dock-text-mid);
  font-size: 10px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 0.6px;
  width: 28px;
  display: flex !important;
  align-items: center;
  justify-content: center;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  padding: 12px 4px;
  cursor: pointer;
  z-index: 36;
  /* Content is replaced via JS to show "DRILLS ›" instead of just "‹" */
}
body.route-drill.sidebar-collapsed .collapse-strip.right:hover {
  background: var(--dock-panel-2);
  color: var(--dock-text);
}

/* ============================================================
   R3: Context strip morph — hide irrelevant groups in the style bar
   based on the active tool. (2026-06-14)
   ============================================================ */
/* Eraser: only the size slider matters. */
body.route-drill:has(.tool[data-tool="eraser"].active) .line-picker .line-picker-group:not(.lpg-size),
body.route-drill:has(.tool[data-tool="eraser"].active) .line-picker .line-picker-divider {
  display: none;
}
/* Text + every stamp-style tool (puck / cone / circle / rect / triangle
   / players / goalie stances): style/ending don't apply; show only
   color + size. */
body.route-drill:has(.tool[data-tool="text"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="text"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="text"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool="text"].active) .line-picker .line-picker-divider:first-of-type,
body.route-drill:has(.tool[data-tool="puck"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="puck"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="puck"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool="cone"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="cone"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="cone"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool="circle"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="circle"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="circle"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool="rect"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="rect"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="rect"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool="triangle"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="triangle"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="triangle"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool="x"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool="x"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool="x"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool^="g-"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool^="g-"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool^="g-"].active) .line-picker .lpd-style,
body.route-drill:has(.tool[data-tool^="label-"].active) .line-picker .lpg-style,
body.route-drill:has(.tool[data-tool^="label-"].active) .line-picker .lpg-ending,
body.route-drill:has(.tool[data-tool^="label-"].active) .line-picker .lpd-style { display: none; }
/* Hide the style bar when the Move tool is active AND nothing is selected
   — there's nothing to style. But the moment a shape IS selected, bring the
   bar back so the coach can recolor / resize / restyle it (clicking a swatch
   recolours the selection; the style-bar handlers already target
   state.selectedShape). */
body.route-drill:has(.tool[data-tool="select"].active):not(.shape-selected) .line-picker {
  display: none;
}
/* With a shape selected, un-hide the style + ending groups (the
   tool-kind="none" rules set them visibility:hidden) so a selected line can
   have its style/ending changed too. Color + size are already shown. */
body.route-drill.shape-selected .lpg-style,
body.route-drill.shape-selected .lpg-ending,
body.route-drill.shape-selected .lpd-style,
body.route-drill.shape-selected .lpd-color {
  visibility: visible;
}

/* ---------- Mode switch: LEFT EDGE, vertically centered ----------
   position:fixed so it stays glued to the viewport even when the
   canvas-wrap scrolls. (Inside canvas-wrap it scrolled with the
   description editor / tag input below the rink, which was the
   "interfering with the floating nav" issue.) */
body.route-drill .drill-mode-switch {
  position: fixed;
  left: 18px;
  top: 50%;
  bottom: auto;
  transform: translateY(-50%);
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 12px;
  padding: 5px;
  box-shadow: var(--dock-shadow-sm);
}
body.route-drill .drill-mode-switch .rail-section--mode {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
}
body.route-drill .drill-mode-switch .rail-section--mode button {
  width: 100%;
  height: 44px;
  border: none;
  background: transparent;
  border-radius: 9px;
  color: var(--dock-text-faint);
  cursor: pointer;
  display: grid;
  place-items: center;
  gap: 2px;
  transition: background 140ms ease, color 140ms ease;
}
/* Fallback (in case some legacy code-path renders mode buttons OUTSIDE
   the rail-section--mode wrapper). */
body.route-drill .drill-mode-switch > button {
  width: 100%;
  height: 44px;
  border: none;
  background: transparent;
  border-radius: 9px;
  color: var(--dock-text-faint);
  cursor: pointer;
  display: grid;
  place-items: center;
  gap: 2px;
  transition: background 140ms ease, color 140ms ease;
}
body.route-drill .drill-mode-switch button:hover {
  background: var(--dock-panel-2);
  color: var(--dock-text-mid);
}
body.route-drill .drill-mode-switch button.on {
  background: var(--dock-panel-2);
  color: var(--dock-text);
}
body.route-drill .drill-mode-switch button.on svg {
  color: var(--dock-blue);
}
body.route-drill .drill-mode-switch button svg {
  width: 19px;
  height: 19px;
}
body.route-drill .drill-mode-switch .ml {
  font-size: 8px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 0.5px;
  margin-top: 1px;
}
/* Expanded rail layout: stacked sections with thin dividers + tiny
   uppercase labels. The DRAW/ANIM/PLAY trio stays on top; FILE and
   EXPORT sections are populated at boot by moving icon buttons over
   from the (hidden) legacy topbar. (R6, 2026-06-14) */
body.route-drill .drill-mode-switch .rail-divider {
  width: 36px;
  height: 1px;
  background: var(--dock-line);
  margin: 4px auto;
}
body.route-drill .drill-mode-switch .rail-label {
  font-size: 8px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 0.6px;
  color: var(--dock-text-faint);
  text-align: center;
  padding: 0 0 4px;
}
body.route-drill .drill-mode-switch .rail-section--actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
}
body.route-drill .drill-mode-switch .rail-section--actions .top-icon-btn {
  width: 28px;
  height: 28px;
  border: 1px solid var(--dock-line);
  background: transparent;
  color: var(--dock-text-mid);
  border-radius: 6px;
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}
body.route-drill .drill-mode-switch .rail-section--actions .top-icon-btn:hover {
  background: var(--dock-panel-2);
  color: var(--dock-text);
}
body.route-drill .drill-mode-switch .rail-section--actions .top-icon-btn svg { width: 13px; height: 13px; }

/* ---------- Bottom dock — centered floating column ----------
   position:fixed so it doesn't scroll with the description editor /
   tag input below the rink. The dock is centered to the viewport
   minus the collapsed sidebar's 22px column on the right — close
   enough to center on the canvas without absolute positioning. */
body.route-drill .drill-dock {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  /* Above the style bar (z=35) so the per-tool tooltips that float
     UP from each .dock-tool can render OVER the bar instead of being
     hidden behind it. (Ian: "tooltips are under the style bar") */
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  width: max-content;
  /* Never wider than the viewport — the pills below scroll horizontally
     instead of wrapping onto a second row when the screen is narrow. */
  max-width: calc(100vw - 24px);
}
/* Respect the [hidden] attribute on the ctx strip — without this rule
   the display:flex below would override hidden's display:none and leave
   an empty 42px-tall white box stacked above the primary pill, which
   pushed the line-picker down INTO the dock area. (2026-06-14) */
body.route-drill .drill-dock-ctx[hidden] { display: none; }
body.route-drill .drill-dock-ctx {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 11px;
  padding: 6px 8px;
  box-shadow: var(--dock-shadow-sm);
  min-height: 42px;
  /* Scroll sideways rather than wrapping when narrow. */
  flex-wrap: nowrap;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x;
  scrollbar-width: none;
}
body.route-drill .drill-dock-ctx::-webkit-scrollbar { display: none; }
body.route-drill .drill-dock-ctx > * { flex-shrink: 0; }
body.route-drill .drill-dock-primary {
  display: flex;
  align-items: center;
  gap: 2px;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 14px;
  padding: 7px;
  box-shadow: var(--dock-shadow);
  /* Single row that scrolls sideways when the screen can't fit every tool —
     never wraps onto a second line (desktop-small, iPad, or phone). The
     tooltip is a fixed bubble on <body> (tooltip.js) so overflow here can't
     clip it. */
  flex-wrap: nowrap;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x;
  scrollbar-width: none;
}
body.route-drill .drill-dock-primary::-webkit-scrollbar { display: none; }
body.route-drill .dock-tool {
  position: relative;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border: none;
  background: transparent;
  border-radius: 10px;
  color: var(--dock-text-mid);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 140ms ease, color 140ms ease, transform 120ms ease;
}
body.route-drill .dock-tool svg { width: 21px; height: 21px; }
/* PNG icons (e.g. Ian's pencil.png on the pen tool) — size to fit the
   dock chip and lock the aspect ratio. Sized larger than the SVGs so the
   pencil dominates its chip the way Figma's pencil does in their
   reference toolbar. (Ian: "i want the pencil to be bigger ... it should
   feel like this") */
body.route-drill .dock-tool img {
  width: 34px;
  height: 34px;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
/* Same sizing for the hidden source `.tool` buttons that mirrorIcons()
   clones from — so the legacy toolbar (and any tooltip preview) shows
   the same pencil at the same size. */
body.route-drill .toolbar .tool img,
body.route-drill .drill-dock-all .dock-tool img { width: 34px; height: 34px; object-fit: contain; }
/* Figma flourish: when the Pencil tool is active, the cursor over the
   drawing surface IS a pencil. Scoped to `#drawing` (the actual drawing
   canvas) so the pencil only appears over the rink — the previous scope
   (`.canvas-stage`) bled the pencil onto the empty padding around the
   rink, which the user saw as "a weird pencil icon... outside the rink".
   Hotspot is the tip (3, 29 — bottom-left). Falls back to crosshair on
   older browsers. (Ian: "there is a weird pencil icon as the cursor on
   the page... its outside the rink") */
body.route-drill:has(.tool[data-tool="pen"].active) #drawing {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><g transform='rotate(-45 16 16)'><rect x='14' y='4' width='4' height='3' fill='%23111'/><rect x='14' y='7' width='4' height='14' fill='%23f4f1ea' stroke='%23222' stroke-width='0.5'/><rect x='14' y='21' width='4' height='2' fill='%23222'/><polygon points='14,23 18,23 16,29' fill='%23111'/></g></svg>") 3 29, crosshair;
}
body.route-drill .dock-tool:hover {
  background: var(--dock-panel-2);
  color: var(--dock-text);
  transform: translateY(-1px);
}
body.route-drill .dock-tool.active {
  background: var(--dock-blue);
  color: #fff;
}
/* Letter-glyph dock tools (X, O) — bold mono-ish letter centered in
   the chip; matches the existing position-label vibe. */
body.route-drill .dock-tool--letter span {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0.5px;
  line-height: 1;
}
body.route-drill .dock-divider {
  width: 1px;
  height: 26px;
  background: var(--dock-line);
  margin: 0 5px;
}
/* Tooltip for .dock-tool — handled by tooltip.js (pc-tooltip). The
   previous CSS `::after` here duplicated that bubble, so a hover showed
   two pills (one above, one on the side). The JS bubble lives in <body>
   and handles viewport edges + delay properly. (Ian: "i have two
   tooltips showing. one above and one on the side") */
/* Down-caret indicator on dock buttons that open a flyout. */
body.route-drill .dock-tool[data-flyout]::before {
  content: '';
  position: absolute;
  right: 4px;
  bottom: 4px;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-bottom: 4px solid currentColor;
  opacity: 0.5;
}

/* ---------- Flyout panels above the dock ---------- */
body.route-drill .dock-flyout {
  position: absolute;
  bottom: 72px;
  z-index: 40;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 12px;
  padding: 10px;
  box-shadow: 0 16px 44px rgba(17, 20, 26, 0.14);
  display: none;
  min-width: 180px;
}
body.route-drill .dock-flyout.open { display: block; animation: dock-rise 180ms ease both; }
@keyframes dock-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
body.route-drill .dock-flyout-row {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
body.route-drill .dock-flyout-item {
  width: 40px;
  height: 40px;
  border: none;
  background: var(--dock-panel-2);
  border-radius: 9px;
  color: var(--dock-text-mid);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 130ms ease, color 130ms ease, transform 120ms ease;
  padding: 0;
}
body.route-drill .dock-flyout-item:hover {
  background: var(--dock-line-soft);
  color: var(--dock-text);
  transform: translateY(-1px);
}
body.route-drill .dock-flyout-item svg { width: 20px; height: 20px; }
/* Position-label stamps (LW, C, RW, LD, RD, G, F, D — small SVG circles
   with text labels inside) come through as <img> elements with embedded
   text. The default 20px sizing renders the text too small to read.
   Bump the img size so the letters are legible. (Ian: "the stamps that
   have numbers on them ... in the bar, they are very small. can we make
   them bigger?") */
body.route-drill .dock-flyout-item img { width: 30px; height: 30px; object-fit: contain; }
body.route-drill .drill-dock-all .dock-tool img { width: 30px; height: 30px; object-fit: contain; }

/* Expanded all-tools strip — sits ABOVE the dock primary pill when
   #dock-expand-toggle is on. Shows every shape, player, stamp, and
   goalie tool inline so the user doesn't have to open four flyouts.
   (2026-06-14 "show all options on the toolbar") */
body.route-drill .drill-dock-all {
  display: none;
  align-items: center;
  gap: 4px;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 14px;
  padding: 6px 8px;
  box-shadow: var(--dock-shadow-sm);
  flex-wrap: wrap;
  max-width: calc(100vw - 80px);
}
body.drill-dock-all-tools .drill-dock-all { display: flex; }
/* When the expanded strip is on, hide the compact primary pill so
   there's only one toolbar on screen at a time. The expand toggle
   moves into the expanded strip so the user can still collapse back. */
body.drill-dock-all-tools .drill-dock-primary { display: none; }
body.route-drill .drill-dock-all .dock-tool {
  width: 36px;
  height: 36px;
}
body.route-drill .drill-dock-all .dock-tool svg { width: 18px; height: 18px; }
body.route-drill .drill-dock-all .dock-group-label {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.6px;
  color: var(--dock-text-faint);
  text-transform: uppercase;
  padding: 0 6px;
}
body.route-drill .drill-dock-all .dock-divider {
  width: 1px;
  height: 18px;
  background: var(--dock-line);
  margin: 0 2px;
}

/* Toggle button — light up blue when "show all" is active. */
body.drill-dock-all-tools .dock-expand-toggle {
  background: var(--dock-blue);
  color: #fff;
}
body.drill-dock-all-tools .dock-expand-toggle .icon-expand { display: none; }
body.drill-dock-all-tools .dock-expand-toggle .icon-collapse { display: block; }

/* ---------- Floating style bar above the dock ----------
   The legacy .line-picker (color swatches + line styles + endings +
   pos-num picker) gets repositioned as a floating panel just above
   the dock primary pill. Same JS hooks, brand-new chrome.
   position:fixed so it stays glued to the viewport like the dock. */
body.route-drill .line-picker {
  position: fixed;
  left: 50%;
  bottom: 86px;            /* 20 (dock bottom) + 54 (pill h) + 12 gap */
  transform: translateX(-50%);
  z-index: 35;
  margin-top: 0;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 11px;
  box-shadow: var(--dock-shadow-sm);
  padding: 5px 8px;
  max-width: calc(100vw - 80px);
  gap: 6px;
}
/* Tighten the floating style bar — drop the STYLE/ENDING/SIZE labels
   and shrink the inter-group gap so the bar isn't twice as wide as
   the dock pill. The buttons themselves are unambiguous enough.
   Also shrinks the line-style previews + swatches + slider so the
   bar matches the dock pill's width. */
body.route-drill .line-picker .lp-label { display: none; }
body.route-drill .line-picker .line-picker-group { gap: 2px; padding: 0; }
body.route-drill .line-picker .line-picker-divider {
  width: 1px;
  height: 16px;
  background: var(--dock-line);
  margin: 0 3px;
}
body.route-drill .line-picker .lp-btn { padding: 2px 3px; border-radius: 5px; }
body.route-drill .line-picker .lp-btn svg,
body.route-drill .line-picker .lp-btn img { width: 28px; height: 12px; }
body.route-drill .line-picker .lp-swatches { gap: 3px; }
body.route-drill .line-picker .lp-swatches .swatch { width: 18px; height: 18px; }
body.route-drill .line-picker input[type="range"] { max-width: 80px; }

/* ---------- Goalie mode: dock pill swaps to goalie tools ----------
   When body.dock-goalie-mode is on, the regular dock-primary buttons
   hide and the goalie-mode strip takes over. Tapping the back button
   restores the normal pill. */
body.route-drill .dock-goalie-strip {
  display: none;
  align-items: center;
  gap: 4px;
  background: var(--dock-panel);
  border: 1px solid rgba(0, 0, 0, 0.09);
  border-radius: 14px;
  padding: 7px;
  box-shadow: var(--dock-shadow);
}
body.dock-goalie-mode.route-drill .drill-dock-primary { display: none; }
body.dock-goalie-mode.route-drill .dock-goalie-strip  { display: flex; }
body.route-drill .dock-goalie-strip .dock-tool { width: 40px; height: 40px; }
body.route-drill .dock-goalie-back {
  width: 32px;
  height: 40px;
  border: none;
  background: transparent;
  border-radius: 8px;
  color: var(--dock-text-mid);
  cursor: pointer;
  display: grid;
  place-items: center;
  margin-right: 2px;
}
body.route-drill .dock-goalie-back:hover { background: var(--dock-panel-2); color: var(--dock-text); }
body.route-drill .dock-goalie-label {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.6px;
  color: var(--dock-text-faint);
  text-transform: uppercase;
  padding-right: 6px;
}

/* ---------- Mode-specific visibility ---------- */
/* Keep the dock primary pill visible in animate mode so the user can
   draw + edit while scrubbing frames. (Ian: "I need to be able to
   edit drills when I'm animating and going frame by frame") */
body.drill-mode-present .drill-dock-primary { display: none; }
body.drill-mode-present .drill-dock-ctx { display: none; }
/* Hide the inline animation panel + frame thumb strip when in DRAW
   mode — they conflict with the floating dock at the viewport bottom
   and the user reaches them via the bottom-left mode switch → ANIM.
   R4 will move them into the dock area when ANIM mode is active. */
body.drill-mode-draw .anim-panel { display: none; }
body.drill-mode-present .canvas-wrap::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.32);
  z-index: 5;
  pointer-events: none;
}

/* ---------- iPad / narrow viewport ---------- */
@media (max-width: 900px) {
  body.route-drill .canvas-wrap { padding-bottom: 180px; }
  body.route-drill .drill-mode-switch { left: 12px; }
  body.route-drill .drill-mode-switch button { width: 38px; height: 38px; }
  body.route-drill .drill-mode-switch button svg { width: 16px; height: 16px; }
  body.route-drill .drill-dock { bottom: 14px; }
  body.route-drill .dock-tool { width: 38px; height: 38px; }
  body.route-drill .dock-tool svg { width: 19px; height: 19px; }
}

/* ---------- Mobile sweep — phones (≤640px) ----------
   (Ian: "make this look good for mobile") */
@media (max-width: 640px) {
  /* Tab strip: compact tabs, hide divider text, smaller surface/time pills */
  body.route-drill #drill-tabs { padding: 4px 8px 4px 4px; min-height: 36px; gap: 4px; }
  body.route-drill .drill-tab { padding: 3px 8px; font-size: 10px; max-width: 100px; }
  body.route-drill .drill-tabs-actions { gap: 4px; }
  body.route-drill .drill-tabs-actions .top-icon-btn,
  body.route-drill .drill-tabs-actions .rink-btn,
  body.route-drill .drill-tabs-actions select.mins { height: 26px; font-size: 10px; padding: 2px 6px; }
  body.route-drill #drill-tabs-slot-share .top-icon-btn::after { content: none; }
  body.route-drill #drill-tabs-slot-share .top-icon-btn { width: 26px; padding: 0; }
  body.route-drill .drill-tabs-divider { display: none; }

  /* Mode switch: even smaller, hugs the edge */
  body.route-drill .drill-mode-switch { left: 6px; padding: 3px; gap: 2px; }
  body.route-drill .drill-mode-switch button { width: 34px; height: 34px; }
  body.route-drill .drill-mode-switch button svg { width: 14px; height: 14px; }
  body.route-drill .drill-mode-switch .ml { font-size: 7px; }
  body.route-drill .drill-mode-switch .rail-label { font-size: 7px; padding: 0 0 2px; }
  body.route-drill .drill-mode-switch .rail-section--actions { gap: 3px; }
  body.route-drill .drill-mode-switch .rail-section--actions .top-icon-btn { width: 24px; height: 24px; }
  body.route-drill .drill-mode-switch .rail-section--actions .top-icon-btn svg { width: 11px; height: 11px; }

  /* Canvas: tighter padding so the rink can use what's left */
  body.route-drill .canvas-wrap { padding-left: 48px; padding-bottom: 130px; }

  /* Floating dock: shrink chips, allow horizontal scroll for the
     expanded "show all" strip so even a 360px phone can tap any tool. */
  body.route-drill .drill-dock { bottom: 12px; max-width: calc(100vw - 16px); }
  body.route-drill .drill-dock-primary { padding: 4px; gap: 1px; flex-wrap: nowrap; justify-content: flex-start; }
  body.route-drill .dock-tool { width: 34px; height: 34px; border-radius: 8px; }
  body.route-drill .dock-tool svg { width: 16px; height: 16px; }
  body.route-drill .dock-tool--letter span { font-size: 13px; }
  body.route-drill .drill-dock-all { padding: 4px 6px; overflow-x: auto; flex-wrap: nowrap; max-width: calc(100vw - 16px); }
  body.route-drill .drill-dock-all .dock-tool { width: 30px; height: 30px; flex-shrink: 0; }
  body.route-drill .drill-dock-all .dock-tool svg { width: 14px; height: 14px; }
  body.route-drill .drill-dock-all .dock-group-label { font-size: 8px; padding: 0 4px; flex-shrink: 0; }

  /* Style bar: smaller buttons + tighter padding, can wrap */
  body.route-drill .line-picker { bottom: 70px; padding: 3px 6px; flex-wrap: wrap; max-width: calc(100vw - 16px); }
  body.route-drill .line-picker .lp-btn { padding: 1px 3px; }
  body.route-drill .line-picker .lp-btn svg,
  body.route-drill .line-picker .lp-btn img { width: 24px; height: 11px; }
  body.route-drill .line-picker .lp-swatches .swatch { width: 16px; height: 16px; }
  body.route-drill .line-picker input[type="range"] { max-width: 60px; }
  body.drill-mode-animate.route-drill .line-picker { bottom: 110px; }

  /* Animation panel: smaller text + buttons in animate mode */
  body.drill-mode-animate.route-drill .anim-panel { bottom: 140px; padding: 6px 8px; font-size: 10px; gap: 4px; }

  /* Sidebar: full-width slide-over on top of everything when open;
     keep the 22px collapsed strip so the user can re-open it. */
  body.route-drill:not(.sidebar-collapsed) .app main {
    grid-template-columns: 22px minmax(0, 1fr) 22px;
  }
  body.route-drill:not(.sidebar-collapsed) aside.sidebar {
    position: fixed;
    top: 90px;
    right: 0;
    bottom: 0;
    width: min(100vw, 360px);
    z-index: 38;
    box-shadow: -10px 0 30px rgba(0,0,0,0.25);
  }
  body.route-drill .sidebar-resize-handle { display: none; } /* Drag handle isn't useful on phones */
  body.route-drill .collapse-strip.right { font-size: 9px; padding: 8px 3px; }

  /* DRILLS / NOTES sidebar tabs */
  body.route-drill .sidebar-tab { padding: 6px 8px; font-size: 11px; }

  /* Notes panel: full-width chrome, even tighter buttons */
  body.route-drill #panel-notes { padding: 10px 8px; }
  body.route-drill #panel-notes .notes-toolbar button { padding: 3px 5px; min-width: 24px; }
}

/* ---------- Tablets / small laptops 641-900px ---------- */
@media (max-width: 900px) and (min-width: 641px) {
  body.route-drill .drill-tabs-divider { display: none; }
}

/* ============================================================
   Save status pill (Option B, 2026-06-15)
   Lives in the tabs action area near Share. Click to save now.
   States — saved (green dot), unsaved (amber), saving (animated
   blue), error (red).
   (Ian: "give me an area on the page that shows save details")
   ============================================================ */
body.route-drill #save-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--dock-line, #e5e7eb);
  background: #fff;
  color: #4b5563;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  transition: background 120ms, border-color 120ms, color 120ms;
}
body.route-drill #save-status:hover {
  background: #f9fafb;
  border-color: #d1d5db;
}
body.route-drill .save-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #10b981;
  flex: 0 0 auto;
}
body.route-drill .save-status--unsaved .save-status-dot { background: #f59e0b; }
body.route-drill .save-status--saving .save-status-dot {
  background: #3b82f6;
  animation: save-status-pulse 1s ease-in-out infinite;
}
body.route-drill .save-status--error {
  border-color: #fecaca;
  background: #fef2f2;
  color: #b91c1c;
}
body.route-drill .save-status--error .save-status-dot { background: #ef4444; }
@keyframes save-status-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.5; transform: scale(0.7); }
}
@media (max-width: 640px) {
  body.route-drill #save-status .save-status-label { display: none; }
}

/* PLAY (Present) mode button — hidden unless the active drill has
   actual animation frames. Drills with 0 or 1 frame have nothing to
   play back, so the button is a UX dead end. JS toggles
   `body.drill-has-anim` whenever state.animFrames changes.
   (Ian: "only show the play button if there is additional frames in
   the drill") */
body.route-drill:not(.drill-has-anim) #drill-mode-switch button[data-mode="present"] {
  display: none;
}

/* Inline rename on drill tab — when contenteditable is on, give the
   name span a subtle editing affordance so the user knows they're in
   edit mode. (Ian: "can i double click on a drill title in the tab to
   rename?") */
body.route-drill .drill-tab-name.is-editing {
  outline: 2px solid var(--blue, #3b82f6);
  outline-offset: 2px;
  border-radius: 4px;
  background: #fff;
  cursor: text;
  user-select: text;
}

/* Tab switch / new tab loading cue. Spinner on the active tab + slight
   canvas dim so the user sees something is happening between click and
   repaint. Otherwise the tab feels dead during the ~30-100ms switch.
   (Ian: "small lag when i click on a tab ... feels like its dead") */
body.route-drill.drill-tab-switching .drill-tab.active .drill-tab-name::before {
  content: '';
  display: inline-block;
  vertical-align: -2px;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  border: 2px solid rgba(0, 0, 0, 0.18);
  border-top-color: var(--blue, #3b82f6);
  border-radius: 50%;
  animation: drill-tab-spin 0.7s linear infinite;
}
body.route-drill.drill-tab-switching .canvas-stage {
  opacity: 0.55;
  transition: opacity 100ms ease;
  pointer-events: none;
}
body.route-drill:not(.drill-tab-switching) .canvas-stage {
  transition: opacity 180ms ease;
}
@keyframes drill-tab-spin {
  to { transform: rotate(360deg); }
}

/* ============================================================
   Save modal v2 — redesigned 2026-06-15
   (Ian: "can you improve the modal for the save as?")
   ============================================================ */
.save-modal-v2 {
  width: 460px;
  max-width: 92vw;
  padding: 22px 22px 18px;
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.25);
}
.save-modal-v2 .save-modal-head {
  margin-bottom: 18px;
}
.save-modal-v2 h3 {
  margin: 0 0 4px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.save-modal-v2 .save-modal-sub {
  margin: 0;
  color: var(--text-dim, #6b7280);
  font-size: 13px;
  line-height: 1.4;
}
.save-modal-v2 .save-modal-section {
  margin-bottom: 14px;
}
.save-modal-v2 .save-modal-section[hidden] {
  display: none;
}
.save-modal-v2 .save-modal-label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--text-dim, #6b7280);
  margin: 0 0 6px;
}
.save-modal-v2 .save-modal-label-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.save-modal-v2 .save-modal-label-row .save-modal-label { margin: 0; }
.save-modal-v2 .save-modal-hint {
  color: #9ca3af;
  font-size: 10px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  margin-left: 4px;
}
.save-modal-v2 .save-modal-folder-count {
  font-size: 11px;
  color: var(--blue, #3b82f6);
  font-weight: 600;
}

/* Segmented control — two stacked cards with radio-driven highlight. */
.save-modal-v2 .seg-control {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.save-modal-v2 .seg-control--scope { grid-template-columns: 1fr 1fr; }
.save-modal-v2 .seg-item {
  display: block;
  padding: 10px 12px;
  border: 1.5px solid var(--border, #e5e7eb);
  border-radius: 10px;
  cursor: pointer;
  transition: background 130ms ease, border-color 130ms ease;
  position: relative;
}
.save-modal-v2 .seg-item input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.save-modal-v2 .seg-item:hover {
  border-color: #d1d5db;
  background: #f9fafb;
}
.save-modal-v2 .seg-item:has(input:checked) {
  border-color: var(--blue, #3b82f6);
  background: rgba(59, 130, 246, 0.06);
}
.save-modal-v2 .seg-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: #111827;
}
.save-modal-v2 .seg-desc {
  display: block;
  font-size: 11.5px;
  color: var(--text-dim, #6b7280);
  margin-top: 2px;
  font-weight: 400;
}

/* Name input with live character counter. */
.save-modal-v2 .save-modal-name-wrap {
  position: relative;
}
.save-modal-v2 .save-modal-name-wrap input {
  padding-right: 56px;
}
.save-modal-v2 .save-modal-name-count {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 11px;
  color: #9ca3af;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.save-modal-v2 .save-modal-name-count.is-near {
  color: #f59e0b;
}
.save-modal-v2 .save-modal-name-count.is-max {
  color: #ef4444;
}

/* Search above the folder list. */
.save-modal-v2 .save-modal-search {
  margin-bottom: 6px;
}

/* Folder list — custom checkboxes (2026-06-15). Native input is
   visually hidden but still focusable for a11y. A styled box renders
   via the `:checked + span::before` selector. Matches the modal's
   segmented controls: blue accent, rounded corners, smooth hover/
   focus. The whole row stays a <label> so click-anywhere-on-row still
   toggles. (Ian: "the checkboxes in the folders are a little weird")
   Picked via ui-ux-pro-max rules: focus-states, touch-target-size,
   color-contrast 4.5:1, duration 130 ms. */
.save-modal-v2 #modal-folders {
  max-height: 180px;
  overflow-y: auto;
  border: 1px solid var(--border-soft, #f3f4f6);
  border-radius: 8px;
  background: #fafafa;
  padding: 4px;
}
.save-modal-v2 .modal-folder-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 9px;
  border-radius: 6px;
  font-size: 13.5px;
  color: #1f2937;
  cursor: pointer;
  user-select: none;
  transition: background 130ms ease, color 130ms ease;
}
.save-modal-v2 .modal-folder-row:hover {
  background: #fff;
}
.save-modal-v2 .modal-folder-row:has(input:checked) {
  background: rgba(59, 130, 246, 0.08);
  color: #111827;
  font-weight: 500;
}
.save-modal-v2 .modal-folder-row.is-hidden {
  display: none;
}
/* Visually hide the native input but keep it in tab order. */
.save-modal-v2 .modal-folder-row input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
/* The span carries the label text AND renders the custom checkbox as
   a ::before pseudo. */
.save-modal-v2 .modal-folder-row > span {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  line-height: 1.3;
}
.save-modal-v2 .modal-folder-row > span::before {
  content: '';
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border: 1.5px solid #cbd5e1;
  border-radius: 5px;
  background: #fff;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 12px 12px;
  transition: background-color 130ms ease, border-color 130ms ease,
              box-shadow 130ms ease;
}
.save-modal-v2 .modal-folder-row:hover > span::before {
  border-color: #94a3b8;
}
/* Checked: blue fill + white SVG check. Data URI so no extra HTTP. */
.save-modal-v2 .modal-folder-row input:checked + span::before {
  background-color: var(--blue, #3b82f6);
  border-color: var(--blue, #3b82f6);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'><polyline points='5 12.5 10 17 19 7'/></svg>");
}
/* Keyboard focus ring for sighted keyboard users. */
.save-modal-v2 .modal-folder-row input:focus-visible + span::before {
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25);
  border-color: var(--blue, #3b82f6);
}
@media (prefers-reduced-motion: reduce) {
  .save-modal-v2 .modal-folder-row,
  .save-modal-v2 .modal-folder-row > span::before {
    transition: none;
  }
}

/* "Add a new folder" with leading plus icon. */
.save-modal-v2 .save-modal-new-folder {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1.5px dashed var(--border, #e5e7eb);
  border-radius: 8px;
  padding: 4px 10px;
  margin-top: 8px;
  color: var(--text-dim, #6b7280);
  transition: border-color 120ms ease;
}
.save-modal-v2 .save-modal-new-folder:focus-within {
  border-color: var(--blue, #3b82f6);
  color: var(--blue, #3b82f6);
}
.save-modal-v2 .save-modal-new-folder input {
  border: none;
  background: transparent;
  padding: 8px 0;
  font-size: 13px;
}

/* Action row — larger buttons + Save is the primary blue. */
.save-modal-v2 .modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft, #f3f4f6);
}
.save-modal-v2 .modal-actions .btn {
  padding: 9px 18px;
  font-size: 13.5px;
  font-weight: 600;
  border-radius: 8px;
}

/* ============================================================
   Realistic video export — split Export-video button + modal.
   The caret on the right side of the button opens a small menu
   with Diagram (.webm) and Realistic (AI · beta). The modal
   walks the coach through prompt review → submit → poll → play.
   ============================================================ */
.anim-export-group {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  gap: 0;
}
.anim-export-group .anim-export-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  padding-right: 10px;
}
.anim-export-group .anim-export-caret {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  padding: 0 6px;
  margin-left: 1px;
  min-width: 22px;
}
.anim-export-group .anim-export-caret svg { width: 12px; height: 12px; }
.anim-export-group .anim-export-caret[aria-expanded="true"] {
  background: rgba(0, 0, 0, 0.06);
}

.anim-export-menu {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  min-width: 230px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 12px;
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.18);
  padding: 6px;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* When portaled to document.body, switch from absolute (positioned
   relative to .anim-export-group inside the z:36 .anim-panel stacking
   context) to fixed at the viewport level. JS sets left/top from the
   button's getBoundingClientRect; the menu now stacks over the dock,
   topbar, and tab strip. */
.anim-export-menu--portal {
  position: fixed;
  bottom: auto;
  right: auto;
  z-index: 2300;
}
.anim-export-menu[hidden] { display: none; }
.anim-export-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  background: transparent;
  border-radius: 8px;
  cursor: pointer;
  text-align: left;
  color: var(--text, #111);
}
.anim-export-item:hover { background: rgba(0, 0, 0, 0.05); }
.anim-export-item-icon {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.05);
  color: var(--text, #111);
}
.anim-export-item-icon svg { width: 16px; height: 16px; }
.anim-export-item-pro .anim-export-item-icon {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
}
.anim-export-item-main {
  display: flex; flex-direction: column; gap: 2px;
}
.anim-export-item-title {
  font-weight: 600; font-size: 13px; color: var(--text, #111);
  display: inline-flex; align-items: center; gap: 8px;
}
.anim-export-item-sub {
  font-size: 11px; color: rgba(0, 0, 0, 0.55);
}
.anim-export-beta {
  font-size: 9.5px; letter-spacing: 0.05em; text-transform: uppercase;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff; padding: 2px 6px; border-radius: 999px; font-weight: 700;
}

/* ---- Modal ---- */
.rv-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(8, 10, 18, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 2400;
  padding: 24px;
  animation: rv-fade 160ms ease-out;
}
.rv-modal-backdrop[hidden] { display: none; }
@keyframes rv-fade { from { opacity: 0; } to { opacity: 1; } }
body.rv-modal-open { overflow: hidden; }

.rv-modal {
  background: #fff;
  border-radius: 16px;
  width: min(640px, 100%);
  max-height: 90vh;
  overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.3);
  animation: rv-rise 200ms ease-out;
}
@keyframes rv-rise { from { transform: translateY(12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

.rv-modal-head {
  padding: 18px 20px 14px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.07);
  display: flex; align-items: center; justify-content: space-between;
}
.rv-modal-head h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--text, #111);
}
.rv-modal-icon {
  width: 28px; height: 28px;
  border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
}
.rv-modal-icon svg { width: 16px; height: 16px; }
.rv-badge {
  font-size: 9.5px; letter-spacing: 0.05em; text-transform: uppercase;
  background: rgba(108, 92, 231, 0.12); color: #6c5ce7;
  padding: 3px 7px; border-radius: 999px; font-weight: 700;
}
.rv-modal-close {
  border: 0; background: transparent; cursor: pointer;
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px;
  color: rgba(0, 0, 0, 0.5);
}
.rv-modal-close:hover { background: rgba(0, 0, 0, 0.06); color: var(--text, #111); }
.rv-modal-close svg { width: 16px; height: 16px; }

.rv-modal-body {
  padding: 20px;
  overflow-y: auto;
}

.rv-tagline {
  margin: 0 0 14px;
  font-size: 13.5px;
  color: rgba(0, 0, 0, 0.62);
  line-height: 1.55;
}
.rv-field-label {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(0, 0, 0, 0.5);
  margin-bottom: 6px;
}
.rv-prompt {
  width: 100%;
  font: 13.5px/1.55 inherit;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid rgba(0, 0, 0, 0.12);
  resize: vertical;
  min-height: 140px;
  background: #fafbff;
  color: var(--text, #111);
  outline: none;
  transition: border-color 120ms, background 120ms;
}
.rv-prompt:focus {
  border-color: #6c5ce7;
  background: #fff;
  box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.12);
}
.rv-prompt-meta {
  display: flex; justify-content: flex-end;
  font-size: 11.5px; color: rgba(0, 0, 0, 0.45);
  margin-top: 4px;
}
.rv-row {
  display: flex; align-items: center; gap: 12px;
  margin-top: 16px;
}
.rv-row .rv-field-label { margin: 0; }

.rv-segmented {
  display: inline-flex;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
}
.rv-seg {
  border: 0;
  background: transparent;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.6);
  cursor: pointer;
  transition: background 120ms, color 120ms;
}
.rv-seg[aria-pressed="true"] {
  background: #fff;
  color: var(--text, #111);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.rv-footnote {
  margin: 18px 0 0;
  font-size: 11.5px;
  color: rgba(0, 0, 0, 0.5);
  line-height: 1.5;
}

.rv-actions {
  display: flex; justify-content: flex-end; gap: 10px;
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid rgba(0, 0, 0, 0.06);
}
.rv-btn-primary,
.rv-btn-secondary {
  border: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 10px 16px;
  border-radius: 10px;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  text-decoration: none;
}
.rv-btn-primary {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  box-shadow: 0 2px 8px rgba(108, 92, 231, 0.3);
}
.rv-btn-primary:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(108, 92, 231, 0.35); }
.rv-btn-primary svg { width: 14px; height: 14px; }
.rv-btn-secondary {
  background: rgba(0, 0, 0, 0.06);
  color: var(--text, #111);
}
.rv-btn-secondary:hover { background: rgba(0, 0, 0, 0.1); }
.rv-btn-secondary svg { width: 14px; height: 14px; }

.rv-loading, .rv-progress, .rv-result, .rv-error {
  text-align: center;
  padding: 18px 10px;
}
.rv-loading p { margin: 14px 0 0; color: rgba(0, 0, 0, 0.6); font-size: 13.5px; }
.rv-spinner {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 3px solid rgba(108, 92, 231, 0.2);
  border-top-color: #6c5ce7;
  margin: 0 auto;
  animation: rv-spin 700ms linear infinite;
}
.rv-spinner-lg { width: 52px; height: 52px; border-width: 4px; }
@keyframes rv-spin { to { transform: rotate(360deg); } }

.rv-progress h3 {
  margin: 16px 0 6px;
  font-size: 17px;
  font-weight: 700;
  color: var(--text, #111);
}
.rv-progress-sub {
  margin: 0 auto 18px;
  font-size: 13px; color: rgba(0, 0, 0, 0.6);
  line-height: 1.55;
  max-width: 440px;
}
.rv-progress-bar {
  width: 100%;
  height: 6px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.08);
  overflow: hidden;
}
.rv-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #6c5ce7, #00cec9);
  transition: width 250ms ease-out;
}

.rv-result .rv-video {
  width: 100%;
  border-radius: 12px;
  background: #000;
  display: block;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
}
.rv-result-caption {
  margin: 14px 0 0;
  font-size: 13px;
  color: rgba(0, 0, 0, 0.62);
  text-align: center;
}

.rv-error h3 {
  margin: 4px 0 8px;
  font-size: 15px;
  font-weight: 700;
  color: #c0392b;
}
.rv-error p {
  margin: 0;
  font-size: 13px;
  color: rgba(0, 0, 0, 0.7);
  line-height: 1.55;
  text-align: left;
  background: rgba(192, 57, 43, 0.06);
  padding: 12px 14px;
  border-radius: 10px;
  word-break: break-word;
}

@media (max-width: 520px) {
  .rv-modal { max-height: 92vh; border-radius: 14px; }
  .rv-modal-body { padding: 16px; }
  .rv-row { flex-direction: column; align-items: flex-start; }
  .rv-actions { flex-direction: column-reverse; }
  .rv-actions .rv-btn-primary,
  .rv-actions .rv-btn-secondary { width: 100%; justify-content: center; }
}

/* ============================================================
   Drill-board boot overlay — hides the FOUC during the gap
   between HTML parse and tabsRestore. Removed once tabs and
   the active drill have been hydrated from localStorage.
   ============================================================ */
.drill-boot-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg, #f5f6f8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 5000;
  opacity: 1;
  transition: opacity 280ms ease-out;
  pointer-events: auto;
}
.drill-boot-spinner {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 3px solid rgba(0, 0, 0, 0.08);
  border-top-color: var(--accent, #6c5ce7);
  animation: drill-boot-spin 720ms linear infinite;
}
@keyframes drill-boot-spin { to { transform: rotate(360deg); } }
html:not(.rb-booting) .drill-boot-overlay {
  opacity: 0;
  pointer-events: none;
}
/* Hide the rest of the drill UI while booting — overlay covers it,
   but if the user squints/inspects mid-load they shouldn't see the
   half-rendered "Untitled" drill behind. */
html.rb-booting body.route-drill .app { opacity: 0; }
body.route-drill .app { transition: opacity 280ms ease-out; }

/* ============================================================
   Gradient treatment for AI features + state indicators.
   Establishes the "gradient = special / AI / state" pattern
   already used on the Realistic Video icon + stamp palette.
   ============================================================ */

/* --- AI Coach buttons (Adapt / Cues / Critique) ---
   AI features get the purple→teal treatment to brand them as such.
   Override the existing color-mix flat fill via higher specificity
   on the drill-board notes panel. */
body.route-drill .notes-ai-btn,
body.route-drill #panel-notes .notes-ai-btn {
  background: linear-gradient(135deg, #6c5ce7, #00cec9) !important;
  color: #ffffff !important;
  border: none !important;
  box-shadow: 0 1px 2px rgba(108, 92, 231, 0.25);
  transition: transform 120ms, box-shadow 120ms, opacity 120ms;
}
body.route-drill .notes-ai-btn:hover,
body.route-drill #panel-notes .notes-ai-btn:hover {
  background: linear-gradient(135deg, #6c5ce7, #00cec9) !important;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(108, 92, 231, 0.32);
}
body.route-drill .notes-ai-btn:disabled,
body.route-drill #panel-notes .notes-ai-btn:disabled {
  transform: none;
  box-shadow: none;
}

/* --- Animated-drill badge on drill cards ---
   Was flat blue rgba(30,111,191). Same gradient family as the
   "Blue" stamp swatch so the badge and the player stamps inside
   the thumbnail read as the same brand color. */
.anim-badge {
  background: linear-gradient(135deg, #6c5ce7, #00cec9) !important;
  box-shadow: 0 1px 3px rgba(108, 92, 231, 0.28) !important;
}

/* --- Favorite star (filled state) on drill cards ---
   Was flat red. A warm gold→amber gradient lands closer to
   Apple's filled-star treatment — feels premium, matches the
   yellow swatch family. White star reads cleanly on top. */
.drill-card .fav.fav--on {
  background: linear-gradient(135deg, #fbbf24, #fb923c) !important;
  color: #ffffff !important;
  box-shadow: 0 1px 3px rgba(251, 146, 60, 0.32);
}
.drill-card .fav.fav--on:hover {
  background: linear-gradient(135deg, #fbbf24, #fb923c) !important;
  color: #ffffff !important;
  transform: scale(1.08);
}

/* --- Save status pill (success state) ---
   Default state is "Saved" — promote the green dot into a
   green→lime gradient so the constant attention real estate
   feels alive. Other states (saving/unsaved/error) keep their
   semantic flat color so it's still legible at a glance. */
body.route-drill #save-status:not(.save-status--saving):not(.save-status--unsaved):not(.save-status--error) .save-status-dot {
  background: linear-gradient(135deg, #10b981, #84cc16);
  box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.12);
}

/* ============================================================
   Drill-tab kebab menu — 3-dot per-tab actions (add to plan,
   rename, duplicate). Portaled to body to escape the tab strip's
   stacking context.
   ============================================================ */
.drill-tab-kebab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: 2px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: background 120ms, color 120ms;
}
.drill-tab-kebab:hover {
  background: rgba(0, 0, 0, 0.07);
  color: var(--text, #111);
}
.drill-tab-kebab svg { width: 16px; height: 16px; }
.drill-tab.active .drill-tab-kebab { color: rgba(0, 0, 0, 0.6); }

.drill-tab-kebab-menu {
  position: fixed;
  min-width: 220px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 12px;
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.18);
  padding: 6px;
  z-index: 2300;
  display: flex;
  flex-direction: column;
  gap: 2px;
  animation: kebab-rise 140ms ease-out;
}
@keyframes kebab-rise { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.drill-tab-kebab-menu > button {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font: inherit;
  font-size: 13px;
  color: var(--text, #111);
  text-align: left;
  cursor: pointer;
  width: 100%;
}
.drill-tab-kebab-menu > button:hover { background: rgba(0, 0, 0, 0.05); }
.drill-tab-kebab-menu .kebab-item-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: 7px;
  background: rgba(0, 0, 0, 0.05);
  color: rgba(0, 0, 0, 0.7);
}
.drill-tab-kebab-menu .kebab-item-icon svg { width: 15px; height: 15px; }

/* ============================================================
   /drill-share — premium share-link landing page.
   First impression for recipients clicking a coach's emailed
   link. Coachly brand: 135° purple→teal gradient flagship,
   glassmorphism + white surfaces, Geist/system-ui type stack.
   ============================================================ */
body.route-drill-share {
  background:
    radial-gradient(1200px 600px at 12% -10%, rgba(108, 92, 231, 0.10), transparent 60%),
    radial-gradient(1000px 500px at 105% 0%, rgba(0, 206, 201, 0.10), transparent 60%),
    linear-gradient(180deg, #fbfbfd 0%, #f6f7fb 100%);
  min-height: 100vh;
}
.page-drill-share {
  position: relative;
  width: 90%;
  /* Hard cap at 1620px so anything wider than ~1800px viewport stops
     growing — keeps line lengths sane on ultrawides. Below that the
     card stays at 90% of the viewport. */
  max-width: 1620px;
  margin: 0 auto;
  padding: 28px 0 60px;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* Aurora bloom — subtle background atmosphere so the card floats
   on something, not flat gray. Pointer-events none + behind everything.
   Scales with viewport so the bloom feels right at any width. */
.dshare-aurora {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}
.dshare-aurora-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(100px);
  opacity: 0.45;
  will-change: transform;
}
.dshare-aurora-blob--a {
  width: 40vw; height: 40vw;
  min-width: 420px; min-height: 420px;
  top: -10vw; left: -10vw;
  background: radial-gradient(circle, #6c5ce7 0%, transparent 65%);
}
.dshare-aurora-blob--b {
  width: 36vw; height: 36vw;
  min-width: 380px; min-height: 380px;
  top: 8vw; right: -8vw;
  background: radial-gradient(circle, #00cec9 0%, transparent 65%);
}
@media (prefers-reduced-motion: reduce) {
  .dshare-aurora-blob { animation: none; }
}

/* Brand mark — centered header. Trust signal for first-time visitors. */
.dshare-brand {
  position: relative;
  z-index: 2;
  margin-bottom: 36px;
  align-self: flex-start;
}
.dshare-brand-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--text, #111);
  transition: opacity 150ms;
}
.dshare-brand-link:hover { opacity: 0.75; }
.dshare-brand-mark {
  width: 32px; height: 32px;
  border-radius: 9px;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff;
  box-shadow: 0 4px 12px rgba(108, 92, 231, 0.28);
}
.dshare-brand-mark svg { width: 18px; height: 18px; }
.dshare-brand-text {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text, #111);
}

/* Loading state */
.dshare-loading {
  position: relative;
  z-index: 1;
  display: flex; flex-direction: column; align-items: center;
  padding: 80px 20px;
  color: rgba(0, 0, 0, 0.55);
}
.dshare-loading p { margin-top: 16px; font-size: 14px; font-weight: 500; }
.dshare-spinner {
  width: 40px; height: 40px;
  border-radius: 50%;
  border: 3px solid rgba(108, 92, 231, 0.15);
  border-top-color: #6c5ce7;
  animation: dshare-spin 720ms linear infinite;
}
@keyframes dshare-spin { to { transform: rotate(360deg); } }

/* The hero card — two-column landing layout, centered in viewport.
   Thumb on the left, metadata column on the right. Body column gets
   its own scroll if the description is very long so the rink stays
   visible while the recipient reads. */
.dshare-hero {
  position: relative;
  z-index: 1;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(360px, 1.35fr) minmax(340px, 1fr);
  align-items: start;
  gap: 36px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 24px;
  padding: clamp(24px, 2.4vw, 40px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 30px 60px -20px rgba(17, 24, 39, 0.18),
    0 10px 20px -10px rgba(108, 92, 231, 0.10);
}
.dshare-hero[hidden] { display: none; }

/* Thumb panel — clean white surface, no border, so the rink SVG
   sits flush with the card. Sticky so a long description column
   scrolls past while the rink stays in view. */
.dshare-hero-thumb {
  position: sticky;
  top: 24px;
  width: 100%;
  background: #ffffff;
  border-radius: 18px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  display: flex; align-items: center; justify-content: center;
}
.dshare-hero-thumb--clickable {
  cursor: zoom-in;
  transition: transform 200ms cubic-bezier(.3, .9, .4, 1.1);
}
.dshare-hero-thumb--clickable:hover img { transform: scale(1.012); }
.dshare-hero-thumb--clickable img { transition: transform 280ms ease; }
.dshare-hero-thumb--clickable:focus-visible {
  outline: 3px solid rgba(108, 92, 231, 0.45);
  outline-offset: 3px;
}

/* Lightbox — click rink to enlarge */
.dshare-lightbox {
  position: fixed;
  inset: 0;
  z-index: 5000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(8, 12, 24, 0.78);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  padding: 40px;
  opacity: 0;
  transition: opacity 200ms ease-out;
}
.dshare-lightbox[hidden] { display: none; }
.dshare-lightbox--open { opacity: 1; }
.dshare-lightbox-frame {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: 1600px;
  display: flex; align-items: center; justify-content: center;
  transform: scale(0.97);
  transition: transform 280ms cubic-bezier(.3, .9, .4, 1.1);
}
.dshare-lightbox--open .dshare-lightbox-frame { transform: scale(1); }
.dshare-lightbox-frame img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 18px;
  background: #fff;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
}
.dshare-lightbox-close {
  position: absolute;
  top: 20px; right: 20px;
  width: 44px; height: 44px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.10);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 150ms, transform 150ms;
  z-index: 1;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.dshare-lightbox-close:hover { background: rgba(255, 255, 255, 0.18); transform: scale(1.05); }
.dshare-lightbox-close svg { width: 18px; height: 18px; }

@media (max-width: 720px) {
  .dshare-lightbox { padding: 16px; }
  .dshare-lightbox-close { top: 14px; right: 14px; width: 38px; height: 38px; }
}
.dshare-hero-thumb img {
  width: 100%; height: 100%;
  object-fit: contain;
  display: block;
  position: relative; z-index: 1;
}
.dshare-thumb-glow {
  position: absolute;
  inset: -1px;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(135deg, rgba(108, 92, 231, 0.18), rgba(0, 206, 201, 0.18));
  opacity: 0;
  transition: opacity 260ms;
}
.dshare-hero-thumb:hover .dshare-thumb-glow { opacity: 1; }
.dshare-thumb-badges {
  position: absolute;
  top: 14px; left: 14px;
  display: flex; gap: 6px;
  z-index: 2;
}
.dshare-thumb-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: #fff;
  background: rgba(15, 23, 42, 0.78);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.22);
}
.dshare-thumb-badge svg { width: 11px; height: 11px; }
.dshare-thumb-badge--anim {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  box-shadow: 0 4px 12px rgba(108, 92, 231, 0.35);
}

/* Body column — left-aligned next to the thumb. */
.dshare-hero-body {
  display: flex; flex-direction: column;
  min-width: 0;
  padding: 2px 0;
}
.dshare-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(0, 0, 0, 0.45);
  margin-bottom: 12px;
}
.dshare-eyebrow-sep { color: rgba(0, 0, 0, 0.25); }
.dshare-eyebrow-sport {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 800;
  letter-spacing: 0.06em;
}
.dshare-hero-body h1 {
  margin: 0 0 14px;
  font-size: clamp(26px, 2.2vw, 36px);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text, #0f172a);
  line-height: 1.15;
  word-wrap: break-word;
}
.dshare-meta-row {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-bottom: 18px;
}
.dshare-chip {
  display: inline-flex; align-items: center;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.05);
  border: 1px solid rgba(15, 23, 42, 0.04);
  font-size: 12px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.78);
}

/* Owner attribution row — avatar + name + handle. Compact pill,
   left-aligned in the body column. */
.dshare-attribution {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 8px 8px;
  margin-bottom: 18px;
  background: rgba(108, 92, 231, 0.05);
  border: 1px solid rgba(108, 92, 231, 0.12);
  border-radius: 999px;
  align-self: flex-start;
}
.dshare-avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  flex-shrink: 0;
  box-shadow: 0 4px 10px rgba(108, 92, 231, 0.28);
}
.dshare-attribution-body {
  display: inline-flex; align-items: baseline; gap: 6px;
  font-size: 13px;
  line-height: 1.3;
}
.dshare-attribution-label {
  font-size: 11.5px;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.5);
}
.dshare-attribution-name {
  font-weight: 700;
  color: var(--text, #0f172a);
}
.dshare-attribution-handle {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.45);
  font-variant-numeric: tabular-nums;
}

/* Description — left-aligned for natural reading. */
.dshare-description {
  font-size: 14.5px;
  color: rgba(15, 23, 42, 0.75);
  line-height: 1.65;
  margin-bottom: 22px;
  flex: 1;
}
.dshare-description-empty { color: rgba(0, 0, 0, 0.4); font-style: italic; }

/* Sport-mismatch warning */
.dshare-sport-mismatch {
  display: flex; gap: 10px; align-items: flex-start;
  background: linear-gradient(135deg, rgba(251, 191, 36, 0.10), rgba(251, 146, 60, 0.10));
  border: 1px solid rgba(251, 146, 60, 0.25);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 13px;
  color: #92400e;
  line-height: 1.5;
  margin-bottom: 18px;
}
.dshare-sport-mismatch[hidden] { display: none; }
.dshare-sport-mismatch svg { width: 18px; height: 18px; color: #d97706; flex-shrink: 0; margin-top: 1px; }
.dshare-sport-mismatch strong { color: #78350f; font-weight: 700; }

/* CTA row — left-aligned, pinned to the bottom of the body column. */
.dshare-cta {
  display: flex; gap: 12px; align-items: center;
  margin-top: auto;
}
.dshare-claim-btn {
  position: relative;
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 24px;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  border: 0;
  border-radius: 14px;
  font: inherit;
  font-size: 14.5px;
  font-weight: 700;
  cursor: pointer;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.3) inset,
    0 8px 22px -4px rgba(108, 92, 231, 0.45),
    0 2px 6px rgba(108, 92, 231, 0.18);
  transition: transform 180ms cubic-bezier(.3, .9, .4, 1.1),
              box-shadow 180ms cubic-bezier(.3, .9, .4, 1.1),
              filter 180ms;
  overflow: hidden;
  isolation: isolate;
}
.dshare-claim-btn::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(120deg, transparent 35%, rgba(255,255,255,0.32) 50%, transparent 65%);
  transform: translateX(-120%);
  transition: transform 600ms cubic-bezier(.3, .9, .4, 1.1);
  pointer-events: none;
  z-index: -1;
}
.dshare-claim-btn:hover {
  transform: translateY(-2px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.4) inset,
    0 14px 30px -6px rgba(108, 92, 231, 0.55),
    0 4px 10px rgba(108, 92, 231, 0.25);
}
.dshare-claim-btn:hover::before { transform: translateX(120%); }
.dshare-claim-btn:active { transform: translateY(0); }
.dshare-claim-btn:focus-visible {
  outline: 3px solid rgba(108, 92, 231, 0.45);
  outline-offset: 2px;
}
.dshare-claim-btn:disabled { opacity: 0.5; cursor: progress; transform: none; filter: saturate(0.5); }
.dshare-claim-btn svg { width: 18px; height: 18px; }
.dshare-claim-btn--blocked { opacity: 0.7; filter: saturate(0.6); }
.dshare-claim-btn--loading svg { animation: dshare-spin 700ms linear infinite; }

.dshare-cta-secondary {
  font-size: 13.5px;
  font-weight: 500;
  color: rgba(15, 23, 42, 0.55);
  text-decoration: none;
  padding: 10px 14px;
  border-radius: 10px;
  transition: background 150ms, color 150ms;
}
.dshare-cta-secondary:hover {
  color: var(--text, #0f172a);
  background: rgba(15, 23, 42, 0.04);
}
.dshare-cta-secondary:focus-visible {
  outline: 2px solid rgba(108, 92, 231, 0.45);
  outline-offset: 2px;
}

/* Footer mark */
.dshare-footer {
  position: relative;
  z-index: 1;
  margin-top: 40px;
  padding-top: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 12.5px;
  color: rgba(15, 23, 42, 0.5);
}
.dshare-footer strong { color: var(--text, #0f172a); font-weight: 700; }
.dshare-footer-mark {
  width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  color: rgba(108, 92, 231, 0.85);
}
.dshare-footer-mark svg { width: 16px; height: 16px; }
.dshare-footer-sep { color: rgba(15, 23, 42, 0.25); }
.dshare-footer-link {
  color: rgba(108, 92, 231, 0.85);
  text-decoration: none;
  font-weight: 600;
}
.dshare-footer-link:hover { color: #6c5ce7; text-decoration: underline; }

@media (max-width: 880px) {
  .dshare-hero {
    grid-template-columns: 1fr;
    gap: 22px;
  }
}
@media (max-width: 720px) {
  .page-drill-share { width: 100%; padding: 20px 16px 40px; }
  .dshare-brand { margin-bottom: 24px; }
  .dshare-hero {
    gap: 20px;
    padding: 20px;
    border-radius: 20px;
  }
  .dshare-hero-thumb { aspect-ratio: 16 / 9; }
  .dshare-cta { flex-direction: column-reverse; align-items: stretch; }
  .dshare-claim-btn { justify-content: center; padding: 14px 20px; }
  .dshare-cta-secondary { text-align: center; }
  .dshare-aurora-blob { filter: blur(60px); }
}

/* ============================================================
   Share modal — link tab additions: expiry picker + live stats.
   ============================================================ */
.share-link-expiry {
  display: flex; align-items: center; gap: 10px;
  margin: 8px 0 12px;
  font-size: 12px;
}
.share-link-expiry-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(0, 0, 0, 0.5);
}
.share-link-expiry-segs {
  display: inline-flex;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
}
.share-link-expiry-seg {
  border: 0;
  background: transparent;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.6);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
}
.share-link-expiry-seg[aria-pressed="true"] {
  background: #fff;
  color: var(--text, #111);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.share-link-stats {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(0, 0, 0, 0.07);
}
.share-link-stats-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
}
.share-link-stat {
  background: rgba(0, 0, 0, 0.03);
  border-radius: 10px;
  padding: 10px 12px;
  text-align: center;
}
.share-link-stat-num {
  display: block;
  font-size: 20px;
  font-weight: 700;
  color: var(--text, #111);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.share-link-stat-label {
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(0, 0, 0, 0.5);
  margin-top: 2px;
  display: inline-block;
}
.share-link-stat-expiry .share-link-stat-num { font-size: 17px; }

/* Regenerate button — small icon-only, sits next to the primary Copy
   button. Subtle so it doesn't compete with the main action. */
.share-link-regen {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.08);
  background: transparent;
  color: rgba(0, 0, 0, 0.55);
  border-radius: 6px;
  cursor: pointer;
}
.share-link-regen svg { width: 14px; height: 14px; }
.share-link-regen:hover { background: rgba(0, 0, 0, 0.04); color: var(--text, #111); }

/* Polished placeholder when the share snapshot has no thumb.
   Only the placeholder gets a subtle tinted bg — the regular rink
   thumb sits on plain white so the SVG doesn't look framed. */
.dshare-thumb-placeholder {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  width: 100%; height: 100%;
  color: rgba(108, 92, 231, 0.55);
  background:
    radial-gradient(circle at 30% 20%, rgba(108, 92, 231, 0.08), transparent 60%),
    radial-gradient(circle at 70% 80%, rgba(0, 206, 201, 0.08), transparent 60%),
    #fafbff;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.dshare-thumb-placeholder svg { width: 44px; height: 44px; opacity: 0.7; }

/* Coach-authored rich-text description — list bullets + spacing */
.dshare-description ul, .dshare-description ol {
  margin: 6px 0; padding-left: 20px;
}
.dshare-description ul { list-style: disc; }
.dshare-description ol { list-style: decimal; }
.dshare-description li { margin: 2px 0; }
.dshare-description p { margin: 6px 0; }
.dshare-description strong { font-weight: 600; }
.dshare-description em { font-style: italic; }

/* ============================================================
   PLANS LANDING — premium ui-ux-pro-max polish pass.
   Overrides the legacy clipboard skeuomorphism with a modern
   card system that matches the Coachly brand language
   (135° purple→teal gradient, glassmorphism, polished CTAs).
   Appended last so all rules win without selector wars.
   ============================================================ */

/* Page background — subtle aurora to match the share view's vibe */
body.route-plans {
  background:
    radial-gradient(900px 500px at 8% -8%, rgba(108, 92, 231, 0.07), transparent 60%),
    radial-gradient(800px 460px at 102% 5%, rgba(0, 206, 201, 0.07), transparent 60%),
    linear-gradient(180deg, #fbfbfd 0%, #f6f7fb 100%);
}

/* Page header — bigger headline, gradient brand mark */
.plans-page .page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 0 6px;
  margin-bottom: 22px;
}
.plans-page .page-header h1 {
  font-size: 28px !important;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 4px;
  color: var(--text, #0f172a);
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.plans-page .page-header h1::before {
  content: '';
  width: 36px; height: 36px;
  border-radius: 10px;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  background-image:
    linear-gradient(135deg, transparent 30%, rgba(255,255,255,0.18) 50%, transparent 70%),
    linear-gradient(135deg, #6c5ce7, #00cec9);
  box-shadow: 0 4px 14px rgba(108, 92, 231, 0.28);
  flex-shrink: 0;
  position: relative;
}
.plans-page .page-header h1::after {
  content: '';
  position: absolute;
  left: 8px; top: 9px;
  width: 18px; height: 18px;
  background: no-repeat center / contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='5' width='18' height='16' rx='2'/><path d='M16 3v4M8 3v4M3 11h18M8 15h3M8 18h6'/></svg>");
}
.plans-page .page-header .sub {
  font-size: 13.5px;
  color: rgba(15, 23, 42, 0.55);
  margin: 0;
}

/* Action buttons up top — AI gets brand gradient, New Plan gets soft outlined */
.plans-page .page-actions { display: flex; gap: 10px; }
.plans-page #btn-ai-plan {
  padding: 9px 16px !important;
  border: 0 !important;
  border-radius: 11px !important;
  background: linear-gradient(135deg, #6c5ce7, #00cec9) !important;
  color: #fff !important;
  font-weight: 700 !important;
  font-size: 13px !important;
  box-shadow: 0 6px 18px -4px rgba(108, 92, 231, 0.42), 0 2px 6px rgba(108, 92, 231, 0.18) !important;
  transition: transform 160ms, box-shadow 160ms !important;
}
.plans-page #btn-ai-plan:hover { transform: translateY(-1px); box-shadow: 0 10px 24px -6px rgba(108, 92, 231, 0.52) !important; }
.plans-page #btn-ai-plan svg { stroke: #fff; opacity: 0.95; }
.plans-page #btn-new-plan {
  padding: 9px 18px !important;
  border-radius: 11px !important;
  background: #fff !important;
  color: var(--text, #0f172a) !important;
  border: 1px solid rgba(15, 23, 42, 0.12) !important;
  font-weight: 700 !important;
  font-size: 13px !important;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.06) !important;
  transition: transform 160ms, box-shadow 160ms, border-color 160ms !important;
}
.plans-page #btn-new-plan:hover {
  border-color: rgba(108, 92, 231, 0.40) !important;
  box-shadow: 0 6px 16px -4px rgba(108, 92, 231, 0.22) !important;
  transform: translateY(-1px);
}

/* Toolbar — glass card */
.plans-page .plans-toolbar {
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: 16px;
  padding: 16px;
  margin-bottom: 28px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset, 0 6px 20px -8px rgba(15, 23, 42, 0.08);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
}
.plans-page .plans-search { position: relative; }
.plans-page .plans-search input {
  width: 100%;
  padding: 12px 14px 12px 42px;
  font: inherit;
  font-size: 14px;
  background: #fafbff;
  border: 1px solid rgba(15, 23, 42, 0.10);
  border-radius: 12px;
  color: var(--text, #0f172a);
  transition: border-color 150ms, box-shadow 150ms, background 150ms;
  outline: 0;
}
.plans-page .plans-search input::placeholder { color: rgba(15, 23, 42, 0.42); }
.plans-page .plans-search input:focus {
  border-color: #6c5ce7;
  background: #fff;
  box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.14);
}
.plans-page .plans-search-icon {
  position: absolute;
  left: 14px; top: 50%;
  width: 16px; height: 16px;
  transform: translateY(-50%);
  color: rgba(15, 23, 42, 0.45);
  pointer-events: none;
}
.plans-page .plans-toolbar-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.plans-page .plans-book-filters {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.plans-page .plans-book-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  border: 1px solid rgba(15, 23, 42, 0.10);
  background: #fff;
  border-radius: 999px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.65);
  cursor: pointer;
  transition: background 150ms, border-color 150ms, color 150ms, transform 120ms;
}
.plans-page .plans-book-chip:hover {
  border-color: rgba(108, 92, 231, 0.30);
  color: var(--text, #0f172a);
  transform: translateY(-1px);
}
.plans-page .plans-book-chip.is-active {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 4px 12px -2px rgba(108, 92, 231, 0.42);
}
.plans-page .plans-book-chip-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.06);
  color: rgba(15, 23, 42, 0.60);
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.plans-page .plans-book-chip.is-active .plans-book-chip-count {
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
}
.plans-page .plans-sort { display: flex; align-items: center; gap: 8px; }
.plans-page .plans-sort-label {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(15, 23, 42, 0.5);
}
.plans-page .plans-sort-select {
  padding: 8px 32px 8px 12px;
  border: 1px solid rgba(15, 23, 42, 0.10);
  border-radius: 10px;
  background: #fafbff no-repeat right 10px center / 12px url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.4' stroke-linecap='round'><polyline points='6 9 12 15 18 9'/></svg>");
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text, #0f172a);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  transition: border-color 150ms, background-color 150ms;
}
.plans-page .plans-sort-select:hover { border-color: rgba(108, 92, 231, 0.30); }
.plans-page .plans-sort-select:focus { outline: 0; border-color: #6c5ce7; box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.14); }

/* Shelves */
.plans-page #plan-grid { padding-top: 0; }
.plans-page .plans-shelf { margin-bottom: 36px; }
.plans-page .plans-shelf-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
}
.plans-page .plans-shelf-title {
  font-size: 14px !important;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--text, #0f172a);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 12.5px !important;
  margin: 0;
}
.plans-page .plans-shelf-count {
  font-size: 12px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.45);
  font-variant-numeric: tabular-nums;
}
.plans-page .plans-shelf-floor { display: none; }
.plans-page .plans-shelf-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 18px;
  align-items: stretch;
}

/* Plan card — modern, premium, gradient-aware. Override all the
   skeuomorphic clipboard styles defined earlier. */
.plans-page .plan-clip {
  all: unset;
  display: flex;
  flex-direction: column;
  position: relative;
  background: rgba(255, 255, 255, 0.96);
  border: 1px solid rgba(15, 23, 42, 0.07);
  border-radius: 16px;
  overflow: hidden;
  cursor: pointer;
  min-height: 240px;
  transition: transform 200ms cubic-bezier(.3, .9, .4, 1.1),
              box-shadow 200ms cubic-bezier(.3, .9, .4, 1.1),
              border-color 200ms;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 1px 2px rgba(15, 23, 42, 0.05),
    0 6px 16px -8px rgba(15, 23, 42, 0.10);
}
.plans-page .plan-clip:hover {
  transform: translateY(-3px);
  border-color: rgba(108, 92, 231, 0.20);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.9) inset,
    0 2px 4px rgba(15, 23, 42, 0.06),
    0 18px 36px -10px rgba(108, 92, 231, 0.20),
    0 6px 16px -6px rgba(15, 23, 42, 0.10);
}
.plans-page .plan-clip:focus-visible {
  outline: 3px solid rgba(108, 92, 231, 0.40);
  outline-offset: 3px;
}

/* Gradient accent strip on top */
.plans-page .plan-clip::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, #6c5ce7, #00cec9);
  z-index: 1;
}
.plans-page .plan-clip::after { display: none; }

/* Player-visible variant gets a green accent */
.plans-page .plan-clip--shared::before {
  background: linear-gradient(90deg, #10b981, #84cc16);
}
.plans-page .plan-clip--upcoming::before {
  background: linear-gradient(90deg, #f59e0b, #ec4899);
}

/* Strip out the old clipboard parts */
.plans-page .plan-clip-top { display: none; }
.plans-page .plan-clip-clip { display: none; }

/* Page (the body) */
.plans-page .plan-clip-page {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 18px 16px 14px;
  background: none;
  position: relative;
}
.plans-page .plan-clip-page-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--text, #0f172a);
  margin-bottom: 6px;
  min-height: 24px;
}
.plans-page .plan-clip-page-title span {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.plans-page .plan-clip-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.plans-page .plan-clip-dot--visible { background: linear-gradient(135deg, #10b981, #84cc16); box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.15); }
.plans-page .plan-clip-dot--private { background: rgba(15, 23, 42, 0.35); }
.plans-page .plan-clip-page-meta {
  font-size: 12px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.55);
  margin-bottom: 12px;
  font-variant-numeric: tabular-nums;
}

/* Sport diagram panel inside the card */
.plans-page .plan-clip-page-diagram {
  background: linear-gradient(135deg, #f8f9fc, #eef0f6);
  border: 1px solid rgba(15, 23, 42, 0.05);
  border-radius: 11px;
  aspect-ratio: 16 / 9;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 12px;
  overflow: hidden;
  padding: 8px;
}
.plans-page .plan-clip-page-diagram svg {
  max-width: 100%;
  max-height: 100%;
  width: auto; height: auto;
  opacity: 0.85;
}

/* Upcoming pill */
.plans-page .plan-clip-upcoming {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  align-self: flex-start;
  padding: 4px 10px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(245, 158, 11, 0.14), rgba(236, 72, 153, 0.14));
  border: 1px solid rgba(245, 158, 11, 0.30);
  color: #92400e;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  margin-bottom: 10px;
}
.plans-page .plan-clip-upcoming svg { width: 11px; height: 11px; }

/* Footer with book + date */
.plans-page .plan-clip-foot {
  margin-top: auto;
  padding: 10px 16px;
  background: rgba(15, 23, 42, 0.03);
  border-top: 1px solid rgba(15, 23, 42, 0.06);
}
.plans-page .plan-clip-meta {
  font-size: 11.5px;
  font-weight: 600;
  color: rgba(15, 23, 42, 0.55);
  letter-spacing: 0.02em;
}

/* Actions overlay — revealed on hover, glass mini-buttons */
.plans-page .plan-clip-actions {
  position: absolute;
  top: 12px; right: 12px;
  display: flex;
  gap: 4px;
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 180ms, transform 180ms;
  z-index: 2;
}
.plans-page .plan-clip:hover .plan-clip-actions,
.plans-page .plan-clip:focus-within .plan-clip-actions { opacity: 1; transform: translateY(0); }
.plans-page .plan-clip-action {
  width: 30px; height: 30px;
  border: 0;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.92);
  color: rgba(15, 23, 42, 0.55);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 150ms, color 150ms, transform 150ms;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.10);
}
.plans-page .plan-clip-action svg { width: 14px; height: 14px; }
.plans-page .plan-clip-action--share:hover {
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  color: #fff;
  transform: scale(1.05);
}
.plans-page .plan-clip-action--del:hover {
  background: #ef4444;
  color: #fff;
  transform: scale(1.05);
}
.plans-page .plan-clip-action--run:hover {
  background: linear-gradient(135deg, #10b981, #84cc16);
  color: #fff;
  transform: scale(1.05);
}

/* Empty state — bigger icon with gradient ring */
.plans-page #plan-grid .empty {
  text-align: center;
  padding: 80px 24px;
  background: rgba(255, 255, 255, 0.6);
  border: 1px dashed rgba(15, 23, 42, 0.12);
  border-radius: 18px;
  color: rgba(15, 23, 42, 0.55);
  font-size: 14px;
  line-height: 1.6;
}
.plans-page #plan-grid .empty .icon {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 64px; height: 64px;
  margin: 0 auto 18px;
  background: linear-gradient(135deg, #6c5ce7, #00cec9);
  border-radius: 18px;
  box-shadow: 0 8px 24px -6px rgba(108, 92, 231, 0.40);
}
.plans-page #plan-grid .empty .icon svg {
  width: 28px !important;
  height: 28px !important;
  color: #fff !important;
}
.plans-page #plan-grid .empty b { color: var(--text, #0f172a); font-weight: 700; }

/* Mobile */
@media (max-width: 720px) {
  .plans-page .page-header { flex-direction: column; align-items: flex-start; gap: 14px; }
  .plans-page .page-actions { width: 100%; }
  .plans-page .page-actions .btn { flex: 1; justify-content: center; }
  .plans-page .plans-shelf-row { grid-template-columns: 1fr; }
}

/* ============================================================
   PLANS LANDING — v2: team-color gradient + real drill artwork.
   - Gradients now pull from --brand-primary/--brand-secondary
     (team colors), falling back to Coachly purple→teal when a
     team hasn't picked colors.
   - Plan card hero is the FIRST drill's actual thumbnail (Xs &
     Os + arrows the coach drew).
   ============================================================ */
:root {
  --plans-grad-from: var(--brand-primary, #6c5ce7);
  --plans-grad-to:   var(--brand-secondary, #00cec9);
}

/* Re-skin the page mark + buttons + chips to use team colors. */
.plans-page .page-header h1::before {
  background: linear-gradient(135deg, var(--plans-grad-from), var(--plans-grad-to));
  background-image:
    linear-gradient(135deg, transparent 30%, rgba(255,255,255,0.18) 50%, transparent 70%),
    linear-gradient(135deg, var(--plans-grad-from), var(--plans-grad-to));
  box-shadow: 0 4px 14px color-mix(in srgb, var(--plans-grad-from) 35%, transparent);
}
.plans-page #btn-ai-plan {
  background: linear-gradient(135deg, var(--plans-grad-from), var(--plans-grad-to)) !important;
  box-shadow:
    0 6px 18px -4px color-mix(in srgb, var(--plans-grad-from) 45%, transparent),
    0 2px 6px color-mix(in srgb, var(--plans-grad-from) 25%, transparent) !important;
}
.plans-page #btn-ai-plan:hover {
  box-shadow: 0 10px 24px -6px color-mix(in srgb, var(--plans-grad-from) 55%, transparent) !important;
}
.plans-page #btn-new-plan:hover {
  border-color: color-mix(in srgb, var(--plans-grad-from) 40%, transparent) !important;
  box-shadow: 0 6px 16px -4px color-mix(in srgb, var(--plans-grad-from) 22%, transparent) !important;
}
.plans-page .plans-search input:focus {
  border-color: var(--plans-grad-from);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--plans-grad-from) 16%, transparent);
}
.plans-page .plans-book-chip:hover {
  border-color: color-mix(in srgb, var(--plans-grad-from) 32%, transparent);
}
.plans-page .plans-book-chip.is-active {
  background: linear-gradient(135deg, var(--plans-grad-from), var(--plans-grad-to));
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--plans-grad-from) 45%, transparent);
}
.plans-page .plans-sort-select:hover {
  border-color: color-mix(in srgb, var(--plans-grad-from) 32%, transparent);
}
.plans-page .plans-sort-select:focus {
  border-color: var(--plans-grad-from);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--plans-grad-from) 16%, transparent);
}

/* Card top accent + hover tint — pull team colors */
.plans-page .plan-clip::before {
  background: linear-gradient(90deg, var(--plans-grad-from), var(--plans-grad-to));
}
.plans-page .plan-clip:hover {
  border-color: color-mix(in srgb, var(--plans-grad-from) 24%, transparent);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.9) inset,
    0 2px 4px rgba(15, 23, 42, 0.06),
    0 18px 36px -10px color-mix(in srgb, var(--plans-grad-from) 24%, transparent),
    0 6px 16px -6px rgba(15, 23, 42, 0.10);
}
.plans-page .plan-clip:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--plans-grad-from) 44%, transparent);
}

/* Hero — real drill thumbnail at the top of the card */
.plans-page .plan-clip {
  padding: 0;        /* hero + page sections own their own padding */
  min-height: 0;     /* let content drive height */
}
.plans-page .plan-clip-hero {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  background:
    linear-gradient(180deg, rgba(15, 23, 42, 0.02), transparent 40%),
    #ffffff;
  border-bottom: 1px solid color-mix(in srgb, var(--plans-grad-from) 8%, rgba(15, 23, 42, 0.05));
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.plans-page .plan-clip-hero-thumb {
  width: 100%; height: 100%;
  object-fit: contain;
  display: block;
  transition: transform 280ms cubic-bezier(.3, .9, .4, 1.1);
}
.plans-page .plan-clip:hover .plan-clip-hero-thumb { transform: scale(1.025); }
.plans-page .plan-clip-hero-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%; height: 100%;
  padding: 14px;
  color: color-mix(in srgb, var(--plans-grad-from) 75%, #475569);
  background:
    radial-gradient(circle at 30% 20%, color-mix(in srgb, var(--plans-grad-from) 9%, transparent), transparent 60%),
    radial-gradient(circle at 70% 80%, color-mix(in srgb, var(--plans-grad-to) 9%, transparent), transparent 60%),
    linear-gradient(135deg, #f8f9fc, #eef0f6);
}
.plans-page .plan-clip-hero-fallback svg {
  max-width: 100%;
  max-height: 100%;
  opacity: 0.7;
}

/* "+N" badge top-right of the hero when there are multiple drills */
.plans-page .plan-clip-hero-stack {
  position: absolute;
  top: 12px; left: 12px;
  background: linear-gradient(135deg, var(--plans-grad-from), var(--plans-grad-to));
  color: #fff;
  padding: 5px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  box-shadow: 0 4px 10px color-mix(in srgb, var(--plans-grad-from) 35%, transparent);
}

/* Upcoming pill sits below the stack badge on the hero */
.plans-page .plan-clip-hero .plan-clip-upcoming {
  position: absolute;
  bottom: 12px; left: 12px;
  margin: 0;
}

/* Actions overlay — top-right of the hero */
.plans-page .plan-clip-actions { top: 10px; right: 10px; }

/* Page (body) — title + meta below the hero */
.plans-page .plan-clip-page {
  padding: 14px 16px 8px;
}
.plans-page .plan-clip-page-title {
  margin-bottom: 4px;
}
.plans-page .plan-clip-page-meta {
  margin-bottom: 10px;
}

/* Footer — subtle team-color tinted background */
.plans-page .plan-clip-foot {
  background: color-mix(in srgb, var(--plans-grad-from) 5%, #fafbff);
  border-top: 1px solid color-mix(in srgb, var(--plans-grad-from) 10%, rgba(15, 23, 42, 0.05));
}

/* Empty state — gradient icon disc pulls team color */
.plans-page #plan-grid .empty .icon {
  background: linear-gradient(135deg, var(--plans-grad-from), var(--plans-grad-to));
  box-shadow: 0 8px 24px -6px color-mix(in srgb, var(--plans-grad-from) 40%, transparent);
}

/* Aurora bloom in team colors */
body.route-plans {
  background:
    radial-gradient(900px 500px at 8% -8%, color-mix(in srgb, var(--plans-grad-from) 8%, transparent), transparent 60%),
    radial-gradient(800px 460px at 102% 5%, color-mix(in srgb, var(--plans-grad-to) 8%, transparent), transparent 60%),
    linear-gradient(180deg, #fbfbfd 0%, #f6f7fb 100%);
}

/* ============================================================
   PLANS v3 — color-saturated plan cards.
   The plan card itself becomes the team's primary color (with a
   gradient to a complementary tone). Title gets bigger + bolder.
   Thumbnail stays white so the drill diagram reads cleanly.
   ============================================================ */

/* Derive a "to" stop when the team only has a primary color set.
   color-mix in oklch gives a perceptually-lighter version of the
   primary (cleaner than RGB mixing on saturated colors). */
:root {
  --plans-grad-from: var(--brand-primary, #6c5ce7);
  --plans-grad-to:   var(--brand-secondary, color-mix(in oklch, var(--brand-primary, #6c5ce7) 55%, white));
}

/* Card body now PAINTS in team color — not just the accent strip. */
.plans-page .plan-clip {
  background: linear-gradient(155deg, var(--plans-grad-from), var(--plans-grad-to)) !important;
  border-color: color-mix(in srgb, var(--plans-grad-from) 60%, transparent) !important;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.18) inset,
    0 2px 4px color-mix(in srgb, var(--plans-grad-from) 18%, transparent),
    0 14px 30px -10px color-mix(in srgb, var(--plans-grad-from) 36%, transparent) !important;
}
.plans-page .plan-clip:hover {
  border-color: color-mix(in srgb, var(--plans-grad-from) 75%, transparent) !important;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.22) inset,
    0 4px 6px color-mix(in srgb, var(--plans-grad-from) 22%, transparent),
    0 28px 50px -12px color-mix(in srgb, var(--plans-grad-from) 50%, transparent) !important;
}

/* Drop the old accent-strip — the whole card is the accent now. */
.plans-page .plan-clip::before { display: none; }

/* Hero panel — keep white so the rink + Xs/Os read cleanly. */
.plans-page .plan-clip-hero {
  background: #ffffff;
  border-bottom: 0;
  margin: 6px 6px 0;
  border-radius: 11px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.10);
}
.plans-page .plan-clip-hero-fallback {
  background:
    radial-gradient(circle at 30% 20%, color-mix(in srgb, var(--plans-grad-from) 10%, transparent), transparent 60%),
    radial-gradient(circle at 70% 80%, color-mix(in srgb, var(--plans-grad-to) 10%, transparent), transparent 60%),
    linear-gradient(135deg, #f8f9fc, #eef0f6);
}

/* "+N" stack badge — now white pill on the colored card */
.plans-page .plan-clip-hero-stack {
  background: rgba(255, 255, 255, 0.95);
  color: color-mix(in srgb, var(--plans-grad-from) 80%, #0f172a);
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.18);
}

/* Title section — light text on the colored body. Bigger + bolder. */
.plans-page .plan-clip-page {
  padding: 14px 18px 12px;
}
.plans-page .plan-clip-page-title {
  font-size: 19px !important;
  font-weight: 800 !important;
  color: #ffffff !important;
  letter-spacing: -0.015em;
  line-height: 1.18;
  margin-bottom: 6px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.plans-page .plan-clip-page-meta {
  font-size: 12.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.82) !important;
  letter-spacing: 0.01em;
}
.plans-page .plan-clip-dot--visible {
  background: #ffffff;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.25);
}
.plans-page .plan-clip-dot--private {
  background: rgba(255, 255, 255, 0.5);
}

/* Footer — darker tint over the gradient for hierarchy */
.plans-page .plan-clip-foot {
  background: rgba(0, 0, 0, 0.18);
  border-top: 1px solid rgba(255, 255, 255, 0.10);
}
.plans-page .plan-clip-meta {
  color: rgba(255, 255, 255, 0.88) !important;
  font-weight: 600;
  letter-spacing: 0.03em;
}

/* Upcoming pill on the colored hero — needs higher contrast now */
.plans-page .plan-clip-hero .plan-clip-upcoming {
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(255, 255, 255, 0.88));
  border-color: rgba(255, 255, 255, 0.6);
  color: color-mix(in srgb, var(--plans-grad-from) 85%, #0f172a);
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.15);
}

/* Actions overlay — glass white on the colored body */
.plans-page .plan-clip-action {
  background: rgba(255, 255, 255, 0.94);
  color: color-mix(in srgb, var(--plans-grad-from) 80%, #0f172a);
}
.plans-page .plan-clip-action--share:hover {
  background: #ffffff;
  color: var(--plans-grad-from);
}
.plans-page .plan-clip-action--run:hover {
  background: linear-gradient(135deg, #10b981, #84cc16);
  color: #ffffff;
}
.plans-page .plan-clip-action--del:hover {
  background: #ef4444;
  color: #ffffff;
}

/* ============================================================
   PLANS v4 — text-first card design, no artwork.
   Drill preview list anchors the card; bigger bolder title;
   tight info hierarchy.  Card body still paints in team color.
   ============================================================ */
.plans-page .plan-clip {
  display: flex;
  flex-direction: column;
  position: relative;
  padding: 20px 22px 18px;
  background: linear-gradient(155deg, var(--plans-grad-from), var(--plans-grad-to)) !important;
  border: 1px solid color-mix(in srgb, var(--plans-grad-from) 55%, transparent) !important;
  border-radius: 18px;
  overflow: hidden;
  cursor: pointer;
  transition: transform 220ms cubic-bezier(.3, .9, .4, 1.1),
              box-shadow 220ms cubic-bezier(.3, .9, .4, 1.1),
              border-color 220ms;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.18) inset,
    0 1px 3px color-mix(in srgb, var(--plans-grad-from) 22%, transparent),
    0 14px 32px -12px color-mix(in srgb, var(--plans-grad-from) 40%, transparent) !important;
  min-height: 0;
}
.plans-page .plan-clip:hover {
  transform: translateY(-3px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.22) inset,
    0 2px 4px color-mix(in srgb, var(--plans-grad-from) 28%, transparent),
    0 26px 52px -16px color-mix(in srgb, var(--plans-grad-from) 56%, transparent) !important;
}
.plans-page .plan-clip:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--plans-grad-from) 48%, transparent);
  outline-offset: 3px;
}
.plans-page .plan-clip::before { display: none; }
.plans-page .plan-clip::after { display: none; }

/* Subtle gradient sheen at the top — gives the card a polished
   "premium plastic" highlight without the old skeu clip illustration. */
.plans-page .plan-clip > .plan-clip-actions { z-index: 2; }
.plans-page .plan-clip > .plan-clip-eyebrow,
.plans-page .plan-clip > .plan-clip-name,
.plans-page .plan-clip > .plan-clip-stats,
.plans-page .plan-clip > .plan-clip-pill-row,
.plans-page .plan-clip > .plan-clip-drills,
.plans-page .plan-clip > .plan-clip-empty {
  position: relative; z-index: 1;
}

/* Eyebrow — visibility dot + book + date */
.plans-page .plan-clip-eyebrow {
  display: flex; align-items: center; gap: 8px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: 10px;
  min-height: 14px;
}
.plans-page .plan-clip-eyebrow-text { line-height: 1.2; }
.plans-page .plan-clip-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
}
.plans-page .plan-clip-dot--visible {
  background: #ffffff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.20);
}
.plans-page .plan-clip-dot--private {
  background: rgba(255, 255, 255, 0.45);
}

/* Headline — bigger, bolder, tight leading */
.plans-page .plan-clip-name {
  margin: 0 0 12px;
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.12;
  color: #ffffff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Headline meta — drill count · total · age */
.plans-page .plan-clip-stats {
  font-size: 13px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.88);
  margin-bottom: 14px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* Upcoming pill row */
.plans-page .plan-clip-pill-row {
  margin-bottom: 12px;
  display: flex;
  flex-wrap: wrap;
}
.plans-page .plan-clip-pill-row .plan-clip-upcoming {
  position: static;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(255, 255, 255, 0.86));
  border: 1px solid rgba(255, 255, 255, 0.6);
  color: color-mix(in srgb, var(--plans-grad-from) 85%, #0f172a);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.10);
}
.plans-page .plan-clip-pill-row .plan-clip-upcoming svg { width: 11px; height: 11px; color: color-mix(in srgb, var(--plans-grad-from) 85%, #0f172a); }

/* Drill preview list — the content anchor */
.plans-page .plan-clip-drills {
  list-style: none;
  margin: 4px 0 0;
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 12px;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.plans-page .plan-clip-drill {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 13px;
  color: rgba(255, 255, 255, 0.95);
  line-height: 1.35;
}
.plans-page .plan-clip-drill:last-child { border-bottom: 0; }
.plans-page .plan-clip-drill-idx {
  width: 18px; height: 18px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  color: color-mix(in srgb, var(--plans-grad-from) 80%, #0f172a);
  font-size: 10.5px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.plans-page .plan-clip-drill-name {
  flex: 1;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plans-page .plan-clip-drill-mins {
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.7);
  letter-spacing: 0.02em;
}
.plans-page .plan-clip-drill--more {
  justify-content: center;
  padding: 8px 0 2px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.65);
  border-bottom: 0;
}

/* Empty (no drills) state inside the card */
.plans-page .plan-clip-empty {
  padding: 14px 16px;
  background: rgba(0, 0, 0, 0.16);
  border: 1px dashed rgba(255, 255, 255, 0.20);
  border-radius: 12px;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.75);
  font-weight: 500;
  text-align: center;
}

/* Hover-reveal action overlay — top right */
.plans-page .plan-clip-actions {
  position: absolute;
  top: 12px; right: 12px;
  display: flex;
  gap: 4px;
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 180ms, transform 180ms;
}
.plans-page .plan-clip:hover .plan-clip-actions,
.plans-page .plan-clip:focus-within .plan-clip-actions {
  opacity: 1;
  transform: translateY(0);
}
.plans-page .plan-clip-action {
  width: 30px; height: 30px;
  border: 0;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.95);
  color: color-mix(in srgb, var(--plans-grad-from) 75%, #0f172a);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 150ms, color 150ms, transform 150ms;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
}
.plans-page .plan-clip-action svg { width: 14px; height: 14px; }
.plans-page .plan-clip-action--share:hover { background: #ffffff; color: var(--plans-grad-from); transform: scale(1.06); }
.plans-page .plan-clip-action--run:hover { background: linear-gradient(135deg, #10b981, #84cc16); color: #fff; transform: scale(1.06); }
.plans-page .plan-clip-action--del:hover { background: #ef4444; color: #fff; transform: scale(1.06); }

/* The old hero/page/foot layout pieces are no longer rendered, but
   if any cached card markup escapes, hide it cleanly. */
.plans-page .plan-clip-hero,
.plans-page .plan-clip-page,
.plans-page .plan-clip-foot { display: none; }

@media (max-width: 720px) {
  .plans-page .plan-clip { padding: 18px 18px 16px; }
  .plans-page .plan-clip-name { font-size: 22px; }
}

/* ============================================================
   PLANS v5 — gradient = primary → darker primary; centered card.
   The team-set secondary is often a neutral (grey) that ruins the
   gradient, so we ignore it for the card body and derive a deeper
   shade from the primary directly.
   ============================================================ */
:root {
  /* "From" = team primary (full saturation).
     "To"   = darker, slightly desaturated version of primary, mixed
              in oklch for a perceptually-clean shadow tone. */
  --plans-grad-from: var(--brand-primary, #6c5ce7);
  --plans-grad-to:   color-mix(in oklch, var(--brand-primary, #6c5ce7) 70%, #0b0b14);
}

/* Card body now always reads as a confident primary → darker shade. */
.plans-page .plan-clip {
  background: linear-gradient(155deg, var(--plans-grad-from), var(--plans-grad-to)) !important;
  /* Centered layout for eyebrow / headline / stats / pill */
  align-items: center;
  text-align: center;
}

/* Center the inline rows */
.plans-page .plan-clip-eyebrow { justify-content: center; }
.plans-page .plan-clip-pill-row { justify-content: center; }

/* Headline + stats centered (they're block elements, so text-align
   on the parent does it, but be explicit). */
.plans-page .plan-clip-name { text-align: center; }
.plans-page .plan-clip-stats { text-align: center; }

/* Drill list — the box itself is full-width, but each row stays
   left-aligned (lists don't read well centered). */
.plans-page .plan-clip-drills,
.plans-page .plan-clip-empty {
  width: 100%;
  align-self: stretch;
  text-align: left;
}
.plans-page .plan-clip-drill { text-align: left; }
.plans-page .plan-clip-drill--more {
  text-align: center;
  justify-content: center;
}

/* Index disc on each drill row picks the darker stop (matches the
   bottom of the gradient) so the contrast against white is high. */
.plans-page .plan-clip-drill-idx {
  color: var(--plans-grad-to);
}

/* Upcoming pill text + icon use the same darker stop for legibility. */
.plans-page .plan-clip-pill-row .plan-clip-upcoming { color: var(--plans-grad-to); }
.plans-page .plan-clip-pill-row .plan-clip-upcoming svg { color: var(--plans-grad-to); }

/* Action button icon color picks the darker stop too */
.plans-page .plan-clip-action { color: var(--plans-grad-to); }
.plans-page .plan-clip-action--share:hover { color: var(--plans-grad-from); }

/* Stack badge (if it re-appears) uses darker stop too */
.plans-page .plan-clip-hero-stack { color: var(--plans-grad-to); }

/* ============================================================
   PLANS v6 — derive gradient from --panel-dark (the nav color)
   instead of --brand-primary (the swatch). The nav is the strong
   identity color most teams set deliberately for chrome; using
   it on the plan cards ties the bookshelf to the rest of the app.
   ============================================================ */
:root {
  --plans-grad-from: var(--panel-dark, var(--brand-primary, #6c5ce7));
  --plans-grad-to:   color-mix(in oklch, var(--panel-dark, var(--brand-primary, #6c5ce7)) 72%, #0b0b14);
}

/* ============================================================
   PLANS v7 — uniform card heights + 5-row drill preview.
   Reserves consistent vertical space for the drill area so a 2-drill
   plan and a 12-drill plan render at the same card height. Empty
   rows look intentional (glass panel breathing room), not broken.
   ============================================================ */

/* Cards lay out as a grid where the drill area always claims the
   remaining height. Using flex with flex: 1 on the drill list makes
   every card stretch the list to consume whatever's leftover. */
.plans-page .plans-shelf-row {
  align-items: stretch;
}
.plans-page .plan-clip {
  /* Minimum card height that holds 5 drill rows + the chrome above */
  min-height: 380px;
}

/* Drill list panel — reserve 5 rows of space; stretch to fill the
   card so the panel ends at the same baseline across the row. */
.plans-page .plan-clip-drills,
.plans-page .plan-clip-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  /* Lock 5-row minimum: row ≈ 30px (6px pad + 1.35*13px line + 6px pad) +
     panel padding 24px = ~174px. Round up to 184px so the "+ more" row
     also has room to breathe when present. */
  min-height: 184px;
}

/* When fewer than 5 drills, the panel still feels tall because we
   pad the bottom with subtle ghost dots (intentional empty state). */
.plans-page .plan-clip-drills::after {
  content: "";
  flex: 1;
  min-height: 0;
}

@media (max-width: 720px) {
  .plans-page .plan-clip { min-height: 340px; }
  .plans-page .plan-clip-drills,
  .plans-page .plan-clip-empty { min-height: 168px; }
}

/* Season footer — sits under the drill list, centered, uppercase
   eyebrow rhythm so it reads as quiet context (not a header). */
.plans-page .plan-clip-season {
  margin-top: 12px;
  text-align: center;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.78);
}

/* Eyebrow no longer carries season, so include the z-index pattern
   for the season footer too (kept above the gradient background). */
.plans-page .plan-clip > .plan-clip-season { position: relative; z-index: 1; }

/* Lock the headline block to always claim 2 lines of vertical space,
   regardless of whether the title is 1 line or 2.  Without this, a
   single-line title pulls the meta/stats/drills row up by ~27px and
   throws off the row baseline across the shelf. */
.plans-page .plan-clip-name {
  min-height: calc(24px * 1.12 * 2);  /* font-size × line-height × 2 lines */
  min-height: 2lh;                    /* modern browsers — same result */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
@media (max-width: 720px) {
  .plans-page .plan-clip-name {
    min-height: calc(22px * 1.12 * 2);
    min-height: 2lh;
  }
}

/* Use the server-computed mix target so very-dark nav colors (near-black)
   gradient toward white instead of darker (which would be invisible). */
:root {
  --plans-grad-to: color-mix(in oklch, var(--panel-dark, var(--brand-primary, #6c5ce7)) 72%, var(--plans-grad-mix-target, #0b0b14));
}

/* Vault curator button on plan cards: legacy rule parked it at top-right
   where the new hover action row lives. Move to top-left (the eyebrow is
   centered, so the corner is empty). Admin-only — non-admins never see it. */
.plans-page .plan-clip .send-to-vault-btn {
  top: 10px;
  left: 10px;
  right: auto;
  bottom: auto;
}

/* Acumin Pro Semi Condensed Bold (Adobe Fonts) — the site-wide
   display face for all headings (h1-h6), the nav, and plan card
   titles. The font-smoothing pair is critical on macOS — without it
   Chrome / Safari render condensed type with subpixel anti-aliasing
   which produces a fuzzy "not crisp" look. Adobe's specimen pages
   set the same pair. text-rendering: geometricPrecision keeps stroke
   geometry sharp at small sizes. */
h1, h2, h3, h4, h5, h6,
.plans-page .plan-clip-name,
.topnav-link,
.nav-drawer-link {
  font-family: "acumin-pro-semi-condensed", "Acumin Pro Semi Condensed",
               -apple-system, BlinkMacSystemFont, "Segoe UI",
               Geist, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: geometricPrecision;
}
h1, h2, h3, h4, h5, h6 { font-weight: 700; }
.plans-page .plan-clip-name { font-weight: 700; letter-spacing: -0.005em; }

/* Nav links: Bold (700) — Black (900) wasn't in the kit and was
   synthesizing into a blurry mess. Uppercase + slight tracking so
   condensed bold caps don't crash into each other. */
.topnav-link,
.nav-drawer-link {
  font-weight: 700;
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.topnav-link { padding: 8px 11px; }
.topnav-link { color: #fff; }
.topnav-link:not(.active) { color: rgba(255, 255, 255, 0.78); }

/* ─────────────────────────────────────────────────────────────
 * Account-icon dropdown — consolidates Team / Associations / Admin
 * + Sign out under the avatar so the main nav stays short. Class
 * prefix is .acct- (not .user-) on purpose: an older orphaned
 * design used .user-chip/.user-menu and the dead styles were bleeding
 * through (light-grey wrapper background). The .acct- prefix is
 * collision-free.
 * ───────────────────────────────────────────────────────────── */
.acct-chip { position: relative; display: inline-flex; }
.acct-chip-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: 0; padding: 0; margin-right: 6px;
  background: transparent; color: inherit;
  border-radius: 6px; cursor: pointer;
  transition: background 0.12s;
}
.acct-chip-btn:hover { background: rgba(255,255,255,0.10); }
.acct-chip.show .acct-chip-btn { background: rgba(255,255,255,0.14); }

.acct-menu {
  position: absolute; top: 100%; right: 0; margin-top: 6px;
  background: #fff; color: var(--text);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0,0,0,.28), 0 2px 6px rgba(0,0,0,.10);
  min-width: 220px;
  padding: 6px;
  display: none;
  z-index: 96;
}
.acct-menu.show { display: block; }
.acct-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border: 0; background: transparent;
  font: inherit; color: inherit; text-align: left;
  text-decoration: none; border-radius: 6px;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.acct-menu-item:hover { background: var(--bg-soft, #f4f5f8); }
.acct-menu-item.active { color: var(--brand-primary); font-weight: 600; }
.acct-menu-item svg { flex: 0 0 16px; opacity: 0.7; }
.acct-menu-item:hover svg,
.acct-menu-item.active svg { opacity: 1; }
.acct-menu-divider { height: 1px; background: var(--border-soft, rgba(0,0,0,.08)); margin: 6px 0; }
.acct-menu-signout { color: #d4324a; }
.acct-menu-signout svg { color: #d4324a; opacity: 0.9; }

/* ─────────────────────────────────────────────────────────────
 * Demo mode (/demo) — drill board with no auth, no save, no team
 * features.  body.route-demo gates everything that needs login.
 * ───────────────────────────────────────────────────────────── */

/* Black brand bar above the drill board — Coachly icon + wordmark matching
   the landing page. No "demo" wording. */
.demo-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 9000;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  height: 48px;
  padding: 0 18px;
  background: #0c0c12;
  -webkit-font-smoothing: antialiased;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
}
.demo-brand {
  display: inline-flex; align-items: center; gap: 10px;
  text-decoration: none;
}
.demo-brand-mark {
  display: grid; place-items: center;
  width: 28px; height: 28px;
  border-radius: 7px;
  background: linear-gradient(135deg, #6c5ce7 0%, #00cec9 100%);
  color: #fff;
  font: 800 16px/1 Geist, system-ui, sans-serif;
}
.demo-brand-word {
  font-family: 'Anton', Impact, 'Arial Narrow', sans-serif;
  font-size: 21px;
  letter-spacing: 0.06em;
  color: #fff;
  line-height: 1;
}
.demo-banner-cta {
  background: linear-gradient(135deg, #6c5ce7 0%, #00cec9 100%);
  color: #fff;
  font: 700 12px/1 Geist, system-ui, sans-serif;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 9px 14px;
  border-radius: 8px;
  transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
}
.demo-banner-cta:hover {
  filter: brightness(1.08);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(108, 92, 231, 0.40);
}
.demo-banner-actions { display: flex; align-items: center; gap: 8px; }
.demo-banner-save {
  background: rgba(255,255,255,0.12); color: #fff; cursor: pointer;
  font: 700 12px/1 Geist, system-ui, sans-serif; letter-spacing: 0.02em; text-transform: uppercase;
  border: 1px solid rgba(255,255,255,0.25); padding: 9px 14px; border-radius: 8px;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.demo-banner-save:hover { background: rgba(255,255,255,0.2); border-color: rgba(255,255,255,0.45); }

/* ── Demo email-capture popup ── */
.demo-capture-bg {
  position: fixed; inset: 0; z-index: 100000; display: none;
  align-items: center; justify-content: center; padding: 20px;
  background: rgba(10,12,18,0.55); backdrop-filter: blur(2px);
}
.demo-capture-bg.show { display: flex; }
.demo-capture {
  position: relative; width: 400px; max-width: 100%;
  background: #fff; border-radius: 16px; padding: 28px 26px 22px; text-align: center;
  box-shadow: 0 24px 60px rgba(0,0,0,0.35); animation: dcPop 0.18s ease;
}
@keyframes dcPop { from { transform: translateY(8px) scale(0.98); opacity: 0; } to { transform: none; opacity: 1; } }
.demo-capture-x {
  position: absolute; top: 12px; right: 14px; background: none; border: none;
  font-size: 22px; line-height: 1; color: var(--text-dim, #94a3b8); cursor: pointer;
}
.demo-capture-mark {
  width: 46px; height: 46px; margin: 0 auto 12px; border-radius: 12px;
  display: grid; place-items: center; color: #fff; font: 800 24px/1 Anton, Geist, sans-serif;
  background: linear-gradient(135deg, #6c5ce7 0%, #00cec9 100%);
}
.demo-capture h3 { margin: 0 0 6px; font: 700 19px/1.2 'Instrument Sans', Geist, system-ui, sans-serif; color: var(--text, #1a1d21); }
.demo-capture p { margin: 0 0 16px; font: 400 13.5px/1.5 Geist, system-ui, sans-serif; color: var(--text-dim, #64748b); }
.demo-capture-form { display: flex; flex-direction: column; gap: 9px; }
.demo-capture-form input {
  width: 100%; padding: 11px 13px; border: 1px solid var(--border, #d8dce2); border-radius: 9px;
  font: 400 15px/1.2 Geist, system-ui, sans-serif; color: var(--text); background: #fff; text-align: center;
}
.demo-capture-form input:focus { outline: 2px solid #6c5ce7; outline-offset: -1px; border-color: transparent; }
.demo-capture-form .btn-primary { padding: 11px; font-weight: 700; }
.demo-capture-err { margin-top: 10px; font: 500 12.5px/1.4 Geist, system-ui, sans-serif; color: #dc2626; }
.demo-capture-later { margin-top: 12px; background: none; border: none; cursor: pointer; font: 500 12.5px/1 Geist, system-ui, sans-serif; color: var(--text-dim, #94a3b8); text-decoration: underline; }

/* Push the app shell down so the bar doesn't cover the topbar. */
body.route-demo .app { margin-top: 48px; }
body.route-demo .topnav { display: none; }    /* topnav makes no sense without auth */

/* Hide team-only / save-bound UI in demo mode.  Everything left visible:
 * drawing tools, color, undo/redo, animation, PDF/image export, multi-tab. */
body.route-demo .sidebar,            /* drill drawer — nothing to load */
body.route-demo #expand-sidebar,     /* the strip that opens the drawer */
body.route-demo #collapse-sidebar,
body.route-demo .save-pill,          /* save indicator dot */
body.route-demo .save-dot,
body.route-demo #save-indicator,
body.route-demo .share-btn,          /* share modal trigger */
body.route-demo .btn-share,
body.route-demo .btn-push-to-teams,
body.route-demo .send-to-vault-btn,  /* curator-only */
body.route-demo .vault-revert-btn,
body.route-demo .topnav-link,        /* defensive — topnav is hidden but its children may render */
body.route-demo .acct-chip {         /* user-icon dropdown — no account */
  display: none !important;
}

/* The tab kebab menu has "Add to plan" — useless without a team's plans.
 * The whole kebab still serves Rename + Duplicate so keep it visible;
 * hide just the add-to-plan menu item. */
body.route-demo [data-tab-action="add-to-plan"] { display: none !important; }

/* Mobile drawer (hamburger) is also irrelevant in demo. */
body.route-demo .nav-hamburger,
body.route-demo .nav-drawer,
body.route-demo .nav-drawer-backdrop { display: none !important; }

/* Mobile: keep the bar single-row; shrink the CTA so it stays tappable. */
@media (max-width: 600px) {
  .demo-banner { padding: 0 12px; }
  .demo-brand-word { font-size: 18px; }
  .demo-banner-cta { padding: 8px 11px; font-size: 11px; }
}

/* ─────────────────────────────────────────────────────────────────────
 * ROSTER — lineup card (Team-Canada-prediction style, FLAT + light)
 * White surface; Forwards / Defense / Goalies sections; each player is a
 * circular headshot + a flat name pill in the team colour. Replaces the
 * grouped-table roster body.
 * ───────────────────────────────────────────────────────────────────── */
.lineup-card {
  background: transparent;       /* blends with the white table-card */
  padding: 4px 4px 18px;
  max-width: 780px;
  margin: 0 auto;
}
.lineup-head {
  display: flex; align-items: center; justify-content: center; gap: 11px;
  padding: 4px 0 16px;
}
.lineup-shield { width: 30px; height: 30px; color: var(--text, #1a1d21); flex: 0 0 30px; }
.lineup-shield svg { width: 100%; height: 100%; }
.lineup-title {
  font-family: 'acumin-pro-semi-condensed','Anton', Impact, system-ui, sans-serif;
  font-weight: 800;
  font-size: 24px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text, #1a1d21);
}

.lineup-section { margin-top: 18px; }
.lineup-section:first-of-type { margin-top: 4px; }
.lineup-section-head {
  text-align: center;
  font: 800 12px/1 Geist, system-ui, sans-serif;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-dim, #6b7280);
  margin-bottom: 12px;
}

/* Position columns (forwards = 3, defense = 2 centred). */
.lu-grid { display: grid; gap: 14px 10px; }
.lu-grid-3 { grid-template-columns: repeat(3, 1fr); }
.lu-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 64%; margin: 0 auto; }
.lu-col { display: flex; flex-direction: column; gap: 14px; }
.lu-col-label {
  text-align: center;
  font: 700 10px/1 Geist, system-ui, sans-serif;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim, #9aa3af);
  margin-bottom: 2px;
}
.lu-row { display: flex; justify-content: center; gap: 18px; flex-wrap: wrap; }

/* Player tile — circular headshot above a FLAT team-colour name pill. */
.lu-tile {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  width: 100%;
  padding: 6px 4px;
  border: none; background: none; cursor: pointer;
  border-radius: 10px;
  transition: background 0.12s ease;
}
.lu-tile:hover { background: rgba(0, 0, 0, 0.035); }
.lu-avatar {
  position: relative;
  width: 56px; height: 56px; flex: 0 0 56px;
}
.lu-avatar svg, .lu-avatar img {
  width: 100%; height: 100%;
  border-radius: 50%;
  display: block;
  object-fit: cover;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
}
/* Jersey-number badge on the headshot. */
.lu-num {
  position: absolute; bottom: -2px; right: -2px;
  min-width: 18px; height: 18px; padding: 0 4px;
  display: grid; place-items: center;
  background: var(--brand-primary, #d4302b); color: #fff;
  border: 2px solid #fff; border-radius: 999px;
  font: 700 10px/1 JetBrains Mono, monospace;
}
/* AP (affiliate / call-up) badge — amber pill on the avatar corner. */
.lu-ap {
  position: absolute; top: -3px; left: -3px;
  height: 15px; padding: 0 4px; display: grid; place-items: center;
  background: #f59e0b; color: #fff; border: 2px solid #fff; border-radius: 999px;
  font: 800 8px/1 'JetBrains Mono', monospace; letter-spacing: .04em;
}
/* AP toggle in the player edit modal. */
.ap-toggle {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 4px 10px;
  margin: 14px 0 4px; padding: 11px 13px; cursor: pointer;
  border: 1px solid var(--border, #e3e6ea); border-radius: 10px; background: var(--bg-soft, #f7f8fa);
}
.ap-toggle input { width: 18px; height: 18px; margin: 0; cursor: pointer; accent-color: #f59e0b; grid-row: span 2; }
.ap-toggle-text { font: 600 13px/1.2 Geist, system-ui, sans-serif; color: var(--text); }
.ap-toggle-text b { color: #b45309; }
.ap-toggle-hint { grid-column: 2; font: 500 11.5px/1.35 Geist, system-ui, sans-serif; color: var(--text-dim); }
/* Flat name pill — solid team colour, no bevel. */
.lu-name {
  width: 100%; max-width: 150px;
  text-align: center;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--brand-primary, #d4302b);
  color: #fff;
  font: 800 12px/1.15 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.lu-empty {
  text-align: center;
  color: var(--text-dim, #b6bdc7);
  font-size: 13px;
  padding: 10px 0;
}

body.route-roster #roster-groups { padding-top: 6px; }

@media (max-width: 560px) {
  .lineup-title { font-size: 20px; }
  .lu-grid-2 { max-width: 100%; }
  .lu-avatar { width: 48px; height: 48px; flex-basis: 48px; }
  .lu-name { font-size: 11px; max-width: 120px; }
}

/* ─────────────────────────────────────────────────────────────────────
 * ROSTER — drag-and-drop lineup board (lines + special teams)
 * Tabs (Lines / PP1 / PP2 / PK1 / PK2), slot grid, draggable player chips.
 * ───────────────────────────────────────────────────────────────────── */
.lu-tabs {
  display: flex; gap: 6px; justify-content: center; flex-wrap: wrap;
  padding: 2px 0 16px;
  border-bottom: 1px solid var(--border-soft);
  margin-bottom: 18px;
}
.lu-tab {
  font: 700 12px/1 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim);
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  padding: 8px 18px; cursor: pointer;
  transition: color .12s, border-color .12s, background .12s;
}
.lu-tab:hover { color: var(--text); border-color: var(--border); }
.lu-tab.active {
  color: #fff; border-color: transparent;
  /* Flat solid in the team primary — matches the flat name tiles. No
     gradient: a team's secondary colour can be grey/muddy and made the
     active tab fade red→grey. */
  background: var(--brand-primary, #6c5ce7);
}

.lu-board { max-width: 760px; margin: 0 auto; }
.lu-board .lineup-section-head { margin: 16px 0 10px; }
.lu-board .lineup-section-head:first-child { margin-top: 0; }

/* Line rows: [tag] + N slots in a grid. */
.lu-line { display: grid; align-items: stretch; gap: 10px; margin-bottom: 10px; }
.lu-line--f { grid-template-columns: 40px repeat(3, minmax(0, 1fr)); }
.lu-line--d { grid-template-columns: 40px repeat(2, minmax(0, 1fr)); }
.lu-line-tag {
  display: grid; place-items: center;
  font: 800 13px/1 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif;
  letter-spacing: .04em; color: var(--text-dim);
}
.lu-line-head { margin-bottom: 2px; }
.lu-line-head span {
  text-align: center;
  font: 700 10px/1 Geist, system-ui, sans-serif;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim);
}

/* Drop-target slot. */
.lu-slot {
  min-height: 96px;
  display: flex; align-items: center; justify-content: center;
  padding: 6px;
  border: 1.5px dashed var(--border, #d4d9e0);
  border-radius: 12px;
  background: var(--bg-soft, #f6f7f9);
  transition: border-color .12s, background .12s;
}
.lu-slot.filled { border-style: solid; border-color: transparent; background: transparent; }
.lu-slot-label {
  font: 700 11px/1 Geist, system-ui, sans-serif;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-dim); opacity: .55;
}
.lu-drop-hover {
  border-color: var(--brand-primary, #6c5ce7) !important;
  border-style: solid !important;
  background: color-mix(in srgb, var(--brand-primary, #6c5ce7) 9%, transparent) !important;
}

/* Special-teams unit. */
.lu-unit-head { text-align: center; margin-bottom: 4px; }
.lu-unit-title {
  font: 800 19px/1.1 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text);
}
.lu-unit-hint { font: 500 12px/1.3 Geist, system-ui, sans-serif; color: var(--text-dim); margin-top: 3px; }
.lu-unit-slots {
  display: grid; gap: 12px;
  grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr));
  max-width: 540px; margin: 0 auto;
}

/* Player chip — drag handle. Reuses .lu-avatar / .lu-name visuals. */
.lu-chip {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  width: 100%;
  padding: 4px 2px;
  border-radius: 10px;
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  transition: opacity .12s;
}
.lu-chip:active { cursor: grabbing; }
.lu-chip-dragging { opacity: .32; }
.lu-dim { opacity: .26; }
.lu-ghost {
  position: fixed; z-index: 9999; margin: 0; left: 0; top: 0;
  pointer-events: none; opacity: .94;
  filter: drop-shadow(0 10px 20px rgba(0, 0, 0, .3));
}
body.lu-dragging, body.lu-dragging * { cursor: grabbing !important; }
body.lu-dragging { -webkit-user-select: none; user-select: none; }

/* Bench / available pool — wrapping drop zone. */
.lu-bench {
  display: flex; flex-wrap: wrap; gap: 14px 10px;
  min-height: 96px;
  padding: 14px;
  border: 1.5px dashed var(--border, #d4d9e0);
  border-radius: 14px;
  background: var(--bg-soft, #f6f7f9);
  align-content: flex-start;
}
.lu-bench .lu-chip { width: 92px; }
.lu-bench .lu-empty { margin: auto; font-size: 13px; }

@media (max-width: 560px) {
  .lu-line--f { grid-template-columns: 30px repeat(3, minmax(0, 1fr)); gap: 6px; }
  .lu-line--d { grid-template-columns: 30px repeat(2, minmax(0, 1fr)); gap: 6px; }
  .lu-slot { min-height: 84px; }
  .lu-unit-slots { gap: 8px; }
  .lu-bench .lu-chip { width: 78px; }
}

/* ─────────────────────────────────────────────────────────────────────
 * PUBLIC LINEUP SHARE PAGE (/lineup?t=…)
 * Read-only lineup card for a shared link. Reuses .lineup-card / .lu-* .
 * ───────────────────────────────────────────────────────────────────── */
body.route-lineup-share { background: var(--bg, #f6f7f9); }
/* Clean share surface — no app nav even if a logged-in coach previews it. */
body.route-lineup-share .topnav,
body.route-lineup-share .nav-drawer,
body.route-lineup-share .pc-ad-slot { display: none !important; }
/* Force plain block flow — the app shell styles bare <main>/grid containers
   and would otherwise collapse the share layout. */
body.route-lineup-share .lshare-page,
body.route-lineup-share .lshare-main,
body.route-lineup-share #lshare-root { display: block; width: auto; }
.lshare-page { max-width: 820px; margin: 0 auto; padding: 22px 16px 60px; box-sizing: border-box; }
.lshare-page .lineup-card { max-width: none; }
.lshare-brand { display: flex; justify-content: center; padding: 8px 0 22px; }
.lshare-brand-link { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; color: var(--text, #1a1d21); }
.lshare-brand-mark { width: 26px; height: 26px; color: var(--brand-primary, #6c5ce7); }
.lshare-brand-mark svg { width: 100%; height: 100%; }
.lshare-brand-text { font: 800 18px/1 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif; letter-spacing: .02em; }

.lshare-loading, .lshare-error { text-align: center; color: var(--text-dim, #6b7280); padding: 60px 20px; }
.lshare-spinner {
  width: 32px; height: 32px; margin: 0 auto 14px;
  border: 3px solid var(--border-soft, #e3e6ea);
  border-top-color: var(--brand-primary, #6c5ce7);
  border-radius: 50%; animation: lshare-spin .8s linear infinite;
}
@keyframes lshare-spin { to { transform: rotate(360deg); } }

.lshare-head { text-align: center; margin-bottom: 14px; }
.lshare-head h1 {
  font: 800 26px/1.1 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text, #1a1d21); margin: 0;
}
.lshare-head .lshare-sub { font: 500 13px/1.3 Geist, system-ui, sans-serif; color: var(--text-dim, #6b7280); margin-top: 4px; }

.lshare-card {
  background: #fff;
  border: 1px solid var(--border-soft, #e3e6ea);
  border-radius: 16px;
  padding: 18px 18px 24px;
  box-shadow: 0 8px 30px -16px rgba(0, 0, 0, 0.2);
}
.lshare-unit-title {
  text-align: center;
  font: 800 18px/1.1 'acumin-pro-semi-condensed', Geist, system-ui, sans-serif;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text, #1a1d21);
  margin: 26px 0 2px; padding-top: 18px; border-top: 1px solid var(--border-soft, #eef0f3);
}
/* The shared chips are non-interactive. */
.lu-chip--static { cursor: default; }

@media (max-width: 560px) {
  .lshare-head h1 { font-size: 21px; }
  .lshare-card { padding: 14px 12px 18px; }
}

/* ─────────────────────────────────────────────────────────────────────
 * ADMIN — Platform KPIs (/admin/kpis, operator-only)
 * Data-dense operator dashboard: hero metrics + sparklines, SVG charts,
 * engagement strip, leaderboards. Flat + brand-primary (no grey gradients).
 * ───────────────────────────────────────────────────────────────────── */
.kpi-page { max-width: 1320px; }
.kpi-page .kpi-section-label {
  font: 700 11px/1 Geist, system-ui, sans-serif;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-dim); margin: 26px 2px 12px;
}

/* ── Hero headline cards ── */
.kpi-hero-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px; margin-top: 4px;
}
.kpi-hero {
  background: var(--bg, #fff); border: 1px solid var(--border, #e3e6ea);
  border-radius: 14px; padding: 16px 18px 12px; position: relative; overflow: hidden;
  box-shadow: 0 1px 2px rgba(15,30,60,0.04), 0 4px 14px rgba(15,30,60,0.04);
}
.kpi-hero-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 18px; }
.kpi-hero-label {
  font: 700 10px/1 'JetBrains Mono', ui-monospace, monospace;
  color: var(--text-dim, #6b7280); text-transform: uppercase; letter-spacing: .1em;
}
.kpi-hero-value {
  font: 600 34px/1.05 'Instrument Sans', Geist, system-ui, sans-serif;
  letter-spacing: -0.035em; color: var(--text, #1a1d21); margin: 10px 0 3px;
}
.kpi-hero-sub { font: 500 11.5px/1.35 'JetBrains Mono', ui-monospace, monospace; color: var(--text-dim, #6b7280); }
.kpi-hero-spark { margin-top: 10px; height: 28px; }
.kpi-hero-spark .pc-spark { width: 100%; height: 28px; display: block; }

/* delta pills */
.kpi-delta { font: 700 10px/1 'JetBrains Mono', monospace; padding: 3px 6px; border-radius: 6px; white-space: nowrap; }
.kpi-delta--up   { color: #047857; background: rgba(16,185,129,0.12); }
.kpi-delta--down { color: #b91c1c; background: rgba(239,68,68,0.12); }
.kpi-delta--flat { color: var(--text-dim); background: var(--bg-soft, #f1f3f5); }

/* ── Chart grid ── */
.kpi-chart-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}
.chart-card {
  background: var(--bg, #fff); border: 1px solid var(--border, #e3e6ea);
  border-radius: 14px; padding: 16px 18px 14px;
  box-shadow: 0 1px 2px rgba(15,30,60,0.04), 0 4px 14px rgba(15,30,60,0.03);
}
.chart-card--wide { grid-column: 1 / -1; }
.chart-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.chart-card-head h2 { font: 650 15px/1.2 'Instrument Sans', Geist, system-ui, sans-serif; color: var(--text); margin: 0; letter-spacing: -0.01em; }
.chart-card-meta { font: 500 10.5px/1 'JetBrains Mono', monospace; color: var(--text-dim); text-transform: uppercase; letter-spacing: .06em; }
.chart-body { width: 100%; }
.chart-body .pc-svg { width: 100%; height: 210px; display: block; }
.chart-body--bars { padding-top: 2px; }
.chart-legend { display: flex; gap: 16px; margin-top: 8px; padding-left: 4px; }
.chart-legend-item { display: inline-flex; align-items: center; gap: 6px; font: 600 11px/1 Geist, system-ui, sans-serif; color: var(--text-dim); }
.chart-legend-item i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* horizontal bars (drills/week, teams by sport) */
.pc-bars { display: flex; flex-direction: column; gap: 9px; padding: 4px 0 2px; }
.pc-bar-row { display: grid; grid-template-columns: 78px 1fr auto; align-items: center; gap: 10px; }
.pc-bar-label { font: 600 12px/1.2 Geist, system-ui, sans-serif; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pc-bar-track { height: 10px; border-radius: 999px; background: var(--bg-soft, #eef0f3); overflow: hidden; }
.pc-bar-fill { display: block; height: 100%; border-radius: 999px; transition: width .4s ease; }
.pc-bar-val { font: 700 12px/1 'JetBrains Mono', monospace; color: var(--text); text-align: right; }
.pc-bar-val i { font: 500 10px/1 'JetBrains Mono', monospace; color: var(--text-dim); font-style: normal; margin-left: 4px; }

/* donut */
.pc-donut-wrap { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.pc-donut { width: 150px; height: 150px; flex: 0 0 auto; }
.pc-legend { display: flex; flex-direction: column; gap: 7px; flex: 1 1 auto; min-width: 120px; }
.pc-legend-row { display: flex; align-items: center; gap: 8px; font: 600 12.5px/1 Geist, system-ui, sans-serif; color: var(--text); }
.pc-legend-row b { margin-left: auto; font: 700 12.5px/1 'JetBrains Mono', monospace; }
.pc-legend-dot { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }

/* chart hover tooltip */
.pc-chart-tip {
  position: fixed; z-index: 60; pointer-events: none;
  background: #1a1d21; color: #fff; border-radius: 8px; padding: 8px 10px;
  font: 500 12px/1.4 Geist, system-ui, sans-serif; box-shadow: 0 6px 22px rgba(0,0,0,0.25);
  max-width: 220px;
}
.pc-tip-h { font-weight: 700; margin-bottom: 4px; font-size: 11px; opacity: .85; }
.pc-tip-row { display: flex; align-items: center; gap: 6px; }
.pc-tip-row b { margin-left: 4px; }
.pc-tip-dot { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.chart-body .pc-capture { cursor: crosshair; }

/* acquisition funnel (Landing → Demo → Signup) */
.kpi-funnel { display: flex; flex-direction: column; padding: 8px 0 2px; }
.kpi-funnel-stage { padding: 1px 0; }
.kpi-funnel-bar {
  background: var(--brand-primary, #d4302b); color: #fff; border-radius: 9px;
  min-width: 60px; height: 44px; display: flex; align-items: center; padding: 0 14px;
  box-shadow: 0 1px 3px rgba(15,30,60,0.12); transition: width .45s ease;
}
.kpi-funnel-bar span { font: 700 17px/1 'Instrument Sans', Geist, system-ui, sans-serif; letter-spacing: -0.02em; }
.kpi-funnel-stage:nth-of-type(3) .kpi-funnel-bar { opacity: .84; }
.kpi-funnel-stage:nth-of-type(5) .kpi-funnel-bar { opacity: .68; }
.kpi-funnel-label {
  font: 700 10px/1 'JetBrains Mono', monospace; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .08em; margin: 5px 0 2px 2px;
}
.kpi-funnel-arrow { font: 600 11px/1 Geist, system-ui, sans-serif; color: var(--text-dim); padding: 6px 0 6px 16px; }
.kpi-funnel-arrow::before { content: '↓'; margin-right: 7px; font-weight: 700; }

.kpi-label-note { font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--text-dim); opacity: .8; }
.kpi-empty-note { font: 500 12.5px/1.5 Geist, system-ui, sans-serif; color: var(--text-dim); padding: 18px 4px; margin: 0; }
.kpi-empty-note code { font: 600 11.5px/1 'JetBrains Mono', monospace; background: var(--bg-soft, #f1f3f5); padding: 2px 5px; border-radius: 4px; }

/* ── Self-contained stat cards (schedule/roster ones are route-scoped) ── */
.kpi-page .stats-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px; margin-bottom: 4px;
}
.kpi-page .stat-card {
  background: var(--bg, #fff); border: 1px solid var(--border, #e3e6ea);
  border-radius: 12px; padding: 15px 17px; position: relative; overflow: hidden;
  box-shadow: 0 1px 2px rgba(15,30,60,0.04), 0 2px 8px rgba(15,30,60,0.03);
}
.kpi-page .stat-card-label {
  font: 700 10px/1 'JetBrains Mono', ui-monospace, monospace;
  color: var(--text-dim, #6b7280); text-transform: uppercase; letter-spacing: .1em; margin-bottom: 9px;
}
.kpi-page .stat-card-value {
  font: 600 26px/1 'Instrument Sans', Geist, system-ui, sans-serif;
  letter-spacing: -0.03em; color: var(--text, #1a1d21); margin-bottom: 5px;
}
.kpi-page .stat-card-sub { font: 500 11px/1.35 'JetBrains Mono', ui-monospace, monospace; color: var(--text-dim, #6b7280); }

/* ── Tables / leaderboards ── */
.kpi-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 16px; }
.kpi-page .table-card {
  margin-top: 16px; background: var(--bg, #fff); border: 1px solid var(--border, #e3e6ea);
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(15,30,60,0.04), 0 2px 8px rgba(15,30,60,0.03);
}
.kpi-page .table-card .card-head { padding: 14px 18px 8px; }
.kpi-page .table-card .card-head h2 { font: 650 15px/1.2 'Instrument Sans', Geist, system-ui, sans-serif; color: var(--text); margin: 0; }
.kpi-table { width: 100%; border-collapse: collapse; }
.kpi-table td { padding: 9px 18px; border-top: 1px solid var(--border-soft, #eef0f3); font: 500 13px/1.3 Geist, system-ui, sans-serif; color: var(--text); }
.kpi-table tr:first-child td { border-top: none; }
.kpi-muted { color: var(--text-dim); }
.kpi-num { text-align: right; font-family: 'JetBrains Mono', monospace; font-weight: 700; white-space: nowrap; }
td.kpi-muted.kpi-num { font-weight: 500; }

@media (max-width: 980px) { .kpi-chart-grid { grid-template-columns: 1fr; } .chart-card--wide { grid-column: auto; } }
@media (max-width: 760px) { .kpi-cols { grid-template-columns: 1fr; } }
