/* Ursine Optics — Broadcast extras
 *
 * Site-specific patterns the broadcast design system doesn't cover, plus a
 * thin reconciliation layer for live behaviors that diverge from the
 * prototype's layout.
 *
 * Loaded AFTER /styles/system.css so override rules win the cascade.
 *
 * Sections:
 *   1. Spinner — broadcast-styled loading indicator
 *   2. State box — error / empty-state container used by gallery.js
 *   3. Toast — bottom-center transient notifications
 *   4. Strap dot pulse — REC-style 2s opacity pulse with reduced-motion guard
 *   5. Lightbox overlay — bridges system.css's full-frame layout to the
 *      live site's overlay-modal toggle pattern
 */

/* ── 1. Spinner ─────────────────────────────────────────────────────── */

.spinner {
  width: 28px;
  height: 28px;
  margin: 4rem auto;
  border: 1px solid var(--ink-rule);
  border-top-color: var(--signal);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ── 2. State box ───────────────────────────────────────────────────── */

.state-box {
  margin: 5rem auto;
  max-width: 460px;
  padding: 24px 28px;
  text-align: center;
  border: 1px solid var(--ink-rule);
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
}

.state-box p {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-mute);
  line-height: 1.6;
}

.state-box a {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 1px;
}

.state-box a:hover {
  color: var(--signal-deep);
  border-bottom-color: var(--signal-deep);
}

/* ── 3. Toast ───────────────────────────────────────────────────────── */

.toast {
  position: fixed;
  bottom: 5.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(0.5rem);
  background: var(--ink);
  color: var(--bone);
  padding: 10px 18px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 2000;
}

.toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ── 4. Strap dot pulse ─────────────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
  .strap__dot {
    animation: strapPulse 2s ease-in-out infinite;
  }
}

@keyframes strapPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

/* ── 5. Lightbox overlay ────────────────────────────────────────────── */

/* system.css's .lightbox is a full-frame layout (display: grid; height: 100%).
 * The live event page uses it as an overlay modal toggled by .is-open from
 * gallery.js. Bridge that here without touching system.css. */

.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  height: auto;
  z-index: 1000;
}

.lightbox.is-open {
  display: grid;
}

/* ── 6. Photo grid overrides ────────────────────────────────────────── */

/* system.css's .grid__cell ships ::before / ::after pseudo-elements that
 * draw stripe textures + radial glows — those are prototype placeholders
 * for "no real photo yet." With real R2 thumbnails sitting on top of the
 * cell, the pseudos become hidden noise (and would peek through any
 * transparent regions of the JPEG). Strip them for our app's grid. */
.grid__cell::before,
.grid__cell::after {
  display: none;
}

/* Photo fills the cell. Sits above the (now-hidden) pseudo-elements. */
.grid__cell img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease, filter 0.3s ease;
}

.grid__cell {
  cursor: pointer;
}
.grid__cell:hover img {
  transform: scale(1.04);
  filter: brightness(1.05);
}
.grid__cell:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: -2px;
}

/* BEM modifier set by photographer-filter JS to hide non-matching cells. */
.grid__cell--hidden {
  display: none;
}

/* Responsive grid -- system.css ships 4 columns hardcoded, which is too
 * cramped on small screens. Match the legacy 4 -> 3 -> 2 column pattern. */
@media (max-width: 700px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 480px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}

/* ── Highlights feature grid -- larger tiles so hero shots read as "best" ── */
/* BEM modifier toggled by JS when the Highlights toggle is active.
 * auto-fit collapses empty tracks; capping the max at a fixed width (not 1fr)
 * stops a lone hero from stretching edge-to-edge (the .grid__cell is 4/3, so a
 * single full-row cell rendered as a giant banner). justify-content centers the
 * capped tracks. Responsive via the same pattern, ref. moderncss.dev/css-tricks. */
.grid--highlights {
  grid-template-columns: repeat(auto-fit, minmax(320px, 420px));
  justify-content: center;
}
@media (max-width: 700px) {
  .grid--highlights { grid-template-columns: repeat(auto-fit, minmax(240px, 340px)); }
}
@media (max-width: 480px) {
  /* Phone: a single full-width hero reads fine, so keep the 1fr fill here. */
  .grid--highlights { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
}

/* ── Highlights toggle button ─────────────────────────────────────── */
/* Rendered just above the grid by JS; hidden when event has no heroes.
 * Uses the same mono / uppercase typography as the contact chip bar. */
#highlights-bar {
  display: flex;
  align-items: center;
  padding: 10px 0 0;
}

