/* Event list rows, lifecycle stamps, and shared route/RSVP/roster primitives. */

/* photos.css's .photo-grid is shared with discussions/profiles too -- scope a larger
   tile size to events pages only rather than changing the shared default. */
.events-flat .photo-grid {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.1rem;
}

/* A lone full-width photo becomes an oversized empty-looking slab at the desktop
   reading measure.  Keep multi-photo galleries fluid, but give the one-photo case a
   deliberate editorial width; on phones this still fills the available column. */
.events-flat .photo-grid:has(> .photo-item:only-child) {
  grid-template-columns: minmax(0, 24rem);
  justify-content: start;
}

/* Reusable rotated status stamp. */
.stamp {
  display: inline-block;
  vertical-align: middle;
  font-family: 'Staatliches', sans-serif;
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  padding: 0.14rem 0.55rem;
  border: 1px solid var(--pop-dim);
  /* Opaque backing -- these sit right on a card's top edge and were letting whatever's
     behind (border lines, content) show through the middle, garbling the text. */
  background: var(--bg);
  color: var(--pop);
  border-radius: 0.15rem;
  transform: rotate(-4deg);
}

.stamp-past {
  border-color: var(--seam);
  color: var(--muted);
  /* Rotated the opposite way from a live .stamp (and from the h2 "Past" section stamp
     above it) -- same rotation direction as those made the per-item Past badge read as
     a redundant echo of the heading right above it instead of its own label. */
  transform: rotate(3deg);
}

/* In-progress uses the theme's yellow/limited-route accent -- a genuinely different hue
   from both the live-upcoming (--pop) and past (--muted) stamps. */
.stamp-progress {
  border-color: var(--pop-dim);
  color: var(--pop);
  background: color-mix(in srgb, var(--pop) 12%, var(--bg));
}

/* Cancelled pairs a genuinely different color (danger red) with the word "Cancelled" --
   never color alone. */
.stamp-cancelled {
  border-color: var(--error);
  color: var(--error);
}

/* Compact fact chip (camping, "download only", file kind) -- distinct from a stamp
   (durable lifecycle/role label): a badge is a quiet supporting fact, not a status. */
.badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 0.15rem;
  border: 1px solid var(--seam);
  background: var(--bg-2);
  color: var(--text);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

/* Pinned to a card/list-item corner (relies on .list li's position: relative) so it
   reads as a label stamped onto the entry, not as part of the title/button flow next to
   it. Used outside events too (e.g. inbox "Read"). */
.corner-badge {
  position: absolute;
  top: -0.55rem;
  right: 0.8rem;
}

/* --- Events editorial primitives ------------------------------------------------
   Flat, ruled Event layout -- events never put a card inside a card, and an events h2 is a plain flat section label, not the
   site's default rotated-stamp h2 (that stays for discussions/profiles/landing).

   The mockup's own page sits its flat/ruled rows on ITS page background (--cream),
   distinct from the paper each boxed component uses -- on the real site the
   equivalent is one bordered --panel sheet holding the whole flat layout, set here
   once, so the rows inside stay unboxed without floating directly on the site's
   textured --bg body backdrop the way every other page's .card normally prevents. */
.events-flat {
  padding: 1.25rem;
  border: 2px solid var(--text);
  background: var(--panel);
  margin-bottom: 1rem;
}

.events-flat h1 {
  color: var(--text);
}

.event-page-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.event-page-header h1 { margin: 0; }
.event-page-header .viewall { margin: 0; }

.events-flat h2 {
  display: block;
  width: auto;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--text);
  font-family: 'Rajdhani', 'Work Sans', sans-serif;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: none;
  transform: none;
}

/* Events forms use the moss rule and distinct field surface from the approved
   mockup.  Keep this scoped: neutral seams remain the shared-site default. */
.events-flat input,
.events-flat textarea,
.events-flat select {
  border-color: var(--accent-dim);
}

.events-flat input:focus-visible,
.events-flat textarea:focus-visible,
.events-flat select:focus-visible {
  border-color: var(--accent);
}

.event-section {
  padding-top: 1rem;
  border-top: 2px solid var(--text);
}

.event-section:first-child,
.event-hero + .event-section {
  border-top: 0;
  padding-top: 0;
}

