/* Rules Pico has no class for. Colors come from Pico's variables, so dark mode follows. */

/* Titles of games, written as <cite> in server/strings.toml: italic by convention, with
   weight and the strongest text color so they stand out in running text without looking
   like links. */
cite {
  font-style: italic;
  font-weight: 600;
  color: var(--pico-contrast);
}

/* Site nav: on narrow screens the links wrap below the site name instead of squeezing
   each label onto several lines. Lists after the first get its edge alignment when they wrap. */
header nav {
  flex-wrap: wrap;
  column-gap: var(--pico-spacing);
  justify-content: flex-start;
}

/* The site name holds the left; the links and sign-in state share the right. */
header nav ul:first-of-type {
  margin-right: auto;
}

/* The site name is the link home, looking like plain text in every link state. Pico's
   nav padding and negative margin still apply, so it keeps its place and focus ring. It
   may wrap on a narrow phone, unlike the other links. */
header nav a.brand {
  color: inherit;
  text-decoration: none;
  white-space: normal;
}

header nav a,
header nav summary {
  white-space: nowrap;
}

header nav ul:not(:first-of-type) {
  margin-left: calc(var(--pico-nav-element-spacing-horizontal) * -1);
}

/* Sign-in state at the end of the nav. The sign-out button is a form so it can POST, sized
   to sit in line with the links. */
header nav ul.account form {
  margin: 0;
}

header nav ul.account button {
  margin: 0;
  padding: calc(var(--pico-nav-link-spacing-vertical) * 0.5)
    var(--pico-nav-link-spacing-horizontal);
  font-size: inherit;
}

/* Site-wide affiliation disclaimer, with the site's release at the right. The direct-child
   selector keeps this separate from the footers used inside cards. On a narrow screen the
   release wraps under the disclaimer, still at the right. */
body > footer.site-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(var(--pico-spacing) * 0.5) var(--pico-spacing);
  border-top: var(--pico-border-width) solid var(--pico-muted-border-color);
  color: var(--pico-muted-color);
}

body > footer.site-footer .version {
  margin-left: auto;
  white-space: nowrap;
}

/* ROM setup cards. rom.js sets data-state: checking, empty, error, stored or unavailable. */

article.rom > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pico-spacing);
}

article.rom input[type="file"] {
  width: auto;
}

.rom-status {
  margin-bottom: calc(var(--pico-spacing) * 0.5);
}

/* Hashes in a card wrap evenly on narrow screens instead of leaving a stray character. */
article.rom code {
  word-break: break-all;
}

article.rom > footer button {
  margin-bottom: 0;
}

.rom-check,
.step-number {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background-color: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  font-weight: bold;
  line-height: 1;
}

.rom-check {
  display: none;
}

article.rom[data-state="stored"] {
  background-color: color-mix(
    in srgb,
    var(--pico-primary-background) 10%,
    var(--pico-card-background-color)
  );
  box-shadow:
    var(--pico-card-box-shadow),
    0 0 0 2px var(--pico-primary-background);
}

article.rom[data-state="stored"] > header,
article.rom[data-state="stored"] > footer {
  background-color: color-mix(
    in srgb,
    var(--pico-primary-background) 20%,
    var(--pico-card-sectioning-background-color)
  );
}

article.rom[data-state="stored"] .rom-check {
  display: inline-flex;
}

article.rom[data-state="stored"] .rom-status {
  color: var(--pico-primary);
  font-weight: 600;
}

article.rom[data-state="error"] .rom-status {
  color: var(--pico-del-color);
}

/* A stored ROM offers only Forget; anything else offers only the file input. */
article.rom[data-state="stored"] input[type="file"],
article.rom[data-state="stored"] .rom-expected,
article.rom[data-state="unavailable"] input[type="file"],
article.rom:not([data-state="stored"]) > footer {
  display: none;
}

/* Home page steps: numbered cards in Pico's grid, inside an ordered list. */

.steps {
  padding: 0;
}