.highlights-toggle {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 6px 12px;
  border: 1px solid var(--ink-rule);
  color: var(--ink-2);
  cursor: pointer;
  /* Smooth transition on background for non-reduced-motion environments. */
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

/* Pressed state -- not color-only: background fill + text-decoration underline
 * provides two distinct non-color cues (shape change + decoration). */
.highlights-toggle[aria-pressed="true"] {
  background: var(--ink);
  color: var(--bone);
  border-color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Hover state for the unpressed button. */
.highlights-toggle:hover:not([aria-pressed="true"]) {
  border-color: var(--ink-2);
  color: var(--ink);
}

/* focus-visible ring: inherited from the global button:focus-visible rule in
 * extras.css (2px solid var(--signal), outline-offset: 2px). No override needed. */

/* Reduced-motion: kill the transition on the toggle button background. */
@media (prefers-reduced-motion: reduce) {
  .highlights-toggle {
    transition: none;
  }
}

/* ── Empty-intersection message ────────────────────────────────────── */
/* Shown by applyFilters() when highlightsOn=true and visiblePhotoNs is
 * empty (e.g. selected photographer has no hero-rated photos).
 * Uses [hidden] to hide (native semantics; no class toggle needed). */
.highlights-empty {
  padding: 32px 0;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-mute);
  text-align: center;
}
.highlights-empty p {
  margin: 0;
}

/* ── 7. Contact-chip avatar ─────────────────────────────────────────── */

/* Tiny round avatar inside .contact__chip, replacing the design's solid
 * dot. Live photographers have real face photos and the personal
 * recognition value is worth the slight aesthetic departure. */
.contact__chip-avatar {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

/* ── 8. Lightbox photo + avatar + button hover ──────────────────────── */

/* system.css's .lightbox__photo is a placeholder div with stripe texture
 * for the prototype. Real photos use <img class="lightbox__photo"> that
 * needs to size to viewport, not a fixed 80% aspect-ratio panel. */
.lightbox__photo {
  width: auto;
  max-width: 100%;
  max-height: calc(100vh - 180px);
  aspect-ratio: auto;
  background: none;
  border: 0;
  object-fit: contain;
  display: block;
}
.lightbox__photo::after { display: none; }

/* When the credit avatar is a real <img>, override system.css's inline-flex
 * text-avatar defaults so the photo crops cleanly inside the round border. */
img.lightbox__avatar {
  object-fit: cover;
  background: var(--signal);  /* visible during img load and as load-failure fallback */
}

/* Lightbox button hover — system.css ships static styles only. */
.lightbox__btn:hover {
  background: oklch(20% 0.012 260);
  border-color: oklch(58% 0.012 260);
}
.lightbox__btn--accent:hover {
  background: var(--bone);
  border-color: var(--bone);
  color: var(--ink);
}

/* Nav arrow hover + disabled. system.css gives the boxes a static look;
 * adding hover + disabled cues makes prev/next interactive affordances clear. */
.lightbox__nav { cursor: pointer; }
.lightbox__nav:hover {
  background: oklch(28% 0.014 260);
  border-color: var(--signal);
}
.lightbox__nav:disabled {
  opacity: 0.3;
  cursor: not-allowed;
  background: oklch(16% 0.012 260);
  border-color: oklch(28% 0.014 260);
}

/* Ursine Optics — v3 patches (append to /styles/extras.css)
 *
 * Fixes for issues reported after v2:
 *   1. Mobile lightbox nav buttons overlapping the image
 *   2. Admin bar covering the lightbox close button
 *   3. (no CSS change — covered in PATCHES.md HTML edits)
 */

/* ── 1. Lightbox nav: above the image, never overlapping it ───────── */

/* Source-order has <button-prev> BEFORE <img>, so without an explicit
   z-index the prev arrow sits behind the image. Lift both nav buttons
   above the image on every viewport. */
.lightbox__nav {
  z-index: 2;
}

/* On mobile, the stage padding (16px) is narrower than the nav button
   width (36px), so a full-bleed image sits underneath the arrows.
   Reserve horizontal space for the buttons so the image visibly sits
   between them. */
@media (max-width: 960px) {
  .lightbox__stage { padding: 12px 52px; }
  .lightbox__photo { max-height: calc(100vh - 220px); }
  .lightbox__nav--prev { left: 6px; }
  .lightbox__nav--next { right: 6px; }
}

/* ── 2. Lightbox above the admin bar ───────────────────────────────── */

/* admin-bar.js sets z-index: 9999 on the fixed admin bar. The lightbox
   overlay in extras.css ships at z-index: 1000, so the admin bar covers
   the lightbox top row (and the Close button). Raise the lightbox above
   the admin bar so the modal owns the viewport while open. */
.lightbox {
  z-index: 10000;
}

/* ── v5 accessibility patches ────────────────────────────────────────
 * Source: design_handoff_v6/patches/a11y.v5.patch.css
 * Appended per Slice 1 of plans/active/a11y-broadcast-pass/plan.md
 */

/* ── #1 + #3 — Contrast + size lifts ─────────────────────────────── */

/* Darken muted ink so 10–12px text clears 4.5:1 on bone/paper.
   Old value was oklch(48% ...) ≈ #6e6e80 — borderline 4.0:1.
   New value oklch(40% ...) ≈ #54546b — ~5.6:1, comfortable AA. */
:root {
  --ink-mute: oklch(40% 0.012 260);
  --cull-ink-3: oklch(66% 0.012 260);  /* lift muted text on dark surface */
  --cull-ink-4: oklch(56% 0.012 260);  /* placeholders / disabled */
}

/* Strap "grow" cell — was oklch(72% ...) on dark ink (~3.8:1). Lift to bone. */
.strap__cell--grow { color: oklch(86% 0.008 260); }

/* Floor mono labels at 11px (was 9–10px). Aesthetic still tight. */
.kicker,
.stat__label,
.event__sub,
.contact__bar-meta,
.contact__chip,
.contact__chip-dot,
.foot,
.lightbox__top, .lightbox__bot,
.lightbox__btn,
.board__pill,
.board__meta,
.events__filter,
.picker__sub,
.picker__pill,
.picker__hint,
.picker__lbl,
.heroE__kicker,
.heroE__sub,
.tonight__kicker,
.tonight__meta,
.tonight__cta,
.seasonbar__head,
.seasonbar__quick,
.grid__num,
.grid__corner {
  font-size: max(11px, 0.6875rem);
}

/* Picker pill — was 9px, clearly fails. Lift + reduce letter-spacing. */
.picker__pill { font-size: 11px; letter-spacing: 0.16em; padding: 5px 10px; }

/* ── #2 — Focus visibility ─────────────────────────────────────── */

/* Global focus ring on every interactive element. Two-tone so it works
   on bone surfaces (signal blue) and dark surfaces (signal blue is still
   visible — the contrast layer handles low-contrast cases). */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
details:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Picker rows and Tonight CTA — block elements need offset:0 because
   they butt up against page edges / siblings. */
.picker__row:focus-visible,
.tonight:focus-visible,
.board__row:focus-visible,
.event:focus-visible {
  outline: 3px solid var(--signal);
  outline-offset: -3px;
}

/* Lightbox buttons sit on a dark surface — same blue still visible. */
.lightbox__btn:focus-visible,
.lightbox__nav:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}

/* ── #4 — Hide decorative children from screen readers ──────────── */

/* These are visual punctuation only. Add aria-hidden="true" in markup
   (this CSS rule is a fallback that suppresses content if author forgets). */
.strap__dot,
.wordmark__mark,
.heroE__kicker::before,
.tonight__kicker::before,
.tonight__cta__arrow,
.picker__arrow,
.board__arrow,
.seasonbar__chev,
.lightbox__nav::before {
  speak: none;
}

/* ── #6 — Skip to main content ─────────────────────────────────── */

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20000;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 12px 18px;
  text-decoration: none;
}
.skip-link:focus { left: 0; outline: 2px solid var(--signal); outline-offset: 2px; }

/* ── #10 — Reduced motion ───────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* Disable the picker row "slide" hover and tonight card "lift". */
  .picker__row:hover { padding-left: 32px; }
  .tonight:hover { transform: none; }
  .tonight:hover .tonight__cta__arrow,
  .picker__row:hover .picker__arrow { transform: none; }
}
