/* Climber screens (Task 11): find/add gym, gym home, climb grid, add climb,
 * climb detail, rate sheet, sign-in. Builds on the tokens in app.css.
 *
 * The photo is the hero everywhere: cards are mostly photo, with the tape
 * chip and grade riding on it and the vote strip directly beneath, so a
 * climber can find "the green one on the cave" and vote with one thumb.
 */

/* Tape colour as a variable for blanks (no photo yet). */
[data-color='red'] { --tape: var(--hold-red); }
[data-color='orange'] { --tape: var(--hold-orange); }
[data-color='yellow'] { --tape: var(--hold-yellow); }
[data-color='green'] { --tape: var(--hold-green); }
[data-color='blue'] { --tape: var(--hold-blue); }
[data-color='purple'] { --tape: var(--hold-purple); }
[data-color='pink'] { --tape: var(--hold-pink); }
[data-color='black'] { --tape: var(--hold-black); }
[data-color='white'] { --tape: var(--hold-white); }
[data-color='grey'] { --tape: var(--hold-grey); }
[data-color='teal'] { --tape: var(--hold-teal); }
[data-color='lime'] { --tape: var(--hold-lime); }
[data-color='brown'] { --tape: var(--hold-brown); }
[data-color='tan'] { --tape: var(--hold-tan); }
[data-color='navy'] { --tape: var(--hold-navy); }
[data-color='magenta'] { --tape: var(--hold-magenta); }
[data-color='maroon'] { --tape: var(--hold-maroon); }
[data-color='neon'] { --tape: var(--hold-neon); }

/* ── Shared bits ── */

.section-title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 800;
  margin-bottom: var(--s3);
}

.error-box {
  display: grid;
  gap: var(--s2);
  justify-items: start;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--danger) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
  color: var(--ink);
  font-weight: 550;
}

/* "Report a problem" in an error box: a quiet text button, full tap height. */
.error-report {
  min-height: var(--tap);
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 650;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.error-report:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ── Report a problem (views/report-sheet.js, admin list) ── */

.report-sheet {
  display: grid;
  gap: var(--s3);
}

.report-lead {
  padding: 0;
  margin-bottom: var(--s2);
  font-weight: 650;
}

.report-attach-title {
  margin-top: var(--s2);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 700;
}

/* Exactly what goes with the report, label beside value. */
.report-attach {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s1) var(--s4);
  margin: 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: var(--fs-sm);
}

.report-attach dt {
  color: var(--ink-2);
}

.report-attach dd {
  margin: 0;
  font-weight: 650;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.problem .edit-meta {
  align-items: center;
}

.problem a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  overflow-wrap: anywhere;
}

/* Admin usage counts: scrolls inside its own box, never the page. */
.usage-scroll {
  min-width: 0;
  overflow-x: auto;
  border-radius: var(--r-md);
}

.usage-scroll:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.usage-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

.usage-table th,
.usage-table td {
  padding: var(--s2) var(--s1);
  border-bottom: 1px solid var(--line);
  text-align: right;
  white-space: nowrap;
}

.usage-table thead th {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--ink-2);
  white-space: normal;
  vertical-align: bottom;
}

.usage-table th:first-child {
  text-align: left;
  font-weight: 650;
  color: var(--ink-2);
}

.usage-table .usage-total th,
.usage-table .usage-total td {
  font-weight: 750;
  color: var(--ink);
  background: var(--surface-2);
}

/* Admin sections a link can open at (#activity, #review, #errors): clear
 * of the sticky top bar. */
.group[id] {
  scroll-margin-top: calc(var(--topbar-h) + env(safe-area-inset-top) + var(--s3));
}

/* The test site's banner (css/app.css) takes the inset itself. */
.is-test-site .group[id] {
  scroll-margin-top: calc(var(--test-banner-h, 0px) + var(--topbar-h) + var(--s3));
}

.group-subtitle {
  font-size: var(--fs-sm);
  font-weight: 750;
  color: var(--ink-2);
}

/* Activity: the gym and climb-list links in a row keep a 44px target. */
.activity-row .edit-what a,
.activity-row .edit-meta a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 650;
}

.activity-row .edit-meta {
  align-items: center;
}

.owner-switches {
  display: grid;
  justify-items: start;
  gap: var(--s1);
}

/* A day with errors stands out: --danger passes 4.5:1 on --surface (both themes). */
.errors-table td.has-errors {
  color: var(--danger);
  font-weight: 750;
}

.error-message {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.error-where {
  overflow-wrap: anywhere;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 1px var(--s2);
  border-radius: 999px;
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1.6;
  white-space: nowrap;
}

.badge .icon {
  width: 14px;
  height: 14px;
  stroke-width: 3;
}

.badge-verified {
  background: color-mix(in srgb, var(--soft) 18%, transparent);
  color: var(--ink);
}

.badge-unverified {
  background: var(--surface-2);
  color: var(--ink-2);
}

.badge-removed {
  background: color-mix(in srgb, var(--danger) 16%, transparent);
  color: var(--ink);
}

.osm-credit {
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.osm-credit a {
  color: inherit;
}

/* The one "Gym data: …" line after a list or at the foot of a gym page:
   small and muted, always shown (OSMF: legible near the data), the whole
   line a link to /data. */
.data-credit {
  margin-top: var(--s3);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.data-credit a {
  color: inherit;
}

/* Google Maps attribution: Google's text-styling rules (Roboto or the
   system sans-serif, 400, normal, 12-16px, #5E5E5E on light / white on dark,
   one line). See docs/third-party/google-places.md. The system sans-serif
   is used (the CSP allows only self-hosted fonts; it is Roboto on Android).
   "Dark" follows the app's theme, so a forced choice wins over the OS. */
.gmp-credit {
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.gmp-attribution {
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-style: normal;
  font-weight: 400;
  font-size: 13px;
  letter-spacing: normal;
  white-space: nowrap;
  color: #5e5e5e;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .gmp-attribution {
    color: #ffffff;
  }
}

:root[data-theme='dark'] .gmp-attribution {
  color: #ffffff;
}

/* Google's suggestions sit in their own box, apart from RateClimbs' gyms. */
.google-box {
  margin-top: var(--s4);
  padding: var(--s3) var(--s4) var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
}

.google-box-title {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-2);
}

.google-box .gmp-credit {
  text-align: right;
  margin-top: var(--s2);
}

.gym-row-sub {
  display: block;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

/* The town under a gym's name ("Vancouver, BC"): small, muted, one line.
   --ink-3 is at least 4.5:1 on every surface a row sits on, in both themes. */
.gym-row-place {
  font-size: var(--fs-sm);
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.results-title {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-2);
  margin-bottom: var(--s2);
}

.results-empty {
  color: var(--ink-2);
  padding: var(--s2) 0;
}

.fine-print {
  font-size: var(--fs-sm);
  color: var(--ink-3);
  margin-top: var(--s4);
}

/* ── Forms ── */

.stack-form {
  display: grid;
  gap: var(--s5);
}

.field {
  display: grid;
  gap: var(--s2);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.field-label {
  padding: 0;
  font-weight: 700;
}

.field-hint {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

.stack-form input[type='text'],
.stack-form input[type='url'],
.stack-form input[type='search'],
.stack-form input[type='date'],
.stack-form select,
.signin input,
.search-row input,
.filter-chip select {
  width: 100%;
  min-height: 48px;
  padding: 0 var(--s4);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  font-size: 1.0625rem; /* ≥16px: iOS does not zoom on focus. */
}

.stack-form select,
.filter-chip select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%), linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 20px) 50%, calc(100% - 15px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  padding-right: 40px;
}

.stack-form input:focus,
.stack-form select:focus,
.signin input:focus,
.search-row input:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.search-row {
  display: flex;
  gap: var(--s2);
}

.search-row .btn {
  flex: none;
  width: 48px;
  min-height: 48px;
  padding: 0;
  border-radius: var(--r-md);
}

/* Toggle pills: real checkboxes, visually hidden, the label is the target. */
.toggle-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.toggle-pill,
.pill {
  position: relative;
  display: inline-flex;
}

.toggle-pill input,
.pill input,
.segment input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.toggle-pill span,
.pill-face {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s4);
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-weight: 650;
  cursor: pointer;
  user-select: none;
}

.toggle-pill input:checked + span,
.pill input:checked + .pill-face {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg);
}

.toggle-pill input:focus-visible + span,
.pill input:focus-visible + .pill-face,
.segment input:focus-visible + span {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.scale-fields {
  display: grid;
  gap: var(--s4);
}

.scale-fields:empty {
  display: none;
}

.segmented {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  padding: 3px;
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.segment span {
  display: grid;
  place-items: center;
  min-height: var(--tap);
  border-radius: 9px;
  font-weight: 650;
  cursor: pointer;
}

.segment input:checked + span {
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

.where {
  display: grid;
  gap: var(--s3);
}

.where-chosen {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  font-weight: 650;
}

.where-chosen .icon {
  color: var(--accent-text);
}

.where-chosen-block {
  display: grid;
  gap: var(--s1);
  padding: var(--s3);
  border-radius: var(--r-md);
  background: var(--surface);
}

.place-list,
.gym-list,
.dupe-list,
.tag-list,
.grade-hist {
  list-style: none;
  margin: 0;
  padding: 0;
}

.place-list {
  display: grid;
  gap: 1px;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--line);
  margin-bottom: var(--s2);
}

.place-row {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  width: 100%;
  min-height: 52px;
  padding: var(--s3);
  border: 0;
  background: var(--surface);
  text-align: left;
  font-size: var(--fs-sm);
  cursor: pointer;
}

.place-row .icon {
  color: var(--ink-3);
}

.place-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
}

/* The Add-gym map: the pin is the one thing in colour, so it reads as
 * "the gym is here" at a glance, the way a tape chip reads on a photo. */
.where-map {
  height: 220px;
  margin: var(--s2) calc(-1 * var(--s3)) 0;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-2);
  /* Leaflet's own stacking stays inside the map (below the tab bar and sheets). */
  isolation: isolate;
  z-index: 0;
}

.where-map.is-unavailable {
  display: grid;
  place-items: center;
  height: auto;
  min-height: 80px;
  padding: var(--s3);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  text-align: center;
}

.where-map .leaflet-control-attribution {
  font: var(--fs-xs) / 1.4 var(--font);
  color: #333;
}

.map-pin {
  background: none;
  border: 0;
}

.map-pin svg {
  display: block;
  width: 32px;
  height: 44px;
  filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.35));
}

