/* ─────────────────────────────────────────────────────────────────────────────
   ash-reg-mt — one stylesheet for both the studio portal and the admin.

   Tenant branding overrides --brand-* only (see includes/branding.php). Every
   other colour is derived from neutral tokens, so a tenant can reskin the app
   by changing two colours without any layout breaking.

   Rules:
     - No inline style="" in templates. The store did that, and its own theming
       layer cannot reach those declarations.
     - Light is the default: studios fill in long forms and read invoices.
       Dark follows the OS, and the toggle can force either.
   ───────────────────────────────────────────────────────────────────────────── */

:root {
  --brand-primary:      #ed392f;
  --brand-primary-dark: #c42d24;
  --brand-primary-rgb:  237, 57, 47;
  --brand-accent:       #D4A017;

  --bg:          #f6f7f9;
  --surface:     #ffffff;
  --surface-2:   #f0f2f5;
  --border:      #e2e5ea;
  --border-firm: #cfd4dc;
  --text:        #14171c;
  --text-soft:   #5b6472;
  --text-mute:   #8b93a1;

  --ok:      #1a7f4b;
  --ok-bg:   #e7f5ed;
  --warn:    #9a6700;
  --warn-bg: #fff6e0;
  --err:     #b3261e;
  --err-bg:  #fdecea;
  --info:    #0b5cad;
  --info-bg: #e8f1fb;

  --radius:    10px;
  --radius-sm: 6px;
  --shadow:    0 1px 2px rgba(16,24,40,.05), 0 1px 3px rgba(16,24,40,.06);
  --shadow-lg: 0 4px 12px rgba(16,24,40,.08), 0 2px 4px rgba(16,24,40,.05);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:          #0d0f13;
    --surface:     #161a20;
    --surface-2:   #1e232b;
    --border:      #2a3039;
    --border-firm: #3a424e;
    --text:        #eef1f5;
    --text-soft:   #a8b1be;
    --text-mute:   #737d8c;
    --ok-bg:   #10281c; --ok:   #4ade80;
    --warn-bg: #2a2110; --warn: #fbbf24;
    --err-bg:  #2c1512; --err:  #fca5a5;
    --info-bg: #101f30; --info: #7dd3fc;
    --shadow:    0 1px 2px rgba(0,0,0,.4);
    --shadow-lg: 0 4px 14px rgba(0,0,0,.5);
  }
}
:root[data-theme="dark"] {
  --bg:          #0d0f13;
  --surface:     #161a20;
  --surface-2:   #1e232b;
  --border:      #2a3039;
  --border-firm: #3a424e;
  --text:        #eef1f5;
  --text-soft:   #a8b1be;
  --text-mute:   #737d8c;
  --ok-bg:   #10281c; --ok:   #4ade80;
  --warn-bg: #2a2110; --warn: #fbbf24;
  --err-bg:  #2c1512; --err:  #fca5a5;
  --info-bg: #101f30; --info: #7dd3fc;
  --shadow:    0 1px 2px rgba(0,0,0,.4);
  --shadow-lg: 0 4px 14px rgba(0,0,0,.5);
}

/* ── Base ─────────────────────────────────────────────────────────────────── */

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

/* The `hidden` attribute must actually hide.
   Its default `display:none` comes from the UA stylesheet, so ANY component
   rule that sets display beats it — .btn is inline-flex, .check is flex — and
   `el.hidden = true` then does nothing visible. That is not theoretical: it
   silently broke the routine builder's dancer filter, where typing set the
   property on every non-matching chip and none of them went away. One rule
   here rather than a patch per component. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3 { margin: 0 0 .5em; line-height: 1.25; font-weight: 650; letter-spacing: -.01em; }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }

code, .mono { font-family: var(--mono); font-size: .9em; }

/* ── Layout ───────────────────────────────────────────────────────────────── */

.wrap { max-width: 1180px; margin: 0 auto; padding: 24px 20px 64px; }
.wrap-narrow { max-width: 640px; }

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.page-head p { margin: 4px 0 0; color: var(--text-soft); }

.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 900px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 640px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }

.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.row-end { justify-content: flex-end; }
.spacer { flex: 1 1 auto; }

