/* ============================================================================
   styles.css  —  STONKA FISHING CHALLENGE
   ============================================================================

   WHAT THIS FILE DOES
   -------------------
   All the visual design for every page. It is deliberately one file so you
   only ever have one place to look.

   HOW IT IS ORGANISED
   -------------------
   PART 1  The control panel  (all the numbers and colours you might change)
   PART 2  Page foundations
   PART 3  The public scoreboard  (made to look like the physical sign)
   PART 4  View 1 — species board
   PART 5  View 2 — major awards
   PART 6  View 3 — sponsors and announcements
   PART 7  The admin, competitors and settings pages
   PART 8  The login gate
   PART 9  Printing

   HOW IT CONNECTS TO THE OTHER FILES
   ----------------------------------
   Every .html page loads this one stylesheet. The JavaScript files create
   elements using the class names defined here.
   ========================================================================= */


/* ###########################################################################
   PART 1 — THE CONTROL PANEL
   ###########################################################################

   >>> THIS IS THE BLOCK TO EDIT IF YOU WANT TO CHANGE HOW THE BOARD LOOKS <<<

   Everything below Part 1 is built from these values. Change a number here
   and it updates everywhere at once. Nothing else needs touching.
   ========================================================================= */

:root {

  /* ---- MAIN COLOURS -------------------------------------------------- */
  --colour-black:        #0b0b0b;   /* the outer background of the sign     */
  --colour-frame:        #171514;   /* the thick frame around the board     */
  --colour-red:          #c1272d;   /* award heading bars, divider lines    */
  --colour-red-bright:   #e8342c;   /* top of the distressed title gradient */
  --colour-red-deep:     #8d1319;   /* bottom of the title gradient         */
  --colour-orange:       #f2721f;   /* highlight in the title               */
  --colour-blue:         #14417e;   /* the blue section headings            */
  --colour-blue-strip:   #0f5fc4;   /* the sponsor strip across the bottom  */
  --colour-panel:        #f8f7f3;   /* white result panels                  */
  --colour-panel-alt:    #e7e5df;   /* light-grey alternating rows          */
  --colour-ink:          #14120f;   /* the main black text                  */
  --colour-ink-soft:     #57524a;   /* small grey labels like SENIOR        */
  --colour-hand:         #16224a;   /* the "marker pen" colour of results   */
  --colour-hand-empty:   #a9a49a;   /* the dash shown when nothing yet      */

  /* ---- BORDER THICKNESS ---------------------------------------------- */
  --border-frame:        6px;   /* the heavy black frame around the board   */
  --border-panel:        4px;   /* around each section panel                */
  --border-row:          2px;   /* the line between species rows            */
  --border-divider-red:  5px;   /* the red rule under a section heading     */

  /* ---- HEADING SIZES -------------------------------------------------- */
  --size-title:          70px;  /* STONKA FISHING CHALLENGE                 */
  --size-section-head:   34px;  /* REEF SPECIES, PELAGIC SPECIES ...        */
  --size-award-head:     40px;  /* KING/QUEEN OF THE CAPE ...               */
  --size-species-name:   25px;  /* CORAL TROUT, GRUNTER ...                 */
  --size-division-label: 18px;  /* SENIOR / JUNIOR / OPEN CLASS             */
  --size-weight:         28px;  /* the handwritten 4.650                    */
  --size-angler:         21px;  /* the handwritten angler name              */
  --size-comp-number:    16px;  /* the handwritten No. 0814                 */

  /* How wide the species-name part of a row is. Make this SMALLER if long
     angler names are getting cut off, BIGGER if species names are wrapping. */
  --species-name-width:  34%;
  --division-label-width: 72px;  /* "OPEN CLASS" wraps to two lines rather than needing more width */
  --size-award-total:    52px;  /* TOTAL — 32.150 kg                        */
  --size-award-name:     34px;  /* the winner's name on an award panel      */
  --size-award-fish:     21px;  /* each fish line inside an award panel     */
  --size-sponsor-strip:  34px;  /* PROUDLY BROUGHT TO YOU BY ...            */

  /* ---- ROW HEIGHTS AND SPACING ---------------------------------------- */
  --row-min-height:      42px;  /* smallest a single result line may be     */
  --row-padding-y:       5px;   /* space above and below each species row   */
  --row-padding-x:       12px;  /* space at the left and right of a row     */
  --section-head-height: 54px;  /* the blue heading strip inside a panel    */

  /* ---- SCREEN SPACING -------------------------------------------------- */
  --stage-padding:       16px;  /* black margin around the whole board      */
  --stage-gap:           12px;  /* gap between title, board and sponsors    */
  --column-gap:          12px;  /* gap between the three board columns      */

  /* ---- SPONSOR STRIP --------------------------------------------------- */
  --sponsor-strip-height: 88px;

  /* ---- TITLE BAR -------------------------------------------------------- */
  --title-bar-height:    118px;
  --logo-size:           98px;  /* the round Stonka logos in the corners    */

  /* ---- HOW LONG A FADE TAKES ------------------------------------------- */
  /* Keep this short. The brief says no distracting animation.              */
  --fade-duration:       400ms;

  /* ---- FONTS ------------------------------------------------------------ */
  /* The first name in each list is loaded from Google Fonts by the HTML.
     The names after it are fonts already on Windows and Mac, so the board
     still looks right if the internet drops out.                          */
  --font-display: 'Oswald', 'Haettenschweiler', 'Arial Narrow', Impact, sans-serif;
  /* --font-hand was originally a cursive script, matching the marker-pen
     look of the physical sign. Changed to the same bold block font as
     --font-display: the real LED screen this board runs on is only
     892 x 512 pixels across a 2m x 3.5m panel — a thin cursive stroke
     disappears entirely at that pixel density, where a thick block
     letter still reads clearly from a distance. Kept as a separate
     variable (rather than merged into --font-display) so you can still
     point it at a script font again later if you ever run this on a
     sharper screen. */
  --font-hand:    'Oswald', 'Haettenschweiler', 'Arial Narrow', Impact, sans-serif;
  --font-ui:      'Oswald', 'Segoe UI', Arial, sans-serif;
}


