/* =========================================================================
   site.css — the style foundation, shared by the public pages and the admin
   SPA. Sections are in cascade order: tokens, reset, base, layout, components,
   utilities. A rule that has to come later than it reads is in the wrong
   section. See STYLE.md for the vocabulary and LAYOUT.md for the shape.
   ========================================================================= */

/* --- Tokens -------------------------------------------------------------- */

:root {
  /* Both, so the browser paints its own furniture — scrollbars, form controls,
     the flash before the first paint — to match whichever one is in use. */
  color-scheme: light dark;

  /* Space. One geometric scale. A value not on it is a decision to argue for. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  /* Type. Each size interpolates with the viewport and stops at both ends, so
     the scale needs no breakpoint and is never unreadable between two. */
  --font-body:
    system-ui, -apple-system, "Segoe UI", roboto, helvetica, arial, sans-serif;
  --text-sm: clamp(0.83rem, 0.8rem + 0.15vw, 0.9rem);
  --text-base: clamp(1rem, 0.96rem + 0.2vw, 1.12rem);
  --text-lg: clamp(1.2rem, 1.13rem + 0.35vw, 1.4rem);
  --text-xl: clamp(1.45rem, 1.33rem + 0.6vw, 1.75rem);
  --text-2xl: clamp(1.75rem, 1.55rem + 1vw, 2.2rem);
  --text-3xl: clamp(2.1rem, 1.78rem + 1.6vw, 2.8rem);
  --leading-tight: 1.2;
  --leading-body: 1.6;

  /* Measure. Prose is held to this however wide the bars run. */
  --measure: 65ch;

  /* Colour, named for the job it does and never for the hue it happens to be.
     --surface is what the page is laid on; --panel is what anything is read
     against. That distinction is what lets the page be tinted at all.

     These are the light values, and they are the whole palette for a browser
     that has never heard of light-dark(). The block after :root pairs each with
     its dark value for every browser that has. */
  --surface: #e6f2e6;
  --panel: #ffffff;
  --ink: #16181c;
  --ink-muted: #5b6069;
  /* The page's text at its strongest, for where --ink reads as grey: on the
     green of a card. Black in light; in dark, where black would be a hole, the
     pale ink. */
  --ink-strong: #000000;
  --accent: #398639;
  --accent-strong: #066b00;
  --accent-ink: #ffffff;
  --current: #000000;
  --current-ink: #ffffff;
  --link: #078600;
  --border: #cfe0cf;
  /* The line round a row of tabs and what they hold. */
  --tab-line: #398639;
  --focus: #0b2e17;
  --action: #066b00;
  --action-ink: #ffffff;
  --danger: #b3261e;
  /* The sport's own colour behind its code in a list, so that a reader can tell
     them apart at a glance. White on each in light and the page's near-black on
     each in dark, every pairing above 6:1. */
  --sport-ac: #066b00;
  --sport-gc: #1c5fb0;
  --sport-a6w: #a33a00;
  --sport-rc: #6b3fa0;
  --sport-gb: #0a6b6b;
  /* The alert that there is something new to read: the beta banner's yellow, so
     that the two notices read as one kind of thing and neither is the brand's
     green or a fault's red. The same in light and dark, since yellow is bright
     enough to stand out from either and takes the same near-black ink (15:1). */
  --notice: #ffeb3b;
  --notice-ink: #16181c;
  /* Where nothing can be, such as where a player meets themselves in a block's
     grid: blacked out, as the old site had it. */
  --void: #16181c;
  /* A score that won its game, as the old site had it: red. */
  --score-won: #b3261e;
  /* The thick line round a table and between its groups of columns. */
  --table-rule: #066b00;

  /* What a bar's contents are inset by, so that the site name lines up with the
     text in the panel below it rather than with the panel's edge. The panel's
     own inline padding, plus its border. */
  --panel-inset: calc(var(--space-5) + 1px);

  /* Shape. Two radii is a house style; five is an accident. */
  --radius-1: 0.3125rem;
  --radius-2: 0.5rem;
}

/* Light paired with dark, and which one applies follows color-scheme — so
   choosing a theme is one property on <html> rather than a second palette kept
   in step with the first.

   It sits behind @supports rather than as a second declaration beside each
   light value, because a custom property is not checked when it is declared.
   Written twice, "--surface: light-dark(...)" is accepted by a browser that
   cannot evaluate it and replaces the light value; the failure only arrives
   when background: var(--surface) is worked out, and a property that is
   invalid at that point falls back to transparent. The page would have lost its
   colours rather than landed on light. A browser that cannot answer this query
   skips the whole block and keeps the light values instead.

   Dark is not light inverted: the bars give up the brand's green for black,
   the section bar the darker and the header and footer a black a little
   lighter, as in light the section bar is the darker green, since a
   full-width band of green glares at night; the tile marking the current
   section turns pale because black on a dark bar reads as a hole; and links
   take a colour of their own because the dark green that works on white
   disappears on a dark panel. */