/* ── Nav ──────────────────────────────────────────────────────────────────── */

/* Two rows: identity on top, navigation below. Keeping them on one line meant a
   long menu pushed the account controls around and the two competed for the
   same space. */
.nav {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 50;
}
.nav-top {
  max-width: 1180px; margin: 0 auto; padding: 0 20px;
  display: flex; align-items: center; gap: 10px; min-height: 54px;
}
.nav-links {
  max-width: 1180px; margin: 0 auto; padding: 0 20px 8px;
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
}
.nav-brand {
  font-weight: 700; font-size: 1.02rem; letter-spacing: -.01em;
  color: var(--text); display: flex; align-items: center; gap: 9px;
}
.nav-brand:hover { text-decoration: none; }
.nav-brand img { height: 26px; width: auto; display: block; }
.nav-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--brand-primary); flex: none;
}
/* Sized so a full admin menu fits one line at a normal laptop width — a single
   orphaned item on a second row reads as a mistake rather than a wrap. */
.nav a.nav-link {
  padding: 5px 9px; border-radius: var(--radius-sm);
  color: var(--text-soft); font-weight: 500; font-size: .875rem; white-space: nowrap;
}
.nav a.nav-link:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.nav a.nav-link.is-active { background: rgba(var(--brand-primary-rgb), .1); color: var(--brand-primary); }

.nav-user { display: flex; align-items: center; gap: 10px; font-size: .88rem; color: var(--text-soft); }

.nav-me {
  color: var(--text-soft); padding: 4px 8px; border-radius: var(--radius-sm);
  text-decoration: none;
}
.nav-me:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }

/* Section dropdowns.
   CSS only, on purpose: the parent is a real link to its own page and the
   submenu opens on hover or keyboard focus. Nothing here depends on a script
   loading, so a section can never become unreachable. */

.nav-group { position: relative; }
.nav-caret { font-size: .62em; margin-left: 5px; opacity: .65; }

.nav-menu {
  position: absolute; top: 100%; left: 0; z-index: 40;
  min-width: 190px; padding: 5px;
  display: none;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.nav-group:hover > .nav-menu,
.nav-group:focus-within > .nav-menu { display: block; }

.nav .nav-menu-item {
  display: block; padding: 7px 10px; border-radius: var(--radius-sm);
  color: var(--text-soft); font-size: .875rem; font-weight: 500; white-space: nowrap;
}
.nav .nav-menu-item:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.nav .nav-menu-item.is-active { color: var(--brand-primary); font-weight: 600; }

/* Touch has no hover, and a tap on the parent should follow the link rather
   than fight an invisible menu for the same gesture. The section tabs on the
   parent page are how children are reached there. */
@media (hover: none) {
  .nav-menu  { display: none !important; }
  .nav-caret { display: none; }
}

/* ── Cards ────────────────────────────────────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.card-head {
  padding: 13px 16px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px;
  font-weight: 600; font-size: .95rem;
}
.card-body { padding: 16px; }
.card-body > :first-child { margin-top: 0; }
.card-body > :last-child  { margin-bottom: 0; }

/* Stat tiles */
.stat { padding: 16px; }
.stat-label { font-size: .78rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-mute); font-weight: 600; }
.stat-value { font-size: 1.75rem; font-weight: 680; letter-spacing: -.02em; margin-top: 4px; }
.stat-sub   { font-size: .85rem; color: var(--text-soft); margin-top: 2px; }

/* ── Tables ───────────────────────────────────────────────────────────────── */

