@import url("fonts.css");

/* ============================================================
   Better Golf Program — shared stylesheet
   Structure, typography and spacing follow hamfamclan.net.
   The one deliberate change is the palette: colonial navy has
   been replaced by fairway green. Brass stays — it reads as
   club trophy rather than heritage archive, which is the right
   register for Atlanta Athletic Club.
   ============================================================ */

/* ---- Design tokens ---------------------------------------- */
:root {
  --color-bg:          #f4f2e7;   /* parchment, a shade cooler than hamfamclan */
  --color-surface:     #fffdf8;   /* page card */
  --color-ink:         #23271f;   /* near-black warm ink, greened */
  --color-ink-soft:    #55594c;   /* muted body text */
  --color-green:       #2f5d3a;   /* fairway */
  --color-green-deep:  #1d3b26;   /* masthead */
  --color-green-soft:  #7ea287;   /* on dark backgrounds only */
  --color-brass:       #9a7b3f;   /* muted gold accent */
  --color-brass-soft:  #c8a86a;
  /* Brass at body size fails AA on parchment (3.91:1). Use this darker cousin
     wherever brass is the color of actual words; keep --color-brass for
     rules, borders and ornaments so the look is unchanged. */
  --color-brass-text:  #8a6d33;
  --color-rule:        #d8d2bd;   /* hairline / borders */
  --color-flag:        #8c2b30;   /* warnings, over-target, the pin */
  --color-good:        #2f5d3a;

  --font-display: "Cormorant Garamond", "Hoefler Text", Garamond, "Times New Roman", serif;
  --font-body:    "EB Garamond", Georgia, "Times New Roman", serif;

  --measure: 42rem;
  --measure-wide: 60rem;
  --space: 1.25rem;
  --radius: 3px;
  --shadow: 0 1px 3px rgba(35, 39, 31, 0.08), 0 8px 28px rgba(35, 39, 31, 0.06);
}

