:root {
  /* ── PAINTS ──────────────────────────────────────────────────────────────
     The Heartquakers palette, taken from the booking form so the two
     audience-facing apps cannot drift into two readings of one brand. These
     NEVER change between light and dark. They are colors, not roles. */
  --ink:        #241F1C;
  --bone:       #EDE8DC;
  --bone-warm:  #E3DCCB;
  --brass:      #C8922A;
  --rust:       #8C3B22;
  --sage:       #7D8C6E;
  --field:      #2F3B2F;
  --field-deep: #222B22;

  /* ── ROLES ───────────────────────────────────────────────────────────────
     What a thing IS, not what color it is. Only these flip in dark mode.
     Keeping the two apart is not tidiness — the first version of this sheet
     redefined --ink to mean "text color" under dark mode, while .masthead was
     using it as its BACKGROUND. The header ground turned cream, the bone
     heading vanished into it, and the page shipped that way. A paint must
     never be reassigned a role. */
  --paper:     var(--bone);
  --surface:   var(--bone-warm);
  --text:      var(--ink);
  --text-soft: #5A5147;
  --line:      #D6CEBC;

  --ok:     #4B6B3A;
  --warn:   #A65A1E;
  --danger: var(--rust);

  --display: "Big Shoulders Display", Impact, sans-serif;
  --body:    "Karla", system-ui, -apple-system, sans-serif;
  --mono:    "DM Mono", ui-monospace, monospace;

  --radius: 10px;
}

/* Dark mode deepens the page toward the ink the artwork was drawn on. It does
   NOT invert the brand: the masthead is dark in both modes, because that is
   where the logo lives. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper:     #1A1614;
    --surface:   #211C19;
    --text:      var(--bone);
    --text-soft: #A79C8E;
    --line:      #3A322C;
    --ok:        #7FA968;
    --warn:      #D89A4A;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

.card { max-width: 34rem; margin: 0 auto; background: var(--paper); min-height: 100vh; }
@media (min-width: 36rem) {
  .card {
    margin: 2rem auto; min-height: 0;
    border-radius: var(--radius); overflow: hidden;
    box-shadow: 0 1px 3px rgba(36,31,28,.14), 0 12px 32px rgba(36,31,28,.10);
  }
}

/* ---- masthead ------------------------------------------------------------ */
/* The ink ground is the one the badge was drawn on, so it sits in the page
   rather than on it. Built to take a live photo later without a redesign:
   drop a background-image on .masthead and the scrim below keeps the type
   readable over it. */
.masthead {
  position: relative;
  isolation: isolate;
  color: var(--bone);
  padding: 2rem 1.25rem 1.6rem;
  text-align: center;

  /* A gig poster, not a black box. Three layers, back to front:
     a warm vignette that lifts the middle and drops the corners; a low brass
     glow behind the mark, as though it were lit; and the grain on ::before.
     The flat ink ground sat almost on top of the dark page behind it, so the
     header did not read as a separate thing at all. */
  background:
    radial-gradient(68% 52% at 50% 26%, rgba(200,146,42,.15) 0%, rgba(200,146,42,0) 62%),
    radial-gradient(130% 105% at 50% 8%, #352C26 0%, #2A2320 42%, #201B18 100%);
}

/* The grain. Overlay rather than a flat wash so it modulates the gradient
   underneath — darkening some grains, lifting others — which is what makes it
   read as paper rather than as noise laid on top. */
.masthead::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='160'%20height='160'%3E%3Cfilter%20id='g'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.85'%20numOctaves='4'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='saturate'%20values='0'/%3E%3C/filter%3E%3Crect%20width='160'%20height='160'%20filter='url%28%23g%29'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  opacity: .30;
  mix-blend-mode: overlay;
}

/* Inert until a live show photo is dropped in behind: set a background-image on
   .masthead and raise this opacity, and the type stays readable over it. */
.masthead::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(26,22,20,.25), rgba(26,22,20,.75));
  pointer-events: none; opacity: 0;
}

.logo {
  display: block; margin: 0 auto 1.35rem;
  width: 100%; max-width: 300px; height: auto;
}
.wordmark {
  font-family: var(--body);
  font-size: .68rem; letter-spacing: .26em; text-transform: uppercase;
  color: var(--brass); margin-bottom: .5rem;
}
.masthead h1 {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.1rem, 11vw, 2.9rem);
  line-height: .95;
  letter-spacing: .01em;
  text-transform: uppercase;
  margin: 0 0 .85rem;
  color: var(--bone);
}
.masthead .place {
  font-size: .7rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--sage); margin: 0 0 1.5rem;
}

