/* Accessible themes (design_handoff_clubhub_feedback/THEMES.md), Phase 1:
   token contract + fonts + type scale. Four themes, one per-theme font,
   self-hosted under public/vendor/ (same vendoring pattern Inter used --
   no Google Fonts CDN dependency in production). Weights: Public Sans and
   IBM Plex Sans ship as variable fonts covering 400/600/700 from one file
   each; Atkinson Hyperlegible only ships static 400/700. */
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/vendor/public-sans/public-sans-variable.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/vendor/ibm-plex-sans/ibm-plex-sans-variable.woff2") format("woff2");
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/vendor/atkinson-hyperlegible/atkinson-hyperlegible-400.woff2") format("woff2");
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/vendor/atkinson-hyperlegible/atkinson-hyperlegible-700.woff2") format("woff2");
}

/* Token contract -- ink's values live directly on the bare :root (not a
   [data-theme="ink"] block) so "no data-theme attribute at all" == ink for
   free. That's exactly what a static public-post snapshot needs
   (lib/postSnapshot.js emits a plain <html lang="en">, deliberately never
   stamped with a theme) -- confirmed this requires zero changes there.
   The other three themes are :root[data-theme="..."] overrides, which
   beat the bare :root on specificity with no !important needed.

   This file holds tokens, base elements, forms, and buttons only --
   header/nav/tabs live in layout.css, and cards/chips/tables/status-strip
   live in components.css. Every view links all three (plus post-blocks.css
   on the two post views). */
:root {
  color-scheme: light;

  /* -- new contract (design_handoff_clubhub_feedback/THEMES.md) -- */
  --bg: #faf8f4;
  --surface: #ffffff;
  --surface-2: #f0ece3;
  --surface-3: #ece7dc;
  --ink: #14161a;
  --ink-muted: #3a3e46;
  --ink-dim: #4c5058;
  --border: #6b7078;
  --border-strong: #14161a;
  --action: #1d4ed8;
  --action-ink: #faf8f4;
  --action-hover: #163fae;
  --action-tint: #e6ecfd;
  --chip-bg: #14161a;
  --chip-ink: #faf8f4;
  --danger: #8f2c1f;
  --danger-tint: #fbeae7;
  --border-w: 2px;
  --radius: 4px;
  --font-body: "Public Sans";

  /* -- legacy aliases: every pre-theme token name, still consumed as-is by
     files not yet converted (post-blocks.css, forum.css, and anything else
     that hasn't had its own pass) -- kept inside each theme block so they
     resolve correctly under whichever theme is active. --club-accent is
     deliberately NOT derived from anything else: a per-club custom color
     is still applied as a real, independent inline override on <body>
     elsewhere (club.ejs, post.ejs, lib/postSnapshot.js) exactly as before;
     this alias only supplies the *default* when no such override is
     present. Wiring a club's color into the new --action token is a later
     phase (it needs the OKLCH contrast-safety pass THEMES.md describes --
     an unprocessed hex isn't safe to trust behind --action-ink yet). */
  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-surface-sunken: var(--surface-2);
  --color-text: var(--ink);
  --color-text-secondary: var(--ink-muted);
  --color-text-muted: var(--ink-dim);
  --color-text-faint: var(--ink-dim);
  --color-border: var(--border);
  --color-border-tile: var(--border);
  --color-danger: var(--danger);
  --color-danger-hover: var(--danger);
  --color-danger-surface: var(--danger-tint);
  --color-danger-border: var(--border);
  --club-accent: var(--action);
  --club-accent-contrast: var(--action-ink);
  --accent-300: var(--action-hover);
  --accent-400: var(--action-hover);
  --accent-700: var(--action);
  --accent-800: var(--action);
  --accent-900: var(--action-tint);
  --accent-tint: var(--action-tint);
  --accent-tint-strong: var(--action-tint);

  /* -- unchanged across themes, per THEMES.md's own instruction to keep
     this indirection working: --space-*/--radius-sm/--radius-lg names stay
     fixed so the ~1000 lines below (and every per-feature CSS file) that
     already reference them by name don't need touching. --radius-md now
     tracks the theme's single --radius value (direction reversed from
     before, where --radius derived from --radius-md) so every existing
     var(--radius-md) consumer becomes theme-aware for free. -sm/-lg stay
     fixed offsets rather than guessing proportional per-theme values
     THEMES.md doesn't specify. */
  --space-1: 2.8px;
  --space-2: 5.6px;
  --space-3: 8.4px;
  --space-4: 11.2px;
  --space-5: 16.8px;
  --space-6: 22.4px;

  --radius-sm: 4px;
  --radius-md: var(--radius);
  --radius-lg: 14px;

  --shadow-sm: 0 0 0 1px var(--border);
  --shadow-toolbar: 0 0 0 1px var(--action), 0 8px 20px rgba(0, 0, 0, 0.6);
  --shadow-card-elevated: 0 0 0 1px var(--border), 0 16px 40px rgba(0, 0, 0, 0.55);
  --shadow: var(--shadow-sm);

  /* -- type scale (THEMES.md): one multiplier, everything else in rem.
     Independent of theme choice -- set via [data-text-scale] below, not
     part of the four theme blocks. */
  --text-scale: 1;
}