.table-scroll { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; font-size: .92rem; }
table.tbl th, table.tbl td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); }
table.tbl th {
  font-size: .76rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-mute); font-weight: 650; background: var(--surface-2); white-space: nowrap;
}
table.tbl tbody tr:last-child td { border-bottom: 0; }
table.tbl tbody tr:hover { background: var(--surface-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

.empty { padding: 36px 16px; text-align: center; color: var(--text-mute); }

/* ── Forms ────────────────────────────────────────────────────────────────── */

.field { margin-bottom: 14px; }
.field > label {
  display: block; font-size: .85rem; font-weight: 600;
  margin-bottom: 5px; color: var(--text);
}
.field .hint { font-size: .82rem; color: var(--text-mute); margin-top: 4px; }
.req { color: var(--brand-primary); }

.input, .select, .textarea {
  width: 100%; padding: 8px 11px; font: inherit; font-size: .94rem;
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  transition: border-color .12s, box-shadow .12s;
}
.textarea { min-height: 90px; resize: vertical; }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px rgba(var(--brand-primary-rgb), .16);
}
.input:disabled, .select:disabled { background: var(--surface-2); color: var(--text-mute); }
.input.is-error, .select.is-error { border-color: var(--err); }

.check { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 8px; font-size: .93rem; }
.check input { margin-top: 3px; flex: none; }

fieldset.group { border: 0; margin: 0 0 22px; padding: 0; }
fieldset.group > legend {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-mute); font-weight: 650; padding: 0; margin-bottom: 10px;
}

/* ── Buttons ──────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 15px; font: inherit; font-size: .92rem; font-weight: 600;
  border-radius: var(--radius-sm); border: 1px solid transparent;
  cursor: pointer; white-space: nowrap; transition: background .12s, border-color .12s;
}
.btn:hover { text-decoration: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }

.btn-primary { background: var(--brand-primary); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--brand-primary-dark); }

.btn-default { background: var(--surface); color: var(--text); border-color: var(--border-firm); }
.btn-default:hover:not(:disabled) { background: var(--surface-2); }

.btn-danger { background: var(--err); color: #fff; }
.btn-danger:hover:not(:disabled) { filter: brightness(.92); }

.btn-ghost { background: transparent; color: var(--text-soft); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }

.btn-sm { padding: 5px 10px; font-size: .85rem; }

/* ── Badges ───────────────────────────────────────────────────────────────── */

.badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: .76rem; font-weight: 650; letter-spacing: .01em; white-space: nowrap;
  background: var(--surface-2); color: var(--text-soft);
}
.badge-ok   { background: var(--ok-bg);   color: var(--ok); }
.badge-warn { background: var(--warn-bg); color: var(--warn); }
.badge-err  { background: var(--err-bg);  color: var(--err); }
.badge-info { background: var(--info-bg); color: var(--info); }

/* Publish state — see includes/publish.php */
.pb { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: .76rem; font-weight: 650; }
.pb-live      { background: var(--ok-bg);   color: var(--ok); }
.pb-scheduled { background: var(--info-bg); color: var(--info); }
.pb-expired   { background: var(--surface-2); color: var(--text-mute); }
.pb-draft     { background: var(--warn-bg); color: var(--warn); }

/* ── Alerts ───────────────────────────────────────────────────────────────── */

.alert {
  padding: 11px 14px; border-radius: var(--radius-sm);
  border: 1px solid transparent; margin-bottom: 16px; font-size: .93rem;
}
.alert-ok   { background: var(--ok-bg);   color: var(--ok);   border-color: currentColor; }
.alert-warn { background: var(--warn-bg); color: var(--warn); border-color: currentColor; }
.alert-err  { background: var(--err-bg);  color: var(--err);  border-color: currentColor; }
.alert-info { background: var(--info-bg); color: var(--info); border-color: currentColor; }

/* ── Utilities ────────────────────────────────────────────────────────────── */

.muted { color: var(--text-soft); }
.small { font-size: .86rem; }
.tnum  { font-variant-numeric: tabular-nums; }
.mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; }
.mt16 { margin-top: 16px; } .mb16 { margin-bottom: 16px; }
.nowrap { white-space: nowrap; }

/* ── Modal ────────────────────────────────────────────────────────────────── */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(8, 10, 14, .6);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 40px 20px; overflow-y: auto;
}
/* (the global [hidden] rule near the top covers this) */
.modal {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  width: 100%; max-width: 900px;
}
.modal-head {
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px; font-weight: 650;
}
.modal-body { padding: 18px; max-height: 60vh; overflow-y: auto; }
.modal-foot {
  padding: 14px 18px; border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px;
}

