/* ──────────────────────────────────────────────
   MonkeyGrade – Shared Styles
   Palette: sandstone orange + charcoal + off-white
   ────────────────────────────────────────────── */
:root {
  --primary:       #E8731A;
  --primary-dark:  #C85D0E;
  --primary-light: #FFF0E5;
  --dark:          #2B2D42;
  --mid:           #6B7280;
  --light:         #F7F4EF;
  --white:         #FFFFFF;
  --success:       #22C55E;
  --danger:        #EF4444;
  --border:        #DDD5C8;
  --shadow:        0 2px 10px rgba(0,0,0,.08);
  --radius:        12px;

  /* Dark "chrome" surface (header / side-nav / account menu / toast). Decoupled
     from --dark so dark mode can keep it dark while --dark flips to light text
     (#270). In light mode it follows the admin's --dark colour. */
  --chrome:        var(--dark);

  /* grade colours */
  --g1: #22C55E;   /* green  */
  --g2: #84CC16;   /* lime   */
  --g3: #EAB308;   /* yellow */
  --g4: #F97316;   /* orange */
  --g5: #EF4444;   /* red    */
  --g6: #B91C1C;   /* dark red */
  --g7: #7C3AED;   /* purple */
}

/* ── Dark mode (#270) ─────────────────────────────
   Remaps the NEUTRAL tokens (background / surface / text / borders / shadow)
   to a dark palette; the brand accent (--primary) is left untouched so per-gym
   theming still shows through. Applied when the user explicitly picks dark
   (html[data-theme="dark"]) OR when the OS prefers dark and the user hasn't
   forced light. Both selectors out-specify the plain `:root{…}` that the
   /style.css route appends for admin colours (so dark wins). The shared values
   live in --dk-* so the remap isn't duplicated. */
:root {
  /* Aligned with the mobile app's dark ColorScheme (app_theme.dart) so web +
     native dark look like one brand (#270). */
  --dk-bg:#14161b; --dk-surface:#20232d; --dk-text:#e7e8ee; --dk-mid:#9aa1ad;
  --dk-border:#2a2c38; --dk-shadow:0 2px 14px rgba(0,0,0,.55);
  --dk-primary-light:#2a1f16; --dk-chrome:#181a22;
}
:root[data-theme="dark"] {
  --light: var(--dk-bg);  --white: var(--dk-surface); --dark: var(--dk-text);
  --mid: var(--dk-mid);   --border: var(--dk-border); --shadow: var(--dk-shadow);
  --primary-light: var(--dk-primary-light); --chrome: var(--dk-chrome);
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --light: var(--dk-bg);  --white: var(--dk-surface); --dark: var(--dk-text);
    --mid: var(--dk-mid);   --border: var(--dk-border); --shadow: var(--dk-shadow);
    --primary-light: var(--dk-primary-light); --chrome: var(--dk-chrome);
    color-scheme: dark;
  }
}

/* ── Reset ───────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--light);
  color: var(--dark);
  min-height: 100vh;
  line-height: 1.5;
}

/* ── Header ──────────────────────────────────── */
.header {
  background: var(--chrome);
  color: #fff;
  padding: 14px 20px;
  display: flex;
  align-items: center;
  gap: 10px;
  position: sticky;
  top: 0;
  z-index: 10;
  box-shadow: 0 2px 8px rgba(0,0,0,.2);
}
.header .logo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  line-height: 1;
  flex-shrink: 0;
}
.header .logo-img { width: 24px; height: 24px; border-radius: 6px; display: block; }
.header .logo-name { font-size: 1.2rem; font-weight: 800; color: #fff; letter-spacing: .2px; }
/* Page title sits to the right of the brand, visually subordinate to it. */
.header h1    { font-size: 1.05rem; font-weight: 600; color: rgba(255,255,255,.92); }
.header .subtitle {
  font-size: .78rem;
  color: rgba(255,255,255,.55);
  margin-left: 2px;
}
.header-nav { margin-left: auto; display: flex; gap: 16px; }
.header-nav a {
  color: rgba(255,255,255,.65);
  text-decoration: none;
  font-size: .85rem;
  transition: color .2s;
}
.header-nav a:hover { color: #fff; }

/* ── Layout ──────────────────────────────────── */
.container {
  max-width: 760px;
  margin: 0 auto;
  padding: 24px 16px 60px;
}
/* Data-heavy pages (e.g. the boulder list) use more of a wide screen; forms
   stay at the narrow reading width. Narrow screens are unaffected (content
   already fills the width below this cap). */
.container.wide { max-width: 1200px; }

/* ── Cards ───────────────────────────────────── */
.card {
  background: var(--white);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: var(--shadow);
  margin-bottom: 20px;
}
.card-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--dark);
  margin-bottom: 18px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--primary);
  display: flex;
  align-items: center;
  gap: 8px;
}
.card-title .icon { font-size: 1.1rem; }

/* ── Forms ───────────────────────────────────── */
.form-group { margin-bottom: 16px; }
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

label {
  display: block;
  font-weight: 600;
  font-size: .85rem;
  margin-bottom: 5px;
  color: var(--dark);
}
label .req { color: var(--primary); margin-left: 2px; }

input[type=text],
input[type=number],
input[type=password],
input[type=date],
input[type=email],
select,
textarea {
  width: 100%;
  padding: 10px 13px;
  border: 2px solid var(--border);
  border-radius: 8px;
  font-size: .95rem;
  background: var(--white);
  color: var(--dark);
  transition: border-color .2s, box-shadow .2s;
  /* Normalise across browsers (Safari keeps its own look without this) */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  font-family: inherit;
  box-sizing: border-box;
}
/* Keep native calendar/spinner controls for date inputs */
input[type=date]::-webkit-calendar-picker-indicator {
  opacity: .6;
  cursor: pointer;
}
select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236B7280' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 36px;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(232,115,26,.15);
}
textarea { resize: vertical; min-height: 70px; }

