/* Peppertree Pool — the design system (docs/archive/scope/visual-identity.md).
   Mobile-first, high-contrast, one stylesheet, no external requests.

   Four layers, in this order: tokens, type, surfaces, components. Nothing is
   styled by element name where a class will do — the button system proved the
   pattern on 2026-08-07 and the rest of the site now follows it.

   The one rule to know before editing: the four surfaces must stay visually
   distinct and must keep stepping *down* in weight — field, panel, plain,
   sunken. That descent is what stops the page reading as a stack of identical
   grey cards, which is the whole reason this system exists. */

/* --- 1. type ------------------------------------------------------------ */

/* Self-hosted, not a CDN: default-src is 'self' with no font-src exception, so
   a fonts.googleapis.com link is blocked at render and fails the CSP suite's
   external-host sweep. See docs/adr/0002-self-hosted-fonts-under-csp.md.
   Fraunces v38, latin subset, axes opsz 9..144 + wght 400..700. */
@font-face {
  font-family: 'Fraunces';
  src: url('fonts/fraunces-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* --- 2. tokens ---------------------------------------------------------- */

:root {
  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-text: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* 4px base. Used for every gap and pad, so density is one edit, not fifty. */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;

  /* Radius is a hierarchy, not a constant: content is crisp, pills are round.
     The old uniform 10px on everything was part of the sameness. */
  --r-sm: 3px;
  --r-md: 6px;
  --r-pill: 999px;

  /* Colour. Neutrals carry a green-grey cast so they read as chosen rather
     than inherited; a pure mid-grey is what the page had before. */
  --ground: #F5F6F2;
  --raised: #FFFFFF;
  --sunken: #E9ECE4;
  --ink: #161D18;
  --muted: #59645A;
  --line: #D3D9CD;

  --green: #0B6B3A;
  --green-ink: #FFFFFF;
  --field: #063C22;
  --field-ink: #EAF3EC;
  --field-muted: #9CC0AA;

  /* Peppercorn: the mark's berry and uppercase eyebrows, and nothing else.
     Deliberately off semantic duty — a rose-red that also meant "error" would
     be worse than having no secondary at all. */
  --pepper: #B33F62;

  --alive-bg: #D8EDE0;
  --alive-ink: #0A4F2C;
  --out-bg: #F6DCE3;
  --out-ink: #8C2540;
  --warn-ink: #7A5210;
  --warn-bg: #FBEFD6;
  --warn-border: #E0A33C;
  --error: #B00020;
  --error-bg: #FDECEF;
  --focus: #1A73E8;

  /* Aliases onto the ramp. These are the names the rest of the stylesheet grew
     up with; keeping them means the palette moved without every rule changing. */
  --bg: var(--ground);
  --panel: var(--raised);
  --accent: var(--green);
  --accent-ink: var(--green-ink);
  --border: var(--line);
}

/* Every literal above has a counterpart here — tests/test_visual_identity.py
   asserts parity. It caught the palette this replaces: --error was only ever
   defined light, so #b00020 sat on the dark background at 2.4:1. */
@media (prefers-color-scheme: dark) {
  :root {
    --ground: #0E120E;
    --raised: #171D17;
    --sunken: #131813;
    --ink: #E7EBE4;
    --muted: #9AA79A;
    --line: #2C352C;

    --green: #4FCB8B;
    --green-ink: #05271A;
    --field: #0A3120;
    --field-ink: #E7F2EA;
    --field-muted: #8FB79E;

    /* Close to --error in lightness, distinct in hue. They are never adjacent:
       pepper is decorative only. */
    --pepper: #EE86A8;

    --alive-bg: #113D28;
    --alive-ink: #8CE0B0;
    --out-bg: #3E1522;
    --out-ink: #F2A2B8;
    --warn-ink: #E9BE72;
    --warn-bg: #33270F;
    --warn-border: #7A5A1E;
    --error: #FF9184;
    --error-bg: #2F1512;
    --focus: #6BA7FF;
  }
}

/* --- 3. base ------------------------------------------------------------ */

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-text);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* The UA stylesheet's `[hidden] { display: none }` loses to any author rule
   that sets `display`, so an element like .auth-loading (display:flex) stays
   visible even when hidden. Shipped exactly that bug on 2026-08-07 — the
   sign-in loader showed on every page load. Keep this above such rules. */
[hidden] { display: none !important; }

a { color: var(--accent); }

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  text-wrap: balance;
}
/* Fraunces carries an optical-size axis, so small headings get drawn for their
   size instead of being shrunken display type. This is the reason to spend
   65 KB on a variable face rather than a static cut. */