/* ── Tabs ─────────────────────────────────────────────────────────────────── */
/* Plain links, so they work with JavaScript off and each tab is a real URL a
   studio can bookmark or land on from an email. */

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); }
.tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 14px; margin-bottom: -1px;
  border: 1px solid transparent; border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  color: var(--text-soft); font-size: .92rem; font-weight: 550;
  text-decoration: none;
}
.tab:hover { color: var(--text); background: var(--surface-2); }
.tab.is-active {
  color: var(--text); background: var(--surface);
  border-color: var(--border);
  box-shadow: inset 0 2px 0 var(--brand-primary);
}

/* ── Event list ───────────────────────────────────────────────────────────── */
/* Two lines per event: details + status above, action + warnings below. Cards
   were fine for three events and unreadable for nineteen. */

.evt-list { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.evt {
  display: block; padding: 13px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.evt:last-child { border-bottom: 0; }
.evt:hover { background: var(--surface-2); }

.evt-line {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
}
.evt-line + .evt-line { margin-top: 9px; align-items: center; }

.evt-name { font-weight: 650; font-size: 1rem; min-width: 170px; }
.evt-meta { color: var(--text-soft); font-size: .87rem; white-space: nowrap; }
.evt-meta b { color: var(--text); font-weight: 600; }

/* Fixed column widths so dates, close date and early bird line up down the
   page. Without these each span sizes to its own text and the columns wander,
   which is exactly what makes a long list hard to scan. */
.evt-when  { min-width: 290px; }
.evt-close { min-width: 130px; }
.evt-eb    { min-width: 160px; }

/* Status and warnings sit hard right on their own line. */
.evt-right { margin-left: auto; text-align: right; }
.evt-warn  { margin-left: auto; text-align: right; font-size: .86rem; }
.evt-warn .warn-item { display: block; }
.evt-warn .warn-urgent { color: var(--err);  font-weight: 600; }
.evt-warn .warn-soft   { color: var(--warn); }
.evt-warn .warn-quiet  { color: var(--text-mute); }

/* Narrow screens: the columns stop being columns. Drop the fixed widths so the
   metadata flows as one wrapped sentence instead of one line each, which turned
   every event into a half-screen block. */
@media (max-width: 720px) {
  .evt-line { gap: 4px 10px; }
  .evt-name { min-width: 100%; }
  .evt-when, .evt-close, .evt-eb { min-width: 0; }
  .evt-right, .evt-warn { margin-left: 0; text-align: left; width: 100%; }
  .evt-line + .evt-line { margin-top: 8px; }
}

/* ── Support view banner ──────────────────────────────────────────────────── */
/* Sits above the nav and does not scroll away — the whole point is that it
   cannot be missed or forgotten about. */

.support-bar {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 20px;
  background: #7c2d12; color: #ffedd5;
  font-size: .88rem;
  border-bottom: 2px solid #ea580c;
}
.support-bar strong { color: #fff; }
.support-bar .btn {
  background: #ffedd5; color: #7c2d12; border-color: transparent; font-weight: 650;
}
.support-bar .btn:hover { background: #fff; }

/* ── Drop zone ────────────────────────────────────────────────────────────── */

.dropzone {
  border: 2px dashed var(--border-firm);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 30px 20px;
  text-align: center;
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.dropzone:hover { border-color: var(--brand-primary); }
.dropzone.is-over {
  border-color: var(--brand-primary);
  background: rgba(var(--brand-primary-rgb), .08);
}
.dropzone-title { font-weight: 650; font-size: 1rem; margin-bottom: 4px; }
.dropzone-hint  { color: var(--text-soft); font-size: .88rem; }
.dropzone input[type="file"] { display: none; }

/* ── Media ────────────────────────────────────────────────────────────────── */

.player { width: 100%; max-width: 520px; border-radius: var(--radius-sm); display: block; }
.player-audio { height: 40px; }

/* ── Sortable tables, search and pagination ───────────────────────────────── */

.th-sort { padding: 0; }
.th-sort > a {
  display: flex; align-items: center; gap: 5px;
  padding: 10px 12px; color: inherit; font: inherit; text-decoration: none;
}
.th-sort.num > a { justify-content: flex-end; }
.th-sort > a:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.th-sort.is-sorted > a { color: var(--text); }
.sort-mark { font-size: .62em; opacity: .8; }
/* Reserve the arrow's width on every sortable header so the columns do not
   shift sideways when the sort moves. */
.th-sort .sort-mark::after { content: ''; }
.th-sort:not(.is-sorted) .sort-mark::before { content: '↕'; opacity: .28; }

/* Section heading inside a long form, so a twenty-field editor reads as three
   short ones rather than a wall. */
.field-group-label {
  margin: 20px 0 10px; padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: .78rem; font-weight: 650; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-mute);
}
.modal-body > .field-group-label:first-child,
.card-body  > .field-group-label:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

.table-search { display: flex; align-items: center; gap: 6px; }
.table-search .input { width: 220px; }

.pager {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  padding: 10px 16px; border-top: 1px solid var(--border);
  font-size: .85rem;
}
.pager-count { color: var(--text-soft); }
.pager-gap   { color: var(--text-mute); padding: 0 2px; }
.pager-btn {
  min-width: 30px; padding: 4px 8px; text-align: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text-soft); text-decoration: none;
}
.pager-btn:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.pager-btn.is-current {
  background: rgba(var(--brand-primary-rgb), .1);
  border-color: var(--brand-primary); color: var(--brand-primary); font-weight: 600;
}
.pager-btn.is-disabled { opacity: .4; pointer-events: none; }

/* Retention countdown. Deliberately quiet until it is nearly true — a studio
   should notice it when a critique is about to go, not be nagged all year. */
.expiry-soon { color: var(--warn); }

.event-picker { display: flex; align-items: center; gap: 8px; }
.event-picker label { color: var(--text-soft); font-size: .85rem; font-weight: 550; }
.event-picker .select { width: auto; min-width: 260px; padding: 5px 28px 5px 10px; font-size: .88rem; }

@media (max-width: 720px) {
  .table-search { width: 100%; }
  .table-search .input { flex: 1; width: auto; }
  .event-picker { width: 100%; }
  .event-picker .select { flex: 1; min-width: 0; }
  .pager-count { width: 100%; }
}

/* ── Registration: outstanding work ───────────────────────────────────────── */

.todo { list-style: none; margin: 0; padding: 0; }
.todo-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-top: 1px solid var(--border);
}
.todo-item:first-child { border-top: 0; }
.todo-text { flex: 1; font-size: .93rem; }
.todo-dot {
  flex: none; width: 8px; height: 8px; border-radius: 50%;
  background: var(--text-mute);
}
.todo-dot.is-urgent { background: var(--err); }

.stat-value.is-due { color: var(--err); }
.tnum.is-credit    { color: var(--ok); }

/* ── Registration: picking dancers ────────────────────────────────────────── */

.select-sm, .input-sm { padding: 4px 8px; font-size: .85rem; }
.pb0 { padding-bottom: 0 !important; }
.mt8 { margin-top: 8px; }

/* Capped so a 300-dancer roster does not push the submit button off-screen. */
.pick-scroll { max-height: 380px; overflow-y: auto; }
.pick-table thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; }
.pick-row.is-blocked { color: var(--text-mute); }

/* The group/production picker. A wrapped grid of chips reads faster than a
   column of checkboxes when there are sixty of them. */
.pick-grid {
  display: grid; gap: 6px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  max-height: 300px; overflow-y: auto;
  padding: 10px; margin-top: 6px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-2);
}
.pick-chip {
  margin: 0; padding: 5px 8px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid transparent;
  font-size: .88rem;
}
.pick-chip:hover { border-color: var(--border-firm); }
.pick-chip:has(input:checked) {
  border-color: var(--brand-primary);
  background: rgba(var(--brand-primary-rgb), .07);
}

