/* Epic 0034 §6 — Playoff Editor modal + bracket canvas.
   Ported from the design-approved mockup (docs/epics/0034-tournament-module/
   mockup-tournament-editor.html), which mirrors the Scheduler modal chrome
   and app tokens (config/variables.css). pe- = playoff editor; bk-/bm- =
   the shared bracket canvas (also used read-only outside the editor). */

/* ── modal shell ── */
.pe { position: relative; display: flex; flex-direction: column; width: min(1720px, 97vw); height: min(90vh, 1040px); overflow: hidden; background: var(--surface); border-radius: var(--r-lg); box-shadow: var(--shadow-lg); }
.pe__header { flex-shrink: 0; padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--line); }
.pe__header-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.pe__title { font-size: 1.35rem; font-weight: 700; }
.pe__header-controls { display: flex; align-items: center; gap: 1rem; }
.pe__close { background: none; border: none; font-size: 1.5rem; line-height: 1; color: var(--ink-3); cursor: pointer; padding: 0.25rem 0.5rem; border-radius: var(--r-sm); }
.pe__close:hover { background: var(--bg-2); color: var(--ink); }
.pe__content { flex: 1; overflow-y: auto; padding: 1.25rem 1.5rem; background: var(--surface); }
.pe__footer { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem 1.5rem; border-top: 1px solid var(--line); background: var(--surface); }
.pe__footer-left { display: flex; align-items: center; gap: 0.75rem; font-size: 0.8rem; flex: 1; min-width: 0; }
.pe__footer-right { display: flex; gap: 0.6rem; margin-left: auto; flex-shrink: 0; }
/* pure step navigation at a static width — the buttons never move (Gate 2) */
.pe-navbtn { width: 200px; }
.pe-footer-error { color: var(--danger); font-weight: 600; }
.pe-footer-error a { color: var(--accent); margin-left: 0.3rem; }
.pe-footer-dirty { color: var(--ink-3); font-size: 0.78rem; font-weight: 600; }
.pe__footer-left .btn--primary { min-width: 150px; }

/* header summary badges */
.pe__summary { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.6rem; }
.pe-badge { font-size: 0.78rem; font-weight: 600; padding: 0.2rem 0.6rem; border-radius: var(--r-pill); background: var(--bg-2); color: var(--ink-2); white-space: nowrap; }
.pe-badge--warning { background: var(--warning-soft); color: var(--warning); }
.pe-bcard__stats { font-size: 0.76rem; color: var(--ink-3); }

/* stepper */
.pe__steps { display: flex; align-items: center; gap: 0.2rem; flex-wrap: wrap; }
.pe-stepchip { display: flex; align-items: center; gap: 0.4rem; font-size: 0.72rem; font-weight: 600; color: var(--ink-3); padding: 0.15rem 0.3rem; }
.pe-stepnum { width: 1.15rem; height: 1.15rem; border-radius: 50%; background: var(--bg-2); color: var(--ink-3); display: flex; align-items: center; justify-content: center; font-size: 0.68rem; font-weight: 800; flex-shrink: 0; }
.pe-stepchip--done .pe-stepnum { background: var(--success-soft); color: var(--success); }
.pe-stepchip--on { color: var(--ink); }
.pe-stepchip--on .pe-stepnum { background: var(--accent); color: #fff; }
/* chips as navigation (Gate 2): clickable wherever a jump is legal */
.pe-stepchip--link { cursor: pointer; border-radius: var(--r-sm); }
.pe-stepchip--link:hover { color: var(--ink); background: var(--bg-2); }
.pe-steparrow { color: var(--ink-4, var(--ink-3)); font-size: 0.7rem; }

/* steps */
.pe-step { display: none; }
.pe-step--on { display: block; }

/* form bits */
.pe-f { display: flex; flex-direction: column; gap: 0.3rem; }
.pe-frow { display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-end; }
.pe-lbl { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); white-space: nowrap; }
.pe-lbl--sub { text-transform: none; letter-spacing: 0; }
.pe-inp, .pe-sel { appearance: none; -webkit-appearance: none; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 0.4rem 0.6rem; font: inherit; font-size: 0.9rem; color: var(--ink); }
.pe-inp:focus, .pe-sel:focus { outline: 0; border-color: var(--accent); box-shadow: var(--focus-ring, 0 0 0 3px rgba(37, 99, 235, 0.18)); }
.pe-inp--sm, .pe-sel--sm { font-size: 0.85rem; padding: 0.3rem 0.5rem; }
.pe-help-wrap { position: relative; display: inline-flex; }
.pe-help { font-size: 0.7rem; font-weight: 700; color: var(--ink-3); cursor: pointer; border: 1px solid var(--line); background: var(--surface); border-radius: 50%; width: 17px; height: 17px; display: inline-flex; align-items: center; justify-content: center; user-select: none; }
.pe-help:hover { border-color: var(--ink-3); color: var(--ink-2); }
.pe-tooltip { position: absolute; left: 24px; top: 50%; transform: translateY(-50%); z-index: 30; width: 260px; background: var(--gray-800, #1f2937); color: #e5e7eb; font-size: 0.75rem; line-height: 1.45; font-weight: 500; padding: 0.5rem 0.65rem; border-radius: var(--r-md); box-shadow: var(--shadow-lg); }
.pe-notice { font-size: 0.82rem; padding: 0.5rem 0.75rem; border-radius: var(--r-sm); }
.pe-notice--info { background: var(--accent-light); color: var(--ink-2); border-left: 3px solid var(--accent); }
.pe-notice--warning { background: var(--warning-soft); color: var(--warning); border-left: 3px solid var(--warning); }
/* Inline retry inside a notice — the quiet affordance a failed preview needs
   (§20.2): the last good bracket stays on screen, this re-asks for it. */
.pe-linkbtn { background: none; border: 0; padding: 0; font: inherit; color: inherit;
              text-decoration: underline; cursor: pointer; }

/* toggle */
.pe-sw { display: inline-flex; align-items: center; gap: 0.5rem; cursor: pointer; user-select: none; }
.pe-sw input { display: none; }
.pe-sw .pe-tr { width: 36px; height: 20px; border-radius: 999px; background: var(--bg-2); position: relative; transition: 0.15s; flex-shrink: 0; }
.pe-sw .pe-tr::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: 0.15s; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); }
.pe-sw input:checked + .pe-tr { background: var(--accent); }
.pe-sw input:checked + .pe-tr::after { left: 18px; }
.pe-swlbl { font-size: 0.82rem; font-weight: 600; }

/* step 1 split + bracket config cards */
.pe-split { display: grid; grid-template-columns: 380px 1fr; gap: 1.25rem; align-items: start; }
.pe-stack { display: flex; flex-direction: column; gap: 1.1rem; }
.pe-panel { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.pe-panel__head { padding: 0.6rem 0.9rem; border-bottom: 1px solid var(--line-2); background: var(--surface-2); }
.pe-panel__title { font-size: 0.78rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-2); }
.pe-panel__body { padding: 1rem 0.9rem; display: flex; flex-direction: column; gap: 1rem; }
/* The bracket card's color swatch (step 2 head) — the only survivor of the
   pre-rework per-bracket card; the rest of that block retired with §18.6. */
