/* =============================================================================
   Install — the coach's concept teaching surface (Film Room until the Aug 22
   2026 rename; Film Room is the ATHLETE product). Build order step 2.

   Shell/rail/grid/card/empty/btn/chip come from css/practice.css UNCHANGED
   ("Format = the drills page's card grid" — Carlos, Aug 17). Everything below
   is page-specific: the concept detail hero, philosophy strip, rules table,
   variations row and teach mode. Same token system as practice.css
   (--surface/--ink/--volt/etc.) so the page reads as one language, not two.

   The hero canvas is #modalCanvas — the SAME element id play-renderer.js's
   renderPlayOnCanvas()/startModalAnimation() target everywhere else (CTP
   modal, athlete Film Room). bindCtpNoteTips() also hardcodes .ctp-note-*
   class names, so those are restyled here in the practice.css palette rather
   than pulling in css/theme.css (whose :root token names collide with
   practice.css's — --border-strong is declared in both).
   ========================================================================== */

/* ── CONCEPT CARD — additions to .pr-card for the rail grid ────────────── */
.fr-card-syn {
    font-family: var(--font-sub);
    font-size: 12px;
    color: var(--ink-muted);
    margin-top: 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fr-card-count {
    margin-left: auto;
    font-family: var(--font-data);
    font-size: 10px;
    color: var(--ink-faint);
}
.fr-card-thumb {
    aspect-ratio: 16 / 10;
    background: var(--plate-mix);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
}
.fr-card-thumb i, .fr-card-thumb svg {
    width: 30px; height: 30px;
    color: rgba(255,255,255,0.25);
}
/* A card that HAS a play shows the play. The canvas fills the 16:10 plate the
   icon used to sit in the middle of, so the card reads as the board it opens. */
.fr-card-thumb.has-play { padding: 0; }
/* A card with NO play is EMPTY, not broken: it sits on the card surface (never
   the broadcast plate), states its own state in one phrase, and keeps the same
   16:10 box so a grid of mixed cards still lines up. */
.fr-card-thumb.is-empty {
    background: var(--surface-elevated);
    flex-direction: column;
    gap: 6px;
}
.fr-card-thumb.is-empty i, .fr-card-thumb.is-empty svg {
    width: 22px; height: 22px;
    color: var(--ink-faint);
}
.fr-card-thumb.is-empty span {
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-faint);
}
.fr-card-thumb-canvas {
    display: block;
    width: 100%;
    height: 100%;
}

/* ── GAME-DAY TARGETS (census Aug 22 2026, S3 #8) ─────────────────────────
   Every tap on this surface is >= 44px: the drills-page shell ships the rail
   back link at 18px and the icon button at 40px — scoped here, the drills
   page keeps its own bytes. The dot, Animate, Teach close and every
   segmented button are corrected at their own rules below. */
.pr-rail .pr-back { min-height: 44px; }
#viewConcept .pr-icon-btn { width: 44px; height: 44px; }
.fr-topbar-actions { display: flex; align-items: center; gap: 8px; flex: none; }
.fr-topbar-actions .pr-btn[hidden] { display: none; }

/* ── CONCEPT DETAIL ──────────────────────────────────────────────────────── */
.fr-detail-body {
    display: grid;
    grid-template-columns: 1fr 380px;
    gap: 18px;
    flex: 1;
    min-height: 0;
    padding-bottom: 20px;
}
@media (max-width: 980px) {
    .fr-detail-body { grid-template-columns: 1fr; }
}

.fr-hero-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.fr-canvas-wrap {
    position: relative;
    width: 100%;
    border-radius: var(--r-card);
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--plate-mix);
    perspective: 1100px;
    transition: background 0.4s ease, border-color 0.4s ease, padding 0.4s ease;
}
.fr-canvas-wrap canvas { display: block; width: 100%; height: auto; aspect-ratio: 960/600; }
.fr-mike-overlay { position: absolute; inset: 0; z-index: 3; pointer-events: none; }

/* ── VIEW TOGGLE + BROADCAST BOARD (build order step 5) ──────────────────
   #heroWrap (.fr-canvas-wrap) is the perspective STAGE; #boardSurface is
   the ONLY element that tilts — the canvas stack, plus the CTP note-dot
   layer (play-renderer.js appends dots into canvas.parentElement, which is
   now boardSurface, so dots inherit the tilt and stay pinned to the board
   for free). #animateBtn stays OUTSIDE boardSurface and never tilts —
   broadcast grammar is "the field tilts, the chyron doesn't." Pivoting from
   the bottom edge (transform-origin) reads as the near sideline anchored
   while the far side recedes — the standard broadcast table-top look. */
.fr-view-toggle { max-width: 240px; margin-bottom: 2px; }

.fr-board-surface {
    position: relative;
    transform-origin: 50% 100%;
    transform: rotateX(0deg);
    border-radius: var(--r-card);
    overflow: hidden;
    transition: transform 0.4s ease, box-shadow 0.4s ease, border-color 0.4s ease;
}
.fr-canvas-wrap.fr-broadcast-on {
    overflow: visible;
    background: #05070c;
    border-color: rgba(255,255,255,0.08);
    padding: 22px 12px 42px;
}
.fr-canvas-wrap.fr-broadcast-on .fr-board-surface {
    transform: rotateX(55deg);
    box-shadow: 0 32px 38px -16px rgba(0,0,0,0.8);
    border-bottom: 3px solid var(--volt);
}
@media (prefers-reduced-motion: reduce) {
    .fr-canvas-wrap, .fr-board-surface { transition: none; }
}