/* The seismograph line — the logo's own motif, doing the job of a rule.
   Static SVG rather than the booking form's animated canvas: this page has to
   look right with JavaScript off (the uploader cannot run without it, and the
   fallback must not also look broken), and nothing should compete for the main
   thread while a 400 MB upload is running. */
/* The rule now sits INSIDE the header with matching air above and below,
   rather than being flush to its bottom edge. The wrapper holds the static SVG
   and, once seismo.js runs, the canvas that replaces it. */
.seismo { display: block; position: relative; width: 100%; height: 44px; margin: 0;
          overflow: hidden; }
.seismo svg { display: block; width: 100%; height: 44px; }
/* Pinned to the wrapper and clipped by it. A canvas given width/height
   ATTRIBUTES renders at those attributes when no CSS box applies — so if this
   rule ever fails to arrive (a stale cached stylesheet will do it), an
   unstyled canvas sizes itself from its bitmap and spills across the page.
   That happened. Absolute inset plus overflow:hidden makes it impossible:
   there is no size the canvas can take that escapes its wrapper. */
.seismo canvas { display: block; position: absolute; inset: 0;
                 width: 100%; height: 100%; }
.seismo path { fill: none; stroke: var(--brass); stroke-width: 1.6; stroke-linejoin: round; }
.seismo line { stroke: var(--sage); stroke-width: 1; opacity: .35; }

.card > :not(.masthead) { padding-left: 1.25rem; padding-right: 1.25rem; }
.card > .form, .card > .thanks { padding-bottom: 2rem; }

.lead { font-size: 1.08rem; margin: 1.35rem 0 .5rem; }
.lead b { font-weight: 700; }
.muted { color: var(--text-soft); font-size: .93rem; }
.fine  { font-size: .85rem; text-align: center; margin-top: .75rem; }
h2 { font-family: var(--display); font-weight: 700; font-size: 1.5rem;
     text-transform: uppercase; letter-spacing: .01em; margin: 1.35rem 0 .5rem; }
a { color: var(--rust); }
a:hover { color: var(--brass); }

/* ---- form ---------------------------------------------------------------- */
.form { margin-top: 1.35rem; }
.field { display: block; margin-bottom: 1.1rem; }
.field > span {
  display: block; font-weight: 700; font-size: .78rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft);
  margin-bottom: .35rem;
}
.field .opt { font-weight: 400; letter-spacing: .04em; text-transform: none;
              color: var(--text-soft); margin-left: .4rem; }
.field small { display: block; color: var(--text-soft); font-size: .85rem;
               margin-top: .35rem; line-height: 1.45; }

.field select,
.field input[type="text"],
.field input[type="email"] {
  width: 100%;
  font: inherit;                 /* 16px+ or iOS Safari zooms the page on focus */
  padding: .72rem .8rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
}
.field input:focus-visible,
.field select:focus-visible { outline: 2px solid var(--brass); outline-offset: 1px; }

.field.file input[type="file"] {
  width: 100%; font: inherit; font-size: .95rem;
  padding: 1rem; border: 1px dashed var(--sage); border-radius: 8px;
  background: transparent; color: var(--text-soft);
}

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---- consent ------------------------------------------------------------- */
.consent {
  border: 1px solid var(--line); border-left: 3px solid var(--brass);
  border-radius: 8px; padding: .35rem .9rem; margin: 1.35rem 0;
  background: var(--surface);
}
.check { display: flex; gap: .7rem; align-items: flex-start; padding: .85rem 0; cursor: pointer; }
.check + .check { border-top: 1px solid var(--line); }
.check input { width: 24px; height: 24px; margin: 0; flex: 0 0 auto; accent-color: var(--rust); }
.check span { font-size: .95rem; line-height: 1.5; }
.check em { display: block; font-style: normal; color: var(--text-soft);
            font-size: .87rem; margin-top: .2rem; }

