/* The calendar's drawing, shared by the app (index.html) and the static pages: the tokens, the week rows,
   the bars, the agenda and the match card. index.html links this before its own inline <style>, so the
   app's rules still come after these; nothing here names an app control. */

/* ---------- tokens: dark-first, light on request ---------- */
:root{
  color-scheme:dark;
  --bg:#0f1411; --surface:#161c18; --surface-2:#1c231e; --border:#283129; --border-strong:#36423a;
  --text:#e9ede9; --muted:#96a39a; --faint:#69756d;
  --accent:#e8b53f; --accent-ink:#1a1405;
  --c-test:#f0534f; --c-fc:#d98a6e; --c-odi:#5aa2ff; --c-t20:#2fd0a8;
  /* A women's match is the same format in the same family, turned one step round the wheel: every one of
     the four is its base hue +15° in HSL, saturation AND lightness left exactly where they were, so a
     women's bar reads as a shade of its own colour and never as the format next door.
     An earlier pass turned 20° to keep a women's Test clear of a men's first-class - those two sit 14° apart
     - and a pass after that cut it to an even slighter 9°, on the reasoning that every bar had come to
     carry its gender as a letter and the hue was only ever the second cue. No bar wears a letter now -
     the card behind a click names the gender - so on the grid the hue is the one thing that picks a
     women's bar out of a men's-heavy row. So 9° goes most of the way back - 15°, enough to register on
     its own, still a shade of the format and not the format next door.
     Holding `l` costs nothing at this angle, and nothing paints these tokens as text ink - no bar carries
     a badge - so they owe no contrast of their own; the fill they mix into is what --bar-muted below is
     checked against. Only the match bars wear any of this: the format chips and every bubble count stay
     on the base four. */
  --c-test-w:#f07b4f; --c-fc-w:#d9a56e; --c-odi-w:#5a79ff; --c-t20-w:#2fd0d0;
  --bar-mix:26%; --past-mix:13%;
  /* The second line inside a bar - the start time and the series - is read off the bar's own fill, never
     off the page, so it gets its own ink instead of the page's --muted. In this theme the two are the same
     colour and nothing moves; the light palette parts them, because a 40% fill leaves --muted at ~3:1 there
     and this line owes the same 4.5:1 the team name does. One token, set per theme, used only on a bar. */
  --bar-muted:var(--muted);
  --shadow:0 12px 36px rgba(0,0,0,.55);
  /* how wide the seven columns are drawn, everywhere: 1050px is a 150px day, enough for a start time and a
     duration to be read. Narrower screens scroll sideways inside #cal rather than squeezing the columns,
     so a phone sees the same day a laptop does. The script reads this token; it is not repeated in JS. */
  --grid-min:1050px;
}
@media (prefers-color-scheme: light){
  :root:not([data-theme="dark"]){
    color-scheme:light;
    --bg:#f4f6f2; --surface:#ffffff; --surface-2:#eef1ec; --border:#d9dfd8; --border-strong:#bcc6bd;
    --text:#171f1a; --muted:#5b685e; --faint:#8f9a92;
    --accent:#a86f00; --accent-ink:#ffffff;
    /* Light is not dark with the numbers flipped, and it had been drawn as though it were. Against white a
       15% tint of any of the four came out a wash - 1.2:1 on its own cell, the closest two of them 4.7 ΔE
       apart, a played match 4-6 ΔE off the same colour still to come: "impossibly bright and hard to
       differentiate", exactly. The whole fix is the two mix numbers and the four colours going into them,
       so chips, counts, play windows, ghosts and the agenda inherit it and not one element needs a filter.
       The mix goes 15% → 40% (past 8% → 17%), and the four are darkened for a white ground - first-class
       most of all, dropped to a low-chroma brown so it stops reading as a second red beside Test. Bars now
       sit ~1.9:1 on their cell, the closest pair is 17 ΔE, and past is 15-20 ΔE off its own upcoming colour.
       Label text keeps 8.6:1 against `--text`. The second line is the one thing the mix costs: the page's
       --muted reads 2.9-3.3:1 on a 40% fill, so on a bar it gives way to --bar-muted - the same hue carried
       down until it clears 4.5:1 on all eight fills (4.6-5.2 upcoming, 7.0-7.3 past) while staying a clear
       step lighter than --text's 8.4-9.5 there. Nothing off a bar uses it, so the page's own secondary text
       - day numbers, counts, chips, the "+N more" row - is left exactly where it was. */
    --c-test:#c02e2c; --c-fc:#71493d; --c-odi:#1d63bf; --c-t20:#0e7c64;
    --c-test-w:#c0532c; --c-fc-w:#71563d; --c-odi-w:#1d3abf; --c-t20-w:#0e787c;   /* the same +15° turn off this theme's own four, `s` and `l` held */
    --bar-mix:40%; --past-mix:17%; --bar-muted:#3f4a43;
    --shadow:0 12px 36px rgba(20,30,20,.18);
  }
}
:root[data-theme="light"]{
  color-scheme:light;
  --bg:#f4f6f2; --surface:#ffffff; --surface-2:#eef1ec; --border:#d9dfd8; --border-strong:#bcc6bd;
  --text:#171f1a; --muted:#5b685e; --faint:#8f9a92;
  --accent:#a86f00; --accent-ink:#ffffff;
  --c-test:#c02e2c; --c-fc:#71493d; --c-odi:#1d63bf; --c-t20:#0e7c64;            /* this palette and its two mixes are reasoned about on the block above */
  --c-test-w:#c0532c; --c-fc-w:#71563d; --c-odi-w:#1d3abf; --c-t20-w:#0e787c;
  --bar-mix:40%; --past-mix:17%; --bar-muted:#3f4a43;
  --shadow:0 12px 36px rgba(20,30,20,.18);
}