h1 {
  font-variation-settings: 'opsz' 90;
  font-size: clamp(1.6rem, 4.5vw, 2.1rem);
  margin: 0 0 var(--sp-2);
}
h2 { font-variation-settings: 'opsz' 24; font-size: 1.05rem; }
h3 { font-variation-settings: 'opsz' 18; font-size: 1rem; }

.lede { font-size: 1.125rem; }
.muted { color: var(--muted); }

/* Uppercase micro-label. The one place the peppercorn secondary appears in
   running layout. */
.kicker {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--pepper);
}

.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: var(--sp-2);
  top: var(--sp-2);
  background: var(--ink);
  color: var(--ground);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  z-index: 10;
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* --- 4. header ---------------------------------------------------------- */

.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
  background: var(--raised);
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-right: auto;
  text-decoration: none;
  color: var(--ink);
}
.wordmark svg { display: block; flex: none; }
.wordmark b {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 72;
  font-weight: 600;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
  line-height: 1;
}
.site-header nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-4);
}
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.85rem;
  height: 1.85rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
}
.avatar svg {
  width: 1.1rem;
  height: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}

.content {
  max-width: 48rem;
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4) var(--sp-6);
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}

/* Page header: title plus the "where am I" line under it. */
.page-head { display: flex; flex-direction: column; gap: var(--sp-1); }
.page-head h1 { margin: 0; }
.page-head p { margin: 0; }

/* Shown once, to a player who has never picked; it disappears on its own. */
.orientation ol { margin: var(--sp-2) 0 var(--sp-3); padding-left: var(--sp-5); }
.orientation li { margin: var(--sp-1) 0; }

/* --- 5. surfaces -------------------------------------------------------- */
/* Four treatments, descending in weight. Keep them distinct: four class names
   that all render the same card would defeat the point and the test suite. */

/* (1) The stat band. The whole budget for boldness on the page. */
.surface-stat {
  background: var(--field);
  color: var(--field-ink);
  border-radius: var(--r-md);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}
.stat {
  padding: var(--sp-3) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.stat + .stat { border-left: 1px solid rgba(255, 255, 255, 0.13); }
.stat h2 {
  margin: 0;
  font-family: var(--font-text);
  font-size: 0.72rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--field-muted);
}
.stat .value {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 80;
  font-weight: 600;
  font-size: 1.9rem;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.stat .note { font-size: 0.85rem; color: var(--field-muted); }

/* (2) The bordered card. Still here, now used sparingly. */
.panel {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  background: var(--raised);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* (3) Plain: a rule and spacing do the separating, no fill at all. */
.surface-plain {
  border-top: 1px solid var(--line);
  padding-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* (4) Sunken: recessed tint for data — tables, grids, secondary detail. */
.surface-sunken {
  background: var(--sunken);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* The surfaces are flex columns with a gap, so children must not also carry
   block margins — the two stack and open holes (a paragraph's 1em plus the
   gap). Let the layout own the spacing; list indentation is padding, so it
   survives this. */
.panel > *,
.surface-plain > *,
.surface-sunken > * { margin-top: 0; margin-bottom: 0; }

/* --- 6. state ----------------------------------------------------------- */
/* Replaces the coloured left rail on the status card, retired 2026-08-08. The
   rail was decorative — the words beside it did the work — so the replacement
   puts colour, shape and words in one object that cannot decay to colour
   alone. The retired class names are deliberately not written here: a test
   asserts they appear nowhere in this file, and that check is only as strong
   as its bluntness. */

.pill {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.2rem 0.6rem 0.24rem;
  border-radius: var(--r-pill);
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1.25;
}
.pill::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: currentColor;
}
.pill-alive { background: var(--alive-bg); color: var(--alive-ink); }
.pill-out { background: var(--out-bg); color: var(--out-ink); }
.pill-neutral { background: var(--sunken); color: var(--muted); }

/* --- 7. buttons --------------------------------------------------------- */
/* One system, four variants, and nothing styled by element name. Every
   clickable action carries .btn whether it is an <a> or a <button>, so a link
   and a form submit that do the same kind of thing look the same. Styling bare
   `button` used to make the variants implicit: an element picked up the primary
   look for free, so a one-off class like `good` (a text colour, not a button)
   rendered as a half-styled button (owner walk-through 2026-08-07). */
.btn {
  display: inline-block;
  font: inherit;
  font-weight: 600;
  line-height: 1.25;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  text-decoration: none;
  text-align: center;
  cursor: pointer;
}
.btn-secondary {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent);
}
.btn-danger {
  background: transparent;
  color: var(--error);
  border-color: var(--error);
}
.btn-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-weight: inherit;
  text-decoration: underline;
}
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: 0.6;
  cursor: not-allowed;
}