/* Each card spans two grid rows, header and body, shared with the cards beside it
   through subgrid, so a header that wraps keeps every card's header the same height. */
.steps > li,
.steps > li > article {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  row-gap: 0;
  margin: 0;
}

.steps > li {
  list-style: none;
}

.steps article > header {
  display: flex;
  align-items: center;
  gap: calc(var(--pico-spacing) * 0.75);
}

/* Collection pages (server/pages.py): one card per entry, its title linking to its own
   anchor, with the date beside it, wrapping below on a narrow screen. */
.collection > article > header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  column-gap: var(--pico-spacing);
}

.collection > article > header h2 {
  margin-bottom: 0;
}

.collection > article > header h2 a {
  color: inherit;
  text-decoration: none;
}

.collection > article > header h2 a:hover,
.collection > article > header h2 a:focus-visible {
  text-decoration: underline;
}

.collection > article > header time {
  color: var(--pico-muted-color);
}

/* An unwritten string from server/strings.toml: its key, marked, with the note on hover. */
.unwritten {
  outline: 1px dashed var(--pico-del-color);
  color: var(--pico-del-color);
  cursor: help;
}

/* Generate form. A refused submission's notice sits above the form. */
.form-error {
  color: var(--pico-del-color);
  box-shadow:
    var(--pico-card-box-shadow),
    0 0 0 2px var(--pico-del-color);
}

/* The course select is for a vanilla course alone, and a vanilla course ignores the
   sources and the expert cap. Without :has() every field shows, and the server ignores
   what a vanilla course does not read. */
#generate-form .vanilla-only {
  display: none;
}

#generate-form:has(#generate-mode option[value="vanilla_course"]:checked)
  .vanilla-only {
  display: block;
}

#generate-form:has(#generate-mode option[value="vanilla_course"]:checked) .not-vanilla {
  display: none;
}

/* Club rules: a card inside the form, set apart from the everyday settings because they
   are for special events. */
form article.club-rules {
  margin-block: calc(var(--pico-spacing) * 2);
}

form article.club-rules > details {
  margin-bottom: 0;
}

.club-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));
  column-gap: var(--pico-spacing);
}

.club-grid label {
  white-space: nowrap;
}

/* Seed page. */
.magic-words {
  letter-spacing: 0.08em;
}

table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Rounds scorecard: a column per hole, so cells stay tight; the nine and round totals
   stand out from the holes. */
table.scorecard th,
table.scorecard td {
  padding-inline: calc(var(--pico-spacing) * 0.4);
  white-space: nowrap;
}

table.scorecard thead th {
  border-bottom-width: 0px;
}

table.scorecard .nine-total {
  font-weight: 600;
}

/* The hole cells' scorecard decorators are centered (see table .num.strokes below), so
   the hole numbers, pars and totals are too, to keep each column in line. */
table.scorecard .num {
  text-align: center;
}

/* A rule down the right of the Out and In columns, closing off each nine. A column's
   border runs unbroken through every row since Pico collapses table borders, and it wins
   over the cells' own, which draw only a bottom edge. */
table.scorecard col.nine-end {
  border-inline-end: 2px solid var(--pico-muted-color);
}

table.seed-details th {
  width: 40%;
}

/* Seed page sections collapsed into cards, their h2 as the summary. Flex keeps Pico's
   chevron beside the heading rather than floated below it. */
article.collapsible > details {
  margin-bottom: 0;
}

article.collapsible > details > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

article.collapsible > details > summary > h2 {
  margin-bottom: 0;
}

/* The download settings' over-max marker; download.js keeps data-over-max current as
   clubs are checked. */
details.download-settings[data-over-max="false"] .download-over-max {
  display: none;
}

/* Seed page download form. download.js sets data-state: checking, missing, ready,
   building, done, error or unavailable. */
article.download form > :last-child {
  margin-bottom: 0;
}

.download-status {
  margin-bottom: calc(var(--pico-spacing) * 0.5);
}