details.event-section {
  padding-bottom: 1rem;
}

/* The ride description is the organizer's own writing: the blank line they left between
   the meeting plan and the gear list is structure, and collapsing it ran the whole thing
   into one block (feedback #131). `anywhere` keeps a pasted URL from pushing the page
   sideways on a phone. */
.event-description {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- Events list sections -- see events/list.html --------------------------------
   Upcoming and Past are two different jobs (deciding on a ride vs. remembering one),
   and a plain heading with a rule between them read as one continuous stream on a
   phone. Each section now opens with a bar that bleeds past .events-flat's padding:
   evergreen for the live planning surface, ruled paper for the log. */

.event-section-block + .event-section-block {
  margin-top: 1.6rem;
}

.event-section-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.7rem;
  margin: 0 -1.25rem;
  padding: 0.55rem 1.25rem 0.7rem;
  background: var(--panel-2);
}

.event-section-bar h2 {
  margin: 0;
  color: var(--accent-contrast);
  font-size: 1.05rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.event-section-count {
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: color-mix(in srgb, var(--accent-contrast) 72%, transparent);
}

.event-section-bar-quiet {
  background: var(--bg-2);
  border-top: 2px solid var(--text);
  border-bottom: 2px solid var(--text);
}

.event-section-bar-quiet h2 {
  color: var(--text);
}

.event-section-bar-quiet .event-section-count {
  color: var(--muted);
}

/* The two create actions were .add-link text set beside the heading -- easy to miss,
   and never aligned with anything. They are a real button now: full width under the
   heading on a phone, tucked into the bar once there is room for it. */
.event-section-action {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  margin-top: 0.2rem;
  padding: 0 1rem;
  border: 2px solid var(--text);
  border-radius: 0.15rem;
  background: var(--action);
  color: var(--action-contrast);
  font-family: 'Rajdhani', 'Work Sans', sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  text-transform: none;
}

.event-section-action:hover,
.event-section-action:focus-visible {
  background: var(--action-hover);
  text-decoration: none;
}

/* Logging a past ride is the quieter of the two -- one primary action per screen. */
.event-section-action-quiet {
  border: 1px solid var(--accent-dim);
  background: none;
  color: var(--text);
}

.event-section-action-quiet:hover,
.event-section-action-quiet:focus-visible {
  background: color-mix(in srgb, var(--accent-dim) 12%, transparent);
  border-color: var(--muted);
}

.event-section-empty {
  margin: 0.9rem 0 0;
}

/* --- Upcoming ride card -- see events/_event_list_row.html's event_card() ---------
   An upcoming ride is a decision, so it gets the space: cover photo, countdown, the
   handful of facts worth deciding on, and RSVP without leaving the list. */

.event-card {
  padding: 1.1rem 0 1.25rem;
  border-top: 1px solid var(--divider);
}

.event-section-bar + .event-card {
  border-top: 0;
}

/* The cover bleeds to the sheet's edges like the section bar above it, so the photo
   is a band across the page rather than an inset tile with ragged margins. */
.event-card-frame {
  position: relative;
  margin: 0 -1.25rem;
  background: var(--bg-2);
}

.event-card-cover {
  display: block;
  width: 100%;
  /* Fixed ratio + cover: a portrait photo crops to the same band as a landscape one
     instead of deciding the card's height. */
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.event-card-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.event-card-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 2.5rem 1.25rem 0.8rem;
  /* Dark enough at the baseline for white text over any photo -- a bright sky in the
     bottom third is the common case here. */
  background: linear-gradient(to top, rgba(10, 16, 12, 0.9), rgba(10, 16, 12, 0.55) 45%, rgba(10, 16, 12, 0));
  color: var(--accent-contrast);
}

/* No cover photo: the caption is simply the card's head, on paper. A full-width
   hatched placeholder would spend the most space on the least information. */
.event-card-frame-plain {
  margin: 0;
  background: none;
}

.event-card-frame-plain .event-card-caption {
  position: static;
  padding: 0;
  background: none;
  color: var(--text);
}

.event-card-when {
  margin: 0;
  font-family: 'Space Mono', ui-monospace, monospace;
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--accent-contrast) 85%, transparent);
}

