/* Hot Dog Fantasy — a stand on the sideline, at a night game.
   The page itself is the field. The hero is the stand: awning, ketchup red,
   and the dog. Everything else is a stadium scoreboard — near-black panels
   with the league's money lit on them in ketchup (hot dogs you have to eat)
   and mustard (dogs banked against them — see src/ledger.js; nobody ever
   hands anybody a hot dog). */

:root {
  /* the field */
  --turf: #16351f;
  --turf-lit: #1d4227;
  --turf-deep: #0d2314;

  /* The boards. Deliberately neutral and cool, not warm: a brown panel
     reads as leather or card stock, and the whole point is that these are
     lit displays. All the warmth on them comes from the mustard and the
     ketchup, which is where the hot dog lives. */
  --panel: #0e1311;
  --panel-2: #151b19;
  --panel-3: #1d2421;
  --inset: #070a09;
  --line: #2b3431;
  --line-soft: #1f2725;
  --bezel: #39433f;

  --text: #e9f1ec;
  --muted: #8ea299;
  --muted-dim: #5e6f68;

  --mustard: #f5b31e;
  --mustard-bright: #ffc94f;
  --mustard-deep: #a8750a;
  --ketchup: #e64457;
  --ketchup-bright: #ff7b88;
  --ketchup-deep: #a3162a;
  --relish: #6fbf5f;

  /* what the stand left behind: the cream its lettering was painted in */
  --cream: #f7f1e4;

  --font: "Archivo", system-ui, -apple-system, sans-serif;
  --font-figure: "Oswald", "Archivo Narrow", var(--font);
  --font-display: "Graduate", var(--font);

  --radius: 16px;
  --radius-sm: 11px;
  --gutter: 16px;

  /* On a dark theme the shadow does the separating, so it goes deeper and
     an inner top highlight does the work the border used to. */
  --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.35);
  --shadow: 0 2px 6px rgba(0, 0, 0, 0.3), 0 18px 40px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 36px 80px rgba(0, 0, 0, 0.7);
}

* { box-sizing: border-box; }

html { min-height: 100%; background-color: var(--turf-deep); }

/* ---------------------------------------------------------------- field */

/* A real field, laid out the way one actually is: 100 yards of play with a
   ten-yard end zone at each end, a line every five yards, numbers every ten
   with the 50 in the middle, and two rows of hash marks between them.
   Everything is a percentage, so it stays a field at any width.

   Fixed to the viewport rather than sized to the document: the page is far
   taller than it is wide, and a field stretched over the whole scroll height
   would put the numbers thousands of pixels apart and out of sight. */
.gridiron {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background-image:
    /* Mown stripes, one cut every five yards, landing exactly on the yard
       lines. The whole field is 120 yards, so five yards is 4.1667% and a
       light-then-dark pair repeats every 8.3333%. That lands a cut edge on
       both goal lines, on every yard line and on the 50. Ten-yard cuts were
       the first version and read as too wide; five is how a field is
       actually mown. (Before either, the stripes were every 6.25% of the
       viewport and lined up with nothing.) */
    repeating-linear-gradient(
      90deg,
      rgba(255, 255, 255, 0.042) 0 4.1667%,
      rgba(0, 0, 0, 0.075) 4.1667% 8.3333%
    ),
    linear-gradient(180deg, var(--turf-lit), var(--turf-deep));
}

/* Darkens the edges so the middle of the field reads as the lit part. Last
   child of the stack, so it sits over the markings too. */
.gridiron::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(130% 75% at 50% 0%, rgba(255, 255, 255, 0.06), transparent 62%),
    radial-gradient(110% 100% at 50% 50%, transparent 38%, rgba(0, 0, 0, 0.58) 100%);
}

/* End zones: ten yards each, so 1/12th of the 120-yard whole. */
/* Painted solid, not a wash over the turf: the mown stripes stop dead at
   the goal line, which is what makes the end zone read as an end zone. A
   translucent darkening let the cuts run straight through it, and a
   wordmark and a hot dog were tried in here and taken back out. */
.ez {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 8.3333%;
  background: var(--turf-deep);
}
.ez.left { left: 0; }
.ez.right { right: 0; }