/* ---------- scoped resets ---------- */
/* The drawing was designed inside the app, whose body sets the font and whose element rules give a
   button the page's font and ink and a link the surrounding colour. A static page has other global rules
   (pages.css colours every link and has no button reset), so the few the drawing relies on are carried
   here, on its own classes. In the app they restate what the app already gives, and change nothing.
   .cfc is the root a widget's box wears: the 14px/1.45 Plex Sans the drawing was laid out in. */
.cfc{font:14px/1.45 "IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif}
/* The static pages' widget box. Its server-rendered state is one full-width button-link; the drawn
   widget goes above it. */
.cfc.calwidget{display:block;margin:0 0 20px}
/* The button reads as the link it is: bold, large and underlined, in the face of the site's own headings
   (Barlow Condensed 700, which every page already loads; Plex Sans is only loaded to 600). */
.cfc .calwidget-link{display:block;box-sizing:border-box;width:100%;padding:10px 16px;text-align:center;
  font:700 21px/1.3 "Barlow Condensed",system-ui,sans-serif;letter-spacing:.01em;
  color:var(--accent-ink);background:var(--accent);border-radius:8px;
  text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}
.cfc .calwidget-link:hover,.cfc .calwidget-link:focus-visible{text-decoration-thickness:3px}
/* pages.js draws this week and next above the button in the app's own box: the surface, border and radius
   #cal wears, with the month grid's seven columns scrolling sideways inside it where the box is narrower
   than --grid-min, as they do in #cal. While the feed loads the box holds the empty weeks' height with
   nothing shown, so the table below does not jump when the bars arrive. */
.cfc .calwidget-cal{margin:0 0 10px;background:var(--surface);border:1px solid var(--border);border-radius:10px;
  overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent}
.cfc .calwidget-cal.loading{visibility:hidden}
/* The box sits under the page's h1 and, with its button, fits the first screen. Two weeks of the grid always
   do; a phone's agenda of a busy fortnight runs past it, so its days scroll inside the box instead (360px is
   the header, title and button around it; 200px keeps a few days readable on a very short screen). pages.js
   holds the agenda's loading estimate to the same cap. */
.cfc .calwidget-cal.agenda{--calwidget-max:max(200px,calc(100svh - 360px));max-height:var(--calwidget-max);
  overflow-y:auto;overscroll-behavior-y:contain}
.cfc .calwidget-empty{margin:0 0 10px;max-width:none}
.ev,.more{font:inherit;color:inherit}
.pop a{color:inherit}

/* ---------- the week stream (month grid + agenda are two skins of the same rows) ---------- */
/* we re-pin the scroll ourselves when weeks are prepended or pruned, so the browser must not also try */
.stream{display:flow-root;overflow-anchor:none}
.stream.month{min-width:var(--grid-min)}   /* narrow screens scroll the seven columns sideways inside the scroller */
.stream>.wk:last-child{border-bottom-left-radius:10px;border-bottom-right-radius:10px}
.grid-head{display:grid;grid-template-columns:repeat(7,1fr);min-width:var(--grid-min);background:var(--surface)}
.grid-head[hidden]{display:none}
.dow{padding:8px 10px;font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);border-left:1px solid var(--border)}
.dow:first-child{border-left:0}
.dow.wkend{color:var(--faint)}
.wk.alt{background-color:color-mix(in srgb,var(--surface-2) 60%,var(--surface))}   /* alternating month tint */
.wk.mstart{border-top:2px solid var(--border-strong)}                              /* the week the 1st falls in */
.week{position:relative;display:grid;grid-template-columns:repeat(7,1fr);grid-template-rows:30px;grid-auto-rows:22px;row-gap:3px;min-height:132px;padding-bottom:8px;border-top:1px solid var(--border);
  background-image:linear-gradient(to right,var(--border) 1px,transparent 1px);background-size:calc(100%/7) 100%;background-position:-1px 0}
