/* The manager's screen, on the same palette as the app it edits.
   Everything here is layered over /css/styles.css: same tokens, same cards,
   same court colours, so a game looks like a game wherever it's drawn. */

.adminmark{
  font-family:var(--display);font-size:12px;font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;color:var(--pink-deep);background:var(--pink-soft);
  padding:4px 10px;border-radius:999px;
}
/* The same 34px a tab is — 20px of line plus 7px above and below. A select gets
   it as a height rather than as padding and line-height, because the control's
   internal metrics are the browser's and only the box is ours: left to itself it
   took the body's line-height and sat taller than everything beside it. */
/* Its type, caps and colour are the league pages' season pill (.seasonpick in
   styles.css, a class the select carries), so the season reads the same on both
   sides. A select can't hold the pill's chevron, so it draws one to match: the
   picker's own stroke, at the ink2 it is set in faded as the pill fades it. */
.seasonsel select{
  --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 11 7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' fill='none' stroke='%239497B0' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
  appearance:none;-webkit-appearance:none;
  /* As wide as the season it shows, as the pill is, where the browser can;
     elsewhere as wide as its longest season, which is how a select comes. */
  field-sizing:content;
  border:0;background:var(--chev) no-repeat right 12px center / 10px 6px;
  max-width:210px;height:34px;padding:0 30px 0 14px;
}
.seasonsel select:hover{background:var(--line2) var(--chev) no-repeat right 12px center / 10px 6px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.loading{color:var(--muted)}

.pagehead{display:flex;flex-wrap:wrap;align-items:flex-end;gap:12px 20px;margin-bottom:4px}
.pagehead h1{font-size:clamp(27px,3.2vw,38px)}
.pagehead .btn{margin-left:auto}
.hint{color:var(--ink2);font-size:12.5px;margin:8px 0 0;max-width:70ch}
.hint.inline{margin:0;align-self:center}
.linkish{color:var(--pink-deep);font-weight:600;text-decoration:underline;text-underline-offset:2px;font-size:inherit;padding:0;margin:0;border:0;background:none}
/* The one destructive thing on Setup, kept at the foot of the page as text. */
.seasonkill{margin:30px 0 6px;text-align:center;font-size:13px}

.btn{
  display:inline-flex;align-items:center;gap:7px;padding:9px 15px;border-radius:11px;
  border:1px solid var(--line);background:var(--card);font-size:13.5px;font-weight:600;
  color:var(--ink2);text-decoration:none;
}
.btn:hover{background:var(--card2);color:var(--ink)}
.btn.small{padding:7px 12px;font-size:12.5px;border-radius:9px}
.btn.primary{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.btn.primary:hover{background:var(--ink2);color:var(--paper)}
.btn.primary:disabled{opacity:.5;cursor:default}
.btn.danger{color:var(--pink-deep);border-color:var(--pink-soft);background:var(--pink-soft)}
.btn.danger:hover{background:var(--pink);color:#fff}
.btn.ghost{background:transparent}

/* ---------- panels and row forms ---------- */
.panel{
  margin-top:22px;padding:18px 20px 20px;background:var(--card);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow);
}
.panel h2,.panel h3.panelhead{display:flex;align-items:baseline;gap:10px;font-size:20px}
.panel h2 .cnt,.panel h3.panelhead .cnt,.sectionhead .cnt,.subpanel h3 .cnt{
  font-family:var(--body);font-size:12px;font-weight:400;color:var(--muted);letter-spacing:0;
}

/* A page with two jobs on it needs to say where one ends. The rule and the
   kicker do more of that work than another card would. */
/* --line is a card border: on the lavender page it's all but invisible, so the
   rule between sections is drawn from the ink instead. */
.sectionhead{
  margin:34px 0 -4px;padding-top:20px;
  border-top:1px solid color-mix(in srgb, var(--ink) 14%, transparent);
}
/* The one directly under the page title has the title to separate it already. */
.pagehead + .sectionhead{border-top:0;padding-top:0;margin-top:22px}
.sectionhead h2{display:flex;align-items:baseline;gap:10px;font-size:26px;margin-top:2px}
.sectionhead .hint{margin-top:4px}
.panel .addhead{
  margin:18px 0 6px;font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  font-family:var(--display);
}
.panel.empty{color:var(--ink2);font-size:14px}
.rows{display:grid;gap:8px;margin-top:12px}

.rowform{
  display:flex;flex-wrap:wrap;gap:10px 12px;align-items:flex-end;
  padding:11px 12px;border:1px solid var(--line2);border-radius:12px;background:var(--card2);
}
.rowform.adding{border-style:dashed;background:transparent}
.rowform.block{background:transparent;border:0;padding:0}
.fl{display:flex;flex-direction:column;gap:3px;flex:1 1 130px;min-width:0}
.fl.wide{flex:2 1 200px}
.fl.narrow{flex:0 0 78px}
/* A code or a small count: room for a two-word label, no more. */
.fl.short{flex:0 0 120px}
/* A field that reads as a sentence gets the whole line. */
.fl.full{flex:1 1 100%}
/* In a list row it comes after the row's buttons, so Remove or Add stays on
   the first line instead of a line of its own. A block form keeps its order. */
.rowform:not(.block) .fl.full{order:1}
.fl>span{
  font-family:var(--display);font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted);font-weight:600;
}
/* The few boxes that can't be left blank say so; the rest say nothing. */
.fl>span .req{font-style:normal;font-weight:700;color:var(--pink-deep);margin-left:3px}
/* A row that drags: the handle sits at the left edge, the row fades while it moves. */
.rowform.grip{padding-left:28px;position:relative}
.rowform.grip > .hd{position:absolute;left:9px;top:50%;transform:translateY(-50%);color:var(--muted);opacity:.55;font-size:16px;cursor:grab}
.rowform.dragging{opacity:.4}
/* A row added with its button and not yet saved: in the list, dressed as a row. */
.rowform.adding.staged{border-style:solid;border-color:var(--line2);background:var(--card2)}
.fl input,.fl select,.fl textarea{
  font:inherit;font-size:13.5px;color:var(--ink);background:var(--card);
  border:1px solid var(--line);border-radius:9px;padding:8px 10px;width:100%;
}
/* A select draws its own arrow, 14px in from the edge, where the date box's
   calendar sits; the browser's own arrow hugs the edge and ignores padding. */
.fl select{
  appearance:none;-webkit-appearance:none;padding-right:32px;
  background:var(--card) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 11 7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' fill='none' stroke='%23181A42' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 14px center / 11px 7px;
}
.fl textarea{font-family:var(--num);font-size:12.5px;line-height:1.6;resize:vertical}
/* Prose, not a list of times: the body face, at reading size. */
.fl textarea.para{font-family:var(--body);font-size:13.5px;line-height:1.5}
/* A class that sets display beats the UA rule behind the hidden attribute,
   and a block's boxes for the other two kinds stayed on screen. */
.fl[hidden]{display:none}
.panel h2 .btn{margin-left:auto;font-size:12px}
.fl input:focus,.fl select:focus,.fl textarea:focus{outline:2px solid var(--sky);outline-offset:1px;border-color:var(--sky)}
.fl.check{flex:0 0 auto;flex-direction:row;align-items:center;gap:7px;padding-bottom:9px}
.fl.check input[type=checkbox]{width:17px;height:17px;accent-color:var(--pink)}
.fl.check>span{letter-spacing:.04em;text-transform:none;font-size:12.5px;color:var(--ink2)}
.rowacts{display:flex;gap:8px;align-items:center;margin-left:auto}
.rowacts.wide{flex:1 1 100%;margin-left:0}
.maplink{display:block;font-size:12px;color:var(--sky-deep);margin:-2px 0 6px 12px}

/* ---------- the schedule grid ---------- */
.calwrap{
  margin-top:18px;background:var(--card);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow);overflow-x:auto;
}
.cal{display:grid}

