:root {
  --bg: #111214;
  --bg-card: #1b1c1f;
  --fg: #f2f1ed;
  --fg-muted: #a9a9a9;
  --accent: #d8b26a;
  --error: #e46b6b;
  --border: #2c2d31;
}

* { box-sizing: border-box; }

/* Generic "not currently shown" utility — used throughout the lightbox JS
   (gallery-lightbox.js) to toggle the Select vs. Download button, the
   selfie-search error message, etc. Was missing entirely until now: only
   the unrelated, more specific `.lightbox.hidden` rule below existed, so
   every classList.add('hidden') on the lightbox's Select/Download buttons
   was a silent no-op — the Download link stayed visible next to Select on
   every gallery, sell-mode included, even though it was never functional
   there (stale/placeholder href). This is the actual fix for that. */
.hidden { display: none !important; }

/* Site-wide default button look — every <button> and .button-link falls back
   to this gold accent style unless a more specific rule overrides it. This
   is the single source of truth for "buttons should all be the same color":
   new buttons added anywhere on the site automatically match without
   needing their own color rule. Destructive/danger actions (.danger,
   .upload-cancel-btn, .batch-cancel-btn) are the one deliberate exception —
   those stay red so a delete/cancel action never looks identical to a
   normal one. */
button, .button-link, input[type="submit"] {
  background: var(--accent);
  color: #1b1c1f;
  border: 1px solid var(--accent);
  border-radius: 4px;
  padding: 0.6rem 1.1rem;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
button:hover, .button-link:hover, input[type="submit"]:hover { opacity: 0.9; }
button:disabled { opacity: 0.5; cursor: not-allowed; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  line-height: 1.5;
}

h1, h2, h3 {
  font-family: Georgia, 'Times New Roman', serif;
  font-weight: 500;
  letter-spacing: 0.02em;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* width:100% matters more than it looks. .site-content is a flex column
   (see below), and in flexbox an auto margin on the cross axis cancels the
   default stretch — so `margin: 0 auto` alone made this shrink-to-fit its
   contents instead of filling up to max-width. A page whose widest item was
   narrow (e.g. an embedded iframe with no width of its own, which falls back
   to the 300px HTML default) collapsed the ENTIRE page column down to that
   width, cramping the heading and everything else with it. Adding an
   explicit width restores the intended behavior: fill the available space,
   capped by max-width, still centered. box-sizing keeps the padding inside
   that width so nothing overflows. */
.container {
  width: 100%;
  box-sizing: border-box;
  max-width: 1100px;
  margin: 0 auto;
  padding: 2rem 1.5rem 4rem;
}
.container.narrow { max-width: 520px; }
/* Custom Pages (views/page.ejs) get more breathing room than the standard
   .narrow cap — 520px leaves almost nothing for a Half/Third-width block
   (see .page-block-w-half/.page-block-w-third above) to actually look like
   a column instead of a cramped strip. Other .narrow pages (Contact, order
   status, login, etc.) are untouched — this only applies where the extra
   .page-container class is also present. */
.container.narrow.page-container { max-width: 900px; }

/* Order-status page (views/order-status.ejs) — small colored pill showing
   where an order stands: pending payment, ready to download, prints in
   production, or shipped. */
.order-status-badge {
  display: inline-block;
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.85rem;
  margin: 0 0 0.75rem;
}
.order-status-badge.status-pending { background: #f0ece0; color: #6b6b6b; }
.order-status-badge.status-processing { background: #fdf0dc; color: #9a6a1a; }
.order-status-badge.status-ready,
.order-status-badge.status-shipped { background: #e4f3e6; color: #2e7d3f; }
.order-status-details { margin: 0 0 1rem; padding-left: 1.2rem; }

.site-shell {
  display: flex;
  min-height: 100vh;
  align-items: stretch;
}

.sidebar-toggle-checkbox { display: none; }

.sidebar {
  flex: 0 0 260px;
  width: 260px;
  background: var(--bg-card);
  border-right: 1px solid var(--border);
  padding: 0 0 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.sidebar-logo-link {
  display: block;
  width: 100%;
  line-height: 0;
  padding: 1.25rem 1.75rem 0.5rem;
  box-sizing: border-box;
}
.sidebar-logo {
  width: 100%;
  height: auto;
  max-height: 210px;
  object-fit: contain;
  display: block;
  margin: 0 auto;
}

.sidebar-site-name {
  display: block;
  padding: 1.25rem 1rem 1rem 1.25rem;
  font-family: Georgia, serif;
  font-size: 2.2rem;
  letter-spacing: 0.01em;
  line-height: 1.15;
  color: var(--fg);
  overflow-wrap: anywhere;
  word-break: break-word;
}
.sidebar-site-name:hover { color: var(--fg); text-decoration: none; }

.sidebar-close {
  display: none;
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 2;
  width: 34px;
  height: 34px;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.55);
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
  font-size: 1.1rem;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.25rem 1rem;
}
.sidebar-nav a {
  padding: 0.6rem 0.65rem;
  border-radius: 4px;
  color: var(--fg-muted);
  font-size: 1.3rem;
  text-align: center;
}
.sidebar-nav a:hover {
  color: var(--fg);
  background: rgba(255,255,255,0.04);
  text-decoration: none;
}

.sidebar-social {
  margin-top: auto;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}
.sidebar-social a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: var(--fg-muted);
  border: 1px solid var(--border);
}
.sidebar-social a svg { width: 16px; height: 16px; }
.sidebar-social a:hover { color: var(--fg); border-color: var(--fg-muted); text-decoration: none; }

.sidebar-open-btn {
  display: none;
  position: fixed;
  top: 1rem;
  left: 1rem;
  z-index: 50;
  width: 42px;
  height: 42px;
  align-items: center;
  justify-content: center;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--fg);
  font-size: 1.2rem;
  cursor: pointer;
}

.site-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--fg);
}

/* Galleries listing, individual gallery pages, and custom pages default to
   a white background — the sidebar stays on the dark theme regardless,
   since .sidebar is a sibling of .site-content and doesn't inherit these
   overridden variables. */
body.light-content .site-content {
  --bg: #ffffff;
  --bg-card: #f7f6f3;
  --fg: #1a1a1a;
  --fg-muted: #6b6b6b;
  --border: #e2e0da;
}

/* Photo-browsing surfaces (the Races and Events listing, a folder's page,
   a gallery's photo grid, and the single-photo page) run on a neutral dark
   grey instead of white — a dark surround stops the page competing with the
   photos and lets their color and contrast read truer, which is why nearly
   every serious photo site does this.
   Deliberately dark GREY (#1f1f1f), not the near-black --bg the sidebar and
   admin use (#111214): true black around a photo is harsh and crushes the
   look of darker shots.
   Text-and-form pages — cart, checkout, contact, custom pages, race
   registration — intentionally stay on .light-content, since dense text and
   input fields are easier to read and feel more trustworthy on white. To
   revert any page, swap its <body> class back to light-content. */
body.dark-gallery .site-content {
  --bg: #1f1f1f;
  --bg-card: #2a2a2a;
  --fg: #f2f1ed;
  --fg-muted: #b5b5b5;
  --border: #3d3d3d;
}

.site-footer {
  margin-top: auto;
  text-align: center;
  color: var(--fg-muted);
  padding: 2rem;
  font-size: 0.85rem;
}
.footer-legal-links { display: flex; gap: 0.5rem; justify-content: center; }
.footer-legal-links span { color: var(--fg-muted); }

@media (max-width: 860px) {
  .sidebar-open-btn { display: flex; }

  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 60;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    box-shadow: 4px 0 24px rgba(0,0,0,0.4);
  }
  .sidebar-close { display: flex; }

  .sidebar-toggle-checkbox:checked ~ .sidebar { transform: translateX(0); }
  .sidebar-toggle-checkbox:checked ~ .sidebar-open-btn { display: none; }
}