/* The 100 yards between the goal lines. Every measurement inside is a
   percentage of this, which is what makes the yard numbers land on their
   lines: the 50 is at 50%, each 10 is ten percent along. */
.field-play {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 8.3333%;
  right: 8.3333%;
  /* a line every five yards = every 5% */
  background-image:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.13) 0 2px, transparent 2px 5%);
}
/* The goal lines are the heavy ones. */
.field-play::before,
.field-play::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 3px;
  background: rgba(255, 255, 255, 0.24);
}
.field-play::before { left: 0; }
.field-play::after { right: 0; }

/* Two rows of ticks, one per yard, the way hash marks run down a field. */
.hashes {
  position: absolute;
  left: 0;
  right: 0;
  height: 9px;
  background-image:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.12) 0 2px, transparent 2px 1%);
}
.hashes.a { top: 30%; }
.hashes.b { bottom: 30%; }

.yard-nums {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  font-family: var(--font-display);
  font-size: clamp(13px, 2.6vw, 30px);
  line-height: 1;
  color: rgba(255, 255, 255, 0.14);
  letter-spacing: 0.06em;
}
.yard-nums.top { top: 9%; }
.yard-nums.bottom { bottom: 9%; }
.yard-nums span {
  position: absolute;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}

html, body {
  margin: 0;
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  /* A single unbreakable string (a long team name, a pasted URL) would
     otherwise widen the document and clip every section on a phone. */
  overflow-wrap: anywhere;
}

body { min-height: 100vh; background: transparent; }

/* Grain. On a dark theme `multiply` would only darken uniformly and vanish;
   `overlay` speckles both ways, which is what gives the turf its texture.
   Pointer-events off so it never eats a click. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  opacity: 0.075;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

.page {
  max-width: 940px;
  margin: 0 auto;
  padding: 6px var(--gutter) 80px;
}

/* --------------------------------------------------------------- brand */

/* There used to be a ketchup-red stand here, awning and all. It was a tall
   red slab on a phone for the sake of two lines of text, so it is gone: the
   dog and the wordmark now sit straight on the turf, in one row with
   whoever you are at the end of it. The text shadows are what keep cream
   letters legible over the field's stripes — there is no panel under them. */

.site-header {
  margin-bottom: 20px;
  text-align: center;
}

/* Dog above the wording, both centred on the field. */
.brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

/* The drawn dog starts 21.5% of the way down its own file (77 transparent
   rows of 358), so a chunk of the gap above it is inside the image and no
   amount of trimming above would close it. --dog-w is what both the width
   and that correction are sized from: the empty band is 0.12 x the width
   (0.215 of the 0.559 aspect), so the negative margin lifts the drawn dog
   to the top of its own box and the gap becomes the one in the CSS. */
.brand { --dog-w: clamp(126px, 27vw, 208px); }

.hero-dog {
  display: block;
  width: var(--dog-w);
  margin-top: calc(var(--dog-w) * -0.12);
  height: auto;
  transform: rotate(-7deg);
  /* A real cast shadow, not a box-shadow on a rectangle. */
  filter:
    drop-shadow(0 14px 14px rgba(0, 0, 0, 0.5))
    drop-shadow(0 2px 2px rgba(0, 0, 0, 0.35));
  animation: bob 5.5s ease-in-out infinite;
}

@keyframes bob {
  0%, 100% { transform: rotate(-7deg) translateY(0); }
  50%      { transform: rotate(-6deg) translateY(-7px); }
}

.wordmark {
  position: relative;
  font-family: var(--font-display);
  font-weight: 400;
  margin: 0;
  color: var(--cream);
  line-height: 1;
  text-shadow:
    0 2px 0 rgba(0, 0, 0, 0.45),
    0 4px 14px rgba(0, 0, 0, 0.6),
    0 12px 34px rgba(0, 0, 0, 0.5);
}
.wordmark .w1 {
  display: block;
  font-size: clamp(30px, 8vw, 50px);
  letter-spacing: 0.01em;
}
.wordmark .w1 em {
  font-style: normal;
  color: var(--mustard);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.5), 0 0 34px rgba(245, 179, 30, 0.55);
}
.wordmark .w2 {
  display: block;
  font-size: clamp(13px, 3.2vw, 21px);
  letter-spacing: 0.3em;
  margin-top: 7px;
  text-indent: 0.3em; /* offsets the trailing letter-space so it sits centred */
  color: rgba(247, 241, 228, 0.92);
}