.char-row {
  display: flex;
  justify-content: flex-end;
  margin-top: 3px;
}
.char-count {
  font-size: .75rem;
  color: var(--mid);
  transition: color .2s;
}
.char-count.warn  { color: #F97316; }
.char-count.limit { color: var(--danger); font-weight: 700; }

/* ── Buttons ─────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 11px 22px;
  border: none;
  border-radius: 8px;
  font-size: .95rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .2s, transform .15s, box-shadow .2s;
  text-decoration: none;
}
.btn:active { transform: scale(.97); }
/* Disabled buttons read clearly as unavailable (no hover/press effects). */
.btn:disabled, .btn[disabled] {
  opacity: .45;
  cursor: not-allowed;
  box-shadow: none;
  filter: grayscale(40%);
}
.btn:disabled:active { transform: none; }
.btn-primary:disabled:hover   { background: var(--primary); box-shadow: none; }
.btn-secondary:disabled:hover { background: transparent; color: var(--primary); }
.btn-ghost:disabled:hover     { border-color: var(--border); color: var(--mid); }
.btn-danger:disabled:hover    { background: var(--danger); }
.btn-primary {
  background: var(--primary);
  color: #fff;
  width: 100%;
}
.btn-primary:hover { background: var(--primary-dark); box-shadow: 0 4px 12px rgba(232,115,26,.35); }
.btn-sm {
  padding: 5px 12px;
  font-size: .8rem;
  border-radius: 6px;
}
.btn-danger  { background: var(--danger);  color: #fff; }
.btn-secondary { background: transparent; border: 2px solid var(--primary); color: var(--primary); }
.btn-secondary:hover { background: var(--primary); color: #fff; }
.btn-ghost   { background: transparent; border: 2px solid var(--border); color: var(--mid); }
.btn-ghost:hover { border-color: var(--primary); color: var(--primary); }
.btn-icon    { width: 36px; height: 36px; padding: 0; font-size: 1.05rem; flex-shrink: 0; }

/* ── Grade selector ──────────────────────────── */
.grade-selector {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.grade-btn {
  width: 50px;
  height: 50px;
  border: 2px solid var(--border);
  border-radius: 10px;
  font-size: 1.15rem;
  font-weight: 800;
  cursor: pointer;
  background: var(--white);
  color: var(--dark);
  transition: all .18s;
  position: relative;
}
.grade-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 10px rgba(0,0,0,.12); }
/* Dynamic grade buttons use --btn-grade-color set via inline style */
.grade-btn { --gc: var(--btn-grade-color, var(--primary)); }
.grade-btn.active {
  background: var(--gc);
  border-color: var(--gc);
  color: #fff;
  box-shadow: 0 4px 14px rgba(0,0,0,.2);
  transform: translateY(-2px) scale(1.06);
}
.grade-btn[data-g="3"].active { color: var(--dark); }  /* yellow contrast */

.grade-legend {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.grade-legend-item {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: .72rem;
  color: var(--mid);
}
.grade-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

/* ── Captcha ─────────────────────────────────── */
.captcha-box {
  background: var(--light);
  border: 2px dashed var(--border);
  border-radius: 10px;
  padding: 16px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.captcha-question {
  font-size: 1.4rem;
  font-weight: 800;
  color: var(--dark);
  min-width: 100px;
}
.captcha-input {
  width: 90px !important;
  text-align: center;
  font-size: 1.1rem !important;
  font-weight: 700 !important;
}
.captcha-refresh {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  color: var(--mid);
  transition: color .2s, transform .3s;
}
.captcha-refresh:hover { color: var(--primary); transform: rotate(180deg); }

/* ── Photo drop-zone (add boulder form) ─────── */
.photo-drop-zone {
  display: block;
  border: 2px dashed var(--border);
  border-radius: 10px;
  background: var(--light);
  cursor: pointer;
  overflow: hidden;
  transition: border-color .2s, background .2s;
  min-height: 110px;
  position: relative;
}
.photo-drop-zone:hover,
.photo-drop-zone.drag-over {
  border-color: var(--primary);
  background: var(--primary-light);
}
.photo-drop-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 24px 16px;
  text-align: center;
}
.photo-drop-icon { font-size: 1.8rem; }
.photo-drop-text { font-size: .83rem; color: var(--mid); }
.photo-preview {
  width: 100%;
  max-height: 220px;
  object-fit: cover;
  display: block;
  border-radius: 8px;
}

/* ── Alerts ──────────────────────────────────── */
.alert {
  padding: 12px 16px;
  border-radius: 8px;
  font-size: .88rem;
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  animation: fadeIn .3s ease;
}
.alert-success { background: #DCFCE7; color: #15803D; border: 1px solid #BBF7D0; }
.alert-error   { background: #FEE2E2; color: #991B1B; border: 1px solid #FECACA; }
@keyframes fadeIn { from { opacity:0; transform:translateY(-4px);} to {opacity:1; transform:translateY(0);} }

/* ── List controls (filter + sort) ──────────────── */
.list-controls {
  display: flex;
  flex-direction: column;   /* the always-visible bar, then the collapsible fields */
  align-items: stretch;
  gap: 10px;
  margin-bottom: 14px;
}
/* Always-visible bar: Filters toggle + one-line Sort. */
.lc-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.filters-toggle {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  padding: 8px 14px;
  border: 1.5px solid var(--border);
  border-radius: 10px;
  background: var(--white, #fff);
  color: var(--dark);
  cursor: pointer;
}
.filters-toggle:hover { border-color: var(--primary); }
.filters-toggle.open { border-color: var(--primary); color: var(--primary); }
.filters-count { color: var(--primary); font-weight: 700; }
.ft-caret { transition: transform .15s; font-size: .8rem; }
.filters-toggle.open .ft-caret { transform: rotate(180deg); }

/* Collapsible filter fields — wrap onto multiple lines (no horizontal scroll). */
.filter-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-bottom: 2px;
}
.filter-fields[hidden] { display: none; }
.filter-fields .filter-row { flex: 0 1 auto; }   /* each control may share a line / wrap */

/* Each control + its ✕ stays together (nowrap). */
.filter-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
}
.filter-select {
  padding: 6px 10px;
  padding-right: 30px;
  border: 2px solid var(--border);
  border-radius: 8px;
  font-size: .82rem;
  background: var(--white);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236B7280' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  color: var(--dark);
  cursor: pointer;
  min-width: 0;
  flex: 1;
  max-width: 220px;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  font-family: inherit;
}
.filter-select:focus { outline: none; border-color: var(--primary); }

/* ── #282 search + multi-criteria filters ───────────────────────────────── */
.lc-search {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1.5px solid var(--border);
  border-radius: 12px;
  background: var(--white, #fff);
  padding: 2px 10px;
}
.lc-search:focus-within { border-color: var(--primary); }
.lc-search-icon { font-size: .9rem; opacity: .7; }
.lc-search-input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: .9rem;
  color: var(--dark);
  padding: 9px 0;
}
.lc-search-clear,
.lc-search-input::-webkit-search-cancel-button { /* use our own ✕ */ }
.lc-search-clear {
  border: none;
  background: transparent;
  color: var(--mid);
  cursor: pointer;
  font-size: .85rem;
  padding: 4px 6px;
  border-radius: 6px;
}
.lc-search-clear:hover { color: var(--danger); }

/* Suggestion chips parsed from the typed phrase */
.search-suggest { display: flex; flex-wrap: wrap; gap: 8px; }
.search-suggest[hidden] { display: none; }
.suggest-chip {
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  padding: 5px 11px;
  border: 1.5px dashed var(--border);
  border-radius: 999px;
  background: var(--white, #fff);
  color: var(--dark);
  cursor: pointer;
}
.suggest-chip:hover { border-style: solid; border-color: var(--primary); color: var(--primary); }

/* Active-filter chips (removable) */
.active-filters { display: flex; flex-wrap: wrap; gap: 8px; }
.active-filters[hidden] { display: none; }
.afchip {
  font: inherit;
  font-size: .8rem;
  font-weight: 700;
  padding: 5px 11px;
  border: none;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  cursor: pointer;
}
.afchip:hover { filter: brightness(.94); }
.afchip-clear {
  background: transparent;
  color: var(--danger);
  border: 1.5px solid color-mix(in srgb, var(--danger) 40%, transparent);
}

/* Collapsible groups of multi-select chips */
.filter-groups { flex-direction: column; align-items: stretch; gap: 14px; }
.filter-group { display: flex; flex-direction: column; gap: 8px; }
.filter-group[hidden] { display: none; }
.fg-head { display: flex; align-items: center; gap: 10px; }
.fg-title {
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--mid);
}
.fg-modes { display: inline-flex; gap: 10px; margin-left: auto; }
.fg-mode {
  font: inherit;
  font-size: .75rem;
  font-weight: 700;
  border: none;
  background: transparent;
  color: var(--mid);
  cursor: pointer;
  padding: 0;
}
.fg-mode.active { color: var(--primary); text-decoration: underline; }
.fg-hint { font-size: .72rem; color: var(--mid); }
.fg-hint[hidden] { display: none; }
.fg-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.fchip {
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  padding: 6px 12px;
  border: 1.5px solid var(--border);
  border-radius: 999px;
  background: var(--white, #fff);
  color: var(--dark);
  cursor: pointer;
}
.fchip:hover { border-color: var(--primary); }
.fchip.on { background: var(--primary); border-color: var(--primary); color: #fff; }

/* ── Shared send-row presentation (My Sends + public profile, #18/#20) ── */
.send-row { border-bottom: 1px solid var(--border); margin: 0 -6px; }
.send-row:last-child { border-bottom: none; }
.send-main {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 6px; cursor: pointer; border-radius: 6px;
  transition: background .15s;
}
.send-main:hover { background: var(--light); }
.send-row-icon {
  width: 38px; height: 38px; border-radius: 6px; background: var(--light);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.2rem; flex-shrink: 0; border: 1px solid var(--border);
}
.send-row-info { flex: 1; min-width: 0; }
.send-row-title { font-weight: 600; font-size: .92rem; color: var(--dark); }
.send-row-sub { font-size: .78rem; color: var(--mid); margin-top: 2px; }
.send-row-meta { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 4px; }
.color-dot {
  width: 10px; height: 10px; border-radius: 50%; display: inline-block;
  margin-right: 4px; border: 1px solid rgba(0,0,0,.12); flex-shrink: 0;
}
.send-date-badge {
  font-size: .74rem; color: var(--mid); background: var(--light);
  border: 1px solid var(--border); border-radius: 10px; padding: 1px 8px; white-space: nowrap;
}
.send-note-preview { font-size: .78rem; color: var(--mid); font-style: italic; margin-top: 3px; }
.send-video-badge {
  font-size: .72rem; color: var(--mid); background: var(--light);
  border: 1px solid var(--border); border-radius: 10px; padding: 1px 7px; white-space: nowrap;
}
.archived-badge {
  font-size: .72rem; color: #92400e; background: #fef3c7;
  border: 1px solid #fde68a; border-radius: 10px; padding: 1px 7px; white-space: nowrap;
}
.send-row.is-archived .send-main { cursor: default; }
.send-row.is-archived .send-main:hover { background: none; }
.send-action-btn {
  background: none; border: none; cursor: pointer; font-size: .95rem; color: var(--mid);
  padding: 5px 7px; flex-shrink: 0; border-radius: 4px; transition: background .12s, color .12s;
  align-self: flex-start; line-height: 1; display: inline-flex; align-items: center;
}
.send-action-btn:hover { background: var(--border); color: var(--dark); }

/* ── In-page nav (member Settings, #18) — button-styled, matches the page CTAs ── */
.profile-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 0 0 18px;
}
.profile-tab {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  white-space: nowrap;
  padding: 8px 13px;
  border: 1.5px solid var(--border);
  border-radius: 9px;
  background: var(--white, #fff);
  color: var(--dark);
  text-decoration: none;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.profile-tab:hover { border-color: var(--primary); }
.profile-tab.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.filter-input {
  padding: 7px 12px;
  border: 2px solid var(--border);
  border-radius: 8px;
  font-size: .85rem;
  background: var(--white);
  color: var(--dark);
  min-width: 0;
  flex: 1;
  max-width: 320px;
  font-family: inherit;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .15s;
}
.filter-input:focus { outline: none; border-color: var(--primary); }
.filter-input::placeholder { color: var(--mid); }
.clear-filter-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 2px solid var(--border);
  border-radius: 50%;
  background: var(--white);
  color: var(--mid);
  font-size: .75rem;
  cursor: pointer;
  flex-shrink: 0;     /* never collapse or wrap */
  transition: border-color .15s, color .15s;
}
.clear-filter-btn:hover { border-color: var(--danger); color: var(--danger); }
/* Sort group: stays on ONE line (scrolls horizontally if ever too narrow). */
.sort-group {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  margin-left: auto;        /* push Sort to the right of the Filters toggle */
}
.sort-group::-webkit-scrollbar { display: none; }
.sort-label {
  font-size: .78rem;
  color: var(--mid);
  font-weight: 600;
  white-space: nowrap;
}
.sort-btn {
  padding: 5px 12px;
  border: 2px solid var(--border);
  border-radius: 20px;
  background: var(--white);
  color: var(--mid);
  font-size: .78rem;
  font-weight: 600;
  cursor: pointer;
  transition: all .15s;
  white-space: nowrap;
}
.sort-btn:hover { border-color: var(--primary); color: var(--primary); }
.sort-btn.active { background: var(--primary); border-color: var(--primary); color: #fff; }

/* ── Boulder table (home page overview) ─────────── */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.boulder-table { width: 100%; border-collapse: collapse; font-size: .88rem; min-width: 380px; }
.boulder-table th {
  background: var(--light);
  padding: 9px 12px;
  text-align: left;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--mid);
  font-weight: 700;
  white-space: nowrap;
}
.boulder-table td {
  padding: 11px 12px;
  border-top: 1px solid var(--border);
  vertical-align: middle;
}
.clickable-row { cursor: pointer; }
.clickable-row:hover td { background: var(--primary-light); }
.row-photo-icon {
  display: inline-block;
  font-size: .85rem;
  margin-left: 6px;
  opacity: .55;
  cursor: pointer;
  vertical-align: middle;
  transition: opacity .15s, transform .15s;
}
.row-photo-icon:hover { opacity: 1; transform: scale(1.2); }
/* ── Back-to-top button ──────────────────────── */
.back-to-top {
  position: fixed;
  bottom: 24px;
  right: 20px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  border: none;
  font-size: 1.2rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
  opacity: 0;
  pointer-events: none;
  transform: translateY(10px);
  transition: opacity .25s, transform .25s;
  z-index: 90;
}
.back-to-top.visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
/* The mobile "More" sheet (z-index 61) must sit above the back-to-top button —
   hide the button whenever the sheet is open so it can't overlap it. */
body.pub-more-open .back-to-top {
  opacity: 0 !important;
  pointer-events: none !important;
}

/* ── Infinite-scroll sentinel ────────────────── */
.scroll-sentinel {
  text-align: center;
  padding: 14px 0 4px;
  font-size: .8rem;
  color: var(--mid);
  font-style: italic;
}

/* ── Mobile-only hint (hidden on wider screens) ── */
.mobile-hint {
  display: none;
  font-size: .75rem;
  color: var(--mid);
  font-style: italic;
  margin: -10px 0 12px;
}
@media (max-width: 480px) {
  /* Portrait reflow: each boulder is a tidy 2-row card showing ALL data
     (location, Set, Avg, Votes) — no "rotate to landscape". A FIXED-width left
     column keeps every row's columns aligned; the colour pill collapses to its
     dot so it fits. */
  .mobile-hint                    { display: none; }
  /* Tight viewport: drop the "Sort:" label so the sort buttons stay one line. */
  .sort-label                     { display: none; }
  .boulder-table                  { min-width: 0; width: 100%; }
  .boulder-table thead            { display: none; }
  .boulder-table, .boulder-table tbody { display: block; width: 100%; }
  .boulder-table tr {
    display: grid;
    grid-template-columns: 58px 1fr auto;          /* fixed left col → aligned rows */
    grid-template-areas: "id loc avg" "id set votes";
    column-gap: 12px; row-gap: 2px; align-items: center;
    padding: 11px 2px; border-bottom: 1px solid var(--border);
  }
  .boulder-table td               { display: block; border: none !important; padding: 0; min-width: 0; }
  .boulder-table td:first-child   { grid-area: id; align-self: center; display: flex; flex-wrap: wrap;
                                     align-items: center; gap: 4px; font-weight: 800; }
  .boulder-table td:first-child strong { display: block; width: 100%; font-size: 1rem; }
  /* Colour pill → just the dot (name hidden) so the left column stays narrow */
  .boulder-table .color-chip      { font-size: 0; gap: 0; margin: 0; padding: 0;
                                     border: none; background: transparent; }
  .boulder-table .row-photo-icon,
  .boulder-table .row-video-icon  { font-size: .8rem; margin: 0; }
  .boulder-table .col-location    { grid-area: loc; font-weight: 600; align-self: center;
                                     overflow-wrap: break-word; word-break: break-word; }
  .boulder-table td:nth-child(4)  { grid-area: avg; justify-self: end; align-self: center; }  /* Avg badge */
  .boulder-table .col-set         { grid-area: set; font-size: .76rem; color: var(--mid); }
  .boulder-table .col-set::before { content: "Set "; }
  .boulder-table .col-votes       { grid-area: votes; justify-self: end; font-size: .74rem; color: var(--mid); white-space: nowrap; }
  .boulder-table .special-note    { display: block; white-space: normal; margin: 3px 0 0; font-size: .8rem; }
}

/* ── Boulder cards (admin list) ───────────────── */
.boulder-cards { display: flex; flex-direction: column; gap: 10px; }
.boulder-card {
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--light);
  transition: border-color .2s;
}
.boulder-card:hover  { border-color: var(--primary); }
.bc-body             { display: flex; flex-direction: column; gap: 8px; }
.bc-top-row          { display: flex; align-items: flex-start;
                       justify-content: space-between; gap: 10px; }
.bc-top-row > div:first-child { min-width: 0; flex: 1; }
.bc-actions          { display: flex; gap: 8px; flex-shrink: 0; flex-wrap: wrap;
                       justify-content: flex-end; }
.bc-num              { font-size: 1.1rem; font-weight: 800; color: var(--dark); margin-bottom: 2px; }
.bc-loc              { font-size: .88rem; color: var(--mid);
                       white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
                       max-width: 180px; }
.bc-meta             { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.bc-img-wrap         { margin-top: 4px; }
.bc-thumb            { width: 100%; max-height: 200px; object-fit: cover;
                       border-radius: 8px; cursor: zoom-in;
                       transition: opacity .2s; }
.bc-thumb:hover      { opacity: .88; }

/* Upload label styled as a button */
.upload-label        { cursor: pointer; }
.upload-label input  { display: none; }

/* ── Boulder photo on grade page ──────────────── */
.boulder-photo {
  width: 100%;
  max-height: 280px;
  object-fit: cover;
  border-radius: 10px;
  cursor: zoom-in;
  transition: opacity .2s;
  display: block;
}
.boulder-photo:hover { opacity: .88; }

/* ── Grade badge (small pill) ────────────────── */
.g-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 7px;
  font-weight: 800;
  font-size: .85rem;
  color: #fff;
}
.g1 { background: var(--g1); }
.g2 { background: var(--g2); }
.g3 { background: var(--g3); color: var(--dark); }
.g4 { background: var(--g4); }
.g5 { background: var(--g5); }
.g6 { background: var(--g6); }
.g7 { background: var(--g7); }

/* ── Stats row ───────────────────────────────── */
.stats-row {
  display: flex;
  gap: 28px;
  padding: 14px 0 6px;
  flex-wrap: wrap;
}
.stat { text-align: center; }
.stat-value { font-size: 1.9rem; font-weight: 800; color: var(--primary); line-height: 1; }
.stat-label { font-size: .7rem; color: var(--mid); text-transform: uppercase; letter-spacing: .06em; margin-top: 2px; }

/* ── Distribution bar ────────────────────────── */
.dist-bar   { display: flex; gap: 5px; margin: 12px 0 4px; }
.dist-col   { display: flex; flex-direction: column; align-items: center; gap: 3px; flex: 1; }
.dist-track { display: flex; align-items: flex-end; width: 100%; height: 56px; }
.dist-fill  { width: 100%; border-radius: 4px 4px 0 0; min-height: 3px; transition: height .4s ease; }
.dist-label { font-size: .7rem; color: var(--mid); font-weight: 700; }

/* ── Grade comments list ─────────────────────── */
.grade-list { display: flex; flex-direction: column; gap: 8px; }
.grade-item { display: flex; align-items: flex-start; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.grade-item:last-child { border-bottom: none; }
.grade-item-name    { font-size: .82rem; font-weight: 600; color: var(--dark); }
.grade-item-comment { font-size: .85rem; color: var(--mid); font-style: italic; }
.grade-item-time    { font-size: .72rem; color: #B0A898; margin-top: 2px; }
.grade-moderated    { font-size: .82rem; color: #B0A898; font-style: italic; }
.btn-moderate {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  font-size: .9rem;
  opacity: .35;
  padding: 2px 4px;
  border-radius: 4px;
  transition: opacity .15s;
  align-self: center;
}
.btn-moderate:hover { opacity: 1; }

/* ── Empty state ─────────────────────────────── */
.empty { text-align: center; padding: 36px 20px; color: var(--mid); }
.empty .empty-icon { font-size: 2.8rem; margin-bottom: 10px; }
.empty p { font-size: .9rem; }

/* ── Home page ───────────────────────────────── */
.hero { text-align: center; padding: 24px 20px 20px; }
.action-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  max-width: 560px;
  margin: 0 auto;
}
.action-cards-solo {
  grid-template-columns: 1fr;
  max-width: 300px;
}
.action-card-compact {
  flex-direction: row;
  padding: 14px 20px;
  gap: 12px;
  justify-content: center;
  text-align: left;
}
.action-card-compact .ac-icon {
  font-size: 1.5rem;
  margin-bottom: 0;
  flex-shrink: 0;
}
.action-card-compact h3 { margin-bottom: 0; }
.action-card {
  background: var(--white);
  border-radius: var(--radius);
  padding: 28px 20px;
  text-align: center;
  text-decoration: none;
  color: var(--dark);
  box-shadow: var(--shadow);
  transition: all .2s;
  border: 2px solid transparent;
}
.action-card:hover { border-color: var(--primary); transform: translateY(-4px); box-shadow: 0 8px 22px rgba(0,0,0,.12); }
.action-card .ac-icon { font-size: 2.4rem; margin-bottom: 10px; }
.action-card h3 { font-size: 1rem; margin-bottom: 6px; font-weight: 700; }
.action-card p  { font-size: .8rem; color: var(--mid); }

/* ── Admin tiles ─────────────────────────────── */
.admin-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

/* ── Settings page section nav ───────────────── */
/* Sticky wrapper: keeps header + admin nav together at all viewport sizes */
.admin-sticky-bar {
  position: sticky;
  top: 0;
  z-index: 10;
}
.admin-sticky-bar .header {
  position: static;
  box-shadow: none;
}
.settings-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin-bottom: 0;
  background: var(--white);
  padding: 8px 16px;
  box-shadow: 0 2px 6px rgba(0,0,0,.15);
}
.settings-nav::-webkit-scrollbar { display: none; }
.nav-group-label {
  font-size: .7rem;
  font-weight: 700;
  color: var(--mid);
  text-transform: uppercase;
  letter-spacing: .06em;
  white-space: nowrap;
  padding: 4px 4px 4px 0;
  user-select: none;
  flex-shrink: 0;
}
.nav-group-sep {
  width: 1px;
  height: 18px;
  background: var(--border);
  flex-shrink: 0;
  margin: 0 8px;
}
.settings-nav-link {
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  border-radius: 6px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--mid);
  text-decoration: none;
  transition: background .15s, color .15s;
  white-space: nowrap;
  flex-shrink: 0;
}
.settings-nav-link:hover,
.settings-nav-link.active { background: var(--primary); color: #fff; }

.settings-section { scroll-margin-top: 130px; } /* corrected dynamically by JS */
.admin-tile {
  background: var(--white);
  border-radius: var(--radius);
  padding: 24px 18px;
  text-align: center;
  text-decoration: none;
  color: var(--dark);
  box-shadow: var(--shadow);
  border: 2px solid transparent;
  transition: border-color .2s, transform .2s, box-shadow .2s;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.admin-tile:hover {
  border-color: var(--primary);
  transform: translateY(-4px);
  box-shadow: 0 8px 22px rgba(0,0,0,.12);
}
.admin-tile-icon  { font-size: 2rem; }
.admin-tile-title { font-size: .95rem; font-weight: 700; }
.admin-tile-desc  { font-size: .78rem; color: var(--mid); line-height: 1.4; }

/* ── Admin sub-page header back link ─────────── */
.header-back {
  color: rgba(255,255,255,.7);
  text-decoration: none;
  font-size: .85rem;
  white-space: nowrap;
  transition: color .2s;
  flex-shrink: 0;
}
.header-back:hover { color: #fff; }

/* ── Manage rows (walls & setters pages) ─────── */
.manage-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.manage-row:last-child { border-bottom: none; }
.manage-row-name  { flex: 1; font-weight: 600; font-size: .93rem; min-width: 100px; }
.manage-row-input { flex: 1; min-width: 100px; }
.manage-row-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* ── Setter inline-add (create boulder page) ─── */
.setter-inline-toggle {
  background: none;
  border: none;
  color: var(--primary);
  font-size: .82rem;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 0;
  margin-top: 6px;
  display: block;
}
.setter-inline-toggle:hover { text-decoration: underline; }
.setter-inline-add {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 10px 12px;
  background: var(--light);
  border: 1px solid var(--border);
  border-radius: 8px;
  flex-wrap: wrap;
}
.setter-inline-add input { flex: 1; min-width: 140px; }

/* ── Boulder color chip ──────────────────────── */
.color-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: .72rem;
  font-weight: 600;
  color: var(--dark);
  background: var(--white);
  border: 1.5px solid var(--border);
  border-radius: 20px;
  padding: 1px 8px 1px 5px;
  margin-left: 6px;
  vertical-align: middle;
  white-space: nowrap;
}
.color-chip::before {
  content: '';
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--chip-color, #9CA3AF);
  border: 1px solid rgba(0,0,0,.12);
  flex-shrink: 0;
}

/* ── Status badge (admin toggles) ────────────── */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 600;
  font-size: .88rem;
  padding: 4px 10px;
  border-radius: 14px;
  background: var(--light);
}

/* ── Spray Wall ─────────────────────────────── */
.spray-picker-container {
  --zoom:  1;
  --pan-x: 0px;
  --pan-y: 0px;
  position: relative;
  display: block;
  width: 100%;
  cursor: crosshair;
  border-radius: 8px;
  overflow: hidden;
  border: 2px solid var(--border);
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}
.spray-picker-container.pannable    { cursor: grab; }
.spray-picker-container.panning,
.spray-picker-container.panning *   { cursor: grabbing !important; }
/* Inner frame – owns the image + overlay so they always have matching dims.
   In the picker we also use it as the zoom/pan transform target. */
.spray-picker-frame {
  position: relative;
  display: block;
  line-height: 0;
  transform: translate(var(--pan-x, 0px), var(--pan-y, 0px)) scale(var(--zoom, 1));
  transform-origin: center;
  transition: transform .12s ease-out;
}
.spray-picker-container.panning .spray-picker-frame { transition: none; }
/* Dots scale inversely so they stay readable when zoomed in or out */
.spray-picker-container .spray-dot {
  transform: translate(-50%, -50%)
             scale(clamp(.5, calc(.5 + .5 / var(--zoom, 1)), 1.8));
}
.spray-picker-img {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
}
.spray-holds-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Gym-map SVG overlay (admin editor + visitor view) — sits on top of the
   image inside .spray-picker-frame, sized to the frame via inset:0. */
.gym-map-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.gym-map-overlay * { pointer-events: auto; }

/* Segmented Wall areas / Boulders toggle on the visitor gym-map page (#212).
   Mutually-exclusive views: the highlighted button is the active layer. */
.map-view-toggle {
  display: inline-flex;
  /* Solid surface so the toggle stays legible over a light OR dark map image
     (it floats on the map; a transparent background made it unreadable). */
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 20px;
  overflow: hidden;
  flex-shrink: 0;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .22);
}
.map-view-toggle button {
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px 14px;
  font-size: .85rem;
  font-weight: 600;
  color: var(--mid);
  white-space: nowrap;
}
.map-view-toggle button.on { background: var(--primary); color: #fff; }

/* Level switcher on the visitor gym-map page (#159) — multi-floor gyms only.
   Shares the segmented look of the walls/boulders toggle; wraps to a second row
   when a gym has many levels. Hidden entirely for single-level gyms. */
.map-level-switch {
  display: inline-flex;
  flex-wrap: wrap;
  /* Same solid surface as the walls/boulders toggle — both float on the map. */
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .22);
}
.map-level-switch button {
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px 14px;
  font-size: .85rem;
  font-weight: 600;
  color: var(--mid);
  white-space: nowrap;
  border-left: 1px solid var(--border);
}
.map-level-switch button:first-child { border-left: none; }
.map-level-switch button.on { background: var(--primary); color: #fff; }

/* Walls grid on the visitor gym-map page */
.walls-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px;
}
.wall-card {
  background: var(--light);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px;
  text-align: center;
  cursor: pointer;
  text-decoration: none;
  color: var(--dark);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  transition: transform .15s, border-color .15s, box-shadow .15s;
}
.wall-card:hover {
  transform: translateY(-2px);
  border-color: var(--primary);
  box-shadow: 0 4px 12px rgba(232,115,26,.18);
}
.wall-card-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: 6px;
  object-fit: cover;
  background: #ECE6DA;
}
.wall-card-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  color: var(--mid);
}
.wall-card-name {
  font-size: .88rem;
  font-weight: 600;
  line-height: 1.2;
  padding: 2px 4px 4px;
}

/* Floating fullscreen-toggle button (top-right corner of image) */
.spray-fs-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 38px;
  height: 38px;
  border-radius: 8px;
  border: none;
  background: rgba(0,0,0,.55);
  color: #fff;
  cursor: pointer;
  font-size: 1.15rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  font-family: inherit;
  transition: background .15s;
}
.spray-fs-btn:hover { background: rgba(0,0,0,.85); }

/* Toolbar inside fullscreen — hidden in normal mode */
.spray-fs-toolbar { display: none; }

/* ── Fullscreen mode ── */
.spray-picker-container.fullscreen {
  position: fixed;
  inset: 0;
  z-index: 200;
  width: 100vw;
  height: 100vh;
  background: rgba(0,0,0,.95);
  border: none;
  border-radius: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.spray-picker-container.fullscreen .spray-picker-frame {
  display: inline-block;
  max-width: 100vw;
  max-height: 100vh;
}
.spray-picker-container.fullscreen .spray-picker-img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100vw;
  max-height: 100vh;
}
/* Hide the enter-fullscreen button while in fullscreen */
.spray-picker-container.fullscreen .spray-fs-btn { display: none; }
/* Show the fullscreen toolbar */
.spray-picker-container.fullscreen .spray-fs-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  position: absolute;
  /* Clear the iOS status bar / notch in PWA standalone fullscreen (#125, #126) */
  top: calc(12px + env(safe-area-inset-top));
  left: calc(12px + env(safe-area-inset-left));
  right: calc(12px + env(safe-area-inset-right));
  padding: 8px 10px;
  background: rgba(255,255,255,.95);
  border-radius: 10px;
  box-shadow: 0 4px 14px rgba(0,0,0,.4);
  z-index: 1;
  flex-wrap: wrap;
}
.spray-dot {
  position: absolute;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,.9);
  transform: translate(-50%, -50%);
  pointer-events: all;
  cursor: pointer;
  box-shadow: 0 1px 5px rgba(0,0,0,.55);
  transition: transform .1s;
}
.spray-dot:hover { transform: translate(-50%,-50%) scale(1.3); }
.spray-dot-start { background: #22C55E; }
.spray-dot-feet  { background: #60A5FA; }
.spray-dot-hand  { background: #F59E0B; }
.spray-dot-top   { background: #EF4444; }
/* All dots are slightly transparent so the hold underneath shows through —
   in the picker, hovering returns the dot to full opacity for confirmation. */
.spray-dot { opacity: .72; }
.spray-picker-container .spray-dot:hover { opacity: 1; }
/* Smaller dots for list thumbnails and lightbox view */
.spray-dot-sm {
  width: 12px;
  height: 12px;
  border-width: 1.5px;
  pointer-events: none;
  cursor: default;
}
.spray-dot-sm:hover { transform: translate(-50%,-50%); }

/* Hold type selector buttons */
.hold-type-btns {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.hold-type-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border-radius: 20px;
  border: 2px solid var(--border);
  font-size: .88rem;
  font-weight: 600;
  cursor: pointer;
  background: var(--light);
  color: var(--dark);
  transition: border-color .15s, color .15s, background .15s;
  font-family: inherit;
  -webkit-appearance: none;
  appearance: none;
}
.hold-type-btn .hold-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1.5px solid rgba(0,0,0,.1);
}
.hold-type-btn[data-type="start"] .hold-dot { background: #22C55E; }
.hold-type-btn[data-type="feet"]  .hold-dot { background: #60A5FA; }
.hold-type-btn[data-type="hand"]  .hold-dot { background: #F59E0B; }
.hold-type-btn[data-type="top"]   .hold-dot { background: #EF4444; }
.hold-type-btn[data-type="start"].active { color: #16A34A; border-color: #22C55E; background: #F0FDF4; }
.hold-type-btn[data-type="feet"].active  { color: #2563EB; border-color: #60A5FA; background: #EFF6FF; }
.hold-type-btn[data-type="hand"].active  { color: #D97706; border-color: #F59E0B; background: #FFFBEB; }
.hold-type-btn[data-type="top"].active   { color: #DC2626; border-color: #EF4444; background: #FEF2F2; }

/* Hold summary row */
.hold-summary {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: .82rem;
  color: var(--mid);
  margin: 10px 0 4px;
}
.hold-summary-item { display: flex; align-items: center; gap: 5px; }
.hold-summary-dot  { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }

/* Toggle row (checkbox with label, used in the spray boulder form) */
.toggle-row {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  user-select: none;
}
.toggle-row input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--primary);
  flex-shrink: 0;
  cursor: pointer;
}
.toggle-row .toggle-text { font-weight: 500; }
.toggle-row .toggle-hint { font-size: .78rem; color: var(--mid); margin-left: 4px; }

/* "Feet follow hands" badge — focusable, shows tooltip on hover/tap */
.ffh-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1.5px solid #60A5FA;
  background: #EFF6FF;
  border-radius: 50%;
  font-size: .95rem;
  cursor: pointer;
  padding: 0;
  font-family: inherit;
  line-height: 1;
  -webkit-appearance: none;
  appearance: none;
}
.ffh-badge:hover,
.ffh-badge:focus {
  background: #DBEAFE;
  outline: 2px solid #60A5FA;
  outline-offset: 1px;
}
.ffh-badge::after {
  content: 'Feet follow hands';
  position: absolute;
  bottom: 130%;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0,0,0,.92);
  color: #fff;
  padding: 4px 9px;
  border-radius: 5px;
  font-size: .72rem;
  font-weight: 500;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s;
  z-index: 10;
}
.ffh-badge:hover::after,
.ffh-badge:focus::after { opacity: 1; }

/* Colour legend (shown above the active boulder list + in the lightbox) */
.spray-legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: .85rem;
  font-weight: 500;
  align-items: center;
  padding: 8px 12px;
  background: var(--light);
  border-radius: 8px;
  margin-bottom: 12px;
}
.spray-legend-label {
  font-size: .78rem;
  color: var(--mid);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-right: 2px;
}
.spray-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.spray-legend-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
  border: 1.5px solid rgba(255,255,255,.95);
  box-shadow: 0 0 0 1px rgba(0,0,0,.18);
}

/* ── Style-icon legend (collapsible, collapsed by default) ──
   Shared by the Spray Wall + My Stats pages: maps each style icon to its name.
   Built dynamically from /api/boulder-styles. Uses the native <details>/<summary>
   disclosure so it's keyboard-accessible with no JS toggle. */
.style-legend {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--light);
  margin-bottom: 12px;
  font-size: .85rem;
}
.style-legend > summary {
  cursor: pointer;
  list-style: none;
  padding: 8px 12px;
  font-size: .78rem;
  font-weight: 600;
  color: var(--mid);
  text-transform: uppercase;
  letter-spacing: .04em;
  display: flex;
  align-items: center;
  gap: 6px;
}
.style-legend > summary::-webkit-details-marker { display: none; }
.style-legend > summary::before {
  content: "▸";
  font-size: .8rem;
  transition: transform .15s ease;
}
.style-legend[open] > summary::before { transform: rotate(90deg); }
.style-legend-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding: 2px 12px 12px;
}
.style-legend-grid .style-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--dark);
  font-weight: 500;
}
.style-legend-grid .style-legend-item .ic { font-size: 1.05rem; }

/* Row holding a primary action on the left and the style-icon legend button on
   the right (spray wall Create row + boulder-list control bar). */
.list-head-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.list-head-row .style-legend.legend-pop { margin-left: auto; }

/* Compact, button-styled style-icon legend that opens as a dropdown popover.
   A modifier on .style-legend so the member-stats inline box is untouched. */
.style-legend.legend-pop { position: relative; border: none; background: none; margin: 0; flex-shrink: 0; }
.style-legend.legend-pop > summary {
  border: 1.5px solid var(--border);
  border-radius: 10px;
  background: var(--white, #fff);
  color: var(--dark);
  padding: 8px 14px;
  white-space: nowrap;
}
.style-legend.legend-pop > summary:hover { border-color: var(--primary); }
.style-legend.legend-pop[open] > summary { border-color: var(--primary); color: var(--primary); }
/* Belt-and-braces: keep the panel hidden while closed (some browsers render a
   child with an explicit `display` even on a closed <details>). */
.style-legend.legend-pop:not([open]) > .style-legend-grid { display: none; }
.style-legend.legend-pop > .style-legend-grid {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 40;
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 8px;
  min-width: 170px;
  max-width: 280px;
  max-height: 60vh;
  overflow: auto;
  padding: 12px 14px;
  background: var(--white, #fff);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(0,0,0,.14);
}

/* Lightbox – fullscreen image area + caption strip at the bottom */
#lightbox { --zoom: 1; --pan-x: 0px; --pan-y: 0px; }

.lightbox-img-area {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  position: relative;
  overflow: hidden;
  cursor: zoom-out;
  touch-action: none;
}
/* When zoomed in, the area becomes pan-able */
.lightbox-img-area.pannable    { cursor: grab; }
.lightbox-img-area.panning,
.lightbox-img-area.panning *   { cursor: grabbing !important; }

.lightbox-img-frame {
  position: relative;
  display: block;
  line-height: 0;
  max-width: 100%;
  max-height: 100%;
  /* aspect-ratio is set from JS once the image is loaded (#lightbox.--img-aspect),
     which lets the frame size to the image's true ratio while honouring
     max-width / max-height — no circular sizing dependency. */
  aspect-ratio: var(--img-aspect, 1);
  transform: translate(var(--pan-x, 0px), var(--pan-y, 0px)) scale(var(--zoom, 1));
  transform-origin: center;
  transition: transform .12s ease-out;
}
/* No transition while actively dragging — keeps panning snappy */
.lightbox-img-area.panning .lightbox-img-frame { transition: none; }
.lightbox-img-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;   /* frame already matches the image's aspect ratio */
}
#lightboxDots {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* Dots partially compensate for the frame scale so they stay legible
   without dominating or disappearing.  At zoom 1 they are full-size;
   at zoom 2 ≈ 0.75×; at zoom 0.5 ≈ 1.5× (clamped to [0.5, 1.8]). */
.lightbox-img-frame .spray-dot {
  transform: translate(-50%, -50%)
             scale(clamp(.5, calc(.5 + .5 / var(--zoom, 1)), 1.8));
}

/* Zoom controls (top-left, mirroring the close button) */
.lightbox-zoom-controls {
  position: fixed;
  /* PWA standalone: clear the iOS status bar / notch (0 on non-notched). */
  top: calc(14px + env(safe-area-inset-top));
  left: calc(16px + env(safe-area-inset-left));
  z-index: 302;
  display: flex;
  align-items: center;
  gap: 4px;
  background: rgba(0,0,0,.55);
  padding: 4px;
  border-radius: 10px;
}
.lightbox-zoom-controls button {
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 7px;
  background: rgba(255,255,255,.12);
  color: #fff;
  cursor: pointer;
  font-size: 1.1rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  padding: 0;
  line-height: 1;
}
.lightbox-zoom-controls button:hover  { background: rgba(255,255,255,.28); }
.lightbox-zoom-controls button:active { background: rgba(255,255,255,.4); }
.lightbox-zoom-controls .zoom-reset   { font-size: .82rem; padding: 0 10px; width: auto; min-width: 48px; }
.lightbox-zoom-controls #zoomLevel {
  color: #fff;
  font-size: .82rem;
  font-weight: 600;
  min-width: 48px;
  text-align: center;
  padding: 0 4px;
}

.lightbox-caption {
  flex-shrink: 0;
  background: rgba(255,255,255,.97);
  /* Extra bottom padding clears the home indicator (PWA); background still
     reaches the screen edge, so there's no gap below the caption. */
  padding: 10px 16px calc(12px + env(safe-area-inset-bottom));
  font-size: .88rem;
  color: var(--dark);
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
  text-align: center;
  box-shadow: 0 -4px 14px rgba(0,0,0,.35);
  z-index: 301;
}
.lightbox-caption .spray-legend {
  margin: 4px 0 0;
  padding: 6px 12px;
  background: transparent;
}

/* Spray boulder list cards */
/* Mirror the boulder list (#191): a responsive grid of compact cards rather
   than one full-width column of large photos. Every spray boulder shares the
   same wall photo with percentage-positioned hold dots, so the preview keeps
   its natural aspect ratio (no object-fit cropping, which would shift the
   dots) — the narrow column width is what turns it into a thumbnail. */
.spray-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
/* On phones a single column would still render the wall photo full-width and
   tall (it keeps its aspect ratio for dot alignment). Two columns keeps the
   previews genuinely thumbnail-sized — the whole point of #191. */
@media (max-width: 560px) { .spray-list { grid-template-columns: repeat(2, 1fr); gap: 10px; } }
.spray-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--white);
  cursor: pointer;
  transition: border-color .2s;
}
.spray-card:hover { border-color: var(--primary); }
/* Same layout strategy as the picker: image fills the wrap width 100%,
   wrap height = image height (auto), so percentages used to position the
   dots are taken relative to the same dimensions the picker used when the
   user clicked. */