.day{grid-row:1;padding:5px 8px;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;display:flex;align-items:center;gap:6px}
.day .n{display:inline-grid;place-items:center;min-width:24px;height:24px;border-radius:12px;padding:0 5px}
.day.first{color:var(--text)}
.day.today .n{background:var(--accent);color:var(--accent-ink);font-weight:600}
.day .mon{font-size:11px;text-transform:uppercase;letter-spacing:.06em}
.ev{position:relative;margin:0 4px;height:22px;line-height:22px;padding:0 8px 0 6px;font-size:12px;border-radius:4px;border-left:3px solid var(--c);
  background:color-mix(in srgb,var(--c) var(--bar-mix),var(--surface));color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;
  display:flex;align-items:center;gap:6px;border-top:0;border-bottom:0;border-right:0;text-align:left;width:auto}
.ev:hover{background:color-mix(in srgb,var(--c) calc(var(--bar-mix) + 14%),var(--surface))}
.ev .t{font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:11px;color:var(--bar-muted);flex:none}
.ev .teams{font-weight:600;flex:none}
.ev .sub{color:var(--bar-muted);overflow:hidden;text-overflow:ellipsis;min-width:0}
.ev.cl{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:0}
.ev.cr{border-top-right-radius:0;border-bottom-right-radius:0;margin-right:0}
/* The overflow row is a lane like any other, so the label has to sit above what the lane draws under it:
   positioned, one step up, and haloed in the surface colour so it stays legible over a stack of ghosts. */
.more{appearance:none;border:0;background:none;text-align:left;font-size:11px;color:var(--muted);padding:0 10px;cursor:pointer;line-height:22px;
  position:relative;z-index:1;text-shadow:0 0 3px var(--surface),0 0 3px var(--surface),0 0 6px var(--surface)}
.more:hover{color:var(--text);text-decoration:underline}
/* A ghost is the hidden match's own bar, placed by the same routine at the same position, with its text
   and its handlers taken away and its colour turned down to ~1/N so N of them stacked read as a crowd
   rather than a slab. Decorative only: the "+N more" button above owns the row's meaning and its clicks. */
.ev.ghost{opacity:var(--ghost-o,1);pointer-events:none}
/* A highlight: a 1px ring on the bar's own outline, start edge included, in the colour of each profile that would show this match
   too (--hl, one hard-stopped arc per profile, laid on by mkBar). Cut out of a filled box by a mask, so the
   arcs follow the bar's corners and a continued bar's square end alike. */
.ev>i.hl{position:absolute;inset:0 0 0 -3px;z-index:2;border-radius:inherit;padding:1px;background:var(--hl);pointer-events:none;
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box exclude,linear-gradient(#000 0 0)}
/* The ring starts 3px left, over the bar's coloured start edge, which is its border and so outside the box a
   bar clips to; a highlighted bar clips 3px wider to let it through. Safari has no overflow-clip-margin and
   draws the ring inside the start edge instead. A solo chip clips nothing in the first place. */
.ev.lit:not(.solo){overflow:clip;overflow-clip-margin:3px}
.ev:focus-visible,.more:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* ---------- time-of-day bars ---------- */
/* A lane is a full-week strip that bars are placed into by pixel offset, so a match can start
   three-quarters of the way through Thursday instead of filling Thursday's whole column. Grid columns
   cannot say "0.73 of the way in", and two same-day bars sharing one grid area would simply overlap. */
.lane{position:relative;min-width:0}
.lane>.ev{position:absolute;top:0;margin:0}
/* A `.span` is one play window - the hours a match is actually on - painted bright over a dimmed bar, so a
   five-day Test reads as five days of play with four nights between them. A one-day match has one span,
   its whole duration. The bar itself runs on to its minimum label width; the 3px left border is the start
   edge and stays exactly where it always was. A multi-day window runs EXTRA_MS past its scheduled close
   and that tail is the gradient's fade to transparent, so the solid colour still stops at the scheduled
   time and the extra half hour reads as "maybe": the skin sets --fade as a share of the span's own width -
   placeBar in px, the agenda rail in per cent - and 0 leaves the span solid. */
.ev i.span{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:3px;pointer-events:none;
  --fill:color-mix(in srgb,var(--c) var(--bar-mix),var(--surface));--fade:0px;
  background:linear-gradient(to right,var(--fill) calc(100% - var(--fade)),transparent)}
.ev.tod{background:color-mix(in srgb,var(--c) 7%,var(--surface));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--c) 24%,var(--surface))}
.ev.tod>span{position:relative;z-index:1}
.ev.tod:hover{background:color-mix(in srgb,var(--c) 13%,var(--surface))}
.ev.tod:hover i.span{--fill:color-mix(in srgb,var(--c) calc(var(--bar-mix) + 14%),var(--surface))}
/* A one-day match has a single play window and it *is* the whole bar, so the chip is simply drawn at its
   true width - start edge to end time, no dim tail behind a label. The label no longer fits inside it, so
   it leaves the flex flow and is painted over the cell in body ink, from the chip's own left padding and
   running on for exactly the spill lane packing reserved for it (barMin, less that padding and the 4px
   gutter bars have always kept) - which is why it can never reach the next chip in the lane. That spill
   stops at the week, though: a Sunday-evening chip would otherwise run its label past the seventh column
   and hand #cal a horizontal scrollbar. So the box's left and width are the two properties fitLabels()
   overrides per chip - pulling it left until its right edge hugs that edge, never past the label before it,
   and trimming it if even that is not enough. The width comes from JS's own LBL_X/LBL_W on :root, so a
   label that fits is given neither of the two overrides, and the chip itself never moves whatever happens
   to its label. */