/* ---------------------------------------------------------- scoreboards */

/* A board in a bezel: the LED grid is a 4px dot lattice over the panel, and
   the double inset ring is the metal frame catching the light. */
.card {
  position: relative;
  background-color: var(--panel);
  background-image:
    radial-gradient(circle at 1px 1px, rgba(255, 255, 255, 0.035) 1px, transparent 1.4px),
    linear-gradient(180deg, var(--panel-2), var(--panel));
  background-size: 4px 4px, auto;
  border: 1px solid var(--bezel);
  border-radius: var(--radius);
  padding: 20px;
  margin-bottom: 14px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    inset 0 0 0 1px rgba(0, 0, 0, 0.55),
    inset 0 18px 40px rgba(0, 0, 0, 0.35),
    var(--shadow);
}

.card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.card-head h2 { margin: 0; flex: 1 1 auto; }

/* The rule after a heading is a run of hash marks. */
h2 {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
  margin: 0 0 18px;
}
h2::after {
  content: "";
  flex: 1;
  height: 7px;
  border-radius: 2px;
  background: repeating-linear-gradient(90deg, var(--line) 0 2px, transparent 2px 11px);
}

/* The currency. An image rather than an emoji, which renders as a different
   drawing on every platform and as a tofu box on a few. */
.dog {
  display: inline-block;
  width: 1.7em;
  height: 0.95em;
  margin-left: 0.24em;
  vertical-align: -0.1em;
  background: url("/assets/hotdog-sm.webp") center / contain no-repeat;
  /* The dog is dark red and brown, which sinks into a near-black panel.
     A rim of shadow under it is what keeps it legible. */
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8)) brightness(1.06);
}

.figure { font-family: var(--font-figure); font-weight: 600; font-variant-numeric: tabular-nums; }
.eating { color: var(--ketchup); }
.banked { color: var(--mustard); }
.zero { color: var(--muted-dim); }

/* -------------------------------------------------------------- buttons */

/* The solid bottom edge is what makes these feel like objects rather than
   rectangles: it collapses on :active so the button physically sinks. */
button, .btn {
  font-family: var(--font);
  font-size: 14px;
  font-weight: 600;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, var(--panel-3), var(--panel-2));
  color: var(--text);
  padding: 9px 16px;
  cursor: pointer;
  box-shadow: 0 2px 0 #060908, inset 0 1px 0 rgba(255, 255, 255, 0.07);
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.15s, border-color 0.15s, color 0.15s;
}
button:hover, .btn:hover {
  border-color: var(--mustard-deep);
  color: var(--mustard-bright);
  transform: translateY(-1px);
  box-shadow: 0 3px 0 #060908, 0 8px 18px rgba(0, 0, 0, 0.4);
}
button:active, .btn:active {
  transform: translateY(1px);
  box-shadow: 0 0 0 #060908, inset 0 2px 5px rgba(0, 0, 0, 0.6);
}
button:focus-visible, .btn:focus-visible, .tab:focus-visible {
  outline: 3px solid rgba(245, 179, 30, 0.6);
  outline-offset: 2px;
}
button:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }

button.primary {
  background: linear-gradient(180deg, var(--mustard-bright), var(--mustard));
  border-color: #8a5f05;
  color: #3d2705;
  box-shadow: 0 2px 0 #8a5f05, 0 8px 20px rgba(245, 179, 30, 0.26),
              inset 0 1px 0 rgba(255, 255, 255, 0.6);
}
button.primary:hover {
  background: linear-gradient(180deg, #ffd670, var(--mustard-bright));
  color: #3d2705;
  box-shadow: 0 3px 0 #8a5f05, 0 12px 26px rgba(245, 179, 30, 0.34),
              inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
button.primary:active {
  box-shadow: 0 0 0 #8a5f05, inset 0 2px 5px rgba(90, 55, 0, 0.45);
}

button.danger:hover {
  border-color: var(--ketchup);
  color: var(--ketchup-bright);
  background: linear-gradient(180deg, #3a1b1d, #2c1416);
  box-shadow: 0 3px 0 #060908, 0 8px 18px rgba(230, 68, 87, 0.2);
}
button.small { padding: 6px 12px; font-size: 13px; border-radius: 8px; }
button.ghost {
  background: transparent;
  box-shadow: none;
  color: var(--muted);
  border-color: var(--line-soft);
}
button.ghost:hover { background: var(--panel-2); box-shadow: none; }

/* ---------------------------------------------------------------- forms */

input, select, textarea {
  font-family: var(--font);
  font-size: 15px;
  background: var(--inset);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 10px 12px;
  width: 100%;
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.45);
  transition: border-color 0.15s, box-shadow 0.15s;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--mustard);
  box-shadow: 0 0 0 3.5px rgba(245, 179, 30, 0.22), inset 0 2px 4px rgba(0, 0, 0, 0.45);
}
input.error, select.error {
  border-color: var(--ketchup);
  box-shadow: 0 0 0 3.5px rgba(230, 68, 87, 0.2);
}
input::placeholder { color: var(--muted-dim); }
label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
  font-weight: 700;
}
.field { margin-bottom: 14px; }
.row { display: flex; gap: 12px; flex-wrap: wrap; }

/* The browser's own [hidden] rule is display:none at UA specificity, which any
   class that sets display beats — so `.row[hidden]` stayed on screen and the
   over/under line showed on a head-to-head bet. Setting .hidden on the JS side
   instead would mean remembering this on every new row, so it's fixed once,
   here, for anything that ever gets the attribute. */
[hidden] { display: none !important; }
.row > .field { flex: 1 1 140px; margin-bottom: 14px; }
/* The short half of a two-field row - a stake, an over/under - so it doesn't
   take half the width from the field that needs it. */
.row > .field.narrow { flex: 0 0 120px; }

.note { color: var(--muted); font-size: 13px; }
.error-text { color: var(--ketchup-bright); font-size: 13px; margin-top: 8px; font-weight: 600; }
.empty { color: var(--muted); font-size: 14px; padding: 22px 0; text-align: center; }

/* An empty list gets the mascot rather than a bare line of grey text. */
.empty.with-mascot::before {
  content: "";
  display: block;
  width: 112px;
  height: 112px;
  margin: 0 auto 10px;
  opacity: 0.9;
  background: url("/assets/mascot.webp") center / contain no-repeat;
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.5));
}

/* --------------------------------------------------------------- ledger */

/* Diverging bars on a yard-lined track: the biggest total in either
   direction reaches half way, so the bars compare against each other.
   Dogs still to eat grow right in ketchup, dogs banked grow left in mustard.
   Three columns, no position number: the rows are sorted, which is all the
   ordering anyone wanted (the 1-12 column was removed by request). */
.ledger-row {
  display: grid;
  grid-template-columns: 170px 1fr 82px;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line-soft);
}
.ledger-row:last-child { border-bottom: none; }

