/* Split out of style.css when it passed ~700 lines during the
   design_handoff_clubhub_views redesign -- this file is page chrome
   (header/nav, club-page tabs), not general-purpose primitives. Tokens,
   base elements, forms, and buttons stay in style.css; cards/chips/
   tables/status-strip/segmented-control are in components.css. */

/* Site header / nav (views/partials/header.ejs) -- rebuilt again per
   design_handoff_clubhub_feedback/NAVIGATION.md, which merges what used to
   be two stacked strips (.site-header + .site-nav-row) into one bar. Body
   has margin:0 auto and its own side padding, so the header/nav rows use
   negative margins to bleed to the full viewport width for their own
   independent horizontal padding rather than sharing the reading column's
   gutter. */
.site-header-sticky {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--color-bg);
  margin: 0 calc(var(--space-3) * -1) var(--space-4);
}

.bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
}

.bar .brand {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: none;
  font-weight: 600;
  font-size: 1.0588rem;
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}

.site-logo {
  height: 20px;
  vertical-align: middle;
}

.bar-links {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* Links move between .bar-links and #nav-more-panel (public/js/nav.js) --
   this rule intentionally never hides anything itself; it's only a
   measurement aid so overflowing links don't visibly wrap mid-layout before
   JS relocates them on the very first paint. Without JS, .bar-links simply
   wraps to a second line (acceptable, spec-required degradation). */
.bar-links a {
  color: var(--color-text-secondary);
  text-decoration: none;
  white-space: nowrap;
  padding: 9px 2px;
}

.bar-links a:hover,
.bar-links a.is-current {
  color: var(--color-text);
}

.bar-links a.is-current {
  box-shadow: inset 0 -2px 0 var(--club-accent);
}

.header-link {
  color: var(--color-text-secondary);
  text-decoration: none;
  white-space: nowrap;
}

.header-link:hover {
  color: var(--color-text);
}

.header-link.is-current {
  color: var(--color-text);
}

/* The three dropdown menus (club switcher, More, Account) share one
   component: a plain <details>/<summary> so they open with no JS at all --
   public/js/nav.js only adds outside-click/Escape/close-siblings and the
   overflow calculation on top. */
.nav-menu {
  position: relative;
  flex: none;
}

.nav-menu > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.8824rem;
  color: var(--color-text);
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}

.nav-menu > summary::-webkit-details-marker {
  display: none;
}

.nav-menu > summary .icon {
  width: 12px;
  height: 12px;
}

.nav-menu[open] > summary {
  border-color: var(--action);
}

/* Explicit rather than relying on the bare [hidden] attribute -- .nav-menu
   carries its own `position` (and, via <details>, a UA default `display`),
   so a same-or-higher-specificity display rule elsewhere could otherwise
   beat [hidden]'s browser-default `display: none` (the same class of
   gotcha this app's history already tracks for [hidden] rows elsewhere). */
.nav-menu[hidden] {
  display: none;
}

.nav-menu-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 21;
  min-width: 200px;
  max-height: 60vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
}

.nav-menu-panel-right {
  left: auto;
  right: 0;
}

.nav-menu-panel a,
.nav-menu-panel button {
  display: block;
  width: 100%;
  padding: 10px 14px;
  border: none;
  background: none;
  color: var(--color-text);
  text-align: left;
  text-decoration: none;
  font: inherit;
  font-size: 0.8824rem;
  cursor: pointer;
}

.nav-menu-panel a:hover,
.nav-menu-panel button:hover {
  background: var(--surface-2);
}

.nav-menu-panel a.is-current {
  font-weight: 600;
  color: var(--color-text);
}

/* "All clubs" (partials/nav-club-menu.ejs) -- leaves the current club
   entirely, back to the homepage, so it's set off from the list of
   individual clubs below it with a divider rather than looking like just
   another item in that list. */
.nav-menu-all-clubs {
  border-bottom: 1px solid var(--border);
}

.nav-menu-panel button.is-danger {
  color: var(--danger);
}

.nav-menu-panel form {
  display: block;
}

.nav-menu-header {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 0.8824rem;
  color: var(--color-text-muted);
}

.nav-menu-header strong {
  display: block;
  color: var(--color-text);
  text-transform: capitalize;
}

/* "Preview as member" banner (views/partials/header.ejs) -- unchanged by
   the nav merge; it's a persistent state warning, not navigation, so it
   stays its own strip. */
.preview-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 8px 18px;
  background: var(--accent-tint-strong);
  border-bottom: 1px solid var(--club-accent);
  font-size: 0.8824rem;
  color: var(--color-text);
}

.preview-banner form {
  display: inline;
}