@supports (color: light-dark(#000, #fff)) {
  :root {
    --surface: light-dark(#e6f2e6, #10140f);
    --panel: light-dark(#ffffff, #191e18);
    --ink: light-dark(#16181c, #e7ece5);
    --ink-muted: light-dark(#5b6069, #a6b0a3);
    --ink-strong: light-dark(#000000, #e7ece5);
    --accent: light-dark(#398639, #20201f);
    --accent-strong: light-dark(#066b00, #111111);
    --accent-ink: light-dark(#ffffff, #f3f7f1);
    --current: light-dark(#000000, #e7ece5);
    --current-ink: light-dark(#ffffff, #10140f);
    --link: light-dark(#078600, #7fd08d);
    --border: light-dark(#cfe0cf, #2c332b);
    /* The header's green in light; in dark, where the header is black and a
       black line is lost on the dark panel, the line every other border is
       drawn in. */
    --tab-line: light-dark(#398639, #2c332b);
    --focus: light-dark(#0b2e17, #8fd99b);
    /* The button that does what a form is for. The section navigation's colour
       in light; pale in dark, because the section navigation's dark green on a
       dark dialog reads as a hole rather than as the thing to press. */
    --action: light-dark(#066b00, #7fd08d);
    --action-ink: light-dark(#ffffff, #10140f);
    /* What needs the reader's attention. Red in both, and never below 4.5:1 on
       the content it sits on: 6.54:1 in light, 7.42:1 in dark. */
    --danger: light-dark(#b3261e, #ff8a80);
    --sport-ac: light-dark(#066b00, #7fd08d);
    --sport-gc: light-dark(#1c5fb0, #8ab8f0);
    --sport-a6w: light-dark(#a33a00, #f0a07a);
    --sport-rc: light-dark(#6b3fa0, #c3a6e8);
    --sport-gb: light-dark(#0a6b6b, #6fd3d0);
    /* Darker than the dark panel rather than the pale ink, which on a dark
       page would read as something to look at rather than as nothing. */
    --void: light-dark(#16181c, #050605);
    /* Red in both, and never below 4.5:1 on the panel. */
    --score-won: light-dark(#b3261e, #ff8a80);
    /* The section bar's green in light; in dark, where the bar is black and a
       black line is lost on the dark panel, the muted ink, which is not. */
    --table-rule: light-dark(#066b00, #a6b0a3);
  }
}

/* What a reader has asked for, when they have asked. Without either attribute
   the browser's own preference decides, which is what color-scheme: light dark
   on :root already says. */
:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

/* --- Reset --------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd,
ul,
ol {
  margin: 0;
}

ul[class],
ol[class] {
  padding: 0;
  list-style: none;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* A list's options are drawn in the ink on the panel in light, and white on
   #3b3b3b in dark, where some browsers drew the ink, which is light, on a light
   ground (issue 456). The picker of a list that is drawn by the page rather
   than the browser is the same. Behind the query the colours above are behind:
   a browser that cannot answer it draws the options as it always did. */
@supports (color: light-dark(#000, #fff)) {
  select option,
  select optgroup,
  select::picker(select) {
    background: light-dark(var(--panel), #3b3b3b);
    color: light-dark(var(--ink), #fff);
  }
}

/* --- Base ---------------------------------------------------------------- */

html {
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

h1,
h2,
h3,
h4 {
  line-height: var(--leading-tight);
  text-wrap: balance;
}

h1 {
  font-size: var(--text-3xl);
}

h2 {
  font-size: var(--text-2xl);
}

h3 {
  font-size: var(--text-xl);
}

p,
li {
  /* Long words break rather than push the layout sideways. */
  overflow-wrap: break-word;
  text-wrap: pretty;
}

a {
  color: var(--link);
  text-decoration-thickness: max(1px, 0.06em);
  text-underline-offset: 0.15em;
}

a:hover {
  text-decoration-thickness: max(2px, 0.1em);
}

/* Nothing removes an outline without putting something better in its place. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-1);
}

/* On the green bars a dark ring disappears, so it turns white there. */
.site-sections :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--accent-ink);
}

/* A reader who asked for stillness gets it. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* The admin's mount point, which stands between the body and the main the
   admin draws. Out of the way, main is in the body's own column beside the
   header and footer the server puts round it, as it is on every other page,
   and pushes the footer to the foot of the window rather than leaving it under
   a short page. */
#root {
  display: contents;
}

/* --- Layout primitives --------------------------------------------------- */

/* The bars run the full width of the window, so .page holds their contents off
   the window edge rather than centring them in a column. */
.page {
  width: 100%;
  padding-inline: var(--space-4);
}

/* Vertical rhythm as a gap, so it cannot double against a neighbour's margin. */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.stack-loose {
  gap: var(--space-6);
}

/* A horizontal group that wraps when it runs out of room. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

/* Needs no breakpoint: the columns decide for themselves. */
.grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}

/* --- Components ---------------------------------------------------------- */

/* The first focusable thing on the page, past the navigation. */
.skip-link {
  position: absolute;
  inset-inline-start: var(--space-3);
  top: var(--space-3);
  z-index: 10;
  padding: var(--space-2) var(--space-4);
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-1);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

/* The green bar, full width and pinned to the top of the window, as the current
   site's is. It is a sibling of everything else rather than a child of the
   title strip, because a sticky element only sticks within its own container:
   nested in the header, it would scroll away the moment the header did. */
.site-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--accent);
  color: var(--accent-ink);
}

/* Centred in the height of the bar, so that where it is taller for a
   tournament's name beneath the site's, the search, the menu and the account
   stand level with the middle of the names rather than at the top of them. */
.site-bar-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: 10px;
  padding-inline: var(--panel-inset);
}

/* A heading of the help that an address leads to stops beneath the pinned bar,
   which is taller where it wraps, and not under it. */
.help [id] {
  scroll-margin-top: 6rem;
}

/* The first page does not show its title: the panel above it says where the
   reader is. Nor the heading over the subjects, which are cards that say what
   they are. It is kept for a screen reader, which has the title and nothing
   else to say the page is the help, by being made one pixel and clipped. */
.help-first-title,
.help[data-page=""] #subjects {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The first page of the help: the popular questions as a list of links, and the
   subjects as cards. Both are lists written in Markdown, found here by the
   bookmarks of the headings they follow (docs/help/<language>/index.md), so the
   page needs no markup of its own and a translator writes only the words. */
/* The popular questions are a card, drawn in two parts because the heading and
   the list are two elements of the page: the heading is the top of it and the
   list the rest, with the line between them left out. It is the colour of the
   alternating rows of the site's lists, as the subjects' cards are. The page's
   column puts 1rem between the panel and this, and the grid of subjects puts
   its own 1rem between this and it. */
.help[data-page=""] #popular-questions {
  margin: 0;
  padding: var(--space-4) var(--space-4) var(--space-2);
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--radius-2) var(--radius-2) 0 0;
  background: var(--surface);
}

.help[data-page=""] #popular-questions + ul {
  margin: 0;
  padding: 0 var(--space-4) var(--space-4) calc(var(--space-4) + var(--space-5));
  border: 1px solid var(--border);
  border-top: 0;
  border-radius: 0 0 var(--radius-2) var(--radius-2);
  background: var(--surface);
}

.help[data-page=""] #popular-questions + ul li + li {
  margin-top: var(--space-2);
}

/* As many cards in a row as fit at a readable width, and one on a phone. The
   minimum is under the narrowest screen's content width so that the grid never
   asks for more than there is. */
.help[data-page=""] #subjects + ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-4);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
}

.help[data-page=""] #subjects + ul li {
  position: relative;
  margin: 0;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
  background: var(--surface);
}

.help[data-page=""] #subjects + ul li p {
  margin: 0;
}

/* The card's title is the link, and the link is spread over the whole card, so
   that the card is one thing to press and one stop for the keyboard and for a
   screen reader, with no second link in it. */
.help[data-page=""] #subjects + ul li p:first-child {
  font-size: var(--text-lg);
  font-weight: 700;
}

.help[data-page=""] #subjects + ul li p:first-child a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.help[data-page=""] #subjects + ul li p + p {
  margin-top: var(--space-2);
  color: var(--ink-strong);
  font-size: var(--text-sm);
}

.help[data-page=""] #subjects + ul li:hover {
  border-color: var(--accent);
}

/* The card that has the keyboard in it is marked on the card, which is what is
   pressed, and not on the title alone. */
.help[data-page=""] #subjects + ul li:focus-within {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}

.help[data-page=""] #subjects + ul li a:focus {
  outline: none;
}

/* The panel at the top of the help in which a question is typed and the pages
   that answer it are listed. It sits above the article, apart from it by a rule,
   and its results are a list of links each holding the page's title and the
   words around the match. */
/* The search box is a card, as the popular questions and the subjects are: the
   colour of the alternating rows of the site's lists, with the same line and
   corners. The page's column puts 1rem between it and the next. */
.help-search {
  margin: 0;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
  background: var(--surface);
}

/* The panel's title and the headings of the first page's other sections are one
   size, which is smaller than a second level heading is elsewhere: they head
   three parts of one page, and none is to read as more than the others. */
.help-search-title,
.help[data-page=""] h2 {
  color: var(--ink-strong);
  font-size: var(--text-lg);
  font-weight: 700;
}

.help-search-title {
  margin: 0 0 var(--space-2);
}

.help-search form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.help-search input {
  flex: 1 1 14rem;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
  background: var(--panel);
  color: var(--ink-strong);
  font: inherit;
}

.help-search button {
  padding: var(--space-2) var(--space-4);
  border: 0;
  border-radius: var(--radius-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  font: inherit;
  cursor: pointer;
}

.help-search-note {
  margin: var(--space-3) 0 0;
  color: var(--ink-strong);
}

.help-search-note:empty {
  display: none;
}

.help-search-results {
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

/* Nothing asked yet, so nothing to leave room for beneath the box. */
.help-search-results:empty {
  margin: 0;
}

.help-search-results li + li {
  margin-top: var(--space-3);
}

.help-search-results a {
  display: block;
  text-decoration: none;
  color: var(--ink);
}

.help-search-result-title {
  display: block;
  color: var(--link);
  font-weight: 700;
  text-decoration: underline;
}

.help-search-snippet {
  display: block;
  color: var(--ink-strong);
  font-size: var(--text-sm);
}

.help-search-snippet mark {
  background: transparent;
  color: var(--ink-strong);
  font-weight: 700;
}

/* The page's own title, on a green strip below the pinned bar. It scrolls away
   with the page, which is what the current site does and what keeps a
   three-line tournament name off a phone screen once reading has started. */
.site-title-bar {
  background: var(--accent);
  color: var(--accent-ink);
}

/* A tournament's notes, on a green strip below the pinned bar, so that they
   read as said beneath the tournament's name. They scroll away with the page,
   as the title strip does, so that notes of several lines do not keep a phone's
   screen from what the page says. Set in from the edge as the tournament's name
   is, so that the two line up. */
.tournament-subtitle {
  background: var(--accent);
  color: var(--accent-ink);
}

.tournament-subtitle-text {
  padding-inline: var(--panel-inset);
  padding-bottom: var(--space-2);
}

.tournament-subtitle-text > * {
  margin: 0;
  max-width: none;
}

.tournament-subtitle-text > * + * {
  margin-top: var(--space-2);
}

/* In the strip's own colour, and underlined to say they are links, since the
   site's link colour is measured against the panel rather than the green. */
.tournament-subtitle-text a {
  color: inherit;
  text-decoration: underline;
}

/* Above everything, where the site is served from an address that is not one of
   the two websites: the site is a beta and what is entered may be thrown away.
   Black on bright yellow in both themes, because it is a warning and has to
   look like one rather than like part of the page; the pairing is 17:1. */
.beta-banner {
  background: #ffeb3b;
  color: #000;
  text-align: center;
}

.beta-banner p {
  margin: 0;
  max-width: none;
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  font-weight: 700;
}

/* On a try website, the line saying it is somewhere to learn. The beta
   banner's own colours and place, since both say that what is entered may be
   thrown away and a reader should know the one by having met the other. */
.try-banner {
  background: #ffeb3b;
  color: #000;
  text-align: center;
}

.try-banner p {
  margin: 0;
  max-width: none;
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  font-weight: 700;
}

/* The alert that there is something new to read: a message, the way to read
   it, and the two ways of putting the alert away. In the notice yellow, which is
   neither the brand's green nor a fault's red, so that it stands out from the
   panel it sits on. The choices wrap beneath the message on a phone. */
.whats-new {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-2);
  background: var(--notice);
  color: var(--notice-ink);
}

.whats-new p {
  margin: 0;
  max-width: none;
  font-weight: 700;
}

.whats-new-choices,
.whats-new-choices form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.whats-new button {
  min-height: 44px;
  padding-inline: var(--space-3);
  background: transparent;
  color: inherit;
  border: 1px solid currentcolor;
  border-radius: var(--radius-2);
  cursor: pointer;
}

.whats-new-view {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-3);
  background: var(--notice-ink);
  color: var(--notice);
  border-radius: var(--radius-2);
  font-weight: 700;
  text-decoration: none;
}

/* The admin's page has its alert said into it by the server, before the admin
   has drawn anything, so it is in the DOM above the years the admin draws. It
   belongs beneath them, as the home page's is beneath its years, so it is moved
   there by order, which needs no script and so holds before one has run. The
   mount point does not box (#root above), which is what makes the years, the
   main and the alert siblings. The alert is outside any panel, so it is set in
   the page's width. */
.whats-new-bar {
  order: 1;
  padding-block-start: var(--space-3);
}

#root > main,
#root > main ~ * {
  order: 2;
}

body > .site-footer {
  order: 3;
}

/* The site's name, and beneath it, on a tournament's pages, the tournament's,
   set alike so that the two read as one title. */
.site-names {
  display: flex;
  flex-direction: column;
}

.site-name,
.site-tournament,
.site-page {
  color: var(--accent-ink);
  font-size: var(--text-lg);
  font-weight: 700;
  text-decoration: none;
  padding-block: var(--space-1);
}

/* Close beneath the site's name, so that the two read as one title rather
   than as two things in the bar: nothing between them but the lines
   themselves, set tight. */
.site-names:has(.site-tournament, .site-page) .site-name {
  padding-bottom: 0;
}

.site-names:has(.site-tournament, .site-page) {
  line-height: var(--leading-tight);
}

.site-tournament,
.site-page {
  padding-top: 0;
}

/* Long tournament names wrap onto as many lines as they need: the name is the
   page, and truncating it would lose the one thing the reader came for. */
.page-title {
  margin: 0;
  max-width: none;
  padding-inline: var(--panel-inset);
  padding-bottom: var(--space-3);
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: var(--leading-tight);
  color: var(--accent-ink);
}

/* The site name is at one end and the navigation and the account menu together
   at the other: the bar spreads what is in it, and without this the navigation
   would sit in the middle once the menu joined it. */
.site-bar-inner > .menu {
  margin-inline-start: auto;
}

/* The site's search, in the menu's panel before the links: beside them in the
   bar, and at the top of what the menu button opens on a phone. */
.site-search {
  display: flex;
  align-items: center;
  /* Centred in the height of the bar, which is taller where a tournament's
     name is beneath the site's, rather than left at the top with the menu. */
  align-self: center;
  gap: var(--space-1);
  min-width: 0;
  max-width: 100%;
  margin-block-end: var(--space-2);
}

/* Read against the page's own surface and ink, as a field is everywhere, and
   not against the bar's green: the field inherits the bar's white ink, which
   on a white field is not there. */
.site-search input {
  min-width: 0;
  width: 10rem;
  max-width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
  background: var(--panel);
  color: var(--ink);
}

/* In the secondary navigation's colours, and filled as its tab being read is
   when it is hovered, since a hover in the bar's own green would be nothing. */
.site-search button {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  cursor: pointer;
}

.site-search button:hover {
  background: var(--current);
  color: var(--current-ink);
}

/* The way home is a house, which sits on the line with the words beside it. */
.menu-icon {
  display: block;
}

/* Closed until the glass is pressed, which only a page with scripting does
   (layout.ts): without it nothing could open the field. */
.site-search-closed input {
  display: none;
}

/* The page of players' own search, in the content as the results are. */
.players-search {
  display: flex;
  gap: var(--space-1);
  max-width: 38rem;
  margin-block-end: var(--space-4);
}

.players-search input {
  flex: 1;
  min-width: 0;
}

/* What a search found, a list to each kind under its heading, drawn as the
   games of a tournament's Recent page are: headed in the section bar's colours
   and banded, drawn up against the heading as one table. The competition has
   the tournament it is in beside it. */
.search-list {
  margin-block-end: var(--space-4);
}

/* Against the heading by having no margin of its own and the heading none
   beneath it, and not by being pulled up over a margin that the heading may
   not have, which is what left the heading on the first row. */
.search-list > h2,
.players-search-heading {
  margin: 0;
}

.search-list ul,
.players-search-found {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border);
  border-top: 0;
}

.search-list li,
.players-search-found li {
  padding: var(--space-2);
  overflow-wrap: anywhere;
}

.search-list li + li,
.players-search-found li + li {
  border-top: 1px solid var(--border);
}

.search-list li:nth-child(even),
.players-search-found li:nth-child(even) {
  background: var(--surface);
}

/* A player's tournaments, drawn as the other lists of the public site are:
   headed in the section bar's colours, bordered and banded. */
.player-tournaments {
  width: 100%;
  max-width: 38rem;
  border-collapse: collapse;
  margin-block-end: var(--space-4);
}

.player-tournaments th {
  padding: var(--space-1) var(--space-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-size: var(--text-lg);
  text-align: start;
}

.player-tournaments th a {
  color: inherit;
}

.player-tournaments td {
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-top: 0;
  overflow-wrap: anywhere;
}

.player-tournaments tbody tr:nth-child(even) td {
  background: var(--surface);
}

.search-of {
  color: var(--ink-muted);
}

/* The tournaments and the competitions found are tables, drawn as the lists of
   tournaments are (their heading is then plain, since the table's own heads
   are in the section bar's colours), so a list of players is the only one
   that is a heading over a list. The tournament a competition is in is lifted
   above the competition's link, which reaches over the whole row, and wraps
   as a long name does. */
.search-list.tournament-list > h2 {
  padding: 0;
  background: none;
  color: inherit;
  font-size: inherit;
}

/* The dates take the width of the widest and no more, in the lists found and on
   a player's page: a cell as narrow as a percentage can make it is stretched by
   what is in it, which does not wrap, so that on a phone it is the
   tournament's name that wraps. */
.search-list .tournament-dates,
.player-tournaments .tournament-dates {
  width: 1%;
  white-space: nowrap;
}

.tournament-list .search-of {
  position: relative;
  z-index: 1;
  overflow-wrap: anywhere;
}

/* The account menu: the last thing in the header, a person that opens on what
   a reader can do with their account. A disclosure at every width, unlike the
   primary navigation, because it is a menu rather than navigation that happens
   to be collapsed: its items are pages of one reader's own.

   Its items are read against the panel's surface rather than the bar's green,
   so that what is read there is read the way everything else on the site is. */
.account-menu {
  position: relative;
}

.account-menu > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  min-width: 44px;
  min-height: 44px;
  border-radius: var(--radius-1);
  cursor: pointer;
  list-style: none;
}

.account-menu > summary::-webkit-details-marker {
  display: none;
}

.account-menu > summary:hover,
.account-menu > summary:focus-visible {
  background: var(--accent-strong);
}

/* One shape, drawn in the markup so that it costs no request and takes the
   colour of the words beside it. */
.account-menu .person {
  width: 1.5em;
  height: 1.5em;
  fill: currentcolor;
}

.account-menu-links {
  position: absolute;
  inset-inline-end: 0;
  z-index: 5;
  margin-top: var(--space-2);
  padding: var(--space-2);
  min-width: 14rem;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
}

.account-menu-links ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A link and the sign-out button read as one list: signing out is a button
   because it posts, and looking different would say it was something else. */
.account-menu-links a,
.account-menu-links button {
  display: flex;
  align-items: center;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  min-height: 44px;
  border: 0;
  border-radius: var(--radius-1);
  background: none;
  color: var(--link);
  font: inherit;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}

.account-menu-links a:hover,
.account-menu-links a:focus-visible,
.account-menu-links button:hover,
.account-menu-links button:focus-visible {
  background: var(--surface);
}

/* The page being read, marked as the section bar and the primary navigation
   mark theirs: black in light, pale in dark, and not underlined, so that being
   here looks the same wherever it is said. */
.account-menu-links a[aria-current="page"] {
  background: var(--current);
  color: var(--current-ink);
}

/* The primary navigation. Below 40rem, or in a window taller than it is wide,
   it is collapsed behind the disclosure; otherwise the disclosure control is
   not rendered and the links sit inline.
   <details> opens, closes, takes focus and announces itself without script,
   which is what the public side requires of it. */
.menu {
  position: relative;
}

.menu > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  min-height: 44px;
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius-1);
  cursor: pointer;
  list-style: none;
}

.menu > summary::-webkit-details-marker {
  display: none;
}

.menu > summary::before {
  content: "";
  width: 1.25em;
  height: 1em;
  background:
    linear-gradient(currentcolor, currentcolor) 0 0 / 100% 2px no-repeat,
    linear-gradient(currentcolor, currentcolor) 0 50% / 100% 2px no-repeat,
    linear-gradient(currentcolor, currentcolor) 0 100% / 100% 2px no-repeat;
}

/* Three bars become a cross: a plus sign turned through 45 degrees. */
.menu[open] > summary::before {
  background:
    linear-gradient(currentcolor, currentcolor) 50% 50% / 100% 2px no-repeat,
    linear-gradient(currentcolor, currentcolor) 50% 50% / 2px 100% no-repeat;
  transform: rotate(45deg);
}

/* What the button opens: the navigation and, beneath it, the account. The box
   is drawn here rather than on each, so that the two read as one menu. */
.menu-panel {
  position: absolute;
  inset-inline-end: 0;
  z-index: 5;
  margin-top: var(--space-2);
  padding: var(--space-2);
  min-width: 12rem;
  background: var(--accent);
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius-2);
}

.menu-links ul,
.menu-account ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.menu-links a,
.menu-account a,
.menu-account button {
  display: flex;
  align-items: center;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  min-height: 44px;
  border: 0;
  border-radius: var(--radius-1);
  background: none;
  color: var(--accent-ink);
  font: inherit;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}

.menu-links a:hover,
.menu-links a:focus-visible,
.menu-account a:hover,
.menu-account a:focus-visible,
.menu-account button:hover,
.menu-account button:focus-visible {
  background: var(--accent-strong);
}

/* Set off from the navigation above it by a rule and a heading, since the two
   are lists of different things and read as one without them. */
.menu-account {
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--accent-ink);
}

.menu-account-heading {
  margin: 0 0 var(--space-1);
  padding-inline: var(--space-3);
  font-weight: 700;
}

/* Below the breakpoint the person gives way to the group above. */
.account-menu {
  display: none;
}

/* The page being read is marked as the section being read is: black in light,
   pale in dark, and not underlined, which read as a link like any other. */
.menu-links a[aria-current="page"],
.menu-account a[aria-current="page"] {
  background: var(--current);
  color: var(--current-ink);
}

/* From the width of a small tablet, and only while the window is wider than it
   is tall, the links are the navigation and the disclosure has nothing to
   disclose: a tablet held upright is pressed as a phone is. @media cannot read
   a custom property, which is why 40rem is written out rather than tokenised. */
@media (min-width: 40rem) and (orientation: landscape) {
  .menu > summary {
    display: none;
  }

  /* The search and the links on one line, the search first. */
  .menu {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  .site-search {
    margin-block-end: 0;
  }

  /* A closed <details> hides everything but its summary, so hiding the summary
     is not enough: the navigation has to be let out too. Browsers do the hiding
     through ::details-content now and did it through the child's own display
     before, which is why both are set. Verified in a browser, because the first
     version of this rule left the navigation invisible at every width above the
     breakpoint and read perfectly well on the page. */
  .menu::details-content {
    content-visibility: visible;
    display: contents;
  }

  /* A row of its own for the search and the links, and not display: contents.
     Where a closed menu cannot be let out through ::details-content, an open
     one keeps its contents in a block of the browser's making, and children
     promoted past the panel stand one above the next in it: the search above
     the home icon on an iPad. A row of the panel's own is a row either way. */
  .menu-panel {
    position: static;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    min-width: 0;
    background: none;
    border: 0;
  }

  .menu-account {
    display: none;
  }

  .account-menu {
    display: block;
  }

  .menu-links ul {
    flex-direction: row;
    gap: var(--space-2);
  }

  /* Inline in a bar, these are mouse targets and the bar should not be tall for
     their sake. The ones inside the disclosure keep their 44px, because that is
     where a thumb finds them. */
  .menu-links a {
    min-height: 36px;
    padding-block: var(--space-1);
  }
}

/* The dark green bar beneath the header, on pages that have sections to move
   between. Its tabs wrap onto as many rows as they need and collapse behind
   nothing: they are the page's own sections, and hiding them would hide the
   page. */
.site-sections {
  background: var(--accent-strong);
  color: var(--accent-ink);
}

.site-sections ul {
  display: flex;
  flex-wrap: wrap;
  /* 8px of the bar's green above and below the tabs, so that the current
     one is a tile in the bar and not the bar's whole height. There is still no
     row gap, so the black of a tab runs between wrapped rows. */
  gap: 0 var(--space-2);
  margin: 0;
  padding-block: 8px;
  padding-inline: var(--panel-inset);
  list-style: none;
}

/* 10px on every side of a tab's words, competitions' tiles included, so that
   the tabs are as easy to point at as they are to read. */
.site-sections a {
  display: flex;
  align-items: center;
  align-self: stretch;
  padding: 10px;
  color: var(--accent-ink);
  text-decoration: none;
}

/* A tournament's competitions are tiles of one width, as the old site had
   them, since their names run long: "Championship Singles Block A" wraps
   within its tile onto tight lines of its own, and the tiles stand in even
   columns rather than running on in a ragged line. The tournament's own
   sections beside them, Recent, Players, Notes and Commentary, are only as
   wide as their words. Every tab of such a bar is as tall as its own words
   rather than its row, so that the current one beside a name of three lines
   is not a tall block of black. */
.site-sections ul:has(.section-competition) {
  align-items: flex-start;
}

.site-sections ul:has(.section-competition) a {
  align-items: flex-start;
  align-self: start;
  /* No shorter than a pointer can be sure of pressing, as every tab is asked
     to be (TournamentSections.feature), though its words are set tight. */
  min-height: 24px;
  line-height: var(--leading-tight);
}

.section-competition {
  flex: 0 0 8.5rem;
}

.section-competition a {
  overflow-wrap: break-word;
}

.site-sections a:hover {
  background: var(--accent);
}

/* The section being read is unmistakable rather than merely different: black in
   light, pale in dark. Either way it is the one tile that is not the colour of
   the bar. */
.site-sections a[aria-current="page"] {
  background: var(--current);
  color: var(--current-ink);
}

/* What anything is actually read against. The page behind it is tinted; this
   is not. */
.panel {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
  padding: var(--space-5);
}

main {
  flex: 1;
  padding-block: var(--space-5);
}

.site-footer {
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--text-sm);
}

.site-footer-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  padding-block: var(--space-4);
  padding-inline: var(--panel-inset);
}

.site-footer p {
  max-width: var(--measure);
}

.site-footer a {
  color: var(--accent-ink);
}

.site-footer .copyright {
  margin-inline-start: auto;
  text-align: end;
}

/* Which build this is: a thing to say back when reporting a problem. Not
   dimmed to sit quietly: white on the footer's green is already short of the
   contrast wanted (STYLE.md), and less would be worse. */
.site-footer .site-version {
  font-variant-numeric: tabular-nums;
}

/* The links to find rather than to read, on a row of their own beneath the
   donation and the copyright and at the right, where the theme and language
   choices beneath them end. They wrap on a phone, and are still at the right. */
.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2) var(--space-5);
  padding-inline: var(--panel-inset);
  padding-bottom: var(--space-3);
}

/* A row of its own beneath the footer proper. The theme is a setting rather
   than something to read, so it sits apart from the donation and the copyright
   instead of competing with them for the same line. */
.site-footer-theme {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-4);
  padding-inline: var(--panel-inset);
  padding-bottom: var(--space-4);
}

.theme,
.language {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.theme-options {
  display: flex;
  gap: var(--space-1);
}

/* 44px at every width. These are on screen on a phone and pressed with a thumb;
   the 36px the inline navigation is allowed is for links pointed at with a
   mouse above the breakpoint, and does not reach down here. */
.theme button,
.language button,
.language select {
  min-height: 44px;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius-1);
  background: none;
  color: var(--accent-ink);
  cursor: pointer;
}

.theme button:hover,
.language button:hover {
  background: var(--accent-strong);
}

/* The one in force is filled rather than outlined, so it is told apart by more
   than a shade of green. */
.theme button[aria-current="true"] {
  background: var(--accent-ink);
  color: var(--accent);
  font-weight: 700;
}

/* The label on the list's top border, drawn as a field's label is once the
   field holds something (.field-box), since a list is never empty. The field's
   label is placed from inside the box's 1px border and this one from outside
   the list's, so each offset here is a pixel more to land in the same place. */
.language-box {
  position: relative;
  display: flex;
}

.language-box label {
  position: absolute;
  top: -2px;
  inset-inline-start: calc(var(--space-3) + 1px);
  margin-inline-start: calc(-1 * var(--space-1));
  padding-inline: var(--space-1);
  transform: translateY(-50%);
  background: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: var(--leading-tight);
  white-space: nowrap;
}

/* The list is drawn on the green bar like the buttons beside it, and opens
   onto the colours every list's options are drawn on, which are the page's
   own in light. */
.language option {
  background: light-dark(var(--panel), #3b3b3b);
  color: light-dark(var(--ink), #fff);
}

.donate button {
  padding: var(--space-2) var(--space-5);
  min-height: 44px;
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius-1);
  background: var(--accent-ink);
  color: var(--accent-strong);
  font-weight: 700;
  cursor: pointer;
}

.donate button:hover {
  background: var(--surface);
}

/* A form that is a page's purpose. It stands on the page's own background in
   place of the panel, centred across the page, and reads from its title, to its
   content, to its buttons. It is a page region rather than an overlay, so
   nothing here dims, traps focus or needs dismissing. */
.dialog {
  max-width: 32rem;
  margin-inline: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
}

/* Each part carries its own background and the radius of the corner it sits in,
   rather than the dialog clipping them with overflow: hidden — which would also
   clip the focus ring of any control near its edge. */
.dialog-title {
  margin: 0;
  max-width: none;
  padding: var(--space-3) var(--space-5);
  border-radius: calc(var(--radius-2) - 1px) calc(var(--radius-2) - 1px) 0 0;
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-size: var(--text-lg);
}

.dialog-content {
  padding: var(--space-5);
  background: var(--panel);
  color: var(--ink);
}

/* Stacked, each as wide as the fields: the row's padding is the content's, so
   a button stretched across it is as wide as a field. The submit button is
   first in the markup, and so at the top. */
.dialog-buttons {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
  border-radius: 0 0 calc(var(--radius-2) - 1px) calc(var(--radius-2) - 1px);
  background: var(--panel);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* The field's border, one line tall: the same padding and border as a button,
   so that a field and the button beneath it are the same height. The ring for
   the field is drawn here rather than on the input, because the box is what the
   reader sees as the field. The box is itself the <label>, so the text cursor
   over it is the truth: pressing anywhere inside the border, padding included,
   reaches the input. */
.field-box {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius-1);
  background: var(--panel);
  cursor: text;
}

.field-box:focus-within {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* At rest the label lies on the line the typing will go on, at the size of the
   typing, so the field needs no second line to name itself. The box does not
   grow to hold it, so a label too long for the box is cut short inside the
   box's padding rather than wrapping out of it over whatever is beside it. */
.field-box .field-label {
  position: absolute;
  top: 50%;
  inset-inline-start: var(--space-3);
  max-width: calc(100% - 2 * var(--space-3));
  overflow: hidden;
  transform: translateY(-50%);
  color: var(--ink-muted);
  font-size: var(--text-base);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* In use — focused, or holding something — it lifts onto the top border, small,
   with the panel behind it so the border does not run through the words. It
   lifts for something typed as well as for focus, or it would fall back over
   the text when the reader moved on. Empty is known by the blank placeholder
   the input carries for the purpose. A field the browser filled in before
   anyone touched it can still count as showing its placeholder, so that is
   asked about by name. The move is in one step, with nothing sliding between
   the two places.

   The input is asked, and the label follows it in the markup, rather than the
   box being asked with :has(): a browser without :has() would never lift the
   label, and it would lie over whatever was typed. The three are inside :is()
   because :is() drops a selector the browser does not know and keeps the rest,
   where a plain list would be thrown away whole.

   Where it sits on the border, top: -3px, was judged by eye and is on no
   scale: it is where the words looked centred on a 1px border at today's
   --text-sm. Look again if either changes. */
.field-box
  input:is(:focus, :not(:placeholder-shown), :autofill)
  ~ .field-label {
  top: -3px;
  margin-inline-start: calc(-1 * var(--space-1));
  padding-inline: var(--space-1);
  background: var(--panel);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: var(--leading-tight);
}

.field-box input {
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
}

/* The rest of what is offered, drawn after what has been typed in a lighter
   colour. It is laid over the field where the typing is, its copy of the typing
   hidden so that it takes the room the typing does and the rest begins where the
   typing ends. Nothing in it is pressed. */
.field-box .field-ghost {
  position: absolute;
  top: 50%;
  inset-inline-start: var(--space-3);
  max-width: calc(100% - 2 * var(--space-3));
  overflow: hidden;
  transform: translateY(-50%);
  pointer-events: none;
  white-space: pre;
}

.field-box .field-ghost-typed {
  visibility: hidden;
}

.field-box .field-ghost-rest {
  color: var(--ink-muted);
}

/* A browser that fills the field in paints it its own tint, and paints that
   over background-color, so the panel is laid over it as an inset shadow
   instead. A tinted field under a label on the panel reads as a patch. */
.field-box input:autofill {
  box-shadow: inset 0 0 0 100vmax var(--panel);
  -webkit-text-fill-color: var(--ink);
}

/* Something said of what was typed, at the end of the line it is on, and
   never squeezed by the typing beside it. */
.field-box .field-mark {
  flex: none;
}

/* The box draws the ring, so the input does not draw a second one inside it. */
.field-box input:focus-visible {
  outline: none;
}

.field-message {
  color: var(--danger);
  font-size: var(--text-sm);
  font-weight: 700;
}

/* A box to tick, before its words and as tall as anything else pressed with a
   thumb, with the words wrapping beside it rather than beneath it. */
.field-tick-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
}

.field-tick-row input {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  accent-color: var(--accent);
}

.field-tick-label {
  cursor: pointer;
}

/* A line to each rule the field broke. */
.field-message span {
  display: block;
}

/* What a field is for, beneath it, quieter than what is wrong with it. */
.field-explanation {
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

/* What is wrong with a refused form as a whole, above its fields: said as a
   field's message is, since it is one, with the danger colour down its side as
   the notice has the accent's. On the content's own colour rather than the
   notice's tint, because --danger is held to 4.5:1 against that and nothing
   else. */
.dialog-problems {
  padding: var(--space-3) var(--space-4);
  border-inline-start: 4px solid var(--danger);
  color: var(--danger);
  font-weight: 700;
}

/* What a dialog kept open says it did, as "Sam Someone beat Alex Another was
   added": drawn as the notice is, but bold and with a tick, so that a scorer
   entering a batch sees at a glance that the last one went in. Only while it
   says something, since the region stays on the page, empty, for a screen
   reader to be told when it changes. The side and the tick take --link, the
   green that stands out in the dark as well as the light; the tick is left
   unsaid, as the words say it. */
.dialog-status:not(:empty) {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  padding: var(--space-3) var(--space-4);
  border-inline-start: 4px solid var(--link);
  margin-block-end: var(--space-4);
  border-radius: var(--radius-1);
  background: var(--surface);
  color: var(--ink);
  font-weight: 700;
}

.dialog-status:not(:empty)::before {
  content: "✓" / "";
  color: var(--link);
}

/* A thing to press, whether it is a button or a link that behaves like one. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius-1);
  background: none;
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

/* A button drawn as a picture alone, such as Edit's pencil and Archive's trash
   can, or as an arrow, as Up and Down are. Each picture is given the same room
   inside the button's ordinary padding, so that all of them are exactly as
   wide as one another and a row's options line up; what a button does is said
   by its label and its hover text. */
.option-arrow,
.button > .icon-pencil,
.button > .icon-trash-can {
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  text-align: center;
  line-height: 1.25rem;
  fill: currentcolor;
}

/* Red, as what it does is the one thing in a row that is hard to take back. The
   colour is --danger, which is held to enough contrast in both themes. */
.button > .icon-trash-can {
  fill: var(--danger);
}

/* A page's heading with what can be done to the thing it names beside it, such
   as a tournament's Edit. The name wraps within its own room rather than the
   button dropping beneath it, so that on a phone the button is still beside
   the name it is about. */
.page-heading {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.page-heading h1 {
  min-width: 0;
  overflow-wrap: anywhere;
}

.page-heading .button {
  flex-shrink: 0;
}

/* The one that does what the form is for, and the only one that looks like it. */
.button-submit {
  border-color: var(--action);
  background: var(--action);
  color: var(--action-ink);
}

/* Another way to do what a form is for, above its fields. The content's column
   stretches it to the fields' width, since it is a way in of the same weight as
   they are; it is drawn as the buttons other than the submit button are,
   because the way forward it is not is the form's. */
.dialog-alternative {
  gap: var(--space-3);
}

.dialog-alternative-icon {
  flex: none;
}

/* The word between the other way in and the fields. Written in lower case and
   drawn in capitals, for the reason given where it is written (dialog.ts). */
.dialog-or {
  max-width: none;
  margin: 0;
  color: var(--ink-muted);
  font-weight: 600;
  text-align: center;
  text-transform: uppercase;
}

.notice {
  padding: var(--space-3) var(--space-4);
  border-inline-start: 4px solid var(--accent-strong);
  background: var(--surface);
  color: var(--ink);
}

/* What an account is called and where it is reached: each label bold, with
   its value beside it on the same row. The labels take the width of the
   longest, so the values start together; a value too long for its row, such as
   a long address, breaks onto another line of its own column rather than
   pushing out past the panel. */
.profile {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--space-2) var(--space-3);
}

.profile dt {
  font-weight: 700;
}

.profile dd {
  overflow-wrap: anywhere;
}

/* The years of the home page and of a year's page, fitted to the window with
   no scripting to measure them (tournamentLists.ts). Every tab is as wide as every other and so is the drop-down
   list, so how many fit is known from the bar's width alone: the newest is
   always a tab and never in the list, and the page's own rules show each
   further tab, and leave it out of the list, once the bar is wide enough. */
.years-fitted {
  container: years / inline-size;
}

.years-fitted .year-tab {
  display: none;
}

.years-fitted .year-tab:first-child {
  display: flex;
}

.years-fitted .year-tab a {
  justify-content: center;
  width: 4.75rem;
  font-variant-numeric: tabular-nums;
}

.years-fitted .years-earlier {
  position: relative;
  display: flex;
  align-items: center;
  flex: 0 0 12rem;
}

.years-fitted .years-earlier-list li:first-child {
  display: none;
}

/* Pressed with a thumb, so as tall as anything else that is, and drawn as the
   admin draws its drop-down list of years. */
.years-earlier-list summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-2);
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius-1);
  white-space: nowrap;
  cursor: pointer;
}

/* Hanging beneath the bar rather than pushing it open, as the account menu's
   items do, in the bar's own colours since they are its years. */
.years-earlier-list[open] > ul {
  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  padding: 0;
  background: var(--accent-strong);
}

.years-earlier-list li a {
  min-height: 44px;
}

/* The home page's two lists, the recent results and beneath them the upcoming
   tournaments, at every width: side by side they left each table too narrow
   for its four columns. */
.home-lists {
  display: grid;
  gap: var(--space-6);
}

/* A list of tournaments, on the home page or a year's. */
.tournament-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}

/* Headed in the secondary navigation's colours, every other row on a colour
   of its own so that a row is followed across, and no lines between the
   cells, which the colours already part. */
.tournament-list table {
  width: 100%;
  border-collapse: collapse;
}

.tournament-list th,
.tournament-list td {
  padding: var(--space-2) var(--space-3);
  border: 0;
  text-align: start;
  vertical-align: middle;
}

.tournament-list thead :is(th, td) {
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-weight: 600;
}

.tournament-list th a {
  display: flex;
  gap: var(--space-1);
  color: inherit;
  text-decoration: none;
}

.tournament-list tbody tr:nth-child(even) {
  background: var(--surface);
}

/* A row is read as one thing, so it is pressed as one, and pressed with a
   thumb, so as tall as anything else that is. The name's link reaches over its
   own cell and no further: reaching over the row did not work in Safari, which
   does not make a row the box it reaches over, and the link reached over the
   page, header and all. Several ways of telling Safari from the rest were
   tried and each left some Safari wrong. A script follows the name's link from
   the rest of the row, in every browser (tournamentLists.ts). */
.tournament-list td {
  position: relative;
}

/* Only where the script is, so that a pointer does not offer what it cannot do. */
.tournament-list-pressable tbody tr {
  cursor: pointer;
}

.tournament-list td {
  height: 44px;
}

.tournament-list .tournament-name::after {
  position: absolute;
  inset: 0;
  content: "";
}

.tournament-list .tournament-dates {
  white-space: nowrap;
}

/* A national or international tournament's row is bold, every cell of it, so
   that the tournaments that matter beyond one club stand out in a long list. */
.tournament-list tbody tr[data-bold] td,
.player-tournaments tbody tr[data-bold] td {
  font-weight: 700;
}

/* A long name wraps rather than being cut short or pushing out past the
   panel. It is underlined only while the pointer is on its row, since the
   whole row is pressed to reach the tournament, and not while it is on the
   flag, which leads somewhere else. */
.tournament-list .tournament-name {
  overflow-wrap: anywhere;
  text-decoration: none;
}

.tournament-list
  tbody
  tr:hover:not(:has(.tournament-flag a:hover))
  .tournament-name {
  text-decoration: underline;
}

/* A flag is a link of its own, to the lists narrowed to its country, so it is
   lifted above the name's link that reaches over the row, and fills its cell
   so that it is pressed with a thumb as easily as the row is. */
.tournament-list .tournament-flag {
  padding: 0;
}

/* Left out of every list on a phone, heading and rows alike, where the room is
   wanted for the names. */
.tournament-list .tournament-flag {
  display: none;
}

@media (min-width: 40rem) {
  .tournament-list .tournament-flag {
    display: table-cell;
  }
}

.tournament-list .tournament-flag a {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding-inline: var(--space-3);
}

/* At twice the size they were drawn at, which is the only size there is of
   them: 16 pixels across is too small to tell one flag from another at a
   glance. Twice exactly, and each pixel kept square, so that they are as sharp
   as they were rather than blurred by being stretched. Never narrower, or
   the cell, which is only as wide as what is in it, lets the reset's
   max-width squeeze it across while its height stays, and a flag comes out
   taller than it is wide. */
.tournament-list .tournament-flag img {
  display: block;
  flex: none;
  width: 32px;
  max-width: none;
  height: 22px;
  image-rendering: pixelated;
}

/* A month's table is open beneath another's, and a table sized by what is in
   it makes the dates of one month wider than another's, so that the names do
   not begin in the same place. The first three columns are given a width of
   their own, enough for the longest dates (two months, as "28 Dec-03 Jan"),
   the sport's code and the flag, and the names have the rest. */
.year-month-body .tournament-list table {
  table-layout: fixed;
}

.year-month-body .tournament-list thead th:first-child {
  width: 10em;
}

.year-month-body .tournament-list thead .tournament-sport {
  width: 4rem;
}

.year-month-body .tournament-list thead .tournament-flag {
  width: 3.75rem;
}

/* The sport's code, in capitals, on the sport's own colour (--sport-*), in the
   ink the action buttons use, which sits on each at over 6:1 in both themes.
   Left out on a phone, where the room is wanted
   for the names, and shown from the width the navigation is laid out inline,
   which is where a tablet begins. */
.tournament-list .tournament-sport {
  display: none;
  padding-inline-start: 0;
}

@media (min-width: 40rem) {
  .tournament-list .tournament-sport {
    display: table-cell;
    padding-inline-end: 0;
  }

  /* The flag's link has its room inside it, so that it can be pressed with a
     thumb: the gap between the code and the flag is the link's start. */
  .tournament-list .tournament-sport + .tournament-flag a {
    padding-inline-start: 5px;
  }
}

.tournament-list .sport-code {
  display: inline-block;
  min-width: 2.5em;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-1);
  background: var(--action);
  color: var(--action-ink);
  font-size: var(--text-sm);
  font-weight: 700;
  text-align: center;
}