:root[data-theme="ink-reverse"] {
  color-scheme: dark;

  --bg: #0a0b0f;
  --surface: #15171d;
  --surface-2: #1e2129;
  --surface-3: #23262f;
  --ink: #f5f6f8;
  --ink-muted: #c9cdd6;
  --ink-dim: #a8adb8;
  --border: #6b7180;
  --border-strong: #a8adb8;
  --action: #ffc74d;
  --action-ink: #0a0b0f;
  --action-hover: #ffd77a;
  --action-tint: #2a2210;
  --chip-bg: #ffc74d;
  --chip-ink: #0a0b0f;
  --danger: #ff9b8a;
  --danger-tint: #2a1512;
  --border-w: 2px;
  --radius: 6px;
  --font-body: "IBM Plex Sans";

  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-surface-sunken: var(--surface-2);
  --color-text: var(--ink);
  --color-text-secondary: var(--ink-muted);
  --color-text-muted: var(--ink-dim);
  --color-text-faint: var(--ink-dim);
  --color-border: var(--border);
  --color-border-tile: var(--border);
  --color-danger: var(--danger);
  --color-danger-hover: var(--danger);
  --color-danger-surface: var(--danger-tint);
  --color-danger-border: var(--border);
  --club-accent: var(--action);
  --club-accent-contrast: var(--action-ink);
  --accent-300: var(--action-hover);
  --accent-400: var(--action-hover);
  --accent-700: var(--action);
  --accent-800: var(--action);
  --accent-900: var(--action-tint);
  --accent-tint: var(--action-tint);
  --accent-tint-strong: var(--action-tint);
}

:root[data-theme="sepia"] {
  color-scheme: light;

  --bg: #f4e9d8;
  --surface: #fdf7ec;
  --surface-2: #ece0cb;
  --surface-3: #e4d7bf;
  --ink: #2b2013;
  --ink-muted: #4a3a26;
  --ink-dim: #6b5946;
  --border: #8a7a63;
  --border-strong: #2b2013;
  --action: #8f3a1f;
  --action-ink: #fdf7ec;
  --action-hover: #742d15;
  --action-tint: #f6e2d5;
  --chip-bg: #2b2013;
  --chip-ink: #f4e9d8;
  --danger: #7a1f14;
  --danger-tint: #f3ded9;
  --border-w: 2px;
  --radius: 4px;
  --font-body: "Public Sans";

  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-surface-sunken: var(--surface-2);
  --color-text: var(--ink);
  --color-text-secondary: var(--ink-muted);
  --color-text-muted: var(--ink-dim);
  --color-text-faint: var(--ink-dim);
  --color-border: var(--border);
  --color-border-tile: var(--border);
  --color-danger: var(--danger);
  --color-danger-hover: var(--danger);
  --color-danger-surface: var(--danger-tint);
  --color-danger-border: var(--border);
  --club-accent: var(--action);
  --club-accent-contrast: var(--action-ink);
  --accent-300: var(--action-hover);
  --accent-400: var(--action-hover);
  --accent-700: var(--action);
  --accent-800: var(--action);
  --accent-900: var(--action-tint);
  --accent-tint: var(--action-tint);
  --accent-tint-strong: var(--action-tint);
}

/* Two colors, total. Surfaces have no fill distinction from --bg at all --
   every panel/row must carry a real border to read as separate (see the
   border-collision fixes below and the per-feature-file follow-up work
   this phase doesn't reach). Destructive actions can't be red; cyan
   (--danger) is the one permitted second signal, and the word "Deny"
   does the real work. */