.event-card-frame-plain .event-card-caption .event-card-when {
  /* The theme's ride accent, distinct from both link orange and body ink. */
  color: var(--event);
}

.event-card-title {
  margin: 0.18rem 0 0;
  font-family: 'Rajdhani', 'Work Sans', sans-serif;
  font-weight: 700;
  font-size: 1.35rem;
  line-height: 1.1;
}

/* Ride titles are sentence case: they are names, not the uppercase nav/link labels the
   site's base `a` rule assumes. */
.event-card-title a {
  color: var(--accent-contrast);
  text-transform: none;
  letter-spacing: 0.01em;
}

.event-card-title a:hover,
.event-card-title a:focus-visible {
  color: var(--action);
}

.event-card-frame-plain .event-card-title a {
  color: var(--accent);
}

.event-card-frame-plain .event-card-title a:hover,
.event-card-frame-plain .event-card-title a:focus-visible {
  color: var(--accent-hover);
}

.event-card-description {
  margin: 0.6rem 0 0;
  font-size: 0.86rem;
  /* Two lines is enough to tell whether this is the ride you were thinking of; the
     rest is one tap away. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.event-card-rsvp {
  margin-top: 0.7rem;
}

/* --- Fact chips -- the old two-column <dl> of Meeting location / Date / Meet time /
   End time / Organized by. Five labelled rows per event made the list a wall of text
   where the labels outweighed the facts. The location chip is also where a map-picked
   place will land once "choose on map" exists. --- */

.event-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.7rem;
}

.event-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.12rem 0.45rem;
  border: 1px solid var(--seam);
  border-radius: 0.15rem;
  background: var(--field-bg);
  color: var(--text);
  font-size: 0.72rem;
}

.event-chip-icon {
  flex-shrink: 0;
  width: 0.72rem;
  height: 0.72rem;
  color: var(--muted);
}

/* --- Ride log -- see events/_event_list_row.html's event_log_row() ----------------
   A past ride is a memory, not a decision: where it was, when, and how many photos
   came back. Meet time, end time and organizer are gone from here entirely. One row
   is one tap target, two lines tall, the same height for every ride. */