.ledger-name {
  font-size: 14px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The team name needs its own truncation: ellipsis on .ledger-name only
   applies to that element's own inline content, so a block child overflows
   and gets cut mid-word with no ellipsis to show for it. */
.ledger-name small {
  display: block;
  color: var(--muted-dim);
  font-weight: 400;
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.track {
  position: relative;
  height: 24px;
  border-radius: 6px;
  overflow: hidden;
  background-image:
    repeating-linear-gradient(90deg, transparent 0 calc(10% - 1px), rgba(255, 255, 255, 0.07) calc(10% - 1px) 10%),
    linear-gradient(180deg, #050807, var(--inset));
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.65);
}
/* The 50: the line every bar is measured from. */
.track::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
  background: rgba(255, 255, 255, 0.22);
}
.bar {
  position: absolute;
  top: 3px;
  bottom: 3px;
  width: 0;
  border-radius: 4px;
  transition: width 0.85s cubic-bezier(0.22, 1, 0.36, 1);
}
.bar.eating {
  left: 50%;
  background: linear-gradient(90deg, var(--ketchup-deep), #ff5f70);
  box-shadow: 0 0 16px rgba(230, 68, 87, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
.bar.banked {
  right: 50%;
  background: linear-gradient(90deg, var(--mustard-deep), var(--mustard-bright));
  box-shadow: 0 0 16px rgba(245, 179, 30, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}

/* Lit numerals, not printed ones. */
.ledger-value { text-align: right; font-size: 23px; }
.ledger-value.eating { text-shadow: 0 0 18px rgba(230, 68, 87, 0.5); }
.ledger-value.banked { text-shadow: 0 0 18px rgba(245, 179, 30, 0.45); }

/* The board's own title is a neon sign, not an eyebrow label like the other
   sections — it's the one heading that should carry the place. The glow is
   layered shadows from a white-hot core outwards, which is what separates
   neon from a coloured drop shadow. */
.board-title {
  display: block;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(23px, 5.4vw, 36px);
  letter-spacing: 0.2em;
  text-indent: 0.2em; /* offsets the trailing letter-space so it sits centred */
  text-transform: uppercase;
  margin: 4px 0 24px;
  color: #fffbf2;
  text-shadow:
    0 0 5px #fff,
    0 0 13px var(--mustard-bright),
    0 0 28px var(--mustard),
    0 0 55px rgba(245, 179, 30, 0.75),
    0 0 95px rgba(245, 179, 30, 0.4);
  animation: neon 7s ease-in-out infinite;
}
/* No hash-mark rule on this one — it is centred, not a label with a rule. */
.board-title::after { content: none; }

/* A real tube stutters now and then rather than pulsing steadily. */
@keyframes neon {
  0%, 88%, 91%, 93%, 100% { opacity: 1; }
  89.5% { opacity: 0.72; }
  92% { opacity: 0.85; }
}

/* ----------------------------------------------------------------- bets */

/* Status pills on the left, who-is-in-it on the right. They share one row
   at desktop width and stack on a phone, where the tabs already fill a line
   of their own. */
.bet-filters {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.tabs { display: flex; gap: 8px; flex-wrap: wrap; }

/* A dropdown rather than a thirteenth pill: twelve managers and every player
   anyone has bet on would be three more rows of pills. It takes the pill's
   height and roundness so it sits in the same row as one, not the form
   field's. */
.who-select {
  flex: 0 1 auto;
  width: auto;
  max-width: 100%;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  color: var(--muted);
  background: var(--panel-2);
  box-shadow: none;
}
.who-select:hover { border-color: var(--relish); color: var(--relish); }
/* Lit while it is actually filtering, so a list that looks short is never a
   mystery. */
.who-select.on { border-color: var(--mustard-deep); color: var(--mustard-bright); }
.tab {
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  cursor: pointer;
}
.tab:hover { border-color: var(--relish); color: var(--relish); }
.tab.active {
  background: linear-gradient(180deg, #46a84d, #2f7d32);
  border-color: #1f5c24;
  color: #fff;
  box-shadow: 0 2px 0 #143f19, 0 6px 16px rgba(63, 160, 70, 0.3);
}

/* The left edge colour-codes status at a glance down the list. */
.bet {
  border: 1px solid var(--line);
  border-left: 4px solid var(--muted-dim);
  border-radius: var(--radius-sm);
  padding: 15px 17px;
  margin-bottom: 11px;
  background: linear-gradient(180deg, var(--panel-3), var(--panel-2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), var(--shadow-sm);
  transition: box-shadow 0.18s, transform 0.18s;
}
.bet:hover { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), var(--shadow); transform: translateY(-1px); }
.bet.active { border-left-color: var(--relish); }
.bet.open { border-left-color: var(--mustard); }
.bet.settled { border-left-color: var(--line); opacity: 0.72; }

/* The stake sits in the card's top right corner, on the title's own line:
   the bet and what it's worth are one statement. Aligned on the baseline
   rather than the box, so the figure sits level with the first line of a
   title that wraps. */
.bet-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.bet-title { font-weight: 600; font-size: 15.5px; line-height: 1.35; min-width: 0; }

/* The names and the card's own controls share one row, so a bet you can edit
   is no taller than one you can't. Long names wrap on the left; the buttons
   never do. */
.bet-line {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
}
.bet-stake {
  font-family: var(--font-figure);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.1;
  color: var(--mustard);
  white-space: nowrap;
  flex: 0 0 auto;
}
/* Smaller than the action buttons below, so they read as controls on the
   card rather than something to do about the bet.

   `flex: 0 0 auto` and `nowrap` are what keep them one line. Without them
   the names shrink the buttons instead of wrapping themselves, and an open
   challenge - whose "vs whoever takes it" is the longest line there is -
   squeezed Delete down to a 30px content box and broke it across two lines
   as "Delet / e". */
.bet-own { display: flex; gap: 6px; flex: 0 0 auto; }
.bet-own button.small {
  padding: 3px 9px;
  font-size: 12px;
  border-radius: 6px;
  white-space: nowrap;
}

.bet-meta { color: var(--muted); font-size: 13.5px; min-width: 0; flex: 1 1 auto; }
.bet-meta b { color: var(--text); }
.bet-detail {
  color: var(--muted);
  font-size: 14px;
  margin-top: 9px;
  padding-left: 12px;
  border-left: 2px solid var(--line);
}

.chip {
  display: inline-block;
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
  vertical-align: 2px;
  border: 1px solid transparent;
}
.chip.auto { background: rgba(111, 191, 95, 0.14); color: #8fd485; border-color: rgba(111, 191, 95, 0.35); }
.chip.open { background: rgba(245, 179, 30, 0.14); color: var(--mustard-bright); border-color: rgba(245, 179, 30, 0.35); }
.chip.won { background: rgba(111, 191, 95, 0.14); color: #8fd485; border-color: rgba(111, 191, 95, 0.35); }
.chip.lost { background: rgba(230, 68, 87, 0.15); color: var(--ketchup-bright); border-color: rgba(230, 68, 87, 0.35); }
.chip.push { background: rgba(255, 255, 255, 0.06); color: var(--muted); border-color: var(--line); }

/* The live score is the lit display set into the board: darker than the card
   around it, with scanlines, so it reads as a screen rather than a panel. */
.scoreline {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  padding: 11px 15px;
  border-radius: 10px;
  border: 1px solid #3a2e1c;
  color: var(--text);
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, #0a100d, #050908);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8);
  font-size: 13px;
}
.scoreline .side { flex: 1; min-width: 0; color: var(--muted); }
.scoreline .side.leading { color: var(--text); font-weight: 600; }
.scoreline .val {
  font-family: var(--font-figure);
  font-weight: 600;
  font-size: 24px;
  color: var(--text);
  margin-top: 1px;
}
.scoreline .side.leading .val { color: var(--mustard); text-shadow: 0 0 22px rgba(245, 179, 30, 0.7); }
.scoreline .vs {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--muted-dim);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 7px;
}
.scoreline .side:last-child { text-align: right; }

/* A yes/no bet is stored as an over/under on a 0.5 line, which is the right
   shape for the grader and a terrible thing to show a person — "1 vs 0.5"
   means nothing. It takes the same lit display as the scoreline and reads as
   a sentence instead. */
.verdict {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
  padding: 13px 15px;
  border-radius: 10px;
  border: 1px solid #3a2e1c;
  color: var(--muted);
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, #0a100d, #050908);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8);
  font-size: 13px;
}
.verdict b {
  font-family: var(--font-figure);
  font-weight: 600;
  font-size: 19px;
  letter-spacing: 0.01em;
  text-align: right;
  color: var(--text);
}
.verdict.leading { color: var(--text); }
.verdict.leading b { color: var(--mustard); text-shadow: 0 0 22px rgba(245, 179, 30, 0.7); }

/* Explains a zero that came from a player not suiting up, rather than
   leaving the league staring at a number that looks like a bug. */
.grade-note {
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--muted);
  padding-left: 12px;
  border-left: 2px solid var(--mustard-deep);
}

.bet-actions { display: flex; gap: 8px; margin-top: 13px; flex-wrap: wrap; }

/* ----------------------------------------------------------------- chat */

/* Set into the board like the live-score display, so it reads as a panel on
   the scoreboard rather than a form bolted underneath it. */
#chat {
  max-height: 330px;
  overflow-y: auto;
  padding: 4px 12px;
  margin-bottom: 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.025) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, #0a100d, #050908);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.7);
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
#chat::-webkit-scrollbar { width: 8px; }
#chat::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }

.chat-msg {
  padding: 9px 0 10px;
  border-bottom: 1px solid var(--line-soft);
}
.chat-msg:last-child { border-bottom: none; }
.chat-msg.mine { box-shadow: inset 2px 0 0 var(--mustard); padding-left: 10px; }

.chat-meta {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 3px;
}
.chat-meta b {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mustard);
}
.chat-msg.mine .chat-meta b { color: var(--mustard-bright); }
.chat-meta time { font-size: 11px; color: var(--muted-dim); }

.chat-body { font-size: 14.5px; line-height: 1.45; color: var(--text); }

/* Only shows on hover, so a wall of ✕ doesn't sit beside every line. */
.chat-x {
  margin-left: auto;
  padding: 0 5px;
  font-size: 11px;
  line-height: 1;
  color: var(--muted-dim);
  background: none;
  border: none;
  box-shadow: none;
  opacity: 0;
  cursor: pointer;
  transition: opacity 0.15s, color 0.15s;
}
.chat-msg:hover .chat-x { opacity: 1; }
.chat-x:hover { color: var(--ketchup); background: none; box-shadow: none; transform: none; }
.chat-x:focus-visible { opacity: 1; }
/* A phone has no hover, so hiding it there hides it for good - there was no
   way to delete your own message from the app. */
@media (hover: none) {
  .chat-x { opacity: 1; padding: 0 8px; }
}

.chat-form { display: flex; gap: 9px; }
.chat-form input { flex: 1 1 auto; }
.chat-form button { flex: 0 0 auto; }

/* ------------------------------------------------------------- activity */

.activity-row {
  display: flex;
  gap: 10px;
  padding: 9px 0;
  font-size: 13.5px;
  color: var(--muted);
  border-bottom: 1px solid var(--line-soft);
}
.activity-row:last-child { border-bottom: none; }
.activity-row time { color: var(--muted-dim); font-size: 12px; white-space: nowrap; }

/* ---------------------------------------------------------------- yours */

/* Top left of the header, on a line of its own above the centred brand.
   In flow rather than absolute: absolute overlapped the dog as soon as the
   page narrowed. The min-height reserves the row before the JS fills it, so
   the dog doesn't jump. */
.stand-user {
  display: flex;
  /* Stacked, not side by side: the button sits under your name. */
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-height: 32px;
  margin-bottom: 0;
}
.stand-user .who {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cream);
  padding: 5px 11px;
  border: 1px solid rgba(247, 241, 228, 0.35);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.4);
}
/* Floating on the turf, the normal dark button reads as a hole, so these
   keep the chalk-on-dark treatment the stand used to give them. */
.stand-user button.ghost {
  color: rgba(247, 241, 228, 0.82);
  border-color: rgba(247, 241, 228, 0.3);
  background: rgba(0, 0, 0, 0.35);
  box-shadow: none;
}
.stand-user button.ghost:hover {
  color: #fff;
  border-color: var(--mustard);
  background: rgba(0, 0, 0, 0.5);
  box-shadow: none;
}

/* ---------------------------------------------------------------- modal */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(4, 12, 7, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 24px var(--gutter);
  overflow-y: auto;
  z-index: 50;
  animation: fade 0.18s ease-out;
}
.modal {
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
  width: 100%;
  max-width: 520px;
  margin: auto;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), var(--shadow-lg);
  animation: pop 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}
.modal h3 {
  margin: 0 0 18px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 17px;
  letter-spacing: 0.04em;
  color: var(--text);
}

@keyframes fade { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; transform: translateY(10px) scale(0.98); } }

/* Four digits, wide apart — reads as a PIN pad rather than a text field. */
.pin-input {
  font-family: var(--font-figure);
  font-size: 34px;
  font-weight: 600;
  letter-spacing: 16px;
  text-align: center;
  text-indent: 16px; /* offsets the trailing letter-space so digits sit centred */
  padding: 12px;
}

/* The sign-in list: twelve names, tap yours. */
.account-list {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin-bottom: 16px;
  max-height: 58vh;
  overflow-y: auto;
}
.account {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 11px 14px;
}
.account:hover { border-color: var(--mustard); color: var(--text); }
.account-name { font-weight: 600; font-size: 15px; }
.account-name small {
  display: block;
  color: var(--muted-dim);
  font-weight: 400;
  font-size: 12px;
  margin-top: 1px;
}

.player-results {
  border: 1px solid var(--line);
  border-radius: 9px;
  margin-top: 4px;
  max-height: 190px;
  overflow-y: auto;
  background: var(--inset);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5);
}
.player-results div { padding: 9px 12px; cursor: pointer; font-size: 14px; }
.player-results div:hover { background: var(--panel-2); color: var(--mustard-bright); }
.player-results small { color: var(--muted); }