.tournament-list .sport-ac {
  background: var(--sport-ac);
  color: var(--action-ink);
}

.tournament-list .sport-gc {
  background: var(--sport-gc);
  color: var(--action-ink);
}

.tournament-list .sport-a6w {
  background: var(--sport-a6w);
  color: var(--action-ink);
}

.tournament-list .sport-rc {
  background: var(--sport-rc);
  color: var(--action-ink);
}

.tournament-list .sport-gb {
  background: var(--sport-gb);
  color: var(--action-ink);
}

.tournament-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-3);
}

/* Set off from the form above and the lists below, which the notice's own
   padding does not do. */
.tournament-filter-notice {
  margin-block: var(--space-3);
}

/* No wider than the form, however long the longest country's name is. */
.tournament-filter-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  max-width: 100%;
}

.tournament-filter-field label {
  font-weight: 600;
}

/* The days are the same box as the lists beside them, since a field a few
   pixels shorter than its neighbour looks like a mistake. */
.tournament-filter select,
.tournament-filter input[type="date"],
.tournament-filter button {
  box-sizing: border-box;
  max-width: 100%;
  min-height: 44px;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius-1);
  background: var(--panel);
}

/* Every country is on offer, so the list is taller than the room above or
   below the field, and Chrome shuts a list that fits neither as soon as it is
   opened. A height of its own, with the rest scrolled, lets it stay open. It
   is still a plain select, and a browser without this draws its own. */