/* Mobile hamburger + full-height sheet, shown only under the 720px
   breakpoint below -- a real <button>/<nav> pair (not <details>), since a
   full-screen overlay has no <details>-only equivalent and needs JS to
   toggle either way (see public/js/nav.js and the NAVIGATION.md plan). */
.nav-hamburger {
  display: none;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: none;
  color: var(--color-text);
  cursor: pointer;
}

.nav-sheet {
  display: none;
}

.nav-sheet:not([hidden]) {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 25;
  overflow-y: auto;
  background: var(--color-bg);
}

.nav-sheet-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  min-height: 56px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}

.nav-sheet-header button {
  width: 48px;
  height: 48px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: none;
  color: var(--color-text);
  cursor: pointer;
}

.nav-sheet-row {
  display: flex;
  align-items: center;
  min-height: 56px;
  padding: 0 16px 0 21px;
  border-bottom: 1px solid var(--border);
  border-left: 5px solid transparent;
  color: var(--color-text);
  text-decoration: none;
  font-size: 1rem;
  text-align: left;
  background: none;
  width: 100%;
  cursor: pointer;
}

.nav-sheet-row.is-current {
  font-weight: 600;
  background: var(--action-tint);
  border-left-color: var(--action);
}

.nav-sheet-row.is-danger {
  color: var(--danger);
}

.nav-sheet-group-label {
  padding: 12px 16px 6px;
  font-size: 0.7647rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-faint);
}

.nav-menu-club-mobile {
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
}

.nav-menu-club-mobile > summary {
  width: 100%;
  min-height: 56px;
  justify-content: space-between;
}

.nav-menu-club-mobile .nav-menu-panel {
  position: static;
  margin-top: 6px;
  box-shadow: none;
}

@media (max-width: 720px) {
  .bar-links,
  .nav-menu-club,
  .nav-menu-more,
  .nav-menu-account,
  .bar > .header-link {
    display: none;
  }

  .nav-hamburger {
    display: flex;
  }
}

/* Club header -- now shared by every club-scoped page via
   partials/club-nav.ejs, not just the dashboard (views/club.ejs). */
.club-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 24px var(--space-3) 6px;
}

.club-header-link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: inherit;
  text-decoration: none;
}

.club-header h1 {
  /* No font-size/weight override -- inherit the global h1 rule (2rem,
     THEMES.md's explicit 34px target), same call as .narrow-form-page h1
     in components.css. */
  margin: 0;
  letter-spacing: -0.02em;
}

/* The club-switcher + account menu, relocated here (out of the generic top
   bar) whenever a club is in scope -- see partials/header.ejs. */
.club-header-nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
  flex: none;
}

@media (max-width: 720px) {
  .club-header-nav {
    display: none;
  }
}

/* Club page tabs (views/club.ejs, screen 2b) */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 16px var(--space-3) 0;
  border-bottom: 1px solid var(--border);
  margin: 0 0 var(--space-3);
  /* No overflow-x: auto here (Phase 3b removed it) -- a real bug, not a
     style choice: setting only overflow-x computes overflow-y to auto too
     (CSS's own "if one axis is visible and the other isn't, the visible one
     becomes auto" rule), which silently clipped the People/Manage dropdown
     panels below this row -- confirmed directly via elementFromPoint() at
     the open panel's own coordinates returning the page content behind it,
     not the panel. flex-wrap already handles the realistic overflow case
     (a long run of custom nav links on a narrow-but-still-desktop screen);
     this row is hidden entirely below 720px anyway (folds into the mobile
     sheet), so there's little room left for genuine horizontal overflow
     above that width in the first place. */
}

.tab-button {
  background: none;
  color: var(--color-text-muted);
  font-weight: 400;
  font-size: 0.9412rem;
  border: none;
  border-radius: 6px 6px 0 0;
  padding: var(--space-2) var(--space-3);
  white-space: nowrap;
  text-decoration: none;
  display: inline-block;
}

.tab-button:hover {
  filter: none;
  color: var(--accent-300);
  background: var(--surface-2);
}

.tab-button.active {
  color: var(--color-text);
  font-weight: 500;
  /* 4px, not 2px -- NAVIGATION.md's explicit "4px underline in the sections
     row" accessibility requirement (the current-state indicator can't rely
     on color alone). */
  box-shadow: inset 0 -4px 0 var(--club-accent);
}

.tab-button.active:hover {
  background: none;
}

/* The section tabs row (partials/club-nav.ejs, shared by every club-scoped
   page) folds into the mobile sheet's own grouped section list below 720px
   -- this row would otherwise be redundant with (and visually competing
   with) it. Placed after the unconditional .tabs rule above (same
   specificity) so source order lets it win under 720px. */
@media (max-width: 720px) {
  .tabs {
    display: none;
  }
}