.picked {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: rgba(245, 179, 30, 0.1);
  border: 1px solid var(--mustard-deep);
  border-radius: 9px;
  padding: 9px 12px;
  font-size: 14px;
  font-weight: 600;
}

/* --------------------------------------------------------------- motion */

/* Sections deal in on load, top to bottom. `backwards` rather than `both`,
   so no transform is left on the element afterwards to trap fixed children. */
.site-header, .card {
  animation: deal 0.6s cubic-bezier(0.22, 1, 0.36, 1) backwards;
}
.card:nth-of-type(1) { animation-delay: 0.08s; }
.card:nth-of-type(2) { animation-delay: 0.14s; }
.card:nth-of-type(3) { animation-delay: 0.2s; }
.card:nth-of-type(4) { animation-delay: 0.26s; }

@keyframes deal {
  from { opacity: 0; transform: translateY(14px); }
}

/* Hot dogs rain down when a bet settles. */
.confetti {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 200;
  overflow: hidden;
}
.confetti i {
  position: absolute;
  top: -60px;
  width: 42px;
  height: 24px;
  background: url("/assets/hotdog-sm.webp") center / contain no-repeat;
  animation: rain linear forwards;
}
@keyframes rain {
  to { transform: translateY(112vh) rotate(var(--spin, 540deg)); opacity: 0.1; }
}