/* ── Registration: the routine list ───────────────────────────────────────── */
/* <details> rather than a script: a studio with 65 routines needs them
   collapsed, and that should not depend on JavaScript loading. */

.rt-list > .rt + .rt { border-top: 1px solid var(--border); }
.rt-sum {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px;
  padding: 12px 16px; cursor: pointer; list-style: none;
}
.rt-sum::-webkit-details-marker { display: none; }
.rt-sum:hover { background: var(--surface-2); }
.rt[open] > .rt-sum { background: var(--surface-2); border-bottom: 1px solid var(--border); }
.rt-title { font-weight: 650; min-width: 200px; flex: 1; }
.rt-meta  { color: var(--text-soft); font-size: .87rem; white-space: nowrap; }
.rt-open {
  margin-left: auto; font-size: .85rem; font-weight: 550;
  color: var(--brand-primary);
}
.rt-body { padding: 16px; }

/* Same reasoning as the event list: fixed columns so 65 routines can be read
   down the page instead of each row being measured on its own. */
.rt-size  { min-width: 104px; }
.rt-cat   { min-width: 140px; }
.rt-count { min-width: 84px; }
.rt-div   { min-width: 140px; }
.rt-time  { min-width: 42px; }
.rt-music { min-width: 84px; }

/* Reused by the "Add a routine" card, which collapses once routines exist. */
.card-head.as-summary { cursor: pointer; list-style: none; }
.card-head.as-summary::-webkit-details-marker { display: none; }
.card-head.as-summary:hover { background: var(--surface-2); }