.event-log-month {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1.1rem 0 0;
  font-family: 'Space Mono', ui-monospace, monospace;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.event-log-month::after {
  content: "";
  flex-grow: 1;
  height: 1px;
  background: var(--divider);
}

.event-log-row {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  align-items: center;
  gap: 0.7rem;
  margin: 0 -0.5rem;
  padding: 0.6rem 0.5rem;
  border-top: 1px solid var(--divider);
  color: var(--text);
  text-transform: none;
}

.event-log-month + .event-log .event-log-row:first-child {
  border-top: 0;
}

.event-log-row:hover,
.event-log-row:focus-visible {
  background: color-mix(in srgb, var(--accent-dim) 9%, transparent);
  text-decoration: none;
}

.event-log-thumb {
  display: block;
  width: 3.5rem;
  height: 3.5rem;
  overflow: hidden;
  border-radius: 0.15rem;
  background: var(--bg-2);
}

.event-log-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.event-log-thumb-empty {
  border: 1px solid var(--seam);
  background: repeating-linear-gradient(
    -45deg,
    var(--bg-2) 0 8px,
    var(--panel) 8px 16px
  );
}

.event-log-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.event-log-title {
  font-family: 'Rajdhani', 'Work Sans', sans-serif;
  font-weight: 700;
  font-size: 1.02rem;
  line-height: 1.15;
  color: var(--accent);
  /* One line, always: the log's whole value is scanning twenty rides at once, and a
     wrapping title makes every row a different height. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.event-log-row:hover .event-log-title,
.event-log-row:focus-visible .event-log-title {
  color: var(--accent-hover);
}

.event-log-meta {
  font-size: 0.72rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.event-log-date {
  font-family: 'Space Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Visually distinguish cancelled rows without hiding them -- the stamp and note text
   already carry the meaning; this is reinforcement, not the only signal. */
.event-log-row-cancelled {
  opacity: 0.8;
}

.event-log-row-cancelled .event-log-title {
  color: var(--muted);
  text-decoration: line-through;
}

.event-log-row-cancelled .event-log-thumb img {
  filter: grayscale(60%);
}

/* Inline in the fact line, not rotated over the row: a log row is two lines tall and a
   rotated stamp would collide with the row above it. */
.event-log-stamp {
  transform: none;
  padding: 0 0.3rem;
  font-size: 0.62rem;
  vertical-align: baseline;
}

/* The site's reading column tops out at 40rem (see chrome.css's main), so this is the
   only step the list needs -- not a desktop layout, just the point where the phone
   compromises stop paying for themselves. */
@media (min-width: 42rem) {
  .event-section-action {
    flex-basis: auto;
    min-height: 2.25rem;
    margin: 0 0 0 auto;
    border-width: 1px;
  }

  /* The cover moves beside the text and the caption comes off the photo: at this width
     a full-bleed 16/9 band spends a third of the screen on one ride. */
  .event-card:has(.event-card-cover) {
    display: grid;
    grid-template-columns: 14rem minmax(0, 1fr);
    column-gap: 1.1rem;
    align-items: start;
  }

  .event-card:has(.event-card-cover) .event-card-frame {
    display: contents;
  }

  .event-card:has(.event-card-cover) .event-card-cover {
    grid-column: 1;
    grid-row: 1 / span 5;
    aspect-ratio: 4 / 3;
    border-radius: 0.15rem;
  }

  .event-card:has(.event-card-cover) .event-card-caption {
    position: static;
    grid-column: 2;
    padding: 0;
    background: none;
    color: var(--text);
  }

  .event-card:has(.event-card-cover) .event-card-when {
    color: var(--event);
  }

  .event-card:has(.event-card-cover) .event-card-title a {
    color: var(--accent);
  }

  .event-card:has(.event-card-cover) .event-card-title a:hover,
  .event-card:has(.event-card-cover) .event-card-title a:focus-visible {
    color: var(--accent-hover);
  }

  .event-card:has(.event-card-cover) .event-facts,
  .event-card:has(.event-card-cover) .event-card-description,
  .event-card:has(.event-card-cover) .event-card-rsvp {
    grid-column: 2;
  }

  .event-log-row {
    grid-template-columns: 4rem minmax(0, 1fr);
  }

  .event-log-thumb {
    width: 4rem;
    height: 4rem;
  }
}

/* --- RSVP controls -- three equal always-visible choices, see
   events/_rsvp_controls.html --- */

.rsvp-form {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 0.4rem;
  margin: 0.6rem 0 0;
}

.rsvp-form .btn,
.rsvp-form button {
  margin: 0;
  min-height: 2.6rem;
  padding: 0.4rem;
  text-align: center;
  font-size: clamp(0.68rem, 3vw, 0.85rem);
}

.rsvp-selected {
  background: var(--action);
  color: var(--action-contrast);
  border-color: var(--text);
}

.rsvp-counts {
  color: var(--muted);
  margin: 0.2rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

/* --- Route summary/manage -- see events/_route_summary.html, events/edit.html --- */

/* Mockup's .route-card: the map/stats/profile sit in one tinted, bordered box nested
   inside the flat Route section -- the one deliberate nested-border exception. The file
   downloads live below the card, next to the Gaia link. */
.route-card {
  padding: 0.85rem;
  background: color-mix(in srgb, var(--accent-dim) 12%, var(--panel));
  border: 1px solid var(--accent-dim);
}

.route-card .route-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
  margin: 0.65rem 0;
}

.route-card .route-stat {
  background: var(--panel);
  padding: 0.5rem;
  text-align: left;
  font-size: 0.8rem;
}

.route-card .route-stat .value {
  display: block;
  font-size: 1.1rem;
}

.elevation-profile {
  display: block;
  width: 100%;
  /* Half the 9rem this used to be. The SVG's viewBox uses preserveAspectRatio="none", so
     this squashes the trace vertically rather than cropping it -- the whole profile is
     still there, just spending less of the page on a shape you read at a glance. */
  height: 4.5rem;
  margin-top: 0.75rem;
  /* Pine, not the near-white form-field surface -- the profile is a picture, not an
     input, and on the light preset a white panel made it the brightest thing in the route
     card. --panel-2 is the theme's dark tone in every preset, so this needs no new colour;
     the trace switches to --chart-line to stay legible on it. */
  background: var(--panel-2);
  border: 1px solid var(--seam);
  border-radius: 0.2rem;
}

/* Flat fileline rows (mockup's .fileline/.files), not the generic site .list li's own
   mini-card -- avoids boxing a list inside the already-boxed .route-card/.events-flat. */
.events-flat .list {
  gap: 0;
}

.events-flat .list li {
  padding: 0.6rem 0;
  border-radius: 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--seam);
}

.events-flat .list li:last-child {
  border-bottom: 0;
}

/* On detail the list sits between the route card and the Gaia link, so it needs its own
   breathing room rather than the padding it used to inherit from inside the card. */
.route-card + .route-file-list {
  margin-top: 0.85rem;
}

.route-file-list li {
  position: relative;
}

.route-file-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.4rem;
}