.fr-animate-btn {
    position: absolute;
    bottom: 12px;
    right: 12px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 16px;
    background: rgba(0,0,0,0.65);
    border: 1px solid var(--volt-glow);
    border-radius: 999px;
    color: #fff;
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    cursor: pointer;
    backdrop-filter: blur(8px);
    transition: background 0.2s ease, border-color 0.2s ease;
}
.fr-animate-btn:hover { background: rgba(0,0,0,0.8); border-color: var(--volt-deep); }
.fr-animate-btn[disabled] { opacity: 0.5; cursor: progress; }
/* The glyph is CSS, never a character: play = a volt triangle, running =
   a live-red square. The label swaps ANIMATE <-> STOP in the controller;
   the second tap stops the run (census S3 #9 — a swallowed tap and a
   label that never changes). */
.fr-animate-glyph {
    width: 0; height: 0;
    border-style: solid;
    border-width: 5px 0 5px 8px;
    border-color: transparent transparent transparent var(--volt);
}
.fr-animate-btn.running { border-color: var(--live); }
.fr-animate-btn.running .fr-animate-glyph {
    width: 9px; height: 9px;
    border: none;
    border-radius: 1px;
    background: var(--live);
}

/* ── EXPORT (Aug 22) — two independent actions under the board, in the page's
   secondary button grammar (.pr-btn--ghost). State is carried on the button
   the way the CTP modal's export does (play-renderer.js:1082-1090):
   .recording pulses live red, .ready wears the volt bottom edge (the same
   "this one is armed" mark .fr-mike-btn.chosen uses). ───────────────────── */
.fr-export-row { display: flex; gap: 8px; margin-top: 10px; }
.fr-export-btn { flex: 1; }
.fr-export-btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.fr-export-btn.recording { color: var(--live); border-color: var(--live); cursor: progress; animation: frRecPulse 1.1s ease-in-out infinite; }
.fr-export-btn.ready { color: var(--ink); border-color: var(--volt-deep); box-shadow: inset 0 -3px 0 var(--volt); }
.fr-export-reason {
    margin-top: 6px;
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.4px;
    color: var(--ink-muted);
}
@keyframes frRecPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) { .fr-export-btn.recording { animation: none; } }

/* ── MIKE READ (build order step 3) ──────────────────────────────────────
   Every container below matches .pr-card's radius EXACTLY (var(--r-card)) —
   the new elements speak the SAME grammar as the classes lifted from
   practice.css, never a second dialect. No accent ever rides a left rail:
   a fill, or a bottom edge, per the control-grammar law. */
.fr-mike-panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-card);
    padding: 12px 14px;
}
.fr-mike-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.fr-mike-label {
    font-family: var(--font-ui);
    font-weight: 700;
    font-size: 11px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ink-faint);
    flex: none;
}
.fr-mike-rule {
    font-family: var(--font-sub);
    font-size: 13px;
    color: var(--ink-muted);
}
/* ONE joined segmented control, matching platform3's .seg exactly (see
   platform3/schedule.html) — a padded PILL tray, pill buttons, chosen =
   ink fill + volt bottom edge. Not a bordered box with a hairline divider;
   that reads as two buttons wearing a shared outline, not one control. */
.fr-mike-buttons {
    display: flex;
    gap: 4px;
    background: var(--surface-elevated);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px;
}
.fr-mike-btn {
    flex: 1;
    min-height: 44px;
    padding: 0 14px;
    background: none;
    border: none;
    border-radius: 999px;
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    transition: background 0.15s ease, color 0.15s ease;
}
.fr-mike-btn:hover { color: var(--ink); }
.fr-mike-btn.chosen {
    background: var(--ink);
    color: #fff;
    box-shadow: inset 0 -3px 0 var(--volt);
}
/* The pause is a broadcast moment — a lower-third plate (ink surface, card
   radius, accent as a bottom edge), not a bordered note card. */
.fr-mike-caption {
    margin-top: 10px;
    padding: 12px 14px;
    background: var(--ink);
    border-radius: var(--r-card);
    box-shadow: inset 0 -3px 0 var(--volt);
}
.fr-mike-caption-eyebrow {
    font-family: var(--font-ui);
    font-weight: 700;
    font-size: 10px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--volt);
    margin-bottom: 4px;
}
.fr-mike-caption-text {
    font-family: var(--font-ui);
    font-weight: 600;
    font-size: 15px;
    line-height: 1.5;
    color: #fff;
}

/* ── COVERAGE PICKER (build order step 4) ──────────────────────────────── */
.fr-coverage-panel {
    display: flex;
    flex-direction: column;
    gap: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-card);
    padding: 0 14px;
}
/* The header IS the toggle (44px). Collapsed by default so the Mike tray
   above it and this row both sit above the fold at 1366x1024 / 1024x768
   (census S3 #6); it opens itself the moment a look is on the board. */
.fr-cov-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 44px;
    padding: 0;
    background: none;
    border: none;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
}
.fr-cov-head-sum {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-sub);
    font-size: 13px;
    color: var(--ink-muted);
}
.fr-cov-chev { width: 16px; height: 16px; color: var(--ink-faint); transition: transform 0.2s ease; }
.fr-cov-head[aria-expanded="true"] .fr-cov-chev { transform: rotate(180deg); }
.fr-cov-body { display: flex; flex-direction: column; gap: 10px; padding: 2px 0 12px; }
.fr-cov-body[hidden] { display: none; }
.fr-coverage-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.fr-cov-seg { flex: none; }
.fr-cov-seg .fr-mike-btn { flex: none; min-height: 44px; padding: 0 12px; }
/* Scrubber (coverage sim) — a 44px hit band over a 4px track; the thumb
   is the only volt on the row (a fill), the rusher mark is pressure red. */
