/* DUB MIAMI — deep black + elegant orange. ALL visible text uppercase
   (visual only, via text-transform — stored data is never changed). */
:root {
  --bg: #050505;
  --panel: #101010;
  --panel2: #171717;
  --line: #262626;
  --text: #f2f2f2;
  --muted: #9a9a9a;
  --orange: #ff7a00;
  --orange-soft: #ff9a33;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: "Helvetica Neue", Arial, sans-serif;
  text-transform: uppercase;
  letter-spacing: .02em;
  min-height: 100vh;
}
a { color: var(--orange-soft); text-decoration: none; }
button, input, select, textarea { text-transform: uppercase; font-family: inherit; }
input[type="date"], input[type="datetime-local"] { text-transform: none; }
.agreement-text { text-transform: none; white-space: pre-wrap; }

.topbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 20px; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: rgba(5,5,5,.92); z-index: 10;
}
.brand { font-weight: 900; font-size: 22px; color: var(--text); letter-spacing: .08em; }
.brand::after { content: ""; }
.topnav { display: flex; gap: 8px; }
.chip {
  background: var(--panel2); color: var(--text); border: 1px solid var(--line);
  padding: 7px 12px; border-radius: 999px; font-size: 12px; cursor: pointer;
}
.chip:hover { border-color: var(--orange); color: var(--orange-soft); }

main { max-width: 980px; margin: 0 auto; padding: 24px 16px 64px; }
.footer {
  text-align: center; color: var(--muted); padding: 28px 16px 40px;
  border-top: 1px solid var(--line); font-size: 13px; letter-spacing: .3em;
}

.hero { text-align: center; padding: 48px 0 8px; }
.hero .logo { font-size: clamp(64px, 14vw, 120px); font-weight: 900; line-height: .95; letter-spacing: .02em; }
.hero .tagline { color: var(--orange); font-size: clamp(18px, 4.5vw, 30px); font-weight: 800; margin-top: 10px; }
.hero .byline { color: var(--muted); margin-top: 6px; font-size: 14px; }

.paths { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin: 36px 0 8px; }
@media (max-width: 640px) { .paths { grid-template-columns: 1fr; } }
.path-card {
  display: block; background: var(--panel); border: 1px solid var(--line);
  border-radius: 14px; padding: 28px 22px; color: var(--text);
}
.path-card:hover { border-color: var(--orange); }
.path-card .big { font-size: 24px; font-weight: 900; color: var(--orange); }
.path-card .sub { color: var(--muted); margin-top: 8px; font-size: 13px; }

.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 30px 0; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 18px; text-align: center; }
.stat .num { font-size: 34px; font-weight: 900; color: var(--orange); }
.stat .lbl { color: var(--muted); font-size: 12px; margin-top: 4px; }

