/* stripcams.me / striprec.com — one stylesheet, two palettes.
   Every colour comes from a custom property Config::cssVariables() sets per host
   in <head>, so this file never names a brand colour.

   TOKEN ROLES, and getting these wrong is what made the first build unreadable:
     --bg          page background (dark on both hosts)
     --on-bg       text ON the page background      <- NOT --text
     --on-bg-muted secondary text on the page background
     --surface     card / panel background
     --text        text ON a surface                <- dark on stripcams.me
     --accent      fills (buttons, live banner, current page, back-to-top)
     --on-accent   text ON an accent fill
   stripcams.me's --text is #362119 brown, meant for the #a9baab sage card
   surface. Using it for body text put brown on a near-black page. */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--on-bg);
  font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

a { color: inherit; text-decoration: none; }
a:focus-visible, button:focus-visible, input:focus-visible {
  outline: 2px solid var(--accent-warm); outline-offset: 2px;
}

.wrap { max-width: 1600px; margin: 0 auto; padding: 0 20px 96px; }

/* ── Header ─────────────────────────────────────────────────────────────── */
.site-header {
  display: flex; align-items: center; gap: 24px; flex-wrap: wrap;
  padding: 14px 20px;
  background: var(--accent-dk);
  border-bottom: 1px solid var(--border);
}
.brand { font-size: 1.3rem; font-weight: 700; color: var(--on-accent); }
.search { position: relative; flex: 1 1 280px; max-width: 480px; }
.search input {
  width: 100%; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--text); font-size: 1rem;
}
.suggest {
  position: absolute; z-index: 200; inset-inline: 0; top: calc(100% + 4px);
  margin: 0; padding: 4px; list-style: none;
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  max-height: 60vh; overflow-y: auto;
}
.suggest a {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 7px 9px; border-radius: 4px; color: var(--text);
}
.suggest a:hover { background: var(--accent); color: var(--on-accent); }
.suggest-count { opacity: .7; font-variant-numeric: tabular-nums; }

/* ── Category nav: platform buttons + section hover-dropdowns ────────────
   Same markup contract as newsites/fastimages so a fix travels. */
.cat-nav { background: var(--surface); border-bottom: 1px solid var(--border); }
.cat-nav-list {
  list-style: none; margin: 0 auto; padding: 0 20px;
  max-width: 1600px; display: flex; flex-wrap: wrap; gap: .25rem;
}
.cat-item { position: relative; }
.cat-link {
  display: block; padding: .65rem 1rem;
  color: var(--text); font-weight: 600; font-size: .95rem;
  border-bottom: 2px solid transparent;
}
.cat-item:hover > .cat-link { color: var(--accent); border-bottom-color: var(--accent); }
.cat-dropdown {
  list-style: none; margin: 0; padding: .25rem 0;
  position: absolute; top: 100%; left: 0; min-width: 180px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .15s ease, transform .15s ease, visibility .15s;
  z-index: 150;
}
.cat-item:hover > .cat-dropdown,
.cat-item:focus-within > .cat-dropdown { opacity: 1; visibility: visible; transform: translateY(0); }
.cat-dropdown a { display: block; padding: .5rem 1rem; color: var(--text); font-size: .92rem; }
.cat-dropdown a:hover { background: var(--border); color: var(--accent); }

/* ── Headings ───────────────────────────────────────────────────────────── */
h1 { font-size: 1.6rem; margin: 26px 0 6px; color: var(--on-bg); text-wrap: balance; }
h2 { color: var(--on-bg); }
.listing-heading { font-size: 1rem; font-weight: 400; color: var(--on-bg-muted); margin: 0 0 22px; }
.empty { color: var(--on-bg-muted); padding: 40px 0; }

/* ── Card grid ──────────────────────────────────────────────────────────
   Sized off ultron: 4 across on desktop (its grid-3 = 25%), 16/10 thumbs.
   The first build used minmax(180px,1fr), which gave ~8 per row and made
   every card a thumbnail. */