.hero { margin: 0 0 2rem; padding: 0 1.5rem; }
.hero p { color: var(--fg-muted); }
.hero.hero-with-photo {
  margin: 0 0 2rem;
  padding: 2rem;
  background-color: #16171a;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  min-height: 100vh;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
}
.hero.hero-with-photo h1 {
  font-size: 3.4rem;
  color: #fff;
  margin: 0 0 0.5rem;
}
.hero.hero-with-photo p {
  color: rgba(255,255,255,0.9);
  font-size: 1.2rem;
  margin: 0;
}

@media (max-width: 720px) {
  .hero.hero-with-photo { min-height: 70vh; }
  .hero.hero-with-photo h1 { font-size: 2.2rem; }
}

.hero-slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 1.5s ease;
}
.hero-slide.active { opacity: 1; }

/* Used on pages that still show a heading/text over the slideshow (e.g.
   the Galleries page) — darkens the photos for legibility. The homepage
   has no overlay content, so its slideshow shows at full brightness. */
.hero-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 2rem;
  background: linear-gradient(rgba(17,18,20,0.45), rgba(17,18,20,0.85));
}

.hero-cta {
  display: inline-block;
  margin-top: 1.5rem;
  padding: 0.9rem 2.2rem;
  background: var(--accent, #e0393e);
  color: #fff;
  font-weight: 600;
  font-size: 1.05rem;
  text-decoration: none;
  border-radius: 6px;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.hero-cta:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(0,0,0,0.25);
}

/* Starting prices, stated before anyone has to click anything. Sits between
   the gallery title and the search panel so it's read on the way down. */
.gallery-pricing-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  margin: 0.75rem 0 1.25rem;
  padding: 0.7rem 1rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.95rem;
  color: var(--fg);
}

/* "Find your photos" panel. Getting a visitor to their own shots is the whole
   job of this page — scrolling hundreds of thumbnails is where people give
   up — so the search is presented as a real, titled step rather than a bare
   input that reads like generic site search. */