/* Club bar: People/Manage grouped menus (design_handoff_admin_data_and_nav,
   Phase 3b). <details class="nav-menu tabs-nav-menu"> reuses the generic
   .nav-menu dropdown component (public/js/nav.js already handles its
   open/close/outside-click/Escape behavior for free) but needs to look like
   a .tab-button, not the top-bar's bordered dropdown button. */
.tabs-nav-menu {
  position: relative;
}

.tabs-nav-menu > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 0;
  padding: var(--space-2) var(--space-3);
  /* border: none (not just border-color) is what actually matters here --
     .nav-menu[open] > summary's border-color override (0,2,1) always beats
     this rule's border-color (0,1,1) once the group opens, regardless of
     source order. But border-style stays "none" from this rule alone (that
     open-state rule never touches border-style), so no border renders
     either way -- verified directly, not just reasoned about, since this
     app's history has hit real same-specificity cascade surprises before. */
  border: none;
  border-radius: 6px 6px 0 0;
  font-size: 0.9412rem;
  color: var(--color-text-muted);
}

.tabs-nav-menu > summary:hover {
  color: var(--accent-300);
  background: var(--surface-2);
}

.tabs-nav-menu.active > summary {
  color: var(--color-text);
  font-weight: 500;
  box-shadow: inset 0 -4px 0 var(--club-accent);
}

.tabs-nav-menu-current {
  font-weight: 400;
  color: var(--color-text-muted);
}

/* Manage is pushed to the far right, same trick this row's old Admin link
   used to use (margin-left: auto). */
.tabs-nav-menu-right {
  margin-left: auto;
}

/* "View public page" takes over the push-right, so Manage sits straight
   after it instead of the two splitting the free space between them. */
.tabs-public-link {
  margin-left: auto;
}

.tabs-public-link + .tabs-nav-menu-right {
  margin-left: 0;
}

.tabs-nav-menu .nav-menu-panel {
  min-width: 292px;
}

.nav-menu-group-header {
  padding: var(--space-2) 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: 0.8235rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* Higher specificity than the base ".nav-menu-panel a" rule (0,1,1) on
   purpose -- these rows need display:flex for the icon/label/trailing-count
   layout, and a same-or-lower-specificity override has lost this exact
   fight elsewhere in this app before. */
.nav-menu-panel a.nav-menu-panel-row {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 48px;
}

.nav-menu-panel-row .icon {
  width: 18px;
  height: 18px;
  color: var(--ink-dim);
  flex: none;
}

.nav-menu-panel-row.is-current .icon {
  color: var(--action);
}

.nav-menu-panel-row-count {
  margin-left: auto;
  font-size: 0.9412rem;
  color: var(--ink-dim);
}

.nav-sheet-row-trailing {
  margin-left: auto;
  font-size: 0.9412rem;
  color: var(--color-text-muted);
}

.nav-sheet-header-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Roster: list + detail panel (design_handoff_clubhub_feedback/TABLES.md).
   Two panes on desktop; below 720px they're never both visible at once --
   data-has-selection on the wrapper drives which one CSS hides. */
.roster-layout {
  display: grid;
  grid-template-columns: 1fr 330px;
  gap: var(--space-4);
  align-items: start;
}

/* Down to 3 columns (Name/Role/Dues), this table no longer needs
   components.css's ".table-scroll table { min-width: 480px }" (there to
   force a real scroll on wider multi-column tables instead of squeezing
   them thin) -- at 375px it would otherwise force a horizontal scroll
   this table doesn't need, same fix already applied to the feedback
   queue table. (0,2,0) to outrank ".table-scroll table" (0,1,1). */
#roster-table .table-scroll table {
  min-width: 0;
}

/* The whole row is a single "stretched link" -- the <a> lives in the Name
   cell only (so assistive tech announces one link per row, not three),
   and ::after stretches its hit target over the entire <tr>. Real <table>
   markup throughout (not the mockup's div-grid) so public/js/data-table.js
   -- hard-coded to table.tBodies[0].rows -- keeps working unchanged.
   Real bug, reported directly (iPhone, first tap on the search box above
   the table -- opened the LAST visible row's detail instead, every time):
   `position: relative` on a `<tr>` (display: table-row) doesn't reliably
   establish a containing block for an absolutely-positioned descendant in
   every browser -- a real, long-documented WebKit inconsistency. When it
   doesn't, every row's ::after escapes to the nearest ancestor that IS
   actually positioned (or the viewport, if none is), so every row's
   "stretched" hit area ends up stacked on top of each other AND the
   toolbar above the table -- and the last one in paint order wins every
   click in that whole shared area, which is exactly "the last visible row
   swallows taps on the search box." `transform` (any value, even a no-op)
   forces a real containing block per spec, far more consistently supported
   than bare `position: relative` on an internal table display type -- this
   fixes it regardless of the exact browser quirk, not just papers over the
   one symptom reported. */