/* ---- Reset-ish -------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; font-size: 112.5%; }
body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: 1.18rem;
  line-height: 1.7;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--color-green); text-underline-offset: 0.15em; }
a:hover { color: var(--color-brass-text); }
:focus-visible { outline: 3px solid var(--color-brass); outline-offset: 2px; }
h1, h2, h3 { font-family: var(--font-display); font-weight: 600; line-height: 1.15; }

/* ---- Masthead --------------------------------------------- */
.site-header {
  position: relative;
  /* A club that has had its own header read overrides these two; everyone else
     falls back to the app's masthead. */
  background: var(--masthead-bg, var(--color-green-deep));
  color: var(--masthead-ink, #f1ecdc);
  border-bottom: 3px solid var(--color-brass);
  text-align: center;
  padding: 0.7rem 1.25rem 0.6rem;
}
.site-header .crest {
  font-size: 0.78rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--color-brass-soft);
  margin: 0 0 0.15rem;
}
.site-header .site-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.9rem, 5vw, 3.1rem);
  line-height: 1.05;
  margin: 0;
  color: var(--masthead-ink, #fbf7ed);
}
.site-header .site-title a { color: inherit; text-decoration: none; }
.site-header .site-title a:hover { color: var(--color-brass-soft); }
.site-header .tagline {
  font-style: italic;
  color: var(--masthead-ink-soft, #c6bb9c);
  margin: 0.25rem 0 0;
  font-size: 1.02rem;
}
/* Bottom RIGHT, opposite the club mark. Moved off the left 2026-08-21 to clear
   that corner for the logo work: .club-logo sits at left/top and the badge sat
   directly beneath it, so the two shared a corner and neither could grow.
   The vertical position is unchanged — still pinned to the bottom of the
   masthead, just above the nav bar — and .header-user holds the top right, so
   nothing collides. */
.preview-badge {
  position: absolute; right: 0.9rem; bottom: 0.55rem;
  font-family: var(--font-body); font-size: 0.68rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: #f1ecdc;
  background: var(--color-flag); border-radius: 2px; padding: 0.1rem 0.5rem;
}
.header-user {
  position: absolute; right: 1rem; top: 0.9rem;
  font-size: 0.8rem; color: var(--masthead-ink-soft, #d8cfb5);
}
.header-user a { color: var(--masthead-ink, #f1ecdc); }
@media (max-width: 640px) {
  /* Static at narrow widths, but still the anchor for the drop menu —
     without this the absolutely-positioned menu escapes to the page. */
  .header-user { position: relative; right: auto; top: auto; margin: 0.7rem 0 0; }
  .preview-badge { position: static; display: inline-block; margin-top: 0.5rem; }
}

/* ---- Primary navigation ----------------------------------- */
.site-nav { background: var(--color-green); border-bottom: 1px solid rgba(0,0,0,0.2); }
.site-nav > ul {
  list-style: none; margin: 0 auto; padding: 0 1rem; max-width: 80rem;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 0 1.1rem;
}
.site-nav a {
  display: inline-block; padding: 0.5rem 0;
  color: #e6dcc4; text-decoration: none;
  letter-spacing: 0.06em; text-transform: uppercase; font-size: 0.76rem; white-space: nowrap;
}
.site-nav a:hover, .site-nav a[aria-current="page"] {
  color: #fff; border-bottom: 2px solid var(--color-brass-soft);
}

/* ---- Layout ----------------------------------------------- */
main { max-width: var(--measure-wide); margin: 0 auto; padding: 2rem 1.25rem 4rem; }
main.narrow { max-width: var(--measure); }
section { margin-bottom: 2.5rem; }
/* A card followed by a section gets the same air two sections get. Without it
   the next heading crowds the card's bottom edge — the profile form running
   straight into "Link More Clubs" was the case that showed it. */
.card + section { margin-top: 2.5rem; }
.eyebrow {
  font-family: var(--font-body); font-size: 0.74rem; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--color-brass-text); margin: 0 0 0.3rem;
}
h1.page-title { font-size: clamp(1.9rem, 4vw, 2.6rem); margin: 0 0 0.6rem; }
h2 { font-size: 1.6rem; margin: 0 0 0.7rem; }
h3 { font-size: 1.22rem; margin: 0 0 0.3rem; }
.lede { font-size: 1.24rem; color: var(--color-ink-soft); }
.muted { color: var(--color-ink-soft); font-size: 0.95rem; }
hr.rule { border: 0; border-top: 1px solid var(--color-rule); margin: 2rem 0; }

/* ---- Cards ------------------------------------------------ */
.card {
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 1.3rem 1.4rem; box-shadow: var(--shadow);
}
.card + .card { margin-top: 1rem; }
.card-tight { padding: 0.9rem 1.1rem; }
.grid-2 { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 44rem) { .grid-2 { grid-template-columns: 1fr 1fr; } }

/* ---- Stat tiles ------------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.8rem; }
@media (min-width: 44rem) { .stats { grid-template-columns: repeat(4, 1fr); } }
.stat {
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-left: 4px solid var(--color-green); border-radius: var(--radius); padding: 0.9rem 1rem;
}
.stat.miss { border-left-color: var(--color-flag); }
.stat .n {
  font-family: var(--font-display); font-weight: 600; font-size: 2.1rem; line-height: 1;
  font-variant-numeric: tabular-nums; display: block;
}
.stat .l { display: block; font-size: 0.85rem; color: var(--color-ink-soft); line-height: 1.3; margin-top: 0.3rem; }
.stat .t { display: block; font-size: 0.78rem; color: var(--color-brass-text); margin-top: 0.15rem; line-height: 1.3; }

/* ---- Tables ----------------------------------------------- */
.table-wrap { overflow-x: auto; }
table.data {
  width: 100%; border-collapse: collapse; background: var(--color-surface);
  border: 1px solid var(--color-rule); font-variant-numeric: tabular-nums;
}
table.data th {
  background: var(--color-green-deep); color: #f1ecdc; text-align: left;
  font-family: var(--font-body); font-weight: 600; font-size: 0.76rem;
  letter-spacing: 0.1em; text-transform: uppercase; padding: 0.55rem 0.7rem;
}
table.data td { padding: 0.6rem 0.7rem; border-top: 1px solid var(--color-rule); font-size: 0.98rem; }
table.data tr.key td { background: #f6ecec; font-weight: 600; }
table.data th:not(:first-child), table.data td:not(:first-child) { text-align: center; }

/* ---- Forms ------------------------------------------------ */
.field { margin-bottom: 1.1rem; }
label.flabel, .flabel {
  display: block; font-size: 0.78rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--color-ink-soft); margin-bottom: 0.35rem;
}
.flabel .hint { text-transform: none; letter-spacing: 0; color: var(--color-ink-soft); font-size: 0.85rem; }
/* ⚠️ input[type=tel] WAS MISSING FROM THIS LIST and fell through to the browser
   default — shorter, a different font, no padding — so the Phone field sat
   visibly smaller than the address fields beside it. Any new input type has to
   be added here or it will look broken in exactly the same way. */
input[type=text], input[type=email], input[type=password], input[type=number],
input[type=tel], input[type=date], input[type=search], select, textarea {
  width: 100%; font-family: var(--font-body); font-size: 1.05rem; color: var(--color-ink);
  background: #fff; border: 1px solid var(--color-rule); border-radius: var(--radius);
  padding: 0.6rem 0.7rem; min-height: 2.9rem; -webkit-appearance: none;
}
textarea { min-height: 6rem; line-height: 1.5; }
.btn {
  display: inline-block; font-family: var(--font-body); font-size: 0.82rem;
  letter-spacing: 0.12em; text-transform: uppercase; cursor: pointer;
  padding: 0.75rem 1.5rem; min-height: 2.9rem; border-radius: var(--radius);
  border: 1px solid var(--color-green-deep); background: var(--color-green-deep);
  color: #f1ecdc; text-decoration: none; text-align: center;
}
.btn:hover { background: var(--color-green); color: #fff; }
.btn-quiet { background: transparent; color: var(--color-green); border-color: var(--color-rule); }
.btn-quiet:hover { background: var(--color-surface); color: var(--color-green-deep); }
.btn-danger { background: transparent; color: var(--color-flag); border-color: #d9bdbd; }
.btn-block { display: block; width: 100%; }
.btn-row { display: flex; gap: 0.6rem; flex-wrap: wrap; }

/* ---- Notices ---------------------------------------------- */
.notice {
  border: 1px solid var(--color-rule); border-left: 4px solid var(--color-brass);
  background: var(--color-surface); border-radius: var(--radius);
  padding: 0.9rem 1.1rem; margin-bottom: 1.2rem; font-size: 1rem;
}
.notice.err { border-left-color: var(--color-flag); background: #faf0f0; }
.notice.ok  { border-left-color: var(--color-green); background: #f0f5f0; }
.notice.draft { border-left-color: var(--color-flag); background: #faf3ef; font-size: 0.95rem; }

/* ---- Program ---------------------------------------------- */
.rule-item {
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-left: 4px solid var(--color-green); border-radius: var(--radius);
  padding: 0.9rem 1.1rem; margin-bottom: 0.65rem;
}
.rule-item h3 { margin: 0 0 0.15rem; font-size: 1.16rem; }
.rule-item p { margin: 0; font-size: 1rem; color: var(--color-ink-soft); line-height: 1.55; }
.rule-item .num {
  font-family: var(--font-display); color: var(--color-brass-text); margin-right: 0.45rem;
}
.focus-row {
  display: flex; align-items: baseline; gap: 0.8rem;
  border-bottom: 1px solid var(--color-rule); padding: 0.7rem 0;
}
.focus-row:last-child { border-bottom: 0; }
.focus-pct {
  font-family: var(--font-display); font-weight: 600; font-size: 1.5rem;
  color: var(--color-green); min-width: 3.2rem; font-variant-numeric: tabular-nums;
}
.focus-body h3 { margin: 0 0 0.1rem; font-size: 1.1rem; }
.focus-body p { margin: 0; font-size: 0.95rem; color: var(--color-ink-soft); line-height: 1.5; }
.qa { border-top: 1px solid var(--color-rule); padding: 0.8rem 0; }
.qa:first-of-type { border-top: 0; }
.qa .q { font-family: var(--font-display); font-size: 1.2rem; margin: 0 0 0.15rem; }
.qa .a { margin: 0; color: var(--color-ink-soft); font-size: 0.98rem; }

/* ---- Video list ------------------------------------------- */
.vsearch { margin-bottom: 1rem; }
.vgroup { margin-bottom: 1.6rem; }
.vhead {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.8rem;
  border-bottom: 2px solid var(--color-green-deep); padding-bottom: 0.35rem; margin-bottom: 0.6rem;
}
.vhead h3 { margin: 0; font-size: 1.15rem; }
.vhead .pct { font-size: 0.85rem; color: #f1ecdc; background: var(--color-green); border-radius: 1rem; padding: 0.05rem 0.6rem; }
a.v {
  display: flex; align-items: center; gap: 0.8rem; text-decoration: none; color: var(--color-ink);
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 0.65rem 0.8rem; margin-bottom: 0.4rem; min-height: 3rem;
}
a.v:hover { border-color: var(--color-green); }
a.v .t { flex: 1; font-size: 1rem; line-height: 1.35; }
a.v .t .cat { display: block; font-size: 0.78rem; color: var(--color-ink-soft); }
a.v .d { font-variant-numeric: tabular-nums; color: var(--color-green); font-size: 0.9rem; flex-shrink: 0; }
.empty { text-align: center; color: var(--color-ink-soft); padding: 2rem 1rem; }

/* ---- Footer ----------------------------------------------- */
/* One item per line, tight. Margins are zeroed and the spacing comes from the
   line-height alone, so the block stays compact and predictable. */
.site-footer {
  border-top: 1px solid var(--color-rule); margin-top: 3rem;
  padding: 0.8rem 1.25rem; text-align: center;
  font-size: 0.82rem; line-height: 1.6; color: var(--color-ink-soft);
}
.site-footer > * { margin: 0; }
.site-footer a { color: var(--color-ink-soft); }

/* ---- club branding admin ---------------------------------- */
.swatch {
  display: inline-block; width: 2.6rem; height: 1.1rem;
  border: 1px solid var(--color-rule); border-radius: 2px; vertical-align: middle;
}
.club-note { font-size: 0.86rem; color: var(--color-ink-soft); }
.club-badge {
  display: inline-block; font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--color-ink-soft); border: 1px solid var(--color-rule);
  border-radius: 1rem; padding: 0.05rem 0.6rem; margin-left: 0.4rem;
}

/* ---- scorecard review -------------------------------------- */
.issue-err, .issue-warn {
  margin: 0 0 0.5rem; padding-left: 0.8rem; font-size: 0.96rem; line-height: 1.5;
  border-left: 3px solid var(--color-flag);
}
.issue-warn { border-left-color: var(--color-brass); }
.issue-err:last-child, .issue-warn:last-child { margin-bottom: 0; }
.shot { border: 1px solid var(--color-rule); border-radius: var(--radius); max-width: 100%; }
table.data td, table.data th { white-space: nowrap; }

/* ---- roles + club switching -------------------------------- */
.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;
}
.club-switch { display: inline-flex; gap: 0.3rem; margin-left: 0.6rem; vertical-align: middle; }
.club-switch select {
  font-family: var(--font-body); font-size: 0.78rem; padding: 0.15rem 0.4rem;
  min-height: 1.9rem; width: auto; max-width: 12rem;
  background: rgba(255,255,255,0.9); border: 1px solid var(--color-rule); border-radius: 2px;
}
.club-switch button {
  font-family: var(--font-body); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; padding: 0.15rem 0.6rem; min-height: 1.9rem;
  background: transparent; color: #f1ecdc; border: 1px solid rgba(255,255,255,0.45);
  border-radius: 2px; cursor: pointer;
}
.club-switch button:hover { background: rgba(255,255,255,0.14); }
.rolerow { display: flex; flex-wrap: wrap; gap: 0.5rem 1.2rem; margin: 0.6rem 0 0.9rem; }
.rolecheck {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.92rem; color: var(--color-ink);
}
.rolecheck input { width: 1.05rem; height: 1.05rem; min-height: 0; }

/* The good-standing attestation. Wider gap and top alignment than .rolecheck
   because this one wraps to two lines on a phone and the box should sit with
   the first line, not float to the middle of the sentence. */
.attest {
  display: flex; align-items: flex-start; gap: 0.55rem;
  font-size: 0.92rem; color: var(--color-ink);
  margin: 0 0 1rem; line-height: 1.45;
}
.attest input { width: 1.05rem; height: 1.05rem; min-height: 0; margin-top: 0.15rem; flex: 0 0 auto; }

/* ---- Analytics: the hole-by-hole grid ---------------------- */
/* Twenty columns will not fit an iPad in portrait, so the table scrolls inside
   its own wrapper rather than forcing the page sideways. The row label is
   sticky, because a Putts row you have scrolled away from the label of is just
   a line of numbers. */
.round-card { margin-bottom: 2.2rem; }
.round-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.6rem;
  margin: 0 0 0.6rem; font-size: 1.05rem;
}
.round-course { color: var(--color-ink-soft); font-weight: 400; }
.round-tee { color: var(--color-ink-soft); font-size: 0.85rem; font-style: italic; }

table.holegrid { table-layout: auto; min-width: 100%; }
table.holegrid th[scope="row"] {
  position: sticky; left: 0; z-index: 1;
  text-align: left; min-width: 5.2rem;
}
table.holegrid th.holenum, table.holegrid td { min-width: 2.1rem; }
table.holegrid td { border-top: 1px solid var(--color-rule); }

/* Not played. Deliberately different from a dash: a blank is "no hole here",
   a dash is "this hole has no such statistic". */
table.holegrid .unplayed { background: var(--color-bg); }
table.holegrid th.unplayed { opacity: 0.35; }

table.holegrid .sub, table.holegrid .tot {
  border-left: 2px solid var(--color-rule); font-weight: 600; white-space: nowrap;
  background: var(--color-bg);
}
table.holegrid .tot { border-left-width: 3px; }
table.holegrid th.sub, table.holegrid th.tot { background: var(--color-green-deep); }
.holegrid .adj { font-weight: 400; color: var(--color-ink-soft); font-size: 0.85em; }
.holegrid .hit { color: var(--color-green); font-weight: 700; }
.holegrid .miss { color: var(--color-clay, #a5453b); }
/* The direction arrows carry the meaning, so they are sized to be read at a
   glance down a column rather than squinted at inside a cell. */
.holegrid .arrow { font-size: 1.15rem; line-height: 1; font-weight: 700; }
/* A statistic that cannot exist for this hole, versus one simply not entered. */
.holegrid .na { color: var(--color-ink-soft); }
.holegrid .norec { background: repeating-linear-gradient(45deg,
  transparent, transparent 3px, var(--color-rule) 3px, var(--color-rule) 4px); }

/* A member's number on a club's roll. Reads as a fact rather than a role, so it
   is set apart from the uppercase role badges beside it. */
/* A three-across row for city / state / ZIP. Collapses on a phone, where three
   fields side by side leaves the city unreadable. */
.grid-3 { display: grid; grid-template-columns: 2fr 0.7fr 1fr; gap: 0 1rem; }
@media (max-width: 30rem) { .grid-3 { grid-template-columns: 1fr; } }

/* A heading inside a form, marking off a group of fields. */
.fieldset-head {
  font-size: 0.95rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-ink-soft); font-weight: 600;
  margin: 1.8rem 0 0.9rem; padding-top: 1.1rem;
  border-top: 1px solid var(--color-rule);
}
.fieldset-head .hint {
  text-transform: none; letter-spacing: 0; font-weight: 400; font-size: 0.85rem;
}

/* "Near Me" sits with All at the head of the A-Z strip, wide enough to hold a
   count without the letters shuffling as that count changes. */
.alpha-near { white-space: nowrap; }

.member-no {
  display: inline-block; font-size: 0.78rem; letter-spacing: 0.04em;
  color: var(--color-ink-soft); background: var(--color-rule);
  border-radius: 1rem; padding: 0.05rem 0.6rem; margin-left: 0.4rem;
}

/* A value the member cannot edit — the GHIN-fed handicap index. Sized like the
   input it replaces so the row does not jump when the feed takes over. */
/* A readonly field must LOOK unavailable without looking broken. Used by the
   account-claim form's username, which is there for the password manager to
   read rather than for the golfer to edit.
   ⚠️ Deliberately keeps full text contrast: greying the text out would make the
   one thing the page is trying to communicate — which address is your username
   — the hardest thing on it to read. The recessed background carries the state. */
input[readonly] {
  background: var(--color-bg);
  border-style: dashed;
  cursor: default;
}
input[readonly]:focus { outline-offset: 1px; }

.handle {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.82em;
  color: var(--color-brass-text);
  margin-left: 0.4rem;
  white-space: nowrap;
}

.readonly-value {
  margin: 0; font-size: 1.15rem; color: var(--color-ink); line-height: 1.5;
}
.readonly-value .hint {
  display: block; font-size: 0.85rem; color: var(--color-ink-soft);
  letter-spacing: 0; text-transform: none;
}
details > summary {
  cursor: pointer; padding: 0.4rem 0; color: var(--color-green);
}

/* ---- Outside sources (GOLF.com) ---------------------------
   Visually fenced off from club content on purpose: their licence permits a
   link, not an endorsement, so this must never read as ours. */
.outside { margin-top: 2.4rem; border-top: 2px solid var(--color-rule); padding-top: 1.4rem; }
.outside .vhead h2 { margin: 0; font-size: 1.15rem; }
.outside > .muted { margin: 0.2rem 0 1rem; font-size: 0.94rem; }
.o { display: flex; gap: 0.85rem; align-items: center; margin-bottom: 0.6rem; }
.o .v { flex: 1; }

.vthumb {
  position: relative; flex: 0 0 auto; width: 108px; padding: 0; border: 1px solid var(--color-rule);
  border-radius: var(--radius); background: none; cursor: pointer; line-height: 0; overflow: hidden;
}
/* The intrinsic size matters: a lazy image inside a zero-height box never
   enters the viewport as far as the browser is concerned, so it is deferred
   forever and the thumbnail stays blank. width/height on the tag plus this
   ratio give the box a size before the bytes arrive — which also stops the
   row jumping when they do. */
.vthumb img { width: 100%; height: auto; display: block; aspect-ratio: 4 / 3; object-fit: cover; }
.vplay {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 1.5rem; text-shadow: 0 1px 4px rgba(0,0,0,.6);
  background: rgba(29, 59, 38, 0.28);
}
.vthumb:hover .vplay, .vthumb:focus-visible .vplay { background: rgba(29, 59, 38, 0.12); }
.vthumb:focus-visible { outline: 2px solid var(--color-brass); outline-offset: 2px; }

/* 16:9, and it must not blow the page out sideways on an iPad. */
.vplayer { width: 100%; max-width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--radius); }

/* ---- Club staff and invitations --------------------------- */
.staffbox { margin: 1.1rem 0 0.4rem; border-top: 1px solid var(--color-rule); padding-top: 0.9rem; }
.staffbox h4 { margin: 0 0 0.5rem; font-size: 1rem; }
.staffbox > .muted { font-size: 0.88rem; margin-top: 0.5rem; }

ul.staff { list-style: none; margin: 0 0 0.9rem; padding: 0; display: flex; flex-direction: column; gap: 0.45rem; }
ul.staff li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem 0.7rem;
  padding-bottom: 0.45rem; border-bottom: 1px dotted var(--color-rule);
}
ul.staff .who { flex: 1 1 14rem; font-size: 0.94rem; }
ul.staff .what { font-size: 0.82rem; color: var(--color-ink-soft); }
ul.staff .state { font-size: 0.8rem; border-radius: 1rem; padding: 0.05rem 0.6rem; white-space: nowrap; }
ul.staff .state.ok { background: var(--color-green); color: #f1ecdc; }
ul.staff .state.wait { background: transparent; color: var(--color-brass-text); border: 1px solid var(--color-brass); }
form.inline { display: inline; }
.btn-small { font-size: 0.78rem; padding: 0.1rem 0.55rem; }

form.invite { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; flex-wrap: wrap; }
form.invite input[type="email"] { flex: 1 1 15rem; min-width: 0; }

/* The invitation form now carries first name, last name and the address. At an
   iPad's 768px the three fields plus the button do not fit on one line, so the
   names take a narrower basis and the address keeps the wide one — flex-wrap
   then breaks it as names / address+button rather than stranding one field. */
form.invite-wide input[type="text"] { flex: 1 1 8rem; min-width: 0; }
form.invite-wide input[type="email"] { flex: 2 1 15rem; min-width: 0; }

/* A value the user may read but not edit — the frozen email address on the
   profile. Deliberately NOT a readonly <input>: an input that cannot be typed
   into still invites the attempt, and a password manager may try to fill it. */
.readonly-value {
  margin: 0;
  padding: 0.45rem 0.6rem;
  background: var(--color-surface);
  border: 1px solid var(--color-rule);
  border-radius: 3px;
  font-family: inherit;
}
/* The coach's "add an existing member" form reuses form.invite, and a <select>
   needs the same flex sizing the email input gets or it collapses to its
   content width beside a full-width button. */
form.invite select { flex: 1 1 15rem; min-width: 0; }

/* ---- Header name menu ------------------------------------- */
.header-user-toggle {
  background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
  color: inherit; display: inline-flex; align-items: baseline; gap: 0.3rem;
}
.header-user-toggle:focus-visible { outline: 2px solid var(--color-brass-soft); outline-offset: 3px; }
.header-user-name { text-decoration: underline; text-underline-offset: 3px; }
.header-user-caret { font-size: 0.7em; }

.header-user-menu {
  position: absolute; right: 0; top: 100%; margin-top: 0.4rem; z-index: 20;
  min-width: 9rem; display: flex; flex-direction: column;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden;
}
/* A closed menu must not lay out a box. `visibility: hidden` and a bare
   `display: flex` above would both leave it occupying space off to the right,
   which reads as a phantom horizontal scrollbar on EVERY page — the chrome,
   not the page. The attribute wins here on purpose. */
.header-user-menu[hidden] { display: none; }
.header-user-menu a {
  padding: 0.5rem 0.9rem; color: var(--color-ink); text-decoration: none;
  font-size: 0.94rem; white-space: nowrap;
}
.header-user-menu a + a { border-top: 1px solid var(--color-rule); }
.header-user-menu a:hover, .header-user-menu a:focus-visible {
  background: var(--color-bg); text-decoration: underline;
}

/* ---- Club chooser, tabs, logo ------------------------------ */
.clubpick { display: flex; align-items: flex-end; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1.2rem; }
.clubpick .flabel { margin: 0 0 0.2rem; }
.clubpick select { min-width: 14rem; }
.clubpick .btn { white-space: nowrap; }

nav.tabs { display: flex; flex-wrap: wrap; gap: 0.15rem; border-bottom: 2px solid var(--color-rule); margin: 1rem 0 0; }
nav.tabs .tab {
  padding: 0.45rem 0.9rem; text-decoration: none; color: var(--color-ink-soft);
  border: 1px solid transparent; border-bottom: 0; border-radius: var(--radius) var(--radius) 0 0;
  font-size: 0.94rem; margin-bottom: -2px;
}
nav.tabs .tab:hover { color: var(--color-ink); background: var(--color-bg); }
nav.tabs .tab.on {
  color: var(--color-ink); background: var(--color-surface);
  border-color: var(--color-rule); border-bottom: 2px solid var(--color-surface); font-weight: 600;
}
.tabbody { padding-top: 1.1rem; }
.tabbody h4 { margin: 1.4rem 0 0.5rem; font-size: 1rem; }
.tabbody h4:first-child { margin-top: 0; }

.logobox { border: 1px solid var(--color-rule); border-radius: var(--radius); padding: 1rem; }
.logopreview { max-height: 80px; max-width: 100%; display: block; margin-bottom: 0.8rem; }
/* The mark is shown at 64px — big enough to judge, small enough to be honest
   about the fact that it has to survive being 16px in a browser tab. */
.markpreview { width: 64px; height: 64px; object-fit: contain; display: block; margin-bottom: 0.8rem; }
.logobox + .logobox { margin-top: 1rem; }

/* ⚠️ MATCHING THE TITLE'S FONT-SIZE IS NOT THE SAME AS MATCHING ITS PRESENCE,
   and the first attempt at this got it wrong. Set to the title's own clamp the
   crest measured 55.8px against a 55.8px title and still read as an
   afterthought: the AAC mark is a thin PORTRAIT monogram carrying a lot of
   internal whitespace, so at equal height it puts far less ink on the page than
   chunky display type does. Delicate line art needs MORE height than the text
   beside it, not the same. Hence its own curve, roughly 1.7x the title.
   Vertically centred rather than pinned near the top, so the height can grow
   without the mark drifting out of the masthead.
   ⚠️ max-width bounds a WIDE lockup: the AAC crest is portrait and ~60px across
   at this height, but a horizontal wordmark at 95px tall runs past 280 and
   would crowd the centred title without a ceiling. */
.club-logo {
  position: absolute; left: 1.25rem; top: 50%; transform: translateY(-50%);
  line-height: 0;
}
.club-logo img {
  height: clamp(3rem, 7.5vw, 5.25rem);
  width: auto; max-width: 300px; display: block;
}
@media (max-width: 700px) {
  /* No height override here: the clamp above already lands at its 1.9rem floor
     on a phone, so a second number would only be a second thing to keep in sync. */
  .club-logo { position: static; margin: 0 0 0.5rem; }
  .club-logo img { margin: 0 auto; }
}

/* ---- Page heading with an action on the right -------------- */
.pagehead {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
}
.pagehead .page-title { margin-bottom: 0.6rem; }
.pagehead .btn { flex: 0 0 auto; margin-top: 0.4rem; }
/* The Show button is present for a no-JS page and hidden by clubpick.js. */
.clubpick-go[hidden] { display: none; }

/* ---- Footer, modelled on hamfamclan ------------------------ */
.site-footer .last-updated { font-variant-numeric: tabular-nums; }

/* ---- Administration cards ---------------------------------- */
.admin-cards {
  display: grid; gap: 1rem; margin-top: 1.4rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
.admin-card {
  display: block; text-decoration: none; color: inherit;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.1rem 1.2rem;
}
.admin-card:hover, .admin-card:focus-visible {
  border-color: var(--color-brass); box-shadow: 0 2px 6px rgba(35,39,31,.12), 0 10px 30px rgba(35,39,31,.08);
}
.admin-card:focus-visible { outline: 2px solid var(--color-brass); outline-offset: 2px; }
.admin-card h3 {
  margin: 0 0 0.4rem; font-family: var(--font-display); font-size: 1.3rem;
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem;
}
.admin-card p { margin: 0; font-size: 0.94rem; color: var(--color-ink-soft); }
.admin-badge {
  font-family: var(--font-body); font-size: 0.72rem; white-space: nowrap;
  color: #f1ecdc; background: var(--color-green); border-radius: 1rem; padding: 0.05rem 0.6rem;
}

/* ---- About menu in the primary nav -------------------------- */
.nav-group { position: relative; display: inline-flex; align-items: baseline; gap: 0.2rem; }
/* Part of the same click target as the word, not a separate few-pixel button. */
.nav-about-toggle { cursor: pointer; }
.nav-caret { font-size: 0.7em; margin-left: 0.3rem; }
.nav-menu {
  position: absolute; right: 0; top: 100%; margin-top: 0.45rem; z-index: 20;
  min-width: 12rem; display: flex; flex-direction: column;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden;
  text-align: left;
}
/* A closed menu must not lay out a box — a flex box parked off to the right of
   every page reads as a phantom horizontal scrollbar on the chrome. */
.nav-menu[hidden] { display: none; }
/* ⚠️ Scoped under .site-nav on purpose. These links sit INSIDE the nav bar, so
   `.site-nav a:hover { color:#fff }` applies to them at equal specificity —
   which painted the menu's text white on its own light background and made it
   vanish on hover. (0,3,1) beats (0,2,1), so the menu now wins outright
   instead of relying on source order and inheriting whatever the bar wants. */
.site-nav .nav-menu a {
  display: block; padding: 0.5rem 0.9rem; color: var(--color-ink); text-decoration: none;
  font-size: 0.9rem; letter-spacing: normal; text-transform: none; white-space: nowrap;
  border-bottom: 0;
}
.site-nav .nav-menu a + a { border-top: 1px solid var(--color-rule); }
.site-nav .nav-menu a:hover,
.site-nav .nav-menu a:focus-visible,
.site-nav .nav-menu a[aria-current="page"] {
  color: var(--color-ink); background: var(--color-bg);
  text-decoration: underline; border-bottom: 0;
}

/* ---- Independent security checks --------------------------- */
.checks { display: grid; gap: 0.7rem; margin: 1rem 0 1.4rem;
          grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
.check {
  display: flex; flex-direction: column; gap: 0.2rem; text-decoration: none; color: inherit;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 0.75rem 0.9rem;
}
.check:hover, .check:focus-visible { border-color: var(--color-brass); }
.check:focus-visible { outline: 2px solid var(--color-brass); outline-offset: 2px; }
.check strong { color: var(--color-green); font-size: 0.98rem; }
.check span { font-size: 0.85rem; color: var(--color-ink-soft); }

/* The one line the guide page is built around. Set as a statement, not as a
   quotation: it carries no quote marks and no name because the usual
   attribution is wrong (see the comment on guidePage in index.js). */
.maxim {
  margin: 1.1rem 0 1.3rem;
  padding: 0.15rem 0 0.15rem 1rem;
  border-left: 3px solid var(--color-brass);
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 3vw, 1.45rem);
  line-height: 1.3;
  color: var(--color-green);
}

/* ---- Feedback queue ---------------------------------------- */
.fbmsg {
  background: var(--color-bg); border-left: 3px solid var(--color-brass);
  padding: 0.6rem 0.9rem; margin: 0.6rem 0; font-size: 0.94rem;
}

/* ---- Known-courses multi-select ---------------------------- */
ul.pick { list-style: none; margin: 0 0 1rem; padding: 0;
          display: flex; flex-direction: column; gap: 0.1rem; }
ul.pick li { border-bottom: 1px dotted var(--color-rule); }
ul.pick label {
  display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap;
  padding: 0.5rem 0.2rem; cursor: pointer;
}
ul.pick label:hover { background: var(--color-bg); }
ul.pick input[type="checkbox"] { flex: 0 0 auto; width: 1.05rem; height: 1.05rem; }
.pick-name { flex: 1 1 16rem; font-weight: 600; }
.pick-meta { font-size: 0.86rem; color: var(--color-ink-soft); }
/* Distance sits in the Near Me list only. Tabular numerals so a column of
   "4.2 mi" / "18 mi" lines up instead of jittering. */
.pick-mi { font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--color-ink); }
.hint-block { font-size: 0.86rem; color: var(--color-ink-soft); margin: 0.35rem 0 0; }

/* ---- My courses: one line each ------------------------------ */
ul.mycourses { list-style: none; margin: 0 0 0.5rem; padding: 0; }
ul.mycourses li {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.45rem 0.2rem; border-bottom: 1px solid var(--color-rule);
}
/* Home courses sort to the top in SQL; this is what tells you why. */
ul.mycourses li.home .mc-name { font-weight: 600; }
.mc-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-where { flex: 0 0 auto; font-size: 0.86rem; color: var(--color-ink-soft); white-space: nowrap; }
.mc-acts { flex: 0 0 auto; display: flex; gap: 0.15rem; }

.iconbtn {
  background: none; border: 1px solid transparent; border-radius: var(--radius);
  color: var(--color-ink-soft); cursor: pointer; font-size: 1rem; line-height: 1;
  padding: 0.25rem 0.4rem;
}
.iconbtn:hover { border-color: var(--color-rule); background: var(--color-bg); color: var(--color-ink); }
.iconbtn:focus-visible { outline: 2px solid var(--color-brass); outline-offset: 1px; }
/* Blue means it IS a home course — the control shows state, not just an action.
   Deliberately NOT the club's primary: a club whose branding is green or navy
   would make "set" indistinguishable from "not set", and this has to read the
   same on every club's theme. */
.iconbtn.on { color: #1a6fd4; border-color: #1a6fd4; background: rgba(26,111,212,0.08); }
.iconbtn.on:hover { color: #1558a8; border-color: #1558a8; }
.iconbtn.danger:hover { color: var(--color-flag); border-color: var(--color-flag); }

@media (max-width: 560px) {
  ul.mycourses li { flex-wrap: wrap; }
  .mc-name { flex: 1 1 100%; white-space: normal; }
}

/* Sibling section headings that carry a page on their own, with no h1 above
   them. Sized as the page's own headings rather than as subheadings. */
.section-head {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.6rem, 4vw, 2.1rem); line-height: 1.15;
  margin: 0 0 0.6rem;
}
section + section .section-head { margin-top: 2rem; }
/* A .section-head has no top margin of its own, so "Daily Views" sat straight
   on top of the stat tiles. Same complaint, same remedy as .summary below. */
.stats + .section-head { margin-top: 2.5rem; }
/* "By Hole Type" and "Where The Strokes Go" are h3s INSIDE .summary rather than
   headings that start their own section, so the rule above reached them only as
   descendants and gave them the same 2rem it gives a section opener. Measured
   against the deployed stylesheet that is 36px — enough to separate two
   sections, not enough after a six-tile stats grid and a full-width table,
   which is why the page read cramped. They get their own, larger step.
   📌 The root is 18px here, so 1rem = 18px: 2rem = 36px, this = 58.5px. */
.summary * + .section-head { margin-top: 3.25rem; }

/* ---- Course links and the tee table ------------------------- */
.mc-name a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--color-rule); }
.mc-name a:hover, .mc-name a:focus-visible { border-bottom-color: var(--color-brass); }
.pick-link { font-size: 0.8rem; color: var(--color-ink-soft); white-space: nowrap; }

/* Ratings, slopes and yardages are compared down the column, so they line up. */
table.tees td:nth-child(n+2) { text-align: right; font-variant-numeric: tabular-nums; }
table.tees th:nth-child(n+2) { text-align: right; }

/* ---- Course Database: list plus an A-Z rail ------------------ */
.dbwrap { display: flex; align-items: flex-start; gap: 1rem; }
.dblist { flex: 1 1 auto; min-width: 0; }

/* Twenty rows, then scroll. Each row is about 2.1rem, so this is a height
   rather than a count — a fixed pixel value would drift with the type size. */
.dblist ul.pick {
  max-height: 42rem; overflow-y: auto; margin-bottom: 0.6rem;
  border: 1px solid var(--color-rule); border-radius: var(--radius);
  padding: 0.2rem 0.6rem;
}
.dblist ul.pick li:last-child { border-bottom: 0; }

nav.alpha {
  flex: 0 0 auto; display: grid; grid-template-columns: repeat(2, 1.5rem);
  gap: 0.1rem; font-size: 0.78rem; text-align: center;
}
nav.alpha a, nav.alpha span {
  padding: 0.15rem 0; border-radius: 2px; text-decoration: none;
  color: var(--color-green); line-height: 1.3;
}
nav.alpha a:hover, nav.alpha a:focus-visible { background: var(--color-bg); text-decoration: underline; }
nav.alpha a.on { background: var(--color-green); color: #f1ecdc; font-weight: 600; }
/* A letter with nothing behind it is shown, but is not a link and is not bait. */
nav.alpha .dead { color: var(--color-rule); cursor: default; }
nav.alpha .alpha-all { grid-column: 1 / -1; font-weight: 600; }

@media (max-width: 560px) {
  .dbwrap { flex-direction: column; }
  nav.alpha { grid-template-columns: repeat(9, 1fr); width: 100%; }
  nav.alpha .alpha-all { grid-column: 1 / -1; }
}
/* Provenance on a database row: present, but never louder than the course. */
.pick-src { flex: 0 0 auto; font-size: 0.78rem; color: var(--color-ink-soft); white-space: nowrap; }
@media (max-width: 700px) { .pick-src { flex: 1 1 100%; } }

/* ---- Dashboard: index hero + trend chart -------------------
   The chart is server-rendered SVG and the range filter is links, so this
   whole block works with no JavaScript. Do not "improve" it with an inline
   <script> — script-src is 'self' and it would silently never run. */
.idx-hero { display: grid; grid-template-columns: 1fr; gap: 1rem; margin-bottom: 1.4rem; }
/* 🔴 .card + .card adds a 1rem top margin, which inside a grid pushes the SECOND
   card down and breaks the alignment of the pair. Zero it in both grids. */
.idx-hero > .card + .card, .grid-2 > .card + .card { margin-top: 0; }
/* Grid stretch already equalises the row; the cards must be flex columns so the
   scroll region can absorb the difference rather than leaving a ragged gap. */
.idx-hero > .card, .grid-2 > .card { display: flex; flex-direction: column; }
/* 46rem so an iPad in PORTRAIT (768px) still gets index-beside-chart, which is
   the layout this page was designed around and the device most members use. */
@media (min-width: 46rem) { .idx-hero { grid-template-columns: minmax(11rem, 16rem) 1fr; } }

.idx-now { justify-content: flex-start; }
.idx-value {
  font-size: clamp(3.4rem, 11vw, 5rem); line-height: 1; margin: 0.2rem 0 0;
  font-variant-numeric: tabular-nums; color: var(--color-green); font-weight: 600;
}
.idx-meta { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--color-ink-soft); }
.idx-low  { margin: 0.35rem 0 0; font-size: 0.86rem; color: var(--color-brass-text); }

/* Direction indicator, centred at the foot of the card. margin-top:auto pushes
   it down whatever the block above it holds, which also keeps it aligned when
   the card is stretched to match the Index Trend card beside it.
   One glyph, three states — it must stay a symbol, not creep back into being a
   second chart. */
/* flex:1 + centring puts the glyph in the middle of whatever space is left
   below the index, rather than pinning it to the card's floor. The card is
   stretched to match the Index Trend card beside it, so that space is real. */
.idx-trendmark {
  flex: 1 1 auto; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 1rem 0 0.2rem; text-align: center;
}
.idx-arrow {
  display: grid; place-items: center;
  width: 4.6rem; height: 4.6rem; border-radius: 50%;
}
.idx-arrow svg { width: 2.9rem; height: 2.9rem; }
.idx-arrow svg g {
  fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
/* Falling index is the good direction in golf. */
.idx-arrow.down { background: rgba(47, 93, 58, 0.12); }
.idx-arrow.down svg g { stroke: var(--color-green); }
.idx-arrow.up   { background: rgba(140, 43, 48, 0.10); }
.idx-arrow.up   svg g { stroke: var(--color-flag); }
.idx-arrow.flat { background: var(--color-rule); }
.idx-arrow.flat svg g { stroke: var(--color-ink-soft); }

/* Footnote pinned under the table it annotates, at the foot of the card. */
.card-foot {
  margin: 0.6rem 0 0; font-size: 0.8rem; color: var(--color-ink-soft);
}

/* One page-level range control, top right. It governs the chart, the history
   table and the rounds table together, so it must not live inside any one card. */
.page-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: flex-end; gap: 0.35rem 1rem; margin-bottom: 1.1rem;
}

.range-filter { display: flex; flex-wrap: wrap; gap: 0.1rem; font-size: 0.78rem; }
.range-filter a, .range-filter .range-on {
  padding: 0.22rem 0.5rem; border-radius: 999px; white-space: nowrap; text-decoration: none;
}
.range-filter a { color: var(--color-ink-soft); }
.range-filter a:hover { background: var(--color-rule); color: var(--color-ink); }
.range-filter .range-on { background: var(--color-green); color: #fff; font-weight: 600; }

/* No max-height: capping it letterboxed the SVG inside the card, leaving gaps
   either side that read as a bug. The 520x280 viewBox keeps the height sane at
   every width the page actually gets. */
.idx-chart { display: block; width: 100%; height: auto; margin-top: 0.7rem; }
.idx-chart .grid { stroke: var(--color-rule); stroke-width: 1; }
.idx-chart .ylab, .idx-chart .xlab {
  font-size: 11px; fill: var(--color-ink-soft); font-variant-numeric: tabular-nums;
}
.idx-chart .ylab { text-anchor: end; }
.idx-chart .xlab.end { text-anchor: end; }
.idx-chart .area { fill: var(--color-green); opacity: 0.10; }
.idx-chart .line { fill: none; stroke: var(--color-green); stroke-width: 2;
                   stroke-linejoin: round; stroke-linecap: round; }
.idx-chart .pt   { fill: var(--color-green); }
.chart-empty { padding: 2.2rem 0; text-align: center; }

/* Lower is better in golf, so a fall is the good direction. */
.idx-delta { margin: 0.5rem 0 0; font-size: 0.85rem; font-weight: 600; text-align: center; }
.idx-delta.down { color: var(--color-green); }
.idx-delta.up   { color: var(--color-flag); }
.idx-delta.flat { color: var(--color-ink-soft); font-weight: 500; }

table.data.compact td, table.data.compact th { padding: 0.42rem 0.55rem; font-size: 0.92rem; }
table.data.compact td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ── multi-series charts: a coach's whole roster on one pair of axes ──────
   🔴 THE HALO IS NOT DECORATION. Eight lines crossing on one chart merge into
   a knot at every intersection; a stroke of the surface colour drawn under
   each line at double width gives every crossing a clean edge. Drawn first so
   the coloured stroke always sits on top of its own halo. */
.idx-chart.multi .halo  { fill: none; stroke: var(--color-surface); stroke-width: 4.5;
                          stroke-linejoin: round; stroke-linecap: round; }
.idx-chart.multi .sline { fill: none; stroke-width: 2;
                          stroke-linejoin: round; stroke-linecap: round; }
.idx-chart.multi .send  { stroke: var(--color-surface); stroke-width: 1.5; }

/* The legend is a table, because three of the eight series colours sit below
   3:1 on parchment and identity must not rest on a swatch alone. */
.legend-table { margin-top: 0.6rem; }
.legend-table .swatch {
  display: inline-block; width: 0.72rem; height: 0.72rem; border-radius: 2px;
  margin-right: 0.45rem; vertical-align: baseline;
  /* A hairline keeps the palest slots visible against the row behind them. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.22);
}
.legend-table td .down { color: var(--color-green); font-weight: 600; }
.legend-table td .up   { color: var(--color-flag);  font-weight: 600; }
.legend-table td .flat { color: var(--color-ink-soft); }

/* The client filter sits top-left of the dashboard, opposite the range filter. */
.dash-filters { display: flex; flex-wrap: wrap; gap: 0.6rem 1rem;
                align-items: center; justify-content: space-between; }
.client-filter { display: flex; gap: 0.4rem; align-items: center; }
.client-filter select { min-width: 12rem; }

/* The coach's average-index card is a banner, not a column: the number, what it
   covers and the trend read across the card instead of stacking down a narrow
   one. Falls back to stacked below 40rem, where there is no room to sit side by
   side. */
.roster-now { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 1.6rem; }
.roster-now .eyebrow { flex: 1 0 100%; margin: 0; }
.roster-now .idx-value { margin: 0; }
.roster-now .idx-meta { margin: 0; flex: 0 1 auto; max-width: 16rem; }
.roster-now .idx-trendmark {
  display: flex; flex-direction: row; align-items: center; gap: 0.7rem;
  margin: 0 0 0 auto; padding: 0; flex: 0 0 auto; text-align: left;
}
/* A banner-sized arrow: the solo card's 4.6rem disc is the hero of that page
   and merely loud on this one, where the eight lines below are the subject. */
.roster-now .idx-arrow { width: 3rem; height: 3rem; }
.roster-now .idx-arrow svg { width: 1.9rem; height: 1.9rem; }
.roster-now .idx-delta { margin: 0; text-align: left; }
table.data.compact td.course { text-align: left; white-space: normal; line-height: 1.25; }
.c-name { display: block; }
.c-fac  { display: block; font-size: 0.78rem; color: var(--color-ink-soft); }
table.data.compact th:not(:first-child) { text-align: right; }
.card-note { margin: -0.35rem 0 0.7rem; font-size: 0.82rem; color: var(--color-ink-soft); }
.tag { display: inline-block; font-size: 0.68rem; padding: 0.05rem 0.32rem; border-radius: 3px;
       background: var(--color-rule); color: var(--color-ink-soft); vertical-align: 1px; }
.counts { color: var(--color-green); font-weight: 700; }

/* ---- Scrolling card tables --------------------------------
   The two lower cards must match height whatever the range holds — 67 index
   revisions against 20 rounds — so the table region scrolls inside the card
   rather than the card growing to fit. */
.table-scroll {
  flex: 1 1 auto; overflow-y: auto; overflow-x: auto;
  max-height: 21rem; min-height: 6rem;
  border: 1px solid var(--color-rule); border-radius: var(--radius);
}
.table-scroll table.data { margin: 0; }
/* The header must stay put while the body scrolls under it, and its background
   has to be opaque or rows show through. */
.table-scroll table.data.sticky thead th {
  position: sticky; top: 0; z-index: 1; background: var(--color-green-deep);
}
.table-scroll table.data td:first-child { white-space: nowrap; }

/* ---- Score history ----------------------------------------
   Same visual language as the index chart. The full-width card sits between
   the hero pair and the two table cards. */
.score-card { margin-bottom: 1.4rem; }
.score-card .card-foot { max-width: 46rem; }
/* min-height only bites on a phone, where the wide box would otherwise
   collapse to ~110px; it letterboxes vertically rather than clipping. */
.score-chart { min-height: 150px; }
/* A round counting toward the index gets a solid dot; the rest are outlined,
   matching the bullet convention in the Recent Rounds card. */
.score-chart .pt { fill: var(--color-surface); stroke: var(--color-green); stroke-width: 1.6; }
.score-chart .pt.used { fill: var(--color-green); stroke: var(--color-green); }

/* ---- Score chart hover ------------------------------------
   🔴 Drawn tooltip, not <title>. The browser's native SVG tooltip waits about a
   second and the delay cannot be configured — unusable for scrubbing a line of
   twenty points. Revealed by CSS alone, so there is no script for the CSP to
   block, and no inline style either (style-src is 'self'). */
.score-chart .hit { fill: transparent; }          /* generous invisible hover target */
.score-chart .tip { opacity: 0; pointer-events: none; transition: opacity 0.06s linear; }
.score-chart .dot:hover .tip,
.score-chart .dot:focus-within .tip { opacity: 1; }
.score-chart .tip rect { fill: var(--color-green-deep); }
.score-chart .tip text {
  fill: #f1ecdc; font-family: var(--font-body); font-size: 11px;
  text-anchor: middle; font-variant-numeric: tabular-nums;
}
.score-chart .dot:hover .pt { stroke-width: 2.4; }
@media (prefers-reduced-motion: reduce) { .score-chart .tip { transition: none; } }

/* ── Analytics summary ─────────────────────────────────────────────────── */
/* Sits under the hole-by-hole cards. Every figure comes from src/stats.js. */
.summary { margin-top: 3rem; }

/* The one-line finding, when the numbers support one. Deliberately quiet: it
   is a statement about arithmetic, not a coaching instruction, and it must not
   look like the AI narration that will sit below it. */
.leak {
  margin: 0 0 1.25rem;
  padding: 0.75rem 1rem;
  border-left: 3px solid var(--color-brass);
  background: var(--color-surface);
  border-radius: 0 6px 6px 0;
}

.bypar th[scope="row"] { text-align: left; white-space: nowrap; }
.bypar td { font-variant-numeric: tabular-nums; text-align: right; }
.bypar .tot { font-weight: 600; }

/* Marks a number that is carrying the damage. Never the only signal — the
   figure is right there beside it — so a reader who cannot see the colour
   loses nothing. */
.bypar .bad { color: var(--color-flag); font-weight: 600; }

/* ── Practice note ─────────────────────────────────────────────────────── */
/* Deliberately distinct from the statistics above it. The numbers are the
   site's; this is a reading of them, and the two should not be mistaken for
   one another at a glance. */
.note { margin-top: 2.5rem; }

/* What the page could not see. Quiet on purpose: it is an admission about the
   data, not a coaching instruction and not an advertisement, so it takes a top
   rule and smaller type rather than the brass bar .leak uses for a finding.
   It only ever renders when the record is actually thin. */
.coverage-note {
  margin-top: 3rem; padding-top: 1.25rem;
  border-top: 1px solid var(--color-rule);
  color: var(--color-ink-soft);
  font-size: 0.92rem;
}
.coverage-note p { margin: 0 0 0.6rem; }
.coverage-note p:last-child { margin-bottom: 0; }
.coverage-note strong { color: var(--color-ink); }
.coverage-note .cite { font-size: 0.86rem; font-style: italic; }
.coverage-note .cite cite { font-style: inherit; }
.note-body {
  padding: 1.1rem 1.25rem;
  background: var(--color-surface);
  border: 1px solid var(--color-rule);
  border-radius: 8px;
  margin-bottom: 1rem;
}
.note-body.stale { opacity: 0.85; }
.note-stale {
  margin: 0 0 0.9rem;
  font-size: 0.9rem;
  color: var(--color-flag);
}
.note-obs { margin: 0 0 0.9rem; padding-left: 1.1rem; }
.note-obs li { margin-bottom: 0.45rem; line-height: 1.5; }
.note-practice { margin: 0 0 0.9rem; line-height: 1.55; }
.note-focus { margin: 0 0 0.9rem; }

/* The provenance line. Small, but it is the part that keeps the feature
   honest, so it is never hidden behind a disclosure toggle. */
.note-mark {
  margin: 0;
  padding-top: 0.8rem;
  border-top: 1px solid var(--color-rule);
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--color-ink-soft);
}

/* Goals and their grading. Rendered from the site's stored numbers, never from
   the model's prose, so they are styled as data rather than as writing. */
.note-sub {
  margin: 1.2rem 0 0.5rem;
  font-family: var(--font-body);
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-ink-soft);
}
.goals th[scope="row"] { text-align: left; white-space: nowrap; }
.goals td { font-variant-numeric: tabular-nums; text-align: right; }
.note-units { margin: 0.5rem 0 0; font-size: 0.82rem; color: var(--color-ink-soft); line-height: 1.45; }

/* The verdict never rests on colour alone — the word is the signal, the colour
   only reinforces it. */
/* Standalone, not scoped to .goals — the handicap explainer uses the same
   vocabulary in its own table, and scoping them meant they silently did
   nothing there. */
.v-met      { color: var(--color-good); font-weight: 600; }
.v-improved { color: var(--color-brass-text); font-weight: 600; }
.v-missed   { color: var(--color-flag); }
.v-unmeasured { color: var(--color-ink-soft); }
.v-target   { font-weight: 700; }

/* ── Handicap System explainer ─────────────────────────────────────────── */
.formula {
  margin: 0.9rem 0;
  padding: 0.7rem 0.9rem;
  background: var(--color-surface);
  border-left: 3px solid var(--color-brass);
  border-radius: 0 6px 6px 0;
  font-variant-numeric: tabular-nums;
}

/* The counting eight against the twelve that are thrown away. The shading is
   reinforced by the caption and by each bar's own title, so the point survives
   for anyone who cannot distinguish the two fills. */
.diffchart .bar-on  { fill: var(--color-green); }
.diffchart .bar-off { fill: var(--color-rule); }
.diffchart .idxline { stroke: var(--color-flag); stroke-width: 1.5; stroke-dasharray: 5 3; }
.diffchart .idxlabel { fill: var(--color-flag); font-size: 11px; font-weight: 600; }
.diffchart .grid { stroke: var(--color-rule); stroke-width: 0.5; }
.diffchart .axis { stroke: var(--color-ink-soft); stroke-width: 1; }
.diffchart .ax { fill: var(--color-ink-soft); font-size: 11px; }

.assumed { color: var(--color-ink-soft); font-style: italic; }

.chartfig { margin: 1.4rem 0; }
.chartfig figcaption {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: var(--color-ink-soft);
  line-height: 1.45;
}

/* ---- The Library ------------------------------------------- */
.books, .results { list-style: none; margin: 1.2rem 0 1.6rem; padding: 0; display: grid; gap: 0.7rem; }
/* ⚠️ ONE FULL-WIDTH ROW PER BOOK, NOT A GRID OF CONTENT-SIZED CARDS. The card
   used to size itself to its title, so a shelf looked ragged and — worse — the
   buttons were absolutely positioned over the card and a long title ran
   straight underneath them. "Putting Out of Your Mind" overlapped Drop cover.
   Now the card is a flex ROW: cover, then text that takes the slack, then the
   actions pinned right by margin-left:auto. Nothing overlaps because nothing is
   out of flow, and every row is the same width whatever the title. */
.books { grid-template-columns: 1fr; }
.book {
  display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 0.85rem 0.95rem;
}
.book:hover, .book:focus-within { border-color: var(--color-brass); }
.book-link {
  display: flex; gap: 0.9rem; align-items: center;
  flex: 1 1 16rem; min-width: 0;          /* min-width:0 lets a long title wrap */
  text-decoration: none; color: inherit;
}
.book-link:focus-visible { outline: 2px solid var(--color-brass); outline-offset: 3px; border-radius: 3px; }
/* A fixed box whatever the jacket proportions, so a shelf of mixed covers still
   lines up. object-fit contains rather than crops — a cropped book jacket loses
   the title, which is the one thing it is there to show. */
.book-cover { width: 64px; height: 96px; object-fit: contain; flex: 0 0 auto; border-radius: 2px; }
.book-cover-none { background: var(--color-bg); border: 1px dashed var(--color-rule); }
.book-text { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; overflow-wrap: anywhere; }
.book-text strong { color: var(--color-green); }
.book-meta, .book-by, .book-note { font-size: 0.85rem; color: var(--color-ink-soft); }
.book-by { margin-top: 0.35rem; font-style: italic; }
/* margin-left:auto rather than absolute: the actions are pushed right by the
   text beside them, so they can never sit on top of it. */
.book-del { flex: 0 0 auto; margin-left: auto; display: flex; gap: 0.4rem; align-items: center; }
.btn-small { font-size: 0.78rem; padding: 0.25rem 0.6rem; }
.result form {
  display: flex; gap: 0.9rem; align-items: center; justify-content: space-between;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 0.7rem 0.9rem;
}
.result-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.book-add { margin: 1.4rem 0 0.6rem; }
.book-disclosure { font-size: 0.82rem; }
/* A frame so a CONTAINED cover reads as deliberate rather than as a broken
   image floating on the card. Open Library's scans vary in proportion and some
   carry white margins of their own; without an edge they dissolve into the
   card. */
.book-cover { background: var(--color-bg); border: 1px solid var(--color-rule); padding: 2px; }

/* ---- Elevated-privilege warning in the masthead ------------- */
/* Sits exactly where a club crest would, and deliberately does not look like
   one: the site's palette is green and brass, so flag red reads as "not
   normal" at a glance rather than as decoration. */
.admin-warning {
  position: absolute; left: 1.25rem; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; gap: 0.45rem;
  background: var(--color-flag); color: #f6efe2;
  border: 1px solid rgba(255,255,255,0.35); border-radius: 4px;
  padding: 0.3rem 0.6rem 0.3rem 0.5rem;
  font-family: var(--font-body); font-size: 0.7rem;
  letter-spacing: 0.11em; text-transform: uppercase; line-height: 1;
}
.admin-warning svg { flex: 0 0 auto; }
@media (max-width: 700px) {
  /* Static like the club logo at this width, so it cannot overlap the title. */
  .admin-warning { position: static; transform: none; margin: 0 auto 0.6rem;
                   display: inline-flex; }
}

/* Count of feedback waiting, on the About toggle and on the item itself. */
.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  margin-left: 0.35rem;
  padding: 0 0.3rem;
  border-radius: 0.6rem;
  background: var(--color-flag);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  /* Sits on a dark bar and a light menu both, so it carries its own contrast
     rather than inheriting whatever it lands on. */
  vertical-align: middle;
}
.nav-menu .nav-badge { margin-left: 0.5rem; }

/* ---- "Which club are you here as?" -------------------------- */
.choose-club { margin: 1.4rem 0 0.6rem; }
.choose-club-opt {
  display: flex; align-items: flex-start; gap: 0.7rem; cursor: pointer;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 0.85rem 1rem; margin-bottom: 0.6rem;
}
.choose-club-opt:hover { border-color: var(--color-green); }
/* The radio is 1.05rem elsewhere and inherits a min-height from the shared
   input rule; both have to go or it sits below the first line of the label. */
.choose-club-opt input { width: 1.1rem; height: 1.1rem; min-height: 0; margin-top: 0.15rem; flex: none; }
.block { display: block; }

/* A badge that is a caution rather than a label — "no second factor" on the
   site-administrator list has to read differently from "two-factor on". */
.club-badge.warn { background: var(--color-flag); color: #fff; }

/* ---- Two-factor sign-in ------------------------------------- */
/* The setup key is read off a screen and typed into a phone, so it is spaced,
   monospaced and large. A misread character here is an account that cannot be
   signed into, which is the expensive kind of typo. */
.setup-key {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.15rem; letter-spacing: 0.12em; word-break: break-all;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius); padding: 0.7rem 0.9rem; margin: 0.6rem 0;
}
.steps { margin: 0 0 1.4rem; padding-left: 1.2rem; }
.steps li { margin-bottom: 0.9rem; }
.recovery { border-left: 4px solid var(--color-flag); }
.codes {
  list-style: none; margin: 0.8rem 0; padding: 0;
  display: grid; grid-template-columns: 1fr; gap: 0.35rem;
}
@media (min-width: 30rem) { .codes { grid-template-columns: 1fr 1fr; } }
.codes li {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1rem; letter-spacing: 0.06em;
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: 2px; padding: 0.4rem 0.6rem;
}
.recovery-help { margin: 1.2rem 0; }
.recovery-help summary { cursor: pointer; color: var(--color-ink-soft); font-size: 0.92rem; }

/* ---- Site analytics ---------------------------------------- */
.a-trend { width: 100%; height: auto; display: block; margin: 0.6rem 0 0.4rem; }
.a-legend { display: flex; gap: 1.1rem; flex-wrap: wrap; align-items: center;
            font-size: 0.85rem; color: var(--color-ink-soft); margin: 0 0 1.6rem; }
.a-legend i { display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: 2px;
              margin-right: 0.35rem; vertical-align: -1px; }
.sw-green { background: var(--color-green); }
.sw-brass { background: var(--color-brass); }
/* The club filter. ⚠️ NOT .club-switch — that one lives in the dark masthead and
   is painted for it (light text, translucent border). This sits on the page. */
.club-filter { display: flex; gap: 0.4rem; align-items: center; margin: 0 0 1.4rem; }
.club-filter select { width: auto; max-width: 18rem; min-height: 2.1rem;
                      font-size: 0.9rem; padding: 0.2rem 0.5rem; }
.club-filter button {
  font-size: 0.7rem; letter-spacing: 0.09em; text-transform: uppercase;
  padding: 0.3rem 0.8rem; min-height: 2.1rem; cursor: pointer;
  background: transparent; color: var(--color-ink-soft);
  border: 1px solid var(--color-rule); border-radius: 2px;
}
.club-filter button:hover { background: var(--color-rule); color: var(--color-ink); }

/* A path can be long and must stay readable; the counts beside it must not move. */
.a-path { word-break: break-all; font-size: 0.9rem; }
table.data.compact td.num, table.data.compact th:not(:first-child) { text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