.tournament-filter select,
.tournament-filter select::picker(select) {
  appearance: base-select;
}

.tournament-filter select::picker(select) {
  max-height: 20rem;
}

.tournament-filter input[type="date"] {
  color: var(--ink);
  font: inherit;
}

.tournament-filter button {
  border-color: var(--action);
  background: var(--action);
  color: var(--action-ink);
  font-weight: 600;
  cursor: pointer;
}

/* A tournament's games, the most recent first, no wider than 38rem, so that
   the column beside the names stays within a glance of them on a wide screen.
   A game is the winner on one line and the loser on the next, with what the
   game was part of beside them from that width up: the competition beside the winner, and how long ago it was added beside
   the loser. On a phone there is no room beside the names, so those come
   beneath them. */
.games {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 38rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A light line between one game and the next, so that a pair of lines is read
   as one game rather than run on into the next. */
.game + .game {
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

.game {
  display: grid;
  grid-template-areas:
    "winner"
    "loser"
    "competition"
    "ago";
  gap: 0 var(--space-4);
}

@media (min-width: 38rem) {
  .game {
    grid-template-areas:
      "winner competition"
      "loser ago";
    grid-template-columns: 1fr auto;
  }
}

/* Where a game has no competition, as in a block's order of play, whose games
   are all the block's, how long ago is beside the winner, where a reader's eye
   starts on a game, at every width: with nothing else to go beside the names,
   there is room for it even on a phone. */
.game:not(:has(.game-competition)) {
  grid-template-areas:
    "winner ago"
    "loser .";
  grid-template-columns: 1fr auto;
}

.game p {
  margin: 0;
}

.game-winner {
  grid-area: winner;
}

.game-loser {
  grid-area: loser;
}

.game-competition {
  grid-area: competition;
}

/* Against the right edge, where a reader's eye goes down the list to see how
   recent each game is. */
.game-ago {
  grid-area: ago;
  text-align: end;
}

/* A competition's games as a table of two columns, Game over the players and
   Date over how long ago, headed in the section bar's colours as the lists of
   tournaments are, no wider than the games of a list are. A game's row keeps
   the game's two lines, with how long ago against the right edge. */
.games-table {
  width: 100%;
  max-width: 38rem;
  border-collapse: collapse;
}

.games-table th {
  padding: var(--space-1) var(--space-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-weight: 600;
  text-align: start;
}

.games-table th:last-child {
  text-align: end;
}

.games-column a {
  display: inline-flex;
  gap: var(--space-1);
  color: inherit;
  text-decoration: none;
}

.games-table td {
  padding: var(--space-2);
  vertical-align: top;
  border-top: 1px solid var(--border);
}

.games-table > tbody > .game {
  display: table-row;
}

.games-table > tbody > .game + .game {
  padding-top: 0;
  border-top: 0;
}

/* The date column is as wide as its widest date and no wider, and a date is
   never broken across lines: the games' names take the rest of the width. */
.games-table :is(th, td):last-child,
.games-table .game-ago {
  width: 1%;
  white-space: nowrap;
  overflow-wrap: normal;
  text-align: end;
}

/* Wraps rather than pushing out past the panel. */
.game-line {
  overflow-wrap: anywhere;
}

/* A game withdrawn was played, but counts for nothing, so its lines are
   struck through, as a block's grid strikes it. */
.game[data-withdrawn] .game-line {
  text-decoration: line-through;
}

/* Lighter than the name, since the names are what a reader is looking for,
   on a tournament's page and its players' alike. */
.game-representing,
.player-representing {
  color: var(--ink-muted);
}

.game-flag,
.player-flag {
  display: inline;
  vertical-align: middle;
}

/* A tournament's players, one to a line, each name leading to the player's
   own page, set as a block's summary is: headed in the section bar's colours,
   and the rows banded, every other one on the page's tint, so that a long
   list is read a row at a time. The list is drawn up against the heading
   rather than apart from it, so that the two read as one table; where there
   are no players, what says so keeps its place beneath. */
.players-heading,
.games-heading,
.search-list > h2,
.players-search-heading,
.player-games > h2,
.player-competitions > h2 {
  padding: var(--space-1) var(--space-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-size: var(--text-lg);
}

.players {
  display: flex;
  flex-direction: column;
  margin: calc(-1 * var(--space-4)) 0 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border);
  border-top: 0;
}

/* Wraps rather than pushing out past the panel. */
.player {
  padding-inline: var(--space-2);
  overflow-wrap: anywhere;
}

.player + .player {
  border-top: 1px solid var(--border);
}

.player:nth-child(even) {
  background: var(--surface);
}

/* A tournament's page lists its games as its players' page lists its players:
   drawn up against the heading in the section bar's colours, the full width of
   the panel, and banded, every other game on the page's tint, so that a long
   list is read a game at a time. This is the page's own list and not the
   games of a block's order of play, which keep to the narrow column. */
.games-recent {
  max-width: none;
  gap: 0;
  margin: calc(-1 * var(--space-4)) 0 0;
  border: 1px solid var(--border);
  border-top: 0;
}

.games.games-recent > .game {
  padding: var(--space-2);
}

.games.games-recent > .game + .game {
  border-top: 1px solid var(--border);
}

.games.games-recent > .game:nth-child(even) {
  background: var(--surface);
}

/* A tournament played by teams lists its players team by team, each team's
   name headed in the section bar's colours as a tournament's own players are,
   with its players drawn up against it so that the two read as one table. */
.players-team-name {
  margin: 0;
  padding: var(--space-1) var(--space-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-size: var(--text-lg);
}

.players-team > .players {
  margin: 0;
}

/* A tournament's commentaries, set as its players are: headed in the section
   bar's colours and banded, each title leading to the commentary and its
   writer's name lighter beside it, since the titles are what a reader is
   choosing between. What the old site said of commentary comes beneath, the
   full width of the panel, as the commentaries are. */
.commentaries {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border);
}

.commentary-listed {
  padding-inline: var(--space-2);
  overflow-wrap: anywhere;
}

.commentary-listed + .commentary-listed {
  border-top: 1px solid var(--border);
}

.commentary-listed:nth-child(even) {
  background: var(--surface);
}

/* As tall as anything else pressed with a thumb. */
.commentary-listed > a {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.25em;
  align-items: center;
  min-height: 44px;
}

.commentary-listed-writer,
.commentary-writer,
.comment-about {
  color: var(--ink-muted);
}

.commentaries-start {
  margin-block: var(--space-4);
}

/* A commentary's title with, for its writer, the pencil that changes it to
   its right, on the same line while there is room and wrapping beneath it on
   a phone when there is not. */
.commentary-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.commentary-title-edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--link);
}

.commentary-title-edit .icon {
  width: 1.25rem;
  height: 1.25rem;
  fill: currentcolor;
}

/* A commentary: its comments one beneath another, the first written first,
   each parted from the next by a light line so that a comment of several
   paragraphs is read as one, and what is said of it beneath it, smaller. The
   comments run the full width of the panel, as the rest of a tournament's
   pages do. A long word or link wraps rather than pushing out past the panel
   on a phone. */
.commentary-title {
  overflow-wrap: anywhere;
}

.comments {
  margin: 0;
  padding: 0;
  list-style: none;
}

.comment {
  padding-block: var(--space-3);
  overflow-wrap: anywhere;
}

.comment + .comment {
  border-top: 1px solid var(--border);
}

.comment-text > :first-child {
  margin-top: 0;
}

.comment-about {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
}

/* The pencil and the trash can beside a comment, each as big as anything else
   pressed with a thumb though the shape in it is small, drawn in the link's
   colour. */
.comment-edit,
.comment-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--link);
}