/* Checking and ready have no status text; drop the empty line's margin. */
.download-status:empty {
  display: none;
}

article.download[data-state="done"] .download-status {
  color: var(--pico-primary);
  font-weight: 600;
}

article.download[data-state="missing"] .download-status,
article.download[data-state="error"] .download-status,
article.download[data-state="unavailable"] .download-status {
  color: var(--pico-del-color);
}

/* The link to ROM setup shows only while a ROM the seed needs is missing. */
article.download:not([data-state="missing"]) .download-rom-setup {
  display: none;
}

/* Hosting page (/host/<id>): the club-rule warning and the claim code. The code stays
   black on white in dark mode too, so a phone can read it. */
article.host-warning {
  border-left: 0.5rem solid var(--pico-del-color);
}

.host-claim-code {
  width: min(100%, 22rem);
}

.host-claim-code svg {
  display: block;
  width: 100%;
  height: auto;
}

/* A hosted ROM's file name is one long word; let it wrap on a phone. */
article.download code[data-filename] {
  overflow-wrap: anywhere;
}

/* Scan page: one table per nine, side by side while both fit and stacked when they don't.
   Fixed layout and set column widths make the two tables line up either way. */
.nines {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  column-gap: calc(var(--pico-spacing) * 2);
}

table.nine {
  table-layout: fixed;
  width: 26rem;
  max-width: 100%;
}

table.nine col.hole,
table.nine col.putts {
  width: 24%;
}

table.nine col.par {
  width: 18%;
}

table.nine col.strokes {
  width: 34%;
}

/* A round that records fairways has a fifth column; the widths make room for it. */
table.nine.with-fairways col.hole,
table.nine.with-fairways col.putts {
  width: 18%;
}

table.nine.with-fairways col.par {
  width: 14%;
}

table.nine.with-fairways col.strokes {
  width: 28%;
}

table.nine.with-fairways col.fairway {
  width: 22%;
}

table.nine .fairway {
  text-align: center;
}

/* Strokes against par: over par red, under par green, level par left as it is. Also sets
   --score-color, a custom property (unlike currentColor, unaffected by the digit's own
   color below) that the scorecard decorators borrow their ring color from. The admin round
   page colors its holes the same way, without decorators. */
table .over-par {
  color: var(--pico-del-color);
  --score-color: var(--pico-del-color);
}

table .under-par {
  color: var(--pico-ins-color);
  --score-color: var(--pico-ins-color);
}

/* Scorecard decorators on the round page: standard notation for a hole's score against par.
   .score-mark holds the number; each wrapping .score-ring is one more concentric ring for an
   additional stroke of difference. Centered rather than right-aligned like the other .num
   columns, since a right-aligned ring grows from the cell's edge and staggers the digit
   itself out of line row to row. line-height matches a mark's own height (score-depth-0's
   2rem) so a plain score's row is as tall as a decorated one - the front and back nine are
   separate tables, each sized from its own content, so a shorter row on one side would
   otherwise fall out of step with its counterpart on the other. */
table .num.strokes {
  text-align: center;
  line-height: 2rem;
}

/* Drawn from the outside in, so every mark takes up the same space regardless of how many
   strokes it's off by: score-depth-0 is always the outermost ring, at a fixed size, and the
   inner ring nests inward from it by an inset rather than being centered. Every size in this
   chain divides out to a whole pixel at the default 16px root (a 2px inset off a 32px,
   1px-bordered depth-0 leaves an even 26px for depth-1), so the browser never has to round a
   fractional pixel unevenly between the two sides of a ring. */
.score-mark,
.score-ring {
  position: relative;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  border: 1px solid var(--score-color, currentColor);
  border-radius: 50%;
}

.score-mark.square,
.score-ring.square {
  border-radius: 0;
}

/* The ring carries the over/under-par color; the number inside it stays the ordinary text
   color, so a birdie and a bogey read the same and only the shape tells them apart. */