.roster-row {
  position: relative;
  transform: translate(0);
  border-left: 5px solid transparent;
}

.roster-row.is-current {
  background: var(--action-tint);
  border-left-color: var(--action);
}

.roster-row-link {
  color: var(--color-text);
  text-decoration: none;
}

/* "today" / "3d" / "2w": short, so the fourth column costs little width.
   Below 720px it is dropped and the same words sit under the name instead:
   at the Largest text size four columns made the table scroll sideways. */
.roster-seen {
  color: var(--color-text-muted);
  white-space: nowrap;
}

.roster-seen-inline {
  display: none;
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

@media (max-width: 720px) {
  #roster-table .roster-seen {
    display: none;
  }

  .roster-seen-inline {
    display: block;
  }
}

.roster-row-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* The surveys list's title link -- same look as .roster-row-link, but
   deliberately WITHOUT its ::after stretched-row trick. That pseudo-element
   needs its <tr> to be a real containing block (.roster-row's own
   position: relative + transform fix, see the note above) -- the survey
   table's plain <tr> has neither, so reusing .roster-row-link outright
   here let the pseudo-element escape with no positioned ancestor in reach,
   covering the whole page and hijacking clicks on anything above the
   table (including "New survey") to whichever survey's edit link happened
   to render. Only the title was ever meant to be a link here, not the
   whole row, so the fix is a plain link, not adding the <tr> positioning
   this class assumes. */
.survey-row-link {
  color: var(--color-text);
  text-decoration: none;
}

.roster-detail-pane {
  background: var(--color-surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-4);
}

.roster-back-link {
  display: none;
  margin-bottom: var(--space-3);
}

.roster-detail-header {
  margin-bottom: var(--space-3);
}

.roster-detail-name {
  font-size: 1.1765rem;
  font-weight: 600;
  color: var(--color-text);
}

.roster-detail-dues {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  margin-bottom: var(--space-4);
}

.roster-detail-capabilities {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.roster-detail-siteadmin {
  border: var(--border-w) dashed var(--border-strong);
  border-radius: var(--radius);
  padding: var(--space-3);
  margin-bottom: var(--space-4);
}

.roster-detail-remove {
  margin-top: var(--space-2);
}

/* Account details (ROSTER-ADD-EDIT.md): club-admin tier, so a plain bordered
   section like .roster-detail-dues -- not the dashed fence
   .roster-detail-siteadmin uses, which is reserved for the one genuinely
   site-admin-only control. */
.roster-detail-account {
  display: grid;
  gap: var(--space-2);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3);
  margin-bottom: var(--space-4);
}

.roster-detail-account label {
  display: grid;
  gap: 4px;
  font-size: 0.8824rem;
  color: var(--color-text-muted);
}

/* Add-member panel (ROSTER-ADD-EDIT.md) -- same stacked-sections shape as
   the detail panel it sits beside. */
.roster-add-form {
  display: grid;
  gap: var(--space-3);
}

.roster-add-strip {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 10px 12px;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  font-size: 0.9412rem;
}

.roster-add-strip .icon {
  flex-shrink: 0;
  color: var(--club-accent);
}

.roster-add-dues {
  display: grid;
  gap: var(--space-2);
}

/* member-lookup.js toggles these branches via the `hidden` attribute, but
   an author-origin `display` rule always beats the browser's built-in
   `[hidden] { display: none }` UA rule regardless of specificity -- same
   class of bug this app has already hit with `tr[hidden]`/`.tabs`/
   `.nav-sheet`. Without this, both the "found" and "notfound" branches
   (and the found-only Dues panel) rendered visible from page load, before
   any lookup ever ran. */
[data-member-branch][hidden] {
  display: none;
}

@media (max-width: 720px) {
  .roster-layout {
    display: block;
  }

  .roster-layout[data-has-selection="true"] .roster-list-pane {
    display: none;
  }

  .roster-layout[data-has-selection="false"] .roster-detail-pane {
    display: none;
  }

  .roster-back-link {
    display: inline-block;
  }
}

/* Events list (TABLES.md): 3-column table (When/Event/Status), each row a
   single stretched link to its own edit page -- identical technique to the
   roster's .roster-row/.roster-row-link (above), under distinct class names
   so it doesn't collide with the Overview tab's unrelated .event-row*
   classes (the upcoming/past-events summary widget). Same transform fix as
   .roster-row, for the same reason -- see its comment. */
.events-table-row {
  position: relative;
  transform: translate(0);
}

.events-table-row-link {
  color: var(--color-text);
  text-decoration: none;
  font-weight: 600;
}

.events-table-row-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.events-table-sub {
  display: block;
  font-weight: 400;
  font-size: 0.8824rem;
  color: var(--color-text-muted);
}