.ev.solo{overflow:visible;padding:0}   /* border-box: any padding would be a floor under the chip's width */
.ev.solo>.lbl{position:absolute;left:var(--lbl-x);top:0;bottom:0;width:var(--lbl-w);
  display:flex;align-items:center;gap:6px;overflow:hidden;color:var(--text)}
.ev.solo>.lbl>.t{color:var(--text)}
/* Room runs out from the right, and the teams are the one thing in the box that yields: a pair of long
   names is trimmed with an ellipsis rather than cut off mid-letter, which is what the box's own overflow
   used to do to whatever came after them. The start time stays flex:none - it is what a time-of-day chip
   is for. */
.ev.solo>.lbl>.teams{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}
/* A match that has been played is the same bar with its colour turned down: --past-mix instead of
   --bar-mix, which carries the background, the 3px start edge and the hover with it - no second set of
   rules, no second palette. It is given no play windows either, because a finished match has no "when
   it is on" left to say, so five days of Test read as one flat band; and the now line belongs to today's
   row, so it can never appear in the past at all. */
.ev.past{--bar-mix:var(--past-mix);color:var(--bar-muted);border-left-color:color-mix(in srgb,var(--c) 55%,var(--surface))}
.ev.past:hover{background:color-mix(in srgb,var(--c) calc(var(--past-mix) + 8%),var(--surface))}
.ev.past.solo>.lbl,.ev.past.solo>.lbl>.t{color:var(--muted)}
/* the now line: today's cell, at the current time. It is repositioned, never animated - there is nothing
   here for prefers-reduced-motion to turn off. */
.nowline{position:absolute;top:0;bottom:0;width:2px;background:var(--accent);border-radius:1px;z-index:6;pointer-events:none}
.nowline>i{position:absolute;left:-3px;top:-2px;width:8px;height:8px;border-radius:50%;background:var(--accent)}

/* ---------- agenda ---------- */
.wk-agenda{display:flow-root}
.mhead{padding:10px 12px 6px;font:600 20px/1 "Barlow Condensed","Arial Narrow",sans-serif;letter-spacing:.02em;color:var(--text);text-transform:uppercase;border-top:1px solid var(--border)}
.wk-empty{padding:7px 12px;font-size:11px;letter-spacing:.06em;color:var(--faint);border-top:1px solid var(--border)}
.dayrow{display:grid;grid-template-columns:76px 1fr;gap:10px;padding:10px 12px;border-top:1px solid var(--border)}
.stream>.wk:first-child>:first-child{border-top:0}
.dayrow .d{font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:12px;color:var(--muted);padding-top:3px;line-height:1.3}
.dayrow .d b{display:block;font:600 20px/1 "Barlow Condensed","Arial Narrow",sans-serif;color:var(--text);margin-bottom:2px}
.dayrow.today .d b{color:var(--accent)}
/* --rail-x: where the day's axis starts inside an entry - past the 3px start edge, which is the bar's
   colour and not a time. The rail and the now line are the only two things that stand on that axis, and
   they have to agree with each other, so the number is written once here and both read it back. */