.find-your-photos {
  margin: 0 0 1.75rem;
  padding: 1.1rem 1.25rem 1.25rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.find-your-photos h2 {
  margin: 0 0 0.3rem;
  font-size: 1.35rem;
}
.find-your-photos-hint {
  margin: 0 0 0.75rem;
  color: var(--fg-muted);
  font-size: 0.9rem;
}
.find-your-photos .bib-search-form { margin-top: 0; }
.find-your-photos .bib-search-form input {
  max-width: 420px;
  font-size: 1.05rem;
  padding: 0.75rem 0.9rem;
}
.find-your-photos .bib-search-form button { padding: 0.75rem 1.4rem; }

/* Per-photo starting price under the buy button. Small and muted — it
   answers "what does this cost" without shouting over the photo itself. */
.photo-tile-price {
  margin: 0;
  padding: 0 0.5rem 0.5rem;
  color: var(--fg-muted);
  font-size: 0.78rem;
  text-align: center;
}

.bib-search-form {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 1rem 0 0.5rem;
}

/* Phones are where most race photos get browsed, often at the event itself,
   and this search is the step everything else depends on. Side by side, the
   input and button squeeze each other down to unusable widths on a narrow
   screen — so below this width they each take a full row and a full-width
   tap target. */
@media (max-width: 640px) {
  .bib-search-form { flex-wrap: wrap; }
  .bib-search-form input,
  .find-your-photos .bib-search-form input {
    max-width: none;
    width: 100%;
    /* 16px minimum stops iOS Safari from auto-zooming the whole page the
       moment the field is focused, which otherwise leaves the visitor
       zoomed in and scrolled sideways. */
    font-size: 16px;
  }
  .bib-search-form button,
  .find-your-photos .bib-search-form button { width: 100%; }
  .face-search-label { width: 100%; }
  .face-search-label input[type="file"] { max-width: none; width: 100%; }
  .find-your-photos { padding: 1rem; }
  .gallery-pricing-bar { gap: 0.25rem 1rem; }
}
.bib-search-form input {
  flex: 1;
  max-width: 320px;
  padding: 0.65rem 0.9rem;
  background: var(--bg-card);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 1rem;
}
.bib-search-form button {
  padding: 0.65rem 1.1rem;
  background: var(--accent);
  color: #1b1c1f;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  cursor: pointer;
}
.clear-search { color: var(--fg-muted); font-size: 0.9rem; }

/* "Notify me" opt-in form shown under a zero-result bib/name search (see
   gallery.ejs / folder.ejs) — lets a customer leave their email and get
   pinged automatically once a matching photo is uploaded/tagged (see
   data/models.js PhotoAlerts). */
.notify-me-form { margin: 1rem 0; max-width: 420px; }
.notify-me-form label { display: block; margin-bottom: 0.5rem; font-size: 0.9rem; color: var(--fg-muted); }
.notify-me-row { display: flex; gap: 0.5rem; }
.notify-me-row input {
  flex: 1;
  padding: 0.65rem 0.9rem;
  background: var(--bg-card);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 1rem;
}
.notify-me-row button {
  padding: 0.65rem 1.1rem;
  background: var(--accent);
  color: #1b1c1f;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  cursor: pointer;
}

.back-to-folder-link { display: inline-block; margin-bottom: 1rem; }
.back-to-folder-bottom { margin-top: 1.5rem; margin-bottom: 0; }

/* Folder (category) page hero — a single static banner image, not a
   slideshow, since it's mainly standing in as the link-preview thumbnail
   when a folder's shareable link gets pasted somewhere. */
.folder-hero {
  width: 100%;
  height: 320px;
  overflow: hidden;
  background: #16171a;
}
.folder-hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 720px) {
  .folder-hero { height: 200px; }
}

.face-search-form { flex-wrap: wrap; }
.face-search-label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--fg-muted);
}
.face-search-label input[type="file"] {
  max-width: 260px;
  font-size: 0.9rem;
  color: var(--fg);
}

/* .category-heading is now a <summary> (see the admin Galleries list page,
   views/admin/galleries.ejs) so each category's table can be collapsed —
   cursor and outline-removal make that obviously clickable without
   changing the look much from when this was a plain <h2>. Note this can't
   use :first-of-type on .category-heading itself anymore — each <summary>
   is the only one inside its own <details>, so it'd always match. Scoped
   to the first <details class="category-section"> among its siblings
   instead, same "no extra gap before the very first section" effect. */
.category-heading {
  margin: 2rem 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  outline: none;
  font-size: 1.15rem;
}
.category-section:first-of-type .category-heading { margin-top: 0; }
/* A closed folder has no table underneath taking up visual weight, so the
   same 2rem gap that separates two open (table-bearing) sections reads as
   an oversized dead zone between two collapsed ones — tighten it here. */
.category-section:not([open]) .category-heading { margin-top: 0.75rem; }
/* The two "Order ... by" dropdowns on the admin Galleries page (see
   views/admin/galleries.ejs) sit side by side rather than stacked, since
   together they're still narrow enough to fit most screens on one line. */
.gallery-sort-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
/* Bumped up from the site default (inherited, ~1rem) specifically for the
   admin Galleries list page — scoped to .category-section rather than
   .admin-table/.container globally, since .admin-table is shared with
   several other admin pages (Download Sizes, Dashboard, Print Options,
   Packages, Pages) that weren't asked for here. */
.category-section .admin-table th,
.category-section .admin-table td {
  font-size: 1.1rem;
}