.map-pin-body {
  fill: var(--accent);
  stroke: var(--accent-ink);
  stroke-width: 1.5;
}

.map-pin-dot {
  fill: var(--surface);
}

.map-pin:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.leaflet-dragging .map-pin svg {
  transform: translateY(-4px);
}

/* The primary action sits above the tab bar, under the thumb. */
.sticky-action {
  position: sticky;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s2));
  z-index: 5;
  padding-top: var(--s2);
}

.sticky-action::before {
  content: '';
  position: absolute;
  inset: calc(-1 * var(--s4)) calc(-1 * var(--s4)) calc(-1 * var(--s2));
  z-index: -1;
  background: linear-gradient(to bottom, transparent, var(--bg) 40%);
  pointer-events: none;
}

.turnstile-slot:empty {
  display: none;
}

.dupes {
  display: grid;
  gap: var(--s2);
  padding: var(--s4);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--hard) 14%, var(--surface));
}

.dupes-title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 750;
}

/* ── Home: find a gym ── */

.find {
  display: grid;
  gap: var(--s3);
}

.find .section-title {
  margin-bottom: 0;
}

.find-results:empty {
  display: none;
}

.gym-list {
  display: grid;
  gap: var(--s2);
  margin-bottom: var(--s2);
}

.gym-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 60px;
  padding: var(--s3) var(--s3) var(--s3) var(--s4);
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
}

.gym-row:active {
  background: var(--surface-2);
}

.gym-row > .icon {
  color: var(--ink-3);
}

.gym-row-text {
  flex: 1;
  min-width: 0;
  display: grid;
}

.gym-row-name {
  font-weight: 700;
  font-size: 1.0625rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gym-row-meta {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

.gym-row-last {
  border-left: 4px solid var(--accent);
}

/* Round gym avatar: the website's icon on white, or tape-coloured initials. */
.gym-avatar {
  flex: none;
  display: inline-grid;
  place-items: center;
  overflow: hidden;
  border-radius: 50%;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.01em;
  user-select: none;
}

.gym-avatar-icon {
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--line);
}

.gym-avatar-icon img {
  width: 68%;
  height: 68%;
  object-fit: contain;
}

/* Favourites and Recent on the home screen. */
.saved-slot:empty {
  display: none;
}

.saved-gyms .section-title {
  margin-bottom: var(--s2);
}

.saved-gyms .gym-list {
  margin-bottom: 0;
}

/* OSM gyms not in RateClimbs yet: dashed, like an outline waiting to be
 * filled in, with "Add" where the chevron would be. */
.osm-gyms {
  display: grid;
  gap: var(--s2);
  margin-top: var(--s4);
}

.osm-gyms-title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 750;
}

.gym-row-osm {
  background: transparent;
  border: 1.5px dashed var(--line);
}

.gym-row-osm:active {
  background: var(--surface);
}

.gym-row-add {
  flex: none;
  padding: var(--s1) var(--s3);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: var(--fs-sm);
  font-weight: 750;
}

/* Suggested gyms (Overture, OpenStreetMap): each source in its own box, the
 * dashed "waiting to be added" rows of .gym-row-osm, its credit at the end.
 * --brand-green is at least 4.8:1 on --bg and --surface in both themes. */
.suggested-gyms {
  display: grid;
  gap: var(--s2);
  margin-top: var(--s4);
}

.suggested-gyms-title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 750;
}

.suggested-gyms-note {
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

.suggested-gyms .gym-list {
  margin-bottom: 0;
}

.badge-suggested {
  background: transparent;
  color: var(--brand-green);
  box-shadow: inset 0 0 0 1px currentColor;
}

/* Add gym from an Overture suggestion: what to check, with its credit. */
.suggested-intro {
  display: grid;
  gap: var(--s1);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
}

.suggested-intro[hidden] {
  display: none;
}

.report-suggestion {
  justify-self: start;
}

.add-gym-cta {
  display: grid;
  gap: var(--s3);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  color: var(--ink-2);
}

/* ── Sign-in ── */

.signin {
  display: grid;
  gap: var(--s3);
  padding-top: var(--s1);
}

/* The swapped step's children lay out as direct grid items of .signin,
 * next to the stable Turnstile slot. */
.signin-step {
  display: contents;
}

.signin .sheet-title {
  margin-bottom: 0;
}

.sheet-lede {
  color: var(--ink-2);
}

.signin-form {
  display: grid;
  gap: var(--s3);
}

/* Google's button rules: white, #747775 border, #1f1f1f text, the
 * unmodified four-colour G. Same in dark mode (white stays allowed). Font:
 * the system sans-serif, which is Roboto on Android; the CSP allows only
 * self-hosted fonts and Roboto is not one of them. */
.gsi-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 48px;
  padding: 0 var(--s4);
  border: 1px solid #747775;
  border-radius: 999px;
  background: #ffffff;
  color: #1f1f1f;
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-weight: 500;
  font-size: 0.9375rem;
  text-decoration: none;
}

.gsi-btn:active {
  background: #f2f2f2;
}

.gsi-logo {
  width: 20px;
  height: 20px;
  flex: none;
}

.or-rule {
  display: flex;
  align-items: center;
  gap: var(--s3);
  color: var(--ink-3);
  font-size: var(--fs-sm);
}

.or-rule::before,
.or-rule::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

.signin .code-input {
  min-height: 64px;
  text-align: center;
  font-size: 2rem;
  font-weight: 750;
  letter-spacing: 0.4em;
  font-variant-numeric: tabular-nums;
}

.signin-alt {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}

.signin-alt .btn {
  padding: 0 var(--s2);
}

.confirm {
  display: grid;
  gap: var(--s4);
  padding-top: var(--s5);
}

.confirm-title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 800;
}

/* ── Gym home ── */

.gym-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3);
}

.gym-site {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* The header: the gym's own best climb photo, a gradient that keeps the
 * name legible over any wall, the avatar and the star. Without a photo it
 * is a plain surface, name in ink. */
.gym-hero {
  position: relative;
  display: grid;
  align-items: end;
  overflow: hidden;
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
}

.gym-hero.has-cover {
  min-height: 210px;
  background: var(--hold-black);
  color: #fff;
}

.gym-hero-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.gym-hero.has-cover::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0.55) 60%, rgba(0, 0, 0, 0.82) 100%);
}

.gym-hero-row {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
}

.gym-hero.has-cover .gym-avatar {
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.9);
}

.gym-hero-text {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: var(--s1);
  justify-items: start;
}

.gym-hero-name {
  font-family: var(--font-display);
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.015em;
  overflow-wrap: anywhere;
}

.gym-hero.has-cover .gym-hero-name {
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.45);
}

.gym-hero-place {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  overflow-wrap: anywhere;
}

/* The owner's "Edit town" form on the gym page. */
.town-editor summary {
  cursor: pointer;
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 700;
}

.town-editor .stack-form {
  gap: var(--s3);
  margin-top: var(--s3);
}

/* The owner's "Link to a suggestion" results: name and town, then Link. */
.link-suggestion-row {
  align-items: center;
  justify-content: space-between;
  cursor: default;
}