.fr-cov-track { position: relative; flex: 1; min-width: 160px; height: 44px; display: flex; align-items: center; }
.fr-cov-scrub {
    width: 100%;
    height: 44px;
    margin: 0;
    background: transparent;
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
    touch-action: pan-y;
}
.fr-cov-scrub::-webkit-slider-runnable-track { height: 4px; border-radius: 2px; background: var(--border-strong); }
.fr-cov-scrub::-moz-range-track { height: 4px; border-radius: 2px; background: var(--border-strong); }
.fr-cov-scrub::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 22px; height: 22px; margin-top: -9px;
    border-radius: 50%;
    background: var(--volt);
    border: 2px solid var(--ink);
}
.fr-cov-scrub::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: var(--volt); border: 2px solid var(--ink); }
.fr-cov-rush {
    position: absolute; top: 50%; width: 3px; height: 14px; margin-left: -1px;
    transform: translateY(-50%);
    background: var(--live);
    border-radius: 1px;
    pointer-events: none;
}
.fr-cov-clock {
    flex: none;
    font-family: var(--font-data);
    font-size: 13px;
    letter-spacing: 0.5px;
    color: var(--ink);
}
.fr-cov-clock i { font-style: normal; font-family: var(--font-ui); color: var(--ink-faint); padding: 0 4px; }
.fr-cov-eyes { display: flex; gap: 6px; margin-left: auto; }
.fr-cov-eye {
    min-height: 44px;
    padding: 0 10px;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 3px;
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    cursor: pointer;
}
.fr-cov-eye.off { color: var(--ink-faint); text-decoration: line-through; }
.fr-cov-status {
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.4px;
    color: var(--ink-muted);
}
.fr-coverage-label {
    font-family: var(--font-ui);
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--ink-muted);
    flex: none;
}
.fr-coverage-select {
    flex: 1;
    min-height: 38px;
    padding: 0 10px;
    background: var(--surface-elevated);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 600;
}

/* ── PHILOSOPHY CARD ──────────────────────────────────────────────────────
   Same treatment as the Mike panel, lighter weight: light surface, card
   radius, eyebrow label, sentence in body face. No rail. */
.fr-philosophy {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-card);
    padding: 14px 16px;
}
.fr-philosophy-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 6px;
}
.fr-philosophy-head .fr-philosophy-eyebrow { margin-bottom: 0; }
/* .pr-btn sets display:inline-flex (practice.css:191), which beats the UA
   [hidden] rule at equal specificity — same cascade bug as
   .fr-philosophy-edit[hidden] and .fr-philosophy-sub[hidden] below, just on
   a shared button class instead of a page-local one. Without this the Edit
   button stays visible while the editor is open, and a second tap on it
   silently wipes whatever the coach had typed (FR.startConceptEdit()
   overwrites the inputs from the record unconditionally). Fix round 1,
   Aug 31 2026. */
.fr-philosophy-edit-btn[hidden] { display: none; }
.fr-philosophy-eyebrow {
    font-family: var(--font-ui);
    font-weight: 700;
    font-size: 10px;
    letter-spacing: 1.6px;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 6px;
}
/* Read blocks and edit form are mutually exclusive — [hidden] alone would be
   overridden by the flex column below without this (same pattern as
   .fr-topbar-actions .pr-btn[hidden], install.css:64). */
.fr-philosophy-edit {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 10px;
}
.fr-philosophy-edit[hidden] { display: none; }
.fr-philosophy-edit-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}
.fr-philosophy-text {
    font-family: var(--font-sub);
    font-size: 15px;
    line-height: 1.55;
    color: var(--ink);
}
.fr-philosophy-text.fr-empty-inline { color: var(--ink-faint); font-style: italic; }
.fr-philosophy-sub {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
}
/* display:flex above beats the UA [hidden] rule at equal specificity — this
   is the guard that actually hides it while the editor is open. */
.fr-philosophy-sub[hidden] { display: none; }
.fr-philosophy-sub .fr-syn {
    font-family: var(--font-sub);
    font-size: 12px;
    color: var(--ink-faint);
}
/* Square 3px chip, matching platform3's .fchip exactly — the label tier,
   never a grey inline afterthought. */
.fr-beats-chip {
    display: inline-flex;
    align-items: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ink-muted);
    border: 1px solid var(--border-strong);
    border-radius: 3px;
    padding: 4px 9px;
    background: var(--surface);
}

/* ── META LINE — plain micro-copy, never a row of chips (control-grammar
   law: "a row of standalone pills reads vibe-coded — never ship one").
   These are read-only tags; the mock's own .eyebrow/.wk voice is the right
   model, not filter chips. ─────────────────────────────────────────────── */
.fr-meta-row {
    font-family: var(--font-ui);
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--ink-faint);
}
.fr-meta-side { color: var(--ink); }
.fr-meta-side.fr-side-offense { color: var(--info); }
.fr-meta-side.fr-side-defense { color: var(--live); }
.fr-meta-dot { color: var(--ink-faint); font-weight: 400; }

/* ── DETAILS COLUMN ──────────────────────────────────────────────────────── */
.fr-side-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; overflow-y: auto; }
.fr-section-title {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 8px;
}

/* ── RULES TABLE — built from canvas_data.playerNotes ───────────────────── */
.fr-rules-table {
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    overflow: hidden;
}
.fr-rules-row {
    display: grid;
    grid-template-columns: 52px 1fr;
    gap: 10px;
    background: var(--surface);
    padding: 9px 11px;
}
.fr-rules-pos {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 14px;
    letter-spacing: 0.4px;
    color: var(--ink);
    align-self: start;
}
.fr-rules-body { min-width: 0; }
.fr-rules-route {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--on-volt);
    background: var(--volt);
    border-radius: 3px;
    padding: 1px 6px;
    margin-bottom: 3px;
}
.fr-rules-note { font-size: 13px; line-height: 1.45; color: var(--ink-muted); }
.fr-rules-empty {
    padding: 16px 12px;
    text-align: center;
    font-size: 12.5px;
    color: var(--ink-faint);
    background: var(--surface);
}