/* ---- buttons ------------------------------------------------------------- */
.btn {
  display: inline-block; font-family: var(--display); font-weight: 700;
  font-size: 1.05rem; letter-spacing: .06em; text-transform: uppercase;
  background: var(--rust); color: var(--bone);
  border: 0; border-radius: 8px; padding: .8rem 1.5rem;
  cursor: pointer; text-decoration: none;
}
.btn:hover { background: #A04628; color: var(--bone); }
.btn.big { display: block; width: 100%; padding: 1.05rem; font-size: 1.25rem; }
.btn[disabled] { opacity: .55; cursor: default; }
.btn.danger { background: var(--rust); }
.btn.ghost { background: transparent; color: var(--text); border: 1px solid var(--line); }
.btn:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

.link { font: inherit; font-size: .88rem; background: none; border: 0; padding: .25rem 0;
        color: var(--rust); text-decoration: underline; cursor: pointer; }
.link.subtle { color: var(--text-soft); margin-left: .9rem; }

/* ---- upload queue -------------------------------------------------------- */
.queue { list-style: none; margin: 0 0 1.25rem; padding: 0; }
.q { border: 1px solid var(--line); border-radius: 8px; padding: .7rem .85rem;
     margin-bottom: .5rem; background: var(--surface); }
.q-name { font-size: .93rem; font-weight: 700; overflow: hidden;
          text-overflow: ellipsis; white-space: nowrap; }
.q-meta { font-family: var(--mono); font-size: .8rem; color: var(--text-soft); margin-top: .15rem; }
.q-bar { height: 6px; background: var(--line); border-radius: 3px; margin-top: .55rem; overflow: hidden; }
.q-bar i { display: block; height: 100%; background: var(--brass); transition: width .18s ease-out; }
.q.done   { border-color: var(--ok); }
.q.done   .q-meta { color: var(--ok); }
.q.done   .q-bar i { background: var(--ok); }
.q.failed { border-color: var(--danger); }
.q.failed .q-meta { color: var(--danger); }

/* ---- notices ------------------------------------------------------------- */
.notice { border-radius: 8px; padding: .75rem .9rem; margin: 1rem 0;
          font-size: .92rem; line-height: 1.5;
          background: var(--surface); border: 1px solid var(--line);
          border-left: 3px solid var(--sage); }
.notice.warn { border-left-color: var(--warn); color: var(--warn); background: transparent; }
.thanks h2 { margin-top: 1.5rem; }

/* ---- plain pages (withdraw) --------------------------------------------- */
body.plain .card { padding: 1.5rem 1.25rem 2rem; }
body.plain h1 { font-size: .7rem; letter-spacing: .26em; text-transform: uppercase;
                color: var(--brass); margin: 0 0 1rem; font-family: var(--body); }

/* ──────────────────────────────────────────────────────────────────────────
   Admin. Desktop-leaning — judging footage on a phone is possible but nobody
   will actually do it. Same palette as the public page so the band is not
   looking at a different product from their audience.
   ────────────────────────────────────────────────────────────────────────── */

body.admin { background: var(--paper); }

.adminbar {
  display: flex; align-items: center; gap: 1.25rem;
  background: var(--ink); color: var(--bone);
  padding: .7rem 1.25rem; position: sticky; top: 0; z-index: 5;
  border-bottom: 2px solid var(--brass);
}
.adminbar .wordmark {
  margin: 0; font-family: var(--display); font-weight: 800; font-size: 1.15rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--bone);
}
.adminbar nav { display: flex; gap: 1.1rem; flex: 1; flex-wrap: wrap; }
.adminbar a { color: var(--bone); opacity: .68; text-decoration: none;
              font-size: .82rem; letter-spacing: .09em; text-transform: uppercase; }
.adminbar a:hover { opacity: 1; color: var(--bone); }
.adminbar a.on { opacity: 1; box-shadow: inset 0 -2px 0 var(--brass); }
.adminbar .out { opacity: .5; font-size: .75rem; }

.adminmain { max-width: 62rem; margin: 0 auto; padding: 1.25rem; }
.adminmain h1 { font-family: var(--display); font-weight: 800; font-size: 1.7rem;
                text-transform: uppercase; letter-spacing: .02em; margin: .5rem 0 1rem; }
.adminmain h2 { font-size: 1.15rem; }

.rowform, .stack {
  display: flex; flex-wrap: wrap; gap: .75rem; align-items: flex-end;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; padding: 1rem; margin-bottom: 1rem;
}
.stack { display: block; }
.stack p { margin: 0 0 .9rem; }
.rowform label { display: flex; flex-direction: column; gap: .25rem;
                 font-size: .72rem; letter-spacing: .09em; text-transform: uppercase;
                 color: var(--text-soft); }
.rowform input, .rowform select {
  font: inherit; font-size: .95rem; text-transform: none; letter-spacing: normal;
  padding: .45rem .55rem; border: 1px solid var(--line); border-radius: 6px;
  background: var(--paper); color: var(--text);
}