.list{position:relative;display:grid;gap:4px;--rail-x:3px}
.ev.agenda{margin:0;white-space:normal;height:auto;min-height:26px;line-height:1.3;padding:4px 10px 4px 8px;flex-wrap:wrap}
.ev.agenda .sub{white-space:nowrap}
/* An agenda entry is one calendar day at whatever width .list has, so its axis is simply 00:00 to 24:00
   across that width and every play window is a percentage of it: no measuring, no CELL, and nothing to redo
   when the column changes size. The windows go in a slim rail along the bottom rather than behind the text,
   because the entry carries its time, teams and league across its whole width and painting the windows
   under that would give one line two contrasts along its length. The bar keeps the body month gives it
   rather than being dimmed to .tod: the body is not on the axis, the rail is, so turning it down would be
   a night the geometry never claimed - and it is the format's colour at a glance down the list, turned
   down by --past-mix once the match is over. So the rail carries the day instead: a neutral track for the
   whole of it, and the spans over it brighter than the body they sit on, by the same --bar-mix that dims
   with the rest of the bar. */
.ev.agenda.railed{padding-bottom:10px}   /* the rail's own room, reserved only where there is a rail */
.ev.agenda>i.rail{position:absolute;left:0;right:0;bottom:0;height:5px;pointer-events:none;
  background:color-mix(in srgb,var(--text) 14%,transparent);border-radius:3px}
.ev.agenda i.span{--fill:color-mix(in srgb,var(--c) calc(var(--bar-mix) + 45%),var(--surface))}
.ev.agenda:hover i.span{--fill:color-mix(in srgb,var(--c) calc(var(--bar-mix) + 59%),var(--surface))}
.nowline.agenda{left:calc(var(--rail-x) + (100% - var(--rail-x)) * var(--frac,0))}

/* ---------- popover ---------- */
.pop{position:fixed;z-index:50;width:340px;max-width:calc(100vw - 16px);background:var(--surface);border:1px solid var(--border-strong);border-radius:10px;box-shadow:var(--shadow);padding:14px 16px 16px}
.pop[hidden]{display:none}
.pop .x{position:absolute;top:8px;right:8px;width:28px;height:28px;border:0;background:none;border-radius:6px;cursor:pointer;color:var(--muted);font-size:18px;line-height:1}
.pop .x:hover{background:var(--surface-2);color:var(--text)}
.pills{display:flex;gap:6px;margin-bottom:8px;align-items:center}
.pill{font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:2px 8px;border-radius:999px;background:color-mix(in srgb,var(--c) 22%,var(--surface));color:var(--text);border-left:3px solid var(--c)}
/* the fold beside the pills: which tick puts this match on the calendar, one full folder path per line,
   in a box of its own laid over the card under the pills, so opening it moves nothing */
.pills{position:relative}
.pop .whylist{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:1;list-style:none;margin:0;padding:8px 10px;
  display:grid;gap:4px;font-size:12px;color:var(--muted);background:var(--surface);border:1px solid var(--border-strong);border-radius:8px;box-shadow:var(--shadow)}
.pop .whylist[hidden]{display:none}
.pop .whylist li{overflow-wrap:anywhere}
.pop .whylist b{color:var(--text);font-weight:600}
.pop h3{margin:0 0 2px;font:600 22px/1.15 "Barlow Condensed","Arial Narrow",sans-serif;letter-spacing:.01em;text-wrap:balance}
.pop .series{color:var(--muted);margin-bottom:10px}
.pop dl{margin:0 0 12px;display:grid;grid-template-columns:auto 1fr;gap:4px 10px;font-size:13px}
.pop dt{color:var(--faint);font-size:11px;text-transform:uppercase;letter-spacing:.08em;padding-top:2px}
.pop dd{margin:0}
.pop dd.mono{font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:12.5px}
.pop .acts{display:flex;gap:8px;flex-wrap:wrap}
.pop .acts a{font-size:12.5px;text-decoration:none;border:1px solid var(--border-strong);border-radius:6px;padding:5px 9px}
.pop .acts a:hover{border-color:var(--accent)}
.pop .daylist{max-height:60vh;overflow:auto}
/* A name in the popover with a page of its own (a team, the series, the ground): still the same text in
   the same colour, marked only by a dotted underline that goes solid under the pointer or the keyboard. */
.pop a.pg{color:inherit;text-decoration:underline dotted;text-decoration-thickness:1px;text-underline-offset:2px;border-radius:2px}
.pop a.pg:hover,.pop a.pg:focus-visible{text-decoration-style:solid}
.pop a.pg:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

@media (prefers-reduced-motion:no-preference){
  .ev{transition:background-color .12s,border-color .12s,color .12s}
}