/* ###########################################################################
   PART 2 — PAGE FOUNDATIONS
   ######################################################################### */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--colour-black);
  color: var(--colour-ink);
  font-family: var(--font-ui);
}

/* Square corners everywhere. The brief specifically rules out rounded
   app-style cards, so nothing in this file sets a border-radius. */
button, input, select, textarea { border-radius: 0; font-family: inherit; }


/* ###########################################################################
   PART 3 — THE PUBLIC SCOREBOARD SHELL
   ###########################################################################

   HOW THE 1920 x 1080 SIZING WORKS
   --------------------------------
   The board is built at exactly 1920 x 1080 pixels, then scoreboard.js
   shrinks or grows the whole thing to fit whatever screen it is shown on.
   That means the LED screen gets a pixel-perfect layout, and you can still
   check it on a laptop without anything moving around.
   ========================================================================= */

body.scoreboard-page {
  overflow: hidden;          /* never show a scrollbar on the LED screen */
  background: var(--colour-black);
  cursor: none;              /* hide the mouse pointer on the big screen */
}

.stage-wrapper {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--colour-black);
}

.stage {
  position: relative;                /* so the status dot can sit in a corner */
  width: 1920px;
  height: 1080px;

  /* IMPORTANT: do not delete this line.
     .stage sits inside a flex container, and flex items are allowed to
     shrink by default. Without this the board would be SQUEEZED to fit a
     small window instead of being SCALED, which crushes the angler names.
     `flex: 0 0 auto` means "always stay exactly 1920 x 1080" and lets the
     transform below do the fitting properly. */
  flex: 0 0 auto;

  transform-origin: center center;   /* scoreboard.js sets the scale */
  background-color: var(--colour-black);
  background-image: var(--background-texture, none);
  background-size: 512px 512px;
  padding: var(--stage-padding);
  display: flex;
  flex-direction: column;
  gap: var(--stage-gap);
}

/* ---- THE TITLE BAR ------------------------------------------------------ */

.title-bar {
  height: var(--title-bar-height);
  flex: 0 0 var(--title-bar-height);
  background: linear-gradient(180deg, #2a2523 0%, #100e0d 55%, #050505 100%);
  border: var(--border-frame) solid #000;
  display: grid;
  grid-template-columns: var(--logo-size) 1fr var(--logo-size);
  align-items: center;
  gap: 20px;
  padding: 0 18px;
}

.title-logo {
  width: var(--logo-size);
  height: var(--logo-size);
  object-fit: contain;
}

/* The distressed red/orange headline.
   The gradient is painted INTO the letters, then a scratchy dark layer is
   printed on top of them by .board-title::after to give the worn look. */
.board-title {
  position: relative;
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-title);
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;

  background: linear-gradient(178deg,
              var(--colour-orange) 0%,
              var(--colour-red-bright) 42%,
              var(--colour-red) 68%,
              var(--colour-red-deep) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, 0.75));
}

/* The "distress". A copy of the same words in near-black, with an uneven
   mask so only flecks of it show. Raise the opacity for a more worn sign,
   lower it (or set it to 0) for clean modern lettering. */