/* ── VARIATIONS ROW ──────────────────────────────────────────────────────── */
.fr-variations { display: flex; flex-direction: column; gap: 6px; }
.fr-var-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 9px 11px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-xs);
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 700;
    text-align: left;
    transition: all 0.15s ease;
}
.fr-var-btn:hover { border-color: var(--border-strong); color: var(--ink); }
.fr-var-btn.active {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
    box-shadow: inset 0 -2px 0 var(--volt);
}
.fr-var-look {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    opacity: 0.65;
}

/* ── TEACH BUTTON + MODE ─────────────────────────────────────────────────── */
.fr-teach-btn {
    background: linear-gradient(135deg, var(--volt), var(--volt-deep));
    color: var(--on-volt);
}

.fr-teach {
    position: fixed;
    inset: 0;
    z-index: 500;
    background: var(--plate-mix);
    display: none;
    flex-direction: column;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.fr-teach.active { display: flex; }
.fr-teach-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 18px;
    cursor: default;
}
.fr-teach-progress { flex: 1; display: flex; gap: 5px; }
.fr-teach-dot { flex: 1; height: 3px; border-radius: 2px; background: rgba(255,255,255,0.18); }
.fr-teach-dot.done { background: var(--volt); }
.fr-teach-dot.on { background: rgba(255,255,255,0.6); }
.fr-teach-close {
    width: 44px; height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,0.08);
    border-radius: 999px;
    color: #fff;
}
.fr-teach-close i, .fr-teach-close svg { width: 16px; height: 16px; }

.fr-teach-body {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    padding: 10px 24px 30px;
    text-align: center;
}
.fr-teach-panel { display: none; width: 100%; max-width: 780px; cursor: default; }
.fr-teach-panel.active { display: block; }

.fr-teach-cover-name {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(32px, 6vw, 64px);
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #fff;
    line-height: 1;
}
.fr-teach-cover-phil {
    margin-top: 18px;
    font-family: var(--font-sub);
    font-size: 17px;
    line-height: 1.6;
    color: rgba(255,255,255,0.82);
}
.fr-teach-cover-sub {
    margin-top: 14px;
    font-size: 12px;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--volt);
}

.fr-teach-diagram-wrap {
    position: relative;
    width: 100%;
    max-width: 900px;
    margin: 0 auto;
    border-radius: var(--r-card);
    overflow: hidden;
    border: 1px solid rgba(255,255,255,0.12);
}
/* Broadcast tilts the board via a 3D transform (fr-broadcast-on) — Teach
   mode reparents #heroWrap wholesale, so the class travels with it, but
   this wrap's own overflow:hidden would clip the tilted result exactly
   like the home slot's would. Same relief valve, same trigger. */
.fr-teach-diagram-wrap:has(.fr-canvas-wrap.fr-broadcast-on) { overflow: visible; }

.fr-teach-rules-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 22px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #fff;
    margin-bottom: 16px;
}
.fr-teach-rules-table { text-align: left; max-width: 560px; margin: 0 auto; }
.fr-teach-rules-table .fr-rules-row { background: rgba(255,255,255,0.06); }
.fr-teach-rules-table .fr-rules-pos { color: #fff; }
.fr-teach-rules-table .fr-rules-note { color: rgba(255,255,255,0.75); }
.fr-teach-rules-table { background: rgba(255,255,255,0.12); }

/* ── TEACH: a drill on a read-only board ─────────────────────────────────
   Same 16:10 board the drill editor and the library card draw, same panel
   width as the play diagram. The card beat sits the words beside the board;
   the run beat (.fr-teach-drill-running) hands the board the whole slide. */
.fr-teach-drill-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(20px, 3.4vw, 30px);
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #fff;
    margin-bottom: 14px;
}
.fr-teach-drill-body {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: 18px;
    align-items: start;
    text-align: left;
}
.fr-teach-drill-running .fr-teach-drill-body { grid-template-columns: minmax(0, 1fr); }
.fr-teach-drill-board {
    border-radius: var(--r-card);
    overflow: hidden;
    border: 1px solid rgba(255,255,255,0.12);
}
.fr-teach-drill-board canvas { display: block; width: 100%; height: auto; }
.fr-teach-drill-text { min-width: 0; }
.fr-teach-drill-label {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 12px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--volt);
    margin: 12px 0 6px;
}
.fr-teach-drill-text > .fr-teach-drill-label:first-child { margin-top: 0; }
.fr-teach-drill-list {
    margin: 0;
    padding-left: 18px;
    font-family: var(--font-sub);
    font-size: 14px;
    line-height: 1.55;
    color: rgba(255,255,255,0.82);
}
.fr-teach-drill-list li { margin-bottom: 5px; }
/* A tablet held upright puts the words under the board, never beside it. */
@media (max-width: 980px) {
    .fr-teach-drill-body { grid-template-columns: minmax(0, 1fr); }
}

/* ── TEACH: a note, a break, a block whose reference is gone ───────────── */
.fr-teach-card-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(28px, 5vw, 48px);
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #fff;
    line-height: 1.05;
}
.fr-teach-card-sub {
    margin-top: 14px;
    font-family: var(--font-sub);
    font-size: 16px;
    line-height: 1.5;
    color: rgba(255,255,255,0.7);
}
.fr-teach-card-mins {
    margin-top: 16px;
    font-size: 12px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--volt);
}

.fr-teach-next-label {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 15px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--volt);
}
.fr-teach-next-name {
    margin-top: 8px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(26px, 5vw, 44px);
    text-transform: uppercase;
    color: #fff;
}
.fr-teach-hint {
    margin-top: 22px;
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: rgba(255,255,255,0.35);
}