:root[data-theme="low-vision"] {
  color-scheme: dark;

  --bg: #000000;
  --surface: #000000;
  --surface-2: #000000;
  --surface-3: #000000;
  --ink: #ffff00;
  --ink-muted: #ffff00;
  --ink-dim: #ffff00;
  --border: #ffff00;
  --border-strong: #ffff00;
  --action: #ffff00;
  --action-ink: #000000;
  --action-hover: #ffffff;
  --action-tint: #000000;
  --chip-bg: #000000;
  --chip-ink: #ffff00;
  --danger: #00ffff;
  --danger-tint: #000000;
  --border-w: 3px;
  --radius: 0;
  --font-body: "Atkinson Hyperlegible";

  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-surface-sunken: var(--surface-2);
  --color-text: var(--ink);
  --color-text-secondary: var(--ink-muted);
  --color-text-muted: var(--ink-dim);
  --color-text-faint: var(--ink-dim);
  --color-border: var(--border);
  --color-border-tile: var(--border);
  --color-danger: var(--danger);
  --color-danger-hover: var(--danger);
  --color-danger-surface: var(--danger-tint);
  --color-danger-border: var(--border);
  --club-accent: var(--action);
  --club-accent-contrast: var(--action-ink);
  --accent-300: var(--action-hover);
  --accent-400: var(--action-hover);
  --accent-700: var(--action);
  --accent-800: var(--action);
  --accent-900: var(--action-tint);
  --accent-tint: var(--action-tint);
  --accent-tint-strong: var(--action-tint);
}

/* Independent of theme choice -- a separate per-user axis (users.text_scale).
   Normal/Large/Largest per THEMES.md's table (17/20/24px body). Root
   font-size is 17px * scale, which makes 1rem == the body-text floor
   directly, and h1's target (34px at Normal) a clean 2rem. */
[data-text-scale="large"] { --text-scale: 1.18; }
[data-text-scale="largest"] { --text-scale: 1.41; }

html {
  font-size: calc(17px * var(--text-scale));
}

* {
  box-sizing: border-box;
}

body {
  font-family: var(--font-body), system-ui, sans-serif;
  max-width: 840px;
  margin: 0 auto;
  padding: 0 var(--space-3) var(--space-5);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.5;
}

:focus-visible {
  outline: 2px solid var(--action);
  outline-offset: 2px;
}

/* low-vision's own border is already --action-colored (yellow), so the
   normal ring above would be invisible against it -- the one place
   --action-hover (white) earns its keep, per THEMES.md. */
:root[data-theme="low-vision"] :focus-visible {
  outline: 3px solid var(--action-hover);
}

/* Native form controls (radio, checkbox, range) default to the browser's
   own blue regardless of page theme -- pre-existing gap, more visible now
   that the rest of the page consistently uses --action. */
input {
  accent-color: var(--action);
}

h1, h2, h3 {
  color: var(--ink);
  line-height: 1.25;
}

/* h1's target (34px at Normal) is given explicitly by THEMES.md's mapping
   table -- a clean 2rem at the 17px root. h2/h3 aren't specified there;
   kept in the same relative proportion to h1 they held before (71% / 60%)
   rather than inventing new ratios. */
h1 { font-size: 2rem; margin: var(--space-4) 0 var(--space-3); }
h2 { font-size: 1.4rem; margin: var(--space-4) 0 var(--space-2); }
h3 { font-size: 1.15rem; margin: var(--space-3) 0 var(--space-2); }

a {
  color: var(--action);
}

.error {
  color: var(--danger);
  background: var(--danger-tint);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
}

/* Icons (views/partials/icons/*.ejs) -- inline SVG using currentColor so
   they adapt to the active theme and to per-club accent text automatically,
   no separate asset variants needed. */
.icon {
  width: 1.1em;
  height: 1.1em;
  vertical-align: -0.2em;
  margin-right: var(--space-1);
  color: var(--ink-dim);
}

/* Forms */
form.stacked {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 420px;
}

/* 11.5px -> 15px per THEMES.md's mechanical mapping table, expressed as
   rem against the 17px root (15/17). */
form.stacked label {
  display: grid;
  gap: 6px;
  font-size: 0.8824rem;
  color: var(--ink-dim);
}

.radio-row {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  font-size: 1rem;
  color: var(--ink);
}