.grid { width: 100%; border-collapse: collapse; background: var(--surface);
        border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.grid th, .grid td { text-align: left; padding: .6rem .8rem;
                     border-bottom: 1px solid var(--line); font-size: .92rem; }
.grid th { font-size: .7rem; text-transform: uppercase; letter-spacing: .1em;
           color: var(--bone); background: var(--field); }
.grid tr:last-child td { border-bottom: 0; }
.grid .acts { display: flex; gap: .8rem; align-items: center; flex-wrap: wrap; }

.inline { display: inline; }
.warn-text { color: var(--warn); }

.sub { background: var(--surface); border: 1px solid var(--line);
       border-radius: 8px; padding: 1rem; margin-bottom: 1rem; }
.sub.withdrawn { opacity: .55; border-style: dashed; }
.sub h2 { margin: 0 0 .1rem; display: flex; gap: .75rem; align-items: baseline; flex-wrap: wrap;
          font-family: var(--body); font-size: 1.05rem; text-transform: none; letter-spacing: 0; }
.sub .mail { font-size: .85rem; font-weight: 400; color: var(--text-soft); }

.clips { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
         gap: .9rem; margin-top: .8rem; }
.clip { margin: 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
        background: var(--paper); }
.clip.winner { border-color: var(--brass); box-shadow: 0 0 0 2px var(--brass) inset; }
/* contain, not cover: a cropped centre of a dark stage is a black rectangle. */
.clip video { width: 100%; aspect-ratio: 16/10; object-fit: contain;
              background: #000; display: block; }
.clip .noclip { aspect-ratio: 16/10; display: grid; place-items: center;
                background: var(--surface); color: var(--text-soft); font-size: .85rem; }
.clip figcaption { padding: .55rem .65rem; display: flex; gap: .5rem; flex-wrap: wrap;
                   align-items: center; font-size: .85rem; }
.clip .fn { flex: 1 1 100%; overflow: hidden; text-overflow: ellipsis;
            white-space: nowrap; font-weight: 700; }

.stars { display: inline-flex; gap: .1rem; }
.star { background: none; border: 0; cursor: pointer; font-size: 1.05rem;
        color: var(--line); padding: 0 .05rem; }
.star.lit { color: var(--brass); }

/* ---- printable QR card --------------------------------------------------- */
/* This is the one thing that gets physically handled at a merch table, so it
   leans hardest on the brand: ink ground, brass rule, badge, the seismograph. */

body.cardpage { background: var(--paper); padding: 1.5rem; }
.bar { max-width: 30rem; margin: 0 auto 1rem; display: flex;
       justify-content: space-between; align-items: center; }
.bar button { font: inherit; padding: .4rem 1rem; }
.hint { max-width: 30rem; margin: 1rem auto; font-size: .85rem; color: var(--text-soft); }

.qrcard {
  max-width: 30rem; margin: 0 auto;
  background: var(--ink); color: var(--bone);
  border: 1px solid #000; border-radius: 10px; overflow: hidden;
}
.qrcard-in { display: flex; gap: 1rem; align-items: center; padding: 1.1rem; }
.qrcard .qr { flex: 0 0 8.5rem; background: var(--bone); padding: .35rem;
              border-radius: 6px; }
.qrcard .qr svg { width: 100%; height: auto; display: block; }
.qrcard-text { flex: 1; }
.qrcard .kicker { font-size: .58rem; letter-spacing: .24em; text-transform: uppercase;
                  color: var(--brass); }
.qrcard h1 { font-family: var(--display); font-weight: 800; font-size: 1.5rem;
             line-height: .98; text-transform: uppercase; margin: .25rem 0 .4rem;
             color: var(--bone); }
.qrcard p { margin: 0 0 .35rem; font-size: .82rem; line-height: 1.45; color: var(--bone-warm); }
.qrcard .url { font-family: var(--mono); font-size: .78rem; font-weight: 500;
               color: var(--brass); word-break: break-all; }

@media print {
  /* Force the ink ground to actually print; browsers strip backgrounds by
     default and a card with no ground is just floating text. */
  body.cardpage { background: #fff; padding: 0; }
  .noprint { display: none !important; }
  .qrcard {
    width: 3.5in; max-width: none; border-radius: 0; border: 1px dashed #999;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .qrcard-in { padding: .3in; }
  @page { margin: .5in; }
}