/* ── CTP note layer (play-renderer.js hardcodes these class names) ──────── */
.ctp-note-hint {
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--ink-faint);
    text-align: center;
    padding-top: 6px;
}
.ctp-note-dots { position: absolute; inset: 0; pointer-events: none; z-index: 6; }
.ctp-note-dot {
    position: absolute;
    width: 44px; height: 44px;
    margin: -22px 0 0 -22px;
    padding: 0;
    border-radius: 50%;
    clip-path: circle(50%);
    background: transparent;
    border: none;
    cursor: pointer;
    pointer-events: auto;
}
.ctp-note-dot::before {
    content: '';
    position: absolute;
    left: 50%; top: 50%;
    width: 13px; height: 13px;
    margin: -6.5px 0 0 -6.5px;
    border-radius: 50%;
    background: var(--volt);
    border: 2px solid rgba(0,0,0,0.55);
    box-sizing: border-box;
    animation: frNotePulse 2s ease-in-out infinite;
}
@keyframes frNotePulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--volt-glow); }
    50% { box-shadow: 0 0 0 7px rgba(34, 197, 94, 0); }
}
.ctp-note-tip {
    position: fixed;
    z-index: 10010;
    max-width: 260px;
    padding: 10px 12px;
    background: var(--ink);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(0,0,0,0.45);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
    color: rgba(255,255,255,0.85);
    pointer-events: none;
    opacity: 0;
    transform: translateY(4px) scale(0.97);
    transition: opacity 0.16s ease, transform 0.16s ease;
}
.ctp-note-tip.on { opacity: 1; transform: translateY(0) scale(1); }
.ctp-note-tip b {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: #fff;
    margin-bottom: 3px;
}
.ctp-note-tip .ctp-note-route {
    display: block;
    font-style: normal;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.8px;
    color: var(--volt);
    margin-bottom: 2px;
}

/* ── THE PRODUCT MARK IN THE RAIL HEAD ───────────────────────────────────
   Sits above the nav as identity. Two files, one visible: the rail's ground
   flips with the theme, and a mark chosen by filename is how a logo ends up
   black-on-black. */
.pr-brand { display: flex; align-items: center; padding: 2px 2px 0; }
.pr-brand img { display: block; width: auto; height: 22px; max-width: 100%; }
.pr-brand .pr-brand-night { display: none; }
:root[data-theme="dark"] .pr-brand .pr-brand-day { display: none; }
:root[data-theme="dark"] .pr-brand .pr-brand-night { display: block; }

/* ── RAIL-SCOPED EXTRAS ──────────────────────────────────────────────────
   FR.showRail sets [hidden] on everything carrying data-rail. That is enough
   for a plain block, but practice.css:164 gives .pr-rail-section
   `display: flex`, and a class selector outranks the UA's `[hidden]` rule —
   so the chip rows would stay on screen with the attribute set. Restate the
   hide at attribute specificity, the same way practice.css:756 does for
   .pr-team[hidden]. */