/* Nav-links expand-row edit panel (TABLES.md rule 3: no live controls in a
   resting row -- shared by admin-clubs.ejs and club-admin.ejs via
   partials/nav-links-table.ejs). */
.nav-link-edit-fields {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  max-width: 420px;
}

/* Edit and Remove side by side in a resting row. Remove is a plain button,
   not a live field, so the row stays read-only; it asks before removing. */
.nav-link-row-actions {
  display: flex;
  gap: var(--space-1);
  align-items: center;
}
.nav-link-row-actions form {
  margin: 0;
}
/* Two columns, so the table fits the narrow Settings column without
   scrolling sideways (which used to hide the Actions column). The id-less
   selector needs .table-scroll to outrank .table-scroll table's 480px. */
.table-scroll table.nav-links-table {
  min-width: 0;
  width: 100%;
  /* Fixed layout: a long address wraps instead of widening the table. */
  table-layout: fixed;
}
.nav-links-table .nav-link-actions-col {
  width: 6.5rem;
  white-space: nowrap;
}
.nav-link-label {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}
.nav-link-url {
  margin-top: 2px;
  font-size: 0.8824rem;
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}
/* Table cells don't wrap by default; the link's name and address must. */
.nav-links-table td.nav-link-cell {
  white-space: normal;
}

/* Event create/edit page (TABLES.md, screen 11). One shared page for both,
   modeled on post-form.ejs's shell; .stacked supplies label/gap styling,
   this just widens the form past .stacked's 420px cap for the two-column
   row and the scoreboard grid. */
.event-form {
  max-width: 720px;
}

.event-form-back {
  display: inline-block;
  margin-bottom: var(--space-3);
}

.event-form-fieldset {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* <fieldset> defaults to min-width: min-content regardless of its own
     flex/grid context, which silently overflows a narrow parent once
     content (a placeholder, a label) can't shrink any further -- found at
     --text-scale: largest + 375px. min-width: 0 opts back into normal
     flex-shrink behavior. */
  min-width: 0;
}

.event-form-fieldset legend {
  padding: 0;
  margin-bottom: var(--space-1);
  font-size: 1.1176rem;
  font-weight: 700;
  color: var(--color-text);
}

.event-form-row-2 {
  display: grid;
  /* Plain "1fr" computes to minmax(auto, 1fr) -- a wide datetime-local
     input's intrinsic min-content width then forces the track past its
     fair share instead of shrinking, overflowing the viewport (found at
     --text-scale: largest + 375px). minmax(0, 1fr) opts back in to
     shrinking with the rest of the page. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-3);
}

/* Same underlying bug as .event-form-capacity above, one level up: the
   Starts/Location <label>s are themselves display:grid (form.stacked
   label, one implicit column, no explicit grid-template-columns) sitting
   inside this row's own grid track. An implicit column sizes to its
   content's own intrinsic width rather than the label's assigned track
   width, so each datetime-local/text input rendered wider than its own
   label and visually overlapped the field beside it -- confirmed via
   getBoundingClientRect() showing the Starts input's right edge past the
   Location label's left edge. Reported directly (fields "overlapping on
   desktop") after the earlier text-scale/mobile pass missed it, since
   that pass checked for page-level overflow, not two same-row fields
   overlapping each other without the row itself growing. */
.event-form-row-2 label {
  grid-template-columns: 100%;
}

@media (max-width: 560px) {
  .event-form-row-2 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Result / Public-signups: a dashed prompt row (closed) that becomes a
   bordered block with its own heading + destructive action (open). The
   heading/action live in a sibling div, not inside <summary>, since a
   native <summary> toggles on any click within it -- including a
   descendant button's -- which would both fire the button and collapse
   the section. */
/* Dashed (not-yet-open) vs solid (open) is the whole signal in low-vision,
   which has no tint to spare -- TABLES.md's own checklist calls this out
   explicitly, so it's a real border-style change, not just decoration. */
.event-section {
  border: var(--border-w) dashed var(--border-strong);
  border-radius: var(--radius);
  padding: var(--space-3);
}

.event-section[open] {
  border-style: solid;
  border-color: var(--border);
}

.event-section-summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  cursor: pointer;
  color: var(--color-text);
}

.event-section-summary::-webkit-details-marker {
  display: none;
}

.event-section-summary-title {
  flex: 1;
}

.event-section-summary-hint {
  font-size: 0.8235rem;
  color: var(--color-text-muted);
}

.event-section[open] > .event-section-summary {
  display: none;
}

.event-section-open-header {
  display: none;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-weight: 700;
  color: var(--color-text);
}

.event-section[open] > .event-section-open-header {
  display: flex;
}

.event-section-remove {
  background: none;
  border: none;
  padding: 0;
  color: var(--color-danger-hover);
  font-weight: 700;
  cursor: pointer;
}

.event-scoreboard {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 88px auto 88px minmax(0, 1fr);
  gap: var(--space-2);
  align-items: end;
}

/* Same fix as .event-form-row-2 label above: the Home/Away <label>s are
   themselves an unconstrained implicit grid column, so their text input
   rendered at its own intrinsic width and overlapped the score box next
   to it. */
.event-scoreboard label {
  grid-template-columns: 100%;
}

.event-scoreboard input[type="number"] {
  text-align: center;
  font-weight: 700;
}

.event-scoreboard-dash {
  font-weight: 700;
  color: var(--color-text-muted);
  padding-bottom: 11px;
}

@media (max-width: 560px) {
  .event-scoreboard {
    grid-template-columns: minmax(0, 1fr);
  }

  .event-scoreboard-dash {
    display: none;
  }
}

.event-form-signups-body {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
}

/* form.stacked label is display:grid (single implicit column) with no
   explicit track sizing -- an implicit "auto" column lets its content
   (the number input's own intrinsic width) dictate the track size instead
   of respecting this label's own 190px width, so the input rendered past
   its container and visually overlapped the signup-count text beside it
   (reported via production feedback). grid-template-columns: 100% forces
   the track to actually match the label's own width. */
.event-form-capacity {
  width: 190px;
  flex: none;
  display: grid;
  grid-template-columns: 100%;
}

.event-form-signup-count {
  flex: 1;
  min-width: 180px;
  padding-bottom: 11px;
  color: var(--color-text-muted);
}

.event-form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: var(--border-w) solid var(--border);
}