.spray-preview-wrap {
  position: relative;
  width: 100%;
  background: #111;
  line-height: 0;
  overflow: hidden;
}
.spray-preview-img {
  display: block;
  width: 100%;
  height: auto;
  opacity: .82;
}
.spray-card-body  { padding: 10px 14px 12px; }
.spray-card-name  { font-weight: 700; font-size: .95rem; color: var(--dark); }
.spray-card-meta  { font-size: .78rem; color: var(--mid); margin-top: 3px; }

/* ── Redesigned spray card layout (per-line) ───────── */
/* Line 1: name + grade badge + FFH icon, forced onto a single line. The name
   truncates with an ellipsis inside the card (shown in full in the lightbox). */
.spray-card-title {
  display: flex; align-items: center; gap: 8px;
  min-width: 0;                /* allow the name to shrink so ellipsis kicks in */
  flex-wrap: nowrap;
}
.spray-card-title .spray-card-name {
  flex: 1 1 auto; min-width: 0;
  text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
}
.spray-card-title .g-badge,
.spray-card-title .ffh-badge { flex: 0 0 auto; }
/* Line 2: "Set by …" in smaller text so it stays compact. */
.spray-card-setter { font-size: .72rem; color: var(--mid); margin-top: 2px; }
/* Lines 3 & 4: a control on the left, a control/button on the right. */
.spray-card-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: 8px; flex-wrap: nowrap;
}
.spray-card-row-left  { display: flex; align-items: center; gap: 6px; min-width: 0; flex-wrap: wrap; }
.spray-card-row-right { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.spray-card-row .spray-styles { margin-top: 0; }

/* Spray boulder style icons (shown under the name) */
.spray-styles { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.spray-styles .spray-style {
  width: 24px; height: 24px; display: inline-flex; align-items: center;
  justify-content: center; font-size: .95rem; line-height: 1;
  border: 1px solid var(--border); border-radius: 6px; background: var(--light);
}
/* Spray style picker (create form) */
.spray-style-pick { display: flex; flex-wrap: wrap; gap: 6px; }
.spray-style-pick .style-pick-chip {
  padding: 6px 12px; border: 2px solid var(--border); border-radius: 6px;
  background: none; cursor: pointer; font-size: .85rem; transition: all .15s;
  display: inline-flex; align-items: center; gap: 5px;
}
.spray-style-pick .style-pick-chip .ic { font-size: 1.05rem; line-height: 1; }
.spray-style-pick .style-pick-chip.on {
  border-color: var(--primary); background: var(--primary-light); color: var(--primary);
}

/* ── Special note chip ───────────────────────── */
.special-note {
  display: inline-block;
  background: var(--primary-light);
  color: var(--primary-dark);
  font-size: .72rem;
  font-style: italic;
  border-radius: 5px;
  padding: 1px 7px;
  margin-left: 6px;
  vertical-align: middle;
  white-space: nowrap;
}

/* ── Member header button ────────────────────────────────────── */
.member-header-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(255,255,255,.12);
  border: 1.5px solid rgba(255,255,255,.22);
  border-radius: 20px;
  padding: 5px 12px 5px 7px;
  color: #fff;
  font-size: .82rem;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s, border-color .15s;
  white-space: nowrap;
  flex-shrink: 0;
  line-height: 1;
}
.member-header-btn:hover {
  background: rgba(255,255,255,.22);
  border-color: rgba(255,255,255,.5);
  color: #fff;
}
.member-header-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  border: 1.5px solid rgba(255,255,255,.5);
  display: block;
  flex-shrink: 0;
  background: var(--mid);
}
.member-header-icon { font-size: 1rem; line-height: 1; }