.board-title::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  color: #15100e;
  opacity: 0.5;
  pointer-events: none;

  -webkit-mask-image:
    repeating-linear-gradient(97deg,  #000 0 2px, transparent 2px 9px),
    repeating-linear-gradient(6deg,   #000 0 1px, transparent 1px 6px),
    repeating-linear-gradient(-32deg, #000 0 3px, transparent 3px 23px);
  -webkit-mask-composite: source-in;
  mask-image:
    repeating-linear-gradient(97deg,  #000 0 2px, transparent 2px 9px),
    repeating-linear-gradient(6deg,   #000 0 1px, transparent 1px 6px),
    repeating-linear-gradient(-32deg, #000 0 3px, transparent 3px 23px);
  mask-composite: intersect;
}

/* ---- THE ROTATING VIEW AREA -------------------------------------------- */

.screens {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;             /* lets the flex child shrink properly */
}

/* Each view sits stacked on top of the others and fades in when its turn
   comes. Only one carries the .is-visible class at a time. */
.screen {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fade-duration) ease-in-out;
}

.screen.is-visible {
  opacity: 1;
  visibility: visible;
}

/* ---- THE SPONSOR STRIP -------------------------------------------------- */

.sponsor-strip {
  height: var(--sponsor-strip-height);
  flex: 0 0 var(--sponsor-strip-height);
  background: var(--colour-blue-strip);
  border: var(--border-frame) solid #000;
  display: grid;
  grid-template-columns: 1fr auto auto;   /* text | logo | status */
  align-items: center;
  gap: 24px;
  padding: 0 24px;
  overflow: hidden;
  transition: background 260ms ease, transform 260ms ease, box-shadow 260ms ease;
}

/* Turns orange — matching the new-leader announcement's branding — and
   grows slightly, for as long as the weigh-in ticker is showing, so the
   strip visibly stands out rather than just quietly swapping text.
   scoreboard.js adds/removes these same two classes here at the same time
   as it does on .sponsor-strip-message, so the colour, size and text all
   change together. Stays popped through is-ticker-leaving too, since the
   ticker is still visibly sliding out during that phase — it only reverts
   once both classes are gone and the sponsor text is fully back.

   transform-origin: top means the TOP edge stays put and the extra size
   from scale() grows downward, away from the row of results sitting just
   above the strip — this is what makes it "pop up and get bigger" WITHOUT
   covering that row. The small translateY(-6px) adds a touch of upward
   lift for the pop itself without seriously encroaching on it. transform
   never affects layout, so nothing else on the board moves or resizes
   when this happens. */
.sponsor-strip {
  transform-origin: top center;
}

.sponsor-strip.is-ticker-active,
.sponsor-strip.is-ticker-leaving {
  background: linear-gradient(90deg, #b03e0e 0%, var(--colour-orange) 45%, #ffab5c 100%);
  /* scaleY only — NOT scale()/scaleX. A uniform scale() also grows the
     strip WIDER, which at 1920px wide pushed it past the frame's left and
     right edges and clipped the start of the ticker text (seen live: "S"
     of "SPANGLED EMPEROR" cut off). Growing only the height avoids that
     entirely, since width never changes. */
  transform: translateY(-14px) scaleY(1.22);
  box-shadow: 0 -10px 24px rgba(0, 0, 0, 0.4);
}

/* Holds the sponsor text and the weigh-in ticker stacked exactly on top of
   each other — position:relative here is what makes their position:absolute
   below line up, and overflow:hidden clips the slide animation so it never
   spills outside the strip while it is moving. */
.sponsor-strip-message {
  position: relative;
  height: 100%;
  overflow: hidden;
  min-width: 0; /* lets it shrink inside the grid's 1fr track instead of forcing the strip wider */
}

.sponsor-strip-text,
.weighin-ticker {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: transform 260ms ease, opacity 260ms ease;
}

.sponsor-strip-text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-sponsor-strip);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

/* Default state: sponsor text showing, ticker hidden just below the strip
   ready to slide up. is-ticker-active / is-ticker-leaving on the parent
   (added by scoreboard.js) switch between the three states. */
.weighin-ticker {
  transform: translateY(28px);
  opacity: 0;
  pointer-events: none;
  gap: 14px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-sponsor-strip);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

.weighin-ticker-division {
  font-size: 0.62em;
  padding: 2px 10px;
  border: 2px solid rgba(255, 255, 255, 0.75);
  letter-spacing: 0.08em;
}

.weighin-ticker-weight { color: #ffe9b0; }

/* ENTERING / ACTIVE — sponsor text slides+fades out to the right, the
   ticker slides up from the bottom and fades in. Both happen together. */
.sponsor-strip-message.is-ticker-active .sponsor-strip-text,
.sponsor-strip-message.is-ticker-leaving .sponsor-strip-text {
  transform: translateX(60px);
  opacity: 0;
  pointer-events: none;
}

.sponsor-strip-message.is-ticker-active .weighin-ticker {
  transform: translateX(0) translateY(0);
  opacity: 1;
  pointer-events: auto;
}

/* LEAVING — the ticker itself now slides+fades out to the right (a
   different transform than how it arrived), a little faster than the
   entrance. Once this class is removed the sponsor text's own transition
   (above) brings it back by itself — no extra JS step needed for that. */
.sponsor-strip-message.is-ticker-leaving .weighin-ticker {
  transform: translateX(60px) translateY(0);
  opacity: 0;
  transition: transform 220ms ease, opacity 220ms ease;
}

.sponsor-strip-logo {
  height: calc(var(--sponsor-strip-height) - 20px);
  width: auto;
  object-fit: contain;
  transition: transform 260ms ease;
}

/* A light pop on the logo to go with the strip swapping to Stonka's own
   branding during a weigh-in — transform only, same as everywhere else on
   this board, so it costs nothing extra to run. */
.sponsor-strip.is-ticker-active .sponsor-strip-logo,
.sponsor-strip.is-ticker-leaving .sponsor-strip-logo {
  transform: scale(1.12);
}

/* ---- CONNECTION DOT AND LAST-UPDATED ------------------------------------ */

/* The small "am I connected?" line. It lives at the right-hand end of the
   sponsor strip so it never covers up a result. Set `display: none` here if
   you would rather the public board did not show it at all. */
.board-status {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-left: 20px;
  border-left: 2px solid rgba(255, 255, 255, 0.3);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.25;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.85);
  text-transform: uppercase;
  white-space: nowrap;
}

.status-dot {
  width: 12px;
  height: 12px;
  background: #6fbf4b;                    /* green = connected */
  box-shadow: 0 0 6px rgba(111, 191, 75, 0.9);
}

.status-dot.is-offline  { background: #d63b2f; box-shadow: 0 0 6px rgba(214, 59, 47, 0.9); }
.status-dot.is-practice { background: #e6a100; box-shadow: 0 0 6px rgba(230, 161, 0, 0.9); }


/* Sits above BOTH takeover overlays below (z-index higher than either),
   bottom-right, only visible while one of them is on screen — scoreboard.js
   toggles .is-shown on this alongside the overlay itself. Deliberately
   small and low-contrast: it's an escape hatch for whoever is standing at
   the laptop, not something meant to draw the crowd's eye. */
.announcement-skip {
  position: absolute;
  right: 22px;
  bottom: 22px;
  z-index: 60;
  padding: 8px 16px;
  border: none;
  border-radius: 20px;
  background: rgba(0, 0, 0, 0.35);
  color: rgba(255, 255, 255, 0.85);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.08em;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity 200ms ease, background 150ms ease, visibility 0s linear 200ms;
}

.announcement-skip.is-shown {
  opacity: 1;
  visibility: visible;
  transition: opacity 200ms ease, background 150ms ease;
}

.announcement-skip:hover {
  background: rgba(0, 0, 0, 0.55);
}


/* ###########################################################################
   PART 3B — THE NEW LEADER ANNOUNCEMENT
   ###########################################################################
   Covers the whole 1920 x 1080 stage — title bar, whichever view is
   showing, and the sponsor strip all at once — whenever scoreboard.js
   decides a species line has a new leader. Only opacity and transform are
   animated (no color/background/box-shadow animation), which the browser
   can run on the compositor alone without re-painting the page every
   frame — that is what keeps this smooth on modest hardware. */
.leader-announcement {
  position: absolute;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 38%, #ffab5c 0%, var(--colour-orange) 45%, #b03e0e 100%);
  opacity: 0;
  visibility: hidden;
  transform: scale(1.05);
  transition: opacity 380ms ease, transform 380ms ease, visibility 0s linear 380ms;
}

.leader-announcement.is-shown {
  opacity: 1;
  visibility: visible;
  transform: scale(1);
  transition: opacity 380ms ease, transform 380ms ease;
}

.leader-announcement-inner {
  text-align: center;
  /* A slow, gentle scale pulse for the whole 10 seconds it is on screen —
     transform-only, so it stays cheap to run the entire time it is up. */
  animation: leaderAnnouncementPulse 1.8s ease-in-out infinite;
}

@keyframes leaderAnnouncementPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.015); }
}

.leader-announcement-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  margin-bottom: 20px;
}

.leader-announcement-logo {
  width: 180px;
  height: 180px;
  object-fit: contain;
}

.leader-announcement-kicker {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 56px;
  letter-spacing: 0.16em;
  color: #2a1608;
  text-shadow: 0 2px 0 rgba(255, 255, 255, 0.3);
}

.leader-announcement-species {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 94px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #2a1608;
}

.leader-announcement-division {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 42px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #4a2c14;
  margin-bottom: 26px;
}

.leader-announcement-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 132px;
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 4px 0 rgba(0, 0, 0, 0.25);
  margin: 0 auto 20px;
  max-width: 1780px;
  /* No nowrap/ellipsis here on purpose: sized to fit every real
     competitor name on one line (checked against "Amy Valentine
     Schaverien", the longest in the current list), but an unusually
     long name should wrap to a second line rather than being cut off —
     truncating someone's name on their own announcement is worse than
     an occasional two-line wrap. */
}

.leader-announcement-weight {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 108px;
  color: #2a1608;
}

.leader-announcement-weight .weight-unit {
  font-size: 0.5em;
}


/* ###########################################################################
   PART 3C — THE MAJOR AWARD ANNOUNCEMENT
   ###########################################################################
   Same mechanism as PART 3B above (full-stage takeover, opacity/transform
   only) but reserved for the three big awards — King/Queen, Prince/Princess,
   Ultimate Team — so a new champion in one of those reads as a bigger
   moment than an ordinary species leader. Gold instead of orange is the
   only visual signal that distinguishes the two; scoreboard.js makes sure
   they never show at the same time. */
.major-award-announcement {
  position: absolute;
  inset: 0;
  z-index: 51;   /* one above .leader-announcement — see scoreboard.js's shared queue */
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 34%, #fff3c4 0%, #f2c74a 35%, #b8860b 100%);
  opacity: 0;
  visibility: hidden;
  transform: scale(1.05);
  transition: opacity 380ms ease, transform 380ms ease, visibility 0s linear 380ms;
}

.major-award-announcement.is-shown {
  opacity: 1;
  visibility: visible;
  transform: scale(1);
  transition: opacity 380ms ease, transform 380ms ease;
}

.major-award-announcement-inner {
  text-align: center;
  max-width: 1780px;
  animation: leaderAnnouncementPulse 1.8s ease-in-out infinite;
}

.major-award-announcement-kicker {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 44px;
  letter-spacing: 0.16em;
  color: #3a2a04;
  text-shadow: 0 2px 0 rgba(255, 255, 255, 0.3);
  margin-bottom: 6px;
}

.major-award-announcement-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 78px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #3a2a04;
  margin-bottom: 18px;
}