.inline-form { display: inline; margin: 0; }

/* --- 8. forms ----------------------------------------------------------- */

.stack { display: flex; flex-direction: column; gap: var(--sp-2); max-width: 22rem; }
.stack label { font-weight: 600; }
.stack input {
  padding: var(--sp-2) 0.65rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--raised);
  color: var(--ink);
  font: inherit;
}

/* Sign-in column: cap the whole auth block so the Google button, inputs, and
   links share one width. */
.auth { max-width: 22rem; }
.auth .stack { max-width: 100%; }

.or { color: var(--muted); margin: var(--sp-4) 0 var(--sp-2); }

.google-btn {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  background: var(--raised); color: var(--ink); border: 1px solid var(--line);
}
.google-logo { flex: none; }
.auth-links {
  display: flex; justify-content: space-between; gap: var(--sp-2);
  margin: var(--sp-3) 0 0; font-size: 0.9rem;
}
.auth-links a { color: var(--accent); }

fieldset { border: 1px solid var(--line); border-radius: var(--r-md); margin: var(--sp-2) 0; }
fieldset label { display: block; padding: var(--sp-1) 0; }

/* Replaces the last inline style attribute — style-src is 'self' with no
   exceptions, and no nonce can cover a style="" attribute (STRIDE I1). */
.spaced-above { margin-top: var(--sp-4); }

/* Shown in place of the sign-in form while returning from Google. */
.auth-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
}
.auth-loading p { margin: 0; color: var(--muted); }
.spinner {
  width: var(--sp-6); height: var(--sp-6);
  border: 3px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 3s; }
}

/* --- 9. messages -------------------------------------------------------- */

.notice {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--sunken);
}
.error {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--error);
  color: var(--error);
  background: var(--error-bg);
}

