/* The field: every runner on one screen, 4 across and 6 down.
   Each card is a size container, so what it shows depends on the card's own
   size rather than the device: number, name, odds and total on a phone,
   with jockey, barrier, weight and more filling in as cards get bigger. */

:root {
  --turf: #1C4A2D;
  --turf-stripe: #22573A;
  --turf-deep: #123420;
  --rail: #F2F4EE;
  --ink: #0F2419;
  --brass: #D8B24A;
  --rose: #C4203A;
  --chalk: #FFFFFF;

  --rail-width: 3px;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background: var(--rail);
  color: var(--ink);
  /* Condensed fallbacks keep names fitting if the web font is slow to load */
  font-family: 'Archivo', 'Roboto Condensed', 'Arial Narrow', sans-serif-condensed, system-ui, sans-serif;
  font-stretch: 100%;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Grid */

main {
  flex: 1;
  display: flex;
  min-height: 0;
  padding: 0 var(--rail-width) var(--rail-width);
}

.empty {
  margin: auto;
  padding: 1rem;
  max-width: 32ch;
  text-align: center;
}

.field {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* Rows share the screen height; on very short screens (a phone on its
     side) they stop shrinking and the page scrolls instead */
  grid-auto-rows: minmax(86px, 1fr);
  gap: var(--rail-width);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Card */

.runner {
  container: runner / size;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: 3px;
  color: var(--chalk);
}

/* Background on its own layer, so a scratching can grey it without greying
   the text on top. Bottom to top: mowing stripes, the horse's silks (shown
   whole, anchored right), then a tint that keeps the text readable while
   leaving the silk colours recognisable. */
.runner::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(180deg,
      rgb(18 52 32 / 0.85) 0%,
      rgb(18 52 32 / 0.5) 38%,
      rgb(18 52 32 / 0.5) 70%,
      rgb(18 52 32 / 0.9) 100%),
    var(--silk, none),
    repeating-linear-gradient(120deg,
      var(--turf) 0 22px,
      var(--turf-stripe) 22px 44px);
  background-position: center, right 4% center, center;
  background-size: cover, auto 82%, cover;
  background-repeat: no-repeat;
}

.runner__card {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 5px 6px 0;
}

.runner__title {
  display: flex;
  align-items: center;
  gap: 0.3em;
  min-width: 0;
  margin: 0;
  font-size: clamp(0.66rem, 9.5cqi, 1.25rem);
  font-weight: 700;
  font-stretch: 72%;
  line-height: 1.05;
}

/* The saddlecloth: the horse's number as it's worn on race day */
.cloth {
  flex: none;
  min-width: 1.25em;
  padding: 0.1em 0.14em 0.02em;
  border-radius: 2px;
  background: var(--chalk);
  color: var(--ink);
  font-size: 1.3em;
  font-weight: 900;
  font-stretch: 62%;
  font-variant-numeric: tabular-nums;
  line-height: 0.95;
  text-align: center;
}

/* One line; names too long for the card end in an ellipsis */
.name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-align: left;
  padding-top: 0.08em;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Dark halo so names stay legible over pale silks */
  text-shadow: 0 0 3px rgb(0 0 0 / 0.9), 0 1px 2px rgb(0 0 0 / 0.7);
}

/* Long names use the narrowest width of the font, so more of the name
   shows before it's cut off */
.name--squeeze { font-stretch: 62%; }

/* Form details
   The rows are a fixed height and fill the space between title and total.
   Rows that don't fit go into zero-height implicit rows and disappear
   whole, so a card never shows a detail cut in half. Details are in
   priority order: odds first, trainer and country last. */

.form {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: repeat(auto-fill, 1.3em);
  grid-auto-rows: 0;
  column-gap: 0.75rem;
  margin: 0;
  overflow: hidden;
  font-size: clamp(0.68rem, 7.5cqi, 0.95rem);
  font-stretch: 88%;
  line-height: 1.3;
  text-shadow: 0 0 3px rgb(0 0 0 / 0.95), 0 0 1px rgb(0 0 0 / 0.9);
}

.stat {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.4em;
  min-width: 0;
  overflow: hidden;
}

.stat dt {
  flex: none;
  color: rgb(255 255 255 / 0.72);
}

.stat dd {
  margin: 0;
  overflow: hidden;
  font-weight: 650;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Jockey and trainer names need more width than a phone card has */
.long { display: none; }

@container runner (min-width: 140px) {
  .long { display: flex; }
}

/* Wide, short cards (iPad landscape, laptops, monitors): details in columns
   with the label above the value */
@container runner (min-width: 250px) and (orientation: landscape) {
  /* Keep the details clear of the silk on the right: about 0.66 of the
     card height wide at 82% height */
  .runner__card { padding-right: 66cqb; }
  /* .runner__card raises specificity above the later base .takings rule */
  .runner__card .takings { margin-right: -66cqb; }
  .form {
    grid-template-columns: repeat(auto-fill, minmax(54px, 1fr));
    grid-template-rows: repeat(auto-fill, 2.5em);
    column-gap: 0.5rem;
  }
  .stat {
    flex-direction: column;
    justify-content: flex-start;
    gap: 0;
  }
  .long, .stat--scratched { grid-column: span 2; }
  .stat dt { font-size: 0.85em; line-height: 1.15; }
}

/* Card footer: "No bets" on the left when nobody has backed the horse, and
   the chosen contestant's stake (brass chip) on the right when they have.
   The top line turns brass on horses the contestant has backed. */

.takings {
  display: flex;
  align-items: center;
  gap: 0.4em;
  min-height: 1.9em;
  margin: 0 -6px;
  padding: 0.2em 6px 0.25em;
  border-top: 2px solid rgb(255 255 255 / 0.25);
  background: rgb(18 52 32 / 0.85);
  font-size: clamp(0.72rem, 8.5cqi, 1.05rem);
  line-height: 1.1;
}

.takings__none {
  color: rgb(255 255 255 / 0.6);
  font-stretch: 88%;
}

.takings .stake { margin-left: auto; }

.runner.is-backed .takings { border-top-color: var(--brass); }

/* Scratched: out of the race, so greyed back but still readable */

.runner.is-scratched::before {
  filter: grayscale(1) brightness(0.8);
}

.is-scratched .runner__card { color: rgb(255 255 255 / 0.8); }

.is-scratched .name {
  text-decoration: line-through;
  text-decoration-thickness: 0.08em;
}

.stat--scratched dd {
  display: inline-block;
  padding: 0.05em 0.35em;
  border-radius: 2px;
  background: var(--rose);
  color: var(--chalk);
  text-shadow: none;
}

/* Prize pools footer: the total split 50/30/15/5, with the total itself on
   a brass panel at the end. One line per prize: "1st place 50%  $736.53",
   or just "1st $736.53" on phones. */

.prizes {
  border-top: 2px solid var(--brass);
  background: var(--ink);
  color: var(--rail);
}

.prizes dl {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr)) minmax(0, 1.2fr);
  margin: 0;
}