.gallery-folder-section { margin: 0 0 2.5rem; }
.gallery-folder-heading {
  margin: 0 0 1.25rem;
  padding-bottom: 0.6rem;
  border-bottom: 2px solid var(--border);
  font-size: 1.4rem;
}
.gallery-folder-section:first-of-type .gallery-folder-heading { margin-top: 0; }

.gallery-description { color: var(--fg-muted); }
.gallery-content {
  /* Solid, near-black (matches the page's own body text color, --fg on a
     light-content page) rather than the muted gray used for the short
     description above it — this is meant to be read as real page content
     (recap, instructions, results links), not a secondary caption. */
  color: var(--fg);
  white-space: pre-line;
  margin: 0.5rem 0 1.5rem;
  font-size: 1.15rem;
}
.gallery-content-small { font-size: 1rem; }
.gallery-content-medium { font-size: 1.15rem; }
.gallery-content-large { font-size: 1.4rem; }
.gallery-content-link { margin: -0.75rem 0 1.5rem; }

/* Wraps every block on a custom Page (see views/page.ejs) — a flex row that
   wraps, so blocks set to Half or Third width (see the widthField select in
   views/admin/page-edit.ejs) end up sitting next to each other instead of
   each one always taking the full row. A Full-width block still forces a
   line break on its own, same as before this existed. */
.page-blocks-flow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0 1.5rem;
}
.page-block-wrap {
  min-width: 0;
  box-sizing: border-box;
}
.page-block-w-full { flex: 1 1 100%; width: 100%; }
.page-block-w-half { flex: 1 1 calc(50% - 0.75rem); width: calc(50% - 0.75rem); }
.page-block-w-third { flex: 1 1 calc(33.333% - 1rem); width: calc(33.333% - 1rem); }
@media (max-width: 700px) {
  /* Narrow screens: every block reverts to stacking full-width rather than
     squeezing two or three columns into a phone-sized page. */
  .page-block-w-half, .page-block-w-third { flex: 1 1 100%; width: 100%; }
}

.page-content {
  color: var(--fg-muted);
  white-space: pre-line;
  margin: 1rem 0;
  line-height: 1.7;
}

.page-block-figure {
  margin: 1.5rem 0;
}
.page-block-figure img,
.page-block-figure video {
  display: block;
  max-width: 100%;
  border-radius: 6px;
}
.page-block-figure figcaption {
  color: var(--fg-muted);
  font-size: 0.85rem;
  margin-top: 0.4rem;
}

/* Third-party embed block (e.g. a race registration iframe) — most embed
   snippets hard-code a pixel width, so this forces whatever's pasted in to
   never overflow the page on a narrow screen. Height is left alone (the
   snippet usually sets its own, or the widget itself scrolls internally). */
.page-block-embed {
  margin: 1.5rem 0;
}
/* Fill the block's full width. Without an explicit width, a browser falls
   back to the HTML default iframe size (300px), which made a registration
   form embed render as a skinny scrollbar-ed column no matter how wide its
   block was set — max-width alone only caps, it never stretches. Embed code
   that DOES carry its own width attribute still gets honored, since an
   inline width attribute on the element wins over this. */
.page-block-embed iframe {
  width: 100%;
  max-width: 100%;
}

/* Gallery blocks on a custom Page (see views/page.ejs). The embedded
   variant reuses .photo-grid so photos look and behave exactly as they do
   in the real gallery — same tile, same buy button, same lightbox. */
.page-gallery-block { margin: 1.5rem 0 2rem; }
.page-gallery-block h2 { margin: 0 0 0.35rem; }
.page-gallery-block .photo-grid { margin-top: 0.75rem; }
/* The lighter "card that links through" variant. .gallery-card already
   carries the card look site-wide; this just keeps one sitting inside a
   page block from stretching oddly in a Half/Third-width column. */
.page-gallery-card { display: block; max-width: 420px; margin: 1.5rem 0; }

/* Slideshow block — a fading carousel of a gallery's photos (see
   public/js/page-gallery-slideshow.js). Fixed-ratio box, same idea as the
   YouTube embed below, so the layout never jumps as slides swap in/out;
   each slide is a full-bleed absolutely-positioned <img> and only the
   .active one is visible. */