.comment-about .icon {
  width: 1.25rem;
  height: 1.25rem;
  fill: currentcolor;
}

/* What is new to the reader, as a note they have not read: a red asterisk.
   On the section bar's dark green red is too dark to see, so there it stands
   in a pale circle of the panel's colour, against which --danger is
   measured. */
.new-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-inline-start: 0.15em;
  color: var(--danger);
  font-weight: 700;
}

/* Drawn in the mark's colour, its spokes as thick as bold type's strokes. */
.new-mark-asterisk {
  width: 0.7em;
  height: 0.7em;
  fill: none;
  stroke: currentcolor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

.site-sections li:has(> .new-mark) {
  display: flex;
  align-items: center;
}

/* A circle, with the asterisk in its middle. */
.site-sections .new-mark {
  width: 1.4em;
  height: 1.4em;
  border-radius: 50%;
  background: var(--panel);
}

/* A tournament's notes, set as its commentaries are: banded, each title
   leading to the note, with how long ago it was written lighter beside it. */
.notes {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border);
}

.note-listed {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25em;
  padding-inline: var(--space-2);
  overflow-wrap: anywhere;
}

.note-listed + .note-listed {
  border-top: 1px solid var(--border);
}

.note-listed:nth-child(even) {
  background: var(--surface);
}