.link-suggestion-what {
  display: grid;
  gap: 2px;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* "Add town from my location" on a Google-placed gym without a town. */
.town-from-here {
  display: grid;
  gap: var(--s1);
  justify-items: start;
}

.town-from-here .muted {
  margin: 0;
  font-size: var(--fs-sm);
}

/* On a cover photo, under the dark gradient: near-white, like the name. */
.gym-hero.has-cover .gym-hero-place {
  color: rgba(255, 255, 255, 0.92);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}

/* ☆ / ★, a full tap target; filled with the accent when on. */
.fav-toggle {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

.fav-toggle[aria-pressed='true'] {
  border-color: transparent;
  background: var(--accent);
  color: var(--accent-ink);
}

.gym-hero.has-cover .fav-toggle:not([aria-pressed='true']) {
  border-color: rgba(255, 255, 255, 0.4);
  background: rgba(0, 0, 0, 0.35);
  color: #fff;
}

.fav-toggle:disabled {
  opacity: 0.6;
}

@media (prefers-reduced-motion: no-preference) {
  .fav-toggle[aria-pressed='true'] .fav-glyph {
    animation: fav-pop 260ms var(--ease);
  }
}

@keyframes fav-pop {
  50% { transform: scale(1.3); }
}

/* New-set alerts: a switch under the star, for a favourite gym. The track
 * is --star when on and an outlined --star-off when off (both 3:1+ on the
 * surface); over a cover photo it is white on the dark gradient. */
.alerts {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: end;
  gap: var(--s1);
  padding: 0 var(--s4) var(--s3);
  margin-top: calc(-1 * var(--s2));
}

.alerts[hidden],
.alerts-switch[hidden],
.alerts-hint[hidden] {
  display: none;
}

.alerts-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s1);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
}

.alerts-track {
  position: relative;
  flex: none;
  width: 44px;
  height: 26px;
  border: 2px solid var(--star-off);
  border-radius: var(--r-pill);
  background: transparent;
}

.alerts-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--star-off);
}

.alerts-switch[aria-pressed='true'] .alerts-track {
  border-color: var(--star);
  background: var(--star);
}

.alerts-switch[aria-pressed='true'] .alerts-thumb {
  left: 21px;
  background: var(--surface);
}

.alerts-switch[aria-disabled='true'],
.fav-toggle[aria-disabled='true'] {
  opacity: 0.6;
  cursor: progress;
}

.alerts-hint {
  margin: 0;
  padding: 0 var(--s1);
  font-size: var(--fs-xs);
  color: var(--ink-3); /* 5.7:1 on --surface (light), 6.5:1 (dark) */
  text-align: right;
}

.gym-hero.has-cover .alerts-track {
  border-color: rgba(255, 255, 255, 0.85);
}

.gym-hero.has-cover .alerts-thumb {
  background: #fff;
}

.gym-hero.has-cover .alerts-switch[aria-pressed='true'] .alerts-track {
  border-color: var(--accent);
  background: var(--accent);
}

.gym-hero.has-cover .alerts-switch[aria-pressed='true'] .alerts-thumb {
  background: var(--hold-black);
}

.gym-hero.has-cover .alerts-hint {
  /* White over the gradient: 4.7:1 even where it is lightest (0.55 black
   * over a white photo); the hint sits lower, where it is darker still.
   * 0.85 white was 3.9:1 there. */
  color: #fff;
}

@media (prefers-reduced-motion: no-preference) {
  .alerts-thumb {
    transition: left 160ms var(--ease);
  }
}

.fresh-strip {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 112px;
  gap: var(--s2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  margin: 0 calc(-1 * var(--s4));
  padding: 0 var(--s4) var(--s2);
  scrollbar-width: none;
}

.fresh-strip::-webkit-scrollbar {
  display: none;
}

.fresh-card {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--surface-2);
  scroll-snap-align: start;
}

.fresh-card img,
.fresh-blank {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fresh-blank {
  display: block;
  background: linear-gradient(160deg, color-mix(in srgb, var(--tape, var(--hold-grey)) 55%, var(--surface-2)), var(--surface-2));
}

.fresh-meta {
  position: absolute;
  left: var(--s1);
  bottom: var(--s1);
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  padding: 3px 4px 3px 8px;
  border-radius: var(--r-pill);
  background: var(--surface);
}

.wall-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
}

.wall-card {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 2px;
  min-height: 104px;
  padding: var(--s3) var(--s4);
  border: 0;
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.wall-card:active {
  background: var(--surface-2);
}

.wall-card-count {
  order: -1;
  margin-bottom: auto;
  color: var(--ink-3);
  font-size: var(--fs-sm);
}

.wall-card-count strong {
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.wall-card-name {
  font-weight: 700;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.wall-card-meta {
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.wall-card-add {
  align-items: flex-start;
  justify-content: space-between;
  background: transparent;
  border: 1.5px dashed var(--line);
  color: var(--ink-2);
  font: inherit;
}

.feedback-link {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
}

.feedback-link > span {
  flex: 1;
  display: grid;
}

.feedback-link .muted {
  font-size: var(--fs-sm);
}

/* ── Gyms near you (views/rankings.js) ── */

.rank-intro {
  color: var(--ink-2);
}

.rank-nudge-slot:empty {
  display: none;
}

.rank-nudge {
  margin: 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

.rank-nudge a {
  color: var(--accent-text);
  font-weight: 700;
}

.rank-controls {
  display: grid;
  gap: var(--s3);
}

.rank-area {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
}

.rank-locate {
  gap: var(--s1);
  min-height: var(--tap);
}

.rank-locate .icon {
  width: 18px;
  height: 18px;
}

.rank-km {
  flex: 0 0 auto;
  width: auto;
}

.rank-results {
  display: grid;
  gap: var(--s4);
}

.rank-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--s3);
}

.rank-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-card);
  background: var(--surface);
}

.rank-row.is-not-yet {
  grid-template-columns: minmax(0, 1fr);
  padding: var(--s3) var(--s4);
}

.rank-num {
  min-width: 2.5ch;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 800;
  line-height: 1.1;
  color: var(--brand-green);
  font-variant-numeric: tabular-nums;
}

.rank-main {
  display: grid;
  gap: var(--s2);
  min-width: 0;
}

.rank-head {
  display: grid;
  gap: 2px;
}

.rank-name {
  font-weight: 750;
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.rank-name:hover {
  text-decoration: underline;
}

.rank-place {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1) var(--s2);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

.rank-stats {
  font-size: var(--fs-sm);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.rank-stats .stars {
  margin-right: var(--s2);
  vertical-align: -1px;
}

.rank-score {
  font-weight: 750;
  color: var(--ink);
}

.rank-grades {
  display: grid;
  gap: var(--s1);
}

.rank-grades .tri-wrap {
  display: flex;
}

.rank-lean {
  display: grid;
  font-size: var(--fs-sm);
}

.rank-lean .muted {
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

.rank-section {
  display: grid;
  gap: var(--s2);
}

.rank-note,
.rank-footer {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

/* ── Climb grid ── */

.filter-bar {
  position: sticky;
  top: calc(var(--topbar-h) + env(safe-area-inset-top));
  z-index: 8;
  display: flex;
  gap: var(--s2);
  overflow-x: auto;
  margin: calc(-1 * var(--s4)) calc(-1 * var(--s4)) 0;
  padding: var(--s2) var(--s4);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  scrollbar-width: none;
}

/* On the test site the top bar sticks below the banner, which takes the
 * inset (css/app.css, "Test site"). */
.is-test-site .filter-bar {
  top: calc(var(--test-banner-h, 0px) + var(--topbar-h));
}

.filter-bar::-webkit-scrollbar {
  display: none;
}

.filter-chip {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--s4);
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 650;
  white-space: nowrap;
  cursor: pointer;
}

label.filter-chip {
  padding: 0;
}

.filter-chip select {
  min-height: var(--tap);
  border: 0;
  border-radius: 999px;
  background-color: transparent;
  padding: 0 34px 0 var(--s4);
  font-size: var(--fs-sm);
  font-weight: 650;
  max-width: 11rem;
}

.filter-chip.is-on {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg);
}

.filter-chip.is-on select {
  color: var(--bg);
  background-image: linear-gradient(45deg, transparent 50%, var(--bg) 50%), linear-gradient(135deg, var(--bg) 50%, transparent 50%);
}

.climb-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s3) var(--s2);
}

@media (min-width: 560px) {
  .climb-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* The server returns the newest LIST_CAP climbs; say so under the grid. */
/* ── Wall reset ("coming down soon") ── */

.reset-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
}

.reset-row[hidden] {
  display: none;
}

/* The ember edge is decoration; the text is --ink on a tinted --bg. */
.reset-banner {
  flex: 1 1 14rem;
  margin: 0;
  padding: var(--s3) var(--s4);
  border-left: 4px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--accent-soft);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 650;
  line-height: 1.4;
}

.reset-button,
.rename-button,
.clear-wall-button {
  flex: none;
}

/* "Set Oct 12" on a single wall's grid, beside the countdown. */
.wall-set {
  flex: none;
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.stack-form input[type='date'] {
  display: block;
  color: var(--ink);
}

.list-cap {
  margin: var(--s4) 0 0;
  color: var(--ink-2);
  font-size: var(--fs-sm);
  text-align: center;
}

.climb-card {
  display: grid;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--surface);
  transition: opacity 160ms var(--ease);
}

.climb-card.is-saving {
  opacity: 0.7;
}

.climb-card.is-skeleton {
  aspect-ratio: 3 / 5;
  background: linear-gradient(100deg, var(--surface) 30%, var(--surface-2) 50%, var(--surface) 70%) 0 0 / 300% 100%;
  animation: shimmer 1.4s linear infinite;
}

@keyframes shimmer {
  to { background-position: -150% 0; }
}

/* The router's loading screen (js/views/skeleton.js). */
.skeleton-page {
  display: grid;
  gap: var(--s3);
}