.radio-row label {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* 13px -> 19px (THEMES.md: "19px for anything typed into"), as rem (19/17).
   A bare <select> (no .cell-input class -- those get their own compact
   treatment in components.css) was falling through to raw browser/UA
   styling with no theme awareness at all, same class of gap the
   color-scheme fix addressed for dropdown popups -- caught auditing the
   Settings tab's new theme picker in Low-vision, where the native fallback
   (light gray/white) is a real, if legible, violation of that theme's
   "two colors, total" floor. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="datetime-local"],
select,
textarea {
  font: inherit;
  font-size: 1.1176rem;
  color: var(--ink);
  background: var(--surface-2);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  padding: 9px 11px;
  transition: border-color 0.12s;
}

input[type="text"]:hover,
input[type="email"]:hover,
input[type="password"]:hover,
input[type="number"]:hover,
input[type="datetime-local"]:hover,
select:hover,
textarea:hover {
  border-color: var(--action);
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="datetime-local"]:focus,
select:focus,
textarea:focus {
  border-color: var(--action);
}

/* 11px -> 14px, as rem (14/17). */
.field-hint {
  font-size: 0.8235rem;
  color: var(--ink-dim);
}

/* Honeypot field for public forms (signup, event RSVP) -- see lib/honeypot.js.
   Off-screen via absolute positioning rather than display:none/hidden, since
   some bot scripts specifically check for and skip those. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

input[type="color"] {
  width: 3rem;
  height: 2.25rem;
  padding: 2px;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
}

textarea {
  min-height: 6rem;
  font-family: inherit;
}

/* Buttons */
button, .button {
  display: inline-block;
  font: inherit;
  cursor: pointer;
  text-decoration: none;
  border: none;
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  background: var(--action);
  color: var(--action-ink);
}

button:hover, .button:hover {
  filter: brightness(0.92);
}

button.secondary, .button.secondary {
  background: var(--surface);
  color: var(--ink);
  border: var(--border-w) solid var(--border);
}

button.danger, .button.danger {
  background: var(--danger-tint);
  color: var(--danger);
  border: var(--border-w) solid var(--danger);
}

button.danger:hover, .button.danger:hover {
  filter: none;
}

/* Outlined button variants (design_handoff_clubhub_views) -- transparent
   fill, an edge instead of a solid background. Used across the roster/
   posts/admin screens for secondary actions ("Mark paid", "Create a new
   club", "Edit") where a solid accent button would be too loud repeated
   several times on one page. */
button.btn-outline-accent, .button.btn-outline-accent {
  background: transparent;
  color: var(--action);
  border: var(--border-w) solid var(--action);
  font-weight: 500;
}

button.btn-outline-accent:hover, .button.btn-outline-accent:hover {
  background: var(--action-tint);
  filter: none;
}

button.btn-outline-neutral, .button.btn-outline-neutral {
  background: transparent;
  color: var(--ink-muted);
  border: var(--border-w) solid var(--border);
  font-weight: 500;
}

button.btn-outline-neutral:hover, .button.btn-outline-neutral:hover {
  background: var(--surface-2);
  filter: none;
}

/* Small icon-only buttons (roster remove, post/nav delete) -- 26-29px per
   spec depending on context; callers set width/height, this just handles
   the shared shape/hover treatment. */
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  border: var(--border-w) solid var(--border);
  color: var(--ink-dim);
}

.btn-icon:hover {
  filter: none;
  background: var(--surface-2);
  color: var(--ink);
}

/* Two sizes per design_handoff_clubhub_views: 26px for a roster row's
   remove action, 29px for a post row's delete action. */
.btn-icon-sm {
  width: 26px;
  height: 26px;
}

.btn-icon-md {
  width: 29px;
  height: 29px;
}

.btn-icon.btn-icon-danger:hover {
  background: var(--danger-tint);
  color: var(--danger);
  border-color: var(--danger);
}

/* "Active" state for a toggle button whose icon represents on/off rather
   than a destructive action (e.g. pin/unpin a post) -- accent-colored
   instead of the default muted, regardless of hover. */
.btn-icon.btn-icon-active {
  color: var(--action);
  border-color: var(--action);
}

.btn-icon.btn-icon-active:hover {
  background: var(--action-tint);
}

.btn-icon .icon {
  margin-right: 0;
}

button:disabled, .button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

@media (max-width: 600px) {
  form.stacked {
    max-width: 100%;
  }

  form.stacked > button,
  form.stacked > .button {
    width: 100%;
    text-align: center;
  }

  .actions {
    flex-wrap: wrap;
  }

  .actions button, .actions .button {
    flex: 1 1 auto;
  }
}