.grid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; overflow: hidden; color: var(--text);
}
.card-link { display: block; color: inherit; }
.card-thumb {
  display: block; width: 100%;
  aspect-ratio: 16 / 10;          /* ultron's box for both img and hover video */
  object-fit: cover; background: var(--accent-dk);
}
.card-thumb--empty { display: block; }
.card-name {
  display: block; padding: 10px 12px 0; font-weight: 600; font-size: 1rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text);
}
.card-meta {
  display: block; padding: 3px 12px 12px; font-size: .875rem;
  color: var(--muted); font-variant-numeric: tabular-nums;
}
.card:hover { border-color: var(--accent); }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-block; padding: 11px 20px; border-radius: 6px;
  background: var(--accent); color: var(--on-accent); font-weight: 600;
  border: 1px solid var(--accent); cursor: pointer;
}
.btn:hover { filter: brightness(1.12); }
.btn--ghost {
  background: transparent; color: var(--on-bg);
  border-color: var(--border);
}
.btn--ghost:hover { background: var(--surface); color: var(--text); border-color: var(--accent); }

/* ── Performer page ─────────────────────────────────────────────────────── */
.performer-meta {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  color: var(--on-bg-muted); margin-bottom: 18px;
}
.tag { padding: 3px 10px; border: 1px solid var(--border); border-radius: 999px; font-size: .85rem; }
.cb-subject {
  background: var(--surface); color: var(--text);
  border-left: 3px solid var(--accent); padding: 10px 14px; border-radius: 4px;
}
.cb-last-seen { color: var(--on-bg-muted); font-size: .9rem; }
.alias-toggle { margin: 18px 0; }

.live-banner {
  display: inline-flex; align-items: center; gap: 9px;
  margin-top: 22px; padding: 12px 20px; border-radius: 6px;
  background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 1.05rem;
}
.live-banner:hover { filter: brightness(1.12); }
.live-dot { width: 10px; height: 10px; border-radius: 50%; background: #fff; animation: pulse 1.6s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

/* ── Detail page ────────────────────────────────────────────────────────
   Follows fastimages: the detail surface gets its OWN width, wider than the
   listing container, so the media can show near native size on a big monitor.
   The player is shaped by the recording's real aspect ratio (inline, from the
   row) rather than a fixed box -- a lot of this catalogue is portrait and a
   16/10 box letterboxed all of it. */
/* THE DETAIL PAGE GETS A WIDER CONTAINER, which is the actual fix for the meta
   row wrapping. fastimages does this with `main:has(.image-page)`. The listing
   .wrap caps at 1600px, leaving 1520px of usable width against a meta row that
   needs ~1731px -- so forcing one line inside 1520px would have meant shrinking
   the type to ~13px. Widening the surface keeps it readable AND lets the media
   show closer to native size, which is why fastimages does it too. */
.wrap:has(.detail) { max-width: 2150px; }

.detail {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 100%;
  margin-inline: auto;
}
.detail-media {
  display: block;
  /* SIZED BY WHICHEVER AXIS BINDS FIRST, not width:100%.
     fastimages uses width:100% because its content is landscape collages
     (2132x1274). A lot of THIS catalogue is portrait -- 720x960 on the first
     row sampled -- and width:100% on a portrait clip produces a 1560px-wide
     letterbox with a small video floating in the middle of it. Letting the
     intrinsic size be clamped by max-width/max-height means portrait is bounded
     by height and landscape by width, and neither gets bars. */
  max-width: 100%;
  max-height: 80vh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 8px;
  background: #000;
  margin-inline: auto;
}
/* A still collage keeps its own proportions and is never upscaled past its
   natural size. */
.detail-media--still { height: auto; max-width: 100%; }

.detail-dl { margin: 0; }
.detail-performer { color: var(--on-bg-muted); }
.detail-performer a { color: var(--accent-warm); text-decoration: underline; }

/* ADAPTIVE, not a fixed two-column grid. A wrapping flex row of dt:dd pairs
   takes the container's width and reflows -- same shape as fastimages'
   .meta-list -- so it matches the player above it at every viewport instead of
   being pinned to one width. */
.spec {
  display: flex;
  flex-wrap: wrap;
  /* COLUMN-GAP 0, DELIBERATELY. A flex gap applies between EVERY child, and the
     children here are 20 alternating dt/dd elements -- so `gap: 32px` put 32px
     between each label and its own value as well as between pairs: 19 gaps,
     608px of it, which pushed 10 fields onto two lines by 149px. Spacing comes
     from the margins below instead, so it separates PAIRS and not label from
     value. The row-gap stays for the narrow viewports where it does wrap. */
  gap: 7px 0;
  align-items: baseline;
  justify-content: space-between;   /* distribute the slack evenly, not all at the end */
  margin: 0;
  width: 100%;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 13px 18px;
  /* SIZED TO FIT TEN FIELDS ON ONE LINE at a normal desktop width. The ten
     values run to ~1420px of text; at .95rem plus generous margins that needed
     ~1731px and wrapped at anything under ~1800. Trimmed the type a step and
     the inter-pair margin to 16px, which brings it inside a 1520px container
     with room. It still wraps gracefully below ~1200px, which is correct --
     forcing one line there would mean unreadable type. */
  font-size: .85rem;
  line-height: 1.45;
}
.spec dt {
  color: var(--muted);
  font-weight: 600;
  margin-right: 4px;          /* label -> its own value */
  white-space: nowrap;
}
.spec dt::after { content: ':'; }
.spec dd {
  margin: 0 16px 0 0;         /* value -> the NEXT label */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;        /* never split "aac / 44,100 Hz / stereo" */
}
.spec dd:last-of-type { margin-right: 0; }

/* ── Pagination ─────────────────────────────────────────────────────────── */
.pagination {
  display: flex; flex-wrap: wrap; gap: 7px; align-items: center;
  justify-content: center; margin: 40px 0 8px;
}
.pagination a, .pag-current, .pag-step {
  min-width: 44px; padding: 9px 11px; text-align: center;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--text);
  font-variant-numeric: tabular-nums;
}
.pagination a:hover { border-color: var(--accent); color: var(--accent); }
.pag-current { background: var(--accent); color: var(--on-accent); border-color: var(--accent); font-weight: 700; }
.pag-step--off { opacity: .35; }
.dots { padding: 0 4px; color: var(--on-bg-muted); }
.pag-total { color: var(--on-bg-muted); font-variant-numeric: tabular-nums; padding: 0 4px; }
.pag-goto { display: inline-flex; gap: 6px; align-items: center; }
.pag-input {
  width: 92px; padding: 9px 10px; text-align: center;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--text); font-size: 1rem;
}
.pag-go {
  padding: 9px 16px; border-radius: 6px; cursor: pointer;
  background: var(--accent); color: var(--on-accent);
  border: 1px solid var(--accent); font-weight: 600; font-size: 1rem;
}
.pag-go:hover { filter: brightness(1.12); }