.skeleton-block {
  border-radius: var(--r-card);
  background: linear-gradient(100deg, var(--surface) 30%, var(--surface-2) 50%, var(--surface) 70%) 0 0 / 300% 100%;
  animation: shimmer 1.4s linear infinite;
}

.skeleton-hero { height: 112px; }
.skeleton-line { height: 18px; }
.skeleton-short { width: 60%; }
.skeleton-card { height: 72px; }
.skeleton-photo { aspect-ratio: 3 / 4; }

/* Screen swaps (router.js): a quick cross-fade, none with reduced motion
   (the router skips the transition then). */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 120ms;
}

.climb-card-photo {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  background: var(--surface-2);
}

.climb-card-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.climb-card-blank {
  display: grid;
  place-items: center;
  height: 100%;
  background:
    repeating-linear-gradient(-35deg, transparent 0 18px, color-mix(in srgb, var(--ink) 4%, transparent) 18px 19px),
    linear-gradient(170deg, color-mix(in srgb, var(--tape, var(--hold-grey)) 45%, var(--surface-2)), var(--surface-2) 75%);
}

.climb-card-blank .chip {
  width: 64px;
  height: 26px;
}

/* Chip and grade ride on the photo, top left, on a solid tab. */
.climb-card-tag {
  position: absolute;
  top: var(--s2);
  left: var(--s2);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 3px 3px 8px;
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}

.climb-card-tag .chip {
  width: 22px;
  height: 11px;
}

.climb-card-body {
  display: grid;
  gap: 6px;
  padding: var(--s2) var(--s2) var(--s2);
}

.climb-card-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s1);
  min-height: 20px;
  padding: 0 2px;
}

.climb-card-count {
  font-size: var(--fs-xs);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.climb-card .tri-wrap {
  display: flex;
  padding: 0 2px;
}

.card-votes {
  display: grid;
  grid-template-columns: 1fr 1.35fr 1fr;
  gap: 3px;
}

.card-vote {
  min-height: var(--tap);
  padding: 0 2px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 120ms var(--ease), transform 120ms var(--ease);
}

.card-vote:active {
  transform: scale(0.95);
}

.card-vote[aria-pressed='true'].vote-soft,
.vote-btn[aria-checked='true'].vote-soft { background: var(--soft); color: var(--verdict-ink); }
.card-vote[aria-pressed='true'].vote-correct,
.vote-btn[aria-checked='true'].vote-correct { background: var(--correct); color: var(--verdict-ink); }
.card-vote[aria-pressed='true'].vote-hard,
.vote-btn[aria-checked='true'].vote-hard { background: var(--hard); color: var(--verdict-ink); }

/* ── Add climb ── */

.shot {
  display: grid;
  gap: var(--s2);
}

.shot-take {
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--s1);
  min-height: 220px;
  padding: var(--s5);
  border: 2px dashed color-mix(in srgb, var(--accent) 60%, var(--line));
  border-radius: var(--r-lg);
  background: var(--accent-soft);
  text-align: center;
  cursor: pointer;
}

.shot-take .icon {
  width: 44px;
  height: 44px;
  stroke-width: 1.6;
  color: var(--accent-text);
}

.shot-title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 800;
}

.shot-hint {
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

/* "No people in the shot": a rule, not a tip, so it reads as a small sign
   on the camera tile (and in the gallery's add slide). */
.shot-rule {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: var(--s2) 0 0;
  padding: 4px 12px 4px 8px;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 700;
}

.shot-take .shot-rule .icon,
.shot-rule .icon {
  width: 18px;
  height: 18px;
  stroke-width: 2;
  color: var(--danger);
}

.error-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.shot {
  position: relative;
}

.shot-preview {
  width: 100%;
  max-height: 52vh;
  object-fit: cover;
  border-radius: var(--r-lg);
}

.shot-retake {
  position: absolute;
  right: var(--s3);
  bottom: var(--s3);
  background: color-mix(in srgb, var(--surface) 92%, transparent);
}

.color-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--s2);
}

.color-row .pill-face {
  justify-content: center;
  width: 100%;
  min-height: 52px;
  padding: 0;
  border-radius: var(--r-md);
}

.color-row .pill {
  display: flex;
}

.color-row .pill-face .chip {
  width: 38px;
  height: 18px;
}

.color-row .pill input:checked + .pill-face {
  background: var(--surface);
  border: 3px solid var(--ink);
}

.wall-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

/* ── Climb detail ── */

.detail {
  display: grid;
  gap: var(--s4);
}

.detail-photo {
  width: calc(100% + 2 * var(--s4));
  max-height: 68vh;
  margin: calc(-1 * var(--s4)) calc(-1 * var(--s4)) 0;
  object-fit: cover;
  background: var(--surface-2);
}

.detail-photo-blank {
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--s2);
  aspect-ratio: 4 / 3;
  color: var(--ink-2);
  background: linear-gradient(170deg, color-mix(in srgb, var(--tape, var(--hold-grey)) 45%, var(--surface-2)), var(--surface-2) 75%);
}

.detail-photo-blank .chip {
  width: 80px;
  height: 32px;
}

/* Photo gallery: edge to edge like the single photo was, one angle per
 * swipe. The pager is tape in the hold colour; the photo in view gets the
 * long strip. */
.gallery {
  display: grid;
  gap: var(--s2);
  margin: calc(-1 * var(--s4)) calc(-1 * var(--s4)) 0;
}

.gallery-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  background: var(--surface-2);
}

.gallery-track::-webkit-scrollbar {
  display: none;
}

.gallery-track:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: -3px;
}

.gallery-slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.gallery-photo {
  display: block;
  width: 100%;
  height: min(68vh, 133vw);
  object-fit: cover;
  user-select: none;
}

/* The last slide: a frame waiting for another angle. */
.gallery-add {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--s3);
  height: min(68vh, 133vw);
  padding: var(--s5);
  text-align: center;
  border: 2px dashed var(--line);
  background: var(--surface-2);
}

.gallery-add.is-first {
  height: auto;
  aspect-ratio: 4 / 3;
  border: 0;
  background: linear-gradient(170deg, color-mix(in srgb, var(--tape, var(--hold-grey)) 45%, var(--surface-2)), var(--surface-2) 75%);
}

.gallery-add.is-first .chip {
  width: 80px;
  height: 32px;
}

.gallery-add-text {
  max-width: 24ch;
  margin: 0;
  color: var(--ink-2);
}

.gallery-add-count {
  margin: 0;
  font-size: var(--fs-sm);
}

.gallery-add-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s5);
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  font: inherit;
  font-weight: 650;
  cursor: pointer;
}

.gallery-add-btn:disabled,
.gallery-add-btn[aria-disabled='true'] {
  opacity: 0.6;
  cursor: default;
}

.gallery-dots {
  display: flex;
  justify-content: center;
  gap: 2px;
}

.gallery-dot {
  display: grid;
  place-items: center;
  width: 30px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.gallery-dot::before {
  content: '';
  width: 12px;
  height: 7px;
  background: var(--tape, var(--hold-grey));
  opacity: 0.35;
  clip-path: polygon(0 10%, 12% 0, 100% 8%, 92% 55%, 100% 100%, 10% 90%, 0 100%, 6% 50%);
  transition: width 160ms var(--ease), opacity 160ms var(--ease);
}

.gallery-dot[aria-current='true']::before {
  width: 26px;
  opacity: 1;
}

/* White, black, navy and maroon tape vanish on one theme each; the grey
 * stays visible. */
.gallery-dots[data-color='white'] .gallery-dot::before,
.gallery-dots[data-color='black'] .gallery-dot::before,
.gallery-dots[data-color='navy'] .gallery-dot::before,
.gallery-dots[data-color='maroon'] .gallery-dot::before {
  background: var(--ink-3);
}

.gallery-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s2);
}

.gallery-actions:empty {
  display: none;
}

.gallery-spacer {
  flex: 1;
}

.gallery-note {
  padding: 0 var(--s3);
  font-size: var(--fs-sm);
}

.gallery-remove {
  color: var(--danger);
}

@media (prefers-reduced-motion: reduce) {
  .gallery-dot::before {
    transition: none;
  }
}

.detail-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s3);
}

.detail-grade {
  display: grid;
}

.detail-grade-main {
  font-family: var(--font-display);
  font-size: 3.25rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.detail-grade-sub {
  color: var(--ink-2);
  font-weight: 600;
}

.detail-where {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
  font-weight: 650;
  text-align: right;
}

.detail-stars {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.detail-stars .stars {
  font-size: var(--fs-lg);
}

.detail-share {
  margin-left: auto;
}

.detail-share .icon {
  width: 18px;
  height: 18px;
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.detail-consensus {
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--surface);
}

.consensus-verdict {
  font-weight: 650;
}

.stripped-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  padding: var(--s2) var(--s2) var(--s2) var(--s4);
  border-radius: var(--r-md);
  background: var(--ink);
  color: var(--bg);
  font-weight: 650;
}

.detail-strip {
  justify-self: center;
  font-size: var(--fs-sm);
}

/* ── Rate sheet ── */

.rate {
  display: grid;
  gap: var(--s3);
}

.rate-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  color: var(--ink-2);
  font-weight: 600;
}

.rate .sheet-title {
  margin: var(--s2) 0 0;
}