/* As tall as anything else pressed with a thumb. */
.note-listed-title {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.note-listed-ago,
.note-about {
  color: var(--ink-muted);
}

.note-listed-ago {
  margin-inline-start: auto;
  font-size: var(--text-sm);
}

/* A note's page, set as a comment is: a long word or link wraps rather than
   pushing out past the panel on a phone. */
.note-title,
.note-text {
  overflow-wrap: anywhere;
}

/* A paragraph of a note is parted from the next by a full line, as a letter's
   are. The reset above takes every paragraph's margin away, so a note of
   several would otherwise run on as one. Set on the note and not on every
   paragraph, so that a comment, which has its own spacing, is left as it is. */
.note-text p + p {
  margin-top: 1lh;
}

.note-text > :first-child {
  margin-top: 0;
}

.note-about {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
}

/* A modal dialog (STYLE.md §5c), drawn as a dialog is and laid over the page:
   centred, 32rem at most and the full width inside the gutter on a phone. A
   dialog taller than the window scrolls within itself, and the page beneath
   stays where it was. The page behind it is dimmed, so that what can be used
   is what stands out. */
.modal-dialog {
  width: calc(100% - 2 * var(--space-4));
  max-height: calc(100% - 2 * var(--space-4));
  padding: 0;
  overflow-y: auto;
  background: var(--panel);
  color: var(--ink);
}

.modal-dialog::backdrop {
  background: rgb(0 0 0 / 0.5);
}

html:has(dialog:modal) {
  overflow: hidden;
}

/* The box the writer writes in, as wide as the comments and four lines tall,
   with the button that sends it beneath, as a dialog's is. */
.comment-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.comment-box {
  width: 100%;
  box-sizing: border-box;
  padding: var(--space-2);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius-1);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  resize: vertical;
}

.comment-form > .button,
.delete-form > .button {
  align-self: flex-start;
}

.delete-form {
  display: flex;
  margin-top: var(--space-3);
}