.page-slideshow-block { margin: 1.5rem 0 2rem; }
.page-slideshow-block h2 { margin: 0 0 0.35rem; }
.page-slideshow-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: 6px;
  overflow: hidden;
  background: #000;
}
.page-slideshow-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.page-slideshow-slide.active { opacity: 1; }
.page-slideshow-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  border: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  font-size: 1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
}
.page-slideshow-arrow:hover { background: rgba(0, 0, 0, 0.65); }
.page-slideshow-prev { left: 12px; }
.page-slideshow-next { right: 12px; }
.page-slideshow-dots {
  position: absolute;
  bottom: 12px;
  left: 0;
  right: 0;
  z-index: 2;
  display: flex;
  justify-content: center;
  gap: 8px;
}
.page-slideshow-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 0;
  background: rgba(255, 255, 255, 0.5);
  cursor: pointer;
  padding: 0;
  transition: background 0.2s, transform 0.2s;
}
.page-slideshow-dot.active { background: #fff; transform: scale(1.2); }
.page-slideshow-block .button-link { margin-top: 0.75rem; }

/* YouTube block — a fixed 16:9 box via the classic padding-bottom trick, so
   the video keeps its aspect ratio at any width instead of needing a set
   pixel height. Sits inside the same .page-block-figure wrapper used by
   image/video blocks, so it picks up the same Small/Medium/Large/Full
   sizing (see mediaSizeStyle in data/models.js) for free. */
.page-youtube-wrap {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%;
  height: 0;
  overflow: hidden;
  border-radius: 6px;
  background: #000;
}
.page-youtube-wrap iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.folder-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0 1.5rem;
}
.folder-tabs a {
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--fg-muted);
  font-size: 0.9rem;
}
.folder-tabs a:hover { color: var(--fg); text-decoration: none; }
.folder-tabs a.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #1b1c1f;
  font-weight: 600;
}

.gallery-social {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.5rem 0 1rem;
}
.gallery-social a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--fg-muted);
}
.gallery-social a svg { width: 17px; height: 17px; }
.gallery-social a:hover { color: var(--fg); border-color: var(--fg-muted); text-decoration: none; }

.gallery-grid, .photo-grid, .cart-photo-grid, .admin-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 1.25rem;
}
/* The public browsing grid (proofing photos to buy) gets noticeably bigger
   tiles than the gallery-card, cart, and admin grids above — those benefit
   from staying compact so more fits on screen at once, but customers
   deciding whether to buy a photo want to actually see detail in it. */
.photo-grid {
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
}
/* Gallery/subfolder cards on a folder's own page — wider tiles than the
   top-level Races and Events page's denser wall of cards, since a folder
   typically holds a handful of galleries (races, sub-events) rather than
   the whole site's worth. Lands at 2-3 columns on a typical desktop width
   inside the 1100px .container, fewer as the screen narrows. */
.folder-page-grid {
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.admin-photo-grid.small { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); }
.admin-photo-grid.small img { border-radius: 4px; }

.gallery-card {
  display: block;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.gallery-card-thumb { aspect-ratio: 4/3; background: #000; }
.gallery-card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-card-title { padding: 0.75rem 1rem; color: var(--fg); }

.photo-tile, .cart-photo-tile, .admin-photo-tile {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  position: relative;
}
.photo-tile img, .cart-photo-tile img, .admin-photo-tile img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  display: block;
}
.cart-photo-filename {
  margin: 0;
  padding: 0.4rem 0.5rem 0;
  font-size: 0.8rem;
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Wraps just the admin thumbnail image (see views/admin/_photo-tile.ejs) so
   the filename overlay below can anchor to the bottom of the IMAGE itself,
   not the bottom of the whole tile — the tile also has folder-move/tag/
   delete controls stacked underneath the image. */
.admin-photo-thumb { position: relative; }
.photo-filename-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 0.25rem 0.4rem;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.7rem;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}
/* "Cover photo" checkbox overlaid on an admin thumbnail (see
   views/admin/_photo-tile.ejs) — sits opposite the filename overlay, in the
   top-right corner. .is-cover-photo highlights the whole tile once it's the
   gallery's chosen cover, so it's obvious at a glance while scanning the
   grid. */
.admin-photo-tile.is-cover-photo { outline: 2px solid var(--accent); outline-offset: -2px; }
.cover-photo-form { position: absolute; top: 0; right: 0; margin: 0; z-index: 1; }
.cover-photo-overlay {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0.35rem;
  padding: 0.2rem 0.45rem;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.7rem;
  line-height: 1.2;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
}
.cover-photo-overlay input { margin: 0; }

.select-form { padding: 0.5rem; }
.select-form button, .remove {
  width: 100%;
  padding: 0.5rem;
}
/* "+ Select" (add to cart, for a sell-mode gallery) shares the same button
   element as "Download" (an actual free-download gallery) would use, so
   without this override every public gallery — sell or free — showed the
   same solid gold, "lit up" button regardless of whether anything was
   actually free to download. Now a not-yet-selected photo gets a quieter
   outlined look, and only turns solid gold once the customer has actually
   picked it — so gold specifically means "free download" or "you selected
   this," never just "here's a button." Applies everywhere a photo can be
   selected for purchase: the gallery grid, the lightbox overlay, and the
   single-photo detail page. */
.select-form button:not(.selected),
.photo-detail-side button:not(.selected),
.lightbox-actions button:not(.selected) {
  background: none;
  color: var(--accent);
  border: 1px solid var(--accent);
}
.select-form button.selected,
.photo-detail-side button.selected,
.lightbox-actions button.selected {
  background: var(--accent);
  color: #1b1c1f;
  border: 1px solid var(--accent);
}
.logo-choice-form {
  padding: 0 0.5rem;
  margin: 0.2rem 0;
}
.logo-bulk-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0.5rem 0 1rem;
}
.logo-bulk-actions form { display: inline; }
.logo-bulk-btn {
  background: var(--accent);
  color: #1b1c1f;
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
  font-weight: 600;
}
.logo-bulk-btn:hover { opacity: 0.85; }
/* "Remove from all" is the undo of "Include on all" — same size/weight so
   neither looks like an afterthought, but outlined instead of filled so the
   two are still visually distinct from each other at a glance. */