/* ── Logged-in account menu (member-menu.js) ─────────────────── */
.member-menu-wrap { position: relative; display: inline-block; flex-shrink: 0; }
.member-menu-trigger { font: inherit; }
.member-menu-caret { font-size: .7rem; opacity: .8; transition: transform .15s; }
.member-menu-wrap.open .member-menu-caret { transform: rotate(180deg); }
.member-menu-name {
  max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.member-menu-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 200px;
  background: var(--white);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,.18);
  padding: 6px;
  z-index: 1000;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity .14s, transform .14s, visibility .14s;
  /* On short viewports (e.g. a phone in landscape) the menu can be taller than
     the screen — cap it to what's visible and let it scroll instead of spilling
     off-screen / getting clipped. */
  max-height: calc(100vh - 64px);
  max-height: calc(100dvh - 64px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.member-menu-wrap.open .member-menu-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* Scoped under .member-menu-panel so these beat `.header-nav a` (which is
   near-white for the dark header) — otherwise the menu text is white-on-white. */
.member-menu-panel .member-menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border-radius: 8px;
  color: var(--dark, #1f2937);
  font-size: .88rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: background .12s, color .12s;
}
.member-menu-panel .member-menu-item:hover { background: var(--light, #f3f4f6); color: var(--dark, #1f2937); }
.member-menu-panel .member-menu-logout { color: #DC2626; }
.member-menu-panel .member-menu-logout:hover { background: #FEF2F2; color: #DC2626; }
.member-menu-sep { height: 1px; background: var(--border, #e5e7eb); margin: 5px 4px; }
/* Active-gym chip + switcher in the header (P4.5) — shown only when multi-gym is on. */
.mg-gym-chip-wrap { position: relative; display: inline-flex; margin-right: 8px; }
/* Note: rules are scoped under .mg-gym-* (and use !important on colour) so they
   beat the generic `.header-nav a { color:#fff }` the chip lives inside. */
.header-nav .mg-gym-chip { display: inline-flex; align-items: center; gap: 5px; font-size: .8rem;
  font-weight: 600; color: var(--dark, #1f2937) !important; background: var(--light, #f3f4f6);
  border: 1px solid var(--border, #e5e7eb); border-radius: 999px; padding: 3px 10px;
  max-width: 40vw; cursor: default; font-family: inherit; }
.mg-gym-chip-wrap.switchable .mg-gym-chip { cursor: pointer; }
.mg-gym-chip .mg-gym-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 30vw; }
.mg-gym-logo { width: 18px; height: 18px; border-radius: 4px; object-fit: cover; vertical-align: middle; }
.mg-gym-chip .mg-gym-caret { font-size: .7rem; color: var(--mid, #6b7280) !important; }
.mg-gym-panel { position: absolute; top: calc(100% + 6px); left: 0; min-width: 200px; z-index: 60;
  background: var(--white); border: 1px solid var(--border, #e5e7eb); border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12); padding: 5px; display: none;
  /* Scroll the gym list rather than overflowing the viewport on short screens. */
  max-height: calc(100vh - 64px); max-height: calc(100dvh - 64px);
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.mg-gym-chip-wrap.open .mg-gym-panel { display: block; }
.mg-gym-panel .mg-gym-opt { display: flex; align-items: center; gap: 7px; padding: 7px 10px; border-radius: 7px;
  font-size: .87rem; color: var(--dark, #1f2937) !important; text-decoration: none; white-space: nowrap; }
.mg-gym-panel .mg-gym-opt:hover { background: var(--light, #f3f4f6); }
.mg-gym-panel .mg-gym-opt.is-active { font-weight: 700; }
.mg-gym-panel .mg-gym-opt .gym-active-tick { color: var(--primary, #2563eb) !important; margin-left: auto; }
/* Per-row gym badge on My Sends / My Favorites (P4.5) — shows which gym a climb is in. */
.row-gym-badge { display: inline-block; font-size: .68rem; font-weight: 700; vertical-align: middle;
  background: var(--light, #f3f4f6); color: var(--mid, #6b7280);
  border: 1px solid var(--border, #e5e7eb); border-radius: 999px; padding: 1px 7px; margin-left: 6px; }
/* Gym switcher (P4.5) — a labelled group at the top of the account menu. */
.member-menu-gymlabel { font-size: .68rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted, #9ca3af); padding: 4px 14px 2px; font-weight: 700; }
.member-menu-panel .member-gym-item.is-active { font-weight: 700; cursor: default; }
.member-menu-panel .member-gym-item .gym-active-tick { color: var(--primary, #2563eb); margin-left: 4px; }
/* A small hover bridge so the menu doesn't close in the 8px gap. */
.member-menu-wrap::after { content: ""; position: absolute; top: 100%; right: 0; left: 0; height: 10px; }

/* ── Member auth page ────────────────────────────────────────── */
.auth-tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--border);
  margin-bottom: 24px;
}
.auth-tab {
  padding: 10px 22px;
  font-size: .95rem;
  font-weight: 600;
  color: var(--mid);
  border: none;
  background: none;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  transition: color .15s;
  font-family: inherit;
}
.auth-tab.active { color: var(--primary); border-bottom-color: var(--primary); }

.oauth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  color: var(--mid);
  font-size: .82rem;
  font-weight: 600;
}
.oauth-divider::before,
.oauth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}
/* ── Branded social sign-in buttons (#1070) ──────────────────────────────────
   Each provider follows its own brand guidelines: Apple's "Sign in with Apple"
   HIG (black variant, since the page is light-themed) and Google's Sign-In
   branding (white button, thin grey border, the 4-colour "G" mark). They share
   one height / corner radius so the stack reads as a balanced set. The official
   logos ship as inline SVGs in the markup (.oauth-logo); we never recolour the
   Google mark. The disabled "(coming soon)" state (dark-until-configured, D5)
   is rendered as a neutral greyed pill so it doesn't masquerade as a live
   branded button before the owner configures the provider. */
.oauth-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: 8px;
  font-size: .95rem;
  font-weight: 600;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
               Arial, sans-serif;
  letter-spacing: .01em;
  cursor: pointer;
  margin-bottom: 10px;
}
/* Apple — black button, white wordmark + logo (HIG). */
.oauth-btn[data-provider="apple"] {
  background: #000;
  color: #fff;
  border-color: #000;
}
.oauth-btn[data-provider="apple"]:hover:not(:disabled) { background: #1a1a1a; }
/* Google — white button, thin grey border, dark text. */
.oauth-btn[data-provider="google"] {
  background: #fff;
  color: #1f1f1f;
  border-color: #dadce0;
}
.oauth-btn[data-provider="google"]:hover:not(:disabled) { background: #f8f9fa; }
/* Disabled (coming soon) — neutral, never branded. */
.oauth-btn:disabled {
  background: var(--white);
  color: var(--mid);
  border-color: var(--border);
  cursor: not-allowed;
  opacity: .55;
}
/* The greyed mark inherits the disabled text colour; the live mark is brand. */
.oauth-btn:disabled .oauth-logo { opacity: .55; }
.oauth-logo {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  display: block;
}
.oauth-coming-soon { font-weight: 500; opacity: .85; }

/* ── Member profile page ─────────────────────────────────────── */
.avatar-edit-wrap {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
}
.avatar-lg {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  border: 3px solid var(--border);
  background: var(--light);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  color: var(--mid);
  overflow: hidden;
}
.avatar-lg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  display: block;
}

.send-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: .88rem;
  flex-wrap: wrap;
}
.send-item:last-child { border-bottom: none; }
.send-item-date  { font-size: .75rem; color: var(--mid); flex-shrink: 0; }
.send-item-label { flex: 1; min-width: 0; }
.send-item-type  { font-size: .72rem; font-weight: 600; color: var(--mid);
                   background: var(--light); border-radius: 4px; padding: 1px 6px; }

/* Send video player (profile page) */
.send-video-row {
  width: 100%;
  padding: 6px 0 4px;
}
.send-video-player {
  width: 100%;
  max-width: 420px;
  max-height: 260px;
  border-radius: 8px;
  background: #000;
  display: block;
}
.send-video-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 6px;
  flex-wrap: wrap;
}

/* Member video cards (grade page / spray lightbox) */
.member-videos-section {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.member-videos-title {
  font-weight: 700;
  font-size: .9rem;
  color: var(--dark);
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.member-video-card {
  background: var(--light);
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 12px;
}
.member-video-card video {
  width: 100%;
  max-height: 320px;
  display: block;
  background: #000;
}
.member-video-footer {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  font-size: .82rem;
  color: var(--dark);
}
.member-video-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  object-fit: cover;
}
.member-video-name {
  font-weight: 600;
  flex: 1;
}
.member-video-date {
  color: var(--mid);
  font-size: .76rem;
}

/* Social media badges */
.social-links {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.social-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 20px;
  font-size: .8rem;
  font-weight: 600;
  text-decoration: none;
  color: #fff;
}
.social-badge.instagram { background: #E1306C; }
.social-badge.youtube   { background: #FF0000; }
.social-badge.tiktok    { background: #010101; }
.social-badge.x         { background: #000000; }
.social-badge.facebook  { background: #1877F2; }

.toggle-switch {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
}
.toggle-switch input[type=checkbox] {
  width: 42px;
  height: 22px;
  appearance: none;
  -webkit-appearance: none;
  background: var(--border);
  border-radius: 11px;
  cursor: pointer;
  position: relative;
  transition: background .2s;
  flex-shrink: 0;
}
.toggle-switch input[type=checkbox]:checked { background: var(--primary); }
.toggle-switch input[type=checkbox]::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--white);
  transition: transform .2s;
  box-shadow: 0 1px 3px rgba(0,0,0,.2);
}
.toggle-switch input[type=checkbox]:checked::after { transform: translateX(20px); }
.toggle-switch label {
  margin: 0;
  cursor: pointer;
  font-size: .9rem;
  font-weight: 500;
}

/* ── Community page ──────────────────────────────────────────── */
.member-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 14px;
}
.member-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 12px 14px;
  text-align: center;
  text-decoration: none;
  color: var(--dark);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  transition: all .2s;
  cursor: pointer;
}
.member-card:hover {
  border-color: var(--primary);
  transform: translateY(-3px);
  box-shadow: 0 6px 18px rgba(232,115,26,.15);
}
.member-card-avatar {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--light);
  border: 2px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  overflow: hidden;
  flex-shrink: 0;
}
.member-card-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  display: block;
}
.member-card-name  { font-size: .88rem; font-weight: 700; line-height: 1.2; }

/* #25 presence dot — small green (online) / grey (offline) indicator shown next
 * to a member's name in the community grid, conversation list, chat header and
 * public profile. Visibility is server-enforced (connections + show_online), so
 * the markup is identical everywhere; only the colour modifier differs. */
.presence-dot {
  display: inline-block;
  width: .55em;
  height: .55em;
  border-radius: 50%;
  margin-right: .4em;
  vertical-align: middle;
  flex: none;
  background: var(--mid, #8a8f98);          /* offline (grey) — default */
}
.presence-dot.is-online {
  background: #22c55e;                       /* online (green) */
  box-shadow: 0 0 0 2px rgba(34, 197, 94, .22);
}
.presence-dot.is-offline { background: var(--mid, #8a8f98); opacity: .55; }
.member-card-sends { font-size: .78rem; color: var(--mid); }
.member-card-bio   { font-size: .75rem; color: var(--mid);
                     overflow: hidden; display: -webkit-box;
                     -webkit-line-clamp: 2; -webkit-box-orient: vertical;
                     line-height: 1.35; }

/* ── Beta videos grid (#234) ───────────────────────────────────── */
.beta-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
}
.beta-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  transition: all .2s;
}
.beta-card:hover {
  border-color: var(--primary);
  transform: translateY(-3px);
  box-shadow: 0 6px 18px rgba(232,115,26,.15);
}
.beta-thumb {
  position: relative;
  aspect-ratio: 4 / 3;
  background: #000;
  overflow: hidden;
}
.beta-thumb video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.beta-play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.4rem;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0,0,0,.6);
  opacity: .92;
}
.beta-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  font-size: .68rem;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 999px;
  color: #fff;
  backdrop-filter: blur(2px);
}
.beta-badge-staff  { background: rgba(43,45,66,.92); }
.beta-badge-member { background: rgba(232,115,26,.92); }
.beta-info { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 5px; }
.beta-line1 { display: flex; align-items: center; gap: 7px; }
.beta-color-dot {
  width: 13px; height: 13px; border-radius: 50%;
  border: 1px solid var(--border); flex-shrink: 0;
}
.beta-num { font-weight: 800; font-size: .95rem; color: var(--dark); }
.beta-grade {
  margin-left: auto; font-size: .72rem; font-weight: 700;
  background: var(--light); color: var(--mid);
  padding: 2px 8px; border-radius: 999px;
}
.beta-meta { font-size: .78rem; color: var(--mid); }
.beta-styles { display: flex; flex-wrap: wrap; gap: 5px; }
.beta-style {
  font-size: .68rem; color: var(--mid);
  background: var(--light); border-radius: 6px; padding: 2px 7px;
}
.beta-author { font-size: .76rem; color: var(--mid); }
.beta-author-link { color: var(--primary); text-decoration: none; font-weight: 600; }
.beta-author-link:hover { text-decoration: underline; }

/* ── Public member profile ───────────────────────────────────── */
.profile-hero {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  margin-bottom: 6px;
}
.profile-hero-info { flex: 1; min-width: 0; }
.profile-name  { font-size: 1.3rem; font-weight: 800; margin-bottom: 4px; }
.profile-bio   { font-size: .88rem; color: var(--mid); line-height: 1.5; }
.profile-since { font-size: .75rem; color: var(--mid); margin-top: 6px; }

/* ── Send button (grade + spray pages) ──────────────────────── */
.btn-send {
  background: var(--success);
  color: #fff;
}
.btn-send:hover { background: #16a34a; box-shadow: 0 4px 12px rgba(34,197,94,.35); }
.btn-send.sent  { background: var(--mid); cursor: default; }
.btn-send.sent:hover { background: var(--mid); box-shadow: none; transform: none; }
/* Reversed spray send emphasis (request): NOT sent reads as a quiet neutral
   button; SENT becomes the bright green "validated" state. Scoped to the
   spray-specific selector so other .btn-send users keep the default emphasis. */
.spray-send-btn        { background: var(--mid); }
.spray-send-btn:hover  { background: var(--chrome); box-shadow: none; }
.spray-send-btn.sent       { background: var(--success); cursor: default; }
.spray-send-btn.sent:hover { background: #16a34a; box-shadow: 0 4px 12px rgba(34,197,94,.35); transform: none; }

.btn-fav {
  background: #FEF3C7;
  color: #92400E;
  border: 1px solid #FDE68A;
}
.btn-fav:hover { background: #FDE68A; box-shadow: 0 4px 12px rgba(217,119,6,.20); }
.btn-fav.faved { background: #F59E0B; color: #fff; border-color: #D97706; }
.btn-fav.faved:hover { background: #D97706; box-shadow: 0 4px 12px rgba(217,119,6,.35); }

/* Spray favourite-star convention: NOT favourited is a quiet outline ☆ on a
   muted chip; once favourited it becomes the full-colour yellow ⭐ on an amber
   chip. Scoped to the spray selector so the boulder-tile star (.bt-fav) is
   untouched. */
.spray-fav-btn {
  background: var(--light);
  color: var(--mid);
  border: 1px solid var(--border);
}
.spray-fav-btn:hover { background: #FEF3C7; box-shadow: none; }
.spray-fav-btn.faved {
  background: #FEF3C7;
  color: #92400E;
  border: 1px solid #FDE68A;
}
.spray-fav-btn.faved:hover { background: #FDE68A; box-shadow: 0 4px 12px rgba(217,119,6,.20); }

/* ── Responsive ──────────────────────────────── */
@media (max-width: 600px) {
  .admin-tiles { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 400px) {
  .admin-tiles { grid-template-columns: 1fr; }
}
@media (max-width: 500px) {
  .form-row      { grid-template-columns: 1fr; }
  .action-cards  { grid-template-columns: 1fr; }
  .grade-btn     { width: 44px; height: 44px; font-size: 1rem; }
  .captcha-box   { flex-direction: column; align-items: flex-start; }
  .manage-row    { flex-direction: column; align-items: flex-start; }
  .manage-row-actions { width: 100%; }
  .bc-loc        { max-width: 100%; white-space: normal; overflow: visible; }
  .boulder-card .special-note { white-space: normal; display: block; margin: 3px 0 0; }
}

/* ───────────────────── Admin shell (admin-shell.js) ─────────────────────
   Shared left sidebar (desktop) / slide-in drawer (mobile) for all admin
   pages. Built at runtime by admin-shell.js, which removes the legacy
   .admin-sticky-bar and re-parents .container into <main id="admin-main">. */
.adm-skip { position:absolute; left:-9999px; top:0; z-index:200; background:var(--primary); color:#fff;
            padding:10px 16px; border-radius:0 0 8px 0; font-weight:700; }
.adm-skip:focus { left:0; }

.adm-side { position:fixed; top:0; left:0; bottom:0; width:240px; z-index:60;
            background:var(--chrome); color:#fff; display:flex; flex-direction:column; overflow:hidden;
            padding-top:env(safe-area-inset-top); }   /* clear the status bar in PWA standalone (#58) */
.adm-brand { display:flex; align-items:center; gap:10px; padding:16px 18px; font-weight:800; font-size:1.05rem;
             background:var(--chrome); flex-shrink:0; }
.adm-brand-logo { font-size:1.4rem; }
.adm-brand-link { display:flex; align-items:center; gap:10px; text-decoration:none; color:inherit; min-width:0; }
.adm-brand-link:hover { opacity:.85; }
.adm-brand-img { width:22px; height:22px; border-radius:5px; display:block; flex-shrink:0; }
.adm-close { margin-left:auto; background:none; border:none; color:rgba(255,255,255,.7);
             font-size:1.1rem; cursor:pointer; display:none; }
/* Pinned Dashboard (top) — always visible above the scrollable groups. */
.adm-pinned-top { flex-shrink:0; padding:0 10px 4px;
                  border-bottom:1px solid rgba(255,255,255,.08); margin-bottom:4px; }
/* Only the middle groups scroll. */
.adm-nav { flex:1; min-height:0; overflow-y:auto; padding:4px 10px 10px; }
.adm-nav::-webkit-scrollbar { width:8px; }
.adm-nav::-webkit-scrollbar-thumb { background:rgba(255,255,255,.15); border-radius:4px; }
/* Collapsible section header (#427) — a full-width button that folds the links
   under it; fold state is remembered per user in localStorage. */
.adm-group { display:flex; align-items:center; gap:7px; width:100%; background:none;
             border:none; text-align:left; cursor:pointer; font-family:inherit;
             font-size:.66rem; font-weight:800; text-transform:uppercase; letter-spacing:.07em;
             color:rgba(255,255,255,.4); padding:14px 10px 5px; }
.adm-group:hover { color:rgba(255,255,255,.72); }
.adm-group:focus-visible { outline:2px solid #fff; outline-offset:-2px; border-radius:6px; }
.adm-group-label { flex:1; }
.adm-fold-ic { font-size:.6rem; line-height:1; transition:transform .15s ease; }
.adm-group[aria-expanded="false"] .adm-fold-ic { transform:rotate(-90deg); }
/* Foldable parent entry (Settings, #553): the link flexes, a small disclosure
   button on the right folds the sub-links beneath it. */
.adm-parent { display:flex; align-items:center; }
.adm-parent .adm-link { flex:1; }
.adm-fold-toggle { background:none; border:none; cursor:pointer; flex-shrink:0;
                   color:rgba(255,255,255,.5); padding:6px 10px; line-height:1; }
.adm-fold-toggle:hover { color:#fff; }
.adm-fold-toggle:focus-visible { outline:2px solid #fff; outline-offset:-2px; border-radius:6px; }
.adm-fold-toggle .adm-fold-ic { display:inline-block; }
.adm-fold-toggle[aria-expanded="false"] .adm-fold-ic { transform:rotate(-90deg); }
.adm-link { display:flex; align-items:center; gap:11px; padding:9px 11px; border-radius:8px;
            color:rgba(255,255,255,.82); text-decoration:none; font-size:.9rem; font-weight:600; line-height:1.15; }
.adm-link:hover { background:rgba(255,255,255,.08); color:#fff; }
.adm-link.on { background:var(--primary); color:#fff; }
.adm-link:focus-visible { outline:2px solid #fff; outline-offset:-2px; }
/* Indented section deep-links under a parent entry (e.g. Gym settings, #549). */
.adm-link-sub { padding-left:30px; font-size:.84rem; font-weight:500; color:rgba(255,255,255,.66); }
.adm-link-sub .adm-ic { font-size:.9em; }
.adm-ic { width:20px; text-align:center; flex-shrink:0; }
.adm-back { margin:6px 10px 16px; background:rgba(255,255,255,.06); flex-shrink:0; }

.adm-main-wrap { margin-left:240px; min-height:100vh; display:flex; flex-direction:column; }
.adm-top { position:sticky; top:0; z-index:40; background:var(--chrome); color:#fff;
           display:flex; align-items:center; gap:12px; box-shadow:0 2px 8px rgba(0,0,0,.2);
           /* clear the iOS status bar / notch in PWA standalone mode (#58) —
              env() insets are 0 off-iOS, so desktop/Android browser is unchanged. */
           padding:calc(12px + env(safe-area-inset-top)) calc(18px + env(safe-area-inset-right))
                   12px calc(18px + env(safe-area-inset-left)); }
.adm-title { font-size:1.1rem; font-weight:700; }
.adm-top .header-nav { margin-left:auto; }
.adm-burger { display:none; background:none; border:none; color:#fff; font-size:1.4rem;
              cursor:pointer; line-height:1; padding:2px 4px; }
.adm-burger:focus-visible { outline:2px solid #fff; outline-offset:2px; }
.adm-main-wrap > #admin-main { flex:1; }
.adm-main-wrap .container { max-width:1040px; }
.adm-backdrop { display:none; }

@media (max-width:900px){
  .adm-side { transform:translateX(-100%); transition:transform .22s ease; box-shadow:2px 0 18px rgba(0,0,0,.35); }
  body.adm-drawer-open .adm-side { transform:translateX(0); }
  .adm-close { display:block; }
  .adm-main-wrap { margin-left:0; }
  .adm-burger { display:inline-flex; }
  .adm-backdrop { position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:55; }
  body.adm-drawer-open .adm-backdrop { display:block; }
}

/* ───────────────────── Public shell (public-shell.js) ─────────────────────
   Mobile-first frame for public pages: top bar (desktop links) + bottom tab
   bar & "More" sheet (mobile). Legacy .admin-sticky-bar is hidden, not removed,
   so each page's existing nav-toggle JS keeps working. */
body.pub-shell .admin-sticky-bar { display:none; }

.pub-skip { position:absolute; left:-9999px; top:0; z-index:200; background:var(--primary); color:#fff;
            padding:10px 16px; border-radius:0 0 8px 0; font-weight:700; }
.pub-skip:focus { left:0; }

/* "Powered by MonkeyGrade" footer (#53) — injected by public-shell.js /
   admin-shell.js into the page's main content. */
.app-footer { text-align:center; font-size:.78rem; color:var(--mid);
              padding:26px 16px 18px; margin-top:28px; }
.app-footer a { color:var(--mid); font-weight:600; text-decoration:none; }
.app-footer a:hover { color:var(--primary); text-decoration:underline; }
/* Standardized 3-line footer (#243): brand · archive note · cookie links. */
.app-footer p { margin:5px 0; line-height:1.4; }
.app-footer .app-footer-note { opacity:.9; }
/* Colour-scheme toggle (#270). */
.app-footer .app-footer-scheme { background:none; border:0; padding:2px 4px; cursor:pointer;
  font:inherit; font-size:.78rem; color:var(--mid); font-weight:600; text-decoration:underline; }
.app-footer .app-footer-scheme:hover { color:var(--primary); }
.app-footer .app-footer-links a { text-decoration:underline; }
/* On mobile the public bottom tab bar is fixed — clear it so the footer shows. */
@media (max-width:760px){
  .pub-shell .app-footer { margin-bottom:calc(64px + env(safe-area-inset-bottom)); }
}

/* Unread-news count badge on the News nav item. */
.pub-badge { display:inline-flex; align-items:center; justify-content:center;
             min-width:16px; height:16px; padding:0 4px; margin-left:5px; border-radius:999px;
             background:#EF4444; color:#fff; font-size:.64rem; font-weight:800; line-height:1;
             vertical-align:middle; }
.pub-tab { position:relative; }                 /* anchor the corner badge on the bottom tab */
.pub-tab .pub-badge { position:absolute; top:4px; left:calc(50% + 5px); margin-left:0; }

.pub-top { position:sticky; top:0; z-index:50; background:var(--chrome); color:#fff;
           display:flex; align-items:center; gap:14px; box-shadow:0 2px 8px rgba(0,0,0,.2);
           /* viewport-fit=cover: keep the bar clear of the notch / side safe areas
              (env() insets are 0 on non-notched screens, so desktop is unchanged). */
           padding:calc(10px + env(safe-area-inset-top)) calc(18px + env(safe-area-inset-right))
                   10px calc(18px + env(safe-area-inset-left)); }
.pub-logo { display:flex; align-items:center; gap:8px; text-decoration:none; color:#fff; min-width:0; flex-shrink:0; }
.pub-logo-img { width:1.4rem; height:1.4rem; border-radius:5px; display:block; flex-shrink:0; }
.pub-brand { font-size:1.05rem; font-weight:800; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
/* Bare brand bar (auth/landing pages before a gym is chosen): no nav menu. */
body.pub-bare .pub-links,
body.pub-bare .pub-tabs,
body.pub-bare .pub-more,
body.pub-bare .pub-more-backdrop,
body.pub-bare .pub-top .header-nav { display:none !important; }
.pub-links { display:flex; align-items:center; gap:2px; flex:1; flex-wrap:wrap; }
.pub-link { display:inline-flex; align-items:center; gap:7px; padding:7px 12px; border-radius:8px;
            color:rgba(255,255,255,.82); text-decoration:none; font-size:.88rem; font-weight:600; white-space:nowrap; }
.pub-link:hover { background:rgba(255,255,255,.10); color:#fff; }
.pub-link.on { background:var(--primary); color:#fff; }
.pub-link:focus-visible, .pub-tab:focus-visible { outline:2px solid #fff; outline-offset:-2px; }
.pub-top .header-nav { margin-left:auto; flex-shrink:0; }
.pub-link .pub-ic { font-size:1rem; }

/* Classic-menu collapse (landscape phones). When the desktop link row would
   wrap to 2+ lines on a short viewport, public-shell.js adds
   `.pub-links-collapsed` to the bar: the row hides behind a "Menu ▾" button and
   reopens as a vertical, scrollable dropdown so it never eats the limited
   vertical space. The toggle is hidden (display:none) in the normal layout. */
.pub-links-toggle { display:none; align-items:center; gap:7px; padding:7px 12px;
  border-radius:8px; background:rgba(255,255,255,.10); color:#fff; border:none;
  cursor:pointer; font:inherit; font-size:.88rem; font-weight:600; white-space:nowrap; }
.pub-links-toggle:hover { background:rgba(255,255,255,.18); }
.pub-links-toggle:focus-visible { outline:2px solid #fff; outline-offset:-2px; }
.pub-links-toggle .pub-links-caret { font-size:.7rem; opacity:.85; }
.pub-top.pub-links-collapsed .pub-links-toggle { display:inline-flex; }
.pub-top.pub-links-collapsed .pub-links {
  position:absolute; top:100%; left:calc(18px + env(safe-area-inset-left)); right:auto;
  display:none; flex:none; flex-direction:column; flex-wrap:nowrap; align-items:stretch;
  gap:2px; min-width:210px; padding:8px; background:var(--chrome);
  border-radius:0 0 12px 12px; box-shadow:0 8px 24px rgba(0,0,0,.3); z-index:55;
  max-height:calc(100vh - 56px); max-height:calc(100dvh - 56px);
  overflow-y:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch; }
.pub-top.pub-links-collapsed .pub-links.open { display:flex; }

/* Bottom tab bar (mobile) */
.pub-tabs { display:none; }
.pub-tab { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
           min-height:54px; background:none; border:none; cursor:pointer; text-decoration:none;
           color:var(--mid); font-size:.66rem; font-weight:700; padding:6px 2px; }
.pub-tab .pub-ic { font-size:1.25rem; line-height:1; }
.pub-tab.on { color:var(--primary); }

/* More sheet */
.pub-more-backdrop { display:none; position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:60; }
.pub-more { display:none; position:fixed; left:0; right:0; bottom:0; z-index:61; background:var(--white);
            border-radius:16px 16px 0 0; box-shadow:0 -4px 24px rgba(0,0,0,.25); padding:8px 16px max(16px,env(safe-area-inset-bottom));
            touch-action:none; }   /* let the swipe-to-dismiss gesture drive the sheet */
.pub-more-grab { width:40px; height:4px; border-radius:2px; background:var(--border); margin:8px auto 12px; cursor:grab; }
.pub-more-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.pub-more-item { display:flex; align-items:center; gap:10px; padding:14px; border-radius:10px;
                 text-decoration:none; color:var(--dark); font-weight:600; font-size:.92rem; background:var(--light); }
.pub-more-item.on { background:var(--primary); color:#fff; }
.pub-more-item .pub-ic { font-size:1.2rem; }
body.pub-more-open .pub-more, body.pub-more-open .pub-more-backdrop { display:block; }

@media (max-width:760px){
  .pub-links { display:none; }
  /* Keep the brand (top-left) and the account button (top-right) both on-screen:
     the gym chip collapses to its logo only, and the brand wordmark truncates
     before it can ever push the account button past the right edge. */
  .pub-logo { flex-shrink:1; overflow:hidden; }
  .mg-gym-chip .mg-gym-name, .mg-gym-chip .mg-gym-caret { display:none; }
  .mg-gym-chip-wrap { margin-right:4px; }
  .pub-tabs { display:flex; position:fixed; left:0; right:0; bottom:0; z-index:50; background:var(--white);
              border-top:1px solid var(--border); box-shadow:0 -2px 10px rgba(0,0,0,.08);
              padding-bottom:env(safe-area-inset-bottom); }
  body.pub-shell { padding-bottom:calc(66px + env(safe-area-inset-bottom)); }   /* clear the fixed bottom bar (incl. home-indicator inset) */
  /* Lift the back-to-top button above the bottom tab bar so it never overlaps
     the "More" tab. (Only on public-shell pages — the admin pages have no bar.) */
  body.pub-shell .back-to-top { bottom: calc(74px + env(safe-area-inset-bottom)); }
}

/* ── Boulder tiles (shared by the public list + admin tile editor) ─────────── */
/* BOTW card — collapsed-by-default disclosure (#224: minimise on the boulder page) */
.botw-summary { cursor:pointer; list-style:none; display:flex; align-items:center; }
.botw-summary::-webkit-details-marker { display:none; }
.botw-card:not([open]) .botw-summary { margin-bottom:0; padding-bottom:0; border-bottom:none; }
.botw-caret { margin-left:auto; font-size:.8rem; color:var(--mid); transition:transform .15s; }
.botw-card[open] .botw-caret { transform:rotate(180deg); }
/* Boulder of the Week body: the featured boulder shown as a normal list tile,
   with the member's reward progress beside it (stacking on narrow screens). */
.botw-layout { display:flex; gap:16px; align-items:flex-start; flex-wrap:wrap; }
.botw-tile { width:240px; max-width:100%; flex:0 0 auto; }
.botw-progress { flex:1 1 220px; min-width:200px; }
.boulder-tiles { display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr)); gap:12px; }
.boulder-tile { border:1px solid var(--border); border-radius:12px; padding:12px 14px;
                background:var(--white); cursor:pointer; display:flex; flex-direction:column; gap:7px;
                transition:border-color .15s, box-shadow .15s; }
.boulder-tile:hover { border-color:var(--primary); box-shadow:0 4px 14px rgba(0,0,0,.08); }
.bt-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.bt-photo { width:100%; height:150px; object-fit:cover; border-radius:8px; display:block; }
/* Reserved slots so tiles line up even when a boulder lacks the data. */
.bt-photo-empty { display:flex; align-items:center; justify-content:center; height:150px;
                  background:var(--light); border:1px dashed var(--border);
                  color:var(--mid); font-size:1.5rem; opacity:.45; }
.bt-empty { visibility:hidden; }
.bt-num { font-weight:800; font-size:1.05rem; }
/* #927: a community wall-boulder shows its NAME (not a #number) — let it wrap/
   ellipsize so a long name never blows out the tile. */
.bt-num-community { font-size:.98rem; overflow:hidden; text-overflow:ellipsis;
                    white-space:nowrap; max-width:62%; }
/* "Community" badge — visually distinct from gym-set tiles (themed purple pill). */
.bt-community-badge { display:inline-flex; align-items:center; gap:3px; font-size:.66rem;
                      font-weight:700; line-height:1; padding:3px 7px; border-radius:999px;
                      background:#EDE9FE; color:#5B21B6; border:1px solid #DDD6FE;
                      white-space:nowrap; }
.bt-icons { margin-left:auto; display:inline-flex; gap:6px; }
.bt-wall { font-size:.9rem; font-weight:600; color:var(--dark); }
.bt-note { font-size:.8rem; color:var(--primary); font-style:italic;
           white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
.bt-styles { display:flex; flex-wrap:wrap; gap:4px; font-size:1rem; }
.bt-styles .bt-style { width:26px; height:26px; display:inline-flex; align-items:center;
                       justify-content:center; border:1px solid var(--border); border-radius:50%;
                       background:var(--light); }
.bt-g { display:flex; align-items:center; gap:5px; font-size:.78rem; color:var(--mid); }
.bt-setter { font-size:.78rem; color:var(--mid); }
/* #218/#225: favourite star on a tile. Floats to the right of its row; click
   is handled separately from the tile-wide grade link (see
   actToggleBoulderFav). Emphasis is INVERTED (#225): the default (not-yet-
   favourited) state is the eye-catching full-colour yellow ⭐ that invites the
   member to favourite; once favourited it relaxes to a quiet themed outline ☆.
   Scoped to .bt-fav so it never collides with spray's .spray-fav-btn/.btn-fav. */
/* Favourite group sits at the right end of its row: [send-status icon] [star]. */
.bt-fav-wrap { margin-left:auto; display:inline-flex; align-items:center; gap:5px; }
/* Non-clickable send-status icon shown left of the star (⚡ flashed / ✅ sent). */
.bt-send-status { font-size:1rem; line-height:1; cursor:default; user-select:none; }
/* Identical to the spray favourite chip (.btn.btn-sm.spray-fav-btn): a small
   pill — quiet outline ☆ on a muted chip when not favourited, amber-on-fave ⭐ —
   so the boulder tile and spray boulder use the exact same favourite affordance. */
.bt-fav { display:inline-flex; align-items:center; justify-content:center;
          padding:5px 12px; border-radius:6px; font-size:.8rem; font-weight:600;
          line-height:1; cursor:pointer; background:var(--light); color:var(--mid);
          border:1px solid var(--border); transition:background .2s, box-shadow .2s; }
.bt-fav:hover { background:#FEF3C7; }
.bt-fav.faved { background:#FEF3C7; color:#92400E; border:1px solid #FDE68A; }
.bt-fav.faved:hover { background:#FDE68A; box-shadow:0 4px 12px rgba(217,119,6,.20); }

/* ── Mobile: two columns for both lists, with tightened tile text so the denser
      grid stays coherent. Placed after the base rules so it wins on source
      order. (Spray-list grid itself is set in its own 560px block above.) ──── */
@media (max-width: 560px) {
  /* Boulder list mirrors the spray wall: two tiles per row on phones.
     min-width:0 lets each 1fr column shrink below its content's intrinsic
     width so the badge rows wrap instead of forcing horizontal overflow. */
  .boulder-tiles { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .boulder-tile  { padding: 9px 10px; gap: 5px; min-width: 0; }
  .spray-card    { min-width: 0; }
  .bt-row    { gap: 6px; }
  .bt-photo, .bt-photo-empty { height: 104px; }
  .bt-num    { font-size: .9rem; }
  .bt-wall   { font-size: .76rem; }
  .bt-note   { font-size: .72rem; }
  .bt-g, .bt-setter { font-size: .7rem; }
  .bt-fav { font-size: .72rem; padding: 4px 9px; }   /* match the spray chip's mobile size */
  /* Colour: show only the coloured dot, hide the name + pill chrome (like the
     table view). The ::before dot is a fixed 10px, so font-size:0 keeps it. */
  .boulder-tile .color-chip { font-size: 0; gap: 0; margin: 0; padding: 0;
                              border: none; background: transparent; }
  /* Set / Community each take a full line: label on the left, grade on the right. */
  .bt-grade { flex-basis: 100%; justify-content: space-between; }
  .bt-styles { font-size: .85rem; gap: 3px; }
  .bt-styles .bt-style { width: 22px; height: 22px; }

  /* Spray wall cards (already two columns) — match the tighter scale. */
  .spray-card-body { padding: 8px 10px 10px; }
  .spray-card-name { font-size: .82rem; }
  .spray-card-meta { font-size: .7rem; }
  .spray-styles .spray-style { width: 20px; height: 20px; font-size: .82rem; }
  .spray-card .btn-sm, .spray-card .btn-moderate { font-size: .72rem; padding: 5px 8px; }
}

/* ── PWA install affordances (#58) ───────────────────────────────────────── */
/* Discreet install button — sits in the header, just left of Sign in / the name. */
.mg-install { background:transparent; color:rgba(255,255,255,.78); border:1px solid rgba(255,255,255,.32);
  border-radius:8px; padding:5px 9px; font-size:.8rem; font-weight:600; cursor:pointer;
  white-space:nowrap; line-height:1; flex-shrink:0; }
.mg-install:hover { background:rgba(255,255,255,.12); color:#fff; }
.mg-ios-tip { position:fixed; left:10px; right:10px; bottom:calc(72px + env(safe-area-inset-bottom)); z-index:60;
  background:var(--chrome); color:#fff; border-radius:10px; padding:10px 12px; display:flex; gap:10px;
  align-items:center; font-size:.85rem; line-height:1.35; box-shadow:0 4px 14px rgba(0,0,0,.28); }
.mg-ios-tip b { color:#fff; }
.mg-ios-tip button { margin-left:auto; flex-shrink:0; background:none; border:none; color:#fff;
  font-size:1.3rem; cursor:pointer; line-height:1; padding:0 4px; }

/* ── Admin "How it works" help (#174) ────────────────────────────────────────
   An always-present info icon pinned to the RIGHT of the admin top bar (the same
   spot on every admin page). Clicking it opens the page's guidance as an OVERLAY
   on top of the content (dialog popover + backdrop) — never inline. Role-gated in
   admin-help.js: super-admin notes + the Learn-more links are super-admin only.
   Inherits the dark-mode token remap above. */
.adm-help-btn {
  margin-left: auto;             /* pin the icon to the right group of the top bar */
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.3);
  color: #fff;
  cursor: pointer;
  line-height: 1;
}
.adm-help-btn:hover { background: rgba(255,255,255,.22); }
.adm-help-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.adm-help-btn svg { display: block; }
/* The icon owns the right-push; keep the account menu snug to its right. */
.adm-top .adm-help-btn ~ .header-nav { margin-left: 0; }

.adm-help-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.35); z-index: 90; }
.adm-help-pop {
  position: fixed;
  top: 64px;
  right: 16px;
  width: min(420px, calc(100vw - 32px));
  max-height: min(74vh, 660px);
  overflow: auto;
  z-index: 91;
  background: var(--white);
  color: var(--dark);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 14px 44px rgba(0,0,0,.3);
}
.adm-help-pop-head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 16px;
  background: var(--white);
  border-bottom: 1px solid var(--border);
  font-weight: 800;
  font-size: .95rem;
}
.adm-help-ic { font-size: 1.05rem; flex-shrink: 0; }
.adm-help-pop-title { color: var(--primary-dark); }
:root[data-theme="dark"] .adm-help-pop-title { color: var(--primary); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .adm-help-pop-title { color: var(--primary); }
}
.adm-help-pop-close {
  margin-left: auto;
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.2rem;
  line-height: 1;
  color: var(--mid);
  padding: 2px 4px;
}
.adm-help-pop-close:hover { color: var(--dark); }
@media (max-width: 560px) {
  .adm-help-pop { top: 58px; right: 10px; left: 10px; width: auto; max-height: 78vh; }
}
.adm-help-body {
  padding: 12px 16px 16px;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--dark);
}
.adm-help-intro { color: var(--mid); margin-bottom: 12px; }
ol.adm-help-steps { margin: 0 0 4px; padding-left: 22px; }
ol.adm-help-steps li { margin-bottom: 6px; }
.adm-help-steps li::marker { color: var(--primary); font-weight: 700; }
.adm-help-note {
  margin: 12px 0 4px;
  padding: 9px 12px;
  border-radius: 8px;
  background: rgba(0,0,0,.04);
  border-left: 3px solid var(--primary);
  font-size: .86rem;
  color: var(--mid);
}
.adm-help-tips { margin-top: 14px; }
.adm-help-tips-h {
  display: block;
  font-weight: 700;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .3px;
  color: var(--mid);
  margin-bottom: 4px;
}
ul.adm-help-tip-list { margin: 0; padding-left: 20px; }
ul.adm-help-tip-list li { margin-bottom: 5px; }
.adm-help-tip-list li::marker { content: "💡 "; }
.adm-help-docs {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: .85rem;
}
.adm-help-docs-label { color: var(--mid); font-weight: 700; }
.adm-help-docs a { color: var(--primary-dark); font-weight: 600; text-decoration: none; }
.adm-help-docs a:hover { text-decoration: underline; }
:root[data-theme="dark"] .adm-help-docs a { color: var(--primary); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .adm-help-docs a { color: var(--primary); }
}
.adm-help-dot { color: var(--mid); margin: 0 7px; }
.adm-help-body strong { color: var(--dark); font-weight: 700; }
.adm-help-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .85em;
  background: rgba(0,0,0,.06);
  border-radius: 4px;
  padding: 1px 5px;
}

/* ════════════════════════════════════════════════════════════════════════
   #846 — Community wall boulders (member web UI)
   New page wall-boulders.html + the separate community-stats section.
   Reuses the spray editor styles (.spray-picker-*, .spray-dot-*, .hold-*,
   .spray-card, .g-badge); only the genuinely new pieces live here.
   ════════════════════════════════════════════════════════════════════════ */

/* The finish hold reuses spray's "top" red dot; aliased here for clarity so a
   future restyle of finish holds doesn't disturb spray. */

/* ── Gym-map "Create a boulder on this wall" CTA (#846) ── */
.wall-card-wrap { display: flex; flex-direction: column; gap: 6px; }
.wall-card-wrap > .wall-card { flex: 1; }
.wall-card-create {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  font-size: .78rem;
  font-weight: 700;
  color: var(--primary-dark);
  background: var(--primary-light);
  border: 1px solid var(--primary);
  border-radius: 8px;
  padding: 6px 8px;
  text-decoration: none;
  text-align: center;
  transition: background .15s, color .15s;
}
.wall-card-create:hover { background: var(--primary); color: #fff; }

/* ── Wall picker (step 1) photo badge ── */
.wallb-photo-badge {
  font-size: .68rem;
  font-weight: 600;
  color: var(--mid);
  background: rgba(0,0,0,.05);
  border-radius: 999px;
  padding: 2px 8px;
  align-self: center;
}
.wallb-photo-badge.has { color: #16A34A; background: #F0FDF4; }

/* ── Surface picker (step 2) ── */
.wallb-surface-opts { display: flex; flex-direction: column; gap: 10px; }
.wallb-surface-opt {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  background: var(--light);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s, transform .15s;
  font-family: inherit;
}
.wallb-surface-opt:hover {
  border-color: var(--primary);
  box-shadow: 0 4px 14px rgba(232,115,26,.16);
  transform: translateY(-1px);
}
.wallb-surface-opt .opt-ic { font-size: 1.7rem; line-height: 1; flex-shrink: 0; }
.wallb-surface-opt .opt-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.wallb-surface-opt .opt-txt strong { font-size: .95rem; color: var(--dark); }
.wallb-surface-opt .opt-txt small { font-size: .8rem; color: var(--mid); line-height: 1.35; }

/* ── Surface picker (step 1) — mobile-style list (#957 web parity) ──
   "Upload your own photo" card on top, then gym walls grouped into
   "with a photo" (Tier-A) and "on the map" (Tier-C). */
.wallb-pick-list { display: flex; flex-direction: column; gap: 10px; }
.wallb-pick-section {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--mid);
  margin: 14px 0 2px;
}
.wallb-pick-own {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  text-align: left;
  background: rgba(232,115,26,.08);
  border: 1px solid rgba(232,115,26,.3);
  border-radius: 14px;
  padding: 14px 16px;
  cursor: pointer;
  font-family: inherit;
  transition: border-color .15s;
}
.wallb-pick-own:hover { border-color: var(--primary); }
.wallb-pick-own .opt-ic { font-size: 1.6rem; line-height: 1; flex-shrink: 0; }
.wallb-pick-own .opt-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.wallb-pick-own .opt-txt strong { font-size: .95rem; color: var(--dark); }
.wallb-pick-own .opt-txt small { font-size: .8rem; color: var(--mid); line-height: 1.35; }
.wallb-pick-tile {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  background: var(--light);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 10px;
  cursor: pointer;
  font-family: inherit;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.wallb-pick-tile:hover {
  border-color: var(--primary);
  box-shadow: 0 4px 12px rgba(232,115,26,.15);
  transform: translateY(-1px);
}
.wallb-pick-thumb {
  width: 56px;
  height: 56px;
  flex-shrink: 0;
  border-radius: 10px;
  object-fit: cover;
  background: #ECE6DA;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
}
.wallb-pick-thumb-map { color: var(--mid); }
.wallb-pick-meta { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.wallb-pick-name {
  font-size: .95rem;
  font-weight: 700;
  color: var(--dark);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wallb-pick-sub { font-size: .8rem; color: var(--mid); }
.wallb-pick-chev { color: var(--mid); font-size: 1.4rem; flex-shrink: 0; }

/* ── Detail overlay ── */
.wallb-detail-card { max-height: calc(100vh - 36px); overflow-y: auto; }
.wallb-detail-img {
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: #ECE6DA;
  line-height: 0;
}
.wallb-detail-img img { display: block; width: 100%; height: auto; }
.wallb-detail-dots { position: absolute; inset: 0; pointer-events: none; }

/* Side-by-side creator vs community grades — never merged (#846 §6). */
.wallb-grades {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin: 14px 0;
}
.wallb-grade-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  background: var(--light);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 10px;
  text-align: center;
}
.wallb-grade-kind {
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--mid);
}
.wallb-grade-col .g-badge { width: auto; min-width: 34px; padding: 0 10px; height: 30px; font-size: 1rem; }
.wallb-grade-none { font-size: 1.3rem; font-weight: 800; color: var(--mid); }
.wallb-grade-votes { font-size: .72rem; color: var(--mid); }
.wallb-grade-sep {
  align-self: center;
  font-size: .78rem;
  font-weight: 700;
  color: var(--mid);
  text-transform: uppercase;
}

.wallb-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 6px 0; }
.wallb-meta .spray-styles { margin: 0; }
.wallb-sendcount { font-size: .82rem; color: var(--mid); font-weight: 600; }
.wallb-ffh { font-size: .82rem; color: var(--dark); }
.wallb-rules {
  width: 100%;
  font-size: .85rem;
  color: var(--dark);
  background: var(--light);
  border-left: 3px solid var(--primary);
  border-radius: 6px;
  padding: 8px 12px;
  white-space: pre-wrap;
  word-break: break-word;
}

.wallb-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }

/* Suggest-grade vote chips. */
.wallb-vote-block { margin: 12px 0; }
.wallb-vote-label { font-size: .85rem; font-weight: 700; color: var(--dark); margin-bottom: 8px; }
.wallb-vote-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.wallb-vote-chip {
  background: var(--light);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: .82rem;
  font-weight: 700;
  color: var(--dark);
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.wallb-vote-chip:hover { border-color: var(--primary); }
.wallb-vote-chip.on { color: #fff; }

/* Log-a-send sheet. */
.wallb-log-sheet {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  margin: 10px 0;
  background: var(--light);
}
.wallb-log-title { font-size: .92rem; font-weight: 700; color: var(--dark); margin-bottom: 8px; }
.wallb-attempts-row { display: flex; align-items: center; gap: 10px; font-size: .88rem; margin-top: 8px; }
.wallb-attempts-val { min-width: 26px; text-align: center; font-weight: 800; font-size: 1.05rem; color: var(--dark); }

.wallb-detail-footer {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.wallb-detail-manage { display: flex; gap: 8px; flex-wrap: wrap; }
.wallb-report-btn { margin-left: auto; color: var(--mid); }
.wallb-report-form { margin-top: 12px; }

/* List card grade chip (compact creator + community, when present). */
.wallb-grade-chip { display: inline-flex; align-items: center; gap: 4px; }
.wallb-grade-chip-label { font-size: .68rem; color: var(--mid); font-weight: 600; }
.wallb-grade-chip-meta { font-size: .68rem; color: var(--mid); }

/* ── Member-stats: separate "Community boulders" pyramid card (#846 §5) ──
   Visually distinct from the official pyramid: a left accent + tinted heading
   make the separation unmistakable. */
.community-card {
  border-left: 4px solid var(--primary);
  background: linear-gradient(180deg, var(--primary-light), transparent 120px);
}
.community-card .card-title .icon { filter: none; }

/* ── Public profile: community-sent counter ── */
.profile-community-count {
  font-size: .82rem;
  font-weight: 700;
  color: var(--primary-dark);
  margin-top: 6px;
}

/* Narrow screens: stack the side-by-side grades but keep them distinct. */
@media (max-width: 420px) {
  .wallb-grades { flex-direction: column; }
  .wallb-grade-sep { transform: none; }
}

/* ── admin theme overrides ── */
:root{--primary:#E8731A;--primary-dark:#be5e15;--primary-light:#fceee3;--dark:#2B2D42;--light:#F7F4EF;--border:#DDD5C8;}