.route-file-actions form {
  display: contents;
}

.route-file-actions button {
  margin: 0;
}

/* --- Ride roster -- see events/_ride_roster.html ---
   One row per person: name, then their tags. Wraps rather than truncating, since a long
   username plus two tags doesn't fit a 384px phone on one line. */

.roster-list {
  margin-bottom: 0;
}

.roster-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

/* Role (Owner/Admin) is the quieter of the two tags: it's a durable fact about the
   person, where the RSVP is the thing being scanned for. */
.roster-role {
  color: var(--muted);
}

/* Never colour alone (WCAG 1.4.1) -- each tag says its own word. The hues just make the
   three answers separable at a glance down a list. */
.roster-rsvp-going {
  border-color: var(--success);
  color: var(--success);
}

.roster-rsvp-interested {
  border-color: var(--pop-dim);
  color: var(--pop);
}

.roster-rsvp-none {
  color: var(--muted);
}

/* --- Detail hero -- the share card in HTML: the ride's cover photo as the backdrop,
   its title over it, its facts as a row of figures. See events/detail.html for why, and
   app/events/og_image.py for the rendered PNG this mirrors.

   Two treatments from one block of markup. With a cover photo the band is the photo,
   darkened by .event-hero-scrim; without one it is the flat --panel-2 header it has
   always been. --panel-2 is already the theme's darker panel tone in every palette
   (pine-green in the default), so neither needs a hardcoded color. --- */

.event-hero {
  margin: -1.25rem -1.25rem 1rem;
  background: var(--panel-2);
  color: var(--accent-contrast);
  border-bottom: 2px solid var(--text);
  overflow: hidden;
}

.event-hero-cover {
  display: block;
  width: 100%;
  /* Tall, and the same ratio at every width, because the reading column is capped at
     ~38rem even on a 1920px screen -- the hero is a narrow column everywhere, never a
     wide band. A 21/9 hero looked right in the abstract and gave a 259px photo carrying
     a 216px block of text: no photo left. 4/5 clears the text with room to spare, and
     max-height stops a phone spending its whole first screen on the picture. */
  aspect-ratio: 4 / 5;
  max-height: 30rem;
  object-fit: cover;
}

/* The photo is a backdrop for cream text, and we don't get to choose the photo -- a
   washed-out sky or a snow shot has to hold 4.5:1 just like a dark forest one. So the
   scrim is graded rather than uniform: barely there at the top where nothing sits, and
   opaque --panel-2 by the bottom, which is where the title and figures are. The figures
   read against solid pine, exactly as they do on the PNG. */
.event-hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--panel-2) 30%, transparent) 0%,
    color-mix(in srgb, var(--panel-2) 55%, transparent) 38%,
    color-mix(in srgb, var(--panel-2) 93%, transparent) 74%,
    var(--panel-2) 100%
  );
}

/* The photo, its scrim and the text on it. The footer is deliberately outside this box:
   anchoring the body to the bottom of the whole <header> put it on top of the footer. */
.event-hero-media {
  position: relative;
}

/* Over the photo when there is one, in normal flow when there isn't. */
.event-hero.has-cover .event-hero-body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
}

.event-hero-body {
  padding: 1.25rem 1.25rem 1rem;
}

.event-hero-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}