.rate-label {
  margin-top: var(--s3);
  font-size: var(--fs-md);
  font-weight: 700;
}

.star-picker {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--s1);
}

.star-btn {
  min-height: 60px;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--star-off);
  font-size: 2.6rem;
  line-height: 1;
  cursor: pointer;
  transition: transform 140ms var(--ease), color 140ms var(--ease);
}

.star-btn.is-on {
  color: var(--star);
}

.star-btn:active {
  transform: scale(0.88);
}

.star-caption {
  min-height: 1.5em;
  text-align: center;
  color: var(--ink-2);
  font-weight: 650;
}

.vote-picker {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s1);
  padding: 4px;
  border-radius: var(--r-btn);
  background: var(--surface-2);
}

.vote-btn {
  min-height: 52px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--ink-2);
  font-weight: 750;
  font-size: 1rem;
  cursor: pointer;
}

.tag-picker {
  display: grid;
  gap: var(--s3);
}

.tag-group-label {
  margin: 0 0 var(--s1);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 650;
}

.tag-group-pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.tag-pill {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--s4);
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-weight: 600;
  cursor: pointer;
}

.tag-pill:disabled {
  /* Full ink kept readable; a dashed edge says "not available". */
  color: var(--ink-2);
  border-style: dashed;
  cursor: default;
}

.tag-pill[aria-pressed='true'] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg);
}

.tag-pill.is-static {
  min-height: 32px;
  padding: 0 var(--s3);
  background: var(--surface-2);
  border-color: transparent;
  cursor: default;
}

/* Duplicate list (add climb). */
.dupe-row {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 56px;
  padding: var(--s1) var(--s3) var(--s1) var(--s1);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
}

.dupe-row img,
.dupe-blank {
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--surface-2);
}

.dupe-cta {
  margin-left: auto;
  color: var(--accent-text);
  font-weight: 700;
  font-size: var(--fs-sm);
}

.dupe-list {
  display: grid;
  gap: var(--s2);
}

/* ── Colour source ── */

.color-source {
  display: grid;
  gap: var(--s2);
}

.color-source .field-hint {
  margin: 0;
}

.gym-color-source {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--fs-sm);
}

/* The gym page's People section (gym admins and the owner). */
.people-section {
  display: grid;
  gap: var(--s3);
}

.people-section .field-hint {
  margin: 0;
  font-size: var(--fs-sm);
}

.people-role {
  min-height: var(--tap);
}

/* A gym admin's or setter's "You're an admin of this gym" line. */
.gym-staff-line {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--fs-sm);
}

.link-button {
  min-height: var(--tap);
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent-text);
  font: inherit;
  font-weight: 650;
  text-decoration: underline;
  cursor: pointer;
}

.link-button:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* A photo the automatic check refused, in the gallery's add slide. */
.gallery-add-status:empty {
  display: none;
}

.gallery-refused {
  max-width: 28ch;
  margin: 0;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--danger) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
  color: var(--ink);
  font-weight: 600;
}

/* ── Share a climb (js/views/share-sheet.js) ──
   The QR is black on white in both themes (it has to scan off a dark
   screen); the address under it selects whole on a long press. The
   sheet fills the bottom of the screen, so its toasts ("Link copied") show
   at the top instead, clear of the QR and the buttons. */

.sheet:has(.share) .toast-region {
  top: calc(env(safe-area-inset-top) + var(--s3));
  bottom: auto;
}

.share {
  display: grid;
  justify-items: center;
  gap: var(--s3);
  text-align: center;
}

.share .sheet-title {
  justify-self: stretch;
  margin-bottom: 0;
}

.share-what {
  margin: 0;
  color: var(--ink-2);
  font-weight: 600;
}

.share-qr {
  display: grid;
  place-items: center;
  width: min(100%, 220px);
  aspect-ratio: 1;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
}

.share-qr.is-drawn {
  padding: var(--s2);
  border: 0;
  background: white;
}

.share-qr svg {
  display: block;
  width: 100%;
  height: auto;
}

.share-qr-missing {
  margin: 0;
  padding: var(--s4);
  color: var(--ink-2);
}

.share-url {
  margin: 0;
  max-width: 100%;
  color: var(--ink);
  font-weight: 650;
  overflow-wrap: anywhere;
  user-select: all;
  -webkit-user-select: all;
}

.share .sheet-actions {
  justify-self: stretch;
  margin-top: var(--s2);
}

/* ── QR sheets (/g/:slug/qr, js/views/qr-sheet.js) ──
 * On screen each wall's page is a paper card. On paper: one wall per page,
 * content within 186 x 255 mm so A4 and US Letter both fit, the QR at
 * 120 mm, black ink on white whatever the theme, no background fills. The
 * QR itself is black modules on a white square (the library draws it), so
 * it scans from a dark-theme screen too. */
.qr-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.qr-toolbar-text {
  flex: 1 1 16ch;
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

.qr-page {
  display: grid;
  justify-items: center;
  gap: var(--s3);
  padding: var(--s5) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
  text-align: center;
}

.qr-page .brand-mark {
  width: 56px;
  height: 44px;
}

.qr-page .home-title {
  font-size: var(--fs-xl);
}

.qr-gym {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md);
  font-weight: 650;
}

.qr-wall {
  margin: 0;
  max-width: 100%;
  font-family: var(--font-display);
  font-size: 2.5rem;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.qr-code {
  width: min(100%, 320px);
  padding: var(--s2);
  border-radius: var(--r-sm);
  background: white;
}

.qr-code svg {
  display: block;
  width: 100%;
  height: auto;
}

.qr-cta {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 700;
}

.qr-url {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.qr-page-tools {
  padding-top: var(--s2);
}

/* ── Outbox (js/sync.js): ratings kept on the phone until there is signal ── */

.pending-chip {
  justify-self: start;
  margin: 0;
  padding: 2px var(--s2);
  border: 1px dashed var(--accent-text);
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: var(--fs-xs);
  font-weight: 650;
  line-height: 1.4;
}

/* As wide as the content column (page gutters, at most --max-w less them),
 * so its text wraps as little as possible. */
.outbox-banner {
  position: fixed;
  left: max(var(--s4), env(safe-area-inset-left));
  right: max(var(--s4), env(safe-area-inset-right));
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s2));
  z-index: 25;
  max-width: calc(var(--max-w) - 2 * var(--s4));
  margin-inline: auto;
  min-height: var(--tap);
  padding: var(--s2) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-toast);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 650;
  cursor: pointer;
}

.outbox-banner[hidden] {
  display: none;
}

/* Toasts and sticky actions rise above the banner while it shows. */
/* --outbox-h: the banner's measured height plus a gap (0 while hidden), set
 * on body by sync.js (outboxBanner); 72px until first measured. */
.has-outbox {
  --outbox-h: 72px;
}

.has-outbox .toast-region {
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s3) + var(--outbox-h));
}

/* The last rows (a tick's Delete) scroll clear of the banner and tab bar. */
.has-outbox #app {
  padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s5) + var(--outbox-h));
}

.has-outbox .sticky-action {
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s2) + var(--outbox-h));
}

/* ── Logbook: Log it on a climb, the rate sheet's Log it row, My climbs ── */

.detail-log {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--surface);
}

.detail-log .section-title {
  margin-bottom: 0;
}

.log-buttons {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s2);
}

.log-btn {
  min-height: 48px;
  padding: 0 var(--s2);
  border-width: 1.5px;
  border-color: var(--ink-3);
  border-radius: var(--r-btn);
  font-weight: 750;
}

.my-ticks {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.my-tick {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  min-height: 52px;
  border-top: 1px solid var(--line);
}

.my-tick-text {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1) var(--s2);
  min-width: 0;
}

.my-tick-kind {
  color: var(--ink);
}

.log-picker {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s1);
  padding: 4px;
  border-radius: var(--r-btn);
  background: var(--surface-2);
}

.log-option {
  min-height: var(--tap);
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-weight: 750;
  cursor: pointer;
}

.log-option[aria-checked='true'] {
  background: var(--ink);
  color: var(--bg);
}

.logbook {
  display: grid;
  gap: var(--s4);
}

.session {
  display: grid;
  gap: var(--s1);
  padding: var(--s3) var(--s4) var(--s1);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
}

.session-title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 750;
}

.session-counts {
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.logbook-list {
  margin: var(--s1) 0 0;
  padding: 0;
  list-style: none;
}

.logbook-list li + li {
  border-top: 1px solid var(--line);
}

.logbook-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 56px;
  color: var(--ink);
  text-decoration: none;
}

.logbook-row-text {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1) var(--s2);
  min-width: 0;
}