.pr-rail-section[hidden],
.pr-rail-foot[hidden] { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   PRACTICE PLANS (IP) — the plan list, the block timeline, the picker and the
   block editor. Appended BELOW everything above, prefixed `ip-`, consuming the
   same practice.css tokens as the rest of the page: no local palette, no
   hardcoded colour, no !important.

   THE ROW LAW (Carlos, Aug 29 2026) is the whole reason .ip-block is a GRID
   with fixed columns rather than a flex row: every block lines up with the one
   above it — grip, type, what it is, how long, one verb. A block's length, its
   labels and its notes are not in the row; they are behind Edit.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── THE PLAN CARD ────────────────────────────────────────────────────── */
.ip-plan { cursor: pointer; }
.ip-plan-sub {
    margin-bottom: 7px;
    font-family: var(--font-sub);
    font-size: 12px;
    line-height: 1.45;
    color: var(--ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* ONE verb, spelled. It sits on the card the way the drill room's delete does
   (practice.css:771) but stays legible without hover — a coach on a tablet
   never gets one. */
.ip-plan-act {
    position: absolute;
    top: 8px;
    right: 8px;
    min-height: 28px;
    padding: 4px 9px;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface);
    color: var(--ink-faint);
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.ip-plan-act:hover { color: var(--live); border-color: var(--live); }
/* Armed: the first tap says the next one commits, and it reads live rather
   than quiet. Same two-step, same look as the drill card's (practice.css:794)
   — one pattern for "this destroys something", not two. */
.ip-plan-act.is-armed {
    color: var(--surface);
    background: var(--live);
    border-color: var(--live);
}
/* ⛔ THE BUTTON IS ABSOLUTE; THE NAME MUST NOT RUN UNDER IT. The drill card
   gets away with a corner control because its top-right corner is a thumbnail;
   a plan card has no thumb, so the name starts exactly where the button sits.
   Reserve its width and truncate — a long plan name printed underneath a
   Remove button is unreadable at exactly the moment it matters. */
.ip-plan .pr-card-name {
    /* MARGIN, not padding: padding leaves the box full width, so the name's
       box still runs under the absolutely-positioned button even though the
       glyphs stop short. The reserve has to be real. */
    margin-right: 86px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── THE EDITOR HEAD ──────────────────────────────────────────────────── */
.ip-plan-meta {
    display: grid;
    grid-template-columns: 1fr 220px 120px;
    gap: 12px;
    align-items: end;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}
.ip-clock-field { align-items: flex-start; }
/* Numerals only (Orbitron law) — a clock is exactly what this face is for. */
.ip-clock {
    min-height: 44px;
    display: flex;
    align-items: center;
    font-family: var(--font-data);
    font-size: 22px;
    font-weight: 700;
    letter-spacing: 0.5px;
    color: var(--ink);
}

/* ── THE TIMELINE ─────────────────────────────────────────────────────── */
.ip-timeline {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 0 6px;
}
.ip-timeline-empty {
    padding: 34px 0;
    text-align: center;
    font-family: var(--font-sub);
    font-size: 13px;
    color: var(--ink-faint);
}

.ip-block {
    display: grid;
    grid-template-columns: 30px 34px minmax(0, 1fr) 78px 74px;
    align-items: center;
    gap: 10px;
    min-height: 56px;
    padding: 7px 12px 7px 4px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    transition: border-color 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}
.ip-block:hover { border-color: var(--border-strong); }
.ip-block.ip-dragging { opacity: 0.45; }
.ip-block.ip-drag-over { border-color: var(--volt-deep); background: var(--hover); }

.ip-block-grip {
    width: 30px;
    min-height: 44px;
    display: grid;
    place-items: center;
    border-radius: var(--r-xs);
    color: var(--ink-faint);
    cursor: grab;
    touch-action: none;
}
.ip-block-grip:hover, .ip-block-grip:focus-visible { color: var(--ink); background: var(--hover); }
.ip-block-grip:active { cursor: grabbing; }
.ip-block-grip i, .ip-block-grip svg { width: 16px; height: 16px; }

.ip-block-type {
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border-radius: var(--r-xs);
    background: var(--surface-elevated);
    border: 1px solid var(--border);
    color: var(--ink-muted);
}
.ip-block-type i, .ip-block-type svg { width: 16px; height: 16px; }

.ip-block-main { min-width: 0; }
.ip-block-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* ONE muted line. Everything else about a block is behind its Edit. */
.ip-block-sub {
    margin-top: 2px;
    font-family: var(--font-sub);
    font-size: 12px;
    color: var(--ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ip-block-mins {
    font-family: var(--font-data);
    font-size: 11px;
    color: var(--ink-faint);
    text-align: right;
}
.ip-block-act {
    min-height: 34px;
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface);
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.ip-block-act:hover { color: var(--ink); border-color: var(--border-strong); background: var(--hover); }

/* A block whose play or drill has left the library. The row stays, its state
   is said in words, and its one verb still works — that is how a coach gets it
   out of the plan. */
.ip-block-gone .ip-block-type { color: var(--live); border-color: var(--live); }
.ip-block-gone .ip-block-title { color: var(--ink-muted); }
.ip-block-gone .ip-block-sub { color: var(--live); }

/* ── THE ADD ROW — four SQUARE chips, never four pills ────────────────── */
.ip-add-row {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: auto;
    padding: 12px 0 4px;
    background: var(--canvas);
    border-top: 1px solid var(--border);
}
.ip-add-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ip-add {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 8px 13px;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface);
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.ip-add:hover { color: var(--ink); border-color: var(--border-strong); background: var(--hover); }
/* Active = ink fill + volt bottom edge is the platform's on-state; a chip that
   only ever gets pressed uses the same edge as a press affordance. */
.ip-add:active { box-shadow: inset 0 -2px 0 0 var(--volt-deep); }
.ip-add i, .ip-add svg { width: 14px; height: 14px; }

/* ── THE MODALS (picker + block editor) ───────────────────────────────── */
.ip-modal {
    position: fixed;
    inset: 0;
    z-index: 10020;
    display: grid;
    place-items: center;
    padding: 20px;
}
.ip-modal[hidden] { display: none; }
/* THE KEYBOARD IS UP (js/designer-new-play.js fitSheetToKeyboard, Oct 10
   2026): the sheet covers only the part of the screen the coach can see, so
   the field he is typing in is already above the keyboard and iOS has no
   caret to reveal — the reveal, redone per keystroke in a fixed box, was the
   jump. The card fits the visible height; its body scrolls. */
.ip-modal.is-kb {
    top: var(--ip-kb-top, 0px);
    bottom: auto;
    height: var(--ip-kb-h, 100%);
    padding-top: 8px;
    padding-bottom: 8px;
}
.ip-modal.is-kb .ip-modal-card { max-height: 100%; }
.ip-modal-scrim {
    position: absolute;
    inset: 0;
    background: rgba(17, 19, 22, 0.62);
}
.ip-modal-card {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(680px, 100%);
    max-height: min(78vh, 720px);
    padding: 16px 18px 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-shell);
    box-shadow: 0 24px 60px rgba(17, 19, 22, 0.35);
    overflow: hidden;
}
.ip-modal-card--sheet { width: min(520px, 100%); }
.ip-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
}
.ip-modal-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 19px;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--ink);
}

/* Square filter chips (3px), active = ink fill + volt bottom edge. */
.ip-picker-filters { display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 0 4px; }
.ip-picker-filters[hidden] { display: none; }
.ip-pick-chip {
    min-height: 34px;
    padding: 6px 11px;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface);
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    cursor: pointer;
}
.ip-pick-chip:hover { color: var(--ink); border-color: var(--border-strong); }
.ip-pick-chip.active {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--surface);
    box-shadow: inset 0 -3px 0 0 var(--volt);
}

.ip-picker-grid {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 2px 2px;
}
/* .fr-fm-grid's display:grid outranks the UA [hidden] rule (the same cascade
   bug as .ip-modal[hidden] and .ip-picker-filters[hidden] above). Without this
   the designer's Offense/Defense sheet showed BOTH grids at once, and the two
   flex:1 grids split the card's height, squashing every tile's picture. */