.event-hero h1 {
  margin: 0 0 0.3rem;
  color: var(--accent-contrast);
  /* Two long words of a ride name shouldn't push the figures off the photo. */
  overflow-wrap: anywhere;
}

.event-hero-place {
  margin: 0 0 0.9rem;
  font-size: 0.9rem;
  color: color-mix(in srgb, var(--accent-contrast) 76%, transparent);
}

.event-calendar-link {
  color: var(--accent-contrast);
  font-size: 0.76rem;
  white-space: nowrap;
}

/* The figure row, same wording and order as the PNG's -- see events/routes.py's
   _hero_figures. Wraps rather than scrolls: four figures with a long date span do not
   fit one 360px line, and a row you have to swipe hides the one you wanted. */
.event-figures {
  display: flex;
  flex-wrap: wrap;
  /* 1rem, not the 1.4rem this started at: three figures plus their gaps came to 315px
     against the 299px a 390px phone actually leaves inside the hero, so the date wrapped
     onto a line of its own on every ride. The row still wraps for a genuinely wide value
     like a cross-month span, which is what wrapping is for. */
  gap: 0.4rem 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.event-figure {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  /* Keeps a wrapped row lined up in columns instead of ragged. */
  min-width: 5rem;
}

.event-figure .value {
  font-size: 1.6rem;
  line-height: 1;
  color: var(--action);
}

.event-figure .label {
  font-size: 0.62rem;
  letter-spacing: 0.09em;
  color: var(--accent-contrast);
}

/* The date's label is the departure time -- the one thing in the row people come back to
   check -- so it reads at body size rather than as a small-caps caption (feedback #136).
   At that size it no longer fits beside distance and elevation on a phone, so it takes
   its own line there on purpose instead of wrapping under one of them. */
.event-figure-when {
  flex-basis: 100%;
}

.event-figure-when .label {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.event-hero-camping {
  margin: 0.75rem 0 0;
  font-size: 0.7rem;
  letter-spacing: 0.09em;
  color: var(--action);
}

/* Below the photo, on the band's own surface: the organizer's own words, and the actions
   -- which belong within thumb reach at the bottom rather than floating over the middle
   of a picture. A column, so the description always sits above the buttons. */
.event-hero-footer {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: 0.9rem 1.25rem 1.1rem;
  background: var(--panel-2);
}

.event-hero-footer .muted {
  margin: 0;
  font-size: 0.78rem;
  color: color-mix(in srgb, var(--accent-contrast) 75%, transparent);
}

/* The description was its own card three scrolls down the page; it belongs to the ride's
   pitch, so it is on the band under the figures.

   It needs ruling off at both ends to be prose rather than another stats line: dropped
   onto the band bare it ran out of the figures above and into the buttons below, and the
   whole footer read as one undifferentiated block. The rules bleed past the band's
   padding to its full width -- a divider that stops short of the edges reads as a box
   someone forgot to finish. The negative margins have to stay equal to
   .event-hero-footer's horizontal padding, including in the wide-viewport override. */
.event-hero-note {
  margin: 0 -1.25rem;
  padding: 0.9rem 1.25rem 1rem;
  border-top: 1px solid color-mix(in srgb, var(--accent-contrast) 22%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--accent-contrast) 22%, transparent);
}

/* The figures' eyebrow, reused: same size and tracking as MILES and FT MAX ELEV, so the
   hero stays one set of labelled facts rather than growing a heading level. Every h2
   property .events-flat h2 sets has to be overridden here -- it paints body --text,
   which is invisible on the band. */
.event-hero-note-label {
  margin: 0 0 0.45rem;
  color: var(--accent-contrast);
  font-family: inherit;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* A max width so a long paragraph doesn't run the full width of a desktop window, and
   the hero's own light ink rather than body --text. .event-description carries the
   pre-wrap that keeps the organizer's line breaks (feedback #131). */
.event-hero-description {
  margin: 0;
  max-width: 62ch;
  color: color-mix(in srgb, var(--accent-contrast) 90%, transparent);
  font-size: 0.92rem;
  line-height: 1.65;
}

/* Base link color (--accent, orange) is hard to read on the dark evergreen hero --
   same override pattern as landing.css's .moss-line. */
.event-hero a:not(.btn):not(.event-calendar-link) {
  color: var(--accent-contrast);
  text-decoration: underline;
}

.event-hero a:not(.btn):not(.event-calendar-link):hover,
.event-hero a:not(.btn):not(.event-calendar-link):focus-visible {
  color: var(--action);
}

.event-hero-actions {
  display: flex;
  flex-wrap: wrap;
  /* flex-start, not center: the Share control is a <form> that grows a labelled URL line
     under its button on the no-JS path (see .hero-share), and centring that taller item
     pushed RSVP and Manage down out of line with the Share button beside them. Every item
     is the same height in the normal case, so this changes nothing there. */
  align-items: flex-start;
  gap: 0.5rem;
}

.event-hero-actions .btn {
  margin: 0;
  border-color: var(--accent-contrast);
  color: var(--accent-contrast);
}

.event-hero-actions .btn.primary {
  background: var(--action);
  border-color: var(--action);
  color: var(--action-contrast);
}

/* A very short viewport can't spare a 4/5 photo before the title even appears. */
@media (max-height: 34rem) {
  .event-hero-cover {
    aspect-ratio: 16 / 9;
  }
}

@media (min-width: 42rem) {
  .event-hero-body {
    padding: 1.5rem;
  }

  .event-hero h1 {
    font-size: 2.4rem;
  }

  /* Bigger figures want more air between them, and the column is wide enough here. */
  .event-figures {
    column-gap: 1.75rem;
  }

  .event-figure .value {
    font-size: 2.1rem;
  }

  .event-figure .label {
    font-size: 0.68rem;
  }

  .event-figure-when {
    flex-basis: auto;
  }

  .event-figure-when .label {
    font-size: 0.95rem;
  }

  .event-hero-footer {
    padding: 1rem 1.5rem 1.1rem;
  }

  /* Kept equal to the footer's padding above, or the rules stop short of the band. */
  .event-hero-note {
    margin: 0 -1.5rem;
    padding-right: 1.5rem;
    padding-left: 1.5rem;
  }
}

/* --- Manage page -- staged fieldset-style sections rather than a stack of card
   panels; each keeps its own <form> (independent routes/behavior), but is styled as
   one flat rule-separated block, see events/edit.html --- */

.manage-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  margin: 0.75rem 0 0;
  padding-bottom: 0.5rem;
  border-bottom: 2px solid var(--text);
}

.manage-nav a {
  font-size: 0.85rem;
  font-weight: 700;
}

.manage-section {
  padding: 1.1rem 0;
  border-top: 2px solid var(--text);
}

.manage-section:first-of-type {
  border-top: 0;
}

.manage-section > h2 {
  font-size: 1.1rem;
}

.manage-section.danger-zone {
  padding: 1.1rem;
  margin-top: 1.1rem;
  border: 2px solid var(--error);
  background: color-mix(in srgb, var(--error) 8%, var(--panel));
}

/* --- Detail page's collapsible sections -- native <details>, see events/detail.html --- */

/* `display: block` drops the native disclosure triangle, so these headings have to bring
   their own affordance -- without one they read as plain headings and nobody knows to
   press them. That went unnoticed while every section defaulted to `open` (the marker
   only tells you about state you can already see); the Share section starts closed, so a
   section that looks inert but isn't became a real dead end. */
.details-summary {
  display: block;
  cursor: pointer;
  font-family: 'Rajdhani', 'Work Sans', sans-serif;
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  margin: 1rem 0 0.25rem;
  color: var(--text);
}

.details-summary::before {
  content: "";
  display: inline-block;
  width: 0.42em;
  height: 0.42em;
  margin-right: 0.5em;
  vertical-align: middle;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: translateY(-0.12em) rotate(-45deg);
  transition: transform 120ms ease-out;
}

details[open] > .details-summary::before {
  transform: translateY(-0.18em) rotate(45deg);
}

/* Safari still paints its own marker next to a block summary unless this is spelled out. */
.details-summary::-webkit-details-marker {
  display: none;
}

.details-summary:hover {
  color: var(--accent);
}

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

.details-summary:focus-visible {
  outline-offset: 4px;
}

/* --- Share links: the member-facing share block, and the public page it opens --- */

/* Marks the public teaser page (events/shared.html) as what it is, next to the ordinary
   lifecycle stamp -- a visitor arriving cold from a text message has no nav context to
   tell them they're seeing a preview rather than the whole ride. Neutral on purpose: the
   lifecycle stamp beside it owns the color. */
.stamp-shared {
  border-color: var(--seam);
  color: var(--muted);
  transform: rotate(2deg);
}

/* Share, in the hero's action bar. It used to be a whole section at the foot of the page
   -- heading, policy paragraph, a link-styled control and the URL -- whose control shared
   the base `button` background and so flooded orange on hover. It is one ordinary button
   among the others now; the policy and the revoke moved to the Manage page.

   margin-left: auto pushes it to the right end of the bar, which is what makes the two
   label states work: "Copied to clipboard" is three times the width of "Share", and from
   the right end it grows leftward into empty space instead of shoving RSVP and Manage
   along. On a narrow screen the bar wraps and it is right-aligned on its own line, where
   the same thing holds. On a past ride there is no RSVP and no Manage, so Share is the
   only control there is -- one button pushed to the far right of an otherwise empty bar
   reads as misplaced, so it stays where it lands. */
.hero-share {
  margin: 0;
  max-width: 100%;
}

.hero-share:not(:only-child) {
  margin-left: auto;
}

.share-copy {
  gap: 0.45rem;
  white-space: nowrap;
}

/* Two glyphs in one slot -- share_link.js sets .is-copied and the tick replaces the
   arrow, so the confirmation reads as the same control answering rather than a new one. */
.share-icon {
  flex: none;
}

.share-icon-done,
.share-copy.is-copied .share-icon-send {
  display: none;
}

.share-copy.is-copied .share-icon-done {
  display: block;
}

/* The fallback line, revealed only when the clipboard is refused (share_link.js), so it
   hangs under the button rather than sitting in the bar. */
.hero-share .share-link-line {
  margin: 0.4rem 0 0;
}

.hero-share .share-link-label,
.hero-share .share-link-input {
  color: var(--accent-contrast);
}

/* The URL is reference material, not the interface: a small labelled line under the
   button rather than the row of controls it used to be. */
.share-link-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.75rem;
}