/* ── Back to top ────────────────────────────────────────────────────────
   THE ESTATE PATTERN, copied from newsites/fastimages rather than invented for
   a third time. A full-width bar that slides down from behind the top edge once
   you have scrolled past 48px.

   I got this wrong twice. First as a bar pinned to the bottom of the VIEWPORT,
   which is a permanent overlay sitting on the content at every scroll position.
   Then, reading "bottom of the page", as a static block at the end of the
   content -- which is the one place a back-to-top control is useless, because
   you only reach it by already having scrolled to the bottom.

   Threshold is 48px, matching ultron: the bar should already be there by the
   time you want it. The transform keeps it out of the layout entirely when
   inactive, so it never covers anything on a fresh load. */
.backtotop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  padding: 0.85rem 0;
  text-align: center;
  background: var(--accent);
  color: var(--on-accent, #fff);
  border: 0;
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  z-index: 200;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  transform: translateY(-100%);
  transition: transform 0.3s ease;
}
.backtotop:hover { filter: brightness(1.12); color: var(--on-accent, #fff); }
.backtotop:focus-visible { outline: 2px solid var(--on-accent, #fff); outline-offset: -4px; }
.backtotop.active { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .backtotop { transition: none; } }

/* ── Footer ─────────────────────────────────────────────────────────────── */
.site-footer {
  padding: 26px 20px; border-top: 1px solid var(--border);
  color: var(--on-bg-muted);
}

@media (max-width: 900px) {
  .grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
}
@media (max-width: 640px) {
  .grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
  h1 { font-size: 1.3rem; }
  .cat-nav-list { overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; }
  .cat-dropdown {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: 0; min-width: 0; display: none;
  }
  .cat-item:focus-within > .cat-dropdown { display: block; }
}

/* ── Landing page (go. hosts) ──────────────────────────────────────────────
   TWO grids, each 3 wide x 2 high (#432). The tiles reuse .card-thumb so
   app.js's hover binding (`img.card-thumb[data-slideshow]`) works unchanged --
   a landing-only class would mean a second hover implementation to keep in
   step with the grids.

   THE TILE BOX IS PINNED. Collage heights vary by source aspect ratio, and the
   hover <video> is inserted as a SIBLING of the <img>, so without a fixed box
   the tile jumps the moment a preview mounts and the whole grid reflows under
   the pointer. aspect-ratio + object-fit hold both media to the same frame. */
.lp-hero { text-align: center; padding: 56px 16px 40px; }
.lp-kicker {
    text-transform: uppercase; letter-spacing: .14em; font-size: 12px;
    color: var(--on-bg-muted); margin: 0 0 10px;
}
.lp-title { font-size: clamp(28px, 5vw, 46px); line-height: 1.12; margin: 0 0 16px; color: var(--on-bg); }
.lp-lede  { max-width: 62ch; margin: 0 auto; color: var(--on-bg-muted); line-height: 1.6; }
.lp-cta-row { margin: 26px 0 0; }
.lp-btn {
    display: inline-block; padding: 13px 26px; border-radius: var(--radius, 6px);
    background: var(--accent); color: var(--on-accent); text-decoration: none;
    font-weight: 600;
}
.lp-btn:hover { background: var(--accent-dk); }

.lp-sec  { max-width: 1100px; margin: 0 auto; padding: 40px 16px; }
.lp-h2   { font-size: 22px; margin: 0 0 6px; color: var(--on-bg); }
.lp-hint { margin: 0 0 22px; color: var(--on-bg-muted); }

.lp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.lp-tile {
    position: relative; display: block; overflow: hidden;
    border-radius: var(--radius, 6px); background: var(--surface);
    text-decoration: none;
}
.lp-tile img, .lp-tile video {
    display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
}
.lp-tile-name {
    position: absolute; left: 0; right: 0; bottom: 0; padding: 18px 10px 8px;
    color: #fff; font-size: 13px;
    background: linear-gradient(to top, rgba(0,0,0,.72), rgba(0,0,0,0));
}

.lp-points { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.lp-point h3 { font-size: 16px; margin: 0 0 6px; color: var(--on-bg); }
.lp-point p  { margin: 0; color: var(--on-bg-muted); line-height: 1.55; }

.lp-foot { text-align: center; padding: 30px 16px 70px; }

/* FOOTER ALIGNMENT IS SCOPED TO striprec, NOT GLOBAL. This stylesheet is
   shared with stripcams.me, which is not part of the i18n programme and must
   not move (note #287 §1), so the rule hangs off the .site-striprec class
   layout.php puts on <body>. Covers the landing too, since landing hosts
   carry both classes. */
.site-striprec .site-footer { text-align: center; }

/* 3 wide holds to tablet, then 2, then 1. The grid is the page's whole
   argument, so it degrades rather than shrinking to unreadable thumbnails. */
@media (max-width: 900px) {
    .lp-grid, .lp-points { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
    .lp-grid, .lp-points { grid-template-columns: 1fr; }
}

/* ── Locale switcher (§D22) ────────────────────────────────────────────────
   HOVER dropdown, matching the .cat-item/.cat-dropdown bar beside it. The
   three earlier apps shipped this as a details/summary click-toggle, which put
   two different open behaviours in one header. No JS and no CSP surface:
   :hover for pointers, :focus-within for keyboards.

   THE MENU CARRIES A ::before BRIDGE across the gap below the button. Without
   it the pointer leaves .langsel on the way down and the menu closes under the
   cursor. (Named without angle brackets on purpose -- see the note in the bwv
   stylesheet about tags in comments showing up in markup greps.) */
.langsel { position: relative; margin-left: auto; }
.langsel-btn {
    display: inline-flex; align-items: center; gap: 6px; cursor: default;
    padding: 6px 10px; border: 1px solid var(--border);
    border-radius: var(--radius, 6px); color: var(--on-bg);
    background: var(--surface-2, transparent); font-size: 13px; user-select: none;
}
.langsel-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.langsel-caret { font-size: 10px; opacity: .7; }

.langsel-menu {
    display: none; position: absolute; right: 0; top: calc(100% + 6px);
    min-width: 160px; margin: 0; padding: 6px 0; list-style: none; z-index: 60;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius, 6px); box-shadow: 0 8px 22px rgba(0,0,0,.32);
}
.langsel-menu::before {
    content: ""; position: absolute; left: 0; right: 0; top: -8px; height: 8px;
}
.langsel:hover .langsel-menu,
.langsel:focus-within .langsel-menu { display: block; }

.langsel-menu a {
    display: block; padding: 7px 14px; color: var(--text);
    text-decoration: none; font-size: 13px;
}
.langsel-menu a:hover { background: var(--accent); color: var(--on-accent); }
.langsel-menu a[aria-current="true"] { font-weight: 700; }