.logbook-wall {
  overflow: hidden;
  font-weight: 650;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.logbook-kind {
  flex: none;
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 750;
}

.logbook-kind[data-kind='flash'] {
  color: var(--accent-text);
}

/* My progress (/me/progress). Bars are sized through CSSOM (views/progress.js);
   both fills keep 3:1 or more on --surface in both themes: --ink-2 (sent)
   and --accent-text (flash, 6.0:1 light, 6.5:1 dark); a 2px gap and the numbers as text tell them apart. */
.progress-body {
  display: grid;
  gap: var(--s4);
}

.progress-note:empty {
  display: none;
}

.pyramid-list {
  display: grid;
  gap: var(--s4);
}

.pyramid-title {
  margin: 0 0 var(--s2);
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 750;
}

.pyramid-rows {
  display: grid;
  gap: var(--s1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.pyramid-row {
  display: grid;
  grid-template-columns: 3.5rem 1fr 6.5rem;
  align-items: center;
  gap: var(--s2);
  min-height: 28px;
}

.pyramid-grade {
  font-weight: 750;
  font-variant-numeric: tabular-nums;
}

.pyramid-track {
  display: flex;
  justify-content: center;
  gap: 2px;
  min-width: 0;
}

.pyramid-bar {
  display: block;
  min-inline-size: 6px;
  block-size: 20px;
  border-radius: 4px;
}

.pyramid-bar-sent {
  background: var(--ink-2);
}

.pyramid-bar-flash {
  background: var(--accent-text);
}

.pyramid-counts {
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.pyramid-legend {
  display: flex;
  gap: var(--s4);
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 650;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
}

.legend-swatch {
  display: inline-block;
  inline-size: 12px;
  block-size: 12px;
  border-radius: 3px;
}

.weeks {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  align-items: end;
  gap: var(--s1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.week {
  display: grid;
  justify-items: center;
  gap: 2px;
}

.week-count {
  color: var(--ink-2);
  font-size: var(--fs-xs);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.week-slot {
  display: flex;
  align-items: flex-end;
  inline-size: 100%;
  block-size: 96px;
  border-bottom: 1px solid var(--ink-3);
}

.week-bar {
  display: block;
  inline-size: 100%;
  border-radius: 4px 4px 0 0;
  background: var(--ink-2);
}

.weeks-axis {
  display: flex;
  justify-content: space-between;
  margin: 0;
  color: var(--ink-3);
  font-size: var(--fs-xs);
  font-weight: 650;
}

/* ── Session recap (js/views/recap-sheet.js) ──
   Each session's counts share a row with its Recap button. The sheet lists
   the recap lines, the first (the counts) largest; its toasts ("Image
   saved") show at the top, clear of the button. */

.session-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.session-recap {
  flex: none;
}

.sheet:has(.recap) .toast-region {
  top: calc(env(safe-area-inset-top) + var(--s3));
  bottom: auto;
}

.recap .sheet-title {
  margin-bottom: 0;
}

.recap-when {
  margin: var(--s1) 0 0;
  color: var(--ink-2);
  font-weight: 650;
}

.recap-lines {
  display: grid;
  gap: var(--s2);
  margin: var(--s4) 0 0;
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  list-style: none;
  color: var(--ink-2);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.recap-lines .recap-counts {
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 750;
}

.recap .sheet-actions {
  margin-top: var(--s4);
}

.recap-note {
  margin: var(--s3) 0 0;
  color: var(--ink-3);
  font-size: var(--fs-sm);
  text-align: center;
}

@media print {
  @page {
    margin: 12mm;
  }

  .tabbar,
  .topbar,
  .toast-region,
  .outbox-banner,
  .qr-toolbar,
  .qr-page-tools {
    display: none !important;
  }

  html,
  body {
    background: none;
  }

  #app {
    min-height: 0;
    padding: 0;
  }

  .qr-sheet,
  .qr-sheet .screen-body {
    display: block;
    max-width: none;
    margin: 0;
    padding: 0;
  }

  .qr-page {
    max-width: 186mm;
    max-height: 255mm;
    margin: 0 auto;
    padding: 0;
    gap: 5mm;
    border: 0;
    border-radius: 0;
    background: none;
    color: black;
    break-after: page;
    break-inside: avoid;
  }

  .qr-page:last-child {
    break-after: auto;
  }

  .qr-page .brand-mark {
    width: 24mm;
    height: 19mm;
  }

  /* No cream sticker edge on paper; the wordmark in plain ink. */
  .qr-page .brand-mark-edge {
    fill: none;
    stroke: none;
  }

  .qr-page .home-title {
    font-size: 20pt;
  }

  .qr-page .wordmark-climbs,
  .qr-gym,
  .qr-url {
    color: black;
  }

  .qr-gym {
    font-size: 14pt;
  }

  .qr-wall {
    font-size: 36pt;
  }

  .qr-code {
    width: 124mm;
    padding: 2mm;
    border-radius: 0;
  }

  .qr-cta {
    font-size: 16pt;
  }

  .qr-url {
    font-size: 13pt;
  }
}

/* ── Setter feedback: sections, walls, loved climbs ── */

.fb-section {
  display: grid;
  gap: var(--s3);
}

.fb-group-title {
  font-size: var(--fs-sm);
  font-weight: 750;
  color: var(--ink-2);
}

/* A wall row: the name across the top, then the bar and vote count, then
 * the verdict. Wall names are too long for the grade column. */
.fb-walls .fb-legend,
.fb-wall-row {
  grid-template-columns: 1fr 4.25rem;
}

.fb-walls .fb-key {
  grid-column: 1;
}

.fb-wall-name {
  grid-column: 1 / -1;
  overflow: hidden;
  font-weight: 650;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-wall-row .fb-meta {
  grid-column: 1 / -1;
}

.fb-empty {
  color: var(--ink-2);
}

.fb-loved {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
}

.fb-loved li {
  border-top: 1px solid var(--line);
}

.fb-loved li:last-child {
  border-bottom: 1px solid var(--line);
}

.fb-loved-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 56px;
  color: var(--ink);
  text-decoration: none;
}

.fb-loved-look {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex: none;
}

.fb-loved-text {
  display: grid;
  flex: 1;
  min-width: 0;
}

.fb-loved-wall {
  overflow: hidden;
  font-weight: 650;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-loved-meta {
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

.fb-loved-stars {
  display: grid;
  justify-items: end;
  gap: 2px;
  flex: none;
}

.fb-loved-score {
  font-size: var(--fs-sm);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* ── Strip next: three short lists of live climbs, counts only ── */

.sn-list {
  display: grid;
  gap: var(--s2);
}

.sn-note {
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

/* ── Grade histogram: soft / on grade / hard votes on the climb page ── */

.hist-empty {
  margin: 0 0 var(--s2);
  color: var(--ink-2);
}

.grade-hist {
  display: grid;
  gap: var(--s2);
  margin: var(--s3) 0;
}

/* Label, bar, count and share line up across the three rows. */
.hist-row {
  display: grid;
  grid-template-columns: 5.5em 1fr 2.5em 2.75em;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

.hist-track {
  height: 14px;
  border-radius: 7px;
  overflow: hidden;
  background: var(--surface-2);
}

/* A 0 % bar still draws a stub, so the row reads as "none", not missing. */
.hist-bar {
  display: block;
  height: 100%;
  min-width: 2px;
  border-radius: 7px;
}

.hist-soft { background: var(--soft-fill); }
.hist-correct { background: var(--correct-fill); }
.hist-hard { background: var(--hard-fill); }

.hist-count {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.hist-pct {
  font-variant-numeric: tabular-nums;
  text-align: end;
}

/* Too few votes for a verdict: muted bars, no shares. */
.grade-hist.is-tentative .hist-bar { background: var(--ink-3); }
.grade-hist.is-tentative .hist-pct { visibility: hidden; }

/* ── Empty wall invitation: fewer than three climbs, add the ones you see ── */

.wall-invite {
  display: grid;
  gap: var(--s2);
  justify-items: start;
  margin-bottom: var(--s4);
  padding: var(--s4);
  border-radius: var(--r-card);
  background: var(--accent-soft);
}

.wall-invite-title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 700;
}

.wall-invite-body {
  max-width: 40ch;
  color: var(--ink-2);
}

.wall-invite .btn {
  margin-top: var(--s1);
}

/* ── Edit climb: the gym editors' button under the grade ── */

.detail-editor-row {
  display: flex;
  justify-content: flex-end;
}

/* ── Ready for reset: a quiet toggle under Mark as stripped ── */

.detail-reset-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  margin-top: calc(-1 * var(--s3));
}

.detail-reset {
  min-height: 44px;
  font-size: var(--fs-sm);
}

.detail-reset[aria-pressed='true'] {
  border-color: var(--accent-text);
  background: var(--accent-soft);
  color: var(--accent-text);
}

/* ── Wall schedule on cards: "Set Oct 12" and "Down tomorrow" ── */

.wall-card-schedule {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1) var(--s2);
}

.wall-card-set {
  color: var(--ink-2);
  font-size: var(--fs-xs);
  font-weight: 600;
}

.wall-card-reset,
.card-reset {
  justify-self: start;
  align-self: flex-start;
  padding: 2px var(--s2);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: var(--fs-xs);
  font-weight: 600;
}

/* ── Logbook CSV ── */

.logbook-export {
  display: grid;
  justify-items: start;
  gap: var(--s1);
  margin-bottom: var(--s3);
}

.logbook-csv-note:empty {
  display: none;
}

/* ── Wall coverage: "3 of 8 walls have 5 or more climbs" under Walls ── */

.coverage {
  display: grid;
  gap: var(--s2);
  margin-bottom: var(--s4);
}

.coverage-text {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

.coverage-track {
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--line);
  overflow: hidden;
}

.coverage-fill {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--accent);
}

.coverage-more {
  margin: 0;
  font-size: var(--fs-sm);
}

.coverage-more a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--accent-text);
}

/* ── Honesty card: "Share this gym’s grade card" after the compare link ── */

.honesty-share {
  justify-self: start;
  align-self: flex-start;
}

/* ── Still up prompt: "Still up?" above the stars on a forgotten climb ── */

.still-up {
  display: grid;
  gap: var(--s2);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}

.still-up-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 800;
}

.still-up-text {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

.still-up-buttons {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
}

.still-up-buttons .btn {
  min-height: 44px;
}

/* ── Outside grade: the rate sheet's picker and the climb page's block ── */

/* Up to 12 grades (an alias grade like 5.10), so the buttons wrap into
   rows rather than scroll sideways. */
.outside-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(3.75rem, 1fr));
  gap: var(--s1);
  padding: 4px;
  border-radius: var(--r-btn);
  background: var(--surface-2);
}

.outside-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 52px;
  padding: 4px 2px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-weight: 750;
  cursor: pointer;
}

.outside-btn.is-gym {
  box-shadow: inset 0 0 0 1px var(--line);
}

.outside-gym {
  font-size: var(--fs-xs);
  font-weight: 650;
  line-height: 1.15;
  text-align: center;
}

.outside-btn[aria-checked='true'] {
  background: var(--ink);
  color: var(--bg);
}

.detail-outside {
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--surface);
}

/* Grade, bar and count; no shares column, unlike the grade histogram. */
.outside-row {
  grid-template-columns: 4.5em 1fr 2.5em;
}

.outside-bar { background: var(--accent); }

/* The outdoor-equivalent hint under its rate-sheet title. */
.rate-hint {
  margin: 2px 0 var(--s1);
  font-size: 0.875rem;
}

/* ── Custom colour (add climb) ── */

/* Custom… sits last in the colour grid and takes two cells: 18 colours + it
 * fill four rows of five. */
.color-row .pill-custom {
  grid-column: span 2;
}

.color-row .pill-custom .pill-face {
  gap: var(--s2);
  font-size: var(--fs-sm);
}

.color-row .pill-custom.is-picked .pill-face {
  background: var(--surface);
  border: 3px solid var(--ink);
}

.custom-hint:empty {
  display: none;
}

/* The editors' Levels section on the gym page (views/gym-levels.js). */
.gym-levels-discipline {
  display: grid;
  gap: var(--s2);
}

.level-list {
  display: grid;
  gap: var(--s2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.level-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
}

.level-label {
  font-weight: 700;
  overflow-wrap: anywhere;
}

.level-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1);
}

.level-add {
  display: flex;
  gap: var(--s2);
}

.level-add input {
  flex: 1;
  min-width: 0;
}

/* The gym page's walls header and the editors' "Edit walls" sheet
   (views/edit-walls.js). */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
}

.edit-walls-list {
  display: grid;
  gap: var(--s3);
  margin: var(--s3) 0 0;
  padding: 0;
  list-style: none;
}

.edit-walls-row {
  display: grid;
  gap: var(--s2);
  padding-bottom: var(--s3);
  border-bottom: 1px solid var(--line);
}

.edit-walls-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s2);
  margin: 0;
  overflow-wrap: anywhere;
}