.event-form-actions-spacer {
  flex: 1;
}

/* Shared mobile-card transform for any table opting in via .data-table-cards
   alongside .data-table -- new tables only (events list, nav-links); the
   already-shipped roster/activity-log/feedback-queue tables are untouched.
   Keeps real <table>/<tr>/<td> markup (data-table.js needs table.tBodies[0]
   .rows) by turning them into block/flex layout under 720px instead of
   duplicating markup for a second layout. */
@media (max-width: 720px) {
  .data-table-cards .table-scroll table,
  .data-table-cards .table-scroll tbody,
  .data-table-cards .table-scroll tr {
    display: block;
    width: 100%;
    /* Defeats components.css's ".table-scroll table { min-width: 480px }",
       which would otherwise force horizontal overflow even after the
       display:block switch above. */
    min-width: 0;
  }

  .data-table-cards .table-scroll thead {
    display: none;
  }

  .data-table-cards .table-scroll tbody tr:not([data-detail-row]) {
    margin-bottom: var(--space-3);
    border: var(--border-w) solid var(--border);
    border-radius: var(--radius);
    padding: var(--space-2) var(--space-3);
  }

  .data-table-cards .table-scroll td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    box-shadow: none;
    border-bottom: 1px solid var(--border);
    white-space: normal;
  }

  .data-table-cards .table-scroll td:last-child {
    border-bottom: none;
  }

  .data-table-cards .table-scroll td[data-label]::before {
    content: attr(data-label);
    font-weight: 700;
    color: var(--color-text-faint);
    flex: none;
  }

  .data-table-cards .table-scroll td.data-table-card-heading {
    font-weight: 700;
    font-size: 1.05rem;
  }

  .data-table-cards .table-scroll td.data-table-card-heading::before {
    content: none;
  }

  /* The display:block above outranks the browser's own [hidden] rule, which
     left a closed edit row (nav links) open on a phone. */
  .data-table-cards .table-scroll tr[hidden] {
    display: none;
  }

  /* A nav link's name, chips and address stack, not sit side by side. */
  .data-table-cards .table-scroll td.nav-link-cell {
    display: block;
  }
}

/* Persistent footer (views/partials/footer.ejs) -- present on every
   authenticated page (the partial self-gates on currentUser, so it
   silently renders nothing on login/signup/the public event-RSVP page).
   The Feedback button is the feature's whole entry point. */
.site-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin: var(--space-5) calc(var(--space-3) * -1) 0;
  padding: var(--space-2) 18px;
  border-top: 1px solid var(--border);
  font-size: 0.8235rem;
  color: var(--color-text-faint);
}

/* The footer's link to /help sits beside the site name; the Feedback
   button stays at the far end. */
.site-footer-link {
  margin-right: auto;
  margin-left: var(--space-3);
}

/* Admin sidebar (design_handoff_admin_data_and_nav, Phase 3a) --
   partials/admin-sidebar.ejs. Each admin page wraps this + its own content
   in .admin-layout/.admin-content (see the pages themselves). */
.admin-layout {
  display: grid;
  grid-template-columns: 238px minmax(0, 1fr);
  gap: var(--space-5);
  margin: 0 calc(var(--space-3) * -1);
}