.major-award-announcement-name-line {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 20px;
  margin-bottom: 24px;
}

.major-award-announcement-number {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 40px;
  color: #3a2a04;
}

.major-award-announcement-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 116px;
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 4px 0 rgba(0, 0, 0, 0.25);
}

.major-award-announcement-fish {
  margin: 0 auto 24px;
  padding: 0;
  list-style: none;
  columns: 2;
  column-gap: 50px;
  font-family: var(--font-hand);
  font-size: 34px;
  line-height: 1.3;
  color: #3a2a04;
  max-width: 1200px;
}

.major-award-announcement-fish li {
  break-inside: avoid;
  display: flex;
  justify-content: space-between;
  gap: 20px;
  border-bottom: 1px dotted rgba(58, 42, 4, 0.35);
}

.major-award-announcement-fish .fish-label  { text-transform: uppercase; letter-spacing: 0.02em; }
.major-award-announcement-fish .fish-weight { font-weight: 700; white-space: nowrap; }
.major-award-announcement-fish .fish-caught-by {
  font-size: 22px;
  opacity: 0.8;
  text-transform: uppercase;
}

.major-award-announcement-total-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 26px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #3a2a04;
}

.major-award-announcement-total-value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 100px;
  color: #3a2a04;
}

.major-award-announcement-total-value .weight-unit {
  font-size: 0.5em;
}


/* ###########################################################################
   PART 4 — VIEW 1: THE SPECIES BOARD
   ###########################################################################
   Three columns. The middle one holds two sections stacked on top of each
   other, exactly like the physical sign.
   ========================================================================= */

.species-grid {
  height: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--column-gap);
}

.board-column {
  display: flex;
  flex-direction: column;
  gap: var(--column-gap);
  min-height: 0;
}

/* A section = one titled panel such as REEF SPECIES.
   scoreboard.js sets flex-grow on these so that columns with more result
   lines get more height. That is what keeps the board dense with no gaps. */
.section-panel {
  background: var(--colour-panel);
  border: var(--border-panel) solid #000;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

/* The blue section heading, with a red rule beneath it. */
.section-head {
  flex: 0 0 auto;
  min-height: var(--section-head-height);
  display: flex;
  align-items: center;
  padding: 4px var(--row-padding-x);
  background: var(--colour-panel);
  border-bottom: var(--border-divider-red) solid var(--colour-red);
}

.section-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-section-head);
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--colour-blue);
}

.section-rows {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* One species = one row. Alternating rows are light grey, like the sign. */
.species-row {
  display: grid;
  grid-template-columns: var(--species-name-width) 1fr;
  align-items: center;
  gap: 6px;
  padding: var(--row-padding-y) var(--row-padding-x);
  border-bottom: var(--border-row) solid var(--colour-ink);
  background: var(--colour-panel);
  min-height: var(--row-min-height);
}

.species-row:nth-child(even) { background: var(--colour-panel-alt); }
.species-row:last-child      { border-bottom: none; }

.species-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-species-name);
  line-height: 1.02;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--colour-ink);
}