.logo-bulk-btn-outline {
  background: none;
  color: var(--accent);
}
.checkbox-label.small {
  font-size: 0.78rem;
  gap: 0.35rem !important;
}

.package-toggle-form { padding: 0 0.5rem; margin-top: 0.35rem; }
.select-form-button {
  width: 100%;
  padding: 0.4rem;
  font-size: 0.8rem;
}

.floating-cart {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: 50;
  background: var(--accent);
  color: #1b1c1f;
  padding: 0.9rem 1.4rem;
  border-radius: 999px;
  font-weight: 600;
  box-shadow: 0 4px 16px rgba(0,0,0,0.4);
}
.floating-cart:hover { text-decoration: none; opacity: 0.9; }
/* Empty-cart state — still visible on every page (so the cart is never
   "hidden" just because nothing's in it yet), but deliberately quieter than
   the filled state so it doesn't compete for attention with an actual call
   to action. */
.floating-cart-empty {
  background: var(--bg-alt, #2a2b2f);
  color: var(--fg-muted, #b7b7bd);
  border: 1px solid var(--fg-muted, #4a4a50);
  font-weight: 500;
  box-shadow: none;
  padding: 0.6rem 1.1rem;
}

/* Floating "back to top" button — bottom-LEFT so it never overlaps the
   floating cart badge above (that one's bottom-right). Hidden by default;
   public/js/back-to-top.js toggles .visible once the page is scrolled down. */
.back-to-top {
  position: fixed;
  bottom: 1.5rem;
  left: 1.5rem;
  z-index: 50;
  padding: 0.7rem 1.1rem;
  background: var(--accent);
  color: #1b1c1f;
  border: none;
  border-radius: 999px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0,0,0,0.4);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}
.back-to-top.visible { opacity: 1; visibility: visible; transform: translateY(0); }

.photo-detail { display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; margin-top: 1.5rem; }
.photo-detail img { width: 100%; border-radius: 6px; }
.photo-detail-side button, .photo-detail-side .button-link {
  display: block;
  width: 100%;
  padding: 0.8rem;
  margin: 0.5rem 0;
  text-align: center;
}
.photo-detail-position { margin: 0 0 1rem; }

/* Prev/Next arrows overlaid on the single-photo page's image (see
   views/photo.ejs) — same round, semi-transparent look as .lightbox-nav in
   the gallery grid's overlay, just positioned relative to the image itself
   instead of a full-viewport overlay, since this page has no dark backdrop
   to sit on. */
.photo-detail-image-wrap { position: relative; }
.photo-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 1.2rem;
  border-radius: 50%;
  text-decoration: none;
  transition: background 0.15s ease;
}
.photo-nav:hover { background: rgba(0, 0, 0, 0.65); }
.photo-nav-prev { left: 0.75rem; }
.photo-nav-next { right: 0.75rem; }

@media (max-width: 720px) {
  .photo-detail { grid-template-columns: 1fr; }
}

/* Click-to-enlarge lightbox for the public gallery grid (bib search
   results included) — see gallery-lightbox.js. Scoped to .photo-tile so
   this doesn't touch the admin panel's own (separate) lightbox or the
   cart page's photo tiles. */
.photo-tile img { cursor: zoom-in; }

.lightbox {
  position: fixed;
  inset: 0;
  /* Solid, not semi-transparent — a fully opaque surround keeps the page
     behind from bleeding through and tinting how the photo's own colors
     read. Matches the dark grey used by the gallery pages themselves
     (body.dark-gallery above) so enlarging a photo doesn't jump to a
     different shade. */
  background: #1f1f1f;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.lightbox.hidden { display: none; }
.lightbox-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  max-width: 90vw;
  max-height: 90vh;
}
/* The enlarged photo is the moment someone decides whether to buy, so the
   background stays as dark as possible — a dark surround raises apparent
   contrast and saturation, which is what makes a photo look its best.
   The tradeoff is that a shot with dark edges or deep shadows starts
   bleeding into the background and loses its shape. Rather than lighten
   the background (which would cost that pop everywhere), the separation is
   put on the photo itself: a barely-there light hairline plus a soft drop
   shadow. That reads as a print floating off the wall — the image keeps
   its edge no matter how dark it is, and nothing is taken away from how
   the photo looks. */
.lightbox-content img {
  max-width: 90vw;
  max-height: 75vh;
  object-fit: contain;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.65);
}
/* Filename caption under the enlarged image (see #lightbox-title in
   gallery.ejs, populated in gallery-lightbox.js) — .lightbox-content's own
   flex gap already spaces it from the image above and the buttons below,
   so this only needs to handle its own text look. */