.admin-sidebar-details {
  border-right: var(--border-w) solid var(--border-strong);
}

.admin-sidebar-summary {
  display: none;
  cursor: pointer;
  list-style: none;
}

.admin-sidebar-summary::-webkit-details-marker {
  display: none;
}

.admin-sidebar {
  display: flex;
  flex-direction: column;
  background: var(--surface-2);
  padding: var(--space-3) 0 var(--space-5);
}

.admin-sidebar-label {
  padding: var(--space-2) var(--space-4) var(--space-2);
  font-size: 0.8235rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.admin-sidebar-label:not(:first-child) {
  margin-top: var(--space-2);
}

.admin-sidebar-row {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 48px;
  padding: var(--space-2) var(--space-4);
  color: var(--color-text);
  text-decoration: none;
  font-size: 1.0588rem;
}

.admin-sidebar-row .icon {
  width: 18px;
  height: 18px;
  color: var(--ink-dim);
  flex: none;
}

.admin-sidebar-row:hover {
  background: var(--surface-3);
}

.admin-sidebar-row.is-active {
  background: var(--bg);
  font-weight: 700;
  box-shadow: inset 4px 0 0 var(--action);
}

.admin-sidebar-row.is-active .icon {
  color: var(--action);
}

.admin-sidebar-count {
  margin-left: auto;
  font-size: 0.9412rem;
  color: var(--ink-dim);
}

.admin-content {
  min-width: 0;
  padding-right: var(--space-3);
}

@media (max-width: 860px) {
  .admin-layout {
    display: block;
    margin: 0;
  }

  .admin-sidebar-details {
    border-right: none;
    border-bottom: var(--border-w) solid var(--border-strong);
    margin-bottom: var(--space-4);
  }

  .admin-sidebar-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    min-height: 52px;
    padding: var(--space-3);
    margin-bottom: var(--space-3);
    background: var(--surface-2);
    border: var(--border-w) solid var(--border-strong);
    border-radius: var(--radius);
    font-weight: 700;
    font-size: 1.0588rem;
  }

  .admin-sidebar-summary .icon {
    color: var(--action);
  }

  .admin-sidebar-summary > .icon:last-child {
    margin-left: auto;
    color: var(--ink-dim);
    width: 13px;
    height: 13px;
  }

  .admin-sidebar-details[open] .admin-sidebar-summary > .icon:last-child {
    transform: rotate(180deg);
  }

  .admin-sidebar {
    background: none;
    padding: 0;
  }

  .admin-sidebar-row {
    min-height: 52px;
    border-bottom: 1px solid var(--border);
  }

  .admin-content {
    padding-right: 0;
  }
}

/* Survey builder (design_handoff_member_surveys, Phase 1) -- a rail +
   pane layout matching the admin sidebar's own measure and row styling
   (.admin-sidebar-row/-label/-count are reused directly, see
   views/partials/survey-builder-rail.ejs), driven by
   public/js/partial-panel.js rather than a <details> collapse -- question
   selection is a real URL (?q=), not a client-only toggle. */
.survey-builder-layout {
  display: grid;
  grid-template-columns: 238px minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}

.survey-builder-rail {
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius);
  overflow: hidden;
}

.survey-add-question-summary {
  cursor: pointer;
  list-style: none;
}

.survey-add-question-summary::-webkit-details-marker {
  display: none;
}

.survey-add-question-types {
  display: flex;
  flex-direction: column;
  border-top: var(--border-w) solid var(--border);
}

.survey-add-question-types form {
  display: contents;
}

.survey-add-question-types button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  box-sizing: border-box;
  padding: var(--space-2) var(--space-4) var(--space-2) calc(var(--space-4) + 18px);
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--color-text);
  font: inherit;
  font-size: 0.9412rem;
  text-align: left;
  cursor: pointer;
}

.survey-add-question-types button:hover {
  background: var(--surface-3);
}

.survey-add-question-types .icon {
  width: 16px;
  height: 16px;
  color: var(--ink-dim);
  flex: none;
}

.survey-builder-pane {
  min-width: 0;
}

.survey-locked-field {
  background: var(--surface-2);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3);
  color: var(--ink-muted);
}

.survey-locked-field .icon {
  width: 14px;
  height: 14px;
  color: var(--ink-dim);
  vertical-align: -2px;
}

/* A <details> used as a popover trigger elsewhere in the builder pane
   (Change type, Paste a list) styled as a plain button, not a native
   disclosure row -- suppress the marker triangle both browsers' ways. */
.survey-builder-pane details > summary.btn-outline-neutral {
  list-style: none;
  cursor: pointer;
}

.survey-builder-pane details > summary.btn-outline-neutral::-webkit-details-marker {
  display: none;
}