/* The small grey note under a species name, e.g. SPOTTY / SCHOOL / GREY. */
.species-note {
  display: block;
  font-family: var(--font-ui);
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.03em;
  color: var(--colour-ink-soft);
  margin-top: 1px;
}

/* The stack of result lines belonging to one species. */
.species-lines {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  min-width: 0;
}

/* One result line: [ SENIOR ] [ 4.650 ] [ TROY MILLER / No. 0814 ] */
.result-line {
  display: grid;
  grid-template-columns: var(--division-label-width) auto 1fr;
  align-items: center;
  gap: 7px;
  min-width: 0;
}

/* When a species has two divisions, a thin red rule separates them —
   this is the "clearly separate them within the same row" requirement. */
.result-line + .result-line {
  border-top: 2px solid var(--colour-red);
  padding-top: 3px;
}

.line-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--size-division-label);
  line-height: 1.05;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--colour-ink-soft);
}

.line-weight {
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--size-weight);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
  white-space: nowrap;
}

.line-angler {
  min-width: 0;
  line-height: 1.02;
}

.angler-name {
  display: block;
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--size-angler);
  letter-spacing: 0.02em;
  color: var(--colour-hand);
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.angler-number {
  display: block;
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: var(--size-comp-number);
  letter-spacing: 0.02em;
  color: var(--colour-hand);
  /* Was 0.85 — raised close to full strength. A low-resolution LED panel
     has far fewer pixels to render a "faded" grey with; dimmed text like
     this is what disappears first at a distance. */
  opacity: 0.96;
  white-space: nowrap;
}

/* Shown when nobody has weighed in for that line yet. */
.result-line.is-empty .line-weight,
.result-line.is-empty .angler-name { color: var(--colour-hand-empty); }

/* A small red flag on any line an administrator has forced by hand. */
.override-flag {
  display: inline-block;
  margin-left: 6px;
  padding: 0 5px;
  background: var(--colour-red);
  color: #fff;
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.05em;
  vertical-align: middle;
}


/* ###########################################################################
   PART 5 — VIEW 2: MAJOR AWARDS
   ###########################################################################
   Red heading bar, white panel underneath, big total on the right.
   ========================================================================= */

.awards-screen {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--column-gap);
}

.award-panel {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  border: var(--border-panel) solid #000;
  background: var(--colour-panel);
  min-height: 0;
  overflow: hidden;
}

.award-head {
  flex: 0 0 auto;
  background: var(--colour-red);
  border-bottom: var(--border-panel) solid #000;
  padding: 6px 22px;
}

.award-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-award-head);
  line-height: 1.1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

.award-body {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 30px;
  padding: 10px 26px;
  min-height: 0;
  /* Safety net: if an award is ever configured to count a very large number
     of fish, clip rather than push the panel out of shape. */
  overflow: hidden;
}

.award-winner {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
}

.award-name-line {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 4px;
  white-space: nowrap;
}

.award-number {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 26px;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
}

.award-name {
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--size-award-name);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The list of fish that made up the total.
   One column, like the physical sign. scoreboard.js adds .is-two-column when
   an award counts more than six fish, so a long list still fits the panel. */
.award-fish {
  margin: 0;
  padding: 0;
  list-style: none;
  columns: 1;
  column-gap: 40px;
  font-family: var(--font-hand);
  font-size: var(--size-award-fish);
  line-height: 1.22;
  color: var(--colour-hand);
  max-width: 620px;          /* keeps the weights near the names, not adrift */
}

.award-fish.is-two-column {
  columns: 2;
  max-width: 1100px;
}

.award-fish li {
  break-inside: avoid;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  border-bottom: 1px dotted rgba(22, 34, 74, 0.35);
}

.award-fish .fish-label  { text-transform: uppercase; letter-spacing: 0.02em; }
.award-fish .fish-weight { font-weight: 700; white-space: nowrap; }
.award-fish .fish-caught-by {
  font-size: 17px;
  opacity: 0.85; /* was 0.7 — too faint to read on a low-resolution LED panel */
  text-transform: uppercase;
}

/* The big TOTAL — 32.150 kg block on the right. */
.award-total {
  text-align: right;
  border-left: var(--border-row) solid var(--colour-ink);
  padding-left: 28px;
  white-space: nowrap;
}

.award-total .total-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--colour-ink-soft);
}

.award-total .total-value {
  display: block;
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--size-award-total);
  line-height: 1.05;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
}

.award-total .total-unit {
  font-size: 30px;
  letter-spacing: 0.02em;
}

/* The small "kg" after a weight on the species board and in an award's
   fish list. Uses a relative em size so it scales automatically with
   whatever weight number it is sitting next to, rather than needing its
   own fixed size per context. */
.weight-unit {
  font-size: 0.6em;
  letter-spacing: 0.02em;
}

/* Shown inside an award panel while nobody qualifies yet. */
.award-empty {
  font-family: var(--font-hand);
  font-size: 32px;
  color: var(--colour-hand-empty);
}


/* ###########################################################################
   PART 5A — VIEW 2B: COMPETITION-WIDE TOTALS  (optional screen, off by default)
   ###########################################################################
   Two big block-text tiles side by side — deliberately the simplest screen
   in the rotation, legible from across a paddock on the low-resolution
   LED panel this board is built for. */
.stats-screen {
  height: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--column-gap);
}

.stats-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: var(--border-panel) solid #000;
  background: var(--colour-panel);
}

.stats-value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 220px;
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--colour-blue);
}

.stats-unit {
  font-size: 0.35em;
  letter-spacing: 0.02em;
}

.stats-label {
  margin-top: 18px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 42px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--colour-red);
}


/* ###########################################################################
   PART 5B — VIEW 3: TOP 5 ULTIMATE TEAMS  (optional screen, off by default)
   ###########################################################################
   award.places already caps at 5 (AWARD_PLACES_TO_CALCULATE in
   competition-config.js), so this is just five stacked rows, each with the
   team's fish (species, how it was caught, who caught it, weight) on the
   left and a big total on the right — the same visual language as the
   award panels above. */