.pe-bcard__color { width: 26px; height: 26px; padding: 0; border: 1px solid var(--line); border-radius: 50%; background: none; cursor: pointer; flex-shrink: 0; }
.pe-bcard__color::-webkit-color-swatch-wrapper { padding: 2px; }
.pe-bcard__color::-webkit-color-swatch { border: none; border-radius: 50%; }
.pe-bcard__color::-moz-color-swatch { border: none; border-radius: 50%; }
.pe-seg { display: inline-flex; border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; }
.pe-seg button { background: var(--surface); border: none; padding: 0.35rem 0.8rem; font-size: 0.82rem; font-weight: 700; color: var(--ink-3); cursor: pointer; }
.pe-seg button.on { background: var(--accent); color: #fff; }

/* step 2 seeding (wireframe-normative). Exactly two scrollbars: the team
   list card and the brackets column — step 2 pins the modal content
   (pe__content--fixed) so it never adds its own. */
.pe__content--fixed { overflow: hidden; display: flex; flex-direction: column; }
.pe__content--fixed .pe-step--on { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.pe-seed-cols { display: grid; grid-template-columns: 370px 1fr; gap: 1.25rem; align-items: stretch; flex: 1; min-height: 0; }
.pe-seed-col { display: flex; flex-direction: column; min-height: 0; }
.pe-seed-col > .pe-panel__title { margin-bottom: 0.45rem; }
.pe-seed-controls { display: flex; align-items: center; gap: 0.5rem; min-height: 34px; margin-bottom: 0.55rem; }
.pe-fitbtn { background: var(--surface); border: 1px solid var(--warning); border-radius: var(--r-pill); padding: 0.24rem 0.7rem; font: inherit; font-size: 0.74rem; font-weight: 700; color: var(--ink-2); cursor: pointer; }
.pe-fitbtn:hover { background: var(--warning-soft); }
.pe-seed-list { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); padding: 0.5rem; overflow-y: auto; display: flex; flex-direction: column; gap: 0.45rem; flex: 1; min-height: 0; }
/* Slots are single targets, not lists: suppress Sortable's in-slot ghost —
   the drop is a swap/replace resolved by re-render, never an insertion
   preview. Scoped to slot fills ONLY: in the team list, clone-mode tags the
   ORIGINAL card as the ghost, and hiding it made the card vanish from the
   list mid-drag — there it just dims instead. */
.pe-slot__fill .sortable-ghost { display: none !important; }
.pe-seed-list .sortable-ghost { opacity: 0.4; }
.pe-tcard { display: flex; align-items: center; gap: 0.6rem; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); padding: 0.4rem 0.55rem; cursor: grab; box-shadow: 0 1px 2px rgba(17, 24, 39, 0.03); }
.pe-tcard:hover { border-color: var(--ink-3); }
.pe-tcard__icon { width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0; color: #fff; font-size: 0.62rem; font-weight: 800; display: flex; align-items: center; justify-content: center; }
.pe-tcard__text { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.pe-tcard__l1 { font-size: 0.83rem; font-weight: 700; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pe-tcard__l2 { font-size: 0.72rem; color: var(--ink-3); line-height: 1.25; margin-top: 1px; }
.pe-tcard__l2 b { color: var(--ink-2); font-weight: 700; }
.pe-tcard__flag { flex-shrink: 0; width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; font-weight: 800; }
.pe-tcard__flag--seeded { background: var(--success-soft); color: var(--success); }
.pe-tcard__flag--unseeded { background: var(--bg-2); color: var(--ink-3); }
.pe-tcard--ghost { opacity: 0.55; }
/* §18.1: a tiered split landing inside a rank group — the equal-rank ordering,
   not the rank, decided this team's bracket. Both sides of the cut are amber. */
.pe-tcard--boundary { border-color: var(--warning); background: var(--warning-soft); }
.pe-tcard--preview { opacity: 0.45; border-style: dashed; pointer-events: none; }
.pe-hidden-for-preview { display: none !important; }
.pe-tcard__x { margin-left: auto; background: none; border: none; color: var(--ink-3); cursor: pointer; font-size: 0.9rem; padding: 0 0.2rem; }
.pe-tcard__x:hover { color: var(--danger); }
/* overflow: clip on the INLINE axis only. `hidden` clipped both axes, so any
   row shorter than the card silently swallowed its lower seats instead of
   showing them — a seat you cannot see is a seat you cannot drop onto. The
   header's rounded corners only need the horizontal clip. */
.pe-brk { border: 1px solid var(--line); border-radius: var(--r-md); margin-bottom: 0.7rem; overflow-x: clip; background: var(--surface); }
.pe-brk__head { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.7rem; background: var(--surface-2); border-bottom: 1px solid var(--line-2); }
.pe-brk__count { font-size: 0.74rem; color: var(--ink-3); margin-left: auto; }
.pe-brk__slots { padding: 0.5rem 0.6rem; display: flex; flex-direction: column; gap: 0.4rem; }
.pe-slot { display: flex; align-items: center; gap: 0.55rem; min-height: 50px; }
.pe-slot__seed { width: 1.5rem; text-align: right; font-size: 0.78rem; font-weight: 800; color: var(--ink-3); flex-shrink: 0; }
.pe-slot__fill { flex: 1; min-width: 0; min-height: 50px; display: flex; flex-direction: column; justify-content: center; }
.pe-slot__fill .pe-tcard { min-height: 46px; }
.pe-slot__empty { flex: 1; height: 50px; border: 1.5px dashed var(--line); border-radius: var(--r-md); display: flex; align-items: center; padding-left: 0.7rem; color: var(--ink-3); font-size: 0.78rem; font-style: italic; }

/* step 3 tabs + toolbar */
.pe-bk-toolbar { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; flex-wrap: wrap; }
.pe-tabs { display: flex; gap: 0.35rem; overflow-x: auto; }
.pe-tab { padding: 0.45rem 0.9rem; border: 1px solid var(--line); background: var(--surface-2); font-size: 0.82rem; font-weight: 700; color: var(--ink-3); cursor: pointer; border-radius: var(--r-md); display: flex; flex-direction: column; align-items: center; gap: 0.1rem; flex-shrink: 0; }
.pe-tab:hover { color: var(--ink); background: var(--bg-2); }
.pe-tab--on { color: #fff; background: var(--accent); border-color: var(--accent); }
.pe-tab__meta { font-size: 0.7rem; font-weight: 500; }

/* ── shared bracket canvas (editor + read-only surfaces) ── */
.pe-bk-canvas, .bk-canvas { position: relative; overflow: auto; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface-2); background-image: radial-gradient(circle, var(--line-2) 1px, transparent 1px); background-size: 20px 20px; padding: 0.5rem; max-height: calc(90vh - 320px); }
.bk-inner { position: relative; }
.bk-wires { position: absolute; inset: 0; pointer-events: none; }
.bk-wires path { stroke: var(--gray-400, #a3acb9); stroke-width: 1.4; fill: none; }
.bk-rhead { position: absolute; font-size: 0.64rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-3); }
/* .tp-head retired — the consolation round now names itself in the card's own
   label ("M8 · 3rd Place Match"); the separate heading landed on top of it. */
.bm { position: absolute; width: 206px; }
.bm__card { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; background: var(--surface); box-shadow: 0 1px 2px rgba(17, 24, 39, 0.05); }
.bm__side { display: flex; align-items: center; gap: 0.45rem; height: 30px; padding: 0 0.5rem; }
.bm__side + .bm__side { border-top: 1px solid var(--line-2); }
.bm__side--drag { cursor: grab; }
.bm__side--drag:hover { background: var(--accent-light); }
.bm__seed { width: 18px; height: 18px; border-radius: 4px; background: var(--bg-2); color: var(--ink-2); font-size: 0.66rem; font-weight: 800; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
/* A bye: the team advanced without playing. Grey text, no card, no border —
   visibly not a match, and not draggable, because there is nothing here to
   play or to swap. Sits at the row the match it skipped would have used. */
.bk-bye { position: absolute; display: flex; align-items: center; gap: 0.45rem; height: 30px; padding: 0 0.5rem; color: var(--ink-3); pointer-events: none; }
.bk-bye__seed { width: 18px; height: 18px; border-radius: 4px; background: transparent; border: 1px dashed var(--line); color: var(--ink-3); font-size: 0.66rem; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.bk-bye__name { font-size: 0.77rem; font-weight: 500; font-style: italic; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.bk-bye__tag { font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-4, var(--ink-3)); flex-shrink: 0; }
.bk-bye .bm__icon { opacity: 0.55; }

/* Team icon: 20px inside the existing 30px row, so it never changes card
   height. Letter fallback mirrors the app's team-icon chip. */
.bm__icon { width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0; object-fit: cover; }
.bm__icon--letter { display: flex; align-items: center; justify-content: center; color: #fff; font-size: 0.6rem; font-weight: 800; }
.bm__name { font-size: 0.77rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.bm__name--ref { font-style: italic; color: var(--ink-3); font-weight: 500; }
.bm--minor .bm__card { border-style: dashed; }
.bm--final .bm__card { border-color: var(--gold, #D4A017); box-shadow: 0 0 0 1px var(--gold, #D4A017), 0 2px 6px rgba(212, 160, 23, 0.18); }
.bm__label { position: absolute; left: 0; top: -15px; font-size: 0.6rem; font-weight: 800; letter-spacing: 0.04em; color: var(--ink-3); text-transform: uppercase; }
.bm--final .bm__label { color: var(--gold, #D4A017); }

/* ── §18 one-page configuration (Step 1): sub-questions + tiles ── */
.pe-qsub { padding: 0.25rem 0 0.65rem; }
.pe-qsub + .pe-qsub { border-top: 1px dashed var(--line-2); padding-top: 0.75rem; }
.pe-qnum { display: inline-flex; width: 1.15rem; height: 1.15rem; border-radius: 50%; background: var(--bg-2); color: var(--ink-3); font-size: 0.68rem; font-weight: 800; align-items: center; justify-content: center; margin-right: 0.4rem; }
.pe-qnote { font-size: 0.78rem; color: var(--ink-3); margin-top: 0.45rem; max-width: 72ch; }
.pe-qfields { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.55rem; align-items: flex-start; }
.pe-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.7rem; margin-top: 0.5rem; }
.pe-tiles--2col { grid-template-columns: repeat(2, 1fr); }
.pe-tile { border: 1.5px solid var(--line); border-radius: var(--r-md); background: var(--surface); padding: 0.65rem; cursor: pointer; display: flex; flex-direction: column; gap: 0.35rem; transition: border-color 0.12s, box-shadow 0.12s; }
.pe-tile:hover { border-color: var(--ink-4, var(--ink-3)); }
.pe-tile.on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.pe-tile__head { display: flex; align-items: center; justify-content: space-between; gap: 0.4rem; }
.pe-tile__title { font-size: 0.8rem; font-weight: 700; }
.pe-tile__tag { font-size: 0.6rem; font-weight: 800; letter-spacing: 0.05em; color: var(--ink-3); background: var(--bg-2); border-radius: var(--r-pill); padding: 0.1rem 0.45rem; flex-shrink: 0; }
.pe-tile__sub { font-size: 0.72rem; color: var(--ink-3); min-height: 2.1em; }
.pe-tile__viz { background: var(--surface-2); border-radius: var(--r-sm); padding: 0.2rem; height: 86px; }

/* ── §18.6 Step 2: side-by-side bracket-card grid + per-card config ── */
/* Bracket cards vary in height with their team count. `align-items: start` is
   the load-bearing bit: grid items stretch to the tallest card in their ROW by
   default, so a 4-team bracket sitting beside a 12-team one grew a tall empty
   body. Starting them instead lets every card size to its own content — no
   stretching, no inner scrolling, every slot visible and droppable.
   Row-major order is kept deliberately (Bracket 1, 2, 3 read left to right);
   the cost is ragged whitespace under shorter cards, which is the standard
   trade. CSS multi-column would close those gaps but reorders the cards into
   column-major and reflows mid-drag, which is a bad bargain for a
   drag-and-drop surface. */
/* grid-auto-rows: min-content is the load-bearing declaration, not a tidy-up.
   Rows here were coming out a fixed fraction of the container instead of
   sizing to their contents, which produced BOTH reported symptoms from one
   cause: with the default align-items: stretch the card was squashed into the
   short row and `overflow: hidden` clipped its lower seats (cards "cut off"),
   and with align-items: start the card took its natural height and spilled
   over the next row (brackets drawn on top of each other). Pinning the row to
   its content makes a too-short row impossible however the container is
   sized. align-items: start then keeps a 4-team card from growing to match a
   12-team neighbour. */
.pe-seed-brackets { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); grid-auto-rows: min-content; gap: 0.7rem; align-content: start; align-items: start; overflow-y: auto; flex: 1; min-height: 0; padding-right: 0.2rem; }
.pe-seed-brackets .pe-brk { margin-bottom: 0; }
.pe-brk__namein { border: 1px solid transparent; border-radius: var(--r-sm); background: transparent; font-weight: 800; font-size: 0.85rem; color: var(--ink); padding: 0.15rem 0.3rem; min-width: 0; flex: 1; }
.pe-brk__namein:hover, .pe-brk__namein:focus { border-color: var(--line); background: var(--surface); outline: none; }
.pe-brk__meta { display: flex; align-items: flex-end; gap: 0.6rem; padding: 0.45rem 0.7rem 0; }
.pe-brk__meta .pe-f { flex-direction: row; align-items: center; gap: 0.4rem; }
.pe-brk__fmtbtn { border: none; background: none; font-size: 0.74rem; color: var(--ink-3); cursor: pointer; padding: 0.15rem 0; text-align: left; }
.pe-brk__fmtbtn:hover { color: var(--ink); text-decoration: underline; }
.pe-brk__fmtdef { color: var(--ink-4, var(--ink-3)); }
.pe-brk__fmtpanel { display: flex; align-items: center; flex-wrap: wrap; gap: 0.6rem; padding: 0.45rem 0.7rem; border-top: 1px dashed var(--line-2); margin-top: 0.4rem; }
.pe-brk__stats { font-size: 0.72rem; color: var(--ink-3); flex-basis: 100%; }
.pe-badge--accent { background: var(--accent-light); color: var(--accent); }
.pe-seed-controls .pe-tabs { flex: 0 1 auto; min-width: 0; }
.pe-locknote__tail { color: var(--ink-3); font-style: italic; }

/* ── Step 4: Schedule (§19) ─────────────────────────────────────────── */
.pe-sched { display: flex; flex-direction: column; height: 100%; min-height: 0; gap: 0.6rem; }
.pe-sched__chrome { display: flex; flex-direction: column; gap: 0.5rem; }
.pe-sched__pills { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.pe-pill { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.25rem 0.7rem; border-radius: 999px; border: 2px solid var(--line); background: var(--surface); font-size: 0.78rem; font-weight: 700; color: var(--ink-2); cursor: pointer; }
.pe-pill--on { border-color: var(--accent); color: var(--ink); }
.pe-pill__dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.pe-pill-plain { border: none; background: none; font-size: 0.78rem; font-weight: 700; color: var(--accent); cursor: pointer; padding: 0.25rem 0.4rem; }
.pe-sched__bar { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.pe-sched__count { font-size: 0.8rem; font-weight: 700; color: var(--ink-2); }
.pe-sched__actions { margin-left: auto; display: flex; gap: 0.4rem; flex-wrap: wrap; }
.pe-sched__cols { display: grid; grid-template-columns: 1fr 260px; gap: 0.75rem; min-height: 0; flex: 1; }
.pe-sched__main { overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 0.75rem; }
.pe-sched__side { overflow-y: auto; min-height: 0; }
.pe-sched__side__head, .pe-sched-side__head { font-size: 0.85rem; font-weight: 800; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.4rem; }
.pe-sched-fac { flex-shrink: 0; }
.pe-sched-scroll { overflow-x: auto; }
.pe-sched-table { border-collapse: collapse; width: 100%; font-size: 0.78rem; }
.pe-sched-th { text-align: left; padding: 0.4rem 0.6rem; background: var(--surface-2); border: 1px solid var(--line); font-weight: 700; color: var(--ink-3); white-space: nowrap; }
.pe-sched-cell { border: 1px solid var(--line); padding: 0.3rem; min-width: 130px; height: 44px; vertical-align: middle; }
.pe-sched-cell--na { background: var(--bg-2); color: var(--ink-3); text-align: center; }
.pe-sched-cell--free { background: transparent; }
.pe-sched-time { border: 1px solid var(--line); padding: 0.3rem 0.6rem; font-weight: 700; color: var(--ink-2); white-space: nowrap; cursor: pointer; background: var(--surface-2); }
.pe-sched-time:hover { background: var(--bg-2); }
.pe-sched-card { display: flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.5rem; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); font-size: 0.76rem; font-weight: 700; cursor: grab; margin-bottom: 0.3rem; }
.pe-sched-card--armed { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-light, rgba(37,99,235,.15)); }
.pe-sched-cell .pe-sched-card { margin-bottom: 0; }
.pe-sched-round { color: var(--ink-3); font-weight: 500; font-size: 0.7rem; }
.pe-sched-x { border: none; background: none; color: var(--ink-3); font-size: 0.9rem; cursor: pointer; margin-left: auto; padding: 0 0.15rem; }
.pe-sched-x:hover { color: var(--danger, #ef4444); }
.pe-sched-here { width: 100%; border: 1px dashed var(--accent); background: none; color: var(--accent); font-size: 0.74rem; font-weight: 700; padding: 0.3rem; border-radius: var(--r-md); cursor: pointer; }
.pe-sched-empty { text-align: center; padding: 2.5rem 1rem; color: var(--ink-2); display: flex; flex-direction: column; gap: 0.75rem; align-items: center; }
.pe-sched-chip { font-size: 0.62rem; font-weight: 700; color: var(--accent); padding: 0 6px 2px; }
.pe-sched-modal { position: fixed; inset: 0; background: rgba(15,23,42,.45); display: flex; align-items: center; justify-content: center; z-index: 60; }
.pe-sched-modal__box { background: var(--surface); border-radius: var(--r-lg); width: min(560px, 92vw); max-height: 85vh; overflow-y: auto; display: flex; flex-direction: column; }
.pe-sched-modal__body { padding: 1rem; display: flex; flex-direction: column; gap: 0.75rem; font-size: 0.85rem; }
.pe-sched-modal__body label { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; }
.pe-sched-modal__locs { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.pe-sched-modal__times { display: flex; align-items: end; gap: 0.6rem; flex-wrap: wrap; }
.pe-sched-modal__math { font-weight: 700; color: var(--ink-2); }
.pe-sched-modal__note { font-size: 0.78rem; color: var(--ink-3); }
.pe-sched-modal__foot { display: flex; justify-content: flex-end; gap: 0.5rem; padding: 0.75rem 1rem; border-top: 1px solid var(--line); }
.pe-sched-modal__foot .btn--danger { margin-right: auto; }

/* v1.41 keyboard path — a visible, non-colour-alone focus/armed treatment */
.pe-tcard:focus-visible, .pe-slot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pe-kb-armed { outline: 2px dashed var(--accent); outline-offset: 2px; }

/* Gate-1 feedback: visible field borders + stable input widths (native time
   inputs resize with their value, shoving the + button onto a new row) */
.pe-sched-modal__body input, .pe-sched-modal__body select {
  border: 1px solid var(--line); border-radius: 6px; padding: 0.3rem 0.5rem;
  background: var(--surface); font: inherit; font-size: 0.85rem;
}
.pe-sched-modal__times { flex-wrap: nowrap; }
.pe-sched-modal__times input[type="time"] { width: 118px; flex: none; }
.pe-sched-modal__times input[type="number"] { width: 74px; flex: none; }
.pe-sched-modal__body input[type="date"] { width: 160px; flex: none; }

/* Gate-1 round 2: wireframe structure, chips vs buttons, richer cards */
.pe-sched__chrome { border-bottom: 1px solid var(--line); padding-bottom: 0.6rem; }
.pe-sched__side { border-left: 1px solid var(--line); padding-left: 0.75rem; }
.pe-sched-flabel { font-size: 0.8rem; font-weight: 800; letter-spacing: 0.03em; text-transform: uppercase; color: var(--ink-2); margin: 0.15rem 0 0.4rem; }
.pe-sched-tablecard { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 0.4rem; }
/* chips read as filters, not buttons: soft fill + check, never solid */
.pe-pill { border: 1px solid var(--line); background: var(--bg-2); color: var(--ink-3); font-weight: 600; }
.pe-pill--on { border-color: var(--accent); background: var(--accent-light, #eff6ff); color: var(--ink); font-weight: 700; }
.pe-pill__check { color: var(--accent); font-weight: 800; min-width: 0.7em; display: inline-block; }
.pe-seg { display: inline-flex; border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.pe-seg__btn { border: none; background: var(--surface); padding: 0.4rem 0.95rem; font-size: 0.82rem; font-weight: 700; color: var(--ink-3); cursor: pointer; }
.pe-seg__btn + .pe-seg__btn { border-left: 1px solid var(--line); }
/* the Games entry is a LINK among buttons (epic 0044 §5.3) — an inline anchor
   baseline-aligns and breaks the row; it must fill the flex row like its
   button siblings */
a.pe-seg__btn { display: inline-flex; align-items: center; text-decoration: none; }
.pe-seg__btn--on { background: var(--accent); color: #fff; }
/* richer match cards */
.pe-sched-card { display: block; cursor: grab; }
.pe-sched-card__l1 { display: flex; align-items: center; gap: 0.35rem; }
.pe-sched-card__l2 { font-size: 0.72rem; font-weight: 600; color: var(--ink-2); margin-top: 2px; display: flex; align-items: center; gap: 0.35rem; min-width: 0; }
.pe-sched-vs { color: var(--ink-3); font-weight: 500; flex-shrink: 0; }
/* Step-4 sides match the bracket cards: seed badge · icon · name (Kyle) */
.pe-sched-side { display: inline-flex; align-items: center; gap: 0.3rem; vertical-align: middle; min-width: 0; max-width: 100%; }
.pe-sched-card__l2 .bm__name { font-size: 0.72rem; }
.pe-sched-card__l3 { font-size: 0.68rem; font-weight: 600; color: var(--ink-3); margin-top: 1px; }
.pe-sched-cell { height: auto; min-width: 170px; }
.pe-sched-mirror { margin: 0 0 0.25rem auto; display: flex; justify-content: flex-end; }
.pe-sched-chip { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.pe-sched-flabel { display: flex; align-items: center; gap: 0.6rem; }
.pe-sched-facdel { border: none; background: none; color: var(--ink-3); font-size: 0.7rem; font-weight: 600; cursor: pointer; text-transform: none; letter-spacing: 0; }
.pe-sched-facdel:hover { color: var(--danger, #ef4444); }

/* Gate-1 round 3: chrome full-bleed + grey surfaces + toggle selection */
.pe-seg .pe-seg__btn--on { background: var(--accent, #2563eb); color: #fff; }
.pe-seg .pe-seg__btn--on:hover { background: var(--accent, #2563eb); color: #fff; }
/* the divider under the controls spans the whole modal, and the controls
   band reads as its own light-grey region */
.pe-sched__chrome {
  margin: -1.25rem -1.5rem 0; padding: 0.9rem 1.5rem 0.7rem;
  background: var(--bg-2); border-bottom: 1px solid var(--line);
}
/* light-grey canvases so the white cards pop */
.pe-sched__cols { padding-top: 0.75rem; }
.pe-sched__main { background: var(--bg-2); border-radius: var(--r-lg); padding: 0.75rem; }
.pe-sched__side { background: var(--bg-2); border-radius: var(--r-lg); padding: 0.75rem; border-left: none; }
.pe-sched__cols { gap: 1rem; }

/* Gate-1 round 4: white controls, plain sections on a grey base, tables sit
   directly on the background, "…" facility menu, merged date rows */
.pe-sched__chrome { background: var(--surface); }
.pe-sched__cols {
  margin: 0 -1.5rem -1.25rem; padding: 0.9rem 1.5rem 1.25rem;
  background: var(--bg-2);
}
.pe-sched__main { background: none; border-radius: 0; padding: 0; }
.pe-sched__side { background: none; border-radius: 0; padding: 0 0 0 0.75rem; }
.pe-sched-scroll { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); }
.pe-sched-table { border-radius: var(--r-lg); }
.pe-sched-daterow td {
  background: var(--surface-2); color: var(--ink-2); font-weight: 800; font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: 0.04em; padding: 0.35rem 0.6rem;
  border: 1px solid var(--line);
}
/* the whole timetable runs on the header grey so match cards stand out
   (Kyle — editor and Playoff page alike); the list table stays white */
.pe-sched-table:not(.pe-sched-table--list) { background: var(--surface-2); }
.pe-sched-time { font-size: 0.8rem; position: relative; }
/* §19.2 border dragging: slim grab zones on the time cell's top and bottom
   edges; the affordance is the resize cursor, colour only on hover */
/* handles stay INSIDE the cell box — straddling the border (-3px) made
   every facility table overflow by 3px and grow a phantom scrollbar */
.pe-band-handle { position: absolute; left: 0; right: 0; height: 7px; cursor: ns-resize; }
.pe-band-handle--top { top: 0; }
.pe-band-handle--bottom { bottom: 0; }
.pe-band-handle:hover { background: var(--accent-light, rgba(37, 99, 235, 0.18)); }
.pe-band-conflict, .pe-band-conflict [data-bandlabel] { color: var(--danger, #ef4444); }
/* mid-drag, the resize cursor must win over every element's own cursor
   (cards say grab, cells pointer) — and text must not get swipe-selected */
.pe-band-dragging, .pe-band-dragging * { cursor: ns-resize !important; user-select: none; }
.pe-menu { position: relative; display: inline-block; }
.pe-menu__btn { border: none; background: none; color: var(--ink-3); font-size: 1rem; font-weight: 800; cursor: pointer; padding: 0 0.3rem; line-height: 1; }
.pe-menu__btn:hover { color: var(--ink); }
.pe-menu__list {
  position: absolute; top: 100%; left: 0; z-index: 20; min-width: 160px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
  box-shadow: 0 6px 18px rgba(15,23,42,.12); padding: 0.25rem; display: block;
}
.pe-menu__list button {
  display: block; width: 100%; text-align: left; border: none; background: none;
  padding: 0.4rem 0.6rem; font-size: 0.8rem; font-weight: 600; color: var(--danger, #ef4444);
  cursor: pointer; border-radius: 6px; text-transform: none; letter-spacing: 0;
}
.pe-menu__list button:hover { background: var(--bg-2); }

/* Gate-1 round 5: white base, real divider, tight spacing, card meta */
.pe-sched { gap: 0; }
/* __body replaces __cols (it is the step's content region, not a grid of
   card divs) — the old __cols selectors above are dead */
.pe-sched__body {
  display: grid; grid-template-columns: 1fr 280px; gap: 0;
  min-height: 0; flex: 1; background: var(--surface); padding: 0;
}
.pe-sched__body--full { grid-template-columns: 1fr; }
.pe-sched__main { overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 1rem; padding: 0.9rem 1rem 0.9rem 0; }
.pe-sched__side { overflow-y: auto; min-height: 0; border-left: 1px solid var(--line); padding: 0.9rem 0 0.9rem 0.9rem; }
.pe-sched-table { margin: 0; }
.pe-sched-scroll { overflow: hidden auto; }
/* the per-card schedule header (bracket view) */
.bm__meta { display: flex; flex-direction: column; padding: 3px 8px; border-bottom: 1px solid var(--line); background: var(--surface-2); font-size: 0.66rem; font-weight: 700; color: var(--accent); line-height: 1.35; height: 34px; justify-content: center; }
.bm__meta-l2 { color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bm__meta-none { color: var(--ink-3); font-weight: 600; font-style: italic; }

/* Step 4 stacks its bracket canvases in one scrolling column — each canvas
   grows to its full draw height (the step scrolls, the canvas never does
   vertically; horizontal stays for wide brackets). Step 3 keeps its cap. */
.pe-sched__main .pe-bk-canvas { max-height: none; }

/* Gate-1 round 6: stable columns, armed styling, app-style match list */
.pe-sched-table { table-layout: fixed; }
.pe-sched-table th:first-child { width: 132px; }         /* time col identical everywhere */
.pe-sched-table--list { table-layout: auto; }
.pe-sched-table--list th:first-child { width: auto; }
.pe-sched-card--armed { outline: none; border-color: var(--accent); background: var(--accent-light, #eff6ff); box-shadow: 0 0 0 1px var(--accent); }
/* the match list reads like the app's tables: faint row borders, no column
   borders, quiet uppercase headers */
.pe-sched-scroll--list { border: none; border-radius: 0; background: none; overflow: visible auto; }
.pe-sched-table--list th, .pe-sched-table--list td { border: none; border-bottom: 1px solid var(--line); padding: 0.45rem 0.6rem; text-align: left; }
.pe-sched-table--list th { background: none; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-3); }
.pe-sched-table--list td { font-size: 0.8rem; }
.pe-sched-refsel { border: 1px solid var(--line); border-radius: 6px; padding: 0.2rem 0.3rem; font-size: 0.78rem; background: var(--surface); max-width: 160px; }
.pe-sched-durcell { text-decoration: underline dotted; cursor: help; }

/* Gate-1 round 7: list back in its card, left-opening row menus, click "i" */
.pe-sched-scroll--list { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden auto; }
.pe-sched-table--list th { background: var(--surface-2); }
.pe-menu__list--left { left: auto; right: 0; }
.pe-tooltip--pre { white-space: pre-line; width: 230px; }
.pe-sched-durcell { text-decoration: none; cursor: default; }

/* mockup polish: gap rows + hatched not-available cells */
.pe-sched-gaprow td { background: var(--surface-2); color: var(--ink-3); font-size: 0.68rem; font-style: italic; padding: 0.2rem 0.6rem; border: 1px solid var(--line); }
.pe-sched-cell--na {
  background: repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 6px, var(--bg-2) 6px, var(--bg-2) 12px);
}
.pe-sched-na { color: var(--ink-3); font-size: 0.68rem; font-style: italic; }
.pe-sched-listbar { margin-bottom: 0.5rem; font-size: 0.8rem; font-weight: 600; color: var(--ink-2); }
.pe-sched-listbar select { border: 1px solid var(--line); border-radius: 6px; padding: 0.25rem 0.4rem; font-size: 0.8rem; background: var(--surface); margin-left: 0.35rem; }
.pe-sched-th--sort { cursor: pointer; user-select: none; }
.pe-sched-th--sort:hover { color: var(--ink); }
.pe-sched-note { border: 1px solid var(--line); border-radius: 6px; padding: 0.2rem 0.4rem; font-size: 0.78rem; width: 130px; background: var(--surface); }
.pe-sched-bosel { max-width: 110px; }

/* §19.3 Bulk Schedule modal */
.pe-sched-modal__box--wide { width: min(760px, 94vw); }
.pe-bulk-sec { font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-2); }
.pe-bulk-note { font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--ink-3); }
.pe-bulk-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.pe-bulk-table { width: 100%; border-collapse: collapse; }
.pe-bulk-table td { border-top: 1px solid var(--line); padding: 0.5rem 0.4rem; vertical-align: top; }
.pe-bulk-fac { width: 200px; font-size: 0.8rem; font-weight: 700; }
.pe-bulk-fac .pe-bulk-chips { margin-top: 0.35rem; }
.pe-bulk-free { font-weight: 500; color: var(--ink-3); font-size: 0.68rem; }
.pe-pill--dead { opacity: 0.45; cursor: not-allowed; }
.pe-bulk-foot { align-items: center; }
.pe-bulk-summary { margin-right: auto; font-size: 0.78rem; color: var(--ink-2); }
.pe-bulk-summary--short { color: var(--warning, #b45309); font-weight: 600; }

/* bulk modal styling pass: quiet list-style headers, aligned cells,
   clickable cell space */
.pe-bulk-th { text-align: left; padding: 0.35rem 0.4rem; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-3); border-bottom: 1px solid var(--line); background: none; font-weight: 700; }
.pe-bulk-table td { cursor: pointer; }
.pe-bulk-table td:hover { background: var(--bg-2); }
.pe-bulk-fname { margin-bottom: 0.35rem; }
.pe-bulk-bands { padding: 0.5rem 0.4rem; }
.pe-bulk-fac { border-right: 1px solid var(--line); }
/* menu items: neutral by default; only destructive actions read as danger */
.pe-menu__list button { color: var(--ink-2); }
.pe-menu__list button[data-facdel], .pe-menu__list button[data-un] { color: var(--danger, #ef4444); }

/* ── Playoff page read-only viewer (playoff_viewer_controller) ─────────────
   Reuses the editor's pe- components wholesale; only page chrome is new. */
.pv-controls { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 0.75rem 0.9rem; margin-bottom: 1rem; }
.pv-controls .pv-bar:last-child { margin-bottom: 0; }
.pv-bar { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.pv-right { margin-left: auto; }
/* view-only cards: no drag affordance on this page */
.pv .pe-sched-card { cursor: default; }
/* the page's own grey background clashes with grey content fills (Kyle):
   canvases go white (full height — no modal to fit), the timetable runs on
   the header grey throughout so match cards stand out, and date/gap/group
   rows match the header tone instead of the darker bg-2 */
.pv .pe-bk-canvas { background-color: var(--surface); max-height: none; }
.pv-link { background: none; border: none; color: var(--accent); font-size: 0.82rem; font-weight: 700; cursor: pointer; padding: 0.2rem 0.3rem; }
.pv-group { font-size: 0.82rem; font-weight: 600; color: var(--ink-3); display: inline-flex; align-items: center; gap: 0.4rem; margin-left: auto; }
.pv-group select { font-size: 0.82rem; padding: 0.25rem 0.4rem; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); color: var(--ink-2); }
.pv-note { color: var(--ink-3); font-size: 0.85rem; padding: 1rem 0; }

/* ── §21.3 live cards: chips, score boxes, series (read layer) ─────────── */
.pv-chip { margin-left: auto; font-size: 0.6rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.1rem 0.45rem; border-radius: var(--r-pill); white-space: nowrap; }
.pv-chip--unsched, .pv-chip--sched { background: var(--bg-2); color: var(--ink-3); }
.pv-chip--live { background: var(--warning-soft); color: var(--warning); }
.pv-chip--unof { background: var(--accent-light); color: var(--accent); }
.pv-chip--fin { background: var(--success-soft); color: var(--success); }
.pv-chip--notneeded { background: var(--bg-2); color: var(--ink-3); }
.pv-card--na { opacity: 0.55; }
.pv-meta { color: var(--ink-3); font-size: 0.68rem; margin-top: 0.1rem; }
.pv-cardhr { border-bottom: 1px solid var(--line-2); margin: 0.35rem -0.5rem 0.1rem; }
.pv-grid { display: grid; grid-template-columns: minmax(0, 1fr) repeat(var(--pvg, 3), 30px) 26px; gap: 2px 4px; align-items: center; margin-top: 0.3rem; }
.pv-gh { font-size: 0.6rem; color: var(--ink-3); font-weight: 700; text-align: center; }
.pv-sc { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 20px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); font-size: 0.72rem; }
.pv-sc--w { color: var(--success); font-weight: 800; }
/* a conflict must not be signalled by colour alone (WCAG 1.4.1): the border
   also thickens, and the input's aria-label says so for screen readers.
   Dashed is already taken — that's the "fun game" remainder. */
.pv-sc--conf { border-color: var(--warning); border-width: 2px; }
.pv-sc--lock { border-color: transparent; background: none; font-weight: 600; }
/* --fun: the unplayed remainder of a series decided on ENTERED scores. Grey,
   but still editable ("just for fun") — dashed is what separates it from
   --off below, which looks similar and behaves the opposite way. */
.pv-sc--fun { background: var(--surface-2); border-style: dashed; color: var(--ink-3); }
/* --off: the box exists but cannot be scored yet (E3 — an unresolved side, or
   a seed slot on an unlocked playoff). Same frame, very light fill, so it
   reads as "not yet" rather than as an empty editable box. */
.pv-sc--off {
  background: var(--bg-2);
  border-color: var(--line-2);
  color: var(--ink-4);
  cursor: not-allowed;
  opacity: 1;                 /* Safari fades disabled inputs on its own */
  -webkit-text-fill-color: var(--ink-4);
}
.pv-series { font-weight: 800; text-align: center; font-size: 0.8rem; }
.pv-series--w { color: var(--success); }
.pv-pin { color: var(--warning); font-size: 0.7rem; margin-left: 0.2rem; }
.pv-tstack { display: flex; flex-direction: column; gap: 0.25rem; }
.pv-gstack { display: inline-flex; flex-direction: column; gap: 0.25rem; align-items: center; }
/* bracket-canvas compact chips (the §21.3 exception) */
.pv-bkchips { margin-left: auto; display: inline-flex; gap: 3px; align-items: center; flex-shrink: 0; }
.pv-bkchip { font-size: 0.64rem; font-weight: 700; color: var(--ink-2); background: var(--surface-2); border-radius: 4px; padding: 0.06rem 0.28rem; }
.pv-bkchip--w { color: var(--success); font-weight: 800; }
.pv-bkseries { font-size: 0.76rem; font-weight: 800; margin-left: 0.2rem; }
/* the match winner's tally reads green, like a winning game score */
.pv-bkseries--w { color: var(--success); }
.pv-unschedrow { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.pv-unschedrow .pe-sched-card { width: calc(300px + var(--pv-xgames, 0) * 34px); }

/* ── §21.1 interactive layer: kebabs, menus, the match modal ──────────── */
.pv-actions { position: relative; display: inline-flex; margin-left: 0.2rem; }
.pv-kebab { background: none; border: none; color: var(--ink-3); font-weight: 800; cursor: pointer; padding: 0 0.25rem; font-size: 0.85rem; }
.pv-menu { position: absolute; right: 0; top: calc(100% + 2px); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); box-shadow: var(--shadow-lg); min-width: 130px; padding: 0.2rem; z-index: 40; }
.pv-menu button { display: block; width: 100%; text-align: left; background: none; border: none; font: inherit; font-size: 0.8rem; font-weight: 600; color: var(--ink-2); padding: 0.4rem 0.6rem; border-radius: var(--r-sm); cursor: pointer; }
.pv-menu button:hover { background: var(--bg-2); }
.pv-modal-row { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.6rem; }
.pv-modal-col { display: flex; flex-direction: column; gap: 0.5rem; flex: 1; min-width: 180px; }
.pv-f { display: flex; flex-direction: column; gap: 0.15rem; font-size: 0.68rem; font-weight: 700; color: var(--ink-3); }
.pv-f input, .pv-f select { font-size: 0.85rem; padding: 0.35rem 0.5rem; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); color: var(--ink); }
.pv-f--grow { flex: 1.3; min-width: 220px; }
.pv-notes { width: 100%; min-height: 96px; font: inherit; font-size: 0.85rem; padding: 0.35rem 0.5rem; border: 1px solid var(--line); border-radius: var(--r-sm); resize: vertical; }
.pv-modal-games td, .pv-modal-games th { white-space: nowrap; }
.pv-modal-time { color: var(--ink-3); font-size: 0.74rem; }
.pv-badge { font-size: 0.62rem; font-weight: 700; padding: 0.1rem 0.4rem; border-radius: var(--r-pill); }
.pv-badge.badge--ok { background: var(--success-soft); color: var(--success); }
.pv-badge.badge--rev { background: var(--warning-soft); color: var(--warning); }
.pv-badge.badge--none { background: var(--bg-2); color: var(--ink-3); }
.pv-link { color: var(--accent); font-weight: 700; font-size: 0.74rem; text-decoration: none; margin-right: 0.4rem; }
.pv-modal-warn { color: var(--warning); font-size: 0.76rem; font-weight: 600; flex: 1; min-width: 0; }
/* inline-flex on a SPAN inside the cell — display:flex directly on the td
   broke table-cell rendering and left the row border jagged at this column */
.pv-modal-actions { display: inline-flex; align-items: center; gap: 0.3rem; vertical-align: middle; }

/* Action callouts: a state the organizer should act on (a draft playoff
   nobody can see; matches decided but not finalized, whose winners are
   therefore still sitting in place). Accent-toned — this is a nudge, not an
   error — with the action inline. */
.callout--action {
  font-size: var(--text-sm);
  color: var(--ink-2);
  background: var(--accent-light);
  border-left: 3px solid var(--accent);
  padding: 0.6rem 0.9rem;
  border-radius: 0 6px 6px 0;
  margin-bottom: 1rem;
}
.callout--action summary { font-weight: 700; cursor: pointer; color: var(--ink); }
.callout--action .callout__body { margin: 0.4rem 0 0; }
.callout--action ul { margin: 0.4rem 0 0 1.1rem; }
.callout__row { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.callout__row > :first-child { flex: 1; min-width: 12rem; }
.callout__row form { margin: 0; }

/* Soft-state note (manual pins): recorded intent, not an alert — neutral grey,
   never the warning tone the scheduling banner uses. */
.callout--muted {
  font-size: var(--text-sm);
  background: var(--bg-2);
  border-left: 3px solid var(--ink-4);
  color: var(--ink-3);
  padding: 0.6rem 0.9rem;
  border-radius: 0 6px 6px 0;
  margin-bottom: 1rem;
}
.callout--muted summary { font-weight: 700; cursor: pointer; }
.callout--muted ul { margin: 0.5rem 0 0 1.1rem; }

/* ── Q14 Final Placements panels ──────────────────────────────────────── */
.pf-results { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.pf-results__card { flex: 1; min-width: 340px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.pf-results__head { display: flex; align-items: center; gap: 0.45rem; padding: 0.55rem 0.8rem; border-bottom: 1px solid var(--line-2); background: var(--surface-2); font-size: 0.82rem; }
.pf-results__table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.pf-results__table td { padding: 0.4rem 0.8rem; border-bottom: 1px solid var(--line-2); }
.pf-results__table tr:last-child td { border-bottom: none; }
.pf-results__rank { font-weight: 800; width: 2.6rem; }
.pf-results__stat { color: var(--ink-2); white-space: nowrap; text-align: right; }
.pf-results__stat span { color: var(--ink-3); font-size: 0.68rem; }

/* ── Playoff page header: status pipeline + actions menu (v1.56) ───────── */
.pf-flow { display: inline-flex; align-items: center; }
.pf-flow__stage { font-size: 0.7rem; font-weight: 700; padding: 0.18rem 0.6rem; border-radius: var(--r-pill); background: var(--bg-2); color: var(--ink-3); white-space: nowrap; }
.pf-flow__stage--done { background: var(--accent-light); color: var(--accent); }
.pf-flow__stage--on { background: var(--accent); color: #fff; }
.pf-flow__line { width: 14px; height: 1px; background: var(--line); }
.pf-flow + .pf-flow__stage { margin-left: 0.35rem; }
.pf-actions { position: relative; display: inline-flex; }
.pf-actions__btn { font-weight: 800; padding: 0.4rem 0.75rem; }
.pf-actions__menu { display: none; position: absolute; right: 0; top: calc(100% + 4px); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); box-shadow: var(--shadow-lg); min-width: 170px; padding: 0.25rem; z-index: 40; }
.pf-actions__menu.is-open { display: block; }
.pf-actions__menu form { display: block; }
.pf-actions__item { display: block; width: 100%; text-align: left; background: none; border: none; font: inherit; font-size: 0.85rem; font-weight: 600; color: var(--ink-2); padding: 0.45rem 0.7rem; border-radius: var(--r-sm); cursor: pointer; }
.pf-actions__item:hover { background: var(--bg-2); }
.pf-actions__item--danger { color: var(--danger, #ef4444); }

/* ── §21 round 8 (Kyle feedback): unbolded meta lines, always-on divider,
   the score-save entry UX on every surface, live bracket cards, list
   breathing room ───────────────────────────────────────────────────────── */
/* the card base is bold (drag chips); page cards read like the mockup —
   normal weight, only the L1 title line bold */
.pv .pe-sched-card { font-weight: 400; }
.pv .pe-sched-card .pe-sched-card__l1 { font-weight: 700; }

/* score inputs share .pv-sc with the read-only spans; input specifics match
   .game-cell__input (number field, no spinners, warning border when dirty) */
input.pv-sc { font: inherit; font-size: 0.72rem; text-align: center; padding: 0; -moz-appearance: textfield; appearance: textfield; }
input.pv-sc::-webkit-outer-spin-button, input.pv-sc::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input.pv-sc:focus { outline: none; border-color: var(--accent); box-shadow: var(--focus-ring); }
/* Dirty (typed, unsaved) was amber — the same colour as a submissions
   CONFLICT, and it won on !important, so "I typed something" and "the
   submissions disagree" were indistinguishable on the one surface where both
   occur. Unsaved edits take the accent here; amber stays the data problem.
   (The HQ schedule page keeps amber-dirty: it renders no conflict state, so
   nothing is ambiguous there.) */
.pv-sc--dirty { border-color: var(--accent) !important; box-shadow: 0 0 0 1px var(--accent); }
.pv-savebtn { justify-self: center; margin-top: 2px; }

/* Group by + Show details sit on one center line, label left of the toggle */
.pe-sched-listbar { display: flex; align-items: center; }

/* the list gets real column room: locations wrap on a sane width and the
   table scrolls sideways instead of crushing (and hiding the ⋮ column) */
.pv .pe-sched-scroll--list { overflow: auto; }
.pv-loccell { min-width: 10.5rem; }
/* Date and Time read as single lines; the list table scrolls sideways in its
   own container, so width goes to scroll, never to four-line wraps */
.pv-datecell, .pv-timecell { white-space: nowrap; }

/* The TIMETABLE needed the same treatment (Kyle, 390px phone): its container
   carried the editor's `overflow: hidden auto` — "every slot visible and
   droppable", which is right for a drag grid and wrong for a read surface —
   while the fixed-layout table squeezed four courts into ~60px each and the
   cards wrapped one word per line. On the viewer, columns get a floor and the
   table scrolls horizontally inside its own container, which is what §21.6
   specifies for phones. The editor keeps its no-inner-scroll drag grid.
   --pv-cols is stamped by the renderer; the calc keeps the minimum width
   deterministic instead of leaning on max-content table sizing, which is
   exactly where Safari has bitten this codebase before. */
.pv .pe-sched-scroll:not(.pe-sched-scroll--list) { overflow: auto; }
.pv .pe-sched-table:not(.pe-sched-table--list) {
  /* The court column also follows the widest series in its table: each game
     past a Bo3 adds a fixed-width score box to both card rows (--pv-xgames,
     stamped by the renderer; --pv-game-step = box width + grid gap), so a
     fixed column floor left Bo4/Bo5 grids painting outside their cards. Same
     rule the bracket canvas applies to its card width. */
  --pv-court-col: calc(var(--pv-court-base, 190px) + var(--pv-xgames, 0) * var(--pv-game-step, 34px));
  min-width: calc(var(--pv-time-col, 132px) + (var(--pv-cols, 1) * var(--pv-court-col)));
}
.pv .pe-sched-table:not(.pe-sched-table--list) th:not(:first-child) { width: var(--pv-court-col); }
.pv .pe-sched-table:not(.pe-sched-table--list) th:first-child { width: var(--pv-time-col, 132px); }
/* cards fill their column instead of holding a desktop width */
.pv .pe-sched-cell .pe-sched-card { width: auto; }

/* Meta lines truncate rather than wrap — the mockup's own rendering
   ("Senator O'Conn… (Court 1)"). A long facility name was growing the card to
   eight lines of one word each. */
.pv .pe-sched-card .pv-meta {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 640px) {
  /* a narrower time column buys the cards ~40px each without losing the range;
     the game step matches the mobile score boxes (40px + 4px grid gap). The
     base is BUDGETED, not eyeballed (Kyle, 390px, twice): name floor 120
     + Bo3 boxes 120 + series 28 + grid gaps 16 + card padding 16 + cell
     padding 10 = 310. Under-budgeting shows up as the series digits spilling
     past the card edge the moment the name floor engages. */
  .pv .pe-sched-table:not(.pe-sched-table--list) { --pv-time-col: 92px; --pv-court-base: 310px; --pv-game-step: 44px; }
  .pv .pe-sched-time { font-size: 0.68rem; }
  /* the identity line has to fit: the round name is redundant here (the
     Bracket view names it, and the match number carries the identity) */
  .pv .pe-sched-cell .pe-sched-round { display: none; }
  .pv .pe-sched-cell .pe-sched-card__l1 { gap: 0.25rem; }
  .pv .pe-sched-cell .pe-sched-card__l1 strong { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

/* bracket canvas live cards: the status chip + ⋮ live INSIDE the card on its
   header row, beside the schedule text (Kyle) — above the card they read as
   floating annotations rather than part of the match. The header is a row
   with the schedule text stacked on the left and the controls pinned right. */
/* the editor's cards keep the same header — one stacked text block, now in a
   row that simply has no second child */
.bm__meta { flex-direction: row; align-items: center; justify-content: flex-start; gap: 0.35rem; }
.bm__meta-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.bm__metax { margin-left: auto; display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }
.bm__metax .pv-chip { margin-left: 0; font-size: 0.55rem; padding: 0.05rem 0.35rem; }
.bm__metax .pv-kebab { padding: 0 0.15rem; font-size: 0.85rem; line-height: 1; }
/* The ⋮ menu has to escape the card, which clips (overflow: hidden) to keep
   its rounded corners. Dropping the clip means the header must round its own
   top corners, or it squares off over the card's radius. */
.bm .bm__card { overflow: visible; }
.bm .bm__meta { border-radius: var(--r-md) var(--r-md) 0 0; }
.bm__metax .pv-actions { position: static; }
.bm__metax .pv-menu { right: 4px; top: 30px; z-index: 60; }
/* sized for the wider card — enough to read a two-digit score without the
   boxes crowding the team name */
.bm .pv-sc { width: 24px; height: 19px; font-size: 0.68rem; border-radius: 4px; }

/* G1…Gn column headers, sharing the side rows' right-aligned geometry so the
   labels sit over their own boxes */
.bm__ghead { display: flex; padding: 2px 8px 0; }
.pv-bkgh { width: 24px; text-align: center; font-size: 0.56rem; font-weight: 700;
           color: var(--ink-3); letter-spacing: 0.02em; }
/* the trailing series column keeps a stable width in all three rows, or the
   headers and Save buttons drift out of line with the boxes */
.pv-bkseries { min-width: 12px; text-align: center; }

/* Save floats UNDER the card in its game's column: the row is absolutely
   positioned, so showing a button never resizes the card or nudges the
   scores above it (Kyle). Each slot matches a box's width; the button is
   centred on the slot and allowed to overflow it. */
.bm__below { position: absolute; left: 0; right: 0; top: 100%; padding: 3px 8px 0; display: flex; }
.pv-bksave { width: 24px; position: relative; }
.bm .pv-savebtn {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  padding: 2px 7px;
  font-size: 0.6rem;
  white-space: nowrap;
}

/* modal polish: labels left-aligned over their fields (the generic modal
   label rule centers), Location beside Facility and wider */
.pe-sched-modal__body label.pv-f { align-items: flex-start; text-align: left; }
.pv-f--fac { flex: 1; min-width: 200px; }
.pv-f--loc { flex: 1.3; min-width: 180px; }
.pv-f--fac select, .pv-f--loc select { width: 100%; }
/* §21.2 participant pins: full-width select + the derivation hint under it */
.pv-f--pin { flex: 1; min-width: 240px; }
.pv-f--pin select { width: 100%; }
.pv-fhint { font-size: 0.66rem; font-weight: 600; color: var(--ink-3); }
.pv-fhint--pin { color: var(--warning); }
.pv-modal-savecell { min-width: 52px; }

/* ── §10/§21.6 — the readonly viewer on the spectator surfaces (Go league
   site, public website). Same component set; the page around it is narrower
   and has no app chrome, so the controls card loses its heavy framing. ──── */
.pv-public .pv-controls { padding: 0.6rem 0.7rem; }
.pv-public .pe-bk-canvas { background-color: var(--surface); }
.pv-public .pv-controls .pv-bar:last-child { margin-bottom: 0; }

/* ── §21.6 mobile pass. The three views are horizontal-scroll-safe by
   construction (timetable and list scroll in their own containers, the
   bracket canvas pans); what phones need is chrome that wraps, tap targets
   that can be hit, and score boxes big enough to type into. Nothing here
   positions against a table row — the iOS Safari rule.  ─────────────────── */
@media (max-width: 640px) {
  .pv-controls { padding: 0.5rem 0.6rem; }
  .pv-bar { gap: 0.3rem; margin-bottom: 0.4rem; }

  /* No mobile height overrides on the pills or view toggle (Kyle, epic 0044
     round 12, superseding the earlier 34px floor): they render at their
     natural desktop height everywhere — in portrait the rows wrap, so every
     extra pixel of control height multiplies into chrome. The controls that
     take typing (score boxes below) keep their 40px/16px tap targets. */
  .pv-kebab { min-width: 40px; min-height: 40px; font-size: 1rem; }
  .pv-menu button { padding: 0.6rem 0.7rem; }
  .pv-group { margin-left: 0; }
  .pv-group select { min-height: 40px; }

  /* Score entry: 16px keeps iOS from zooming the page on focus, and the box
     grows with it. The grid column width follows so nothing overlaps. */
  /* the name track has a floor — it must never collapse to zero and let the
     G-columns occupy its place (the column widths above budget for it) */
  .pv-grid { grid-template-columns: minmax(120px, 1fr) repeat(var(--pvg, 3), 40px) 28px; }
  .pv-sc { width: 40px; height: 32px; font-size: 0.85rem; }
  input.pv-sc { font-size: 16px; }
  .pv-savebtn { min-height: 32px; }

  /* cards go full width instead of holding a desktop min-width */
  .pv .pe-sched-card, .pv-public .pe-sched-card { font-size: 0.8rem; }
  .pv-unschedrow .pe-sched-card { width: 100%; }
  .pf-results__card { min-width: 0; }

  /* the shared match modal: full-bleed sheet, one field per row */
  .pe-sched-modal__box, .pe-sched-modal__box--wide { width: 96vw; max-height: 92vh; }
  .pe-sched-modal__body .pv-f,
  .pe-sched-modal__body .pv-f--grow,
  .pe-sched-modal__body .pv-f--fac,
  .pe-sched-modal__body .pv-f--loc,
  .pe-sched-modal__body .pv-f--pin { flex: 1 1 100%; min-width: 0; }
  .pe-sched-modal__body .pv-f input,
  .pe-sched-modal__body .pv-f select { font-size: 16px; min-height: 40px; }
  .pe-sched-modal__foot { flex-wrap: wrap; gap: 0.4rem; }
  .pe-sched-modal__foot .btn { min-height: 40px; }
}