.ip-picker-grid[hidden] { display: none; }
.ip-pick-note {
    padding: 34px 8px;
    text-align: center;
    font-family: var(--font-sub);
    font-size: 13px;
    line-height: 1.55;
    color: var(--ink-faint);
}
.ip-pick-group { margin-bottom: 14px; }
.ip-pick-group-title {
    margin-bottom: 6px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--ink-faint);
}
/* Same fixed-column discipline as the timeline: name, one muted line, a number. */
.ip-pick {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 74px;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 48px;
    margin-bottom: 5px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--r-xs);
    background: var(--surface);
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.ip-pick:hover { border-color: var(--border-strong); background: var(--hover); }
.ip-pick-name {
    grid-column: 1;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ip-pick-sub {
    grid-column: 1;
    font-family: var(--font-sub);
    font-size: 12px;
    color: var(--ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ip-pick-mins {
    grid-column: 2;
    grid-row: 1 / span 2;
    font-family: var(--font-data);
    font-size: 11px;
    color: var(--ink-faint);
    text-align: right;
}

.ip-sheet-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px 2px 4px;
}
/* The sheet's reorder row. Square controls (3px), the same grammar as the add
   chips — these are actions, never status. */
.ip-sheet-order {
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
}
.ip-sheet-order-btns { display: flex; flex-wrap: wrap; gap: 6px; }
.ip-move {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface);
    color: var(--ink-muted);
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.ip-move:hover:not(:disabled) { color: var(--ink); border-color: var(--border-strong); background: var(--hover); }
/* An edge is a real state, said out loud rather than swallowed. */
.ip-move:disabled { opacity: 0.4; cursor: default; }
.ip-move i, .ip-move svg { width: 14px; height: 14px; }

/* The picker's honest failure plate: chrome copy plus ONE control. */
.ip-pick-retry {
    display: block;
    margin: 12px auto 0;
    min-height: 40px;
    padding: 8px 16px;
    border: 1px solid var(--border-strong);
    border-radius: 3px;
    background: var(--surface);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    cursor: pointer;
}
.ip-pick-retry:hover { background: var(--hover); }

.ip-sheet-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}

/* ── THE FORMATION SHEET (lane 2e) ────────────────────────────────────────
   A tile is its SHAPE. The svg is the play's own coordinate space (960x600)
   so the picture cannot disagree with what gets written; the dots are drawn
   at play scale and let the viewBox do the shrinking, which is why the r and
   font-size below look large. Square corners and the ink-fill-on-active
   grammar the rest of the platform uses — no pill soup. */
/* TWO UP, so a coach sees six formations without scrolling instead of two
   and a half. Scoped to this sheet — #playPicker's own grid is unchanged. */
/* ⛔ KEYED ON THE CLASS, NOT ON ONE PAGE'S ID (Sep 22 2026, PR 2 M1b). These
   two rules were `#formationGrid`, so coach/play-designer.html's own formation
   sheet — same markup, same tiles, its own id — got NO grid at all and stacked
   eleven tiles in one column. A layout rule that only one document can reach is
   how "render a class the design has no rule for" happens on the next page. */
.fr-fm-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 10px;
    align-content: start;
}
.fr-fm-grid .ip-pick-note { grid-column: 1 / -1; }
.fr-fm-tile {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    cursor: pointer;
    text-align: left;
    min-height: 44px;
    transition: border-color 120ms var(--ease), background 120ms var(--ease);
}
.fr-fm-tile:hover { border-color: var(--border-strong); background: var(--hover); }
.fr-fm-tile:active { background: var(--surface-elevated); }
.fr-fm-shape {
    display: block;
    width: 100%;
    /* The crop is wide and short (bodies, not grass), so the box matches it —
       16/10 would put the empty margins straight back. */
    aspect-ratio: 5 / 2;
    background: var(--surface-elevated);
    border-radius: var(--r-xs);
}
.fr-fm-shape line { stroke: var(--border-strong); stroke-width: 4; }
.fr-fm-shape circle { fill: var(--surface); stroke: var(--ink); stroke-width: 7; }
.fr-fm-shape text {
    fill: var(--ink);
    font-family: var(--font-ui);
    font-size: 46px;
    font-weight: 700;
    text-anchor: middle;
}
.fr-fm-name {
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
}

/* ── HIS FORMATIONS + ADD FORMATION (Sep 25 2026, the designer's sheet) ────
   Every selector below is a class ONLY coach/play-designer.html's sheet ever
   renders (js/formation-sheet.js renderWithMine, reached only with `onAdd`) or
   the editor inside that same card. Install's #formationGrid, #ipPickerGrid
   and #playPickerGrid never carry them, so its sheets paint as before. */
/* ⛔ A PICTURE KEEPS ITS SIZE; THE GRID SCROLLS. `.fr-fm-tile`'s explicit
   `min-height: 44px` replaces a grid item's automatic (content) minimum, so
   when the tiles outgrow the card the `auto` rows collapse toward 44px and
   every picture is squeezed to fit (51px tall at 2eca4aa7d with eleven
   built-ins; 25px once this grid gained his tiles and the labels, with the
   tiles overlapping). max-content rows give each tile its own height back and
   the grid scrolls, as `.ip-picker-grid` already declares it should.
   Only the designer's grid (js/formation-sheet.js renderWithMine) carries
   this class; Install's #formationGrid keeps its own behaviour. */
.fr-fm-grid--mine { grid-auto-rows: max-content; }
/* ⛔ AND THE COVERAGE GRID, AND EVERY OTHER (Oct 6 2026). The rule above was
   given to ONE grid; #pdAlignmentGrid (the Defense tab, same tiles) never got
   it, so its seven pictures were squeezed to ~50px tall inside 116px boxes and
   CB1/LB2 crowded the edge of discs a third of their size. Keyed on the class
   so no grid of these tiles can miss it again: rows are their content's
   height, the picture never shrinks, the grid scrolls. */