.teams-screen {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--column-gap);
}

.teams-head {
  flex: 0 0 auto;
  background: var(--colour-red);
  border: var(--border-panel) solid #000;
  padding: 6px 22px;
}

.teams-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-award-head);
  line-height: 1.1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

.teams-list {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--column-gap);
  min-height: 0;
}

.team-row {
  flex: 1 1 0;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 24px;
  border: var(--border-panel) solid #000;
  background: var(--colour-panel);
  padding: 8px 26px;
  min-height: 0;
  overflow: hidden;
}

.team-rank {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 56px;
  color: var(--colour-red);
  min-width: 60px;
  text-align: center;
}

.team-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
}

.team-name {
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--size-award-name);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 4px;
}

/* Shown before the name on the individual-award top-5 screens (King/Queen,
   Prince/Princess) — the team award has no competitor number, so this is
   simply absent there. */
.team-number {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 0.4em;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
  margin-right: 10px;
  text-transform: none;
}

.team-fish-list {
  margin: 0;
  padding: 0;
  list-style: none;
  columns: 2;
  column-gap: 40px;
  font-family: var(--font-hand);
  font-size: var(--size-award-fish);
  line-height: 1.22;
  color: var(--colour-hand);
  max-width: 1000px;
}

.team-fish-list li {
  break-inside: avoid;
  display: flex;
  align-items: baseline;
  gap: 10px;
  border-bottom: 1px dotted rgba(22, 34, 74, 0.35);
}

.team-fish-label  { text-transform: uppercase; letter-spacing: 0.02em; }
.team-fish-method {
  font-size: 17px;
  opacity: 0.85;
  text-transform: uppercase;
}
.team-fish-caught-by {
  font-size: 17px;
  opacity: 0.85;
  text-transform: uppercase;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.team-fish-weight { font-weight: 700; white-space: nowrap; margin-left: auto; }

.team-total {
  text-align: right;
  border-left: var(--border-row) solid var(--colour-ink);
  padding-left: 28px;
  white-space: nowrap;
}

.team-total .total-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--colour-ink-soft);
}

.team-total .total-value {
  display: block;
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: 48px;
  line-height: 1.05;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
}

.team-total .total-unit {
  font-size: 24px;
  letter-spacing: 0.02em;
}

/* The "Ones to Watch" screen's right-hand column — sits where .team-total
   sits on the other top-5 screens, but shows progress pills (e.g.
   "3/4 REEF") above the partial total instead of just a total. */
.watch-progress {
  text-align: right;
  border-left: var(--border-row) solid var(--colour-ink);
  padding-left: 28px;
  white-space: nowrap;
}

.watch-progress-item {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  background: var(--colour-red);
  border-radius: 4px;
  padding: 3px 9px;
  margin: 0 0 6px 6px;
}

.watch-progress-item.is-complete {
  background: #2f7d3c; /* green — this part of the requirement is already met */
}

.watch-progress .total-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--colour-ink-soft);
}

.watch-progress .total-value {
  display: block;
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: 40px;
  line-height: 1.05;
  letter-spacing: 0.02em;
  color: var(--colour-hand);
}

.watch-progress .total-unit {
  font-size: 20px;
  letter-spacing: 0.02em;
}

.teams-empty {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-hand);
  font-size: 32px;
  color: var(--colour-hand-empty);
}


/* ###########################################################################
   PART 6 — VIEW 3: SPONSORS AND ANNOUNCEMENTS  (optional screen)
   ######################################################################### */

.sponsor-screen {
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: var(--column-gap);
}

.announce-panel {
  background: var(--colour-panel);
  border: var(--border-panel) solid #000;
  padding: 14px 26px;
}

.announce-panel h2 {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-section-head);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--colour-blue);
  border-bottom: var(--border-divider-red) solid var(--colour-red);
  padding-bottom: 6px;
}

.announce-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-hand);
  font-size: 34px;
  line-height: 1.3;
  color: var(--colour-hand);
}

.announce-next {
  margin-top: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 34px;
  text-transform: uppercase;
  color: var(--colour-red);
}

.sponsor-logo-grid {
  background: var(--colour-panel);
  border: var(--border-panel) solid #000;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-auto-rows: 1fr;
  align-items: stretch;
  justify-items: stretch;
  gap: 20px;
  padding: 20px;
  min-height: 0;
  overflow: hidden;  /* a logo's own pixel size must never push past this panel */
}

.sponsor-logo-grid img {
  width: 100%;
  height: 100%;
  /* Grid items default to a content-based minimum size, which for an <img>
     is its natural pixel dimensions — without overriding it to 0 here, a
     large source image ignores height:100% and overflows past the panel
     and the sponsor strip below it instead of being scaled down to fit. */
  min-width: 0;
  min-height: 0;
  object-fit: contain;
}


/* ###########################################################################
   PART 7 — ADMIN, COMPETITORS AND SETTINGS PAGES
   ###########################################################################
   These are working screens for volunteers, not the show board. Big targets,
   high contrast, no clutter. They scroll normally and adapt to any laptop.
   ========================================================================= */

body.admin-page {
  background: #16151a;
  color: #f2f1ee;
  min-height: 100vh;
}

.admin-header {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  padding: 12px 22px;
  background: #000;
  border-bottom: var(--border-panel) solid var(--colour-red);
  position: sticky;
  top: 0;
  z-index: 20;
}

.admin-header h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 30px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #fff;
}

.admin-nav { display: flex; gap: 8px; flex-wrap: wrap; }

.admin-nav a {
  padding: 9px 18px;
  background: #26242c;
  border: 2px solid #3c3945;
  color: #f2f1ee;
  font-family: var(--font-display);
  font-size: 18px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
}