.edit-walls-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1);
}

.edit-walls-note {
  display: grid;
  gap: var(--s2);
  justify-items: start;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.edit-walls-note p {
  margin: 0;
}

/* A queued climb whose gym level was removed: pick its grade again
   (views/regrade-queued.js). */
.regrade-box {
  flex-wrap: wrap;
  padding: var(--s3) var(--s4);
}

.regrade-box p {
  flex-basis: 100%;
  margin: 0;
}

.regrade-box select {
  flex: 1;
  min-width: 0;
}

/* Gym page: "Share today’s session" once the climber has ticked here today. */
.session-share-slot:empty {
  display: none;
}

/* ── Friends ── */

.friends {
  display: grid;
  gap: var(--s5);
}

.friends-gate {
  display: grid;
  gap: var(--s3);
}

.friend-rows {
  margin: 0;
  padding: 0;
  list-style: none;
}

.friend-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: var(--tap);
  padding: var(--s2) 0;
}

.friend-row + .friend-row {
  border-top: 1px solid var(--line);
}

.friend-main,
.friend-link {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.friend-link {
  flex: 1;
  color: var(--ink);
  text-decoration: none;
}

.friend-name {
  font-weight: 650;
  overflow-wrap: anywhere;
}

.friend-sub {
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

/* Person cards (views/person-row.js): the Friends lists. The group around
   them is already a card, so each person sits on --surface-2. */
.person-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--tap);
  margin-bottom: var(--s2);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.person-row:last-child {
  margin-bottom: 0;
}

.person-link,
.person-main {
  display: flex;
  flex: 1;
  align-items: center;
  gap: var(--s3);
  min-width: 0;
}

.person-link {
  color: var(--ink);
  text-decoration: none;
}

.person-avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--ink);
  font-weight: 800;
}

.person-thumb {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: var(--r-sm);
  background: var(--line);
  object-fit: cover;
}

.person-text {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.person-name {
  font-size: var(--fs-lg);
  font-weight: 750;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.person-sub {
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

.person-chevron {
  margin-left: auto;
  color: var(--ink-2);
  font-size: 1.5em;
  line-height: 1;
}

.person-gym {
  display: block;
}

.person-time {
  white-space: nowrap;
}

/* "You’re coming" under a friend's day: a small bold pill on its own line. */
.person-badge {
  display: block;
  width: fit-content;
  margin-top: var(--s1);
  padding: 2px var(--s2);
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--fs-xs);
  font-weight: 750;
}

/* Who is coming to one of your days, bold under the gym and time: the
   Friends screen cards and the editor's Next seven days alike. */
.person-coming {
  display: block;
  margin-top: 2px;
  color: var(--ink);
  font-size: var(--fs-md);
  font-weight: 750;
}

/* Friends' climbing days: each date is a bold heading over its cards. */
.friends-day {
  display: grid;
  gap: var(--s2);
}

.friends-day + .friends-day {
  margin-top: var(--s2);
}

.friends-day-date {
  font-size: var(--fs-md);
  font-weight: 750;
}

.friends .group-title {
  margin-bottom: var(--s2);
  font-size: var(--fs-lg);
  font-weight: 800;
}

.field-hint {
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

.field-hint:empty {
  display: none;
}

.friend-prompt-actions,
.friend-actions,
.friend-confirm {
  display: grid;
  gap: var(--s2);
}

.friend-switch[aria-disabled='true'] {
  opacity: 0.45;
  cursor: default;
}

.friend-side-title {
  margin: var(--s2) 0 calc(var(--s3) * -1);
  font-size: var(--fs-lg);
  font-weight: 700;
  overflow-wrap: anywhere;
}

.friend-climbs {
  margin: 0;
  padding: 0;
  list-style: none;
}

.friend-climb + .friend-climb {
  border-top: 1px solid var(--line);
}

.friend-climb-link {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--tap);
  padding: var(--s2) 0;
  color: var(--ink);
  text-decoration: none;
}

.friend-climb-day {
  flex: none;
  min-width: 3.5em;
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

/* ── Check-ins ── */

.check-in-host:empty {
  display: none;
}

.check-in-slot:empty,
.check-in-own:empty,
.check-in-friends-list:empty {
  display: none;
}

.check-in-slot,
.check-in-sheet {
  display: grid;
  gap: var(--s3);
}

.check-in-card {
  display: grid;
  gap: var(--s2);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
}

.check-in-title {
  margin: 0;
  font-weight: 700;
  font-size: var(--fs-lg);
}

.check-in-sub,
.check-in-elsewhere {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

.check-in-friends-list {
  display: grid;
  gap: var(--s2);
}

.check-in-summary,
.check-in-ended {
  margin: 0;
  font-size: var(--fs-sm);
}

.check-in-answer-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s2);
}

.check-in-answer[aria-pressed='true'] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--surface);
}

.check-in-card:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.check-in-answers {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--s1);
}

.check-in-sheet .seg[hidden] {
  display: none;
}

.check-in-friends .seg-label,
.schedule-friends .seg-label {
  flex-direction: row;
  align-items: center;
  gap: var(--s1);
}

.check-in-friends .seg-input:checked + .seg-label::before,
.schedule-friends .seg-input:checked + .seg-label::before {
  content: '✓';
}

.check-in-hint {
  margin: 0;
  text-align: center;
}

.check-in-hint[hidden] {
  display: none;
}

/* ── Usual days ── */

.schedule-day-list,
.schedule-gyms {
  margin: 0;
  padding: 0;
  list-style: none;
}

.schedule-day {
  display: grid;
  justify-items: start;
  gap: var(--s2);
  padding: var(--s2) 0;
}

.schedule-day + .schedule-day {
  border-top: 1px solid var(--line);
}

.schedule-session {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  width: 100%;
}