@media (prefers-reduced-motion: reduce) {
  .site-header, .card, .modal, .modal-backdrop { animation: none; }
  .hero-dog { animation: none; }
  .board-title { animation: none; }
  .bar { transition: none; }
  .confetti { display: none; }
  button:hover, .btn:hover, .bet:hover { transform: none; }
}

/* ---------------------------------------------------------------- phone */

@media (max-width: 620px) {
  .page { padding-top: 8px; }
  .card { padding: 16px 14px; }

  /* Graduate is wide: the two-line wordmark is what keeps "HOT DOG FANTASY"
     from forcing the document past the viewport and clipping every section. */
  .site-header { margin-bottom: 16px; }
  .wordmark .w2 { letter-spacing: 0.22em; text-indent: 0.22em; margin-top: 5px; }
  .stand-user { min-height: 30px; margin-bottom: 0; }

  /* Four tabs on one line: at the desktop padding they total ~363px and
     "All" drops to a second row on a 390px screen. */
  .tabs { gap: 6px; }
  .tab { padding: 6px 10px; font-size: 12.5px; }

  /* The tabs already fill the width, so the dropdown takes the next line
     whole rather than sitting in a 40px stub beside them. */
  .bet-filters { gap: 9px; }
  .who-select { flex: 1 1 100%; }

  /* 16px is a threshold, not a preference: under it iOS Safari zooms the
     page in when a field takes focus and never zooms back out, so tapping
     the chat box left the whole app scaled and scrolled sideways. The PIN
     pad and the filter pill set their own size and are unaffected - one is
     larger, the other is a select, which iOS opens as a picker. */
  input, textarea { font-size: 16px; }
  .modal select { font-size: 16px; }

  .ledger-row { grid-template-columns: 104px 1fr 62px; gap: 8px; }
  .ledger-value { font-size: 18px; }
  .track { height: 20px; }
  /* A stake is one or two characters; on a phone the row's other half is a
     dropdown whose longest option was being cut to "By hand - someon". */
  .row > .field.narrow { flex: 0 1 104px; }

  .bet-head { gap: 9px; }
  .bet-line { gap: 8px; }
  .bet-stake { font-size: 21px; }
  .bet-own button.small { padding: 3px 8px; font-size: 11.5px; }
  .scoreline { gap: 8px; padding: 10px 12px; }
  .scoreline .val { font-size: 20px; }
  .verdict { gap: 8px; padding: 11px 12px; }
  .verdict b { font-size: 17px; }
}