/* As tall as anything else pressed with a thumb. */
.player-name {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* A player who has withdrawn from the competition being shown is struck
   through wherever it names them, as their games are, since what they played
   counts for nothing. The line alone is set, so that a name that is a link
   keeps its underline and the thickness every link has. */
.player-name[data-withdrawn] {
  text-decoration-line: line-through;
}

a.player-name[data-withdrawn] {
  text-decoration-line: line-through underline;
}

/* A player's page: their competitions first on a phone, since they are short
   and say where the player is playing before the games say how, and from the
   tournament's page's width up the games first, with the competitions in a
   narrower column beside them. */
.player-page {
  display: grid;
  grid-template-areas:
    "competitions"
    "games";
  gap: var(--space-6) var(--space-5);
  align-items: start;
}

@media (min-width: 38rem) {
  .player-page {
    grid-template-areas: "games competitions";
    grid-template-columns: 2fr 1fr;
  }
}

.player-games {
  grid-area: games;
  min-width: 0;
}

.player-competitions {
  grid-area: competitions;
  min-width: 0;
}

/* Each list set as a tournament's players are: on its heading, a row to
   each game or competition with a line between, and every other row on the
   page's tint. Where a player has none, what says so keeps its place beneath
   the heading. */
.player-games-list,
.player-competitions-list {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-wrap: anywhere;
  border: 1px solid var(--border);
  border-top: 0;
}

.player-games-list > li,
.player-competitions-list > li {
  padding: var(--space-1) var(--space-2);
}

.player-games-list > li + li,
.player-competitions-list > li + li {
  border-top: 1px solid var(--border);
}

.player-games-list > li:nth-child(even),
.player-competitions-list > li:nth-child(even) {
  background: var(--surface);
}

/* A game that counts for nothing is struck through, as the tournament's page
   strikes it. */
.player-game[data-withdrawn] {
  text-decoration: line-through;
}

.player-games-none,
.player-competitions-none {
  margin-top: var(--space-2);
}

/* As tall as anything else pressed with a thumb. */
.player-competition {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* A block's grid. Wider than a phone once a block has more than a few
   players, so it scrolls across within the page rather than pushing the page
   out past the window. Positioned, so that what is hidden but said aloud
   within it, being positioned against the nearest positioned box, scrolls
   with it rather than pushing the page out past the window. */
.block-grid-scroll {
  position: relative;
  max-width: 100%;
  overflow-x: auto;
}

.block-grid {
  border-collapse: collapse;
}

.block-grid th,
.block-grid td {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  vertical-align: middle;
}

.block-grid-player {
  min-width: 10rem;
  font-weight: normal;
  text-align: start;
}

/* As tight as the heading row: a name is 44px tall elsewhere, for a thumb,
   but in the grid that would leave every player's row half empty. */
.block-grid .player-name {
  min-height: 0;
}

.block-grid-withdrawn {
  color: var(--ink-muted);
}

.block-grid-initials,
.block-grid-total-heading,
.block-grid-placing-heading,
.block-grid-cell,
.block-grid-total,
.block-grid-placing {
  text-align: center;
  white-space: nowrap;
}

.block-grid-self {
  background: var(--void);
}

/* The games between two players one beneath another, oldest first. */
.block-grid-score {
  display: block;
}

/* Told apart by more than colour: a game won is red and bold, one lost is
   plain and lighter, and one drawn is slanted. */
.block-grid-won {
  color: var(--score-won);
  font-weight: bold;
}

.block-grid-lost {
  color: var(--ink-muted);
}

.block-grid-drawn {
  font-style: italic;
}

/* A game withdrawn was played, but counts for nothing, so it is struck
   through, and said to be withdrawn for whatever reads the page aloud. */
.block-grid-score[data-withdrawn] {
  text-decoration: line-through;
}

/* A block's name with its three views on the same line, against the right
   edge, wrapping beneath the name only where there is not room beside it.
   The views and the printer are one group, pushed to the end with an
   automatic margin: spreading three parts apart (space-between) left the
   views stranded in the middle, and an automatic margin on the views alone
   left the printer at the left of a line of its own where there was no room
   for it beside them. The group wraps inside itself towards the right edge. */
.competition-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.competition-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-inline-start: auto;
}

/* A block's three views, offered beside its heading as a row of links, the
   one being read filled as the section bar's current tile is, so that it is
   told from the others by more than its colour: it is the one that is not a
   link's colour, and it is the one filled. A group's Summary and tests are
   offered the same way, in a row of their own above the page's heading. */
.competition-views ul,
.group-links ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* As tall as anything else pressed with a thumb. */
.competition-view,
.group-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-1);
}

.competition-view[aria-current="page"],
.group-link[aria-current="page"] {
  background: var(--current);
  color: var(--current-ink);
  border-color: var(--current);
  text-decoration: none;
}

/* Parted from what is beneath it as the heading is from the page. */
.group-links {
  margin-block-end: var(--space-3);
}

/* A block's summary: narrow enough for a phone, since it is the view for
   one, the names wrapping rather than pushing the numbers off the edge, and
   no wider than a medium screen, 38rem as a tournament's games are, so that
   on a wide one its numbers stay within a glance of their names. */
.block-summary {
  width: 100%;
  max-width: 38rem;
  border-collapse: collapse;
}

.block-summary th,
.block-summary td {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  vertical-align: middle;
}

.block-summary-player {
  font-weight: normal;
  text-align: start;
  overflow-wrap: anywhere;
}

/* As tight as the heading row, as in the grid. */
.block-summary .player-name {
  min-height: 0;
}

/* Headed in the section bar's colours, so that the headings read as the
   page's own bar over its columns, and the rows banded, every other one on
   the page's tint, so that a reader's eye stays on one player's row across to
   their numbers. */
.block-summary thead th,
.block-summary thead td {
  background: var(--accent-strong);
  color: var(--accent-ink);
  border-color: var(--accent-strong);
}

.block-summary tbody tr:nth-child(even) {
  background: var(--surface);
}

.block-summary-withdrawn {
  color: var(--ink-muted);
}

.block-summary-heading,
.block-summary-total {
  text-align: center;
  white-space: nowrap;
}

.block-summary-ranking,
.block-tie-break {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

/* A knockout's grid: a column for each round, side by side, scrolling across
   within the page where it is wider than the window, as a block's grid does.
   Positioned, for the reason a block's grid is: what is hidden but said aloud
   within it scrolls with it rather than pushing the page out. */
.knockout-scroll {
  position: relative;
  max-width: 100%;
  overflow-x: auto;
}

/* An arrow halfway down the grid's right edge while there is more of it to
   the right, leading to the final, and one halfway down its left edge once it
   is scrolled from its start, leading back to the first round. Whether there
   is more either way is told by how far the grid is scrolled, so that neither
   shows where the whole grid fits, since a grid that does not scroll has no
   scroll to tell by. A browser that cannot tell never shows them, and a
   reader there scrolls as they would have. */
.knockout-frame {
  position: relative;
  timeline-scope: --knockout;
}

.knockout-scroll {
  scroll-timeline: --knockout x;
}

.knockout-arrow {
  display: none;
}

@supports (animation-timeline: scroll()) {
  .knockout-arrow {
    position: absolute;
    top: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    translate: 0 -50%;
    border-radius: 50%;
    background: var(--action);
    color: var(--action-ink);
    text-decoration: none;
    visibility: hidden;
    animation-timeline: --knockout;
    animation-timing-function: linear;
    animation-fill-mode: both;
  }

  .knockout-onward {
    inset-inline-end: var(--space-2);
    animation-name: knockout-onward;
  }

  .knockout-back {
    inset-inline-start: var(--space-2);
    animation-name: knockout-back;
  }
}

/* The same two above the grid and below it, each pair in a row held to the
   width of what shows of the grid and kept there as it scrolls, asked of the
   grid itself whether there is more either way. Where the grid does not
   scroll, the rows are not there at all, rather than empty bands above and
   below it; and a browser that cannot ask never shows them. */
.knockout-scroll {
  container-type: scroll-state;
}

.knockout-edge {
  display: none;
}

@container scroll-state(scrollable: inline) {
  .knockout-edge {
    position: sticky;
    inset-inline-start: 0;
    display: flex;
    justify-content: space-between;
    width: 100%;
  }

  .knockout-above {
    padding-bottom: var(--space-2);
  }

  .knockout-below {
    padding-top: var(--space-2);
  }
}

.knockout-edge-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--action);
  color: var(--action-ink);
  text-decoration: none;
  visibility: hidden;
}

.knockout-edge-onward {
  margin-inline-start: auto;
}

@container scroll-state(scrollable: right) {
  .knockout-edge-onward {
    visibility: visible;
  }
}

@container scroll-state(scrollable: left) {
  .knockout-edge-back {
    visibility: visible;
  }
}

@keyframes knockout-onward {
  0%,
  98% {
    visibility: visible;
  }

  100% {
    visibility: hidden;
  }
}

@keyframes knockout-back {
  0%,
  2% {
    visibility: hidden;
  }

  3%,
  100% {
    visibility: visible;
  }
}

/* In the site's small type, near the old site's, so that a draw of 16 places
   fits a wide screen as it did there. */
.knockout {
  display: flex;
  width: max-content;
  font-size: var(--text-sm);
}

.knockout-round {
  display: flex;
  flex-direction: column;
}

/* Every round's column as tall as the first's, each pair given an equal share
   of it and its two matches at a quarter and three quarters of the way down
   that share, so that each later match stands level with the gap between
   the two before it. */