.prize {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5em;
  min-width: 0;
  padding: 0.2rem 0.6rem 0.25rem;
}

.prize + .prize { border-left: 1px solid rgb(242 244 238 / 0.15); }

.prize dt {
  overflow: hidden;
  color: rgb(242 244 238 / 0.85);
  font-size: 0.85rem;
  font-stretch: 85%;
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prize__share { color: rgb(242 244 238 / 0.55); }

.prize dd {
  margin: 0;
  color: var(--brass);
  font-size: clamp(1rem, 1.6vw, 1.3rem);
  font-weight: 850;
  font-stretch: 70%;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  white-space: nowrap;
}

.prize--total { background: var(--brass); }

.prize--total dt,
.prize--total dd { color: var(--ink); }

/* Phones: one line of just place and amount ("1st $736.53"). The amount
   keeps priority; the label gives way first if a cell gets tight. */
@media (max-width: 599px) {
  /* Columns sized to their contents, with spare width shared out */
  .prizes dl { grid-template-columns: repeat(5, auto); }
  .prize {
    gap: 0.25em;
    padding: 0.2rem 0.3rem 0.25rem;
  }
  .prize dt {
    flex-shrink: 1;
    min-width: 0;
    font-size: 0.68rem;
  }
  .prize dd {
    flex-shrink: 0;
    font-size: 0.9rem;
    font-stretch: 62%;
  }
  .prize__word,
  .prize__share { display: none; }
}

/* Betting. With a contestant chosen, each card has a transparent button over
   it; tapping steps their bet on that horse: none -> $1 -> $2 -> none.
   Without a contestant there's no button, so cards can't be tapped. */

.runner__tap,
.runner__open,
.runner__edit {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: inherit;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.runner__tap:focus-visible,
.runner__open:focus-visible,
.runner__edit:focus-visible {
  outline: 3px solid var(--chalk);
  outline-offset: -3px;
}

/* Press: the card gives slightly under the finger */
.runner:has(.runner__tap) { transition: transform 90ms ease-out; }
.runner:has(.runner__tap:active) { transform: scale(0.97); }

/* Horses the chosen contestant has backed: brass edge and their stake in
   the footer. An outline, as it paints above the silk layer. */
.runner.is-backed {
  outline: 3px solid var(--brass);
  outline-offset: -3px;
}

.stake {
  padding: 0.12em 0.4em 0.05em;
  border-radius: 2px;
  background: var(--brass);
  color: var(--ink);
  font-size: 1em;
  font-weight: 850;
  font-stretch: 70%;
  font-variant-numeric: tabular-nums;
}

.runner.is-pending .runner__card { opacity: 0.55; }
.runner.is-pending .runner__tap { cursor: progress; }

/* The card that just changed gets a brief brass wash */
.runner.just-changed .runner__card { animation: stake-changed 0.5s ease-out; }

@keyframes stake-changed {
  from { background: rgb(216 178 74 / 0.5); }
  to { background: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .runner:has(.runner__tap:active) { transform: none; }
  .runner.just-changed .runner__card { animation: none; }
}

/* All bets page: each card's footer shows how many bets the horse has (left)
   and its total from everyone (right, brass as it's money) */

.takings__amount {
  margin-left: auto;
  color: var(--brass);
  font-size: 1.15em;
  font-weight: 850;
  font-stretch: 70%;
  font-variant-numeric: tabular-nums;
}

.takings__count {
  color: rgb(255 255 255 / 0.75);
  font-stretch: 88%;
}

/* All bets page: the names of the contestants who've backed the horse, as
   tags that wrap to fill the card. Names that don't fit are replaced by a
   "+N" tag (see fitBackers in _board.ejs). */

.backers {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 3px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  list-style: none;
  font-size: clamp(0.66rem, 7.5cqi, 0.92rem);
  line-height: 1.25;
}

.backers li {
  max-width: 100%;
  overflow: hidden;
  padding: 0.1em 0.4em 0.05em;
  border-radius: 2px;
  background: rgb(15 36 25 / 0.75);
  color: var(--chalk);
  font-weight: 650;
  font-stretch: 85%;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.backers .backers__more {
  background: var(--chalk);
  color: var(--ink);
}

.flag-scratched {
  align-self: flex-start;
  margin: 0;
  padding: 0.05em 0.35em;
  border-radius: 2px;
  background: var(--rose);
  color: var(--chalk);
  font-size: clamp(0.66rem, 7.5cqi, 0.92rem);
  font-weight: 650;
}