.admin-nav a:hover      { background: #34313d; }
.admin-nav a.is-current { background: var(--colour-red); border-color: var(--colour-red); }

.admin-header .spacer { flex: 1 1 auto; }

.admin-main {
  max-width: 1500px;
  margin: 0 auto;
  padding: 22px;
}

/* ---- CONNECTION BADGE --------------------------------------------------- */

.conn-badge {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 18px;
  border: 3px solid #000;
  background: #6fbf4b;
  color: #06210a;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.conn-badge[data-status="offline"]  { background: #d63b2f; color: #fff; }
.conn-badge[data-status="saving"]   { background: #e6a100; color: #2a1c00; }
.conn-badge[data-status="saved"]    { background: #2f9e44; color: #fff; }
.conn-badge[data-status="error"]    { background: #8f1a1f; color: #fff; }
.conn-badge[data-status="practice"] { background: #e6a100; color: #2a1c00; }

.conn-message {
  font-family: var(--font-ui);
  font-size: 15px;
  color: #ffb4ae;
  max-width: 420px;
}

/* ---- CARDS AND FORMS ---------------------------------------------------- */

.panel {
  background: #211f26;
  border: 3px solid #35323d;
  border-top: 6px solid var(--colour-red);
  padding: 20px;
  margin-bottom: 22px;
}

.panel > h2 {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 26px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
}

.panel > h2 .hint {
  display: block;
  font-family: var(--font-ui);
  font-weight: 400;
  font-size: 15px;
  letter-spacing: 0;
  text-transform: none;
  color: #a5a0ad;
  margin-top: 3px;
}

.field { margin-bottom: 18px; }

.field label {
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #ddd9e2;
}

.field .field-hint {
  display: block;
  margin-top: 5px;
  font-family: var(--font-ui);
  font-size: 14px;
  color: #a5a0ad;
}

/* Big form controls so they are easy to hit in a busy weigh-in tent. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
select,
textarea {
  width: 100%;
  padding: 14px 14px;
  background: #fff;
  border: 3px solid #000;
  color: #14120f;
  font-family: var(--font-ui);
  font-size: 24px;
}

input:focus, select:focus, textarea:focus {
  outline: 4px solid var(--colour-orange);
  outline-offset: 1px;
}

input:disabled, select:disabled, textarea:disabled { background: #d9d7d2; color: #6b6862; }

textarea { min-height: 110px; resize: vertical; font-size: 19px; }

/* The weight box gets extra size — it is the number that matters most. */
input.weight-input {
  font-family: var(--font-display);
  font-size: 52px;
  font-weight: 700;
  text-align: center;
  letter-spacing: 0.04em;
  padding: 10px;
}

.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
}

/* ---- BUTTONS ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 26px;
  border: 3px solid #000;
  background: #3d3947;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}

.btn:hover:not(:disabled)  { filter: brightness(1.14); }
.btn:active:not(:disabled) { transform: translateY(2px); }
.btn:disabled              { opacity: 0.45; cursor: not-allowed; }

.btn-primary { background: #2f9e44; }
.btn-danger  { background: #c1272d; }
.btn-warn    { background: #e6a100; color: #2a1c00; }
.btn-quiet   { background: #4a4653; }

/* The main SAVE RESULT button. Deliberately enormous. */
.btn-huge {
  width: 100%;
  padding: 26px;
  font-size: 40px;
  letter-spacing: 0.1em;
}

.btn-row { display: flex; gap: 14px; flex-wrap: wrap; }

/* ---- MESSAGES ----------------------------------------------------------- */

.form-error {
  margin: 0 0 16px;
  padding: 14px 18px;
  background: #4a1113;
  border: 3px solid var(--colour-red);
  color: #ffd9d6;
  font-size: 20px;
  display: none;
}

.form-error.is-shown { display: block; }

/* The full-screen RESULT SAVED confirmation. */
.saved-flash {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 14px;
  background: rgba(9, 40, 16, 0.94);
  text-align: center;
}

.saved-flash.is-shown { display: flex; }

.saved-flash strong {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 120px;
  letter-spacing: 0.06em;
  color: #7ff09a;
  text-transform: uppercase;
  line-height: 1;
}

.saved-flash span {
  font-family: var(--font-ui);
  font-size: 32px;
  color: #d7ffe2;
}

/* ---- TABLES (recent entries, competitor list) --------------------------- */

.data-table {
  width: 100%;
  border-collapse: collapse;
  background: #fff;
  color: #14120f;
}

.data-table th {
  background: #000;
  color: #fff;
  font-family: var(--font-display);
  font-size: 17px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: left;
  padding: 11px 12px;
  position: sticky;
  top: 0;
}

.data-table td {
  padding: 11px 12px;
  border-bottom: 2px solid #d6d3cd;
  font-size: 19px;
  vertical-align: middle;
}

.data-table tr:nth-child(even) td { background: #f0eee9; }

.data-table td.numeric {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 23px;
  white-space: nowrap;
}

.table-scroll { max-height: 460px; overflow: auto; border: 3px solid #000; }

.table-actions { display: flex; gap: 8px; white-space: nowrap; }

.btn-small { padding: 7px 14px; font-size: 16px; border-width: 2px; }

.empty-note {
  padding: 26px;
  text-align: center;
  color: #a5a0ad;
  font-size: 20px;
}

.tag {
  display: inline-block;
  padding: 2px 9px;
  border: 2px solid currentColor;
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.tag-senior { color: #14417e; }
.tag-junior { color: #a34a00; }
.tag-locked { color: #8f1a1f; }

/* Used on the settings page's spreadsheet-import preview table, to show at
   a glance what each row will do before the administrator commits. */
.tag-import-new    { color: #1a7a34; }
.tag-import-update { color: #0f5fc4; }
.tag-import-skip   { color: #b5860b; }

/* ---- THE SEARCHABLE COMPETITOR PICKER ----------------------------------- */

.picker { position: relative; }

.picker-list {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  /* Below .admin-header's z-index (20) on purpose — the sticky nav bar
     must stay visible on top when the dropdown list would otherwise
     scroll underneath it, especially on a phone where the list is tall
     relative to the screen. */
  z-index: 15;
  max-height: 320px;
  overflow: auto;
  background: #fff;
  border: 3px solid #000;
  border-top: none;
  display: none;
}

.picker-list.is-open { display: block; }

.picker-option {
  display: grid;
  /* minmax(90px, max-content) — wide enough for a short board number like
     "0741", but grows automatically for longer registration ids like
     "STONKA0099" instead of letting them overlap the name column. */
  grid-template-columns: minmax(90px, max-content) 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  border-bottom: 2px solid #e3e0da;
  color: #14120f;
  font-size: 21px;
  cursor: pointer;
}

.picker-option:hover,
.picker-option.is-active { background: #ffe6b8; }

.picker-option .opt-number {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 22px;
}

.picker-chosen {
  margin-top: 8px;
  padding: 12px 16px;
  background: #14417e;
  color: #fff;
  font-size: 22px;
  display: none;
}

.picker-chosen.is-shown { display: block; }

/* ---- SETTINGS PAGE ODDS AND ENDS ---------------------------------------- */

.settings-grid {
  display: grid;
  /* min(420px, 100%) instead of a bare 420px — a bare number here would
     force every panel to be at least 420px wide even on a phone screen
     narrower than that, causing the whole page to scroll sideways. */
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: 22px;
  align-items: start;
}

.danger-panel { border-top-color: #ff4b3e; background: #2b1416; }

.mode-note {
  padding: 14px 18px;
  margin-bottom: 22px;
  background: #4a3a00;
  border: 3px solid #e6a100;
  color: #ffe9b0;
  font-size: 19px;
}

.override-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 2px solid #35323d;
}


/* ###########################################################################
   PART 8 — THE LOGIN GATE
   ######################################################################### */

/* Shown across the top of admin pages while shared.js's REQUIRE_LOGIN is
   set to false — see the big comment above requireAdmin() in shared.js.
   Deliberately loud and impossible to mistake for anything else on the
   page, and NOT sticky on purpose: it only needs to be seen once when the
   page loads, not fight the header for space while scrolling. */
.login-disabled-banner {
  background: var(--colour-red);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.03em;
  text-align: center;
  padding: 10px 18px;
  border-bottom: 3px solid #000;
}

.login-gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: #0b0b0b;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.login-box {
  width: min(480px, 100%);
  background: #211f26;
  border: 4px solid #000;
  border-top: 10px solid var(--colour-red);
  padding: 32px;
}

.login-box h1 {
  margin: 0 0 20px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 40px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
  text-align: center;
}

.login-box label {
  display: block;
  margin: 14px 0 6px;
  font-family: var(--font-display);
  font-size: 19px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #ddd9e2;
}

.login-box .btn { margin-top: 24px; }

.login-error {
  margin: 16px 0 0;
  color: #ff9c93;
  font-size: 17px;
  line-height: 1.45;
}

.login-mode {
  margin: 0;
  font-size: 16px;
  color: #a5a0ad;
  text-align: center;
}

.login-mode.is-practice {
  background: #4a3a00;
  border: 2px solid #e6a100;
  color: #ffe9b0;
  padding: 10px;
}

/* ---- THE LANDING PAGE (index.html) -------------------------------------- */

.landing {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 30px;
  background: var(--colour-black);
}

.landing-inner { width: min(1000px, 100%); text-align: center; }

.landing .board-title { font-size: 62px; margin-bottom: 8px; }

.landing p.tagline {
  color: #a5a0ad;
  font-size: 20px;
  margin: 0 0 34px;
}

.landing-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 18px;
}

.landing-card {
  display: block;
  padding: 30px 22px;
  background: #211f26;
  border: 4px solid #000;
  border-top: 8px solid var(--colour-red);
  color: #fff;
  text-decoration: none;
  text-align: left;
}

.landing-card:hover { background: #2c2934; }

.landing-card strong {
  display: block;
  font-family: var(--font-display);
  font-size: 27px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 8px;
}

.landing-card span { color: #a5a0ad; font-size: 17px; line-height: 1.45; }


/* ---- APP FOOTER (the small "app design by" credit) -----------------------
   Used on the landing page and every admin page, never on the public
   scoreboard — the scoreboard already has its own sponsor strip, and this
   is a credit for the app itself, not an event sponsor. */
.app-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 22px 18px;
  color: #6e6a76;
  font-family: var(--font-ui);
  font-size: 13px;
  letter-spacing: 0.03em;
  text-align: center;
}

.app-footer img {
  height: 22px;
  width: auto;
  opacity: 0.85;
}

.app-footer strong {
  color: #9b96a5;
  font-weight: 600;
}


/* ###########################################################################
   PART 9 — PRINTING  (the final results report)
   ######################################################################### */

@media print {
  body { background: #fff; color: #000; }
  .admin-header, .admin-nav, .btn, .no-print { display: none !important; }
  .panel { background: #fff; border: 2px solid #000; color: #000; page-break-inside: avoid; }
  .panel > h2 { color: #000; }
  .data-table th { background: #ddd; color: #000; }
  .report-area { display: block !important; }
}


/* ###########################################################################
   PART 10 — SMALL SCREENS  (a volunteer using a phone at the weigh-in table)
   ###########################################################################
   The admin pages were sized for a laptop first. These are the sizes that
   turned out too large once actually tested on a real phone width — the
   SAVE RESULT button was wrapping onto three lines, and the RESULT SAVED
   confirmation text ran off the edge of the screen. Everything else in the
   layout already adapts on its own (fields stack, tables scroll sideways),
   so only the oversized text needs a phone-specific size here. */
@media (max-width: 480px) {
  .btn-huge {
    font-size: 26px;
    letter-spacing: 0.06em;
    padding: 20px;
  }

  .saved-flash strong {
    font-size: 52px;
  }

  .saved-flash span {
    font-size: 22px;
    padding: 0 20px;
    text-align: center;
  }

  input.weight-input {
    font-size: 38px;
  }

  .login-box h1 {
    font-size: 30px;
  }
}