@media (max-width: 720px) {
  .rt-title { min-width: 100%; }
  .rt-open  { margin-left: 0; }
  .rt-size, .rt-cat, .rt-count, .rt-div, .rt-time, .rt-music { min-width: 0; }
}

/* ── Upload progress ──────────────────────────────────────────────────────── */
/* Lives in the Track cell, so the bar sits exactly where the filename will be
   once it lands. Fixed width, because a bar that resizes as the percentage
   text changes reads as jitter rather than progress. */

/* A file picker that looks like the rest of the app.
   The native <input type=file> renders as an OS widget with a truncated
   "No file selected" beside it — unstyleable, different in every browser, and
   a second control next to the button that was already there. Hiding the input
   inside its own label collapses both into one, and because a label activates
   its input natively, it still takes one click with scripts off. */

.file-btn { position: relative; display: inline-flex; align-items: center; cursor: pointer; }
.file-btn input[type="file"] {
  /* Not display:none — the input stays focusable, so it is reachable by
     keyboard and browsers can still report validation against it. */
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* The input is invisible, so its focus ring has to come from the label. */
.file-btn:focus-within { outline: 2px solid var(--brand-primary); outline-offset: 2px; }
.file-btn.is-busy { opacity: .55; pointer-events: none; }

.up-name { font-weight: 550; margin-bottom: 4px; word-break: break-all; }
.up-bar {
  width: 160px; height: 6px; border-radius: 3px;
  background: var(--surface-2); overflow: hidden;
}
.up-bar > span {
  display: block; height: 100%; width: 0;
  background: var(--brand-primary);
  transition: width .15s linear;
}
.up-note     { color: var(--text-mute); font-size: .8rem; margin-top: 4px; }
.up-note-row { margin-top: 6px; }
.up-err      { color: var(--err); }
.up-warn     { color: var(--warn); }

@media (prefers-reduced-motion: reduce) {
  .up-bar > span { transition: none; }
}

/* ── Sign-in cards ────────────────────────────────────────────────────────── */

.auth-card { max-width: 420px; margin: 8vh auto 0; }
.auth-note { text-align: center; margin-top: 14px; }

/* The dancer chooser. A whole row is the target, because this is mostly used on
   a phone by a parent with three children on one email. */
.pick-profile { margin: 0; }
.profile-row {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 14px 16px; background: none; border: 0; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
}
.profile-row:hover { background: var(--surface-2); }
.profile-name   { font-weight: 650; }
.profile-studio { color: var(--text-soft); font-size: .87rem; }

/* ── Schedule timeline ────────────────────────────────────────────────────── */
/* Breaks read as gaps in the show, so they sit visually apart from routine rows. */
.sched-break > td { background: var(--surface-2); color: var(--text-soft); }
.sched-break strong { color: var(--text); }

/* Drag-and-drop reordering. The grip is the handle; the row dims while dragging;
   a dragged-over row shows where the routine will land. */
.drag-grip { cursor: grab; color: var(--text-mute); user-select: none; margin-right: 4px; letter-spacing: -2px; }
.sched-row.dragging { opacity: .45; }
.sched-row.drag-over > td { box-shadow: inset 0 2px 0 0 var(--brand-primary); }

/* ── Judge portal: pinned performance tracker ─────────────────────────────── */
.track-bar {
  display: flex; gap: 28px; align-items: center; flex-wrap: wrap;
  max-width: 1180px; margin: 0 auto; padding: 10px 20px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  font-size: .92rem;
}
.track-live { display: inline-flex; align-items: center; gap: 8px; color: var(--text-soft); }
.track-dot  { width: 9px; height: 9px; border-radius: 50%; background: var(--text-mute); flex: none; }
.track-dot.is-live { background: #22c55e; box-shadow: 0 0 0 3px rgba(34,197,94,.22); }
.track-dot.is-err  { background: var(--err); }
.track-label { color: var(--text-mute); font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; margin-right: 6px; }
.track-next  { color: var(--text-soft); }

/* ── API key reveal ───────────────────────────────────────────────────────── */
.key-reveal {
  display: inline-block; padding: 8px 12px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--border);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .95rem; word-break: break-all; user-select: all;
}

/* ── Notes editor (simple WYSIWYG) ────────────────────────────────────────── */
.rt-toolbar { display: flex; gap: 6px; align-items: stretch; flex-wrap: wrap; margin-bottom: 8px; }
.rt-toolbar .btn { min-width: 36px; }
.rt-sep { width: 1px; background: var(--border); margin: 2px 4px; }
.rt-area {
  min-height: 120px; max-height: 380px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; background: var(--surface);
}
.rt-area:focus { outline: 2px solid var(--brand-primary); outline-offset: -1px; }
.rt-area:empty::before { content: attr(data-placeholder); color: var(--text-mute); }

/* ── Key/value list ───────────────────────────────────────────────────────── */
.kv { display: grid; grid-template-columns: minmax(90px, auto) 1fr; gap: 6px 16px; margin: 0; }
.kv dt { color: var(--text-mute); font-size: .85rem; }
.kv dd { margin: 0; }

/* ── Branding ─────────────────────────────────────────────────────────────── */
.auth-brand { text-align: center; margin-top: 24px; }
.auth-brand img { max-height: 72px; max-width: 100%; }
.input-color { width: 64px; height: 38px; padding: 2px; cursor: pointer; }

/* ── Footer ───────────────────────────────────────────────────────────────── */

.site-footer {
  max-width: 1180px; margin: 24px auto 0; padding: 20px 20px 32px;
  border-top: 1px solid var(--border);
  text-align: center;
  color: var(--text-mute); font-size: .82rem;
}
.site-footer p { margin: 0; }
.site-footer-links { margin-top: 6px; display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; }
.site-footer a { color: var(--text-soft); text-decoration: none; }
.site-footer a:hover { color: var(--text); text-decoration: underline; }

/* ── Legal documents ──────────────────────────────────────────────────────── */
/* Long-form prose, which the rest of the app has none of. Measure and rhythm
   matter more here than anywhere else in the product — these are the pages
   people give up on. */

.legal { line-height: 1.65; }
.legal .card-body { max-width: 72ch; }
.legal h2 {
  margin: 32px 0 10px; padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 1.12rem; font-weight: 650;
}
.legal h2:first-of-type { border-top: 0; padding-top: 0; }
.legal h3 { margin: 20px 0 6px; font-size: .98rem; font-weight: 650; }
.legal p  { margin: 0 0 12px; }
.legal ul { margin: 0 0 14px; padding-left: 22px; }
.legal li { margin-bottom: 6px; }
.legal-meta {
  padding-bottom: 14px; margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
  color: var(--text-soft); font-size: .86rem;
}

/* ── htmx ─────────────────────────────────────────────────────────────────── */
/* htmx is progressive enhancement only: every form here also works as a plain
   POST when the script is absent. These rules just soften the swap. */

.htmx-indicator { opacity: 0; transition: opacity .15s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.htmx-swapping { opacity: .5; transition: opacity .1s; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