.schedule-session-gym {
  flex: 1 1 100%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.schedule-time {
  flex: 1 1 9rem;
}

.schedule-repeat {
  flex: 1 1 9rem;
  min-width: 0;
}

.schedule-session .btn-quiet,
.schedule-next .btn {
  flex: none;
  white-space: nowrap;
}

.schedule-next-what {
  overflow-wrap: anywhere;
}

.schedule-next.is-skipped .schedule-next-what {
  color: var(--ink-2);
  text-decoration: line-through;
}

.schedule-skipped {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: var(--s1);
}

.schedule-friends .field-hint {
  margin: 0;
}

.schedule-picker,
.schedule-gym-group,
.schedule-gyms {
  display: grid;
  gap: var(--s2);
}

.schedule-picker {
  gap: var(--s4);
}

.schedule-gym-group .field-label {
  margin: 0;
}

.schedule-gym {
  justify-content: flex-start;
  overflow-wrap: anywhere;
  text-align: left;
}

/* Friends' side: a friend's page and the gym page line. */

.usual-days-host:empty,
.week-here:empty {
  display: none;
}

.usual-day-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.usual-day {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) 0;
}

.usual-day + .usual-day {
  border-top: 1px solid var(--line);
}

.usual-day-what {
  flex: 1 1 auto;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.usual-day-come {
  flex: none;
  white-space: nowrap;
}

.usual-day-come[aria-pressed='true'] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--surface);
}

.week-here {
  margin: 0;
  font-size: var(--fs-sm);
}

/* The week strip: seven owner-local days, today first; highlighted days
   have a session. Seven equal columns fit 390 px with 16 px gutters. */

.week-strip {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--s1);
  margin: 0 0 var(--s2);
  padding: 0;
  list-style: none;
}

.week-strip-day {
  display: grid;
  justify-items: center;
  gap: 2px;
  min-width: 0;
  padding: var(--s1) 0;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
}

.week-strip-day.is-on {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--surface);
}

.week-strip-initial {
  font-size: var(--fs-xs);
  font-weight: 650;
}

.week-strip-date {
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

.week-strip-link {
  display: block;
  margin-top: var(--s2);
  border-radius: var(--r-sm);
  color: inherit;
  text-decoration: none;
}

.week-strip-link .week-strip {
  margin: 0;
}

/* ── Board climbs ── views/board-new.js, board-climb.js, board-fields.js;
 * the hold marks over the photo are under "Hold marks" below. */

.board-new-body,
.board-climb {
  display: grid;
  gap: var(--s5);
}

.board-fixed {
  display: grid;
  gap: var(--s5);
}

.board-fixed select:disabled {
  opacity: 0.6;
}

.board-marks-slot:empty {
  display: none;
}

.board-photo {
  margin: 0;
}

/* The poster's climb with no photo: friends can't see it until it has one. */
.board-no-photo {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border: 2px solid var(--ink);
  border-radius: var(--r-md);
}

.board-no-photo-text {
  font-weight: 700;
}

.board-photo-note {
  margin-top: var(--s2);
  font-weight: 650;
  color: var(--ink-2);
}

.board-climb-title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 800;
  overflow-wrap: anywhere;
}

.board-climb-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3);
  margin-top: calc(-1 * var(--s3));
}

.board-status {
  padding: 4px 12px;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  font-weight: 700;
}

.board-status-sent {
  border-color: transparent;
  background: var(--ink);
  color: var(--bg);
}

.board-climb-gym {
  margin-top: calc(-1 * var(--s3));
  font-weight: 650;
}

/* "Edit marks" hides while the marking editor is open. */
.board-climb .btn[hidden] {
  display: none;
}

.board-taps,
.board-edit {
  display: grid;
  gap: var(--s3);
}

.board-tap[aria-pressed='true'] {
  border-color: transparent;
  background: var(--accent);
  color: var(--accent-ink);
}

.board-tap[aria-pressed='true']::before {
  content: '✓ ';
}

/* ── Hold marks ── views/board-marks.js. Each role has its own colour AND
 * its own line (start solid, hand dashed, foot dotted, finish dash-dot), so
 * none relies on colour alone. A dark halo under every line keeps it legible
 * on any photo. Line widths and dashes are set by board-marks.js (divided
 * by the zoom, board-shapes.js markStroke); only colours live here. */

:root {
  --mark-start: #13994f;
  --mark-hand: #2a64e0;
  --mark-foot: #d98a00;
  --mark-finish: #c42a8e;
  --mark-halo: rgba(8, 20, 17, 0.72);
  --mark-halo-selected: #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --mark-start: #3fd384;
    --mark-hand: #6f9bff;
    --mark-foot: #ffc44a;
    --mark-finish: #f264c4;
  }
}

:root[data-theme='dark'] {
  --mark-start: #3fd384;
  --mark-hand: #6f9bff;
  --mark-foot: #ffc44a;
  --mark-finish: #f264c4;
}

.marks-view,
.marks-editor,
.board-marks-edit {
  display: grid;
  gap: var(--s3);
}

/* The frame takes the photo's shape (--photo-ratio, set when it loads) and
 * fits in 70% of the screen's height, so the overlay lines up with it. */
.marks-stage {
  position: relative;
  overflow: hidden;
  width: min(100%, calc(70vh * var(--photo-ratio, 1.333)));
  margin-inline: auto;
  border-radius: var(--r-lg);
  background: var(--surface-2);
}

.marks-content {
  position: relative;
  transform-origin: 0 0;
}

.marks-photo {
  display: block;
  width: 100%;
  height: auto;
}

.marks-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.marks-svg.is-hidden {
  display: none;
}

/* Only the photo being marked takes every touch: one finger draws, two
 * zoom. The rest of the page scrolls as usual. */
.marks-stage.is-editable {
  touch-action: none;
  cursor: crosshair;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.marks-stage.is-editable .marks-photo {
  pointer-events: none;
}

.marks-svg ellipse,
.marks-svg polyline,
.mark-sample line {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.mark-halo {
  stroke: var(--mark-halo);
}

.mark-group.is-selected .mark-halo {
  stroke: var(--mark-halo-selected);
}

.mark[data-role='start'],
.marks-preview[data-role='start'] { stroke: var(--mark-start); }
.mark[data-role='hand'],
.marks-preview[data-role='hand'] { stroke: var(--mark-hand); }
.mark[data-role='foot'],
.marks-preview[data-role='foot'] { stroke: var(--mark-foot); }
.mark[data-role='finish'],
.marks-preview[data-role='finish'] { stroke: var(--mark-finish); }

.marks-preview {
  opacity: 0.9;
}

.mark-sample {
  flex: none;
  width: 36px;
  height: 12px;
  overflow: visible;
}

.marks-chips {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s2);
}

.marks-chip {
  display: grid;
  justify-items: center;
  gap: var(--s1);
  min-height: 60px;
  padding: var(--s2) var(--s1);
  border: 2px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 750;
  cursor: pointer;
}

.marks-chip[aria-pressed='true'] {
  border-color: var(--ink);
  background: var(--surface-2);
  box-shadow: inset 0 0 0 1px var(--ink);
}

.marks-chip:focus-visible,
.marks-key:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.marks-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
}

.marks-bar .btn:disabled {
  opacity: 0.5;
}

.marks-summary {
  flex: 1 1 auto;
  font-weight: 700;
}

.marks-note:empty {
  display: none;
}

.marks-note {
  font-weight: 650;
  color: var(--ink-2);
}

/* A button per mark, for the keyboard: hidden until one has focus. */
.marks-keys:not(:focus-within) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.marks-keys {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.marks-key {
  min-height: var(--tap);
  padding: 0 var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-weight: 650;
}

.marks-key[aria-pressed='true'] {
  border-color: var(--ink);
  background: var(--surface-2);
}

.marks-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.marks-legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-weight: 650;
}

/* ── Climbs on the wrong wall (views/wrong-wall.js, views/climb-picker.js) ── */

.off-wall-banner.is-lost {
  border: 2px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
}

.wrong-wall {
  display: grid;
  gap: var(--s2);
  justify-items: center;
}

.wrong-wall-row {
  display: grid;
  gap: var(--s1);
  justify-items: center;
  width: 100%;
  text-align: center;
}

.wrong-wall-row .group-text {
  margin: 0;
}

.wrong-wall-sheet,
.picker,
.picker-list {
  display: grid;
  gap: var(--s2);
}

.wrong-wall-sheet .sheet-title,
.picker .sheet-title {
  margin: var(--s1) 0 0;
}

.wrong-wall-reason {
  min-height: calc(var(--tap) + var(--s3));
  font-size: var(--fs-md);
  font-weight: 700;
}

.picker-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.picker-wall {
  justify-content: flex-start;
  overflow-wrap: anywhere;
  text-align: left;
}

/* A climb as a card row: photo, colour name beside its swatch, grade. */
.picker-climb {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.picker-climb:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.picker-photo {
  width: 4.5rem;
  height: 6rem;
  border-radius: var(--r-sm);
  object-fit: cover;
}

.picker-no-photo {
  display: grid;
  place-items: center;
  border: 1px dashed var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: var(--fs-xs);
  text-align: center;
}

.picker-climb-text {
  display: grid;
  gap: var(--s1);
  min-width: 0;
}

.picker-colour {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fs-md);
}

.picker-climb-text .grade {
  justify-self: start;
}

.wrong-wall-question {
  margin: 0;
  font-size: var(--fs-md);
}