.share-link-line[hidden] {
  display: none;
}

.share-link-label {
  font-size: 0.8rem;
  color: var(--muted);
}

/* Grows to fill the row but stays readable on a phone, where the flex row wraps and the
   input takes the full width on its own line.

   No font-family override here: body is already Space Mono. The one that used to sit on
   this rule restacked the token onto a fallback face whose underscores landed flush on
   the field's own bottom border, so a token like "N_mFpLLg" read as "N mFpLLg" -- an
   invisible character in a string people do retype by hand. The line-height and the
   extra bottom padding are what hold the underscore clear of that border; tightening
   them back up brings the bug back. */
.share-link-input {
  flex: 1 1 18rem;
  min-width: 0;
  font-size: 0.8rem;
  line-height: 1.7;
  padding-bottom: 0.7rem;
  color: var(--muted);
  background: none;
  border: none;
  border-bottom: 1px solid var(--seam);
  border-radius: 0;
}

/* A route row on the public page that needs an account: greyed to read as unavailable,
   but a real link to the login page, so pressing the greyed thing goes somewhere instead
   of doing nothing the way a disabled button would. Each such row only renders when the
   thing behind it actually exists -- see sharing._public_route_teaser. */
.route-locked {
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px dashed var(--seam);
}

.route-locked:hover,
.route-locked:focus-visible {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* Every "log in to see the rest" line on the public page: one consistent treatment, so
   the gates read as one rule rather than as a scattering of unrelated notes. */
.share-gate {
  border-left: 2px solid var(--seam);
  padding-left: 0.75rem;
}

.share-cta {
  border-top: 1px solid var(--seam);
  padding-top: 1rem;
}

.share-cta .btn {
  margin-right: 0.5rem;
}

/* "Count in total mileage" on Manage -- see set_route_file_counts. */
.route-file-total {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.4rem 0 0;
}

.route-file-total label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  font-weight: normal;
}

.route-file-total button {
  margin: 0;
}