.lightbox-title {
  margin: 0;
  max-width: 90vw;
  color: #fff;
  font-size: 0.9rem;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lightbox-actions { display: flex; gap: 0.75rem; }
.lightbox-actions button, .lightbox-actions .button-link {
  padding: 0.7rem 1.4rem;
  font-size: 0.95rem;
}
.lightbox-close {
  position: absolute;
  top: 1rem;
  right: 1.5rem;
  background: none;
  border: none;
  color: #fff;
  font-size: 2.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.lightbox-close:hover { opacity: 0.8; }
.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(255, 255, 255, 0.12);
  border: none;
  color: #fff;
  font-size: 1.3rem;
  padding: 0.75rem 1rem;
  cursor: pointer;
  border-radius: 6px;
}
.lightbox-nav:hover { background: rgba(255, 255, 255, 0.28); }
.lightbox-prev { left: 1rem; }
.lightbox-next { right: 1rem; }
body.lightbox-open { overflow: hidden; }

.back-link { display: inline-block; margin-bottom: 1rem; color: var(--fg-muted); }

.cart-section, .admin-section {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.package-option {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.package-option:last-of-type { border-bottom: none; }
.package-option input { margin-top: 0.3rem; }
.package-option p { margin: 0.25rem 0 0; color: var(--fg-muted); font-size: 0.9rem; }

.qty-label { display: block; margin: 1rem 0; }
.qty-label input { width: 5rem; margin-left: 0.5rem; }

.package-fill-box {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1rem;
  margin-bottom: 1.25rem;
}
.package-fill-box-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}
.package-fill-box-header form { flex-shrink: 0; }
.package-fill-box-header button.remove { width: auto; padding: 0.4rem 0.8rem; }

/* Stays pinned to the top of the viewport while the customer scrolls through
   the "fill each package" section (sticky within its containing section, so
   it scrolls away naturally once that section ends) — a constant reminder of
   which direction to scroll for the two things they'll want next. */
/* Containing block for .scroll-hint's sticky positioning — spans from the
   package section through the digital-downloads section, ending right
   before the order summary. That's what makes the hint stay pinned in view
   the whole time the customer is filling packages / adding extra prints or
   downloads, then scroll away naturally once they actually reach the order
   summary at the bottom. */
.scroll-hint-wrapper { position: relative; }

/* Anchor-jump targets (#choose-packages, #fill-packages, #package-fill-<id>,
   #order-summary) all get a little breathing room above them so the sticky
   .scroll-hint bar never lands directly on top of — and hides — the heading
   the browser just jumped to. */
#choose-packages, #fill-packages, .package-fill-box, #order-summary {
  scroll-margin-top: 4.5rem;
}

.scroll-hint {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 1.25rem;
  padding: 0.6rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.scroll-hint .button-link { font-size: 0.85rem; padding: 0.5rem 1rem; }

/* Backdoor-gallery banner pointing at the real public gallery to share (see
   routes/public.js linkedTargetGallery) — same card treatment as
   .scroll-hint, just not sticky, since it only needs to be seen once at the
   top of the page rather than while scrolling through photos. */
.linked-gallery-note {
  margin: 0 0 1.25rem;
  padding: 0.7rem 0.9rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.linked-gallery-note .copy-link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

/* Same look as .scroll-hint but not sticky — this one lives inside the
   order summary itself, next to the "these photos aren't covered yet"
   notice, so it's just a plain inline action rather than something that
   needs to follow the customer while they scroll. */
.uncovered-hint {
  display: flex;
  margin: 0 0 1rem;
}
.uncovered-hint .button-link { font-size: 0.85rem; padding: 0.5rem 1rem; }
.package-fill-box h3 { margin: 0; font-size: 1rem; }
.cart-photo-grid.small { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.75rem; margin-bottom: 1rem; }
.photo-check-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem;
  cursor: pointer;
  text-align: center;
}
.photo-check-tile img { width: 100%; aspect-ratio: 4/3; object-fit: cover; border-radius: 4px; }
.photo-check-tile.disabled { opacity: 0.45; cursor: not-allowed; }
.photo-check-tile .cart-photo-filename { padding: 0; }

.package-fill-box h4 { margin: 1rem 0 0.25rem; font-size: 0.95rem; }
.package-print-slot {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
}
.package-print-slot:first-of-type { border-top: none; }
.package-print-slot strong { min-width: 90px; }

.cart-table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; }
.cart-table td { padding: 0.5rem 0.25rem; border-bottom: 1px solid var(--border); }

.add-print-form { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.add-print-form select, .add-print-form input { padding: 0.5rem; background: var(--bg); color: var(--fg); border: 1px solid var(--border); border-radius: 4px; }

/* Print crop-preview box (see public/js/print-crop-preview.js) — shows a
   dashed crop boundary over the chosen photo once both a photo and a print
   size are selected on the "Add print" form above. */
.print-crop-preview { max-width: 360px; margin: 0.75rem 0 1rem; }
.print-crop-preview-frame { position: relative; display: inline-block; max-width: 100%; }
.print-crop-preview-frame img { display: block; max-width: 100%; height: auto; border-radius: 4px; }
.print-crop-preview-box {
  position: absolute;
  border: 2px dashed var(--accent);
  box-shadow: 0 0 0 1000px rgba(0, 0, 0, 0.35);
  pointer-events: none;
  display: none;
}

/* "Update package", "Add print", "Add download" — matches the same gold
   accent used by the Checkout button and every other primary action button
   site-wide, rather than falling back to a plain unstyled button. */
.package-form button,
.add-print-form button {
  padding: 0.65rem 1.1rem;
  background: var(--accent);
  color: #1b1c1f;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  cursor: pointer;
}
.package-form button:hover,
.add-print-form button:hover {
  opacity: 0.9;
}

.order-summary-list {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.order-summary-list li {
  padding: 0.5rem 0;
  color: var(--fg);
  font-size: 0.92rem;
}
.order-summary-list li + li { border-top: 1px solid var(--border); }
.totals p { margin: 0.25rem 0; color: var(--fg-muted); }
.grand-total { color: var(--fg) !important; font-size: 1.3rem; font-weight: 600; margin-top: 0.5rem !important; }
.checkout-button {
  width: 100%;
  padding: 1rem;
  margin-top: 1rem;
  background: var(--accent);
  color: #1b1c1f;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
}
.checkout-button[disabled] { opacity: 0.5; cursor: not-allowed; }

.link-button {
  background: none;
  border: none;
  color: var(--fg-muted);
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  margin-top: 0.75rem;
}

.stacked-form { display: flex; flex-direction: column; gap: 1rem; max-width: 480px; }
.stacked-form label { display: flex; flex-direction: column; gap: 0.35rem; color: var(--fg-muted); }
.stacked-form input, .stacked-form textarea, .stacked-form select {
  padding: 0.6rem;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 1rem;
}
.stacked-form button {
  padding: 0.8rem;
  background: var(--accent);
  color: #1b1c1f;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  cursor: pointer;
}
.checkbox-label { flex-direction: row !important; align-items: center; gap: 0.5rem !important; }

.shipping-options-form { margin: 0.75rem 0; }
.shipping-option-choice {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0;
  cursor: pointer;
}
.shipping-options-form button { margin-top: 0.5rem; }

.button-link {
  display: inline-block;
  padding: 0.6rem 1.2rem;
  background: var(--accent);
  color: #1b1c1f !important;
  border-radius: 4px;
  font-weight: 600;
}
.button-link:hover { text-decoration: none; opacity: 0.9; }
.download-all-top { margin: 0.5rem 0 1rem; }
.download-all-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.5rem 0 1rem;
}
.download-all-form select {
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-card);
  color: var(--fg);
}

.error { color: var(--error); }
.success { color: #5cb87a; }
.empty { color: var(--fg-muted); }
.fine-print { color: var(--fg-muted); font-size: 0.85rem; }
.hint { color: var(--fg-muted); font-size: 0.9rem; }
.private-note { color: var(--fg-muted); font-size: 0.9rem; margin-top: 2rem; }
/* Cart-page callout letting a customer know they can drop the race/event
   logo from any photo — only shown when at least one selected photo
   actually has one available (see views/cart.ejs). */
.cart-logo-note {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.7rem 1rem;
  margin: 1rem 0;
  font-size: 0.9rem;
}
/* Top-of-page cart instructions box, with an inline "Clear cart" action —
   the same POST /cart/clear the bottom-of-page button already used, just
   also offered up top so a customer doesn't have to scroll to start over
   (see views/cart.ejs). */
.cart-instructions {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.7rem 1rem;
  margin: 1rem 0;
  font-size: 0.9rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.cart-instructions p { margin: 0; }
.cart-instructions .inline-clear-cart-form { margin: 0; }
.folder-breadcrumbs { margin-bottom: 0.75rem; }
.folder-breadcrumbs a { color: var(--fg-muted); }
.download-list { list-style: none; padding: 0; }
.download-list li { margin-bottom: 0.5rem; }
.download-list a { display: inline-block; padding: 0.6rem 1rem; background: var(--accent); color: #1b1c1f; border-radius: 4px; }

/* ---------- Race registration form (views/partials/registration-form.ejs) ---------- */
.registration-form-block { margin: 2rem 0; }
.registration-fieldset {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem 1.25rem 1.25rem;
  margin: 0 0 1.25rem;
}
.registration-fieldset legend {
  font-weight: 600;
  padding: 0 0.4rem;
}
.registration-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.4rem;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.registration-option:last-child { border-bottom: none; }
.registration-option.is-full { opacity: 0.5; cursor: not-allowed; }
.registration-option-name { flex: 1; }
.registration-option-price { font-weight: 600; }
.registration-option-note {
  font-size: 0.8rem;
  color: var(--accent);
  font-weight: 600;
}
/* Waivers are long — cap the height and scroll rather than pushing the
   actual signup fields miles down the page. */
.registration-waiver-text {
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.75rem;
  margin-bottom: 0.75rem;
  font-size: 0.85rem;
  line-height: 1.6;
  white-space: pre-line;
  background: var(--bg-card);
}
.registration-success {
  border: 1px solid #b9e2b9;
  background: #eaf7ea;
  color: #2c6b2c;
  border-radius: 8px;
  padding: 1.25rem;
}
.registration-success h3 { margin-top: 0; }
.registration-closed {
  border: 1px solid var(--border);
  background: var(--bg-card);
  border-radius: 8px;
  padding: 1.25rem;
}