.flash {
  padding: var(--sp-2) 0.9rem;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--raised);
}
.flash.ok { border-color: var(--accent); }
.flash.error { border-color: var(--error); color: var(--error); background: var(--error-bg); }
.flash.warn { border-color: var(--warn-border); color: var(--warn-ink); background: var(--warn-bg); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* --- 10. text tones ----------------------------------------------------- */

.good { color: var(--accent); font-weight: 600; }
.bad { color: var(--error); font-weight: 600; }
.warn { color: var(--warn-ink); font-weight: 600; }
.unverified { color: var(--error); font-weight: 600; }
.big {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 80;
  font-size: 1.5rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  margin: var(--sp-1) 0;
}

.tag {
  display: inline-block;
  font-size: 0.85rem;
  line-height: 1.3;
  /* In a narrow grid cell "win & lose" otherwise breaks into a vertical stack
     of three words. The cells around it are allowed to wrap; a label is not. */
  white-space: nowrap;
  padding: 0.02rem 0.4rem;
  border-radius: var(--r-sm);
  background: var(--sunken);
  border: 1px solid var(--line);
  color: var(--muted);
}

/* --- 11. tables --------------------------------------------------------- */

.table-scroll { overflow-x: auto; }
/* When the scroll container *is* the surface (the admin tables), the sunken
   surface's flex column would make the table a flex item and swallow the
   sideways scroll. Block flow restores it; the tint and padding stay. */
.surface-sunken.table-scroll { display: block; }
table.grid {
  border-collapse: collapse;
  width: 100%;
  min-width: 20rem;
  font-variant-numeric: tabular-nums;
}
table.grid th {
  text-align: left;
  padding: var(--sp-1) var(--sp-2);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.grid td {
  text-align: left;
  padding: 0.38rem var(--sp-2);
  border-bottom: 1px solid var(--line);
}
table.grid tr:last-child td { border-bottom: 0; }
table.grid tr.row-alert { background: var(--error-bg); }
table.grid tr.row-warn { background: var(--warn-bg); }
/* /players grids: the row label stays put while the weeks scroll sideways. A
   sticky cell needs its own background or the scrolled cells show through. */
table.grid.sticky-first th:first-child,
table.grid.sticky-first td:first-child {
  position: sticky;
  /* Sticky offsets are measured inside the scroller's padding; a negative one
     sticks flush to its edge, so scrolled cells can't show in the gap. */
  left: calc(-1 * var(--sp-3));
  z-index: 1;
  background: var(--sunken);
  white-space: nowrap;
}
table.grid th.cell,
table.grid td.cell {
  text-align: center;
  padding-left: var(--sp-1);
  padding-right: var(--sp-1);
  white-space: nowrap;
}
table.grid td.cell abbr { text-decoration: none; cursor: help; }
table.grid td.out-after {
  background: repeating-linear-gradient(
    135deg, transparent 0 4px, var(--line) 4px 5px
  );
  opacity: 0.6;
}

/* --- 12. picking -------------------------------------------------------- */

.pick-slot {
  margin: 0;
  border-top: 1px solid var(--line);
  padding-top: var(--sp-3);
}
.team-grid {
  border: none; padding: 0; margin: var(--sp-2) 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--sp-1);
}
.team-opt {
  display: flex; flex-direction: column; gap: 0.1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 0.45rem var(--sp-2);
  background: var(--raised);
  cursor: pointer;
}
.team-opt.is-disabled { opacity: 0.55; cursor: not-allowed; }
.team-grid.hides-unavailable .team-opt.is-disabled { display: none; }
.hide-toggle { margin: var(--sp-2) 0 0; }
.hide-toggle label { display: inline-flex; align-items: center; gap: 0.45rem; cursor: pointer; }
.team-row { display: flex; align-items: center; gap: var(--sp-1); }
.team-name, .team-abbr { font-weight: 700; }
/* This line carries the opponent, kickoff, home/away and used-week tag — i.e.
   everything a pick decision rests on. It used to be the smallest type on the
   page at 0.8rem (audit 2026-08); load-bearing text doesn't get the fine-print
   treatment, and the density pass of 2026-08-08 did not claw it back. */
.team-meta { font-size: 0.95rem; color: var(--muted); }
.team-record {
  margin-left: auto;
  font-size: 0.9rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Was a 4px accent rail on a rounded box — the same device the status card
   carried, so it went the same way. The deadline is a warning, so it now says
   so in tone rather than with a stripe. */
.pick-deadline {
  background: var(--warn-bg);
  color: var(--warn-ink);
  border-radius: var(--r-md);
  padding: var(--sp-2) 0.85rem;
}

/* Saved-state affordances (UX polish batch) */
.saved-pick {
  padding: var(--sp-2) 0.85rem;
  border-radius: var(--r-md);
  background: var(--alive-bg);
  color: var(--alive-ink);
}
.tag-saved {
  border-color: var(--accent);
  color: var(--accent);
}
.change-pick summary {
  cursor: pointer;
  color: var(--accent);
  margin: var(--sp-2) 0;
}
.side-cat.is-saved select,
.side-cat.is-saved input {
  border-color: var(--accent);
}
/* Several saved side picks in one panel: one per line, not a run-on. */
.saved-pick .fact { display: block; }

/* The dashboard's "Your pick: Los Angeles Rams (win)". A one-item bullet list
   was the previous shape — a list needs more than one thing in it, and week 4
   gets a line each rather than two bullets (owner walk-through 2026-08-08). */
.pick-line { margin: var(--sp-1) 0; }

/* --- 13. lists & admin -------------------------------------------------- */

.filter-bar { display: flex; align-items: center; gap: var(--sp-2); margin: 0; }
.filter-bar select {
  padding: var(--sp-1); border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--raised); color: var(--ink); font: inherit;
}
.pager { display: flex; gap: var(--sp-5); margin-top: var(--sp-3); }

.admin-nav { list-style: none; padding: 0; margin: 0; }
.admin-nav li { padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); }
.admin-nav li:last-child { border-bottom: 0; }

/* Label/value facts — the profile's Account block. It had no rule at all and
   was falling through to the UA stylesheet: every `dd` indented 40px under its
   label with no row spacing, which is the odd gap the owner reported on
   2026-08-08. Stacked on a phone, two columns once there's room. */
.facts { margin: 0; display: grid; gap: var(--sp-1) var(--sp-4); }
.facts dt { color: var(--muted); }
.facts dd { margin: 0 0 var(--sp-2); }
@media (min-width: 30rem) {
  .facts { grid-template-columns: minmax(9rem, auto) 1fr; align-items: baseline; }
  .facts dd { margin-bottom: 0; }
}

/* The rules page. Eight sections of black-on-white was a wall to scan (owner
   walk-through 2026-08-08), so colour goes on the section headings and the
   list markers and nowhere else. Every value is a token: --green on --ground
   and on --raised are already held to 4.5:1 by the palette tests, in both
   themes, which is exactly why a literal here would be a bug. */
.rules h2 {
  color: var(--accent);
  border-top: 1px solid var(--line);
  padding-top: var(--sp-4);
  margin-top: var(--sp-5);
}
.rules h2:first-of-type { border-top: 0; }
.rules ol > li::marker,
.rules ul > li::marker { color: var(--accent); }
.rules li { margin-bottom: var(--sp-1); }

.games, .open-book { padding-left: 1.1rem; }
.side-cat { margin-bottom: var(--sp-3); }
.side-cat select, .side-cat input {
  width: 100%; padding: var(--sp-2); border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--raised); color: var(--ink); font: inherit;
}