h2.section { font-size: 20px; font-weight: 900; margin: 36px 0 14px; }
h2.section .accent { color: var(--orange); }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 14px; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 18px; }
.card h3 { margin: 0 0 6px; font-size: 18px; }
.card .meta { color: var(--muted); font-size: 13px; line-height: 1.5; }
.card a.card-link { color: inherit; display: block; }
.venue-address { margin: 6px 0 0; }
a.addr-link { color: var(--muted); }
a.addr-link:hover { color: var(--orange); }
.card img.cover, .panel img.cover { width: 100%; height: 150px; object-fit: cover; border-radius: 8px; margin-bottom: 12px; background: #000; }
.event-flyer { width: 100%; display: block; border: 1px solid var(--line); border-radius: 12px; margin: 0 0 18px; background: #0c0c0e; }
.mode-tag { display: inline-block; border: 1px solid var(--orange); color: var(--orange-soft); border-radius: 999px; padding: 3px 10px; font-size: 11px; margin-top: 8px; }

.btn {
  display: inline-block; background: var(--orange); color: #000; font-weight: 800;
  border: none; border-radius: 10px; padding: 12px 18px; font-size: 14px; cursor: pointer;
}
.btn:hover { background: var(--orange-soft); }
.btn.ghost { background: transparent; color: var(--orange-soft); border: 1px solid var(--orange); }
.btn.small { padding: 7px 12px; font-size: 12px; border-radius: 8px; }
.btn.danger { background: transparent; color: #ff5252; border: 1px solid #662222; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

form .field { margin-bottom: 14px; }
label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }
input, select, textarea {
  width: 100%; background: var(--panel2); border: 1px solid var(--line); color: var(--text);
  border-radius: 8px; padding: 11px 12px; font-size: 14px;
}
textarea { min-height: 90px; resize: vertical; }
input:focus, select:focus, textarea:focus { outline: 1px solid var(--orange); }
.row { display: flex; gap: 10px; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 140px; }

.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 20px; margin-bottom: 16px; }
.muted { color: var(--muted); }
.orange { color: var(--orange); }
.err { background: #2a0f0f; border: 1px solid #662222; color: #ff9a9a; padding: 10px 14px; border-radius: 8px; margin-bottom: 14px; font-size: 13px; }
.ok-note { background: #0f2412; border: 1px solid #1f5c2a; color: #9fe8ab; padding: 10px 14px; border-radius: 8px; margin-bottom: 14px; font-size: 13px; }
.warn-note { background: #2a2008; border: 1px solid #6b5518; color: #ffd97a; padding: 10px 14px; border-radius: 8px; margin-bottom: 14px; font-size: 13px; }
.scan-overlay { position: fixed; inset: 0; z-index: 100; background: #000; display: flex; flex-direction: column; padding: 16px; overflow-y: auto; }
.scan-overlay video { flex: 1; width: 100%; min-height: 0; object-fit: cover; border-radius: 12px; background: #111; }
.scan-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.scan-overlay #scanMsg:empty { display: none; }
.scan-overlay #scanMsg { margin-top: 12px; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 9px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
th { color: var(--muted); font-size: 11px; }
.avatar { width: 42px; height: 42px; border-radius: 50%; object-fit: cover; background: #000; vertical-align: middle; }
.avatar-lg { width: 110px; height: 110px; border-radius: 12px; object-fit: cover; background: #000; }

.ticket { background: #0b0b0b; border: 1px dashed var(--orange); border-radius: 14px; padding: 22px; text-align: center; }
.ticket canvas { background: #fff; border-radius: 8px; padding: 6px; }
.ticket .code { font-size: 22px; font-weight: 900; color: var(--orange); letter-spacing: .1em; }

.lineup-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.lineup-item .who { flex: 1; }
.lineup-item .set-time { color: var(--orange-soft); font-weight: 700; }
.lineup-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px 14px; }
@media (max-width: 640px) { .lineup-grid { grid-template-columns: repeat(2, 1fr); } }
.dj-tile { text-align: center; }
.dj-tile .dj-photo { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 12px; background: #000; display: block; }
.dj-tile .dj-initials { display: flex; align-items: center; justify-content: center; border: 1px solid var(--line); background: repeating-linear-gradient(45deg, #0b0b0b 0 10px, #141414 10px 20px); color: var(--orange); font-weight: 800; font-size: 42px; }
.dj-tile .dj-name { margin-top: 8px; font-weight: 700; text-transform: uppercase; }
.dj-tile .dj-set { color: var(--muted); font-size: 12px; margin-top: 2px; }
.going-grid { display: flex; flex-wrap: wrap; gap: 16px 12px; }
.going-chip { width: 76px; text-align: center; }
.going-chip .avatar { width: 52px; height: 52px; }
.going-chip .initials { display: inline-flex; align-items: center; justify-content: center; width: 52px; height: 52px; border-radius: 50%; background: #000; border: 1px solid var(--orange); color: var(--orange-soft); font-weight: 800; font-size: 17px; }
.going-name { font-size: 12px; color: var(--muted); margin-top: 6px; text-transform: uppercase; }

.agreement-box { background: #0a0a0a; border: 1px solid var(--line); border-radius: 10px; padding: 16px; max-height: 340px; overflow: auto; font-size: 13px; line-height: 1.55; }
.tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.tabs .chip.active { background: var(--orange); color: #000; border-color: var(--orange); font-weight: 800; }
details summary { cursor: pointer; color: var(--orange-soft); font-size: 13px; margin: 8px 0; }

/* ================= v5 — WARM / ALIVE BACKGROUND =================
   Real DUB event photos under a dark treatment, film grain, faint
   orange glows and glassier cards. Brand (black + orange) unchanged. */

/* v25 (item 51) — the page background is a LAYERED texture, CSS-only:
   fine SVG noise + a brand-orange glow anchored at the top (5.5%) +
   two whisper glows + a soft dark vertical gradient over near-black.
   It is the body's own background — always BEHIND the content, painted
   in the first frame with the shell, zero image downloads, zero extra
   requests. Texture you feel, not a pattern you stare at; the black +
   orange identity is untouched. (Before v25 the grain rode ABOVE the
   content as a body::after overlay and the mid-page still read flat —
   the noise now lives in this stack instead; do not re-add the
   overlay, it would double the grain and sit on top of the text.) */
body {
  background-color: var(--bg);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),
    radial-gradient(900px 480px at 50% -120px, rgba(255,122,0,.055), transparent 62%),
    radial-gradient(820px 540px at 90% 32%, rgba(255,122,0,.04), transparent 62%),
    radial-gradient(760px 520px at 50% 110%, rgba(255,122,0,.04), transparent 62%),
    linear-gradient(180deg, #080808 0%, var(--bg) 46%, #040404 100%);
  background-size: 180px 180px, auto, auto, auto, auto;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat, no-repeat;
  background-attachment: fixed;
}

/* hero: real crowd photo, dark-treated, melting into black */
.hero { position: relative; isolation: isolate; }
.hero::before {
  content: ""; position: absolute; z-index: -2;
  top: -24px; bottom: -72px; left: -16px; right: -16px;
  background: url("/img/hero.jpg") center 36% / cover no-repeat;
  filter: brightness(.42) saturate(1.08);
}
.hero::after {
  content: ""; position: absolute; z-index: -1;
  top: -24px; bottom: -72px; left: -16px; right: -16px;
  background:
    radial-gradient(58% 46% at 50% 40%, rgba(255,122,0,.17), transparent 70%),
    linear-gradient(to bottom, rgba(5,5,5,.42) 0%, rgba(5,5,5,.16) 34%, rgba(5,5,5,.60) 74%, var(--bg) 100%);
}
.hero .logo { text-shadow: 0 2px 34px rgba(0,0,0,.6); }
.hero .tagline { text-shadow: 0 2px 18px rgba(0,0,0,.65); }
.hero .byline { color: #c4c4c4; text-shadow: 0 1px 10px rgba(0,0,0,.7); }
@media (max-width: 640px) {
  .hero::before, .hero::after { bottom: -56px; }
  .hero::before { background-position: center 30%; }
}

/* cards: dark glass with a hairline top highlight */
.path-card, .stat, .card, .panel {
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.012) 55%), var(--panel);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 12px 32px rgba(0,0,0,.35);
}

/* footer: second photo band behind the sign-off line */
.footer { position: relative; isolation: isolate; color: #d9d9d9; text-shadow: 0 1px 12px rgba(0,0,0,.8); }
.footer::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background: url("/img/band.jpg") center 42% / cover no-repeat;
  filter: brightness(.33) saturate(1.06);
}
.footer::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to bottom, var(--bg) 0%, rgba(5,5,5,.40) 46%, rgba(5,5,5,.74) 100%);
}

/* v8 fix: stats row paints above the hero photo fade (numbers were clipped) */
.stats { position: relative; z-index: 2; }

/* ================= v17 — DJ PROFILE LINKS + GUEST DRILL-DOWN =================
   Functional rules for the new interactive elements (all widths). */
a.dj-tile { display: block; color: var(--text); }
a.dj-tile:hover .dj-name { color: var(--orange-soft); }
.guest-link { cursor: pointer; }
.guest-link:hover strong { color: var(--orange-soft); text-decoration: underline; }

/* ================= v17 — DESKTOP SCALE-DOWN =================
   Owner feedback: on a computer everything renders too big (the event
   flyer especially). Tighten the desktop layout ~10–15% across the
   board. Mobile (<1024px) is intentionally untouched. */
@media (min-width: 1024px) {
  main { max-width: 880px; padding-top: 18px; }
  .hero { padding: 34px 0 4px; }
  .hero .logo { font-size: 96px; }
  .hero .tagline { font-size: 25px; }
  .paths { margin-top: 26px; }
  .path-card { padding: 22px 18px; }
  .path-card .big { font-size: 21px; }
  .stats { margin: 22px 0; }
  .stat { padding: 14px; }
  .stat .num { font-size: 29px; }
  h1 { font-size: 27px; }
  h2.section { font-size: 18px; margin: 28px 0 12px; }
  .card { padding: 15px; }
  .card h3 { font-size: 16px; }
  .card img.cover, .panel img.cover { height: 128px; }
  .event-flyer { max-width: 600px; margin-left: auto; margin-right: auto; }
  .panel { padding: 17px; }
  .avatar-lg { width: 92px; height: 92px; }
  .btn { padding: 10px 16px; }
}

/* ================= v18 — READABLE AGREEMENTS =================
   The agreement texts used to render as one raw pre-wrap wall inside
   .agreement-box. agreementHtml() now emits structured blocks (titles,
   clause headings, paragraphs, dividers) styled here. Natural case is
   forced: the legal text reads as written, not in the app's caps voice. */
.agreement-doc { font-size: 13.5px; line-height: 1.6; text-transform: none; }
.agreement-doc .agr-sec { margin-bottom: 1.1em; }
.agreement-doc .agr-sec:last-child { margin-bottom: 0; }
.agreement-doc .agr-title { font-size: 15px; font-weight: 900; letter-spacing: .06em; color: var(--text); margin: 2px 0 8px; }
.agreement-doc .agr-h { font-size: 13px; font-weight: 800; letter-spacing: .05em; color: var(--orange-soft); margin: 1.4em 0 .45em; }
.agreement-doc .agr-sec > .agr-h:first-child { margin-top: .15em; }
.agreement-doc .agr-p { margin: 0 0 .9em; }
.agreement-doc .agr-p:last-child { margin-bottom: 0; }
.agreement-doc .agr-li { padding-left: 14px; }
.agreement-doc .agr-div { border: none; border-top: 1px solid var(--line); margin: 1.3em 0; }

/* ---- v19: long-form body copy (event descriptions, guest-list /
   reservation notes, release descriptions) reads in NATURAL case with
   friendly body typography. Brand caps stay on titles, headings, buttons,
   labels and stats — this class is the only exception. */
.body-copy { text-transform: none; font-size: 15.5px; line-height: 1.6; letter-spacing: 0; }
p.body-copy { margin: 0 0 12px; }

/* ================= v20 — HEADING BALANCE, EVENT TITLE, LINK CHIPS ======
   Owner feedback, two layout fixes:
   (1) Big headings wrapped with a lone orphan token dangling ("…THU NOV /
   19"). Large headings now balance their lines, and the event/venue page
   title gets a responsive clamp() size so typical titles sit evenly on
   mobile widths. Layout only — brand caps and wording untouched.
   (2) The DJ profile link chips were inline pills inside a <p>: their
   vertical padding overflows the line box, so wrapped rows piled onto each
   other and long labels clipped at the card edge. They now live in a
   wrapped flex row where each chip is a real box that flows to the next
   line and ellipsizes instead of pushing out of the card. */
h1, h2.section, .card h3, .path-card .big { text-wrap: balance; }
.event-title { font-size: clamp(24px, 6.2vw, 34px); line-height: 1.12; }
@media (min-width: 1024px) { .event-title { font-size: 28px; } }
.link-chips {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  max-width: 100%; margin: 16px 0 2px;
}
.link-chips .chip {
  flex: 0 1 auto; min-width: 0; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ================= v21 — ORGANIZER MOBILE PASS + TRACK LINKS ============
   Owner screenshots from his iPhone (~390px): the DJs table forced the
   whole page to desktop width (iOS zoomed out, form cards squeezed to
   ~55%), two-column form rows overlapped (the event form's MODO select
   over the FECHA field), and lineup editor controls clipped off-screen.
   Fixes: wide tables scroll INSIDE their own box, form rows become
   shrink-safe grids that stack on phones, lineup rows wrap, and the
   panel can never push the page sideways. */

/* backstop: content may scroll inside components, never the page itself */
main { overflow-x: clip; }

/* wide admin tables live in a horizontal scroller */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.table-scroll > table { width: 100%; }
.table-scroll.wide > table { min-width: 640px; }

/* form rows: equal grid columns that can actually shrink (minmax 0),
   so selects/inputs stop overlapping; controls never exceed the row */
.frow {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: 12px; margin-bottom: 14px;
}
.frow .field { margin-bottom: 0; min-width: 0; }
.frow input, .frow select, .frow textarea { min-width: 0; width: 100%; }
input, select, textarea { max-width: 100%; }

/* event detail header row (door list title + download button) */
.panel-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap; margin-bottom: 14px;
}

/* Posh-style track links (organizer event detail) */
.track-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.track-row:last-child { border-bottom: none; }
.track-who { flex: 1; min-width: 0; }
.track-nums { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px; font-size: 13px; }
.track-nums strong { color: var(--orange-soft); }
.track-link {
  text-transform: none; font-size: 12.5px; color: var(--muted);
  word-break: break-all; user-select: all; -webkit-user-select: all; margin-top: 6px;
}

@media (max-width: 640px) {
  /* every organizer form row stacks: one full-width field per line */
  .frow { grid-auto-flow: row; grid-auto-columns: unset; grid-template-columns: minmax(0, 1fr); }
  /* lineup / door / application rows wrap instead of clipping buttons */
  .lineup-item { flex-wrap: wrap; row-gap: 8px; }
  .lineup-edit .who { flex: 1 1 100%; }
  .lineup-edit input.setTimeInput { flex: 1 1 110px; width: auto !important; min-width: 0; }
  .track-row { gap: 10px; }
}

/* ================= v22 — ORGANIZER CHROME, SHARE, META, CONSISTENCY ====
   Owner priority this pass: the ORGANIZER panel on his phone. His Create
   Event screenshot showed the admin tab bar wider than the screen (tabs
   clipped mid-word at BOTH edges, bleeding into the header zone) and the
   panel header row clipped (logo cut at the left, Log out half off the
   right edge). Client views only gain the share button + meta segments. */

/* --- organizer tab strip: ONE scrollable row, never a page-wide row ---
   The strip scrolls inside itself (touch, scrollbar hidden); chips keep
   their natural width so no label is ever clipped mid-word, and the app
   scrolls the active chip into view (wireOrgLogout). */
.tabs {
  flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none; max-width: 100%; padding-bottom: 2px;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs .chip { flex: none; white-space: nowrap; padding: 8px 14px; }

/* --- top header must fit a phone: shrink before anything can clip --- */
@media (max-width: 480px) {
  .topbar { padding: 12px 14px; }
  .brand { font-size: 19px; }
  .topnav { gap: 6px; }
  .topnav .chip { padding: 6px 10px; font-size: 11px; white-space: nowrap; }
}

/* --- share affordances --- */
.share-row { margin: 0 0 18px; }
.gig-link {
  text-transform: none; user-select: all; -webkit-user-select: all;
  word-break: break-all;
}

/* --- event meta segments: the address NEVER splits mid-address --------
   Date · venue · address render as non-breaking segments. The line wraps
   BETWEEN segments (the address drops whole to its own line) instead of
   inside the address. Cards/venue lines reuse .meta-addr inline. */
.event-meta {
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 8px;
  color: var(--muted); font-size: 14.5px; margin: 0 0 14px;
}
.event-meta .meta-seg { white-space: nowrap; }
.event-meta .meta-seg + .meta-seg::before { content: "·"; margin-right: 8px; }
.meta-addr { white-space: nowrap; }
@media (max-width: 400px) { .event-meta { font-size: 13.5px; } }
.card .meta .meta-addr { font-size: 12px; letter-spacing: 0; }
.venue-address { font-size: 14px; }

/* --- door section: one-line mode hint --- */
.door-hint { font-size: 12.5px; margin: 0 0 12px; }

/* --- consistency normalization (existing tokens only) ---
   - base h1/h3 type styles replace browser defaults + per-screen hacks;
     panel-first headings get their flush top from ONE rule instead of
     21 inline style="margin-top:0" copies (all stripped in v22);
   - .card padding now matches .panel at both breakpoints;
   - one-off inline styles became named classes. */
h1 { font-size: 30px; font-weight: 900; line-height: 1.15; margin: 0 0 10px; }
@media (min-width: 1024px) { h1 { font-size: 27px; } }
h3 { font-size: 15px; font-weight: 800; margin: 18px 0 8px; }
:is(.panel, .ticket) > h3:first-child { margin-top: 0; }
.panel > h2.section:first-child { margin-top: 0; }
.panel-head > h2.section { margin: 0; }
.card { padding: 20px; }
@media (min-width: 1024px) { .card { padding: 17px; } }
.panel.center { text-align: center; }
.panel.nested { background: var(--panel2); margin-top: 14px; }
.panel.spaced { margin-top: 24px; }
.lineup-item.flush { border-bottom: none; padding-top: 0; }
.out-box { margin-top: 14px; }
.home-foot { text-align: center; margin-top: 36px; }
.row.center { align-items: center; }
.avatar-ph {
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); color: var(--orange);
  font-weight: 800; font-size: 38px;
}
img.cover.venue-hero {
  width: 100%; height: auto; max-height: 260px; object-fit: cover;
  border-radius: 12px; margin-bottom: 14px; background: #000;
}

/* --- photo pick feedback (v22): the processed thumbnail appears in the
   form the moment a file is picked — proof it took, before saving. An
   unreadable file shows the standard .err box in the same slot. */
.photo-preview { margin-top: 10px; }
.photo-preview:empty { margin-top: 0; }
.photo-thumb {
  width: 110px; height: 110px; object-fit: cover; display: block;
  border-radius: 12px; border: 1px solid var(--line); background: #000;
}

/* ================= v23 — SIMPLE HOME, THREE DOORS, REAL SECTIONS ======
   Owner pass: the home is hero + three doors + events, nothing else.
   The hero photo now ENDS at the hero (v22 let it bleed 72px under the
   doors — the overlap he flagged); doors get real presence on desktop;
   sections open with a centered header + rule so they read as sections. */

.hero::before, .hero::after { bottom: 0; }
.hero { padding-bottom: 44px; }
.hero .byline a { color: #c4c4c4; }
.hero .byline a:hover { color: var(--orange-soft); }

.paths {
  grid-template-columns: repeat(3, 1fr); gap: 16px;
  margin: 34px 0 10px; position: relative; z-index: 2;
}
.path-card { text-align: center; padding: 34px 20px; border-radius: 16px; }
.path-card .door-icon { font-size: 34px; line-height: 1; margin-bottom: 12px; }
.path-card .big { font-size: 25px; }
.path-card:hover { transform: translateY(-2px); }
.path-card { transition: transform .15s ease, border-color .15s ease; }
@media (max-width: 760px) { .paths { grid-template-columns: 1fr; } .path-card { padding: 26px 18px; } }

/* section headers: centered title, orange rule with a diamond */
.section-head { text-align: center; margin: 52px 0 20px; }
.section-head h2 {
  font-size: 26px; font-weight: 900; letter-spacing: .06em; margin: 0;
  text-wrap: balance;
}
.section-rule {
  width: 120px; height: 2px; margin: 12px auto 0; position: relative;
  background: linear-gradient(90deg, transparent, var(--orange), transparent);
}
.section-rule::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 7px; height: 7px; background: var(--orange);
  transform: translate(-50%, -50%) rotate(45deg);
}
@media (min-width: 1024px) { .section-head h2 { font-size: 23px; } }

/* stats grids adapt to 3 or 4 cards (work page + organizer home) */
.stats { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
a.stat { display: block; color: var(--text); }
a.stat:hover { border-color: var(--orange); }

/* party page venue filter */
.filter-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 0 0 18px; }
.filter-row .chip.active { background: var(--orange); color: #000; border-color: var(--orange); font-weight: 800; }

/* Dice button on the event page */
.dice-row { margin: 0 0 18px; }
.btn.dice { background: #101010; color: var(--orange-soft); border: 1px solid var(--orange); }
.btn.dice:hover { background: #1c1c1c; color: var(--orange); }

/* work-with-us concept tabs */
.work-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 18px 0 22px; }
.work-tab {
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  border-radius: 14px; padding: 18px 12px; font-size: 19px; font-weight: 900;
  letter-spacing: .05em; cursor: pointer;
}
.work-tab.active { border-color: var(--orange); color: var(--orange); background: linear-gradient(180deg, rgba(255,122,0,.10), rgba(255,122,0,.02)), var(--panel); }

/* organizer DJ list: the name is the door to the internal profile */
a.dj-name-link { color: var(--text); }
a.dj-name-link:hover strong { color: var(--orange-soft); text-decoration: underline; }

/* footer socials */
.footer .socials {
  display: flex; justify-content: center; gap: 8px; flex-wrap: nowrap;
  margin-bottom: 16px; letter-spacing: .05em; padding: 0 6px;
}
.footer .social-link {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; min-width: 0;
  background: rgba(10,10,10,.72); border: 1px solid var(--line);
  color: #f2f2f2; border-radius: 999px; padding: 8px 12px;
  font-size: 12px; font-weight: 700; text-shadow: none;
}
.footer .social-link:hover { border-color: var(--orange); color: var(--orange-soft); }
.footer .social-link svg { width: 16px; height: 16px; fill: currentColor; flex: none; }
/* v24: the three social pills ALWAYS share one row on phones (owner
   rule, like the PLUR line below them) — narrow screens shrink the type
   and padding instead of wrapping 2+1. */
@media (max-width: 430px) {
  .footer .socials { gap: 6px; padding: 0 4px; letter-spacing: 0; }
  .footer .social-link { padding: 7px 8px; font-size: 10.5px; gap: 5px; }
  .footer .social-link svg { width: 13px; height: 13px; }
}


/* ================= v25 — items 41, 42, 34, 43, 48, 50 ================= */
/* 41 — native date/time inputs stay INSIDE their field at any width:
   full-width like every other field, shrinkable to zero, and the value
   left-aligned so a long "Nov 14, 2026 · 9:00 PM" never pushes the box
   past the card edge (the panel screenshot that overflowed the screen). */
input[type="datetime-local"], input[type="date"] {
  width: 100%; min-width: 0; max-width: 100%; text-align: left;
}
/* 42 — the sticky top header is fully OPAQUE: panel back links (and any
   content) sliding beneath it while scrolling no longer ghost through
   the translucent bar and read as "covered by the header". Back links
   also get their own stacking + breathing room. */
.topbar { background: #050505; }
.backlink { position: relative; z-index: 2; margin: 2px 0 10px; }
.backlink a { display: inline-block; padding: 4px 0; }
/* 34 — Stripe paid markers: a quiet green, readable on the door list,
   the guest detail and the guest's own profile. */
.paid-inline { color: #9fe8ab; font-weight: 800; }
.paid-chip { border-color: #1f5c2a; color: #9fe8ab; }
/* 43 — release platform buttons sit under the card meta like the DJ
   profile link chips. */
.plat-row { margin-top: 10px; justify-content: flex-start; }
/* 48 — the DJ door on This is DUB: a full path-card between the concept
   tabs and the venue form. */
.path-card.dj-door { margin: 26px 0 4px; text-align: center; }
/* 50 — the followers band reads as a clean 2×2 SQUARE on phones (four
   cards since @newkids_dj_school joined) and one row of four on
   desktop. */
.stats.followers { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 641px) { .stats.followers { grid-template-columns: repeat(4, 1fr); } }
/* v26 (items 56/58): a two-card followers band (DNTD: Instagram +
   Facebook) keeps two wide columns at desktop width too — the pair
   fills the band evenly instead of leaving a half-empty 4-col row. */
@media (min-width: 641px) { .stats.followers.duo { grid-template-columns: repeat(2, 1fr); } }
/* 52 — marketing-consent marker in Tu Audiencia (same quiet green as
   the PAID markers; capture only, no sending reads it yet). */
.promo-chip { border-color: #1f5c2a; color: #9fe8ab; }

/* ================= v28.1 — FONDO VIVO, INTENSIDAD SUBIDA (PROPUESTA, SIN DESPLEGAR) =================
   Reydel (29-oct): "que el fondo no se vea solo negro" — textura con un
   poco más de dinamismo y movimiento, sin tocar la marca (negro + naranja
   DUB) ni la velocidad. Todo CSS, cero JS, cero imágenes nuevas.
   v28.1 (mismo día, tras ver la primera propuesta): "se ve un poquito
   mejor pero casi no se nota — que se note un poquito más". Subida de
   intensidad: resplandores ~1.9× más presentes y más grandes/suaves,
   grano .065 → .09, deriva 27s → 19s con más recorrido y respiración
   más amplia. Sigue siendo ambiente de club, no una marquesina.

   Capas (de atrás hacia adelante):
   1. La base de la v25 se mantiene (grano SVG + brillos fijos + degradado),
      con dos toques: el grano sube de .05 a .09 (textura que se siente
      de verdad, sin ensuciar el texto)
      y se suma una VIÑETA suave como primera capa del fondo del body —
      oscurece apenas las esquinas y le da profundidad de "sala oscura".
      Vive en el background del body (detrás de todo), NO es un overlay.
   2. body::before — UNA capa fija de resplandores naranja que DERIVAN
      lento (19s, ida y vuelta) con transform/opacity: es el
      movimiento ambiental de toda la página. Ojo: esto NO es el overlay
      de grano sobre el contenido que la v25 prohibió re-agregar — aquel
      iba ENCIMA del texto (body::after con ruido); este va DETRÁS
      (z-index:-1, sin textura, solo luz) y el texto ni lo toca.
   3. El resplandor del hero "respira" (opacity, 7s) y la banda de foto
      del footer hace un zoom lentísimo (transform, 24s).
   4. Las tarjetas-puerta (.path-card) ganan un brillo que las cruza
      despacio (sheen) y todas las tarjetas un levante de 2px al hover:
      micro-vida sin mareo.
   prefers-reduced-motion apaga TODO el movimiento nuevo. */

body {
  background-image:
    radial-gradient(118% 88% at 50% 42%, transparent 56%, rgba(0,0,0,.30) 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.09 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),
    radial-gradient(1100px 560px at 50% -120px, rgba(255,122,0,.10), transparent 64%),
    radial-gradient(1000px 620px at 90% 32%, rgba(255,122,0,.075), transparent 64%),
    radial-gradient(950px 600px at 50% 110%, rgba(255,122,0,.075), transparent 64%),
    linear-gradient(180deg, #0a0a0a 0%, var(--bg) 46%, #030303 100%);
  background-size: auto, 180px 180px, auto, auto, auto, auto;
  background-repeat: no-repeat, repeat, no-repeat, no-repeat, no-repeat, no-repeat;
}

/* resplandores ambientales en deriva lenta — detrás de todo el contenido */
body::before {
  content: "";
  position: fixed;
  inset: -16% -10%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(1150px 640px at 50% -4%, rgba(255,122,0,.14), transparent 68%),
    radial-gradient(980px 680px at 96% 38%, rgba(255,122,0,.095), transparent 68%),
    radial-gradient(1050px 720px at -6% 78%, rgba(255,90,0,.085), transparent 68%),
    radial-gradient(820px 540px at 78% 108%, rgba(255,154,51,.065), transparent 70%);
  animation: dubAmbient 19s ease-in-out infinite alternate;
  will-change: transform, opacity;
}
@keyframes dubAmbient {
  from { transform: translate3d(-2.6%, -1.8%, 0) scale(1.03); opacity: .78; }
  to   { transform: translate3d(2.8%, 2.4%, 0) scale(1.09); opacity: 1; }
}

/* el brillo naranja del hero respira */
.hero::after { animation: dubHeroGlow 7s ease-in-out infinite alternate; }
@keyframes dubHeroGlow {
  from { opacity: .72; }
  to   { opacity: 1; }
}

/* la banda de foto del footer: zoom casi imperceptible (inset negativo
   para que la foto nunca deje ver un borde al escalar) */
.footer::before {
  inset: -4%;
  animation: dubBand 24s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes dubBand {
  from { transform: scale(1); }
  to   { transform: scale(1.08); }
}

/* tarjetas: levante suave al hover + brillo que cruza las tarjetas-puerta */
.path-card, .card { transition: border-color .35s ease, transform .35s ease, box-shadow .35s ease; }
.path-card:hover, .card:hover {
  transform: translateY(-2px);
  border-color: rgba(255,122,0,.55);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 18px 40px rgba(0,0,0,.45);
}
.path-card { position: relative; overflow: hidden; }
.path-card::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 32%, rgba(255,255,255,.07) 50%, transparent 68%);
  background-size: 260% 100%;
  background-position: 115% 0;
  animation: dubSheen 7.5s ease-in-out infinite alternate;
}
@keyframes dubSheen {
  from { background-position: 115% 0; }
  to   { background-position: -15% 0; }
}

/* quien prefiere menos movimiento, recibe la página quieta */
@media (prefers-reduced-motion: reduce) {
  body::before, .hero::after, .footer::before, .path-card::after { animation: none !important; }
  .path-card, .card { transition: none; }
  .path-card:hover, .card:hover { transform: none; }
}

/* v31: stock-aware ticket tiers — urgency line (brand orange, same
   weight language as .stat/.accent), sold-out option dimmed with a
   struck price and a quiet pill badge (same family as .paid-chip). */
.tier-urgency { color: var(--orange); font-size: 12.5px; font-weight: 700; letter-spacing: .02em; margin-top: 3px; }
.tier-soldout { opacity: .55; }
.tier-soldout s { color: var(--muted); }
.soldout-badge { display: inline-block; border: 1px solid var(--line); background: var(--panel2); color: var(--muted); border-radius: 999px; padding: 1px 9px; font-size: 11px; font-weight: 700; letter-spacing: .05em; margin-left: 8px; vertical-align: 1px; }
