/* ---------------------------------------------------------------- base */
:root{
  --bg:#0d1411; --bg2:#131d19; --card:#16211c; --line:#25342c;
  --ink:#e8f2ec; --muted:#8ea79a; --accent:#3ddc84; --accent2:#38bdf8;
  --home:#3ddc84; --away:#fbbf24;
  --goal:#22c55e; --saved:#38bdf8; --blocked:#a78bfa; --post:#f472b6; --off:#94a3b8;
  --danger:#ef4444;
  --r:14px;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--bg); color:var(--ink);
  font:15px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  -webkit-text-size-adjust:100%; padding-bottom:40px;
  -webkit-tap-highlight-color:transparent;
}
h1,h2,h3{margin:0 0 10px}
h1{font-size:24px} h2{font-size:19px} h3{font-size:15px;letter-spacing:.02em}
.muted{color:var(--muted)} .small{font-size:12.5px} .strong{font-weight:700}
.hidden{display:none !important}
code{background:#0b120f;padding:1px 5px;border-radius:5px;font-size:12px}

/* -------------------------------------------------------------- topbar */
#topbar{
  position:sticky; top:0; z-index:30; background:rgba(13,20,17,.94);
  backdrop-filter:blur(8px); border-bottom:1px solid var(--line);
  display:flex; align-items:center; flex-wrap:nowrap; gap:12px; padding:6px 14px;
  padding-top:calc(6px + env(safe-area-inset-top));
}
/* The tabs always win the space; the brand gives way, then disappears. */
.brand{display:flex; align-items:center; gap:6px; min-width:0; flex:0 1 auto;
  font-weight:800; letter-spacing:-.01em; overflow:hidden}