.score-mark {
  color: var(--pico-color);
  /* Without this, the table's line-height (1.5) makes the line box taller than a small
     inner ring, and flex centering balances that box rather than the glyph itself, so the
     digit reads as sitting low and off-center instead of in the middle of the ring. */
  line-height: 1;
}

/* Even at line-height 1, the line box includes the font's room above and below the
   digits, which is rarely even, so a centered line box leaves the digit itself about a
   pixel high. text-box trims the box to run from the baseline to cap height, so centering
   it centers the glyph. It only applies to a block container, hence the digit's own block
   span inside the flex ring; the triangle's absolutely positioned value is one already.
   Browsers without text-box support keep the untrimmed box. */
.score-digit {
  display: block;
}

.score-digit,
.score-triangle-value {
  text-box: trim-both cap alphabetic;
}

.score-depth-0 {
  width: 2rem;
  aspect-ratio: 1;
}

.score-depth-1,
.score-depth-2 {
  position: absolute;
  inset: 2px;
}

.score-depth-2 {
  font-size: 0.9em;
}

/* An eagle or double bogey nests through score-depth-1 to reach score-depth-2 rather than
   stopping at depth-1, so its two visible rings sit as far apart as an albatross's outer
   and inner ring, not its outer and middle. score-spacer keeps depth-1 in the DOM, sized
   and positioned as normal, purely to place depth-2 correctly - it just isn't drawn. */
.score-spacer {
  border-color: transparent;
}

/* A triple bogey (or worse) uses a triangle instead of squares - a commonly cited (if not
   universally agreed) way to draw it - point up, flat edge down, like a warning triangle
   rather than an inverted one. An SVG stroke, since a hollow triangle outline isn't
   something a plain CSS border can draw. The number sits at the triangle's centroid, not
   the bounding box's midpoint, since that's where a triangle actually reads as "the
   middle". */
.score-triangle {
  position: relative;
  display: inline-flex;
  vertical-align: middle;
}

.score-triangle svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.score-triangle polygon {
  fill: none;
  stroke: var(--score-color, currentColor);
  stroke-width: 1;
  stroke-linejoin: round;
}

.score-triangle-value {
  position: absolute;
  left: 50%;
  top: 63%;
  transform: translate(-50%, -50%);
  color: var(--pico-color);
  line-height: 1;
}

/* The triangle narrows toward its apex, so even at the same overall footprint as a circle
   or square, there's less width at the digit's position - a two-digit score needs a
   smaller font than those shapes to stay inside the sides instead of crossing them. A
   single digit already fits at full size, so this only applies once strokes reaches 10. */
.score-triangle-value.wide {
  font-size: 0.7em;
}

/* Admin pages: a row of links under the site header, and buttons that sit in a table row. */
nav.admin-nav {
  flex-wrap: wrap;
  justify-content: flex-start;
  margin-bottom: var(--pico-spacing);
}

nav.admin-nav ul {
  flex-wrap: wrap;
}

form.admin-inline,
form.admin-inline button {
  margin: 0;
}

form.admin-inline button {
  padding: calc(var(--pico-form-element-spacing-vertical) * 0.5)
    var(--pico-form-element-spacing-horizontal);
}

/* The seed page's course overview: a hole's transforms as small outlined chips after its
   id, on the same line, so a transformed hole's row is no taller than any other. */
table.holes [data-transform] {
  display: inline-block;
  margin-left: 0.35em;
  padding: 0 0.4em;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  color: var(--pico-muted-color);
  font-size: 0.75em;
  line-height: 1.6;
  white-space: nowrap;
  vertical-align: middle;
  cursor: help;
}

/* The metrics window picker: two small controls on one line, rather than the full-width
   stack Pico gives a form by default. */
form.admin-window {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--pico-spacing);
  margin-bottom: var(--pico-block-spacing-vertical);
}

form.admin-window input,
form.admin-window button {
  width: auto;
  margin-bottom: 0;
}

form.admin-window input {
  max-width: 6rem;
}