.knockout-matches {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.knockout-pair {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: space-around;
  padding-inline-end: var(--space-3);
}

/* The bracket, as the old site drew it: a line from the middle of each match
   of a pair out to the right, joined down the side, that leads on to the
   match their winners meet in. */
.knockout-pair::after {
  content: "";
  position: absolute;
  top: 25%;
  inset-inline-end: 0;
  bottom: 25%;
  width: var(--space-3);
  border: 1px solid var(--ink-muted);
  border-inline-start: 0;
}

/* The line on from the bracket before, into the middle of each match of a
   later round: a pair's two at a quarter and three quarters of the way down,
   the final's alone at half. */
.knockout-round + .knockout-round .knockout-pair {
  padding-inline-start: var(--space-3);
}

.knockout-round + .knockout-round .knockout-pair::before {
  content: "";
  position: absolute;
  top: 25%;
  inset-inline-start: 0;
  width: var(--space-3);
  height: 50%;
  border-top: 1px solid var(--ink-muted);
  border-bottom: 1px solid var(--ink-muted);
}

.knockout-pair-alone {
  padding-inline-end: 0;
}

.knockout-pair-alone::after {
  content: none;
}

.knockout-round + .knockout-round .knockout-pair-alone::before {
  top: 50%;
  height: 0;
  border-bottom: 0;
}

/* A match is a box with its two sides in it, as on the old site, its cells
   with no lines between them. */
.knockout-match {
  border: 1px solid var(--ink-muted);
  border-collapse: collapse;
}

.knockout-match th,
.knockout-match td {
  padding: var(--space-1) var(--space-2);
  vertical-align: middle;
}

/* A name on one line, so that every match is as tall as every other and the
   brackets meet them in their middles. */
.knockout-name {
  font-weight: normal;
  text-align: start;
  white-space: nowrap;
}

/* After the first round a long name wraps, as on the old site, so that a
   draw of 16 places fits a wide screen. Only the first round's matches need
   be of one height: they set the column's height, and a later match is set
   by the middle of its share, whatever its height. */
.knockout-round + .knockout-round .knockout-name {
  min-width: 9rem;
  max-width: 11rem;
  white-space: normal;
}

.knockout-round-name,
.knockout-summary-round > h2 {
  margin: 0 0 var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: var(--accent-strong);
  color: var(--accent-ink);
  font-size: var(--text-base);
}

/* Plain, as the old site's were, but for leading to the player's page, which
   a line beneath says when it is pointed at. */
.knockout .player-name,
.knockout-summary .player-name {
  min-height: 0;
  color: inherit;
  text-decoration: none;
}

.knockout .player-name:hover,
.knockout-summary .player-name:hover {
  text-decoration: underline;
}

/* Struck through as everywhere, and still so when pointed at, with the
   underline a knockout's name has only then. */
.knockout a.player-name[data-withdrawn],
.knockout-summary a.player-name[data-withdrawn] {
  text-decoration-line: line-through;
}

.knockout a.player-name[data-withdrawn]:hover,
.knockout-summary a.player-name[data-withdrawn]:hover {
  text-decoration-line: line-through underline;
}

.knockout-score {
  width: 1.75rem;
  text-align: center;
  white-space: nowrap;
}

.knockout-withdrawn,
.knockout-bye {
  color: var(--ink-muted);
}

/* Unmarked by colour, as the old site's were, but a game won is bold, so that
   a reader can still tell a match's winner at a glance, and the result is
   said aloud for whoever cannot see it. */
.knockout-won {
  font-weight: bold;
}

/* A knockout's summary: its rounds one beneath another, each match a table of
   its own, for a phone. */
/* No wider than a medium screen, 38rem as a tournament's games are, since it
   is the view for a phone and its numbers would drift away from their names
   across a wide one. */
.knockout-summary {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  max-width: 38rem;
}

/* In the summary, for a phone, a match is as wide as the page allows and a
   long name wraps rather than running off its edge, its scores still in a
   column of their own. */
.knockout-summary .knockout-match {
  width: 100%;
  table-layout: fixed;
}

.knockout-summary .knockout-name {
  white-space: normal;
  overflow-wrap: anywhere;
}

.knockout-summary .knockout-score {
  width: 2.5rem;
}

.knockout-summary-round {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Where even with its results wrapped the table is wider than a phone, it
   scrolls across within the page, as a block's grid does, rather than
   pushing the page out past the window. */
.swiss-scroll {
  position: relative;
  max-width: 100%;
  overflow-x: auto;
}

/* A Swiss's table, set as a block's summary is: headed in the section bar's
   colours and its rows banded, so that a reader's eye stays on one player's
   row across to their results. The results wrap within their column rather
   than pushing the table out past the window. Positioned, for the reason a
   block's grid is: what is hidden but said aloud within it, the opponents'
   whole names, stays within it rather than pushing the page out. */
.swiss-table {
  position: relative;
  width: 100%;
  border-collapse: collapse;
}

.swiss-table th,
.swiss-table td {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  vertical-align: middle;
}

.swiss-table thead th,
.swiss-table thead td {
  background: var(--accent-strong);
  color: var(--accent-ink);
  border-color: var(--accent-strong);
}

.swiss-table tbody tr:nth-child(even) {
  background: var(--surface);
}

/* A name wraps between its words, and within one only where a word is wider
   than its column, rather than wherever its column could be made narrower. */
.swiss-player {
  font-weight: normal;
  text-align: start;
  overflow-wrap: break-word;
}

/* As tight as the heading row, as in a block's table. */
.swiss-table .player-name {
  min-height: 0;
}

.swiss-withdrawn {
  color: var(--ink-muted);
}

.swiss-heading,
.swiss-total {
  text-align: center;
  white-space: nowrap;
}

.swiss-results {
  min-width: 7rem;
}

/* A result on one line of its own words, wrapping between results rather
   than within one. */
.swiss-result {
  white-space: nowrap;
}

/* Told apart by more than colour: the sign of the margin says which, and a
   result won is in the colour a block's grid gives a score won, and bold. */
.swiss-won {
  color: var(--score-won);
  font-weight: bold;
}

.swiss-lost,
.swiss-drawn {
  color: var(--ink-muted);
}

/* A game withdrawn was played, but counts for nothing, so it is struck
   through, as a block's grid strikes it. */
.swiss-result[data-withdrawn] {
  text-decoration: line-through;
}

/* The summary, without the results, is for a phone, and no wider than a
   medium screen, as a block's summary is. */
.swiss-table:not(:has(.swiss-results)) {
  max-width: 38rem;
}

/* A tournament played by teams' summary, set as a block's summary is: headed
   in the section bar's colours, its groups above their columns, and its rows
   banded. Scrolling across within the page where it is wider than the window,
   as a block's grid does, rather than pushing the page out past it. */
.team-summary-scroll {
  position: relative;
  max-width: 100%;
  overflow-x: auto;
}

/* A thick line round the whole table and between its groups, Tests, Games
   and Hoops, so that each group reads as one, as on the old site. */
.team-summary {
  border-collapse: collapse;
  border: 3px solid var(--table-rule);
}

.team-summary .team-summary-starts {
  border-inline-start: 3px solid var(--table-rule);
}

.team-summary th,
.team-summary td {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  vertical-align: middle;
}

.team-summary thead th,
.team-summary thead td {
  background: var(--accent-strong);
  color: var(--accent-ink);
  border-color: var(--accent-strong);
}

.team-summary tbody tr:nth-child(even) {
  background: var(--surface);
}

.team-summary-team,
.team-summary-corner {
  text-align: start;
}

.team-summary-group,
.team-summary-heading,
.team-summary-number {
  text-align: center;
  white-space: nowrap;
}

/* A test's grid, as the old site drew it: the two teams' players either side
   of their games, the first team on the left, and each team's totals beneath
   on its own side; headed in the section bar's colours and its rows banded,
   no wider than a medium screen, and scrolling across within the page where
   it is still wider than the window. */
.test-scroll {
  position: relative;
  max-width: 100%;
  overflow-x: auto;
}

.test-matches {
  width: 100%;
  max-width: 38rem;
  border-collapse: collapse;
}

.test-matches th,
.test-matches td {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  vertical-align: middle;
}

.test-matches thead th {
  background: var(--accent-strong);
  color: var(--accent-ink);
  border-color: var(--accent-strong);
}

.test-matches tbody tr:nth-child(even) {
  background: var(--surface);
}

.test-side,
.test-total-number {
  overflow-wrap: break-word;
}

/* The first team's side against the games and the second's from them, each
   heading over its own side. */
.test-matches tr > :first-child {
  text-align: end;
}

.test-matches tr > :last-child {
  text-align: start;
}

.test-vs,
.test-games,
.test-total-name {
  text-align: center;
  white-space: nowrap;
}

/* A match's games one beneath another. */
.test-game {
  display: block;
}

/* Told apart by more than colour, as a block's grid tells them. */
.test-won {
  color: var(--score-won);
  font-weight: bold;
}

.test-matches tfoot td,
.test-matches tfoot th {
  font-weight: bold;
}

/* --- Utilities ----------------------------------------------------------- */

.lead {
  font-size: var(--text-lg);
  color: var(--ink-muted);
}

/* Prose that asks to be held to a comfortable line length. Not applied to every
   paragraph, because the panel runs the width of the window and most of what
   goes in it — scores, tables, lists — wants that width. */
.prose {
  max-width: var(--measure);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The button that prints a competition's page. As tall as anything else
   pressed with a thumb, and drawn as the views beside it are. */
.print-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-1);
  color: inherit;
  cursor: pointer;
}

.print-button[hidden] {
  display: none;
}

.print-button .icon {
  width: 1.5rem;
  height: 1.5rem;
  fill: currentColor;
}

/* The page's first-level heading, said on paper, where the site's bars are
   not, so that a printed page says whose results they are. On the screen the
   tournament's name is already in the bar above, so it is only said aloud
   there (visually-hidden). The competition's name beneath it is the second
   level and drawn as large as a first, as it was. */
.competition-heading h2 {
  font-size: var(--text-3xl);
}

/* Said under the results, in the muted ink, since it explains the scores
   above it rather than being what the page is for. */
.competition-played-to {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  margin-block: var(--space-3) 0;
}

/* A page printed is the competition's name and its results, and nothing that
   is for finding the page: the site's bars, the views, the button. Black on
   white with no panel, since ink is spent on a tint nobody reads against. The
   paper's shape is the page's, named by the heading (competitionPages.ts),
   because a block's grid and a knockout's draw are wide and want the paper
   across, and a Swiss's table and a test's are long and want it up. */
@page landscape {
  size: landscape;
  margin: 10mm;
}

@page portrait {
  size: portrait;
  margin: 10mm;
}

/* What the paper is wide enough for, which the page cannot ask the printer,
   so it is less than any paper it is likely to be printed on is, less the
   margins: Letter across is 11in, 279mm, and the margin set above is 10mm on
   each side (printPieces.ts). */
:root {
  --print-width: 259mm;
}

@media print {
  body:has([data-print="landscape"]) {
    page: landscape;
  }

  body:has([data-print="portrait"]) {
    page: portrait;
  }

  body {
    background: #fff;
    color: #000;
    min-height: 0;
  }

  .try-banner,
  .site-bar,
  .site-sections,
  .site-title-bar,
  .tournament-subtitle,
  .site-footer,
  .group-links,
  .competition-actions,
  .competition-views,
  .print-button,
  .knockout-edge,
  .knockout-arrow {
    display: none;
  }

  /* What is wider than the paper is cut into pieces just before it is printed
     (printPieces.ts), the whole of it not printed, and each piece after the
     first on a page of its own. */
  [data-print-split] {
    display: none;
  }

  .print-piece + .print-piece {
    break-before: page;
  }

  main {
    padding-block: 0;
  }

  .panel {
    background: none;
    border: 0;
    padding: 0;
  }

  .print-tournament {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
    white-space: normal;
    font-size: var(--text-3xl);
    font-weight: bold;
  }

  /* A step beneath the first level, as the levels are on paper, though on the
     screen it is drawn as large as a first was. */
  .competition-heading h2 {
    font-size: var(--text-2xl);
  }

  /* A link on paper goes nowhere, and an underline under it only reads as
     something to press. A withdrawn player's name keeps the line through it,
     which says they withdrew (above). */
  a {
    text-decoration-line: none;
  }

  a.player-name[data-withdrawn] {
    text-decoration-line: line-through;
  }

  /* Everything on paper, not what fits a window. */
  .block-grid-scroll,
  .knockout-scroll,
  .swiss-scroll,
  .test-scroll {
    overflow: visible;
  }
}

/* The months of a year's page (yearMonths.ts): twelve to press, each opening
   its tournaments beneath it. The toggle is a button, and as tall as anything
   else pressed with a thumb. Open, it is the same green as the table's column
   headings and touches them, so that the two read as one heading. */
.year-month-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.year-month-toggle {
  display: flex;
  gap: var(--space-2);
  min-height: 44px;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: 0;
  background: var(--panel);
  color: var(--link);
  font: inherit;
  font-weight: 600;
  text-align: start;
  align-items: center;
  cursor: pointer;
}

/* Beneath the heading, above the months. A link-coloured button without a
   frame, as the months are, and as tall as one. */
.year-months-all {
  min-height: 44px;
  margin-block-end: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 0;
  background: none;
  color: var(--link);
  font-weight: 600;
  cursor: pointer;
}

.year-month-mark {
  display: inline-block;
  width: 1ch;
  text-align: center;
}

.year-month-toggle[aria-expanded="true"] {
  border-color: var(--accent-strong);
  background: var(--accent-strong);
  color: var(--accent-ink);
}

.year-month-body {
  padding: 0;
}

.year-month-body .tournament-list {
  gap: 0;
}

.year-month[aria-busy="true"] .year-month-toggle {
  cursor: progress;
}