/* One board, two clocks. A playoff day runs on hours the season does not, and
   making every week carry those extra rows costs the whole season height for the
   sake of one day. The fence lets each side keep its own time axis instead.
   Rows do not line up across it — that is the trade, and it is the manager's
   screen, where seeing the placement matters more than reading across. */
.split{display:flex;align-items:stretch;min-width:min-content}
/* A side is never narrower than its board: allowed to shrink, the band stopped
   at the side's edge while the board ran on past it, and left a notch. The
   whole split scrolls sideways instead. */
.split .side{display:flex;flex-direction:column;min-width:min-content}
.split .side.po{border-left:3px solid var(--pink,#FF2E88)}
.split .side .cal{flex:1;align-content:start}
/* The season side runs out of rows before the playoff side does. Hatching what
   is left says "no more hours here"; an unpainted gap reads as a broken table. */
.split .side .cal{
  background:repeating-linear-gradient(135deg,transparent,transparent 6px,var(--card2) 6px,var(--card2) 12px);
}
.split .cal .tcell,.split .cal .slot,.split .cal .bye{background:var(--card)}

/* One line, one height, both sides — the day headers have to line up across the
   fence or the two boards read as one broken board. */
.split .band{
  display:flex;align-items:center;height:34px;padding:0 12px;
  border-bottom:1px solid var(--line);background:var(--card2);
  /* No overflow:hidden — it would make this the sticky label's scroll container
     and pin it to nothing. One line at a fixed height has nothing to clip. */
  white-space:nowrap;
}
.split .side.po .band{background:var(--pink-soft,#FFE1EE);color:var(--pink-deep,#D80F68)}
/* Pinned to the scrollport like the time gutter is: a label at the far left of a
   board seven columns wide is a label nobody ever sees. */
.split .bandin{position:sticky;left:12px;display:inline-flex;align-items:baseline;gap:9px;min-width:0;max-width:100%}
.split .band b{
  font-family:var(--display);font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;
}
.split .band b,.split .band a{flex:none}
.split .band a{font-size:11px;letter-spacing:.04em;color:inherit}

/* An hour a day has no business in. Hatched rather than filled with empty
   courts, because there is nothing to add there and it must not invite it. */
.cal .slot.void{
  border-top:1px solid var(--line2);border-left:1px solid var(--line2);
  background:repeating-linear-gradient(135deg,transparent,transparent 6px,var(--card2) 6px,var(--card2) 12px);
}
.cal .hcell{
  position:sticky;top:0;z-index:2;background:var(--card);
  padding:10px 12px 9px;border-bottom:1.5px solid var(--line);border-left:1px solid var(--line2);
}
.cal .hcell.gutter{border-left:0}
.cal .hcell .wk{font-family:var(--display);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.cal .hcell .dy{font-family:var(--display);font-size:17px;font-weight:700}
.cal .hcell .cnt{font-size:10.5px;color:var(--muted)}
.cal .tcell{
  border-top:1px solid var(--line2);padding:10px 9px 0 0;text-align:right;
  font-family:var(--num);font-size:11px;color:var(--muted);
}
.cal .slot{border-top:1px solid var(--line2);border-left:1px solid var(--line2);padding:5px;display:grid;gap:4px}
.cal .bye{
  border-left:1px solid var(--line2);border-top:1px solid var(--line2);
  display:flex;align-items:center;justify-content:center;
  background:repeating-linear-gradient(135deg,transparent,transparent 7px,var(--line2) 7px,var(--line2) 8px);
}
.cal .bye span{
  writing-mode:vertical-rl;font-family:var(--display);font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);background:var(--card);padding:10px 3px;border-radius:6px;
}

/* A court, empty or holding a game. Always the same height, so a day reads as
   a shape: four courts is four rows whether or not anything is scheduled. */
.drop{
  position:relative;min-height:56px;border-radius:9px;border:1.5px dashed var(--line);
  display:flex;padding:0;transition:background .12s,border-color .12s;
}
.drop>.ghost{
  margin:auto;font-family:var(--display);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);opacity:.75;padding:0 6px;text-align:center;
}
/* An empty court says which court it is until you reach for it, then says what
   clicking does. Both live in the same box so nothing moves on hover. */
.drop.vacant{cursor:pointer}
.drop.vacant>.plus{
  position:absolute;inset:0;display:grid;place-items:center;opacity:0;
  font-family:var(--display);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--sky-deep);font-weight:700;
}
.drop.vacant:hover,.drop.vacant:focus-visible{border-color:var(--sky);background:var(--sky-soft)}
.drop.vacant:hover>.ghost,.drop.vacant:focus-visible>.ghost{opacity:0}
.drop.vacant:hover>.plus,.drop.vacant:focus-visible>.plus{opacity:1}

/* ---------- staged, not saved ---------- */
/* Staged keeps its own border, and it is the one place a dashed edge earns
   itself: it means "not written yet", which is a real difference from every
   saved match beside it. The division colour stays on the left edge. */
.cal .ev.staged{border-style:dashed;border-width:1.5px;border-color:var(--sky-deep);background:var(--sky-soft)}
.cal .ev.staged{border-left-style:solid;border-left-width:3px}
.cal .ev .stagedflag{color:var(--sky-deep);letter-spacing:.08em;font-weight:700;margin-left:auto}
/* The save bar is shared with the public pages' editor; it lives in styles.css. */

/* ---------- what's wrong with the week ---------- */
.problems{
  margin-top:16px;padding:12px 15px;border-radius:var(--r);
  background:#FFF8E6;border:1px solid #F2D9A0;color:#6B4E00;
}
.problems.bad{background:var(--pink-soft);border-color:color-mix(in srgb,var(--pink) 40%,transparent);color:var(--pink-deep)}
.problems b{font-family:var(--display);font-size:12px;letter-spacing:.14em;text-transform:uppercase}
.problems ul{margin:6px 0 0;padding-left:18px;font-size:13px;line-height:1.6}
.problems li::marker{color:currentColor}
.problems li.clash{font-weight:600}
.problems .linkish{color:inherit;margin-left:6px;font-size:12px}

/* ---------- a match in a cell ---------- */
/* The block itself is `.ev` from styles.css — the same one the player's season
   page draws, so a match is coloured by division on both. Only the states that
   exist here are added: staged edits, and a schedule that can't be honoured. */
.cal .ev{flex:1;min-width:0;width:100%;background:var(--card);cursor:pointer}
.cal .ev:hover{box-shadow:var(--shadow)}
.cal a.ev{text-decoration:none;color:inherit}
.cal .ev .top{gap:6px}
.cal .ev .top .scored{color:var(--live);letter-spacing:.08em}
/* A match the schedule can't honour: a team in two places at once is an error,
   a team playing more often than the season runs is a caution. */
.cal .ev .flag{margin-left:auto;font-weight:700;letter-spacing:.08em}
.cal .ev .flag + .d{margin-left:6px}
.cal .ev.clash{border-color:var(--pink);background:var(--pink-soft)}
.cal .ev.clash .flag{color:var(--pink-deep)}
.cal .ev.overload{border-color:#E0B457;background:#FFF8E6}
.cal .ev.overload .flag{color:#8A6300}
.cal .ev .flag.po{color:var(--pink-deep)}

/* ---------- the add/edit game dialog ---------- */
/* Two teams on one line, then where and when on the next: the fields read as a
   sentence, not a flex row that gives Start time half the dialog. */
.gameform{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:2px 19px 4px}
.gameform .trio{grid-column:1/-1;display:grid;grid-template-columns:1.6fr 1fr .7fr;gap:12px}
.gameform .fl{flex:none;min-width:0}
/* Delete on the far left and alone; the two you might press without looking
   sit together on the right, in the order they're reached. The gap between
   them is the point — the destructive button should never be the thing your
   thumb lands on next to the one that confirms. */
.gameform .rowacts{grid-column:1/-1;margin-left:0;margin-top:2px}
.rowacts .righthand{display:flex;gap:8px;margin-left:auto}
@media (max-width:560px){
  .gameform,.gameform .trio{grid-template-columns:1fr}
}

.calwrap+.problems{margin-top:14px}

@media (max-width:700px){
  .rowform{padding:10px}
  .fl{flex:1 1 100%}
  .fl.narrow{flex:0 0 92px}
  .rowacts{margin-left:0}
}

/* A playoff week reads as its own thing in the header, the way it does on the
   public overview — the bracket is the week, not another Week 8. */
.cal .hcell.playoffs .wk{color:var(--pink-deep);font-weight:700}
/* The playoff heading is a link to the bracket, because that is where its
   matches are made. Underlined only on hover, so a column heading doesn't read
   as a run of links across the top of the grid. */
a.hcell{text-decoration:none;color:inherit}
a.hcell:hover{background:var(--pink-soft)}
a.hcell:hover .wk{text-decoration:underline}

/* ---------- the change log ---------- */
/* A read-out, so it reads as a list rather than as a table: the time and the
   sentence carry it, and the address is set quiet because it's the thing you
   only look at when something's wrong. */
.changelog{padding:0}
.changeday{
  position:sticky;top:0;z-index:1;background:var(--card2);border-bottom:1px solid var(--line);
  padding:8px 16px;font-family:var(--display);font-size:10.5px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
}
.change{
  display:grid;grid-template-columns:68px 74px 1fr minmax(0,auto);gap:12px;align-items:baseline;
  padding:10px 16px;border-bottom:1px solid var(--line2);font-size:13.5px;
}
.change:last-child{border-bottom:0}
.ctime{font-family:var(--num);font-size:11.5px;color:var(--muted);white-space:nowrap}
.ckind{
  font-family:var(--display);font-size:9.5px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:var(--muted);
  background:var(--line2);border-radius:999px;padding:2px 8px;text-align:center;
}
.ckind.k-score{background:var(--live-soft);color:var(--live)}
.ckind.k-games,.ckind.k-schedule{background:var(--sky-soft);color:var(--sky-deep)}
.cwhat{min-width:0}
.cwhat small{display:block;font-size:11px;color:var(--muted)}
/* An IPv6 address is 39 characters and would rather be one line than fit the
   column, so it is told it may break. Labelled, because an unlabelled address
   set this quiet reads as a serial number rather than as the thing you paste
   into a Cloudflare access rule. */
.cwho{
  font-family:var(--num);font-size:11px;color:var(--muted);
  max-width:22ch;overflow-wrap:anywhere;text-align:right;
}
.cwho i{
  font-family:var(--display);font-style:normal;font-size:8.5px;font-weight:700;
  letter-spacing:.14em;color:var(--muted);opacity:.7;margin-right:5px;
}
@media (max-width:640px){
  .change{grid-template-columns:60px 1fr;gap:4px 10px}
  .ckind{grid-column:1;justify-self:start}
  .cwhat{grid-column:2}
  .cwho{grid-column:2;font-size:10.5px;max-width:none;text-align:left}
}

/* ---------- the nav: tabs, then More ---------- */
/* Scoped to the manager's own nav. `.seg` is shared with the player app, where
   it draws the court filter and must keep sizing itself to its contents.

   Allowed to shrink and clipping what it can't hold is what makes the overflow
   measurable: scrollWidth past clientWidth is the answer, so no tab width is
   ever added up in JS. */
/* The nav can only give way if everything holding it can. A flex item's default
   min-width is its own content, so without this the header just grows wider
   than the page and takes the document with it — and every position:fixed
   element then pins to that wider viewport. Scoped to the manager: the player
   app's header has three tabs and never needs to give. */
body.admin .topright{min-width:0}
.navbar{display:flex;align-items:center;gap:2px;flex:0 1 auto;min-width:0}
.navseg{flex:0 1 auto;min-width:0;overflow:hidden}
.morewrap{position:relative;display:flex;flex:none}
/* A class setting display beats the UA rule behind the hidden attribute, so
   without this More stayed on screen holding nothing whenever every tab fit. */
.morewrap[hidden]{display:none}
.morebtn{
  display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  padding:7px 14px;border-radius:999px;font-size:13.5px;line-height:20px;font-weight:600;
  color:var(--muted);transition:background .16s,color .16s;
}
.morebtn:hover,.morebtn[aria-expanded="true"]{background:var(--line2);color:var(--ink2)}
/* Wearing the selected tab's clothes, because that is what it is standing in
   for: the page you're on is in the menu behind it. */
.morebtn[aria-current="page"]{background:var(--ink);color:var(--paper)}
.morebtn[aria-current="page"]:hover{background:var(--ink2);color:var(--paper)}
.morebtn[aria-current="page"] svg{opacity:.8}
.morebtn svg{opacity:.55;transition:transform .18s}
.morebtn[aria-expanded="true"] svg{transform:rotate(180deg)}
.moremenu{
  position:absolute;top:calc(100% + 7px);right:0;z-index:60;min-width:170px;
  display:flex;flex-direction:column;padding:5px;
  background:var(--card);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-lg);
}
.moremenu button,.moremenu a{
  text-align:left;padding:8px 11px;border-radius:8px;font-size:13.5px;font-weight:600;
  color:var(--ink2);white-space:nowrap;
}
.moremenu a[aria-current="page"]{background:var(--ink);color:var(--paper)}
.moremenu a{text-decoration:none}
.moremenu button:hover,.moremenu a:hover{background:var(--line2);color:var(--ink)}

/* ---------- the header on a phone ---------- */
/* The mark and the badge on one line, and the desktop's own pill on the next —
   tabs, divider and season picker inside it, in that order, exactly as they sit
   on a wide screen.

   The header was one 999px pill wrapped around both rows before this, which at
   81px tall stopped reading as a pill at all: the ends bowed out around the tabs
   and the last one ran into the curve. A radius that says "one row of controls"
   has to sit on something that is one row of controls. Splitting the picker out
   as its own field fixed that and cost something else — a control that belongs
   with the nav read as a separate thing that had landed nearby. */
@media (max-width:640px){
  .topbar .wrap{height:auto;flex-wrap:wrap;gap:9px;padding-top:10px;padding-bottom:12px}
  .adminmark{margin-left:auto}
  /* The same pill as the desktop, given a row of its own: tabs, divider and
     season picker together, because they are one set of controls and splitting
     the picker off made it read as some other thing that had landed nearby. */
  .topright{margin-left:0;flex:1 1 100%;min-width:0;flex-wrap:nowrap;gap:0}
  .navbar{flex:0 1 auto;min-width:0;flex-shrink:1}
  /* The nav takes what it can hold and gives the rest to More, which is the
     whole point of it on a phone. Not allowed to grow: given the spare room it
     pushed More to the far end of the pill and left a hole in the middle. */
  .navseg{flex:0 1 auto}
  .navseg button,.navseg a{padding:7px 13px;font-size:12.5px;white-space:nowrap}
  .morebtn{padding:7px 12px;font-size:12.5px}
  /* Anchored to the whole bar rather than to the button. Hung off the button it
     opened as a second rounded white box overlapping the season picker below,
     and the two read as one shape that had gone wrong. The width of the bar it
     drops from is a clearer thing to be. */
  .navbar{position:relative}
  .morewrap{position:static}
  .moremenu{left:0;right:0;min-width:0}
  /* A fixed share of the pill, neither growing nor shrinking, because anything
     elastic here chases its own tail: the nav is measured to decide how many
     tabs fit, hiding a tab makes the nav narrower, the picker widens into the
     space, and the room the nav just gave up is gone before it can be measured
     again. Three tabs went under More that way to pay for a name nobody was
     reading. Fixed, the nav's allowance is known before anything is hidden.

     The name is what gives, which is the right way round: a season is chosen
     once and then glanced at, so "Summer II…" costs less than a tab does. */
  .seasonsel{flex:0 0 clamp(96px,30%,150px);min-width:0}
  .seasonsel select{
    width:100%;max-width:none;padding:0 22px 0 8px;background-position:right 8px center;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  /* The pill is a full row, so something in it has to absorb the slack. The
     divider does, and takes it on its left: the space then falls between the
     tabs and the divider, and the divider stays against the picker it divides
     the tabs from. Carried by the picker instead — which is where it was — the
     gap opened up between the divider and the season name, and the two ends of
     the pill read as having drifted apart. */
  .topdiv{display:block;margin:0 3px 0 auto}
}

/* ------------------------------------------------------------- playoffs */
/* She builds in the same ladder the league reads. The source pill is the whole
   idea made visible: a side is a seed, or the winner or loser of another match.
   No connecting lines — in a division where losers feed a second bracket the
   wire crosses to the other tree, and a line between columns would be a lie. */
.divblock{margin-top:26px}
.divhd{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px}
.divhd h2{font-size:20px;margin:0}
.divhd .hint{margin:0}

.brk{background:var(--card);border:1px solid var(--line);border-radius:14px;margin-top:12px;overflow:hidden}
.brktop{display:flex;flex-wrap:wrap;align-items:center;gap:8px 11px;padding:12px 14px}
.brktop .grow{flex:1}
.nameinput{
  font-family:var(--display);font-size:19px;font-weight:700;color:var(--ink);
  background:transparent;border:1px solid transparent;border-radius:8px;
  padding:2px 7px;margin-left:-7px;min-width:70px;max-width:260px;
}
.nameinput:hover,.nameinput:focus{border-color:var(--line);background:var(--card2)}
.pilltag{display:inline-flex;align-items:center;padding:3px 10px;border-radius:999px;font-size:11.5px;font-weight:600}
.pilltag.draft{background:var(--card2);color:var(--muted);border:1px dashed var(--muted)}
.pilltag.livet{background:var(--live-soft);color:var(--live);border:1px solid var(--live)}

/* Seeds and Matches are named sections rather than a stack of controls: they are
   two different decisions, and the second is built out of the first. */
.bsec{border-top:1px solid var(--line)}
.bsec:first-of-type{border-top:0}
.bsechd{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 12px;
  padding:12px 14px 11px;background:var(--card2);border-bottom:1px solid var(--line2);
}
.bsechd h3{font-family:var(--display);font-size:16px;font-weight:700;margin:0}
.bsechd .sub{font-size:12px;color:var(--muted);flex:1 1 200px;min-width:0}
.bsechd .btn{margin-left:auto;align-self:center}
.bsecbody{padding:11px 14px 13px;background:var(--card)}
.plbl{
  font-family:var(--display);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
}
.seeds{display:flex;flex-wrap:wrap;gap:6px}
.sdchip{
  display:inline-flex;align-items:center;gap:5px;padding:3px 4px 3px 7px;border-radius:8px;
  background:var(--card);border:1px solid var(--purple-soft);font-size:13px;
}
.sdchip .rank{font-size:11px;color:var(--purple);font-weight:700;min-width:13px}
.sdchip .who{max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sdchip .mv,.sdchip .rm{
  width:20px;height:20px;border-radius:6px;font-size:12px;line-height:1;
  border:0;background:none;color:var(--muted);cursor:pointer;
}
.sdchip .mv:hover{background:var(--purple-soft);color:var(--purple)}
.sdchip .rm:hover{background:var(--pink-soft);color:var(--pink-deep)}
.pool{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:11px;padding-top:11px;border-top:1px dashed var(--line)}
.pool .hint{margin:0}
.add{
  padding:3px 9px;border-radius:8px;border:1px dashed var(--line);background:var(--card);
  font:inherit;font-size:12.5px;color:var(--ink2);cursor:pointer;
}
.add:hover{border-style:solid;border-color:var(--purple);color:var(--purple)}

.lad{display:flex;gap:26px;overflow-x:auto;padding:14px 16px 18px}
.rung{flex:none;width:196px;display:flex;flex-direction:column;gap:9px}
.rhd{
  font-family:var(--display);font-size:10px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--muted);padding-bottom:3px;border-bottom:1px solid var(--line);
}
.rinner{display:flex;flex-direction:column;justify-content:space-around;gap:9px;flex:1}
/* The whole card is the way in, the way a chip on the schedule grid is. */
/* The header row the season grid uses on a match: what it is on the left in
   mono caps, what it is called on the right in the display face. The court is
   written rather than colour-coded, which is the rule there too — a bare number
   beside a time read as "2 7:00 PM". */
/* No division on these cards: the page is already sectioned by division, with
   the heading right above the ladder. */
/* The court reads as words in the same mono caps the season grid uses, ahead of
   the time it shares a line with. */
.node:hover .nft{border-top-color:var(--line)}
/* The wires are drawn, because two stubs at different heights read as two
   dashes rather than as a connection. See drawWires. */
.lad{position:relative}
.wires{position:absolute;inset:0;pointer-events:none;z-index:0}
.wires path{fill:none;stroke:var(--line);stroke-width:1.5}
.rung{position:relative;z-index:1}
.emptylad{padding:20px 16px 24px;text-align:center;color:var(--muted);font-size:13.5px}


.addrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:11px 14px;border-top:1px dashed var(--line);background:var(--card)}


.checks{display:grid;gap:7px;padding:11px 14px 13px}
.chk{display:flex;align-items:flex-start;gap:9px;font-size:13px;color:var(--ink2)}
.chk .mark{flex:none;width:18px;height:18px;border-radius:5px;display:grid;place-items:center;font-size:11px;font-weight:700;margin-top:1px}
.chk.ok .mark{background:var(--live-soft);color:var(--live)}
.chk.bad .mark{background:var(--pink-soft);color:var(--pink-deep)}
.chk.bad{color:var(--pink-deep)}
.pubrow{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:4px}
.pubrow .hint{margin:0;flex:1 1 240px}

.newbrk{
  margin-top:11px;width:100%;padding:13px;border-radius:14px;
  border:1px dashed var(--muted);background:var(--card2);
  font:inherit;font-size:13.5px;font-weight:600;color:var(--ink2);cursor:pointer;
}
.newbrk:hover{border-color:var(--purple);color:var(--purple);background:var(--card)}

@media (max-width:560px){
  .brktop{gap:7px 9px}
  .nameinput{font-size:17px;max-width:none;flex:1 1 140px}
  .lad{padding:12px}
  /* On a phone the section's action drops under its title rather than being
     squeezed onto the same line as a wrapped subtitle. */
  .bsechd .btn{margin-left:0;width:100%;margin-top:8px}
}

/* The season rank rides beside the seed number, muted, because they are the
   same number until she moves someone — and it is the moment they come apart
   that she needs to see both. */
.emptylad p{margin:0 0 12px;max-width:46ch;margin-inline:auto}

/* A match that is wrong says so on the card, not only in a list at the bottom.
   Red is reserved for something she has to act on — an unplaced match is
   incomplete, not wrong, and stays quiet. */
.node.bad{border-color:var(--pink-deep);background:#FFFBFC}
.node .fault{
  display:block;margin:0;font-size:10.5px;line-height:1.35;color:var(--pink-deep);
  padding-left:9px;position:relative;
}
.node .fault::before{content:"!";position:absolute;left:0;font-weight:700}

/* Courts and times, not "slots" — the grid is built out of those two, and that
   is what the league says. */
/* The last step, at the foot of the page, because it can only be done once the
   brackets are right — it lays the rounds out in order across the days. */
.placebar{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;
  margin-top:14px;padding:13px 15px;border-radius:12px;
  background:var(--card2);border:1px solid var(--line2);
}
.placebar.done{border-style:dashed}
.placebar.done b{color:var(--live)}
.placebar b{display:block;font-family:var(--display);font-size:15px}
.placebar small{color:var(--muted);font-size:12px}
.placebar span{flex:1 1 320px;min-width:0}
/* Start times on a game-day row. Any day may run hours the season does not, so
   this is a game-day field rather than a playoff feature.

   Every control here edits a hidden input and the row's own Save button submits
   it — chips that wrote straight through would give one row two save models. */
.chipfield{flex:2 1 260px}
.chips{display:flex;flex-wrap:wrap;gap:5px;align-items:center}
.chip{
  display:inline-flex;align-items:center;gap:4px;padding:3px 4px 3px 9px;border-radius:999px;
  background:var(--card);border:1px solid var(--line);font-size:12.5px;color:var(--ink2);
}
.chip button{
  border:0;background:none;color:inherit;opacity:.55;cursor:pointer;
  font-size:14px;line-height:1;padding:0 3px;
}
.chip button:hover{opacity:1}
/* The tight right edge is room for the ×; a chip that only shows a time, as on
   the Playoffs page, has none, so its padding evens out and the time centres. */
.chip:not(:has(button)){padding-right:9px}
.addchip{
  padding:3px 11px;border-radius:999px;border:1px dashed var(--line);
  background:var(--card);font:inherit;font-size:12.5px;color:var(--ink);cursor:pointer;
}
.addchip:hover{border-style:solid}
.chipin{
  font:inherit;font-size:12.5px;padding:3px 9px;border-radius:999px;
  border:1px solid var(--ink2);background:var(--card);color:var(--ink);width:8em;
}

/* The playoff days and the button that fills them: one panel, in the same shape
   as every other section — h2, a count, a hint — rather than a bold line and a
   bar that happened to sit next to each other. */
.placefoot{margin-top:30px}
.placefoot .hint{margin-bottom:4px}
.pday{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:11px 0;border-top:1px solid var(--line2)}
.pday:first-of-type{margin-top:10px}
.pdaywhen{min-width:118px}
.pdaywhen b{font-family:var(--display);font-size:14px;display:block}
.pdaywhen small{color:var(--muted);font-size:11px}
.pdaytimes{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1 1 240px}
.pdaycount{font-family:var(--num);font-size:12px;color:var(--muted);text-align:right;min-width:118px}
.pdaycount.over{color:var(--pink-deep)}

.shortfall{
  display:grid;gap:3px;margin-top:11px;padding:12px 15px;border-radius:14px;
  background:var(--pink-soft);border:1px solid var(--pink-deep);color:var(--pink-deep);font-size:13px;
}
.shortfall b{font-family:var(--display);font-size:14px;letter-spacing:.02em}

/* The faults again inside the dialog, where she is about to change the thing
   that is wrong with them. */
.dlgfaults{
  display:grid;gap:4px;padding:9px 11px;border-radius:10px;
  background:var(--pink-soft);border:1px solid var(--pink-deep);
}
.dlgfaults .fault{margin:0;font-size:12px;color:var(--pink-deep);padding-left:10px;position:relative}
.dlgfaults .fault::before{content:"!";position:absolute;left:0;font-weight:700}

/* A playoff match on the schedule grid: shown, because she placed it there, but
   edited on the Playoffs tab — its sides are wiring rather than a pair of teams. */
.gchip.playoff{text-decoration:none}
.gchip.playoff .gm{color:var(--pink-deep)}
.flag.po{
  font-style:normal;letter-spacing:.08em;text-transform:uppercase;
  color:var(--pink-deep);font-size:9px;font-weight:700;
}

/* ---------- sign-in ---------- */
/* Scrimmy's own dress: white ground, black ink, wash cards, Oswald headings,
   the mono mark with its coral dot. Not the club's lavender — until someone is
   in, nobody knows whose screen this is. The club's header, tabs and picker
   stay off the page. */
/* The class is on <html> from the head's first script when there is no
   session marker, and on <body> once the server has said nobody is signed in. */
html.signedout,html.signedout body,body.signedout{background:#fff}
.signedout .topbar,.signedout main,.signedout .foot{display:none}
html.signedout #signin{display:block}
/* Phone wording, shown only where texting is set up (GET /login/ways). Until
   it is, signing in is by email and the screen says so and nothing else. */
.ifsms{display:none}
html.texting .ifsms{display:revert}
.signin{
  --cs-ink:#141414;--cs-red:#FF6B5A;--cs-line:#D3D5E3;--cs-dim:#6A7093;--cs-wash:#F4F5FB;
  --cs-disp:"Oswald","Arial Narrow",sans-serif;
  max-width:460px;margin:0 auto;padding:26px 22px 64px;color:var(--cs-ink);
  font:16px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
}
/* A class that sets display beats the UA rule behind the hidden attribute. */
.signin [hidden]{display:none}
.cs-mark{padding:2px 0 14px}
.cs-mark .scrimmy{font-size:22px}
.cs-card{display:grid;gap:12px;margin-top:22px;padding:18px 18px 20px;background:var(--cs-wash);border-radius:14px}
.cs-card h2{font-family:var(--cs-disp);font-size:19px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;margin:0;color:var(--cs-ink)}
.cs-card label{display:grid;gap:5px;font-size:12.5px;font-weight:600;color:var(--cs-dim)}
.cs-card input{
  font:inherit;font-size:18px;padding:11px 12px;border:1.5px solid var(--cs-line);border-radius:10px;
  background:#fff;color:var(--cs-ink);width:100%;
}
.cs-card input:focus{outline:2px solid var(--cs-ink);outline-offset:1px;border-color:var(--cs-ink)}
.cs-card input[name=code]{font-family:var(--num);font-size:26px;letter-spacing:.3em;text-align:center}
.cs-lead{margin:0;font-size:15px}
.cs-hint{margin:0;font-size:13px;color:var(--cs-dim)}
.cs-hint a{color:var(--cs-ink)}
.cs-btn{font:inherit;font-weight:700;font-size:15px;padding:12px 18px;border:0;border-radius:10px;background:var(--cs-ink);color:#fff;cursor:pointer}
.cs-btn:hover{background:#2A2A2A}
.cs-btn[disabled]{opacity:.6;cursor:default}
.cs-link{
  font:inherit;font-size:13.5px;color:var(--cs-ink);background:none;border:0;padding:0;
  text-decoration:underline;text-underline-offset:3px;cursor:pointer;justify-self:start;
}
.cs-links{display:flex;flex-wrap:wrap;gap:6px 18px}
.cs-fault{margin:12px 0 0;color:var(--cs-red);font-size:13.5px}
.devcode{font-family:var(--num);color:var(--cs-ink)}

/* ---------- the Teams page: a list, not a wall of boxes ---------- */
/* A team is one line until it is tapped; then the same row opens to its
   fields. The form is the row, so the save bar counts it either way. */
.rowform.team{display:block;padding:0;background:var(--card);border-color:var(--line)}
.rowform.team .tsum{display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer}
.rowform.team .tsum:hover{background:var(--card2)}
.rowform.team .hd{width:14px;color:var(--line2);font-size:16px;flex:none;cursor:grab;text-align:center}
.rowform.team.dragging{opacity:.4}
.rowform.team .nm{flex:1;min-width:0;font-weight:600;font-size:14.5px;line-height:1.25}
.rowform.team .nm small{display:block;font-weight:400;font-size:12px;color:var(--muted);margin-top:2px}
.rowform.team .nm small.note{color:var(--ink2);font-style:italic}
.rowform.team.dim .nm{color:var(--muted)}
.rowform.team .st{
  flex:none;font-family:var(--display);font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  padding:4px 9px;border-radius:999px;background:var(--line2);color:var(--ink2);
}
.rowform.team .st.confirmed{background:#DDF5EA;color:#0E9B66}
.rowform.team .st.pending{background:#FBEFC4;color:#8A6400}
.rowform.team .st.waitlisted{background:var(--pink-soft);color:var(--pink-deep)}
.rowform.team .st.withdrawn{background:#EEE;color:#777}
.rowform.team .tsum .btn{flex:none}
/* Open: a two-column grid of fields under the line, every box the same width. */
.rowform.team .tedit{display:none;grid-template-columns:1fr 1fr;gap:10px;padding:4px 12px 12px 36px;border-top:1px solid var(--line2);background:var(--card2)}
.rowform.team.open .tedit{display:grid}
.rowform.team .tedit .fl{flex:none}
.rowform.team .tedit .fl.wide{grid-column:1/3}
.rowform.team .tedit .rowacts{grid-column:1/3;justify-content:flex-end;margin:2px 0 0}
/* A removed row is gone from the page; the save bar counts it until Save. */
.rowform.removing:not([data-kind="seasons"]){display:none}
@media (max-width:560px){
  .rowform.team .tedit{padding-left:12px}
}

/* The new-season sheet: the form sits in the sheet's body with the row's own padding. */
.sheetbody{padding:4px 19px 18px}
.sheetbody .rowform.block{padding:0}

/* ---------- switches, money, and two panels abreast ---------- */
.fl.sw{flex-direction:row;align-items:flex-start;gap:10px;cursor:pointer;position:relative}
.fl.sw input[type=checkbox]{position:absolute;opacity:0;width:1px;height:1px}
.fl.sw .knob{width:34px;height:20px;border-radius:999px;background:var(--line);position:relative;flex:none;margin-top:1px;transition:background .15s}
.fl.sw .knob::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.2);transition:left .15s}
/* On is green: dark ink read as off beside the pale track it slides along. */
.fl.sw input:checked+.knob{background:var(--live)}
.fl.sw input:checked+.knob::after{left:16px}
.fl.sw input:focus-visible+.knob{outline:2px solid var(--sky);outline-offset:2px}
.fl.sw .swtext{font-family:var(--body);font-size:13.5px;letter-spacing:0;text-transform:none;color:var(--ink);font-weight:500;line-height:20px}
/* The unit is part of the box, so the label never has to say "dollars". */
.money{display:flex;align-items:center;border:1px solid var(--line);border-radius:9px;background:var(--card);overflow:hidden}
.money b{padding-left:10px;color:var(--muted);font-weight:600;font-size:13.5px}
.fl .money input{border:0;border-radius:0;flex:1;min-width:0;padding-left:4px;width:auto}
.money i{font-style:normal;color:var(--muted);font-size:12.5px;padding-right:10px;white-space:nowrap}
/* A money box is the width of a number and its unit, however much room the row has. */
.fl:has(> .money){flex:0 1 190px}
/* A count that sits over a money box takes its width, so each count lines up with its fee. */
.fl.pair{flex:0 1 190px}
/* Three subjects in one panel: each a card2 box with its own small heading. */
/* Opened from the league page's "Edit in Setup", a panel lands with room above it. */
.panel[id]{scroll-margin-top:16px}
.subpanels{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:2px;align-items:start}
.subpanel{background:var(--card2);border:1px solid var(--line2);border-radius:12px;padding:14px 16px 16px;margin:0}
.subpanel.across{grid-column:1/-1}
.subpanel h3{font-family:var(--display);font-size:15px;font-weight:600;letter-spacing:.03em;margin:0 0 10px;display:flex;align-items:baseline;gap:8px}
.subpanel .rowform.block{padding:0}
/* A list inside a box: its rows are white on the box's grey, as on the page. */
.subpanel .rows{margin-top:0}
.subpanel .rowform:not(.block):not(.adding),.subpanel .rowform.adding.staged{background:var(--card)}
.subpanel .addhead{margin-top:16px}
/* Ends a line inside a block form, so related boxes start the next one together. */
.rowform.block .break{flex-basis:100%;height:0}
@media (max-width:760px){.subpanels{grid-template-columns:1fr}}

/* The ? beside a label: what the field means, on hover, focus or a tap.
   Whatever holds it is a flex line centred on its middle, so the ? sits level
   with caps labels, switch labels and headings alike; a vertical-align
   nudge only ever fitted one size of type. */
.fl>span,.fl.sw .swtext{display:flex;align-items:center;flex-wrap:wrap}
.tip{
  display:inline-grid;place-items:center;width:15px;height:15px;margin-left:6px;flex:none;
  border-radius:50%;border:1px solid var(--muted);color:var(--muted);background:none;
  font-size:0;letter-spacing:0;cursor:help;position:relative;padding:0;
}
.tip:hover,.tip:focus-visible,.tip.on{border-color:var(--ink);color:var(--ink)}
.tip::after{
  content:attr(data-tip);position:absolute;left:0;top:calc(100% + 6px);z-index:40;
  width:max-content;max-width:260px;padding:8px 10px;border-radius:9px;
  background:var(--ink);color:var(--paper);font:400 12.5px/1.4 var(--body);
  letter-spacing:0;text-transform:none;text-align:left;box-shadow:var(--shadow-lg);
  opacity:0;pointer-events:none;transition:opacity .12s;
}
.tip:hover::after,.tip:focus-visible::after,.tip.on::after{opacity:1}