.fr-fm-grid { grid-auto-rows: max-content; }
.fr-fm-tile > .fr-fm-shape { flex: none; }
.fr-fm-grid .ip-pick-group-title { grid-column: 1 / -1; margin: 4px 0 0; }
.fr-fm-grid .ip-pick-group-title ~ .ip-pick-group-title {
    margin-top: 8px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.fr-fm-mute {
    grid-column: 1 / -1;
    font-family: var(--font-sub);
    font-size: 12px;
    line-height: 1.5;
    color: var(--ink-faint);
}
/* The door to making one: the same tile, dashed, a plus where the shape goes. */
.fr-fm-add { border-style: dashed; border-color: var(--border-strong); }
.fr-fm-add .fr-fm-name { color: var(--ink); font-weight: 700; }
.fr-fm-plus path { fill: none; stroke: var(--ink); stroke-width: 7; stroke-linecap: round; }
/* Just saved: ink edge + the volt bottom edge, the platform's on-state. */
.fr-fm-tile.is-new { border-color: var(--ink); box-shadow: inset 0 -3px 0 0 var(--volt); }

/* The editor: the tile's picture at field scale, a name, Save. */
.fr-fe {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
    overflow-y: auto;
    padding-top: 12px;
}
.fr-fe[hidden] { display: none; }
.ip-modal-head .seg[hidden] { display: none; }
.fr-fm-shape.fr-fe-board {
    aspect-ratio: 1068 / 354;   /* js/formation-sheet.js EDITOR_VIEWBOX */
    touch-action: none;         /* a drag moves a player, never the page */
    user-select: none;
    -webkit-user-select: none;
}
/* a 5v5 field is narrower than the board: its two sidelines, drawn in the
   editor where the board's own sit (js/formation-sheet.js fieldEdges) */
.fr-fm-shape line.fr-fe-sideline { stroke: var(--ink-muted); stroke-width: 4; }
.fr-fe-tok { cursor: grab; outline: none; }
.fr-fe-tok[data-type="C"] { cursor: ew-resize; }
.fr-fe-tok.is-drag { cursor: grabbing; }
.fr-fe-tok.is-drag circle,
.fr-fe-tok:focus-visible circle { fill: var(--ink); }
.fr-fe-tok.is-drag text,
.fr-fe-tok:focus-visible text { fill: var(--surface); }
/* ⛔ THE GRAB AREA, NOT THE PICTURE (Sep 30 2026, token-size dial). .fr-fe-hit
   is the invisible, fixed-size first circle js/formation-sheet.js draws so a
   coach who dials the visible token down to Small never loses the ≥44px
   target underneath it. Higher specificity than the two rules above (which
   would otherwise paint it ink on drag/focus, same as the visible dot). */
.fr-fe-tok .fr-fe-hit,
.fr-fe-tok.is-drag .fr-fe-hit,
.fr-fe-tok:focus-visible .fr-fe-hit { fill: transparent; stroke: none; }
.fr-fe-msg {
    min-height: 18px;
    margin: 0;
    font-family: var(--font-sub);
    font-size: 13px;
    line-height: 1.45;
    color: var(--ink-muted);
}
.fr-fe-msg.is-refused { color: var(--live); }
.fr-fe .pd-run { min-height: 44px; font-family: var(--font-ui); cursor: pointer; }
.fr-fe .pd-run[disabled] { opacity: 0.55; cursor: progress; }

/* ── THE RAIL NARROWS TO ITS ICONS (Carlos, Sep 3 2026) ──────────────────
   Not a disappearance and not an overlay. .pr-shell's first grid track goes
   from 264px to 68px, so the board takes every pixel the words give up, and
   the four destinations stay exactly where the hand already reaches for them —
   the icon rail from design-directions/install-design-rail.html, which he
   designed. Nothing floats over the board; nothing has to be found again. */
.pr-shell.rail-away { --pr-rail-w: 68px; }
.pr-shell.rail-away .pr-rail { padding-left: 6px; padding-right: 6px; }
/* Words go; icons, order, spacing and the active treatment all stay. */
.pr-shell.rail-away .pr-nav-item span,
.pr-shell.rail-away .pr-rail-section,
.pr-shell.rail-away .pr-brand,
.pr-shell.rail-away .pr-wordmark,
.pr-shell.rail-away .pr-team-meta,
.pr-shell.rail-away .pr-back span { display: none; }
.pr-shell.rail-away .pr-nav-item { justify-content: center; padding: 0; gap: 0; }
.pr-shell.rail-away .pr-back { justify-content: center; }
/* The team card keeps its CREST — whose install this is survives the fold;
   only the words go, and the plate shrinks to fit the badge. */
.pr-shell.rail-away .pr-team { padding: 8px; justify-content: center; }
/* The fold turns into the way back, in place: same item, same 44px, arrow
   reversed. A coach never hunts for the control he just used. */
.pr-shell.rail-away #railFold i,
.pr-shell.rail-away #railFold svg { transform: scaleX(-1); }

/* ── THE ASK (method.md #11) ──────────────────────────────────────────────
   Two options, each a full-width plate: the label in the UI voice, one muted
   line saying what it does. Square corners and the card tier's radius — the
   control grammar's plates, never pills, and never a row of them. */
.pd-ask-body { display: flex; flex-direction: column; gap: 10px; }
.pd-ask-opt {
    display: flex;
    flex-direction: column;
    gap: 3px;
    width: 100%;
    min-height: 44px;
    padding: 13px 16px;
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    cursor: pointer;
}
.pd-ask-opt:hover { background: var(--hover); border-color: var(--border-strong); }
.pd-ask-lab {
    font-family: var(--font-ui);
    font-size: 14px;
    font-weight: 700;
    color: var(--ink);
}
.pd-ask-sub {
    font-family: var(--font-sub);
    font-size: 12px;
    color: var(--ink-muted);
}