@media (max-width: 720px) {
  .survey-builder-layout {
    display: block;
  }

  [data-has-selection="false"] .survey-builder-pane {
    display: none;
  }

  [data-has-selection="true"] .survey-builder-rail {
    display: none;
  }
}

/* Member answering page (Phase 2) -- every answer control is >=52px tall
   with the whole row as the label/hit target, per the design doc, not a
   24px native radio/checkbox box. */
.survey-answer-option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 52px;
  padding: var(--space-3);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  margin-bottom: var(--space-2);
  cursor: pointer;
}

.survey-answer-option:has(input:checked) {
  background: var(--action-tint);
  border-color: var(--action);
  font-weight: 700;
}

.survey-answer-option input {
  flex: none;
}

.survey-rating-scale {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.survey-rating-scale-end {
  font-size: 0.85rem;
  color: var(--ink-dim);
  flex: none;
}

.survey-rating-squares {
  display: flex;
  gap: var(--space-2);
  flex: 1;
}

.survey-rating-square {
  flex: 1;
  min-height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  font-weight: 700;
  font-size: 1.2rem;
}

.survey-rating-square:has(input:checked) {
  background: var(--action);
  border-color: var(--action);
  color: var(--action-ink);
}

.survey-rating-square input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.survey-yesno {
  display: flex;
  gap: var(--space-3);
}

.survey-yesno label {
  flex: 1;
  min-height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  font-weight: 700;
}

.survey-yesno label:has(input:checked) {
  background: var(--action-tint);
  border-color: var(--action);
}

.survey-yesno input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.survey-recap-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}

.survey-recap-row:last-child {
  border-bottom: none;
}

.survey-question-error {
  border-color: var(--danger);
}

/* Date/Number questions: "two-up on desktop" reads as the input taking
   about half the panel's width (not stretching edge-to-edge like a text
   input), full width on mobile -- not a second field to pair with. */
.survey-answer-input-narrow {
  max-width: 50%;
}

@media (max-width: 560px) {
  .survey-answer-input-narrow {
    max-width: 100%;
  }
}

/* Survey results (Phase 3) -- plain CSS bars, no charting library (none
   exists in this app). A bordered track + a filled inset div, same
   "status is a bordered shape, never colour alone" rule the rest of the
   app's chips already follow. */
.survey-result-bar-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.survey-result-bar-label {
  flex: 0 0 160px;
  font-size: 0.9412rem;
  color: var(--ink);
}

.survey-result-bar-track {
  flex: 1;
  height: 20px;
  border-radius: var(--radius-sm);
  border: var(--border-w) solid var(--border);
  overflow: hidden;
  background: var(--surface);
}

.survey-result-bar-fill {
  height: 100%;
  background: var(--action-tint);
  border-right: var(--border-w) solid var(--action);
}

.survey-result-bar-count {
  flex: 0 0 auto;
  min-width: 64px;
  text-align: right;
  font-size: 0.9412rem;
  color: var(--ink-muted);
}

.survey-result-yesno-track {
  display: flex;
  height: 24px;
  border-radius: var(--radius-sm);
  border: var(--border-w) solid var(--border);
  overflow: hidden;
}

.survey-result-yesno-yes {
  background: var(--action-tint);
}

.survey-result-yesno-no {
  background: var(--surface-3);
}

/* Overview-tab survey cards (design_handoff_member_surveys, Phase 3) -- the
   only tinted block on the Overview tab is an open, unanswered survey's
   banner, "which is what earns it the slot" per the design doc. */
.survey-overview-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3);
  margin-bottom: var(--space-3);
  background: var(--action-tint);
  border: var(--border-w) solid var(--action);
  border-radius: var(--radius);
}

.survey-overview-banner-body {
  flex: 1;
  min-width: 220px;
}

.survey-participation-track {
  max-width: 320px;
  height: 14px;
  margin: var(--space-2) 0;
  border: 2px solid var(--ink);
  border-radius: 7px;
  overflow: hidden;
  background: var(--surface);
}

.survey-participation-fill {
  height: 100%;
  background: var(--action);
}

.survey-overview-quiet {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  margin-bottom: var(--space-2);
  font-size: 0.9412rem;
  color: var(--ink-muted);
}

.survey-overview-card {
  margin-bottom: var(--space-3);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}

.survey-overview-card-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--action-tint);
}

.survey-overview-card.is-shared .survey-overview-card-header {
  background: var(--surface-3);
}

.survey-overview-card-body {
  padding: var(--space-3);
}

.survey-overview-figure-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  font-size: 0.9412rem;
  color: var(--ink-muted);
  margin-bottom: var(--space-2);
}

.survey-overview-collapsed {
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3);
  margin-bottom: var(--space-3);
}