.brand-mark{flex:none}
.brand-name{white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.tabs{display:flex; gap:6px; margin-left:auto; flex:0 0 auto; flex-wrap:nowrap}
/* Thinner pills, mostly vertically: the height of this bar is stolen from the
   pitch on every page. 34px of tappable height is still comfortably past the
   ~30px a thumb needs, and the horizontal padding stays generous so the pill
   still reads as a pill rather than bare text. */
.tab{
  color:var(--muted); text-decoration:none; font-weight:600; font-size:13.5px;
  padding:4px 12px; border-radius:999px; border:1px solid transparent;
  white-space:nowrap; line-height:1.5;
}
.tab.active{color:#06120c; background:var(--accent); border-color:var(--accent)}
.lbl-short{display:none}

.view{display:none; max-width:1100px; margin:0 auto; padding:14px}
.view.on{display:block}

/* --------------------------------------------------------------- bits */
.btn{
  font:inherit; font-weight:700; border-radius:10px; border:1px solid var(--line);
  background:var(--bg2); color:var(--ink); padding:10px 14px; cursor:pointer;
}
.btn:active{transform:translateY(1px)}
.btn-go{background:var(--accent); color:#06120c; border-color:var(--accent)}
.btn-stop{background:#ef4444; color:#fff; border-color:#ef4444}
.btn-ghost{background:transparent}
.btn.small{padding:6px 10px; font-size:12.5px}
.btn .ico{margin-right:4px}
.linkbtn{background:none;border:0;color:var(--muted);font:inherit;font-size:12.5px;
  text-decoration:underline;cursor:pointer;padding:4px 2px}
.linkbtn.danger{color:#f87171}
.iconbtn{background:none;border:0;color:var(--muted);font-size:15px;cursor:pointer;padding:4px 7px;border-radius:8px}
.iconbtn.danger:hover{color:#fff;background:var(--danger)}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:14px;margin-bottom:14px}
.pill{margin-left:auto;font-size:12px;color:var(--muted);background:var(--bg2);
  border:1px solid var(--line);border-radius:999px;padding:3px 10px}
.empty{color:var(--muted);font-style:italic;padding:10px 2px;font-size:13.5px}
.hint{color:var(--muted);font-size:13px;margin:6px 2px 10px;text-align:center}
.hint.tight{margin:8px 0 6px}

/* inline-grid with 1fr columns: every segment is the same width AND as wide as
   the longest label, so the divider sits dead centre and nothing wraps. Flex
   couldn't do both at once — equal widths forced the labels onto two lines. */
.seg{display:inline-grid;grid-auto-flow:column;grid-auto-columns:1fr;align-items:stretch;
  background:var(--bg2);border:1px solid var(--line);border-radius:11px;padding:3px;gap:3px}
.seg.wide{display:grid;width:100%;margin-bottom:12px}
/* min-width:0 is what actually makes flex:1 split the row evenly — without it a
   longer label claims more space and the divider sits off-centre. Labels wrap
   rather than shrink the button, so both halves always match. */
.seg-btn{min-width:0;display:flex;align-items:center;justify-content:center;
  text-align:center;font:inherit;font-weight:700;font-size:13.5px;border:0;border-radius:8px;
  background:transparent;color:#c3d5cb;padding:10px 12px;cursor:pointer;
  white-space:normal;line-height:1.2;overflow-wrap:break-word}
.seg-btn:not(.active):hover{color:var(--ink)}
.seg-btn.active{background:var(--accent);color:#06120c}
#team-seg .seg-btn[data-team="away"].active{background:var(--away);color:#231a00}

/* --------------------------------------------------------- scoreboard */
.scoreboard{display:grid;grid-template-columns:1fr auto 1fr;gap:10px;align-items:start;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:12px;margin-bottom:12px}
.score-team{text-align:center;min-width:0;overflow:hidden}
.st-name{font-size:12.5px;color:var(--muted);font-weight:700}
.st-goals{font-size:38px;font-weight:800;line-height:1.05}
#sb-home .st-goals{color:var(--home)} #sb-away .st-goals{color:var(--away)}
.clock-block{text-align:center;padding-top:2px}
.clock{font:inherit;font-size:30px;font-weight:800;font-variant-numeric:tabular-nums;
  letter-spacing:.01em;background:none;border:0;color:var(--ink);padding:0 4px;cursor:pointer;
  border-bottom:1px dashed transparent}
.clock:hover{border-bottom-color:var(--line)}
body.clock-running .clock{color:var(--accent)}
.clock-controls{display:flex;gap:6px;justify-content:center;margin-top:6px}
/* A native select left-aligns its text and reserves room for the system arrow,
   so it can never be truly centred. Draw the label ourselves, centred with the
   chevron as one group, and lay the real select over it, invisible, to handle
   the tap and the picker. */
.period-wrap{position:relative;display:inline-flex;align-items:center;justify-content:center;
  gap:7px;background:var(--bg2);border:1px solid var(--line);border-radius:10px;
  padding:12px 16px;min-width:118px;cursor:pointer}
.period-wrap:focus-within{border-color:var(--accent)}
.period-label{font-size:15px;font-weight:800;color:var(--ink);white-space:nowrap}
.period-chev{width:11px;height:7px;flex:none;fill:none;stroke:var(--muted);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.period{position:absolute;inset:-1px;opacity:0;cursor:pointer;   /* -1px covers the border */
  appearance:none;-webkit-appearance:none;border:0;font:inherit}

.controls{display:flex;gap:8px;flex-wrap:wrap;align-items:center;justify-content:center;
  margin-bottom:4px}
#btn-undo{white-space:nowrap}
/* Undo becomes Redo after it fires: the same button, but plainly a different one
   to press, so nobody taps it twice expecting two shots to come off. */
.btn.is-redo{border-color:var(--accent);color:var(--accent);background:rgba(61,220,132,.10)}

/* -------------------------------------------------------------- pitch */
.svg-host{display:block;width:100%}
.pitch-svg{display:block;width:100%;height:auto;margin:0 auto}
.pitch-svg[data-mode="full"]{max-width:min(100%,46vh)}
.turf{fill:#123020}
.stripe{fill:#14361f;opacity:.55}
.ln{fill:none;stroke:rgba(255,255,255,.62);stroke-width:.28}
.dot{fill:rgba(255,255,255,.72)}
.goalbox{fill:rgba(255,255,255,.14);stroke:rgba(255,255,255,.7);stroke-width:.24}
.pitch-tag{fill:rgba(255,255,255,.42);font-size:1.9px;letter-spacing:.5px;text-anchor:middle}
.pitch-svg{cursor:crosshair}
/* The opponent's pitch is a cooler, lighter green — different enough to notice
   at a glance without leaving the colour of grass. The name on the pitch is the
   cue that actually matters; this just backs it up. */
.pitch-svg.team-away .turf{fill:#173f35}
.pitch-svg.team-away .stripe{fill:#1b4a3d}

/* markers */
.mk circle{stroke:#0b120f;stroke-width:.22;opacity:.8}
/* stacked shots read as a denser blob rather than hiding one another */
.mk-dim{opacity:.3}
/* the other team, mirrored onto their own half — present but clearly secondary */
.mk-other circle{opacity:.55;stroke-dasharray:.5 .35}
.mk-other text{opacity:.75}
.mk-hot circle{opacity:1;stroke:#fff;stroke-width:.34}
.mk-halo{fill:none;stroke:#fff;stroke-width:.3;opacity:.85}
.goal-svg .mk-hot circle{stroke-width:.06}
.goal-svg .mk-halo{stroke-width:.055}
/* never let a plotted shot swallow a tap meant for the pitch underneath */
#pitch-host .mk,.sheet-pitch .mk{pointer-events:none}
.mk text{fill:#08110c;text-anchor:middle;font-weight:800;paint-order:stroke}
.mk-goal circle{fill:var(--goal)} .mk-saved circle{fill:var(--saved)}
.mk-blocked circle{fill:var(--blocked)} .mk-post circle{fill:var(--post)}
.mk-off circle{fill:var(--off)}

/* ---------------------------------------------------------- goal mouth */
.goal-svg{display:block;width:100%;height:auto;max-height:40vh;cursor:crosshair}
.miss-zone{fill:#0f1a15}
.ground{fill:#123020}
.goalline{stroke:rgba(255,255,255,.6);stroke-width:.05}
.net{fill:rgba(255,255,255,.06)}
.mesh{stroke:rgba(255,255,255,.16);stroke-width:.02}
.guide{stroke:rgba(255,255,255,.22);stroke-width:.03;stroke-dasharray:.12 .12}
.frame{fill:none;stroke:#f4f7f5;stroke-width:.13;stroke-linecap:square}
.goal-tag{fill:rgba(255,255,255,.35);font-size:.28px}
.place-mark{fill:#fff;stroke:#0b120f;stroke-width:.05}

/* --------------------------------------------------------------- flow */
.flow{position:fixed;inset:0;z-index:60;background:rgba(4,8,6,.72);
  display:flex;align-items:flex-end;justify-content:center}
.flow-sheet{background:var(--card);border:1px solid var(--line);
  border-radius:18px 18px 0 0;width:100%;max-width:640px;max-height:94vh;
  display:flex;flex-direction:column;padding:14px;
  padding-bottom:calc(14px + env(safe-area-inset-bottom));
  box-shadow:0 -18px 50px rgba(0,0,0,.55)}
.flow-head{display:flex;align-items:flex-start;gap:10px;margin-bottom:12px}
.flow-step{font-size:11.5px;color:var(--muted);font-weight:700;letter-spacing:.06em;text-transform:uppercase}
.flow-title{font-size:20px;font-weight:800}
.flow-meta{margin-left:auto;display:flex;align-items:center;gap:6px}
.badge{display:inline-flex;align-items:center;gap:5px;background:var(--bg2);
  border:1px solid var(--line);border-radius:999px;padding:4px 10px;font-size:12px;
  font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;max-width:100%}
.badge .crest{width:15px;height:15px;flex:none}
.badge .badge-txt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.badge.team-home{color:var(--home);border-color:rgba(61,220,132,.4);
  background:rgba(61,220,132,.10)}
.badge.team-away{color:var(--away);border-color:rgba(251,191,36,.4);
  background:rgba(251,191,36,.10)}
.flow-body{overflow-y:auto;-webkit-overflow-scrolling:touch;flex:1}
.flow-foot{display:flex;align-items:center;gap:10px;margin-top:12px;padding-top:10px;border-top:1px solid var(--line)}
.crumbs{margin-left:auto;display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--muted);flex-wrap:wrap}
.crumb.on{color:var(--accent)} .crumb.cur{color:var(--ink);font-weight:700}
.crumb-sep{opacity:.4}

.numgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(78px,1fr));gap:8px}
.wide-note{grid-column:1/-1}
.numbtn{background:var(--bg2);border:1px solid var(--line);border-radius:12px;
  padding:10px 6px;cursor:pointer;color:var(--ink);font:inherit;display:flex;
  flex-direction:column;align-items:center;gap:2px;min-height:64px;justify-content:center}
.numbtn:active{background:var(--accent);color:#06120c}
.numbtn .n{font-size:22px;font-weight:800;line-height:1}
.numbtn .nm{font-size:10.5px;color:var(--muted);text-align:center;line-height:1.15;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.numbtn:active .nm{color:#06120c}
.numbtn.other{border-style:dashed}

.typegrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}
.typebtn{background:var(--bg2);border:1px solid var(--line);border-radius:12px;color:var(--ink);
  font:inherit;font-weight:700;padding:16px 10px;cursor:pointer}
.typebtn:active{background:var(--accent);color:#06120c}

.outcomes{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:7px;margin-top:4px}
.ocbtn{font:inherit;font-weight:800;font-size:13px;border-radius:11px;padding:13px 6px;cursor:pointer;
  border:1px solid var(--line);background:var(--bg2);color:var(--muted)}
.ocbtn:disabled{opacity:.35;cursor:not-allowed}
.ocbtn:not(:disabled).oc-goal{color:var(--goal);border-color:var(--goal)}
.ocbtn:not(:disabled).oc-saved{color:var(--saved);border-color:var(--saved)}
.ocbtn:not(:disabled).oc-blocked{color:var(--blocked);border-color:var(--blocked)}
.ocbtn:not(:disabled).oc-post{color:var(--post);border-color:var(--post)}
.ocbtn:not(:disabled).oc-off{color:var(--off);border-color:var(--off)}
.ocbtn.suggest{box-shadow:0 0 0 2px rgba(61,220,132,.28)}
.goal-host{background:#0b1310;border:1px solid var(--line);border-radius:12px;padding:4px}

/* --------------------------------------------------- edit a logged shot */
.editlist{list-style:none;margin:0 0 14px;padding:0}
.editlist li{display:flex;align-items:center;gap:10px;padding:13px 4px;
  border-bottom:1px solid var(--line);cursor:pointer}
.editlist li:active{background:var(--bg2)}
.el-label{color:var(--muted);font-size:12.5px;min-width:88px;flex:none}
.el-value{flex:1;font-weight:700;min-width:0}
.el-go{color:var(--muted);font-size:18px;flex:none}
.editactions{display:flex;gap:8px;flex-wrap:wrap}
.editactions .btn{flex:1;min-width:140px}
.danger-btn{color:#f87171;border-color:#5b2020}
.btn.wide{width:100%;margin-top:4px}
.numbtn.picked,.typebtn.picked{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.ocbtn.picked{box-shadow:inset 0 0 0 2px currentColor}
.sheet-pitch{background:#0b1310;border:1px solid var(--line);border-radius:12px;padding:6px}
.sheet-pitch .pitch-svg{max-width:min(100%,38vh);margin:0 auto}
.timeedit{display:flex;gap:8px;align-items:center;margin-bottom:10px}
.time-input{flex:1;min-width:0;font:inherit;font-size:28px;font-weight:800;text-align:center;
  font-variant-numeric:tabular-nums;background:var(--bg2);color:var(--ink);
  border:1px solid var(--line);border-radius:11px;padding:12px 8px}
.nudges{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.nudges .btn{padding:11px 4px;font-size:13px}
.presets{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px;margin-bottom:12px}
.presets .btn{padding:11px 6px;font-size:13px}
.tight-top{margin:12px 2px 6px}
.halflen{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted);
  margin-bottom:12px;flex-wrap:wrap}
.halflen input{width:72px;font:inherit;font-size:15px;font-weight:700;text-align:center;
  background:var(--bg2);color:var(--ink);border:1px solid var(--line);border-radius:9px;padding:8px}
/* On iOS a plain select opens the system wheel picker, which is exactly the control
   wanted here; elsewhere it's a normal dropdown. */
.wheelwrap{display:flex;justify-content:center;padding:6px 0 2px}
.numwheel{font:inherit;font-size:34px;font-weight:800;font-variant-numeric:tabular-nums;
  text-align:center;text-align-last:center;background:var(--bg2);color:var(--ink);
  border:1px solid var(--line);border-radius:14px;padding:16px 28px;min-width:160px}
.numwheel:focus{outline:0;border-color:var(--accent)}

/* end half / end game, spanning the scoreboard */
.match-actions{grid-column:1 / -1;display:flex;gap:8px;justify-content:center;
  margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}

/* running shots-per-team comparison on the tracker */
.tally{display:flex;flex-direction:column;gap:6px;margin:4px 0 12px}
/* One line per team, always: the club name gives way, the numbers never do. */
.tally-row{display:flex;align-items:center;gap:9px;flex-wrap:nowrap;font-size:12.5px;
  color:var(--muted);padding:7px 8px;border-radius:10px;background:var(--bg2);
  border:1px solid transparent;overflow:hidden}
.tally-row.current{border-color:var(--line)}
.tally-row .badge{margin-right:2px;min-width:0;flex:0 1 auto}
.tally-n{white-space:nowrap;flex:none;display:inline-flex;align-items:center;gap:3px}
.tally-n b{color:var(--ink);font-size:14px;font-weight:800}
/* Emoji render tall for their point size; hold them to the line's rhythm. */
.tally-n .ti{font-style:normal;font-size:12px;line-height:1}

/* the number chip on each log row, coloured like its dot on the pitch */
.rownum{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;
  border-radius:50%;font-size:11.5px;font-weight:800;color:#08110c;flex:none;
  background:var(--off)}
.rownum[data-oc="goal"]{background:var(--goal)}
.rownum[data-oc="saved"]{background:var(--saved)}
.rownum[data-oc="blocked"]{background:var(--blocked)}
.rownum[data-oc="post"]{background:var(--post)}
.rownum[data-oc="off"]{background:var(--off)}
/* The chip is filled by the outcome and ringed by the team, in the same green
   and amber the team pills and the pitch use — so whose shot it was reads from
   the left edge of the row without following the pill across it. A box-shadow
   rather than an outline: it is guaranteed to follow the circle everywhere. */
.rownum[data-team="home"]{box-shadow:0 0 0 1.5px var(--card),0 0 0 3.5px var(--home)}
.rownum[data-team="away"]{box-shadow:0 0 0 1.5px var(--card),0 0 0 3.5px var(--away)}

/* the key to those chips, sat above the shot list */
.legend-track{display:flex;flex-direction:column;align-items:flex-start;
  margin:2px 0 12px;gap:6px;font-size:10.5px}
.lg-row{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px}
/* All five outcomes belong on one line — split across two they stop reading as
   one scale. The short labels above are what buys the width. */
.lg-fill{flex-wrap:nowrap;gap:9px;max-width:100%;overflow-x:auto;scrollbar-width:none}
.lg-fill::-webkit-scrollbar{display:none}
.lg-fill .lg{white-space:nowrap}
/* the oldest small phones need a shade less of everything to hold the line */
@media (max-width:345px){
  .legend-track{font-size:9px}
  .lg-fill{gap:6px}
  .lg-fill .lg{gap:4px}
  .lg-fill .sw{width:8px;height:8px}
}
.legend-track .lg-lead{font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);opacity:.8}
/* a swatch drawn the way a chip is: filled by the outcome, ringed by the team */
.sw-ring{background:var(--bg2);margin-right:3px}
.sw-ring[data-team="home"]{box-shadow:0 0 0 1px var(--card),0 0 0 2.5px var(--home)}
.sw-ring[data-team="away"]{box-shadow:0 0 0 1px var(--card),0 0 0 2.5px var(--away)}

/* ------------------------------------------------- highlighted shot bar */
.hot-bar{display:flex;align-items:center;gap:8px;margin-top:8px;padding:8px 10px;
  background:var(--card);border:1px solid var(--accent);border-radius:12px;font-size:12.5px}
.hot-bar.hidden{display:none}
.hot-n{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;
  border-radius:50%;background:var(--accent);color:#06120c;font-weight:800;flex:none}
.hot-txt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.logrow.hot{background:rgba(61,220,132,.10);border-radius:8px}
.logrow.hot .who{color:var(--accent)}

/* --------------------------------------------------------------- log */
.log{list-style:none;margin:0;padding:0}
.logrow{display:flex;align-items:center;gap:8px;padding:8px 4px;border-bottom:1px solid var(--line);font-size:13px}
.logrow[data-edit]{cursor:pointer}
.logrow[data-edit]:active{background:var(--bg2)}
.logrow:last-child{border-bottom:0}
.logrow .t{font-variant-numeric:tabular-nums;color:var(--muted);min-width:70px;white-space:nowrap}
.logrow .who{font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.logrow .ty{color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.logrow .oc{margin-left:auto}
@media (max-width:620px){
  .logrow.arch{flex-wrap:wrap}
  /* Outcome pill sits on the top line so the shot type gets real width on the
     bottom one — squeezed into a leftover column it truncated to "Ri…". */
  /* No edit button on the row itself any more — the swipe carries it — so the
     club name gets that column back. */
  .logrow:not(.arch){display:grid;gap:4px 8px;align-items:center;
    grid-template-columns:auto minmax(0,1fr) auto;
    grid-template-areas:"time team oc" "who who ty"}
  .logrow .ty{text-align:right}
  /* every cell must be allowed to shrink, or a long club name in a pill pushes
     the outcome chip and the edit button off the screen */
  .logrow:not(.arch) > *{min-width:0}
  .logrow .t{grid-area:time} .logrow .badge{grid-area:team;justify-self:start}
  .logrow .who{grid-area:who} .logrow .ty{grid-area:ty;text-align:right}
  .logrow .oc{grid-area:oc;margin-left:0}
}
/* ---- a shot row you can swipe aside to delete ---- */
.swipe-row{position:relative;overflow:hidden;border-bottom:1px solid var(--line)}
.swipe-row:last-child{border-bottom:0}
/* The row rides over its own delete button, so it has to be opaque; a see-through
   highlight would show the red through the row itself. */
.swipe-row > .logrow{border-bottom:0;background:var(--card);position:relative;z-index:1;
  transition:transform .18s ease;touch-action:pan-y}
.swipe-row > .logrow.hot{background:#1a3426}
.swipe-row > .logrow.sliding{transition:none}      /* follow the finger, don't chase it */
.swipe-row.open > .logrow{transform:translateX(-124px)}
.row-actions{position:absolute;top:0;right:0;bottom:0;display:flex}
.row-act{width:62px;padding:0;border:0;color:#fff;cursor:pointer;
  display:flex;align-items:center;justify-content:center}
.row-act svg{width:21px;height:21px;fill:currentColor}
.row-act:active{filter:brightness(.85)}
/* grey for the reversible one, red for the one that isn't */
.row-edit{background:#3a4a42}
.row-del{background:var(--danger)}

/* ---- home on the left, away on the right ----
   Which side the chip sits on is the fastest read of whose shot it was, so the
   row keeps a chip-width margin at both ends and the chip takes one of them. */
/* Room for the chip plus a clear gap, so the time and the outcome pill stop
   running up against it at either end. */
.swipe-row > .logrow{padding-left:45px;padding-right:45px}
.swipe-row .rownum{position:absolute;top:50%;transform:translateY(-50%)}
/* 6px, not flush: the team ring stands 3.5px proud of the chip and the row clips
   whatever hangs over its edge. */
.swipe-row .logrow[data-side="home"] .rownum{left:6px}
.swipe-row .logrow[data-side="away"] .rownum{right:6px}

.oc{font-weight:800;font-size:11.5px;border-radius:999px;padding:3px 9px;white-space:nowrap;
  border:1px solid currentColor}
.oc-goal{color:var(--goal)} .oc-saved{color:var(--saved)} .oc-blocked{color:var(--blocked)}
.oc-post{color:var(--post)} .oc-off{color:var(--off)}
.recent{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:12px;margin-top:14px}

/* ------------------------------------------------------------- roster */
/* One team at a time — the tab at the top of the page picks which, and the
   line-up pitch below follows the same choice. */
.roster-grid{display:block}
.team-card{display:none}
.team-card.on{display:block}
/* The squad folds away so the pitch under it is a scroll away rather than a
   whole roster away. */
.collapse-btn{background:none;border:0;color:var(--muted);cursor:pointer;flex:none;
  padding:8px 6px;margin:-6px -4px -6px 0;border-radius:8px;
  display:inline-flex;align-items:center;justify-content:center}
.collapse-btn .chev{width:14px;height:9px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .15s}
.team-card.collapsed .collapse-btn .chev{transform:rotate(-90deg)}
.team-card.collapsed .card-body{display:none}
.team-card.collapsed .card-head{margin-bottom:0}
.card-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
/* Crests come in every shape — tall shields, wide ovals, circles. A fixed square
   box with object-fit:contain gives them all the same footprint so rows line up
   whatever the club. */
/* A default size matters: every other rule here is context-specific, so a crest
   in a context nobody styled — the stats table — rendered at its natural 128px.
   The context rules below out-specify this one. */
.crest{display:inline-block;object-fit:contain;vertical-align:middle;width:18px;height:18px}
.tbl .crest{width:18px;height:18px;margin-right:6px;flex:none}
.card-head .crest{width:36px;height:36px;flex:none}
.st-name .crest{width:26px;height:26px}
/* Wrap rather than truncate — a club name is worth two lines. min-width:0 on both
   the flex container and the text is what actually lets it shrink; flex items
   default to min-width:auto and will happily overflow the column instead. */
/* Fixed height, top-aligned: both crests land on the same line and both scores
   start at the same y, whether a club name runs to one line or two. */
.st-name{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:4px;line-height:1.2;height:62px;overflow:hidden;min-width:0;max-width:100%}
.st-text{min-width:0;max-width:100%;white-space:normal;overflow-wrap:break-word}
.finalscore .crest{width:30px;height:30px;flex:none}
.report-team h2 .crest{width:26px;height:26px;margin-right:8px}
.team-shots-head{margin:16px 0 8px}
.tbl-keeper{max-width:560px}
.keeper-hint{margin:14px 0 0}

/* a shot's note, tucked under its own row */
.note-row td{border-top:1px dashed var(--line);font-size:12.5px;color:var(--muted);
  padding:5px 8px 7px;white-space:normal}
.note-label{display:inline-block;font-size:10px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--accent);margin-right:7px}

/* the note field in the entry flow */
.note-input{width:100%;font:inherit;font-size:15px;background:var(--bg2);color:var(--ink);
  border:1px solid var(--line);border-radius:11px;padding:11px;resize:none}
.note-input:focus{outline:0;border-color:var(--accent)}
.note-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;
  margin:6px 2px 12px}
.nm-short,.bd-short,.oc-short,.nm-num,.th-short{display:none}
.list-head{display:flex;align-items:center;gap:7px;margin:16px 0 8px}
.list-head .crest{width:20px;height:20px}
.team-cell{display:inline-flex;align-items:center;gap:6px}
.team-cell .crest{width:16px;height:16px;flex:none}
.team-abbr{display:none}
.logobar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.team-name-input{font:inherit;font-size:17px;font-weight:800;background:transparent;
  border:0;border-bottom:1px dashed var(--line);color:var(--ink);padding:4px 2px;min-width:0;flex:1}
.team-name-input:focus{outline:0;border-bottom-color:var(--accent)}
.oppbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px;
  padding-bottom:10px;border-bottom:1px dashed var(--line)}
[data-saved-select]{flex:1;min-width:150px;font:inherit;font-size:13px;padding:9px 8px}
[data-saved-select]:disabled{color:var(--muted)}
.oppstate{font-size:11.5px;font-weight:700;white-space:nowrap}
.oppstate.ok{color:var(--accent)} .oppstate.warn{color:var(--away)}

/* Native selects paint themselves white regardless of the page, so the chrome
   comes off and the chevron is drawn back on by hand. */
.add-row select,[data-saved-select]{appearance:none;-webkit-appearance:none;
  background-color:var(--bg2);color:var(--ink);border:1px solid var(--line);
  border-radius:9px;cursor:pointer;padding-right:26px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%238ea79a' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 9px center;background-size:11px 7px}
.add-row select:focus,[data-saved-select]:focus{outline:none;border-color:var(--accent2)}
/* the options list itself, for the browsers that honour it */
.add-row select option,[data-saved-select] option{background:var(--card);color:var(--ink)}

.add-row{display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap}
.add-row input,.add-row select{font:inherit;background:var(--bg2);border:1px solid var(--line);
  border-radius:9px;color:var(--ink);padding:9px 10px;min-width:0}
.add-row .num{width:62px;text-align:center;font-weight:800}
.add-row .nm{flex:1;min-width:96px}
/* Sized so "DEF/MID" still reads in full while #, name, Pos and Add stay on one
   line at 375px — the widest label drives the width, not the placeholder. */
.add-row .ps{width:82px;font-size:12.5px;padding-left:8px;padding-right:19px;
  background-position:right 6px center}
.add-row input[name="type"]{flex:1;min-width:150px}
.players{list-style:none;margin:0 0 10px;padding:0}
.players li{display:flex;align-items:center;gap:10px;padding:7px 2px;border-bottom:1px solid var(--line)}
.jersey{display:inline-flex;align-items:center;justify-content:center;min-width:34px;height:34px;
  border-radius:9px;background:var(--bg2);border:1px solid var(--line);font-weight:800}
.pname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pos{font-size:11px;font-weight:800;letter-spacing:.04em;width:68px;text-align:center;
  color:var(--muted)}
.pos-GK,.pos-DEF,.pos-MID,.pos-FWD,.pos-DEF-MID,.pos-MID-FWD{border-radius:999px;padding:3px 0;
  border:1px solid var(--line)}
/* Hybrids carry twice the text in the same pill. */
.pos-DEF-MID,.pos-MID-FWD{font-size:9.5px;letter-spacing:.02em}
.pos-GK{background:rgba(56,189,248,.15);border-color:var(--saved);color:var(--saved)}
.players li.is-gk .jersey{border-color:var(--saved);color:var(--saved)}

/* The row is the button: make that legible without shouting. */
.players li.prow{cursor:pointer;border-radius:10px}
.players li.prow:hover,.players li.prow:focus-visible{background:rgba(255,255,255,.04);outline:none}
.players li.prow:focus-visible{box-shadow:inset 0 0 0 2px var(--accent)}
.rowedit{width:22px;text-align:right;color:var(--muted);font-size:13px;opacity:.5}
.players li.prow:hover .rowedit{opacity:1}

/* ---- player edit sheet ---- */
.pl-row{display:flex;gap:10px;align-items:flex-end}
.pl-field{display:block;margin-bottom:14px}
.pl-num{width:88px;flex:0 0 88px}
.pl-name{flex:1 1 auto;min-width:0}
.pl-label{display:block;font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin-bottom:5px}
.pl-field input{width:100%;font:inherit;font-size:16px;padding:10px 12px;border-radius:10px;
  background:var(--panel);color:var(--text);border:1px solid var(--line)}
/* Six choices: three across, back-to-front reading order. */
.posgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.posbtn{font:inherit;font-size:14px;font-weight:800;letter-spacing:.04em;padding:12px 2px;
  border-radius:10px;cursor:pointer;background:var(--panel);color:var(--muted);
  border:1px solid var(--line)}
.posbtn.on{background:rgba(56,189,248,.16);border-color:var(--saved);color:var(--saved)}
.pl-foot{display:flex;align-items:center;justify-content:space-between;gap:12px}
.bulk{margin-bottom:8px}
.bulk summary{cursor:pointer;color:var(--muted);font-size:13px}
.bulk textarea{width:100%;font:inherit;font-size:13px;background:var(--bg2);border:1px solid var(--line);
  border-radius:9px;color:var(--ink);padding:9px;margin-bottom:8px}
.switch{display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-weight:700;
  font-size:14px;padding:6px 2px}
.switch input{width:20px;height:20px;accent-color:var(--accent);cursor:pointer}
/* the extra-time length hangs under the switch that turns extra time on */
.fmtgrid{display:flex;flex-direction:column;gap:2px;margin-bottom:2px}
.fmtgrid .halflen{margin:2px 0 8px 30px}
.chips{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px}
.subhead{font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);
  margin:14px 0 8px}
.pickgroup{margin-bottom:14px}
.pickgroup h4{font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin:0 0 8px}
.chips-pick{display:flex;flex-wrap:wrap;gap:6px}
.chippick{font:inherit;font-size:13px;font-weight:700;border-radius:999px;padding:9px 14px;
  cursor:pointer;background:var(--bg2);border:1px solid var(--line);color:var(--muted)}
.chippick.on{background:var(--accent);border-color:var(--accent);color:#06120c}
.chip{display:inline-flex;align-items:center;gap:4px;background:var(--bg2);border:1px solid var(--line);
  border-radius:999px;padding:6px 6px 6px 12px;font-size:13px;font-weight:600}
.chip-x{background:none;border:0;color:var(--muted);cursor:pointer;font-size:12px;padding:0 4px}

/* ------------------------------------------------------------- report */
.report-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.statusline{font-size:12.5px;font-weight:600;margin:10px 2px 0;color:var(--muted)}
.statusline.ok{color:var(--accent)}
.statusline.warn{color:var(--away)}
.statusline.bad{color:#f87171}
.statusline a{color:var(--accent);font-weight:800}
#game-label{flex:1;min-width:200px;font:inherit;background:var(--bg2);border:1px solid var(--line);
  border-radius:9px;color:var(--ink);padding:10px}
.report-head{text-align:center;margin-bottom:6px}
/* a team's shots, two tables abreast */
.shots-2up{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));
  gap:14px;align-items:start}
.finalscore{display:flex;flex-direction:column;gap:4px;margin:12px auto 0;
  max-width:420px;text-align:left}
.fs-row{display:flex;align-items:center;gap:12px;padding:6px 0;
  border-bottom:1px solid var(--line)}
.fs-row:last-child{border-bottom:0}
.fs-team{flex:1;min-width:0;display:flex;align-items:center;gap:8px;
  font-size:15px;font-weight:700;overflow-wrap:break-word}
.fs-score{font-size:30px;font-weight:800;font-variant-numeric:tabular-nums;
  min-width:1.3em;text-align:right;flex:none}
.fs-home{color:var(--home)} .fs-away{color:var(--away)}
/* Fixed four across so eight tiles make two even rows — auto-fit was leaving a
   single tile stranded on a row of its own. */
.statgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-bottom:14px}
/* Nine tiles with xG on: three across divides evenly where four leaves an orphan. */
.statgrid.has-xg{grid-template-columns:repeat(3,minmax(0,1fr))}
@media (max-width:520px){
  .statgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .statgrid.has-xg{grid-template-columns:repeat(3,minmax(0,1fr))}
  .statgrid.has-xg .sv{font-size:18px}
  .statgrid.has-xg .sl{font-size:10px}
}
.stat{background:var(--bg2);border:1px solid var(--line);border-radius:11px;padding:9px 6px;
  text-align:center}
.sv{font-size:21px;font-weight:800} .sl{font-size:11px;color:var(--muted)}

/* tinted to match each outcome's colour on the maps */
.stat-goal{background:rgba(34,197,94,.12);border-color:rgba(34,197,94,.45)}
.stat-goal .sv{color:var(--goal)}
.stat-saved{background:rgba(56,189,248,.10);border-color:rgba(56,189,248,.4)}
.stat-saved .sv{color:var(--saved)}
.stat-blocked{background:rgba(167,139,250,.10);border-color:rgba(167,139,250,.4)}
.stat-blocked .sv{color:var(--blocked)}
.stat-post{background:rgba(244,114,182,.10);border-color:rgba(244,114,182,.4)}
.stat-post .sv{color:var(--post)}
.stat-off .sv{color:var(--off)}
.stat-rate{background:rgba(61,220,132,.08);border-color:rgba(61,220,132,.35)}
.stat-rate .sv{color:var(--accent)}
.stat-xg{background:rgba(56,189,248,.08);border-color:rgba(56,189,248,.35)}
.stat-xg .sv{color:var(--accent2)}
.tally-n.xg b{color:var(--accent2)}
/* the one label that is a word, so it needs the type treatment the emoji don't */
.tally-n.xg .ti{font-size:11px;font-weight:800;color:var(--accent2);opacity:.75;
  letter-spacing:.01em}
td.xg{font-variant-numeric:tabular-nums}
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:14px}
.tbl{width:100%;border-collapse:collapse;font-size:13px}
.tbl th,.tbl td{white-space:nowrap}
.tbl th{text-align:left;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.05em;
  padding:6px 8px;border-bottom:1px solid var(--line)}
.tbl td{padding:7px 8px;border-bottom:1px solid var(--line)}
.tbl td.num{font-weight:800;color:var(--muted)}
.tbl.compact{max-width:420px}
@media print{.tbl-wrap{overflow:visible}}
/* Football's own notation: 2 (4) — the score, then the shootout in brackets. */
.pk-score{font-size:.6em;font-weight:800;color:var(--muted);vertical-align:middle}
.pk-line{margin:8px 0 0;text-align:center;font-weight:800;font-size:13.5px;color:var(--accent)}
.pk-headline{margin:0 0 12px;font-size:16px;font-weight:700}
.pk-headline strong{font-size:19px}
/* ---- the shot strip beside a map ----
   One line per shot: the circle it is on the pitch, the minute, and the shirt.
   The dot is drawn, not painted, so it prints whether or not the browser was
   asked for background graphics. */
.map-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2fr) minmax(0,1fr);
  gap:10px;align-items:start}
.shotstrip{list-style:none;margin:0;padding:0;font-size:11px;
  font-variant-numeric:tabular-nums}
.shotstrip li{display:flex;align-items:center;gap:4px;padding:1px 0;white-space:nowrap}
/* more specific than the row rule above it, or the name inherits nowrap and a
   long club name runs off the side of the strip */
.shotstrip .ss-head{display:block;font-weight:800;font-size:10.5px;color:var(--muted);
  text-transform:uppercase;letter-spacing:.04em;line-height:1.2;margin-bottom:3px;
  white-space:normal;overflow-wrap:break-word}
/* Both strips read left to right: right-aligning one made its dots, minutes and
   shirts each start at a different place down the column. */
.ss-dot{width:15px;height:15px;flex:none}
.ss-dot text{fill:#fff;text-anchor:middle;font-weight:800;font-size:11px;
  font-family:inherit}
.ss-dot .oc-goal{fill:var(--goal)} .ss-dot .oc-saved{fill:var(--saved)}
.ss-dot .oc-blocked{fill:var(--blocked)} .ss-dot .oc-post{fill:var(--post)}
.ss-dot .oc-off{fill:var(--off)}
.ss-t{color:var(--muted);min-width:3.2em}
.ss-p{font-weight:700}
.ss-none{color:var(--muted);font-style:italic}

/* the quiet print under a map: what it is, and what it isn't */
.mapnote{margin:8px 2px 0;font-size:11.5px;line-height:1.35;color:var(--muted);font-style:italic}
/* charts inside a report card: figure's default margin is 40px a side */
.overview-map figure{margin:0 0 14px}
.overview-map figcaption{font-size:11.5px;color:var(--muted);text-transform:uppercase;
  letter-spacing:.05em;margin-bottom:6px}
.maps{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:14px;align-items:start}
.maps figure{margin:0}
.maps .goal-svg{max-width:430px}
.maps figcaption{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px}
.maps .pitch-svg[data-mode="full"]{max-width:min(100%,300px)}
/* map beside the shot log — stacked on a phone, side by side once there's room */
/* min-width:0 on the children is essential: grid items default to min-width:auto,
   so a table whose min-content is wider than its track overflows the card instead
   of fitting inside it. */
.overview-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;align-items:start}
.overview-grid > *{min-width:0}
.overview-log{overflow:hidden}
.overview-map .tbl-wrap{margin-bottom:12px}
.overview-log h3{margin:14px 0 8px}
.overview-log h3:first-child{margin-top:0}
.overview-log .list-head:first-child{margin-top:0}
.half-block .tbl td .crest{width:18px;height:18px;margin-right:6px}
.map-both .pitch-svg{max-width:min(100%,340px);margin:0 auto}
.team-log + .team-log{margin-top:14px}
@media (min-width:900px){
  .overview-grid{grid-template-columns:minmax(0,300px) minmax(0,1fr);gap:22px}
  .map-both .pitch-svg{max-width:100%}
}
/* the team's two maps, side by side under its totals */
.team-maps{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));
  gap:16px;align-items:start;margin-bottom:4px}
.team-maps figure{margin:0}
.team-maps figcaption{font-size:11.5px;color:var(--muted);text-transform:uppercase;
  letter-spacing:.05em;margin-bottom:6px}
.team-maps .pitch-svg{max-width:min(100%,300px);margin:0 auto}
.team-maps .goal-svg{max-width:100%}
.legend{display:flex;flex-wrap:wrap;gap:12px;margin-top:12px;font-size:11.5px;color:var(--muted)}
.lg{display:inline-flex;align-items:center;gap:5px}
.sw{width:10px;height:10px;border-radius:50%;display:inline-block;background:currentColor}
.sw.oc-goal{background:var(--goal)} .sw.oc-saved{background:var(--saved)}
.sw.oc-blocked{background:var(--blocked)} .sw.oc-post{background:var(--post)} .sw.oc-off{background:var(--off)}

/* --------------------------------------------------------- update bar */
.update-bar{position:fixed;left:12px;right:12px;margin:0 auto;
  width:fit-content;max-width:min(92vw,520px);
  bottom:calc(16px + env(safe-area-inset-bottom));z-index:70;
  display:flex;align-items:center;gap:10px;
  background:var(--card);border:1px solid var(--accent);border-radius:14px;
  padding:10px 10px 10px 16px;font-size:13px;font-weight:600;
  box-shadow:0 12px 34px rgba(0,0,0,.5)}
.update-bar.hidden{display:none}
.update-bar span{flex:1;min-width:0}
.update-bar .btn{flex:none;white-space:nowrap}

/* -------------------------------------------------------------- toast */
.toast{position:fixed;left:12px;right:12px;margin:0 auto;width:fit-content;
  max-width:min(92vw,440px);bottom:calc(24px + env(safe-area-inset-bottom));z-index:80;
  transform:translateY(20px);
  background:#0b120f;border:1px solid var(--accent);color:var(--ink);border-radius:999px;
  padding:11px 18px;font-size:13px;font-weight:600;opacity:0;pointer-events:none;
  transition:opacity .18s,transform .18s;text-align:center}
.toast.on{opacity:1;transform:translateY(0)}
body.has-update .toast{bottom:calc(86px + env(safe-area-inset-bottom))}

@media (max-width:520px){
  .brand{font-size:14px}
  .tab{padding:6px 10px;font-size:12.5px}
  .seg-btn{font-size:13px;padding:10px 8px}
  .st-goals{font-size:32px} .clock{font-size:26px}
  .st-name{font-size:11.5px}
  .scoreboard{gap:6px;padding:10px 8px}
  .period-wrap{padding:12px 12px;min-width:104px}
  .period-label{font-size:14px}
  .clock-controls{gap:4px}
  .view{padding:10px}
}
/* Below this the wordmark costs more than it's worth — keep just the ball. */
@media (max-width:470px){
  #topbar{gap:8px}
  .brand-name{display:none}
}
/* Five tabs: shorten the longest ones rather than let anything wrap. */
@media (max-width:560px){
  .lbl-long{display:none}
  .lbl-short{display:inline}
}
/* Tightest phones: tighten the row itself as well. */
@media (max-width:360px){
  #topbar{padding-left:10px;padding-right:10px}
  .tabs{gap:4px}
  .tab{padding:6px 9px;font-size:12px}
}

/* -------------------------------------------------------------- print */
@media print{
  body{background:#fff;color:#111;padding:0}
  #topbar,.no-print,.flow,.toast,.update-bar,.match-actions{display:none !important}
  .view:not(.on){display:none !important}
  .view.on{display:block !important;max-width:none;padding:0}
  /* No frame on paper. Each module has a page to itself, so the border earned
     nothing — and a border is the one thing a printer will push onto the next
     sheet on its own, which is how a page appears with nothing on it but a line.
     -webkit- prefixes too: Safari paginates on the old property names. */
  .card{background:#fff;border:0;padding:0;margin-bottom:0;
    break-inside:avoid;page-break-inside:avoid;-webkit-column-break-inside:avoid}

  /* The title block was taking an inch and a half of page one for information
     that fits comfortably in half of it. */
  /* The title block is page one's tax: every line here is a line of shots that
     doesn't fit. The date and clock line goes (the title already carries the
     date), and the two score rows become one, with each score against its own
     team's name rather than pushed out to a column edge. */
  /* The title block is the map's caption: never let a page break come between
     them. Without this the map, which must stay whole, jumps to the next page
     and leaves the title stranded on its own. */
  .report-head{padding:5px 10px;break-after:avoid;page-break-after:avoid}
  .report-head h1{font-size:12pt;line-height:1.1;margin:0}
  .report-head .muted{display:none}
  .report-head .finalscore{flex-direction:row;justify-content:center;align-items:baseline;
    gap:22px;margin:3px auto 0;max-width:none;text-align:center}
  .report-head .fs-row{display:inline-flex;align-items:baseline;gap:4px;padding:0;
    border-bottom:0;width:auto}
  .report-head .fs-team{flex:none;font-size:9.5pt;gap:4px;align-items:baseline}
  .report-head .finalscore .crest{width:12px;height:12px;align-self:center}
  .report-head .fs-score{font-size:13pt;min-width:0;text-align:left}
  .overview h2,.report-team h2{font-size:12pt;margin:0 0 6px}
  .overview .legend{margin-top:6px}
  /* these are taller than a page by design — let them flow rather than fight it */
  .report-team,.overview{break-inside:auto;page-break-inside:auto}
  .muted,.sl,.maps figcaption,.tbl th{color:#555}
  .statgrid{grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin-bottom:10px}
  .statgrid.has-xg{grid-template-columns:repeat(3,minmax(0,1fr))}
  .stat{background:#f4f4f4;border-color:#ddd;padding:5px 4px}
  .sv{font-size:13pt} .sl{font-size:6.5pt}
  /* darker on white so the tint still reads once printed */
  .stat-goal{background:#e8f7ee;border-color:#9ad9b4} .stat-goal .sv{color:#15803d}
  .stat-saved{background:#e8f4fd;border-color:#9ccdf0} .stat-saved .sv{color:#0369a1}
  .stat-blocked{background:#f0ecfd;border-color:#c3b5f2} .stat-blocked .sv{color:#6d28d9}
  .stat-post{background:#fdecf4;border-color:#f2b5d1} .stat-post .sv{color:#be185d}
  .stat-off .sv{color:#475569}
  .stat-rate{background:#eef7f1;border-color:#b6ddc5} .stat-rate .sv{color:#15803d}
  .stat-xg{background:#eaf3fb;border-color:#a9cdea} .stat-xg .sv{color:#0369a1}
  .fs-home,.fs-away{color:#111}
  .fs-row{border-bottom:1px solid #ddd}
  .tbl td,.tbl th{border-bottom:1px solid #ddd}
  .turf{fill:#f2f7f3} .stripe{fill:#e8f1ea}
  .ln{stroke:#7d8b83} .dot{fill:#7d8b83} .goalbox{fill:#e5e9e7;stroke:#7d8b83}
  .pitch-tag,.goal-tag{fill:#999}
  .miss-zone{fill:#f6f7f6} .ground{fill:#eef3ef} .net{fill:#fafafa}
  .mesh{stroke:#ddd} .guide{stroke:#ccc} .frame{stroke:#333} .goalline{stroke:#999}
  .mk circle{stroke:#fff} .mk text{fill:#fff}
  .mk-off circle{fill:#64748b}
  /* Each section starts its own page and stays whole on it, so a module is never
     split and never shares a sheet with another. */
  .report-team{page-break-before:always;break-before:page;
    break-inside:avoid;page-break-inside:avoid;-webkit-column-break-inside:avoid}
  .report-team[data-long="1"],.report-team[data-long="1"] .team-detail,
  .report-team[data-long="1"] .shots-2up{break-inside:auto;page-break-inside:auto}
  .report-team .statgrid{break-inside:avoid;page-break-inside:avoid}
  /* One row of numbers doesn't need a full section's worth of air, and the
     page-1 stack here has little to spare before the unbreakable chart block. */
  /* the per-player table set like the goalkeeping line under it — they are the
     same kind of table and were printing at two different sizes */
  .report-team .tbl-players{font-size:8pt}
  .report-team .tbl-players th{text-transform:none;letter-spacing:0;font-size:7.5pt}
  .report-team .tbl-players th,.report-team .tbl-players td{padding:3px 6px}
  .report-team .tbl-keeper{font-size:8pt}
  .report-team .tbl-keeper th{text-transform:none;letter-spacing:0;font-size:7.5pt}
  .report-team .tbl-keeper th,.report-team .tbl-keeper td{padding:3px 6px}
  .report-team .keeper-head{margin:8px 0 4px;font-size:9pt}
  .report-team .tbl-wrap.keeper-wrap{margin-bottom:0;break-inside:avoid;page-break-inside:avoid}
  /* keep the heading with the single row it labels */
  .report-team .keeper-head{break-after:avoid;page-break-after:avoid}
  .report-team .team-detail{break-inside:avoid;page-break-inside:avoid}
  .team-maps{break-inside:avoid;page-break-inside:avoid}
  .report-team .team-shots-head{break-after:avoid;page-break-after:avoid}
  /* From / Placement come out on the team pages too. Their wording wraps to two
     lines per row, which pushed the shots + charts block past a full page and
     forced the split this was meant to prevent — and the two charts directly
     below say the same thing in pictures. */
  .report-team .col-where{display:none}

  /* The team list now sits in a 48% column beside the charts, so it takes the
     same shape as the overview list rather than a full-width table. */
  .report-team .col-sit{display:none}
  /* A team's page is one page: the tiles run in a single row, the maps are
     capped, and the rows of every table on it lose the leading meant for prose.
     Two maps at full height plus three rows of tiles was most of the sheet
     before the numbers had been printed. */
  .report-team .statgrid,.report-team .statgrid.has-xg{
    grid-template-columns:repeat(9,minmax(0,1fr));gap:4px;margin-bottom:8px}
  .report-team .stat{padding:3px 2px}
  .report-team .sv{font-size:11pt} .report-team .sl{font-size:5.5pt}
  .report-team .tbl td,.report-team .tbl th{padding:2px 4px;line-height:1.15}
  .team-maps{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px;margin-bottom:2px}
  .team-maps figure{margin:0;break-inside:avoid;page-break-inside:avoid}
  .team-maps figcaption{font-size:7pt;margin-bottom:3px}
  .team-maps .goal-svg{max-width:100%;width:100%;max-height:1.15in}
  .team-maps .pitch-svg{max-width:100% !important;width:100%;max-height:1.7in;margin:0 auto}
  /* page one carries the small print about the spots; a team's page need not
     repeat it, and the line is worth two shots' worth of height here */
  .report-team .mapnote{display:none}
  .report-team .legend{font-size:7pt;margin-top:4px}
  /* the pair of tables is one thing: a page break through the middle of it puts
     a heading and a single row at the foot of one page */
  .shots-2up{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px;
    align-items:start;break-inside:avoid;page-break-inside:avoid}
  .report-team .team-shots-head{break-after:avoid;page-break-after:avoid}
  .report-team .tbl-shots{font-size:6.6pt;width:100%;table-layout:fixed}
  .report-team .tbl-shots th,.report-team .tbl-shots td{padding:2px;line-height:1.15;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Never shorten the number: a clipped "1…" that could be 10 through 19 is
     worse than useless on a page whose whole job is matching rows to dots. */
  .tbl-shots td.num,.tbl-kicks td.num{text-overflow:clip;overflow:visible}
  /* uppercase + letter-spacing pushes "PLACEMENT" past its column */
  .report-team .tbl-shots th{text-transform:none;letter-spacing:0;font-size:7.5pt}
  /* 7% held one digit and an ellipsis, so every shot from the tenth on printed
     as "1…". These columns are fixed-width, so the number can't push its cell
     wider — it has to be given the room up front. */
  .report-team .tbl-shots td,.report-team .tbl-shots th{font-size:inherit}
  .report-team .tbl-shots td:nth-child(1),.report-team .tbl-shots th:nth-child(1){width:11%}
  .report-team .tbl-shots td:nth-child(2),.report-team .tbl-shots th:nth-child(2){width:19%;
    font-variant-numeric:tabular-nums}
  .report-team .tbl-shots td:nth-child(3),.report-team .tbl-shots th:nth-child(3){width:33%}
  .report-team .tbl-shots td:nth-child(4),.report-team .tbl-shots th:nth-child(4){width:20%}
  .report-team .tbl-shots td:nth-child(6),.report-team .tbl-shots th:nth-child(6){width:17%}
  .report-team .th-full{display:none}
  .report-team .th-short{display:inline}
  .report-team .tbl-shots tbody tr:nth-child(odd){background:#f6f8f7}
  /* notes print under their shot, spanning the row */
  .report-team .note-row td{white-space:normal;font-size:7.5pt;padding:2px 4px 4px 22px;
    border-top:1px dashed #ccc;color:#444}
  .report-team .note-label{font-size:6.5pt;color:#15803d}
  /* the striping counts rows, so a note row would flip the pattern — keep the
     note the same shade as the shot it belongs to */
  .report-team .tbl-shots tbody tr:nth-child(odd),
  .report-team .tbl-shots tbody tr:nth-child(even){background:none}
  .report-team .tbl-shots tbody tr.shot-row.alt,
  .report-team .tbl-shots tbody tr.shot-row.alt + tr.note-row{background:#f6f8f7}
  .pitch-svg{height:auto !important}
  .pitch-svg[data-mode="full"]{max-width:230px}
  .goal-svg{max-width:340px}

  /* The overview prints as its own page: pitch down the left, shots down the
     right. A pitch is half again as tall as it is wide, so filling the page
     vertically means giving it most of the width. 56/44 is the balance where the
     pitch is still big and the table stops wrapping every heading. */
  /* One forced break per section, on the section that starts a page. Pairing a
     break-after with the next element's break-before can leave a blank page. */
  /* fr, not %: percentage tracks plus a gap add up to more than the container,
     which pushed the right-hand column past the card border by exactly the gap.
     fr divides what's left after the gap. */
  .overview-grid{grid-template-columns:minmax(0,56fr) minmax(0,44fr);gap:12px;
    align-items:start}
  .overview-grid > *{min-width:0;overflow:hidden}

  /* Capped by height as well as width so the whole section clears one page.
     An SVG with a viewBox keeps its aspect when max-height bites, so the pitch
     just gets proportionally smaller rather than squashed. */
  /* ---- a map page ----
     The pitch is the page: it stands upright and takes what is left once the
     score, the totals and the legend are printed. Not the last pixel of the
     sheet — filling it exactly leaves a sliver to spill onto the next page, and
     the forced break after it then reads as a blank one. Nothing here grows
     with the game, so the section is asked to stay whole and always does. */
  .overview-tall{break-inside:avoid;page-break-inside:avoid;-webkit-column-break-inside:avoid}
  /* 5.6in, well short of what Chrome's own margins would allow. A sheet loses
     height to wider margins, to the browser's header and footer, and to whatever
     a phone's print engine decides — none of which this stylesheet can see. The
     map is sized so that page one still holds when all of them apply at once. */
  .overview-tall .pitch-svg{max-height:5.6in;max-width:100% !important;width:100%;
    margin:0 auto}
  /* a strip of shots down each side of it, one team a side */
  .map-row{display:grid;grid-template-columns:1.2in minmax(0,1fr) 1.2in;gap:9px;
    align-items:start}
  /* longer than the pitch is tall: the strips fold in two and take the width
     they need, and the pitch gives it up */
  .overview-tall[data-strip="2"] .map-row{grid-template-columns:1.95in minmax(0,1fr) 1.95in}
  .overview-tall[data-strip="2"] .shotstrip{columns:2;column-gap:8px}
  .overview-tall[data-strip="2"] .ss-head{column-span:all}

  /* ---- a half page ----
     The pitch lies on its side here — short and wide is the shape of the room a
     half page has spare — with that half's shots underneath, a column a team. */
  .half-block .pitch-svg{max-width:100% !important;width:100%;max-height:2.9in;margin:0 auto}
  .half-block .overview-log{display:grid;grid-template-columns:1fr 1fr;gap:16px;
    align-items:start;margin-top:6px}
  .half-block .team-log + .team-log{margin-top:0}
  .half-block .list-head{break-after:avoid;page-break-after:avoid}
  .half-block .tbl-shots{font-size:7pt}
  .half-block .tbl.tbl-shots td,.half-block .tbl.tbl-shots th{font-size:inherit;
    padding:2px;line-height:1.15}
  .half-block .th-full{display:none}
  .half-block .th-short{display:inline}
  .half-block .tbl-shots td:nth-child(1),.half-block .tbl-shots th:nth-child(1){width:11%}
  .half-block .tbl-shots td:nth-child(2),.half-block .tbl-shots th:nth-child(2){width:19%}
  .half-block .tbl-shots td:nth-child(3),.half-block .tbl-shots th:nth-child(3){width:33%}
  .half-block .tbl-shots td:nth-child(4),.half-block .tbl-shots th:nth-child(4){width:20%}
  .half-block .tbl-shots td:nth-child(6),.half-block .tbl-shots th:nth-child(6){width:17%}
  .half-block .mins{font-variant-numeric:tabular-nums;white-space:nowrap}
  /* a half longer than any of ours: each team's column folds in two */
  .half-block[data-dense="2"] .pitch-svg{max-height:2.6in}
  .half-block[data-dense="2"] .team-log{columns:2;column-gap:10px}
  .half-block[data-dense="2"] .tbl-shots{font-size:6.2pt}
  .half-block[data-dense="2"] .tbl.tbl-shots th,
  .half-block[data-dense="2"] .tbl.tbl-shots td{padding:1px 2px}
  .half-block[data-dense="2"] .list-head{font-size:8pt;margin:4px 0 3px}
  .half-block[data-dense="2"] .tbl-shots td:nth-child(4),
  .half-block[data-dense="2"] .tbl-shots th:nth-child(4){display:none}
  .half-block[data-dense="2"] .nm-short{display:none}
  .half-block[data-dense="2"] .nm-num{display:inline}
  .half-block[data-dense="2"] .tbl-shots td:nth-child(1),
  .half-block[data-dense="2"] .tbl-shots th:nth-child(1){width:14%}
  .half-block[data-dense="2"] .tbl-shots td:nth-child(2),
  .half-block[data-dense="2"] .tbl-shots th:nth-child(2){width:26%}
  .half-block[data-dense="2"] .tbl-shots td:nth-child(3),
  .half-block[data-dense="2"] .tbl-shots th:nth-child(3){width:26%}
  .half-block[data-dense="2"] .tbl-shots td:nth-child(6),
  .half-block[data-dense="2"] .tbl-shots th:nth-child(6){width:34%}
  /* The map already says where, and the situation is on the team pages. These
     need to out-specify the cell rules further down, which set display:block. */
  /* surname only, and "Rt. foot" — the full forms stay on screen */
  .overview .nm-full,.overview .bd-full,
  .report-team .nm-full,.report-team .bd-full{display:none}
  .overview .nm-short,.overview .bd-short,.overview .oc-short,
  .report-team .nm-short,.report-team .bd-short,.report-team .oc-short{display:inline}
  .overview .oc-full,.report-team .oc-full{display:none}

  .overview .col-where,.overview .col-sit,
  .overview .tbl-shots td.col-where,.overview .tbl-shots td.col-sit,
  .overview .tbl-shots th.col-where,.overview .tbl-shots th.col-sit{display:none}
  .half-block{page-break-before:always;break-before:page;
    break-inside:avoid;page-break-inside:avoid;-webkit-column-break-inside:avoid}
  /* The map column is asked to stay whole — a pitch cannot usefully be sliced in
     half — but the section around it may break. A block that must stay whole yet
     cannot fit a page is what jumps to the next one and leaves a hole behind, so
     the only things marked here are the ones the rules above keep small. */
  .overview .overview-map{break-inside:avoid;page-break-inside:avoid}
  .tbl tr{break-inside:avoid;page-break-inside:avoid}
  .overview .tbl{font-size:7.5pt;width:100%}
  .overview .tbl th{text-transform:none;letter-spacing:0;font-size:7.5pt;
    white-space:nowrap}
  /* The global rule keeps every cell on one line, which is what made club names
     run over the column beside them. Cells wrap here; the columns that must stay
     on one line say so individually below. */
  .overview .tbl th,.overview .tbl td{padding:3px 4px;vertical-align:middle;
    white-space:normal;overflow-wrap:break-word;overflow:hidden}
  .overview .tbl tbody tr:nth-child(odd){background:#f6f8f7}   /* easier to track */
  .overview .tbl-wrap{overflow:visible}
  /* the pill's border and padding push "Off Target" past a narrow column */
  .overview .oc,.report-team .oc{border:0;padding:0;font-size:7.5pt;white-space:nowrap}
  .overview .legend{font-size:7.5pt;gap:7px}
  .overview-log h3{font-size:9.5pt;margin:10px 0 5px}

  /* Initials instead of the club name repeated down a narrow column. The crest
     goes too — at 13px beside text it only crowds the cell. */
  .overview .team-full{display:none}
  .overview .team-abbr{display:inline;font-weight:700}
  .overview .team-cell{max-width:100%;overflow:hidden}
  .overview .team-cell .crest{display:none}

  /* With one list per team the Team column is gone, which is exactly the width
     that was missing — every row now fits on one line at real name lengths. */
  .overview .tbl-shots{table-layout:fixed;width:100%}
  /* padding and column widths come from the map-page block above */
  .overview .tbl-shots th,.overview .tbl-shots td{white-space:nowrap;overflow:hidden;
    text-overflow:ellipsis}
  /* the column widths for these lists are set with the rest of the map-page
     layout further up — this block is only the shared table dressing */
  .overview .tbl-shots tbody tr.shot-row.alt{background:#f6f8f7}
  .overview .list-head{font-size:9pt;margin:10px 0 4px;display:flex;align-items:center;gap:5px}
  .overview .list-head .crest{width:12px;height:12px}

  /* nine columns in a narrow gutter: short headings, no uppercase tracking */
  /* Scoped under .overview so these beat the generic cell rules above — without
     it every heading wrapped into "Pos t" and "Con v". */
  /* Now in the wider left column above the pitch, so it can go back up a size. */
  .overview .tbl-halfstats{table-layout:fixed;font-size:7pt;margin-bottom:8px}
  .overview .tbl-halfstats th{text-transform:none;letter-spacing:0;font-size:6.5pt;
    white-space:nowrap;text-align:center}
  .overview .tbl-halfstats td{white-space:nowrap;text-align:center}
  .overview .tbl-halfstats th:nth-child(1),
  .overview .tbl-halfstats td:nth-child(1){width:22%;text-align:left;white-space:normal}
  .overview .tbl-halfstats th:not(:nth-child(1)),
  .overview .tbl-halfstats td:not(:nth-child(1)){width:9.75%}
  /* with xG on there are ten columns rather than nine */
  .overview .tbl-halfstats.has-xg th:not(:nth-child(1)),
  .overview .tbl-halfstats.has-xg td:not(:nth-child(1)){width:8.66%}
  .overview .tbl-halfstats th,.overview .tbl-halfstats td{padding:3px 1px}
  .overview .tbl-halfstats .crest{display:none}
  .overview .oc{border:0;padding:0;font-size:7.5pt}
  .overview .legend{font-size:7.5pt;gap:7px}
  .overview-log h3{font-size:9pt;margin:8px 0 4px}

  .mapnote{font-size:6.5pt;color:#666;margin:5px 0 0}

  /* ---- penalty shootout ---- */
  .shootout-block{page-break-before:always;break-before:page;
    break-inside:avoid;page-break-inside:avoid;-webkit-column-break-inside:avoid}
  .pk-line{color:#15803d;font-size:9pt;margin-top:3px}
  .pk-headline{font-size:11pt;margin-bottom:8px}
  .pk-headline strong{font-size:13pt}
  .pk-score{color:#555}
  .shootout-block .overview-map figure{margin:0 0 10px}
  .shootout-block .overview-map figcaption{font-size:7pt;margin-bottom:3px}
  .shootout-block .goal-svg{max-width:100%;width:100%}
  .tbl-kicks td:nth-child(1),.tbl-kicks th:nth-child(1){width:11%;padding-right:2px}

}

/* ===================================================================
   HOSTED MODE — sign-in, read-only viewing, and the live badge.
   Everything here is inert in the private single-user copy: with no
   server to answer /api/auth/me, no data-role is ever set and the
   viewer rules below never match.
   =================================================================== */

/* ---- signing in --------------------------------------------------- */

/* [hidden] is display:none in the UA stylesheet, which any author rule of equal
   specificity beats — so `.signin { display: flex }` quietly made the overlay
   permanent and no amount of signing in could dismiss it. Guard every element
   that gets a display, not just this one. */
[hidden] { display: none !important; }

.signin {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg, #0d1117);
}
body.locked { overflow: hidden; }

.signin-card {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: center;
}
.signin-mark { font-size: 44px; line-height: 1; }
.signin-card h1 { margin: 0; font-size: 26px; letter-spacing: -0.01em; }
.signin-card .muted { margin: 0 0 10px; }
.signin-label {
  text-align: left;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  opacity: 0.7;
}
#signin-pw {
  width: 100%;
  padding: 12px 14px;
  font-size: 17px;             /* 16px or more, or iOS zooms the page on focus */
  border-radius: 8px;
}
.signin-msg { margin: 4px 0 0; font-size: 13px; min-height: 1.2em; opacity: 0.75; }

/* ---- the live badge ------------------------------------------------ */

/* Directly above the clock, in the scoreboard's middle column. In normal flow
   rather than absolutely placed, so a long message pushes the clock down a few
   pixels instead of landing on top of a crest. */
.live-status {
  display: inline-block;
  margin: 0 auto 5px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid currentColor;
  line-height: 1.5;
  max-width: 100%;
}
.live-status.is-live  { color: #35c37d; }
.live-status.is-idle  { color: #8b98a5; }
/* Amber, not red: the tracker being out of signal is expected at a field and
   is not an error — it just means what's on screen has stopped being current. */
.live-status.is-stale { color: #d99a2b; text-transform: none; letter-spacing: 0; }
.live-status.is-off   { color: #d9663b; text-transform: none; letter-spacing: 0; }

/* ---- read-only ------------------------------------------------------
   Viewers see the whole match — pitch, shot map, scoreboard, clock,
   report, past games — and can change none of it. The controls are
   hidden rather than disabled: a greyed-out row of buttons they can
   never use is just clutter on a phone screen. */

body[data-role="viewer"] #btn-clock,
body[data-role="viewer"] #btn-undo,
body[data-role="viewer"] #archive-game,
body[data-role="viewer"] .tab[data-view="settings"],
body[data-role="viewer"] #track-hint,
body[data-role="viewer"] #view-settings,
body[data-role="viewer"] #team-seg,
body[data-role="viewer"] #pitch-seg,
/* Roster page: everything that edits a squad. The squads themselves stay
   visible — a parent wants to see who wore 9. */
body[data-role="viewer"] .logobar,
body[data-role="viewer"] .oppbar,
body[data-role="viewer"] .add-row,
body[data-role="viewer"] .bulk,
body[data-role="viewer"] .clear-team,
body[data-role="viewer"] #shared-roster { display: none !important; }

/* The Rosters tab is squad management. A viewer who wants to know who wore 9
   reads it off the report, where it is attached to actual shots. */
body[data-role="viewer"] .tab[data-view="roster"],
body[data-role="viewer"] #view-roster { display: none !important; }

/* Same rule as the past-game report: a viewer gets Print / PDF and nothing
   that writes, imports, or exports. */
body[data-role="viewer"] #game-label,
body[data-role="viewer"] #export-csv,
body[data-role="viewer"] #export-json,
body[data-role="viewer"] #import-json,
body[data-role="viewer"] #offline-status { display: none !important; }

/* With no game there is nothing to label, save, export or print, so the whole
   action bar goes and the empty state speaks for the page. */
/* Nothing to label, save, export or print when no game is being tracked. */
body.no-live-game #view-report .card.no-print { display: none !important; }

/* A viewer's action bar holds one button. A card around a single button is
   chrome around nothing, so the panel drops away and the button stands on its
   own, centred. Admins keep the card -- theirs holds six controls and a status
   line, which does need a container. */
body[data-role="viewer"] #view-report .card.no-print,
body[data-role="viewer"] #past-actions {
  background: none;
  border: 0;
  padding: 0;
  margin-top: 18px;
}
body[data-role="viewer"] .report-actions { justify-content: center; }

.empty-live { text-align: center; padding: 40px 24px; }
.empty-live h2 { margin: 0 0 6px; }
.empty-live p { margin: 0 0 18px; }
.empty-live .btn { text-decoration: none; display: inline-block; }

/* Readable, not editable. */
body[data-role="viewer"] .team-name-input,
body[data-role="viewer"] .players { pointer-events: none; }
body[data-role="viewer"] .team-name-input {
  border-color: transparent;
  background: transparent;
}

/* ---- features that only exist when the app is served from a laptop ----
   Both of these talk to serve.py, which is not what is running here:
   /logo-fetch proxies an arbitrary URL (it is not on the public server on
   purpose — see the plan), and the shared roster reads and writes a
   roster.json next to serve.py. Left visible they are buttons that always
   fail. The hosted app has no need for the second one anyway: rosters now
   travel to the server with the game. */
body[data-role] #shared-roster,
body[data-role] [data-logo-url] { display: none !important; }

/* Setting the clock, ending a half and ending a game all change the match.
   The period LABEL stays — a viewer needs to know it is the second half —
   but the select behind it and the chevron that advertises it both go. */
body[data-role="viewer"] #btn-clock-set,
body[data-role="viewer"] .match-actions,
body[data-role="viewer"] .period-chev,
body[data-role="viewer"] #period-select { display: none !important; }

/* The pitch stays visible and stays legible — it simply stops accepting
   taps, so a viewer can never open the shot flow at all. */
body[data-role="viewer"] #pitch-host { pointer-events: none; }

/* Half of that hint is still true for a viewer; the swipe half is not. */
body[data-role="viewer"] .admin-only { display: none !important; }

/* The shot log stays tappable for viewers — tapping a row lights that shot up
   on the pitch, which is reading, not tracking. Only the edit and delete
   buttons behind the row go; the swipe that reveals them is disabled in
   track.js, since a gesture cannot be turned off from a stylesheet. */
body[data-role="viewer"] #recent-list .row-actions { display: none !important; }


/* ---- the Live Game tab --------------------------------------------
   Pulses only while a game is actually being tracked, so it means
   something when it moves. A dot rather than the label itself: animating
   text is hard to read, and the tab still has to be tappable. */
body[data-role="viewer"] .tab[data-view="track"] { position: relative; }

body[data-role="viewer"] .tab.tab-live::after {
  content: "";
  position: absolute;
  top: 2px;
  right: -2px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #35c37d;
  animation: gt-pulse 1.8s ease-in-out infinite;
}

@keyframes gt-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.72); }
}

/* A pulse is decoration; the dot is the information. Keep the dot. */
@media (prefers-reduced-motion: reduce) {
  body[data-role="viewer"] .tab.tab-live::after { animation: none; }
}

/* ---- past games list ----------------------------------------------
   Fixture, score, and a way in. Nothing else earns the width. */
.logrow.arch {
  display: flex;
  align-items: center;
  gap: 12px;
}
.gl-fixture {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
.gl-teams {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 15px;
  line-height: 1.35;
  min-width: 0;
}
/* Names shrink before the score does — the score is the thing being scanned. */
.gl-nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gl-when { font-size: 12px; opacity: 0.6; }
.gl-score { font-variant-numeric: tabular-nums; padding: 0 2px; flex: none; }

.gl-crest {
  flex: none;
  width: 20px;
  height: 20px;
  object-fit: contain;
  border-radius: 3px;
}
/* A club with no crest still takes the space, so the names stay in a column
   down the list instead of stepping in and out. */
.gl-crest-none { display: inline-block; }
.gl-report { flex: none; text-decoration: none; }

/* ---- correcting a shot in a saved report ---------------------------- */

.edit-hint { margin: 8px 0 0; }

/* Rows only look tappable for the tracker; a viewer never gets the class. */
.tbl-shots tr.editable { cursor: pointer; }
.tbl-shots tr.editable:hover td { background: rgba(61, 220, 132, .08); }
.tbl-shots tr.editable:active td { background: rgba(61, 220, 132, .16); }

.sheet-back {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  z-index: 300;
}
.sheet-card {
  position: fixed;
  z-index: 301;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(460px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 18px;
}
.sheet-card h3 { margin: 0 0 2px; }
.sheet-card > .muted.small { margin: 0 0 14px; }

.edit-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 10px;
}
.edit-grid label,
.edit-note {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--muted);
  min-width: 0;
}
.edit-note { margin-bottom: 14px; }
.edit-grid input,
.edit-grid select,
.edit-note input {
  width: 100%;
  /* 16px or more, or iOS zooms the page when the field takes focus. */
  font-size: 16px;
  padding: 8px 10px;
  border-radius: 8px;
}

/* A correction sheet has no business on a printed report. */
@media print { .sheet-back, .sheet-card, .edit-hint { display: none !important; } }

/* ---- the tracker cohort link ---------------------------------------
   Hidden for everyone but viewers, and quiet even for them: almost every
   person on this page is a parent watching a match, not a coach about to
   take over the tracking. */
.cohort-wrap { display: none; margin: 28px 0 8px; text-align: center; }
body[data-role="viewer"] .cohort-wrap { display: block; }

.cohort-link {
  font-size: 12px;
  opacity: 0.45;
  letter-spacing: 0.02em;
}
.cohort-link:hover, .cohort-link:focus-visible { opacity: 0.85; }

#signin-back { margin-top: 4px; font-size: 13px; opacity: 0.7; }

/* ---- goal scorers on the scoreboard ---------------------------------
   Minute and shirt number under the side that scored, the way a broadcast
   scoreboard reads. Quiet enough that the score itself still dominates. */
.scorers {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-top: 4px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.scorers:empty { display: none; }
.scorer { white-space: nowrap; }
