/* ============================================================
   Shows Dashboard — UCB Customizations
   ============================================================ */

/* ── 1. CSS Custom Properties ──────────────────────────────── */
:root {
  --ucb-brand: #8B2025;
  --ucb-brand-dark: #6B181C;
  --ucb-brand-light: #A83035;
  --ucb-accent: #D4A84B;
  --ucb-accent-light: #E8C97A;
  --ucb-green: #10b981;
  --ucb-green-light: #34d399;
  /* WCAG audit (2026-07): #059669 only hit 3.77:1 on white, failing the 4.5:1
     normal-text threshold everywhere it's used as text/white-on-solid-bg
     (status labels, checkin-btn "done" fill, recap-send-btn). Moved one
     Tailwind emerald step darker (600→700) to clear AA with margin (5.48:1)
     while keeping the same hue family. */
  --ucb-green-dark: #047857;
  --ucb-red: #ef4444;
  --ucb-red-light: #fca5a5;
  /* Text-safe tier for --ucb-red (2026-07 WCAG audit): the base red is only
     3.76:1 on white, failing 4.5:1 for the many small error/status texts
     that use it. Use --ucb-red-dark for TEXT and any solid-bg + white-text
     pairing; leave --ucb-red for borders/tints/dots, which already clear the
     lighter 3:1 non-text threshold. */
  --ucb-red-dark: #b91c1c;
  --ucb-blue: #3b82f6;
  --ucb-blue-light: #93c5fd;
  /* Text-safe tier for --ucb-blue (2026-07 WCAG audit) — same rationale as
     --ucb-red-dark. Matches the value already hand-picked for .setup-pill-cc. */
  --ucb-blue-dark: #1d4ed8;
  --ucb-amber: #d97706;
  --ucb-amber-light: #f59e0b;
  /* Text-safe tier for --ucb-amber (2026-07 WCAG audit) — base amber is
     3.19:1 on white; fine for large text (>=3:1) but fails 4.5:1 for the
     many small amber status texts. */
  --ucb-amber-dark: #b45309;
  --ucb-purple: #8b5cf6;
  /* Text-safe tier for --ucb-purple (2026-07 WCAG audit) — base purple is
     4.23:1 on white, just short of the 4.5:1 normal-text threshold. */
  --ucb-purple-dark: #7c3aed;
  --ucb-gray-50: #fafafa;
  --ucb-gray-100: #f4f4f5;
  --ucb-gray-200: #e4e4e7;
  --ucb-gray-300: #d4d4d8;
  --ucb-gray-400: #8c8c96;
  --ucb-gray-500: #71717a;
  --ucb-gray-600: #52525b;
  --ucb-gray-700: #3f3f46;
  --ucb-gray-800: #27272a;
  --ucb-gray-900: #18181b;
  /* WCAG 1.4.11 non-text contrast (2026-07 audit): --ucb-gray-200 (1.27:1)
     and --ucb-gray-300 (1.48:1) are both used interchangeably as borders on
     real form controls (inputs/selects/textareas) and the checkin-btn/tab
     controls across this file — both fail the 3:1 UI-component-boundary
     minimum badly. Rather than darken gray-200/300 themselves (they're also
     the standard subtle divider for decorative cards/panels/tables, where a
     3:1 border would look like a redesign), this is a dedicated border tier
     for controls that actually need to be identifiable. See the "input
     boxes" fixes below for its usages. */
  --ucb-border-strong: #767676;
  --ucb-radius: 14px;
  --ucb-radius-sm: 8px;
  --ucb-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
  --ucb-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
  --ucb-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.08);
  --ucb-shadow-glow: 0 0 40px rgba(139, 32, 37, 0.06);
  --ucb-transition: 0.15s ease;
}

/* ── 2. Base Reset ─────────────────────────────────────────── */
#shows-dashboard,
#shows-dashboard *,
#shows-dashboard *::before,
#shows-dashboard *::after {
  box-sizing: border-box;
}
#shows-dashboard {
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  color: var(--ucb-gray-900);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
#shows-dashboard h1,
#shows-dashboard h2,
#shows-dashboard h3 {
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  text-transform: uppercase;
}
#shows-dashboard .hidden {
  display: none !important;
}

/* ── 3a. Global Brand Bar + Main Tabs (one dark block) ─────────
   The brand label and the top-level tabs share a single solid
   near-black block so they read as one piece of app chrome. The
   warm gradient picks up below this, on the event picker. */
.dash-brandbar {
  background: #0d0d10;
  color: white;
  padding: 12px max(30px, calc((100% - 1200px) / 2 + 30px)) 0;
}
.dash-brandbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.dash-brand {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 28px;
}
/* Base ucb-logo + comedy-badge — also used by the PIN gate, inline-login
   forms, and anywhere else the lockup appears outside the brand bar. */
.ucb-logo {
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  font-weight: 900;
  font-size: 22px;
  letter-spacing: 4px;
  color: var(--ucb-brand);
}
.comedy-badge {
  display: inline-block;
  background: var(--ucb-accent);
  color: var(--ucb-gray-900);
  font-size: 7px;
  font-weight: 800;
  letter-spacing: 2px;
  padding: 2px 6px;
  border-radius: 3px;
  vertical-align: middle;
  margin-left: 5px;
  position: relative;
  top: -1px;
}
/* Brand-bar variants — white logo on the dark chrome */
.dash-brandbar .ucb-logo {
  color: white;
  display: inline-flex;
  align-items: center;
}
.dash-brand-divider {
  display: inline-block;
  width: 1px;
  height: 20px;
  background: rgba(255, 255, 255, 0.2);
}
.dash-brand-sub {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 2.5px;
  color: rgba(255, 255, 255, 0.55);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}

/* ── App-level actions (right side of the brand bar) ──────────
   "+ New Event" + the notification bell. They read as a pair of app
   actions, which is exactly what they are — deliberately OUTSIDE the
   event picker row and the show-scoped hero below it (2.34.2).
   .dash-attention still carries margin-left:auto from when it was the
   lone right-hand child; inside this content-sized wrapper there is no
   free space for it to claim, so it resolves to 0 and stays inert. */
.dash-brandbar-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}
/* Solid brand fill: it's the primary create action for the whole app and
   no longer sits beside the white BROWSE pill it once had to differentiate
   itself from. Sized to the bell's optical height so the pair sits on one
   baseline without either dominating. */
.brand-new-event-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 7px 15px;
  border: none;
  border-radius: var(--ucb-radius-sm);
  background: var(--ucb-brand);
  color: #fff;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease;
}
.brand-new-event-btn:hover {
  background: var(--ucb-brand-dark);
  color: #fff;
}
.brand-new-event-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #0d0d10, 0 0 0 4px var(--ucb-accent);
}
.brand-new-event-plus {
  font-size: 15px;
  font-weight: 700;
  line-height: 0.8;
}
/* Narrow screens: the brand lockup + both actions won't fit on one line.
   Drop the label and keep the "+" as an icon button — the bell is already
   icon-only, so the pair stays coherent. */
@media (max-width: 600px) {
  .brand-new-event-btn {
    padding: 7px 11px;
  }
  .brand-new-event-btn .brand-new-event-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* ── 3b. Main tabs bar — shares the brand bar's solid black ───
   Visually continues the brand bar so they read as one block.
   No top border between them. */
.main-tabs-bar {
  background: #0d0d10;
  padding: 0 max(30px, calc((100% - 1200px) / 2 + 30px));
}
.main-tabs-bar .main-tabs {
  /* No max-width or auto margin — the padding on the bar above
     defines the gutter, and the flex items align to its left edge.
     This keeps the tabs flush with the sub-tabs and the brand. */
  padding: 0;
}

/* ── 4. Show Hero — picker + show info, single gradient block ──
   Replaces the previous standalone event-selector + page-header
   pair. The picker is the first row; show info reveals below it
   once an event is chosen. Same gradient runs across both. */
#shows-dashboard .page-header {
  background: linear-gradient(135deg, var(--ucb-gray-900) 0%, var(--ucb-brand-dark) 60%, var(--ucb-brand) 100%);
  color: white;
  padding: 0;
  position: relative;
  overflow: hidden;
}
.page-header::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 25% 50%, rgba(212, 168, 75, 0.07) 0%, transparent 55%);
  pointer-events: none;
}
.header-inner {
  /* Padding-only pattern matches the brand bar + tabs above and
     the sub-tabs below, so every row in the dashboard aligns to
     the same left edge. */
  padding: 16px max(30px, calc((100% - 1200px) / 2 + 30px)) 20px;
  position: relative;
  z-index: 1;
}

/* Event picker row */
.event-picker-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 18px;
}
.event-picker-row:last-child {
  margin-bottom: 0; /* When show-info is hidden */
}
/* Visually hidden (owner call 2026-08-05: the picker's placeholder and the
   dark hero band already say "event" — the visible label was dead space).
   The <label for="event-filter"> stays in the DOM so the select keeps its
   accessible name; this is the standard sr-only clip pattern. */
.event-select-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.event-select {
  padding: 8px 14px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: var(--ucb-radius-sm);
  font-size: 13px;
  font-weight: 500;
  color: var(--ucb-gray-900);
  background: rgba(255, 255, 255, 0.96);
  font-family: inherit;
  min-width: 360px;
  max-width: 100%;
  flex: 1;
}
/* Select2 widget themed to fit on the dark hero */
.event-picker-row .select2-container {
  flex: 1;
  min-width: 0;
}
.event-picker-row .select2-container--default .select2-selection--single {
  height: 40px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--ucb-radius-sm);
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
  display: flex;
  align-items: center;
}
.event-picker-row .select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 38px;
  padding: 0 36px 0 14px;
  color: var(--ucb-gray-900);
  font-weight: 500;
  /* Keep the selected show on ONE line with an ellipsis. Without this the
     long title wraps to 3 lines on a narrow/full-width picker, grows the
     box past its 40px height, and visually buries the selection (the ID is
     still shown in the "EVENT (… · VIEW)" label above). */
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.event-picker-row .select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 38px;
}
.event-picker-row .select2-container--default.select2-container--focus .select2-selection--single,
.event-picker-row .select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--ucb-accent);
  box-shadow: 0 0 0 2px rgba(212, 168, 75, 0.35);
}

/* Event picker input group — the select and "Browse" share ONE white
   pill (hairline-divided segments), so Browse reads as the picker's
   second mode: pick from the dropdown, or browse the full list.
   Clicking it clears the selection and opens the Shows browser. */
.event-picker-group {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-width: 0;
}
/* Flatten the select's right corners so it butts into the Browse segment. */
.event-picker-group .select2-container--default .select2-selection--single {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: 0;
}
.browse-shows-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  /* No fixed height — the group's align-items:stretch sizes it to the
     Select2 pill exactly, whatever box-sizing the theme/select2 apply
     (a hard 40px sat 2px proud of the select). */
  padding: 0 16px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-left: 1px solid var(--ucb-gray-200);
  border-radius: 0 var(--ucb-radius-sm) var(--ucb-radius-sm) 0;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
  color: var(--ucb-gray-600);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
}
.browse-shows-btn:hover {
  color: var(--ucb-brand);
  background: #fff;
}
.browse-shows-btn:focus-visible {
  outline: none;
  border-color: var(--ucb-accent);
  box-shadow: 0 0 0 2px rgba(212, 168, 75, 0.35);
}
.browse-shows-icon { opacity: 0.75; }
.browse-shows-btn:hover .browse-shows-icon { opacity: 1; }


/* ── Shows browser (no-selection landing state) ──────────────────────
   Visibility contract: #shows-browser is display:none by default; the
   `is-browsing` class on #content-shows (setBrowsing() in
   shows-dashboard.js) swaps it in and hides the sub-nav + the active
   sub-panel. Everything below is scoped under #shows-browser so The7's
   form-element styling can't out-specify it. */
#shows-browser { display: none; }
#content-shows.is-browsing #shows-browser { display: block; }
#content-shows.is-browsing .shows-subnav-bar,
#content-shows.is-browsing > .tab-content { display: none !important; }

#shows-browser {
  /* Same centered-column padding formula as .header-inner so the list
     aligns with the hero content above it. */
  padding: 22px max(30px, calc((100% - 1200px) / 2 + 30px)) 44px;
}
.shows-browser-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 14px;
}
.shows-browser-title {
  margin: 0;
  font-size: 24px;
  color: var(--ucb-gray-900);
}
.shows-browser-count {
  font-size: 13px;
  color: var(--ucb-gray-500);
  white-space: nowrap;
}
/* Clear button: undo the global `.btn { width:100% }` and pin it to the
   filter-row control height (the .btn padding made it tower over the
   38px inputs). */
#shows-browser .browser-clear-btn {
  width: auto;
  flex-shrink: 0;
  height: 38px;
  padding: 0 14px;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
}

.shows-browser-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}
#shows-browser .shows-browser-filters input[type="search"],
#shows-browser .shows-browser-filters .browser-date,
#shows-browser .shows-browser-filters select {
  padding: 7px 10px;
  border: 1px solid var(--ucb-gray-300);
  border-radius: var(--ucb-radius-sm);
  background: #fff;
  color: var(--ucb-gray-900);
  font-size: 13px;
  font-family: inherit;
  height: 38px;
  margin: 0;
}
/* Hello Elementor's reset gives bare selects (and inputs) width:100%, which
   made every filter claim its own row on Elementor sites (Coldtowne) —
   search, region, and date-preset stacked instead of sharing the row like
   they do under The7. Selects size to content; the search keeps growing via
   .browser-search's flex-basis, and .browser-date keeps its 110px below. */
#shows-browser .shows-browser-filters select {
  width: auto;
  /* …and make them LOOK like dropdowns. Sharing the input's border and
     height with no indicator, "All Regions" / "Today" / "Show date" read as
     three text boxes someone had already filled in. appearance:none drops
     the native arrow (which The7 renders as a hairline caret and Hello
     Elementor as nothing at all) in favour of one that matches on both. */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%2352525b' d='M0 0h10L5 6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 10px 6px;
}
#shows-browser .browser-search {
  flex: 1 1 240px;
  min-width: 180px;
}
/* From/To are flatpickr altInputs (class copied from the original input). */
#shows-browser .shows-browser-filters .browser-date {
  width: 110px;
}
.browser-date-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ucb-gray-600);
  white-space: nowrap;
  margin: 0;
}

.browser-group-title {
  margin: 22px 0 8px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--ucb-gray-500);
}
.browser-group:first-child .browser-group-title {
  margin-top: 0;
}
.browser-group-rows {
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  background: #fff;
  overflow: hidden;
}
.browser-row {
  display: grid;
  /* dot · date · title · location · audit chip */
  grid-template-columns: 10px 200px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--ucb-gray-100);
  cursor: pointer;
  font-size: 14px;
}
.browser-row:last-child {
  border-bottom: none;
}
.browser-row:hover,
.browser-row:focus-visible {
  background: var(--ucb-gray-50);
}
.browser-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ucb-gray-400);
}
/* Status dot colors match formatEventOption()'s picker dots. */
.browser-dot--today  { background: #017e01; }
.browser-dot--future { background: #05699d; }
.browser-dot--past   { background: #a62d23; }
.browser-dot--draft  { background: #8a8a8a; }
.browser-dot--scheduled { background: var(--ucb-blue); }
.browser-row-date {
  color: var(--ucb-gray-600);
  font-size: 13px;
  white-space: nowrap;
}
/* Long / short renderings of the same date — exactly one is ever displayed
   (see §25e for the swap). Both are in the DOM so neither needs a JS
   resize listener; the hidden one is display:none, so it is out of the
   accessibility tree too and never double-read. */
.browser-date-short {
  display: none;
}
.browser-row-title {
  font-weight: 600;
  color: var(--ucb-gray-900);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.browser-row-loc {
  color: var(--ucb-gray-500);
  font-size: 13px;
  white-space: nowrap;
  justify-self: end;
}
.browser-draft-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 9px;
  background: var(--ucb-gray-200);
  color: var(--ucb-gray-600);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  vertical-align: 1px;
}
/* Scheduled reads as "queued to go live", not "unfinished" — same chip, blue.
   The -dark blue is the text-safe tier (2026-07 WCAG audit). */
.browser-draft-badge.browser-scheduled-badge {
  background: rgba(59, 130, 246, 0.15);
  color: var(--ucb-blue-dark);
}
.browser-row-audit {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 11px;
  background: rgba(239, 68, 68, 0.12);
  color: var(--ucb-red-dark);
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  justify-self: end;
}
.browser-empty {
  color: var(--ucb-gray-500);
  padding: 18px 0;
}
@media (max-width: 700px) {
  /* Phone layout: title on its own full-width line, then date + venue, then
     the audit chip if there is one.
     ⚠ The title MUST span both content columns. When it shared row 1 with the
     audit chip, column 2 was sized by the (hidden) chip's track and a
     three-word show title wrapped to three lines — "Improv 201 / Class Show –
     / Egan" — while two thirds of the row sat empty.
     ⚠ And date/venue MUST be allowed to wrap here. The desktop rules keep both
     `white-space: nowrap`, and a nowrap span in a squeezed grid track overflows
     its cell rather than shrinking it: that is exactly how "September 6, 2026
     6:30 PM" ended up printed ON TOP of "NY – 14TH ST. Upstairs". */
  .browser-row {
    /* Date column `auto` (it is nowrap, so it takes exactly what it needs),
       venue column `minmax(0, 1fr)` so it absorbs the remainder and WRAPS.
       An `auto` venue track cannot shrink past its longest word, which is how
       "LA Silver Lake (Class Show)" ended up sitting on top of the date on a
       class show; a 1fr track can shrink to nothing, so the pair can always
       be laid out. */
    grid-template-columns: 10px auto minmax(0, 1fr);
    grid-template-areas:
      'dot title title'
      'dot date  loc'
      'dot audit audit';
    align-items: start;
    column-gap: 10px;
    row-gap: 3px;
    padding: 12px 14px;
  }
  .browser-dot       { grid-area: dot; margin-top: 5px; }
  .browser-row-title { grid-area: title; white-space: normal; font-size: 15px; line-height: 1.3; }
  .browser-row-date,
  .browser-row-loc   { font-size: 12px; line-height: 1.35; }
  /* The date keeps nowrap and the VENUE is the one that gives — the venue's
     min-content is a short word ("Mainstage", "FRANKLIN"), so the row always
     resolves, while letting the date wrap orphans a "PM" onto line two. It
     is the pair of them being nowrap that overflowed. */
  .browser-row-date  { grid-area: date; white-space: nowrap; }
  .browser-date-long  { display: none; }
  .browser-date-short { display: inline; }
  .browser-row-loc   { grid-area: loc; justify-self: end; text-align: right; white-space: normal; }
  /* Its own row rather than the title's right edge — the chip is rare, and
     when it is absent `.hidden` collapses the row to nothing. */
  .browser-row-audit { grid-area: audit; justify-self: start; margin-top: 3px; }
}

/* Header quick links — View / Edit / Duplicate / Unpublish, under the
   show title+meta (they only exist once an event is selected, so they
   live with it instead of crowding the picker label). */
.show-header-links {
  margin-top: 6px;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.55);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.show-header-links a {
  color: rgba(255, 255, 255, 0.75);
  text-decoration: none;
  border-bottom: 1px dotted rgba(255, 255, 255, 0.35);
  white-space: nowrap;
}
.show-header-links a:hover {
  color: #fff;
  border-bottom-color: rgba(255, 255, 255, 0.7);
}
.show-header-links-sep {
  opacity: 0.5;
}

/* Publish button — the one prominent header action a draft needs. */
.header-actions .publish-event-btn {
  background: var(--ucb-accent);
  border: 1px solid var(--ucb-accent);
  color: #1a1a1a;
  font-weight: 700;
}
.header-actions .publish-event-btn:hover {
  filter: brightness(1.08);
}

/* Schedule… / Reschedule… — deliberately quieter than Publish. It sits on the
   dark header bar, so it declares BOTH colour and background rather than
   inheriting .btn's white-on-dark assumption (convention 33). */
.header-actions .schedule-event-btn,
.header-actions .schedule-event-btn:hover,
.header-actions .schedule-event-btn:focus {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.45);
  color: #fff;
  font-weight: 600;
}
.header-actions .schedule-event-btn:hover,
.header-actions .schedule-event-btn:focus {
  border-color: rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.1);
}

/* "Publishes Aug 20, 9:00 AM" — the scheduled state's one piece of standing
   information, so it reads as a status chip rather than another link. */
.show-header-links .show-scheduled-pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 9px;
  background: rgba(59, 130, 246, 0.22);
  border: 1px solid rgba(147, 197, 253, 0.5);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  white-space: nowrap;
}

/* ucbExplain's popup is position:absolute, and #shows-dashboard .page-header
   sets `overflow: hidden` — so the popup was sliced off at the header's bottom
   edge (NOT a z-index problem: .header-inner's z-index:1 stacking context
   already paints above the content below).
   Lifted only while a scheduled pill is actually showing its explainer, so
   every other header state keeps today's clipping byte for byte. The clip
   guards nothing else today — the header's one absolutely-positioned
   descendant is .page-header::before at `inset: 0`, and .show-artwork is
   fixed-size with object-fit — but scoping it costs nothing and means this
   can't become the reason some future header child escapes.
   Browsers without :has() simply keep the old clipped popup. */
#shows-dashboard .page-header:has(.show-scheduled-pill .ucb-explain) {
  overflow: visible;
  /* …and lift the whole header above .stats-strip (position:relative; z-index:2),
     which is the first thing below it that paints in the same stacking context.
     The popup's own z-index:200 CANNOT do this: .header-inner sets z-index:1, so
     200 only ranks the popup INSIDE that context — against the strip, the header's
     level is what counts. Harmless for layout (the header's box doesn't overlap
     anything below it) and can't intercept clicks, since .ucb-explain__pop is
     pointer-events:none. Was invisible until the note grew tall enough to reach
     the strip; before that it only overlapped the un-positioned sub-tab bar. */
  z-index: 5;
}

/* The pill's "?" sits on the DARK header bar, where the component's default
   white-on-light trigger reads as a bright dot. Restyle the trigger only — the
   popup renders on its own light panel and is fine as shipped. */
.show-scheduled-pill .ucb-explain {
  /* The typography reset that used to live here (text-transform / letter-spacing /
     white-space, against this chip's uppercase+tracked+nowrap inheriting into the
     popup) moved into the component itself — .ucb-explain__pop and
     .ucb-explain__trigger now guard themselves for every consumer. */
  margin-left: 6px;
}
.show-header-links .ucb-explain__trigger {
  border-color: rgba(255, 255, 255, 0.55);
  background: transparent;
  color: rgba(255, 255, 255, 0.9);
}
.show-header-links .ucb-explain__trigger:hover,
.show-header-links .ucb-explain__trigger:focus {
  border-color: #fff;
  color: #fff;
}

/* Schedule dialog field (ucbDialog body — light panel, not the dark header). */
.ucb-schedule-field {
  margin-top: 14px;
  text-align: left;
}
.ucb-schedule-field label {
  display: block;
  margin-bottom: 4px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--ucb-gray-600);
}
/* `static: true` (required for flatpickr inside a modal — convention 19) wraps
   the input in flatpickr's own `.flatpickr-wrapper`, which ships
   `display: inline-block`. An inline-block shrink-wraps its content, so
   `width: 100%` on the input resolves against a parent that sized itself to
   that same input — circular, and the field stays at its intrinsic width no
   matter how the rule is written. THIS is what clipped the value at
   "…at 1:00 P"; it was never a specificity fight (The7 has no competing input
   width rule — checked). The wrapper has to become a block first.
   Only inside our field: flatpickr's default positioning is load-bearing for
   the in-page tab pickers. */
.ucb-dialog .ucb-schedule-field .flatpickr-wrapper {
  display: block;
  width: 100%;
}

/* Every input in the field rather than a specific class: with altInput on, the
   field the user actually sees is the one FLATPICKR made, carrying flatpickr's
   own altInputClass ("form-control input") — not ours — so a rule keyed on our
   class styles the hidden original instead.
   :not([type=hidden]) because flatpickr turns that original into a hidden input
   and leaves it in the DOM; `display: block` on it is only saved by a UA
   !important, which isn't something to depend on.
   Plain specificity is enough — NEITHER theme competes here (The7 has no input
   width rule at all; Hello's reset.css already says width:100%). */
.ucb-dialog .ucb-schedule-field input:not([type="hidden"]) {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: 1px solid var(--ucb-gray-300);
  border-radius: 6px;
  font-size: 14px;
  background: #fff;
  color: var(--ucb-gray-800);
}
/* "That's 4:00 PM where you are" — only rendered for viewers whose timezone
   differs from the site's, so it must read as a quiet aside, not a warning. */
.ucb-schedule-field .ucb-schedule-local {
  margin: 6px 0 0;
  color: var(--ucb-gray-600);
  font-size: 12px;
}
.ucb-schedule-field .ucb-schedule-error {
  margin: 6px 0 0;
  /* -dark tier: the base red fails contrast as text (2026-07 WCAG audit). */
  color: var(--ucb-red-dark);
  font-size: 12px;
}

/* Show info row: artwork | title+meta | CSV actions */
.header-body {
  display: flex;
  align-items: center;
  gap: 20px;
  margin: 0;
}
.header-body-text {
  flex: 1;
  min-width: 0;
}
.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
/* The sizing lives on the BUTTON so the image can fill it: the wrapper is
   what the hero's flex row measures and what the mobile rules resize. */
.show-artwork-btn {
  width: 160px;
  flex-shrink: 0;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 8px;
  cursor: zoom-in;
  line-height: 0;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
.show-artwork-btn:focus-visible {
  outline: 2px solid var(--ucb-accent);
  outline-offset: 3px;
}
.show-artwork {
  width: 100%;
  /* ⚠ 2:1 always. The featured image is authored at 2:1 and `object-fit: cover`
     will silently crop it to whatever box it is given — a square box on a phone
     ate the ends of every title card. Change the WIDTH for a breakpoint, never
     the ratio. */
  aspect-ratio: 2 / 1;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: none;
  display: block;
}
@media (max-width: 720px) {
  /* Event picker stacks: label on its own line, the (Select2) picker full
     width below it. */
  .event-picker-row {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .event-picker-row .select2-container,
  .event-picker-row .event-select {
    /* Beat the inline width Select2 sets on the container. */
    width: 100% !important;
    min-width: 0;
    flex: none;
  }
  /* Sub-tab swipe-scroll moved to §25a — it now covers every strip, not
     just this one and Reports. */
  .header-body {
    flex-wrap: wrap;
    gap: 14px;
  }
  .show-artwork-btn { width: 120px; }
  .header-actions {
    width: 100%;
    justify-content: flex-start;
  }
}
#shows-dashboard .show-title {
  font-size: 28px;
  font-weight: 900;
  line-height: 1.15;
  margin: 0 0 6px;
  color: white;
  letter-spacing: 0.5px;
}
.show-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 12px;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.7);
  margin: 0;
}
.show-meta span {
  display: inline-flex;
  align-items: center;
}
.show-meta span + span::before {
  content: '•';
  margin-right: 12px;
  color: rgba(255, 255, 255, 0.35);
}

/* CSV buttons sit on the dark hero — translucent so they don't
   blow out against the gradient. */
.header-actions .btn-secondary {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: white;
  backdrop-filter: blur(4px);
}
.header-actions .btn-secondary:hover {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.35);
}

/* ── 4b. Attention bell (brand bar) ─────────────────────────── */
.dash-attention {
  position: relative;
  margin-left: auto;
}
.attention-bell {
  position: relative;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 4px 6px;
  font-size: 18px;
  line-height: 1;
  filter: grayscale(1) brightness(1.6);
  transition: filter var(--ucb-transition);
}
.attention-bell:hover,
.attention-bell[aria-expanded="true"] {
  filter: none;
}
.attention-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--ucb-brand);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  filter: none; /* keep the red badge red over the grayscaled bell */
}
.attention-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  width: 340px;
  max-width: 90vw;
  max-height: 60vh;
  overflow-y: auto;
  background: #fff;
  color: var(--ucb-gray-900);
  border-radius: var(--ucb-radius-sm);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
  z-index: 1000;
  text-align: left;
}
.attention-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--ucb-gray-200);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-600);
}
.attention-mark-read {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 11px;
  color: var(--ucb-brand);
  text-transform: none;
  letter-spacing: 0;
  padding: 0;
}
.attention-group-label {
  padding: 8px 14px 2px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-600);
}
.attention-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  width: 100%;
  padding: 8px 14px;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  font-size: 13px;
  line-height: 1.35;
  color: var(--ucb-gray-800);
}
.attention-item:hover {
  background: var(--ucb-gray-50);
}
.attention-item-dot {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ucb-brand);
  margin-top: 5px;
}
.attention-item.is-seen {
  color: var(--ucb-gray-500);
}
.attention-item.is-seen .attention-item-dot {
  background: var(--ucb-gray-300);
}
.attention-empty {
  margin: 0;
  padding: 18px 14px;
  font-size: 13px;
  color: var(--ucb-gray-500);
}

/* ── 5. Tab Bar ────────────────────────────────────────────── */
.main-tabs {
  display: flex;
  gap: 0;
  padding: 0;
  overflow-x: auto;
}
.main-tab {
  padding: 12px 20px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  border: none;
  background: transparent;
  color: rgba(255, 255, 255, 0.5);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  border-bottom: 3px solid transparent;
  transition: color var(--ucb-transition), border-color var(--ucb-transition);
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
}
.main-tab:hover {
  color: rgba(255, 255, 255, 0.8);
}
.main-tab[aria-selected="true"],
.main-tab.active {
  color: white;
  border-bottom-color: var(--ucb-accent);
}
.main-tab:focus-visible {
  outline: 2px solid var(--ucb-accent);
  outline-offset: -2px;
}
/* Settings floats to the far right of the tab row — it's the least-used
   tab, and the gap visually separates config from day-to-day work. In the
   mobile scroll container margin-left:auto is inert (content overflows),
   so it degrades gracefully to a normal last tab. */
.main-tab--right {
  margin-left: auto;
}

/* ── 5b. Shows shell + sub-tabs ─────────────────────────────── */
/* The Shows panel is a transparent wrapper around the event selector,
   page header, sub-tab nav, and sub-panels. It doesn't add padding or
   max-width — the inner pieces handle their own layout. */
.shows-shell[hidden] {
  display: none;
}

.shows-subnav-bar {
  background: white;
  border-bottom: 1px solid var(--ucb-gray-200);
  padding: 0 max(30px, calc((100% - 1200px) / 2 + 30px));
}
.shows-subnav {
  display: flex;
  gap: 0;
  /* No overflow-x: auto — five sub-tabs always fit, and the rule creates a
     scroll container that macOS paints a phantom scrollbar in. Same fix
     applied earlier to .settings-subnav. */
}
/* A sub-tab whose panel is holding unsaved edits. Switching sub-tabs does NOT
   discard them, so this is a REMINDER, not a warning — the blocking confirm is
   reserved for switching shows, which does discard. Its whole point is that
   the panel's own "Unsaved" chip is invisible once you leave the panel.
   The dot is decorative; paintUnsavedSubtabs() also appends real sr-only text,
   because a colour or a glyph alone is not a status (convention 46). */
.shows-subtab.has-unsaved::after {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 6px;
  vertical-align: 1px;
  border-radius: 50%;
  background: var(--ucb-amber);
}
.shows-subtab.has-unsaved {
  color: var(--ucb-amber-dark);
}

.shows-subtab {
  padding: 10px 18px;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  color: var(--ucb-gray-500);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
  transition: color var(--ucb-transition), border-color var(--ucb-transition);
}
.shows-subtab:hover {
  color: var(--ucb-gray-900);
}
.shows-subtab[aria-selected="true"],
.shows-subtab.active {
  color: var(--ucb-brand);
  border-bottom-color: var(--ucb-brand);
}
.shows-subtab:focus-visible {
  outline: 2px solid var(--ucb-accent);
  outline-offset: -2px;
}
/* "+ New Event" — right-aligned action tab (show_admin only). Creation
   is a verb, so it reads as an action, not a place: pushed to the far
   end of the sub-nav, accent-colored. Activating it opens the create
   panel like any tab. In the mobile scroll container margin-left:auto
   is inert and it degrades to a normal last tab. */
.shows-subtab--action {
  margin-left: auto;
  color: var(--ucb-brand);
  font-weight: 700;
}
.shows-subtab--action:hover {
  color: var(--ucb-brand);
  filter: brightness(1.15);
}

/* Lifecycle phase divider — a short centered tick before the first tab of
   a phase (night-of │ prep & sales │ wrap-up). Kept subtle: tabs keep
   their positions, the divider just makes the grouping readable. */
.shows-subtab--phase {
  position: relative;
  margin-left: 9px;
}
.shows-subtab--phase::before {
  content: '';
  position: absolute;
  left: -5px;
  top: 50%;
  transform: translateY(-50%);
  height: 55%;
  width: 1px;
  background: var(--ucb-gray-300);
}

.settings-stub {
  color: var(--ucb-gray-500);
  font-style: italic;
}

/* ── 5d. Reports tab — sub-nav ──────────────────────────────── */
.ucb-reports {
  width: 100%;
}
.reports-subnav-bar {
  border-bottom: 1px solid var(--ucb-gray-200);
  margin-bottom: 24px;
}
.reports-subnav {
  display: flex;
  gap: 0;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 30px;
  /* Swipe-scroll + edge fade: §25a, which applies the same pattern to
     every tab strip. This one used to carry its own copy (2026-07-24) and
     was the only sub-nav that had it. */
}
.reports-subnav .reports-subtab,
.talent-subnav .talent-subtab {
  flex: none;
  white-space: nowrap;
}
.reports-subtab,
.talent-subtab {
  padding: 10px 18px;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  color: var(--ucb-gray-500);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
  transition: color var(--ucb-transition), border-color var(--ucb-transition);
}
.reports-subtab:hover,
.talent-subtab:hover {
  color: var(--ucb-gray-900);
}
.reports-subtab[aria-selected="true"],
.reports-subtab.active,
.talent-subtab[aria-selected="true"],
.talent-subtab.active {
  color: var(--ucb-brand);
  border-bottom-color: var(--ucb-brand);
}
.reports-subtab:focus-visible,
.talent-subtab:focus-visible {
  outline: 2px solid var(--ucb-accent);
  outline-offset: -2px;
}
/* Talent tab sub-nav (Talent / Approvals). Shares .reports-subtab's
   metrics above rather than adding a fifth copy of the same rule; only the
   bar and the inner-panel reset are its own. */
.talent-subnav-bar {
  border-bottom: 1px solid var(--ucb-gray-200);
  margin-bottom: 18px;
}
.talent-subnav {
  display: flex;
  gap: 0;
}
/* Inner panels drop .tab-content's padding/max-width — the outer
   #content-talent-packet already handles centering (same pattern as
   Settings / Reports / Day View / Show Holds). */
.talent-panel {
  padding: 0;
  max-width: none;
}

/* The embedded report shortcodes ship their own admin-style chrome —
   give them breathing room from the dashboard's brand container without
   double-wrapping. */
.reports-embed {
  padding-top: 8px;
}
.reports-loading {
  color: var(--ucb-gray-500);
  font-style: italic;
  /* Align with the sub-tab labels above: same 1200px centered cap as
     .reports-subnav, plus its 30px side padding and the subtab's own 18px
     label inset (48px total). */
  padding: 24px 48px;
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}
.reports-loading--error {
  color: var(--ucb-red-dark);
  font-style: normal;
}

/* Reports tab content stretches beyond the dashboard's 1200px cap.
   The sub-nav above stays constrained (max-width: 1200px on .reports-subnav)
   so the tab strip aligns with the rest of the dashboard chrome, but the
   wide ticket-type tables inside the reports can use the full container
   width. */
#shows-dashboard .tab-content#content-reports {
  max-width: none;
}

/* The "Normalize report buttons" block that lived here is GONE (2.55.8).
   It repainted `.ucb-sales-button` and WP-admin's `.button` / `.button-primary`
   to look like `.btn` — a third spelling of the same control, and it only
   existed because `.btn` was locked inside this stylesheet and therefore
   unreachable on the standalone report pages. Every embedded report now uses
   the real `.btn` from ucb-button.css.
   ⚠ Don't re-add it. If a report renders a button that looks wrong, give that
   button `.btn` — repainting a foreign class from here is how the drift
   started. Genuine wp-admin screens (the CSV importer, the DCM show linker)
   keep `.button` on purpose: that is WordPress's design language, not ours. */

/* Reports filter layout — each report uses multiple <form> elements as
   block-level siblings (filter form, clear form, export form), which is
   why the buttons stack vertically by default. Make every form inside
   the reports embed an inline-flex container, and wrap when out of room,
   so the date inputs + select + buttons share one row when space allows. */
.reports-embed form {
  display: inline-flex !important;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  vertical-align: middle;
  margin: 0 12px 16px 0 !important;
}
.reports-embed form label,
.reports-embed form .ucb-sales-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  margin: 0;
}
/* Select2 widget — force inline-block + cap width so it shares the row.
   Note the leading `#shows-dashboard` — needed to outrank the catch-all
   `#shows-dashboard .select2-container { width: 100% !important }` rule
   in the Select2 overrides section below (specificity 1+1 vs 0+2). */
#shows-dashboard .reports-embed .select2-container {
  display: inline-block !important;
  vertical-align: middle;
  width: 300px !important;
  max-width: 320px;
}
/*
 * ⚠ ONE place that neutralises The7's site-wide bare-input bottom margin.
 *
 * The7 ships `input[type=text]:not(.elementor-field):not(.searchform-s) {
 * margin-bottom: 10px }` at (0,2,1). The `.reports-embed form input[type=...]`
 * rule below is ALSO (0,2,1) — an exact tie, decided only by stylesheet load
 * order, which is why the margin kept coming back in places that looked
 * covered. An `#shows-dashboard` prefix makes it (1,0,1) and settles it
 * outright, for every input we render in the dashboard rather than per feature.
 *
 * A report rendered OUTSIDE the dashboard does not get this file, so its own
 * stylesheet must still out-specify The7 on its own (convention 33).
 */
#shows-dashboard input[type="text"],
#shows-dashboard input[type="date"],
#shows-dashboard input[type="number"],
#shows-dashboard input[type="search"],
#shows-dashboard input[type="email"],
#shows-dashboard input[type="tel"] {
  margin-bottom: 0;
}

.reports-embed form input[type="date"],
.reports-embed form input[type="text"],
.reports-embed form input[type="number"] {
  display: inline-block;
  width: auto;
  /* The7 gives bare inputs a 10px bottom margin site-wide
     (input[type=date]:not(.elementor-field) { margin-bottom: 10px }),
     which knocks the filter inputs out of vertical alignment. The extra
     attribute selector here outranks the theme rule. */
  margin-bottom: 0;
}
/* Native selects — constrain to a sensible width. Critically: DO NOT
   touch `.select2-hidden-accessible` selects, because that's what Select2
   uses to keep the original element offscreen — overriding its display
   re-shows it as a wide multi-select box (which is what was happening). */
.reports-embed form select:not(.select2-hidden-accessible) {
  display: inline-block;
  width: auto;
  min-width: 200px;
  max-width: 320px;
}
.reports-embed form select[multiple]:not(.select2-hidden-accessible) {
  /* If Select2 didn't init for some reason, at least keep the native
     multi-select to a single-row height so it doesn't stretch tall. */
  height: 38px;
}

/* ── 5c. Settings tab — sub-nav and cards ───────────────────── */
.ucb-settings {
  width: 100%;
}
.settings-subnav-bar {
  border-bottom: 1px solid var(--ucb-gray-200);
  margin-bottom: 24px;
}
.settings-subnav {
  display: flex;
  gap: 0;
  /* This used to say "two tabs always fit" and therefore declined to
     scroll. It grew to eight: measured 1,164px of tabs in a 324px row on a
     phone, with everything past "Emails" simply unreachable. §25a scrolls
     it (with the scrollbar hidden, which was the real objection). */
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 30px;
}
.settings-subtab {
  padding: 10px 18px;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  color: var(--ucb-gray-500);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  text-transform: uppercase;
  letter-spacing: 1px;
  white-space: nowrap;
  transition: color var(--ucb-transition), border-color var(--ucb-transition);
}
.settings-subtab:hover {
  color: var(--ucb-gray-900);
}
.settings-subtab[aria-selected="true"],
.settings-subtab.active {
  color: var(--ucb-brand);
  border-bottom-color: var(--ucb-brand);
}
.settings-subtab:focus-visible {
  outline: 2px solid var(--ucb-accent);
  outline-offset: -2px;
}

/* Settings sub-panels inherit .tab-content (for the show/hide rules) but
   the OUTER #content-settings is also a .tab-content with its own padding
   and 1200px cap. Without resetting, the inner panel's padding stacks
   with the outer and the inner 1200px cap can collide with the outer
   centering, producing a phantom inner scrollbar at wide viewports.
   Reset inner panels to a transparent wrapper that only does show/hide.
   Same applies to the Reports tab. */
.tab-content.settings-panel,
.tab-content.reports-panel {
  padding: 0;
  max-width: none;
  margin: 0;
}
.ucb-settings,
.ucb-settings .content,
.ucb-reports,
.ucb-reports .content {
  overflow: visible;
}

.settings-card {
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius);
  padding: 24px;
  box-shadow: var(--ucb-shadow-sm);
}
.settings-card-heading {
  margin: 0 0 8px;
  font-size: 18px;
  color: var(--ucb-gray-900);
}
.settings-card-desc {
  margin: 0 0 16px;
  color: var(--ucb-gray-600);
  font-size: 14px;
  line-height: 1.5;
}
.settings-card-desc code {
  background: var(--ucb-gray-100);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 12px;
}
.settings-readonly-notice {
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 10px 14px;
  margin: 0 0 16px;
  color: var(--ucb-gray-700);
  font-size: 13px;
}
.settings-error {
  color: var(--ucb-red-dark);
  font-size: 14px;
}
.settings-input {
  width: 100%;
  padding: 7px 10px;
  font-size: 14px;
  /* border-strong, not gray-300: real input borders need 3:1 against the
     white page (gray-300 was only 1.48:1 — WCAG audit 2026-07). */
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  background: white;
  font-family: inherit;
  color: var(--ucb-gray-900);
  transition: border-color var(--ucb-transition);
}
.settings-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.1);
}
/* Bump specificity so any WP theme styles like `input { color: … }`
   don't dim the typed text in settings forms. */
#shows-dashboard .ucb-settings input.settings-input,
#shows-dashboard .ucb-settings textarea.settings-input,
#shows-dashboard .ucb-settings select.settings-input {
  color: var(--ucb-gray-900);
  background-color: white;
}
#shows-dashboard .ucb-settings input.settings-input::placeholder,
#shows-dashboard .ucb-settings textarea.settings-input::placeholder {
  color: var(--ucb-gray-500);
  opacity: 1;
}

/* ── Settings → Producer Emails / Email Templates sub-tabs ────────────
   These two sub-tabs render the SAME PHP methods the wp-admin "UCB
   Settings → Emails" page uses (Producer_Comms::render_settings_tab(),
   UCB_Admin_Settings::render_ticket_emails_panel()/render_woo_emails_panel(),
   Transfer_Notification_Email::render_settings_tab()) — reuse, not a
   second copy (CLAUDE.md's "reuse helpers, don't duplicate" rule). Those
   methods emit wp-admin-styled markup (.ucb-item accordions, .button /
   .button-primary, .large-text / .small-text, .description) with none of
   wp-admin's own admin.css loaded on this front-end page, so this block
   is a minimal scoped port of the relevant rules from
   UCB_Admin_Settings::output_admin_styles() — just enough to be
   presentable, not a pixel-match of wp-admin. Everything is scoped under
   .email-settings-embed so it can't leak into the rest of the dashboard
   (mirrors the existing .reports-embed pattern above). */
.email-settings-embed {
  margin-top: 4px;
}
.email-settings-embed h3.settings-subheading {
  margin-top: 32px;
}
.email-settings-embed h3.settings-subheading:first-child {
  margin-top: 0;
}

.email-settings-embed .ucb-section-intro {
  background: var(--ucb-gray-50);
  border-left: 4px solid var(--ucb-brand);
  padding: 12px 16px;
  margin-bottom: 20px;
  border-radius: 0 var(--ucb-radius-sm) var(--ucb-radius-sm) 0;
}
.email-settings-embed .ucb-section-intro p {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.email-settings-embed .ucb-section-intro p:last-child {
  margin-bottom: 0;
}
.email-settings-embed .ucb-section-intro code {
  background: var(--ucb-gray-100);
  padding: 2px 6px;
  border-radius: 3px;
}

.email-settings-embed .ucb-settings-section-heading {
  font-size: 15px;
  margin: 28px 0 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ucb-gray-200);
  color: var(--ucb-gray-900);
}
.email-settings-embed .ucb-settings-section-heading:first-child {
  margin-top: 0;
}
.email-settings-embed .ucb-settings-section-desc {
  color: var(--ucb-gray-600);
  margin: 0 0 20px;
  max-width: 680px;
  font-size: 13px;
  line-height: 1.5;
}
.email-settings-embed .ucb-settings-row {
  margin-bottom: 18px;
}
.email-settings-embed .ucb-settings-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 420px;
}
/* --full: template-content fields (email subject/body editors) escape the
   scalar-control width cap. Mirrored in UCB_Admin_Settings::output_admin_styles(). */
.email-settings-embed .ucb-settings-field--full {
  max-width: none;
}
/* Tier-1 UX/a11y pass (2026-08-14), mirrored in
   UCB_Admin_Settings::output_admin_styles(): keyboard focus ring for the
   now-focusable accordion headers, per-row customization chips, the
   workflow map strip, and the unknown-merge-field warnings list. */
.email-settings-embed .ucb-item-header:focus-visible {
  outline: 2px solid var(--ucb-maroon, #8b2025);
  outline-offset: -2px;
}
.email-settings-embed .ucb-item-chips {
  margin-left: auto;
  font-size: 11px;
  color: var(--ucb-gray-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 55%;
}
.email-settings-embed .ucb-pcomm-map {
  margin: 0 0 22px;
  padding: 10px 14px;
  border-left: 3px solid var(--ucb-gray-300);
  background: var(--ucb-gray-50);
  list-style: none;
}
.email-settings-embed .ucb-pcomm-map li {
  margin: 3px 0;
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.email-settings-embed .ucb-pcomm-save-warnings {
  margin: 10px 0 0;
  padding: 10px 14px 10px 30px;
  background: #fcf9e8;
  border-left: 3px solid #dba617;
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.email-settings-embed .ucb-pcomm-save-warnings li { margin: 3px 0; }
.email-settings-embed .ucb-pcomm-preview-meta {
  font-size: 12.5px;
  color: var(--ucb-gray-500);
  margin: 8px 0 6px;
  font-style: italic;
}
.email-settings-embed .ucb-pcomm-preview-subject {
  font-weight: 600;
  font-size: 13px;
  padding: 8px 10px;
  margin-bottom: 10px;
  background: var(--ucb-gray-50);
  border-left: 3px solid var(--ucb-gray-300);
}
/* Venue-override rows: which-email-is-this grouping (2.36.8). Mirrored in
   UCB_Admin_Settings::output_admin_styles(). */
.email-settings-embed .ucb-pcomm-subgroup {
  margin: 18px 0 6px;
  padding-top: 10px;
  border-top: 1px dashed var(--ucb-gray-300);
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ucb-gray-600);
}
/* Venue-first tab strip (Tier 3 restructure, 2026-08-14) — Producer Emails'
   "Applies to" rows became tabs instead of an accordion. Underline style,
   consistent with .settings-subnav/.settings-subtab elsewhere in this file.
   Mirrored in UCB_Admin_Settings::output_admin_styles(). */
.email-settings-embed .ucb-pcomm-vtabs-intro {
  margin-bottom: 14px;
}
.email-settings-embed .ucb-pcomm-vtabs-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 10px;
  border-bottom: 1px solid var(--ucb-gray-200);
  margin-bottom: 20px;
}
.email-settings-embed .ucb-pcomm-vtabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
}
.email-settings-embed .ucb-pcomm-vtab {
  padding: 10px 16px;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--ucb-gray-600);
}
.email-settings-embed .ucb-pcomm-vtab:hover {
  color: var(--ucb-gray-900);
}
.email-settings-embed .ucb-pcomm-vtab.is-active {
  border-bottom-color: var(--ucb-brand);
  color: var(--ucb-gray-900);
}
.email-settings-embed .ucb-pcomm-vtab:focus-visible {
  outline: 2px solid var(--ucb-maroon, #8b2025);
  outline-offset: -2px;
}
/* Secondary, so it doesn't read as one more venue tab. */
.email-settings-embed .ucb-pcomm-vtab-add {
  margin-bottom: 8px;
  padding: 6px 12px;
  background: none;
  border: 1px dashed var(--ucb-gray-300);
  border-radius: var(--ucb-radius-sm);
  color: var(--ucb-gray-600);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
}
.email-settings-embed .ucb-pcomm-vtab-add:hover {
  color: var(--ucb-brand);
  border-color: var(--ucb-brand);
}
.email-settings-embed .ucb-pcomm-vtab-add:focus-visible {
  outline: 2px solid var(--ucb-maroon, #8b2025);
  outline-offset: -2px;
}
.email-settings-embed .ucb-pcomm-vpanel[hidden] {
  display: none;
}
.email-settings-embed .ucb-pcomm-inherit-note {
  font-size: 12px;
  font-style: italic;
  color: var(--ucb-gray-600);
  margin: 0 0 10px;
}
.email-settings-embed .ucb-pcomm-chips {
  font-size: 11px;
  color: var(--ucb-gray-500);
  margin: 0 0 18px;
}
.email-settings-embed .ucb-pcomm-field-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.email-settings-embed .ucb-pcomm-start-from-default {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: var(--ucb-brand);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  text-decoration: underline;
}
.email-settings-embed .ucb-pcomm-start-from-default:hover {
  color: var(--ucb-brand-dark);
}
.email-settings-embed .ucb-pcomm-venue-remove {
  color: var(--ucb-red-dark);
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  font-size: 13px;
}
.email-settings-embed .ucb-pcomm-venue-remove:hover {
  text-decoration: underline;
}
.email-settings-embed .ucb-settings-field label {
  font-weight: 600;
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.email-settings-embed .ucb-field-desc {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin: 0;
}
.email-settings-embed .ucb-input-prefix-wrap {
  display: flex;
  align-items: center;
}
.email-settings-embed .ucb-input-prefix {
  background: var(--ucb-gray-100);
  border: 1px solid var(--ucb-border-strong);
  border-right: none;
  padding: 7px 10px;
  border-radius: var(--ucb-radius-sm) 0 0 var(--ucb-radius-sm);
  font-size: 14px;
  color: var(--ucb-gray-600);
}

/* Accordion rows (venue overrides, per-venue email templates) */
.email-settings-embed .ucb-items-list {
  margin-bottom: 16px;
}
.email-settings-embed .ucb-item {
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  margin-bottom: 10px;
}
.email-settings-embed .ucb-item-header {
  padding: 12px 15px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
.email-settings-embed .ucb-item-header:hover {
  background: var(--ucb-gray-100);
}
.email-settings-embed .ucb-drag-handle {
  cursor: grab;
  color: var(--ucb-gray-600);
}
.email-settings-embed .ucb-drag-handle:active {
  cursor: grabbing;
}
.email-settings-embed .ucb-item-title {
  flex: 1;
  font-weight: 600;
  color: var(--ucb-gray-900);
  font-size: 13px;
}
.email-settings-embed .ucb-item-toggle {
  color: var(--ucb-gray-500);
  transition: transform var(--ucb-transition);
}
.email-settings-embed .ucb-item.is-open .ucb-item-toggle {
  transform: rotate(180deg);
}
.email-settings-embed .ucb-item-fields {
  display: none;
  padding: 15px;
  border-top: 1px solid var(--ucb-gray-200);
  background: #fff;
}
.email-settings-embed .ucb-item.is-open .ucb-item-fields {
  display: block;
}
.email-settings-embed .ucb-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
  margin-bottom: 15px;
}
.email-settings-embed .ucb-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.email-settings-embed .ucb-field-full {
  grid-column: 1 / -1;
}
.email-settings-embed .ucb-field label {
  font-weight: 600;
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.email-settings-embed .ucb-item-actions {
  display: flex;
  gap: 10px;
  padding-top: 15px;
  border-top: 1px solid var(--ucb-gray-200);
  margin-top: 15px;
}
.email-settings-embed .ucb-btn-remove {
  color: var(--ucb-red-dark);
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  font-size: 13px;
}
.email-settings-embed .ucb-btn-remove:hover {
  text-decoration: underline;
}

.email-settings-embed .ucb-actions-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 15px;
  border-top: 1px solid var(--ucb-gray-200);
  margin-top: 20px;
}
.email-settings-embed .ucb-save-bar {
  display: flex;
  align-items: center;
  gap: 10px;
}
.email-settings-embed .ucb-save-status {
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.email-settings-embed .ucb-save-status.is-saved {
  color: var(--ucb-green-dark);
}
.email-settings-embed .ucb-save-status.is-error {
  color: var(--ucb-red-dark);
}

.email-settings-embed .ucb-email-preview-section {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 2px solid var(--ucb-gray-200);
}
.email-settings-embed .ucb-email-preview-section h3 {
  margin: 0 0 10px;
  font-size: 15px;
  color: var(--ucb-gray-900);
}
.email-settings-embed .ucb-preview-notice {
  color: var(--ucb-gray-600);
  font-style: italic;
  margin-bottom: 15px;
  font-size: 13px;
}
.email-settings-embed .ucb-preview-controls {
  display: flex;
  gap: 10px;
  margin-bottom: 15px;
  flex-wrap: wrap;
  align-items: center;
}
/* The theme paints the select caret inside the right edge; the embed's
   10px side padding let it overlap short selects' text ("Show Confirmatio▾n",
   2026-08-14). And .button ships its own height/margins — stretch it to the
   row so it can't sit below the selects. */
.email-settings-embed .ucb-preview-controls select {
  padding-right: 34px;
}
.email-settings-embed .ucb-preview-controls .button {
  align-self: stretch;
  display: inline-flex;
  align-items: center;
  margin: 0;
}
.email-settings-embed .ucb-preview-frame {
  border: 1px solid var(--ucb-gray-200);
  padding: 18px;
  background: var(--ucb-gray-50);
  min-height: 80px;
  border-radius: var(--ucb-radius-sm);
}
.email-settings-embed .ucb-preview-frame.is-loading {
  opacity: 0.5;
}
.email-settings-embed .ucb-preview-empty {
  color: var(--ucb-gray-600);
  font-style: italic;
  margin: 0;
}
.email-settings-embed .ucb-preview-meta {
  display: flex;
  gap: 15px;
  flex-wrap: wrap;
  margin-bottom: 15px;
  padding: 10px 14px;
  background: var(--ucb-gray-50);
  border-left: 4px solid var(--ucb-brand);
  border-radius: 0 4px 4px 0;
  font-size: 13px;
}
.email-settings-embed .ucb-woo-preview-iframe {
  width: 100%;
  border: none;
  min-height: 500px;
  background: #fff;
}

/* Editor chrome (wp_editor) — wp_enqueue_editor() ships TinyMCE + the
   editor-buttons stylesheet, but not wp-admin's own admin.css, so the
   Visual/Text tab strip and outer wrap have no border/background here. */
.email-settings-embed .wp-editor-wrap {
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  overflow: hidden;
}
.email-settings-embed .wp-editor-tabs {
  padding: 6px 6px 0;
  background: var(--ucb-gray-50);
}

/* Bare form controls + WP-admin utility width classes (.large-text /
   .small-text) — neither is defined outside wp-admin's own forms.css. */
.email-settings-embed input[type="text"],
.email-settings-embed input[type="email"],
.email-settings-embed input[type="number"],
.email-settings-embed textarea,
.email-settings-embed select {
  font-family: inherit;
  font-size: 14px;
  padding: 7px 10px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  box-sizing: border-box;
}
.email-settings-embed .large-text {
  width: 100%;
}
.email-settings-embed .small-text {
  width: 90px;
}
.email-settings-embed .description {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin: 4px 0 0;
}
/* The7 (and Hello Elementor on Coldtowne — CLAUDE.md convention 33) style
   bare form controls at real specificity and can repaint typed/pre-filled
   text a mid-grey that reads as placeholder text. Out-specify with the
   established `#shows-dashboard .<panel-class>` idiom (same fix already
   applied to `.settings-input` above) rather than !important. */
#shows-dashboard .email-settings-embed input[type="text"],
#shows-dashboard .email-settings-embed input[type="email"],
#shows-dashboard .email-settings-embed input[type="number"],
#shows-dashboard .email-settings-embed textarea,
#shows-dashboard .email-settings-embed select {
  color: var(--ucb-gray-900);
  background-color: #fff;
}
#shows-dashboard .email-settings-embed input::placeholder,
#shows-dashboard .email-settings-embed textarea::placeholder {
  color: var(--ucb-gray-500);
  opacity: 1;
}

/* WP-admin's .button / .button-primary — same treatment as .reports-embed
   above (button.button / button.button-primary), brought into the
   dashboard's brand palette since wp-admin's own button CSS isn't loaded. */
.email-settings-embed button.button,
.email-settings-embed input.button,
.email-settings-embed button.button-primary,
.email-settings-embed input.button-primary {
  background: var(--ucb-gray-100);
  color: var(--ucb-gray-800);
  border: 1px solid var(--ucb-border-strong);
  padding: 8px 16px;
  border-radius: var(--ucb-radius-sm);
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--ucb-transition), color var(--ucb-transition);
  box-shadow: none;
}
.email-settings-embed button.button:hover,
.email-settings-embed input.button:hover {
  background: var(--ucb-gray-200);
}
.email-settings-embed button.button-primary,
.email-settings-embed input.button-primary {
  background: var(--ucb-brand);
  color: #fff;
  border-color: var(--ucb-brand);
}
.email-settings-embed button.button-primary:hover,
.email-settings-embed input.button-primary:hover {
  background: var(--ucb-brand-dark);
  color: #fff;
}

/* Sortable placeholder (jquery-ui-sortable, used by the venue-email lists) */
.email-settings-embed .ucb-item-placeholder {
  border: 2px dashed var(--ucb-gray-300);
  border-radius: var(--ucb-radius-sm);
  margin-bottom: 10px;
  height: 48px;
}

/* dashicons drag-handle / toggle glyphs — dashicons is a wp-admin-only
   style by default; Shows_Dashboard::enqueue_assets() enqueues it
   explicitly for show_admin so these render instead of showing as tofu
   boxes/blank glyphs. */
.email-settings-embed .dashicons {
  font-size: 18px;
  width: 18px;
  height: 18px;
  line-height: 1;
}

/* ── Regions editor table ──────────────────────────────────── */
.regions-table {
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  overflow: hidden;
  margin-bottom: 16px;
}
.regions-row {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(180px, 2fr) 40px;
  gap: 12px;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--ucb-gray-200);
}
.regions-row:last-child {
  border-bottom: none;
}
.regions-row--header {
  background: var(--ucb-gray-50);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-500);
}
.regions-cell {
  min-width: 0;
}
.regions-cell--actions {
  text-align: right;
}
.regions-slug-display {
  display: inline-block;
  background: var(--ucb-gray-100);
  padding: 5px 8px;
  border-radius: 4px;
  font-size: 13px;
  color: var(--ucb-gray-800);
}
.regions-remove {
  background: none;
  border: none;
  color: var(--ucb-gray-500);
  font-size: 20px;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
  border-radius: 4px;
  transition: color var(--ucb-transition), background var(--ucb-transition);
}
.regions-remove:hover {
  color: var(--ucb-red-dark);
  background: rgba(239, 68, 68, 0.08);
}

.regions-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* ── Settings → Check-In sub-tab ───────────────────────────────── */
.settings-checkin-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.settings-checkin-group {
  border: 1px solid var(--ucb-gray-200);
  border-radius: 6px;
  padding: 14px 18px 18px;
  margin: 0;
}
.settings-checkin-group[disabled] {
  opacity: 0.75;
}
.settings-checkin-legend {
  font-weight: 600;
  font-size: 14px;
  padding: 0 6px;
  color: var(--ucb-gray-900);
}
.settings-checkin-help {
  color: var(--ucb-gray-700);
  font-size: 13px;
  margin: 4px 0 12px;
  max-width: 720px;
  line-height: 1.5;
}
.settings-checkin-help code {
  background: var(--ucb-gray-100);
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 12px;
}
.settings-checkin-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-weight: 500;
  user-select: none;
}
.settings-checkin-toggle input[type="checkbox"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
}
.settings-checkin-hint {
  color: var(--ucb-gray-600);
  font-size: 12px;
  margin: 6px 0 0;
}
.settings-checkin-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: flex-end;
}
/* The dashboard's global `.btn { width: 100% }` makes the Save button stretch
   and offset inside this flex row (leaving a gap on its left). Keep it
   auto-width and right-aligned, with the status text pushed to the left. */
.settings-checkin-actions .btn {
  width: auto;
}
.settings-checkin-actions .settings-admin-status,
.settings-checkin-actions .settings-checkin-status {
  margin-right: auto;
}
.settings-checkin-status {
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.settings-checkin-status.is-saved {
  color: var(--ucb-green-dark);
}
.settings-checkin-status.is-error {
  color: var(--ucb-red-dark);
}
/* Admin-only Settings panels (Recap Emails / Access & Alerts) */
.settings-subheading {
  font-size: 14px;
  font-weight: 700;
  color: var(--ucb-gray-900);
  margin: 22px 0 6px;
}
.settings-subheading-note {
  font-weight: 400;
  color: var(--ucb-gray-500);
  font-size: 13px;
}
.settings-repeater {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 10px;
}
.settings-repeater-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.settings-repeater-input {
  flex: 1 1 140px;
  min-width: 0;
}
.settings-repeater-remove {
  flex: 0 0 auto;
  line-height: 1;
  padding: 6px 12px;
}
.settings-field-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.settings-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 240px;
  margin-bottom: 8px;
}
.settings-field-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ucb-gray-700);
}
.settings-admin-status {
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.settings-admin-status.is-saved { color: var(--ucb-green-dark); }
.settings-admin-status.is-error { color: var(--ucb-red-dark); }
.regions-save-status {
  margin-left: auto;
  font-size: 13px;
  color: var(--ucb-green-dark);
}
.regions-save-status--error {
  color: var(--ucb-red-dark);
}

/* When the table is read-only (no edit caps), drop the actions column */
.settings-regions-list[data-can-edit="0"] .regions-row {
  grid-template-columns: minmax(140px, 1fr) minmax(180px, 2fr);
}

/* Rooms textarea row attached under each region */
.regions-row--rooms {
  background: var(--ucb-gray-50);
  border-bottom: 1px solid var(--ucb-gray-200);
  align-items: start;
  padding: 8px 14px 10px;
}
.regions-rooms-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ucb-gray-600);
}
.regions-rooms-hint {
  display: block;
  font-size: 11px;
  color: var(--ucb-gray-500);
  margin-top: 2px;
}
.regions-rooms-textarea {
  width: 100%;
  font-family: inherit;
  font-size: 13px;
  resize: vertical;
}
.regions-rooms-ro {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 13px;
  color: var(--ucb-gray-800);
}
.regions-rooms-ro li {
  padding: 2px 0;
}

/* ── Schedule tab ──────────────────────────────────────────── */
.ucb-schedule {
  width: 100%;
}
.schedule-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
  padding: 12px 14px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
}
.schedule-control {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.schedule-control-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ucb-gray-500);
}
.schedule-control-input {
  padding: 7px 10px;
  font-size: 14px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  background: white;
  color: var(--ucb-gray-900);
  font-family: inherit;
}
.schedule-save-status {
  margin-left: auto;
  font-size: 13px;
  color: var(--ucb-green-dark);
  align-self: center;
}
.schedule-save-status--error { color: var(--ucb-red-dark); }
.schedule-empty-note {
  color: var(--ucb-gray-500);
  font-style: italic;
}

/* Two-column today/tomorrow grid */
.schedule-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-bottom: 24px;
}
@media (max-width: 900px) {
  .schedule-grid { grid-template-columns: 1fr; }
}

/* Bottom row: Today's Shows + My Shifts side by side, but full-width while
   the My Shifts panel is hidden (PIN staff, or user not roster-linked). */
.schedule-grid--bottom {
  grid-template-columns: 1fr;
}
.schedule-grid--bottom:has(.schedule-myshifts-panel:not([hidden])) {
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 900px) {
  .schedule-grid--bottom:has(.schedule-myshifts-panel:not([hidden])) {
    grid-template-columns: 1fr;
  }
}
.schedule-panel,
.schedule-shows-panel {
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius);
  overflow: hidden;
}
.schedule-panel--tomorrow {
  background: var(--ucb-gray-50);
}
.schedule-panel-header,
.schedule-shows-panel .schedule-panel-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--ucb-gray-200);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  background: linear-gradient(180deg, var(--ucb-gray-50) 0%, white 100%);
}
.schedule-panel--tomorrow .schedule-panel-header {
  background: linear-gradient(180deg, var(--ucb-gray-100) 0%, var(--ucb-gray-50) 100%);
}
.schedule-panel-title {
  margin: 0;
  font-size: 18px;
  color: var(--ucb-gray-900);
  text-transform: uppercase;
  letter-spacing: 1px;
}
.schedule-panel-subtitle {
  font-size: 13px;
  color: var(--ucb-gray-500);
}
.schedule-panel-body {
  padding: 14px 18px 18px;
}
.schedule-empty {
  color: var(--ucb-gray-500);
  font-style: italic;
  margin: 8px 0;
}
.schedule-empty--error { color: var(--ucb-red-dark); }

/* Section heading inside a panel */
.schedule-section {
  margin-bottom: 18px;
}
.schedule-section-heading {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-brand);
  margin: 0 0 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--ucb-gray-200);
}

/* Read-only lists (Tomorrow + PIN-staff Today) */
.schedule-ro-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
}
.schedule-ro-list li {
  padding: 4px 0;
  color: var(--ucb-gray-800);
  border-bottom: 1px dashed var(--ucb-gray-100);
}
.schedule-ro-list li:last-child { border-bottom: none; }
.schedule-ro-list em {
  color: var(--ucb-gray-500);
  font-style: normal;
  font-size: 12px;
}
.schedule-notes {
  margin: 0;
  font-size: 14px;
  color: var(--ucb-gray-800);
  white-space: pre-wrap;
}

/* Edit mode — call rows */
.schedule-call-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 8px;
}
/* Flex-wrap layout so the row adapts to the half-width Today panel without
   getting clipped on the right. Each input has a sensible min-width and
   can grow into available space. */
.schedule-call-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.schedule-input--staff   { flex: 1 1 200px; min-width: 180px; }
.schedule-input--name    { flex: 1 1 140px; min-width: 120px; }
.schedule-input--time    { flex: 0 0 110px; width: 110px; }
.schedule-input--suffix  { flex: 1 1 130px; min-width: 110px; }
.schedule-call-row .schedule-remove-btn { flex: 0 0 28px; margin-left: auto; }

.schedule-room-entry {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}
.schedule-input--title { flex: 1 1 180px; min-width: 140px; }
.schedule-room-entry .schedule-remove-btn { flex: 0 0 28px; margin-left: auto; }
.schedule-input {
  padding: 6px 8px;
  font-size: 13px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: 4px;
  background: white;
  color: var(--ucb-gray-900);
  font-family: inherit;
  min-width: 0;
}
.schedule-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 2px rgba(139, 32, 37, 0.1);
}
.schedule-input--time { width: 100%; }
#shows-dashboard .ucb-schedule input.schedule-input,
#shows-dashboard .ucb-schedule textarea.schedule-notes-input,
#shows-dashboard .ucb-schedule select.schedule-input {
  color: var(--ucb-gray-900);
  background-color: white;
}

/* Room block */
.schedule-room {
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 10px 12px;
  margin-bottom: 12px;
}
.schedule-room .schedule-section-heading {
  display: none; /* The label input is the heading */
}
.schedule-room-header {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}
.schedule-input--room-label {
  flex: 1;
  font-weight: 700;
  font-size: 14px;
  color: var(--ucb-gray-900);
}
.schedule-add-call,
.schedule-add-room-wrap {
  margin-top: 4px;
}
.schedule-add-room-wrap {
  margin-bottom: 16px;
}
.schedule-remove-btn {
  background: none;
  border: none;
  color: var(--ucb-gray-500);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 4px;
}
.schedule-remove-btn:hover {
  color: var(--ucb-red-dark);
  background: rgba(239, 68, 68, 0.08);
}

.schedule-notes-input {
  width: 100%;
  padding: 8px 10px;
  font-size: 14px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  background: white;
  color: var(--ucb-gray-900);
  font-family: inherit;
  resize: vertical;
}

.schedule-save-bar {
  padding-top: 14px;
  border-top: 1px solid var(--ucb-gray-200);
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* Read-only top bar with the "Edit Schedule" button. Sits above the
   schedule content so managers can drop into edit mode from a blank-slate
   day too. */
.schedule-edit-bar {
  display: flex;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
}

/* Auto-derived class-session rows (Arlo seam) — display-only. */
.schedule-class-badge {
  display: inline-block;
  padding: 0 6px;
  border-radius: 9px;
  font-size: 11px;
  line-height: 18px;
  background: var(--ucb-gray-100, #f1f5f9);
  color: var(--ucb-gray-500, #64748b);
  border: 1px solid var(--ucb-gray-300, #cbd5e1);
  vertical-align: 1px;
}
.schedule-class-ro {
  padding: 4px 2px;
  font-size: 13px;
  color: var(--ucb-gray-500, #64748b);
}

/* Class Rooms (Arlo room map) editor — Settings sub-tab. */
.settings-classrooms-table {
  width: 100%;
  border-collapse: collapse;
  margin: 10px 0;
}
.settings-classrooms-table th {
  text-align: left;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ucb-gray-500, #64748b);
  padding: 6px 8px 6px 0;
  border-bottom: 1px solid var(--ucb-gray-200, #e2e8f0);
}
.settings-classrooms-table td {
  padding: 6px 8px 6px 0;
  border-bottom: 1px solid var(--ucb-gray-100, #f1f5f9);
  vertical-align: middle;
}
.settings-classrooms-table .setup-input {
  width: 100%;
  min-width: 110px;
  box-sizing: border-box;
}
/* Venues (street addresses published in event listings) — Settings sub-tab.
   Scrolls inside .ucb-scroll-x rather than widening the panel; the address
   fields are wide and the table has six columns. */
.settings-venues-table {
  width: 100%;
  border-collapse: collapse;
  margin: 10px 0;
}
.settings-venues-table th {
  text-align: left;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ucb-gray-500, #64748b);
  padding: 6px 8px 6px 0;
  border-bottom: 1px solid var(--ucb-gray-200, #e2e8f0);
  white-space: nowrap;
}
.settings-venues-table td {
  padding: 6px 8px 6px 0;
  border-bottom: 1px solid var(--ucb-gray-100, #f1f5f9);
  vertical-align: middle;
}
.settings-venues-table th[scope="row"] {
  text-transform: none;
  letter-spacing: 0;
  font-size: 13px;
  color: var(--ucb-gray-800, #1e293b);
  padding-right: 14px;
  border-bottom: 1px solid var(--ucb-gray-100, #f1f5f9);
}
.settings-venues-input {
  box-sizing: border-box;
  width: 100%;
  padding: 5px 7px;
  font-size: 13px;
  font-family: inherit;
  border: 1px solid var(--ucb-gray-300, #cbd5e1);
  border-radius: 4px;
  background: #fff;
  color: var(--ucb-gray-800, #1e293b);
}
.settings-venues-input:disabled {
  background: var(--ucb-gray-50, #f8fafc);
  color: var(--ucb-gray-500, #64748b);
  /* Chrome ignores `color` on disabled inputs unless the fill color is set
     explicitly, dimming the text well below readable — the view-only state
     of this table was the "too light" report (2026-08-14). */
  -webkit-text-fill-color: var(--ucb-gray-500, #64748b);
  opacity: 1;
}
/* Seeded addresses render as placeholders; with no explicit rule they fall
   through to the browser/theme default grey, below WCAG 2.1 AA's 4.5:1.
   --ucb-gray-500 (#71717a) on white ≈ 4.8:1 — same AA-enforcing pattern as
   the setup-input placeholder rule. */
.settings-venues-input::placeholder {
  color: var(--ucb-gray-500, #71717a);
  opacity: 1;
}
.settings-venues-input.is-lg { min-width: 190px; }
.settings-venues-input.is-md { min-width: 140px; }
.settings-venues-input.is-sm { min-width: 80px; }
.settings-venues-input.is-xs { min-width: 60px; }
/* "built-in" = the address came from the seeded defaults, not this site's
   saved rows. Editing one saves your version over the seed. */
.settings-venues-seeded {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 9px;
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ucb-gray-500, #64748b);
  background: var(--ucb-gray-100, #f1f5f9);
}

.settings-classrooms-observed {
  margin-bottom: 12px;
}
.settings-classrooms-chip {
  margin: 0 6px 6px 0;
}
.settings-classrooms-status {
  margin-left: auto;
  margin-right: 10px;
  font-size: 13px;
  color: var(--ucb-gray-500, #64748b);
}

/* My Shifts panel: ICS subscribe row. */
.schedule-ics-wrap {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--ucb-gray-200, #e2e8f0);
}
.schedule-ics-hint {
  margin: 0 0 6px;
  font-size: 12px;
  color: var(--ucb-gray-500, #64748b);
}
.schedule-ics-row {
  display: flex;
  gap: 6px;
  align-items: center;
}
.schedule-ics-url {
  flex: 1;
  min-width: 0;
  font-size: 12px;
}

/* "Last saved by … on …" line above the read-only schedule. */
.schedule-saved-meta {
  margin: 0 0 12px;
  font-size: 12px;
  color: var(--ucb-gray-500);
  font-style: italic;
}

/* Shows panel (auto from Tickera) */
.schedule-shows-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
}
.schedule-shows-list li {
  padding: 6px 0;
  border-bottom: 1px dashed var(--ucb-gray-100);
}
.schedule-shows-list li:last-child { border-bottom: none; }
.schedule-show-time {
  display: inline-block;
  min-width: 80px;
  margin-right: 8px;
  color: var(--ucb-gray-900);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.schedule-show-location {
  color: var(--ucb-gray-500);
  font-size: 13px;
}
.schedule-shows-list a {
  color: var(--ucb-brand);
  text-decoration: none;
}
.schedule-shows-list a:hover { text-decoration: underline; }

/* ── Staff Roster ──────────────────────────────────────────── */
.staff-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
}
.staff-filter-search { flex: 1; min-width: 200px; }
.staff-filter-region { width: auto; max-width: 200px; }
.staff-filter-retired {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ucb-gray-700);
  cursor: pointer;
}
.staff-add-btn { margin-left: auto; }

.staff-list {
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  /* No overflow:hidden — it clipped the role-chip .ucb-explain__pop
     tooltips at the list edge. The rounded corners are handled on the
     first/last rows instead so row backgrounds still respect the radius. */
}
.staff-row:first-child {
  border-top-left-radius: var(--ucb-radius-sm);
  border-top-right-radius: var(--ucb-radius-sm);
}
.staff-row:last-child {
  border-bottom-left-radius: var(--ucb-radius-sm);
  border-bottom-right-radius: var(--ucb-radius-sm);
}
.staff-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--ucb-gray-200);
  background: white;
}
.staff-row:last-child { border-bottom: none; }
.staff-row--retired {
  background: var(--ucb-gray-50);
  opacity: 0.85;
}
/* One person, one line. The card used to stack name / meta / chips into three
   rows plus padding, so 50 people were a very tall page of mostly white space —
   and the Table view now owns dense column work, leaving this view free to be
   compact WITHOUT becoming a spreadsheet. Everything wraps to a second line
   only when it genuinely doesn't fit. */
.staff-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
}
.staff-row-name {
  font-weight: 600;
  font-size: 15px;
  color: var(--ucb-gray-900);
}
.staff-row-meta {
  font-size: 12px;
  color: var(--ucb-gray-500);
}
.staff-row-meta a {
  color: var(--ucb-gray-700);
  text-decoration: none;
}
.staff-row-meta a:hover { text-decoration: underline; }
/* ── Roster editor: Sign-in section ──────────────────────────────────
   ONE control answering "how does this person get in?", replacing a
   role-scoped WP-account picker plus a separate email-keyed access panel.
   The card carries the state; the label and the ucbExplain pop carry the
   meaning. State is never colour-only — every variant has its own icon and
   headline text, so it survives greyscale and colour-blindness. */
.staff-signin-card {
  background: #fff;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 12px 14px;
}
.staff-signin-status {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.staff-signin-icon {
  flex: 0 0 auto;
  font-size: 15px;
  line-height: 1.5;
}
.staff-signin-status.is-ok   .staff-signin-icon { color: #2f7d32; }
.staff-signin-status.is-warn .staff-signin-icon { color: #a4281d; }
.staff-signin-body {
  flex: 1 1 auto;
  min-width: 0;
}
.staff-signin-headline {
  font-size: 14px;
  font-weight: 600;
  color: var(--ucb-gray-900);
}
.staff-signin-sub {
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ucb-gray-600);
  overflow-wrap: anywhere;
}
.staff-signin-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}
.staff-signin-actions:empty {
  display: none;
}
.staff-signin-picker {
  margin-top: 10px;
}
/* The7 ships `button.button * { color:#fff }` and .elementor-kit-N button
   lands at (0,1,1), so a .btn on a light panel must declare BOTH colours at a
   doubled class (convention 33) rather than inheriting either theme's idea. */
.staff-signin .staff-signin-btn.staff-signin-btn {
  background: #fff;
  color: var(--ucb-gray-800);
  border: 1px solid var(--ucb-gray-300);
}
.staff-signin .staff-signin-btn.staff-signin-btn:hover:not(:disabled) {
  background: var(--ucb-gray-50);
  color: var(--ucb-gray-900);
  border-color: var(--ucb-gray-400);
}
.staff-signin .staff-signin-btn.staff-signin-btn.is-danger {
  color: #a02020;
  border-color: #e0b4b4;
}
.staff-signin .staff-signin-btn.staff-signin-btn.is-danger:hover:not(:disabled) {
  background: #fdf3f3;
  color: #8a1a1a;
  border-color: #d09090;
}
.staff-signin .staff-signin-btn.staff-signin-btn:disabled {
  opacity: 0.6;
  cursor: default;
}
/* Quiet secondary action ("Change account", "Cancel") — a real <button> for
   keyboard and screen-reader semantics, styled as a link. Doubled class so the
   themes' bare-button background/colour rules can't repaint it. */
.staff-signin .staff-signin-link.staff-signin-link {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  padding: 0 2px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ucb-brand);
  cursor: pointer;
  text-decoration: underline;
}
.staff-signin .staff-signin-link.staff-signin-link:hover {
  background: transparent;
  color: var(--ucb-red-dark);
}
/* Permissions nest INSIDE the linked state — a grant is checked against the
   signed-in user, so it means nothing without a linked account. Previously
   rendered as permanently disabled checkboxes with a note explaining why. */
.staff-signin-perms {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--ucb-gray-200);
}

/* Restricted-field helper text under the Hourly Rate input. */
.staff-form-hint {
  margin: 4px 0 0;
  font-size: 12px;
  line-height: 1.4;
}
.staff-row-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}
.staff-region-chip {
  display: inline-block;
  background: var(--ucb-gray-100);
  color: var(--ucb-gray-700);
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
}
/* WP role chip — the linked account's current role(s), read live through
   the user_id link. Hover (title) shows what the role can do. Tinted
   differently from region chips so the two vocabularies don't blur. */
.staff-role-chip {
  display: inline-block;
  background: rgba(164, 40, 29, 0.08);
  color: var(--ucb-brand);
  border: 1px solid rgba(164, 40, 29, 0.25);
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  cursor: help;
}
/* Sign-in standing chip on a roster row (buildAccessChip). Colour carries
   the state, but never alone — the LABEL says "Sign-in" vs "PIN only" and the
   .ucb-explain pop spells out what to do next, so the meaning survives for a
   colour-blind reader and in the print/greyscale case. */
.staff-access-chip {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  cursor: help;
  border: 1px solid transparent;
}
/* Access through a manager role — not changeable from this page. */
.staff-access-chip.is-senior {
  background: rgba(47, 125, 50, 0.10);
  color: #1f5c22;
  border-color: rgba(47, 125, 50, 0.30);
}
/* A show_crew sign-in — the thing this page grants. */
.staff-access-chip.is-crew {
  background: rgba(43, 108, 176, 0.10);
  color: #1f4e7a;
  border-color: rgba(43, 108, 176, 0.30);
}
/* No sign-in yet: actionable, so it reads as neutral-quiet rather than an
   error. Most of the roster sits here and it is not a problem state. */
.staff-access-chip.is-none,
.staff-access-chip.is-unknown {
  background: var(--ucb-gray-100, #f2f2f5);
  color: var(--ucb-gray-700, #52525b);
  border-color: var(--ucb-gray-300, #d4d4d8);
}

.staff-retired-badge {
  display: inline-block;
  background: var(--ucb-gray-200);
  color: var(--ucb-gray-700);
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-left: 6px;
}
.staff-row-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* Staff form panel (add/edit) */
.staff-form-panel {
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 16px;
  margin-bottom: 16px;
}
.staff-form-heading {
  margin: 0 0 12px;
  font-size: 16px;
  color: var(--ucb-gray-900);
}
/* Three fieldsets — Person / Shifts & pay / Access. Grouping is what makes
   the form legible: it used to be one flat run of a dozen fields in which
   five separate controls all read as "what can this person do". */
.staff-form-group {
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  background: #fff;
  padding: 12px 14px 4px;
  margin: 0 0 14px;
  /* UA default for <fieldset>; reset so the box matches the panel's rhythm. */
  min-inline-size: 0;
}
.staff-form-legend {
  padding: 0 6px;
  margin-left: -6px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ucb-gray-700);
}
/* Two columns on desktop so short paired inputs (first/last name, shift
   role/hourly rate) sit side by side. The form was tall enough that every edit
   meant scrolling past most of it; pairing roughly halves it. Wide or
   list-like fields opt out with .is-full (see full() in the JS). */
.staff-form-group-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 14px;
  align-items: start;
}
.staff-form-group-body > .is-full {
  grid-column: 1 / -1;
}
/* Phones: one column. A @media block adds no specificity, so this stays a
   plain override of the rule above rather than fighting it (convention 33). */
@media (max-width: 700px) {
  .staff-form-group-body {
    grid-template-columns: 1fr;
  }
}
.staff-form-group-body > .staff-form-field:last-child {
  margin-bottom: 8px;
}
.staff-form-field {
  margin-bottom: 12px;
}
.staff-form-label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ucb-gray-600);
  margin-bottom: 4px;
}
.staff-region-group {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: 8px;
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
}
.staff-region-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ucb-gray-800);
  cursor: pointer;
}
/* Edit-mode banner. The heading alone did not stop an existing entry being
   retyped as if it were a new one — this states whose record is open and
   offers the way out. */
.staff-edit-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  margin-bottom: 12px;
  background: #fffaf0;
  border: 1px solid var(--ucb-amber-dark);
  border-left-width: 4px;
  border-radius: var(--ucb-radius-sm);
  font-size: 13px;
  color: var(--ucb-gray-800);
}
.staff-edit-banner-link {
  background: none;
  border: 0;
  padding: 0;
  color: var(--ucb-brand);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
}

/* Duplicate prompt: the existing (retired) entry, with reactivating as the
   action that actually preserves their history. */
.staff-dupe-match {
  padding: 10px 12px;
  margin-bottom: 8px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  text-align: left;
}
.staff-dupe-name {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 2px;
}
.staff-dupe-match .settings-stub {
  margin: 0 0 8px;
}

/* ── Roster: view switcher, compact table, rates grid ──────────
   (SCOPE-staff-roles-and-rates.md §5) */
.staff-view-switch {
  display: inline-flex;
  gap: 4px;
  margin-left: auto;
}
.staff-bulk-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 10px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  font-size: 13px;
}
/* An author `display` defeats the [hidden] attribute (convention 33) — without
   this the "empty" bar painted as a grey strip above the table. */
.staff-bulk-bar[hidden] {
  display: none;
}
.staff-bulk-count {
  font-weight: 700;
}
.staff-bulk-danger {
  color: var(--ucb-red-dark);
  border-color: var(--ucb-red-dark);
}
/* The roster grid takes the full CONTAINER, the same way the Reports tab does
   (#content-reports drops its max-width, above) — not a viewport breakout.

   It used to be `width: min(96vw, 1800px)` with a negative margin, which is a
   different width on each of the two sites this plugin serves and can overhang
   the wrapper: The7 gives the dashboard ~1620px inside an 1888px window, while
   ColdTowne's Elementor kit caps its wrapper at 1080px no matter how wide the
   window is (docs/theme-compat.md). A vw number can't mean the same thing on
   both. Lifting the ancestor's 1200px cap does — it is as wide as the page
   actually has, on either theme, with no arithmetic.

   The whole PANEL widens (card, heading, filter bar and grid together):
   breaking out only the grid left it hanging off the bottom of a 1200px card,
   which reads as a layout bug rather than a wide view. */
/* No rule here sets the width — sizeRosterCard() in
   shows-dashboard-settings.js measures the dashboard root and writes `width`
   and `margin-left` inline, re-measuring under a ResizeObserver. The class is
   the marker the sizer and the sticky code look for. */
.staff-card-wide {
  max-width: none;
}
/* Both grids scroll inside their OWN box — vertically as well as
   horizontally, which is what makes the sticky header stick: position:sticky
   resolves against the nearest scrolling ancestor, so a container that only
   scrolls sideways would leave the header pinned to nothing while the page
   moved underneath it. CSS gives no way to have one and not the other:
   `overflow-x: auto` computes `overflow-y` to `auto` as well, so a box that
   scrolls sideways is a vertical scrollport whether you wanted one or not —
   which is why the height cap is load-bearing here rather than decorative.

   THE CAP LIFTS WHEN THE GRID FITS. syncRosterSticky()/applyRosterSticky()
   (shows-dashboard-settings.js) measure the table against its box on every
   render, resize and scroll frame,
   and when nothing overflows sideways there is nothing left for the box to
   scroll: `.is-page-sticky` hands scrolling back to the PAGE, and the header
   sticks to the viewport instead — the whole roster in one column, no inner
   scrollbar. The offset it sticks at is --ucb-roster-sticky-top, measured
   from whatever fixed/sticky site chrome is pinned above it (admin bar,
   theme header), because `top: 0` alone would slide the header under it. */
.staff-table-wrap,
.staff-rates-scroll {
  overflow: auto;
  max-height: 70vh;
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
}
.staff-table-wrap.is-page-sticky,
.staff-rates-scroll.is-page-sticky {
  overflow: visible;
  max-height: none;
}
.staff-table thead th,
.staff-rates-table thead tr:first-child th {
  position: sticky;
  top: var(--ucb-roster-sticky-top, 0px);
  /* Above the Standard row, deliberately: the two offsets are floored to
     whole pixels, so they meet with a sub-pixel OVERLAP rather than a gap,
     and the header has to be the one that paints over it. */
  z-index: 5;
  background: var(--ucb-gray-50);
}
/* The rate card row sits directly under the column heads and sticks with
   them — it is the reference every cell below is read against.

   Its offset is the MEASURED height of the header row: applyRosterSticky()
   in shows-dashboard-settings.js stamps --ucb-rates-head-h on the table and
   re-measures whenever that row resizes (a column label wraps at narrow
   widths and the row grows). The hardcoded 34px it replaced was taller than
   the row it was standing in for (11px caps + 6px padding), and body rows
   scrolled through the band between the two sticky rows — most visibly the
   frozen name column, which read as staff names bleeding through the
   header. */
.staff-rates-table thead tr.staff-rates-standard-row th {
  position: sticky;
  top: calc(var(--ucb-roster-sticky-top, 0px) + var(--ucb-rates-head-h, 34px));
  z-index: 3;
  background: white;
  border-bottom: 2px solid var(--ucb-gray-200);
}
/* Names stay put while the roles scroll sideways — a rate in an unlabelled
   row is unreadable. */
.staff-rates-table th:first-child,
.staff-rates-table td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background: white;
}
.staff-rates-table thead tr:first-child th:first-child {
  z-index: 6;
  background: var(--ucb-gray-50);
}
.staff-rates-table thead tr.staff-rates-standard-row th:first-child {
  z-index: 4;
}
.staff-rates-standard-label {
  white-space: nowrap;
  font-weight: 700;
}
.staff-rates-standard-cell {
  white-space: nowrap;
}
.staff-standard-cell {
  width: 74px;
}
/* A derived standard is what people happen to be paid, not the rate card —
   it reads as a suggestion until someone types one. */
.staff-standard-cell.is-suggested {
  color: var(--ucb-gray-600);
  font-style: italic;
  border-style: dashed;
}
.staff-standard-fill {
  background: none;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  margin-left: 4px;
  padding: 1px 5px;
  cursor: pointer;
  font-size: 12px;
  line-height: 1.4;
}
.staff-standard-fill:hover {
  background: var(--ucb-gray-50);
}
.staff-table,
.staff-rates-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 13px;
}
.staff-table th,
.staff-table td,
.staff-rates-table th,
.staff-rates-table td {
  padding: 6px 10px;
  text-align: left;
  border-bottom: 1px solid var(--ucb-gray-100);
  vertical-align: middle;
}
.staff-table thead th,
.staff-rates-table thead th {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ucb-gray-600);
  white-space: nowrap;
}
.staff-table tbody tr:hover {
  background: var(--ucb-gray-50);
}
/* The grid carries the whole record now, so it is wide enough to scroll on any
   screen — which makes the name useless the moment you scroll to Notes. The
   leading two columns (the tick box and Last name) pin left so you always know
   whose row you are editing.

   Both must be sticky and in order: a sticky column that isn't the leading one
   scrolls UNDER its neighbours. The tick box therefore gets a fixed width so
   the name's offset is a known number rather than a measurement.

   ⚠ `.staff-table td` sets no background, and a transparent sticky cell shows
   the scrolling content sliding beneath it. The row's own background has to be
   restated here, hover included. */
.staff-table th:nth-child(1),
.staff-table td:nth-child(1) {
  position: sticky;
  left: 0;
  width: 34px;
  /* Explicit, not inherited: the 34px offset on the next column is only
     correct if this cell's 10px side padding is INSIDE that width. Both themes
     happen to set a global border-box reset today (measured: 33px rendered),
     so this states the dependency rather than trusting it. */
  box-sizing: border-box;
  z-index: 3;
  background: white;
}
.staff-table th:nth-child(2),
.staff-table td:nth-child(2) {
  position: sticky;
  left: 34px;
  z-index: 3;
  background: white;
  white-space: nowrap;
}
.staff-table thead th:nth-child(1),
.staff-table thead th:nth-child(2) {
  /* Corner cells are sticky in BOTH directions, so they have to paint over
     the sticky header row as well as the sticky column. */
  z-index: 6;
  background: var(--ucb-gray-50);
}
.staff-table tbody tr:hover td:nth-child(1),
.staff-table tbody tr:hover td:nth-child(2) {
  background: var(--ucb-gray-50);
}
.staff-table tr.staff-row--retired td {
  opacity: 0.6;
}
/* An inline-editable cell has to LOOK editable — a plain text cell that
   happens to respond to a click is a feature nobody finds. */
.staff-cell {
  cursor: text;
}
.staff-cell:not(.is-editing) .staff-cell-value {
  border-bottom: 1px dotted var(--ucb-gray-400);
}
.staff-cell:not(.is-editing):hover .staff-cell-value::after,
.staff-cell:not(.is-editing):focus .staff-cell-value::after {
  content: ' ✎';
  color: var(--ucb-gray-600);
}
.staff-cell:not(.is-editing):hover {
  background: var(--ucb-gray-50);
}
.staff-cell-value.is-empty {
  color: var(--ucb-gray-600);
}
.staff-cell.is-editing {
  background: var(--ucb-gray-50);
  white-space: nowrap;
}
.staff-cell.is-saving {
  opacity: 0.6;
}
.staff-cell-input {
  width: 160px;
  padding: 2px 6px;
  font-size: 13px;
  display: inline-block;
}
.staff-cell-regions {
  display: inline-flex;
  gap: 10px;
  align-items: center;
}
.staff-cell-actions {
  margin-left: 6px;
  white-space: nowrap;
}
.staff-cell-btn {
  background: none;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 1px 6px;
  cursor: pointer;
  font-size: 12px;
  line-height: 1.4;
}
.staff-roles-link {
  background: none;
  border: 0;
  padding: 0;
  color: var(--ucb-brand);
  cursor: pointer;
  font: inherit;
  text-align: left;
}
/* Roles cell: role names carry their rate in parentheses. The rate is only in
   the payload at all for someone holding view_pay (Staff_Role_Rates::
   shape_for_wire), so there is nothing to hide with CSS — this is layout. */
.staff-roles-link.is-empty {
  color: var(--ucb-gray-600);
}
.staff-cell-roles,
.staff-cell-signin,
.staff-cell-checklist {
  white-space: nowrap;
}
/* "Notified about time entries +2" is longer than the column deserves; clip it
   rather than letting one long flag label set the column's width. */
.staff-cell-checklist .staff-roles-link {
  display: inline-block;
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}

/* Notifications / Permissions dialog. One checkbox per line: these labels are
   sentences ("Notified about meal waivers"), and wrapping them into columns
   put the tick box a long way from the words it governs. */
.staff-checklist-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 0;
  line-height: 1.35;
  cursor: pointer;
}
.staff-checklist-row input {
  margin-top: 2px;
  flex: 0 0 auto;
}
.staff-checklist .settings-stub {
  margin-top: 12px;
}

/* Sign-in cell: the verb, then the chip that explains the state. The button is
   the action; the chip stays a chip (cursor:help, hover explainer). */
.staff-signin-cell-btn {
  background: none;
  border: 0;
  padding: 0;
  color: var(--ucb-brand);
  cursor: pointer;
  font: inherit;
  text-align: left;
}
/* Nothing to do until an email exists — say so quietly rather than offering a
   verb that would fail. */
.staff-signin-cell-btn.is-unlinked,
.staff-signin-cell-btn.is-senior,
.staff-signin-cell-btn.is-has_access {
  color: var(--ucb-gray-700);
  cursor: pointer;
}
.staff-access-chip--inline {
  margin-left: 6px;
}

/* Status pill. --ucb-gray-400 is a FILL/border token (2.5-3.8:1) and never a
   text colour — the label reads from the -dark tier (convention 46). */
.staff-status-btn.is-inactive {
  color: var(--ucb-gray-700);
  border-color: var(--ucb-gray-300);
}

/* Notes cell — one line in the grid, the rest in the title. Without a cap the
   row grows to the height of somebody's paragraph and the whole grid jumps. */
.staff-table td.staff-cell--multiline .staff-cell-value {
  display: inline-block;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
.staff-cell-textarea {
  width: 280px;
  min-height: 60px;
}

/* Quick add — two columns on anything but a phone, and the wide fields
   (regions, sign-in) span both. */
.staff-quickadd {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 16px;
}
.staff-quickadd .staff-quickadd-full {
  grid-column: 1 / -1;
}
@media (max-width: 640px) {
  .staff-quickadd {
    grid-template-columns: minmax(0, 1fr);
  }
}
.staff-signin-dialog .staff-signin-status {
  margin: 0 0 12px;
}
.staff-signin-dialog .staff-signin-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.staff-rates-head {
  margin-bottom: 10px;
}
.staff-rates-standard {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ucb-gray-600);
}
.staff-rates-name {
  white-space: nowrap;
  font-weight: 600;
}
.staff-rate-cell {
  width: 92px;
  padding: 2px 6px;
  font-size: 13px;
}
/* Assigned vs not is the grid's one structural distinction, so it carries
   real weight: an assigned cell is a white box you fill in, an unassigned one
   is flat and grey — typing there ADDS the role, which should feel like a
   decision rather than a correction. */
.staff-rates-table td.is-assigned .staff-rate-cell {
  border-color: var(--ucb-border-strong);
  background: white;
}
.staff-rates-table td:not(.is-assigned) .staff-rate-cell {
  border-color: transparent;
  background: var(--ucb-gray-50);
  color: var(--ucb-gray-600);
}
.staff-rates-table td:not(.is-assigned) .staff-rate-cell:hover,
.staff-rates-table td:not(.is-assigned) .staff-rate-cell:focus {
  border-color: var(--ucb-gray-200);
  background: white;
}
.staff-rate-cell.is-off-standard {
  border-color: var(--ucb-amber-dark);
  background: #fffaf0;
  /* An amber border alone is invisible in a wall of bordered inputs — the
     inset bar is what makes an off-standard rate findable by scanning. */
  box-shadow: inset 3px 0 0 var(--ucb-amber-dark);
}
.staff-rate-cell.is-saving {
  opacity: 0.5;
}
/* Shift-role matrix — roles down, the person's regions across. Scrolls inside
   its own container so a two-region grid never widens the form. */
.staff-roles-matrix-host {
  overflow-x: auto;
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 8px;
}
.staff-roles-matrix {
  border-collapse: collapse;
  width: 100%;
  font-size: 13px;
}
.staff-roles-matrix th,
.staff-roles-matrix td {
  padding: 4px 8px;
  text-align: left;
  border-bottom: 1px solid var(--ucb-gray-100);
  white-space: nowrap;
}
.staff-roles-matrix thead th {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ucb-gray-600);
}
.staff-roles-matrix tbody th {
  font-weight: 600;
  color: var(--ucb-gray-800);
}
.staff-roles-primary-col {
  text-align: center;
}
.staff-roles-rate {
  width: 84px;
  margin-left: 6px;
  padding: 2px 6px;
  font-size: 13px;
}
/* An author `display` defeats [hidden] (convention 33) — .settings-input may
   set one, so the attribute needs saying explicitly. */
.staff-roles-rate[hidden] {
  display: none;
}
/* A prefilled standard is a SUGGESTION until someone edits it, and it has to
   look like one — a confident number nobody typed is how a wrong rate ships. */
.staff-roles-rate.is-suggested {
  color: var(--ucb-gray-600);
  font-style: italic;
  border-style: dashed;
}
.staff-form-error {
  color: var(--ucb-red-dark);
  font-size: 13px;
  margin-bottom: 8px;
}
.staff-form-actions {
  display: flex;
  gap: 8px;
}

/* ── 6. Tab Panels ─────────────────────────────────────────── */
.tab-content {
  display: none;
  max-width: 1200px;
  margin: 0 auto;
  padding: 30px 30px 40px;
}
.tab-content.active {
  display: block;
}
[role="tabpanel"][hidden] {
  display: none;
}

/* ── 7. Stats Strip ────────────────────────────────────────── */
.stats-strip {
  margin: 0 0 14px;
  padding: 0;
  position: relative;
  z-index: 2;
}
.stats-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  box-shadow: var(--ucb-shadow-sm);
  overflow: hidden;
}
.stat-card {
  background: transparent;
  padding: 16px 20px;
  border-right: 1px solid var(--ucb-gray-100);
  text-align: left;
}
.stat-card:last-child {
  border-right: none;
}
/* Recoupment KPI whose figure was read out of free text that isn't a bare
   amount — the number shown is a guess, so the card says so rather than
   presenting it as fact. See Keyed_Amount / convention 21. */
.stat-card--warn {
  background: rgba(217, 119, 6, 0.08);
  box-shadow: inset 3px 0 0 var(--ucb-amber);
}
.final-recoup-flag {
  color: var(--ucb-amber-dark);
  font-weight: 700;
  cursor: help;
}
/* Full-width explainer directly under the Recoupment row in the profit
   table. Amber, not red: the show data is fine, the keyed value is not. */
.final-recoup-warn-detail td {
  background: rgba(217, 119, 6, 0.08);
  border-left: 3px solid var(--ucb-amber);
  color: #78350f;
  font-size: 12px;
  line-height: 1.5;
  padding: 8px 12px;
}
.final-recoup-warn-detail strong {
  color: var(--ucb-amber-dark);
}

/* Recoupment in the profit table is a control, not output — it needs to LOOK
   editable or people go to wp-admin to change it (which is what happened).
   Dotted underline + a pencil that firms up on hover. */
.final-recoup-edit {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 1px 2px;
  border: 0;
  background: none;
  color: var(--ucb-amber-dark);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  border-bottom: 1px dashed var(--ucb-amber);
}
.final-recoup-edit.is-empty {
  color: var(--ucb-gray-500);
  font-weight: 400;
}
.final-recoup-edit:hover,
.final-recoup-edit:focus-visible {
  border-bottom-style: solid;
  background: rgba(217, 119, 6, 0.08);
  border-radius: 3px;
}
.final-recoup-pencil {
  font-size: 11px;
  opacity: .65;
}
.final-recoup-edit:hover .final-recoup-pencil {
  opacity: 1;
}
/* Momentary highlight when the profit-table figure sends focus down here, so
   the eye lands on the right box after the scroll. */
.ucb-field-targeted {
  box-shadow: 0 0 0 3px rgba(217, 119, 6, .35);
  transition: box-shadow .2s ease;
}
/* Doubled class to out-specify `.btn`, which sets color:#fff for a dark
   background it never gets inside this amber block — the button rendered as
   white-on-#efefef (invisible). Declare BOTH colors, never just one. */
.final-recoup-warn-detail .final-recoup-fix.final-recoup-fix {
  display: inline-block;
  margin: 6px 0 0;
  padding: 5px 12px;
  background: #fff;
  border: 1px solid var(--ucb-amber);
  border-radius: 4px;
  color: var(--ucb-amber-dark);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  cursor: pointer;
}
.final-recoup-warn-detail .final-recoup-fix.final-recoup-fix:hover,
.final-recoup-warn-detail .final-recoup-fix.final-recoup-fix:focus-visible {
  background: var(--ucb-amber-dark);
  color: #fff;
}
.stat-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--ucb-gray-500);
  margin-bottom: 6px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.stat-value {
  font-size: 30px;
  font-weight: 800;
  line-height: 1;
  color: var(--ucb-gray-900);
}
.stat-sub {
  font-size: 11px;
  color: var(--ucb-gray-500);
  margin-top: 4px;
  font-weight: 500;
}
.stat-value.green { color: var(--ucb-green-dark); }
.stat-value.brand { color: var(--ucb-brand); }
.stat-value.blue { color: var(--ucb-blue-dark); }
.stat-value.amber { color: var(--ucb-amber-dark); }

/* ── 8. Content & Panels ───────────────────────────────────── */
/* Check-in tab uses a unique layout class + flex with `order` so source
   order stays audience-first (a11y) but left column renders first visually.
   !important guards against theme cascade on generic properties. */
#shows-dashboard .checkin-layout {
  display: flex !important;
  flex-direction: row !important;
  align-items: flex-start !important;
  gap: 18px !important;
  width: 100%;
}
#shows-dashboard .checkin-layout > .checkin-layout-left {
  order: -1 !important;
  flex: 0 0 320px !important;
  display: flex !important;
  flex-direction: column !important;
  gap: 18px !important;
  min-width: 0 !important;
  width: 320px !important;
}
#shows-dashboard .checkin-layout > .checkin-layout-left > .panel {
  margin-bottom: 0 !important;
  width: 100% !important;
  display: block !important;
}
#shows-dashboard .checkin-layout > #audience-panel {
  order: 0 !important;
  flex: 1 1 auto !important;
  min-width: 0 !important;
  margin-bottom: 0 !important;
}
.panel {
  background: white;
  border-radius: var(--ucb-radius);
  box-shadow: var(--ucb-shadow-md);
  border: 1px solid var(--ucb-gray-200);
  overflow: hidden;
  margin-bottom: 18px;
}
.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 18px;
  border-bottom: 1px solid var(--ucb-gray-100);
  background: var(--ucb-gray-50);
}

/* Unsaved-changes chip — the dashboard-wide dirty-state convention.
   createDirtyTracker (shows-dashboard.js) stamps .ucb-panel-dirty on the
   .panel a user edited in a form-style tab; the tab's save flow clears it.
   Amber pill in the panel's top-right corner; panels WITH a .panel-header
   drop it just below the header so it never collides with header badges. */
.panel.ucb-panel-dirty,
.recap-section.ucb-panel-dirty {
  position: relative;
}
.panel.ucb-panel-dirty::after,
.recap-section.ucb-panel-dirty::after {
  content: 'Unsaved';
  position: absolute;
  top: 10px;
  right: 12px;
  z-index: 2;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: #92400e;
  background: rgba(245, 158, 11, 0.16);
  border: 1px solid rgba(245, 158, 11, 0.45);
  border-radius: 999px;
  padding: 2px 8px;
  pointer-events: none;
}
.panel.ucb-panel-dirty:has(.panel-header)::after {
  top: 52px;
}
/* A .recap-section always leads with a .recap-section-head, so the chip has to
   clear it or it lands on the section title. */
.recap-section.ucb-panel-dirty::after {
  top: 46px;
}
.panel-title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-600);
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.panel-title .icon {
  font-size: 15px;
}
.panel-badge {
  font-size: 10px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 100px;
  letter-spacing: 0.5px;
}
.panel-badge.count {
  background: var(--ucb-gray-100);
  color: var(--ucb-gray-600);
}
.placeholder-panel {
  padding: 40px 18px;
  text-align: center;
  color: var(--ucb-gray-500);
  font-size: 14px;
}
/* Inline loading placeholder used inside the audience check-in box.
   Matches placeholder-panel's spacing so the swap from loading → list
   doesn't shift the box height. */
.loading-msg {
  margin: 0;
  padding: 36px 18px;
  text-align: center;
  color: var(--ucb-gray-600);
  font-size: 14px;
}
/* The attendee list's non-list states (error, unparseable response). They render
   into the same bordered box as the rows, so a bare <p> sat flush against the
   border with no padding. Matches .loading-msg, which is the same box in its
   fourth state — only the colour differs, so an error doesn't read as progress. */
.audience-msg {
  margin: 0;
  padding: 36px 18px;
  text-align: center;
  color: var(--ucb-gray-600);
  font-size: 14px;
}
.audience-msg.is-error {
  color: var(--ucb-brand);
  font-weight: 600;
}
.ucb-login-required {
  padding: 60px 20px;
  text-align: center;
  color: var(--ucb-gray-500);
  font-size: 15px;
}
.ucb-login-required a {
  color: var(--ucb-brand);
  font-weight: 600;
  text-decoration: underline;
}

/* ── 9. Buttons ────────────────────────────────────────────── */
/* MOVED to assets/css/ucb-button.css (handle `ucb-button`, 2.55.8) — a
   registered dependency of this stylesheet, so it loads FIRST and every
   dashboard rule below still out-ranks it on source order. It was extracted
   because the report shortcodes render OUTSIDE the dashboard, where this file
   isn't enqueued: `.btn` was unreachable there, so each report grew its own
   button class instead. Don't re-add a copy here; edit the shared file. */

/* ── 10. Search Bar ────────────────────────────────────────── */
.search-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--ucb-gray-100);
  background: white;
}
.search-input {
  flex: 1;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  padding: 10px 14px 10px 36px;
  font-size: 14px;
  font-weight: 500;
  color: var(--ucb-gray-900);
  font-family: inherit;
  background: var(--ucb-gray-50) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23a1a1aa' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85zm-5.242.156a5 5 0 1 1 0-10 5 5 0 0 1 0 10z'/%3E%3C/svg%3E") no-repeat 12px center;
}
.search-input::placeholder {
  color: var(--ucb-gray-600);
  opacity: 1;
}
#shows-dashboard input.search-input {
  color: var(--ucb-gray-900);
  /* Re-assert the 36px left padding too — the theme's generic `input`
     rule sometimes wins on padding without this specificity bump,
     which made the search icon overlap the placeholder text. */
  padding-left: 36px;
}
#shows-dashboard input.search-input::placeholder {
  color: var(--ucb-gray-600);
  opacity: 1;
}
.search-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.25);
}

/* ── 11. Audience Tabs (sub-filter) ────────────────────────── */
.audience-tabs {
  padding: 10px 18px;
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--ucb-gray-100);
}
.a-tab {
  padding: 5px 12px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 5px;
  cursor: pointer;
  border: 1px solid var(--ucb-border-strong);
  background: white;
  color: var(--ucb-gray-500);
  font-family: inherit;
  transition: background var(--ucb-transition), color var(--ucb-transition);
}
.a-tab:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 2px;
}
.a-tab.active,
.a-tab[aria-pressed="true"] {
  background: var(--ucb-brand);
  color: white;
  border-color: var(--ucb-brand);
}

/* ── 12. Audience List / Rows ──────────────────────────────── */
.audience-list {
  min-height: 60px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  /* No overflow:hidden — it clipped the .ucb-explain__pop on the student-ID flag
     chips at the list edge, exactly as it did for the role chips on .staff-row.
     The rounded corners are handled on the first/last child instead, so row
     backgrounds still respect the radius. */
  margin: 0 18px 14px;
  background: white;
}
.audience-list > :first-child {
  border-top-left-radius: var(--ucb-radius-sm);
  border-top-right-radius: var(--ucb-radius-sm);
}
.audience-list > :last-child {
  border-bottom-left-radius: var(--ucb-radius-sm);
  border-bottom-right-radius: var(--ucb-radius-sm);
}
/* Unclipping the list alone left only ~32px between a LAST-row popup and the panel
   edge — fine for today's four-line note, one word away from clipping again. So the
   audience panel opts out of .panel's overflow:hidden too, and its first/last
   children take over the corner rounding (both carry a #fafafa fill and square
   corners, so they would otherwise poke out of the panel's 14px radius). Scoped by
   id: every other .panel keeps clipping. */
#audience-panel {
  overflow: visible;
}
#audience-panel > .panel-header {
  border-top-left-radius: var(--ucb-radius);
  border-top-right-radius: var(--ucb-radius);
}
#audience-panel > :last-child {
  border-bottom-left-radius: var(--ucb-radius);
  border-bottom-right-radius: var(--ucb-radius);
}
.audience-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--ucb-gray-100);
  font-size: 13px;
  transition: background var(--ucb-transition);
}
/* Search-as-you-type hides non-matching rows via class toggle instead
   of rebuilding the table on every keystroke. !important so it wins
   against the audience-tabs inline display:'' set on the "All" filter. */
.audience-row.is-hidden-by-search,
.audience-dup-expandwrap.is-hidden-by-search {
  display: none !important;
}
.audience-row:last-child {
  border-bottom: none;
}
.audience-row:hover {
  background: var(--ucb-gray-50);
}
.audience-row.checked-in {
  background-color: rgba(16, 185, 129, 0.06);
}
.audience-row.checked-in:hover {
  background-color: rgba(16, 185, 129, 0.1);
}
.audience-num {
  width: 22px;
  color: var(--ucb-gray-500);
  font-size: 11px;
  font-weight: 600;
  flex-shrink: 0;
  text-align: left;
}
.audience-name {
  flex: 1;
  min-width: 0;
}
.audience-name-full {
  font-weight: 700;
  font-size: 15px;
  color: var(--ucb-gray-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.25;
}
.audience-name-email {
  font-size: 12px;
  color: var(--ucb-gray-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
}
/* Student-ID frequency flag — how many free student tickets this account holds in
   the trailing 7 days, stamped onto ST rows by applyStudentFlags(). Amber-on-cream
   reads as "worth a look" without the red of an error: nothing here is wrong, and
   door walk-ups are unlimited on purpose. */
.audience-name-flag {
  display: inline-block;
  margin-top: 3px;
  padding: 1px 8px 1px 7px;
  border: 1px solid #e6c98a;
  border-radius: 999px;
  background: #fdf6e6;
  color: #7a5a12;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
}
/* Typography inheritance from the pill is handled by .ucb-explain__pop's own reset. */
.audience-name-flag .ucb-explain {
  margin-left: 5px;
}
.audience-name-flag .ucb-explain__trigger {
  border-color: #d9b25f;
  color: #8a6a1c;
}
/* Pill row under the email. Both pills that can appear on an ST row live here —
   provenance (always) and the frequency flag (only above its threshold) — so they
   wrap together instead of stacking two full-width lines on a phone. */
.audience-name-flags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 3px;
}
.audience-name-flags .audience-name-flag {
  margin-top: 0;
}
/* Provenance: how this student ticket came to exist. Colours carry the meaning,
   so the three read apart at a glance on a dim phone at the door.
     Reserved — grey, the unremarkable case (booked online days ago)
     Door     — purple, matching the ST ticket-type pill: normal, just tonight
     Override — brand red, staff deliberately went past the show's student limit.
                Kept distinct from the amber frequency flag, which can appear on
                the SAME row and means something else entirely. */
.audience-name-flag.is-reserved {
  border-color: var(--ucb-gray-200);
  background: var(--ucb-gray-50);
  color: var(--ucb-gray-600);
}
.audience-name-flag.is-reserved .ucb-explain__trigger {
  border-color: var(--ucb-gray-200);
  color: var(--ucb-gray-600);
}
.audience-name-flag.is-door {
  border-color: rgba(139, 92, 246, 0.35);
  background: rgba(139, 92, 246, 0.07);
  color: var(--ucb-purple-dark);
}
.audience-name-flag.is-door .ucb-explain__trigger {
  border-color: rgba(139, 92, 246, 0.45);
  color: var(--ucb-purple-dark);
}
.audience-name-flag.is-override {
  border-color: rgba(139, 32, 37, 0.35);
  background: rgba(139, 32, 37, 0.07);
  color: var(--ucb-brand);
}
.audience-name-flag.is-override .ucb-explain__trigger {
  border-color: rgba(139, 32, 37, 0.45);
  color: var(--ucb-brand);
}
.audience-type {
  font-size: 10px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--ucb-gray-200);
  background: var(--ucb-gray-50);
  color: var(--ucb-gray-600);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  flex-shrink: 0;
  line-height: 1.3;
}
.audience-type.ga { color: var(--ucb-gray-700); }
.audience-type.ad { color: var(--ucb-amber-dark); border-color: rgba(217, 119, 6, 0.25); background: rgba(217, 119, 6, 0.05); }
.audience-type.co { color: var(--ucb-green-dark); border-color: rgba(16, 185, 129, 0.3); background: rgba(16, 185, 129, 0.06); }
.audience-type.st { color: var(--ucb-purple-dark); border-color: rgba(139, 92, 246, 0.25); background: rgba(139, 92, 246, 0.05); }
.audience-type.ls { color: var(--ucb-brand); border-color: rgba(139, 32, 37, 0.25); background: rgba(139, 32, 37, 0.05); }
.audience-time {
  font-size: 12px;
  font-weight: 600;
  color: var(--ucb-green-dark);
  flex-shrink: 0;
  min-width: 38px;
  white-space: nowrap;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ── 12a. Check-in circle toggle ──────────────────────────── */
.checkin-btn {
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  padding: 0;
  margin: 0;
  background: white;
  /* border-strong, not gray-300: this is a clickable toggle and needs a 3:1
     boundary (gray-300 was only 1.48:1 — WCAG audit 2026-07). */
  border: 2px solid var(--ucb-border-strong);
  cursor: pointer;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--ucb-transition), border-color var(--ucb-transition);
  font-family: inherit;
  -webkit-tap-highlight-color: transparent;
}
.checkin-btn:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 2px;
}
.checkin-btn .checkin-icon {
  display: block;
  width: 18px;
  height: 18px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

/* Not arrived — hollow circle with faint plus, hover turns solid green with plus */
.checkin-btn.do {
  background: white;
  border-color: var(--ucb-border-strong);
}
.checkin-btn.do .checkin-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23d4d4d8' d='M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z'/%3E%3C/svg%3E");
}
.checkin-btn.do:hover,
.checkin-btn.do:focus-visible {
  /* green-dark, not green: the white plus icon needs 3:1 against this fill
     (base green was only 2.54:1 — WCAG audit 2026-07). */
  background: var(--ucb-green-dark);
  border-color: var(--ucb-green-dark);
  box-shadow: 0 2px 6px rgba(16, 185, 129, 0.3);
}
.checkin-btn.do:hover .checkin-icon,
.checkin-btn.do:focus-visible .checkin-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z'/%3E%3C/svg%3E");
}

/* Checked in — solid green with white check, hover turns red with undo arrow */
.checkin-btn.done {
  /* green-dark, not green: the white checkmark icon needs 3:1 against this
     fill (base green was only 2.54:1 — WCAG audit 2026-07). */
  background: var(--ucb-green-dark);
  border-color: var(--ucb-green-dark);
  box-shadow: 0 2px 6px rgba(16, 185, 129, 0.25);
}
.checkin-btn.done .checkin-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z'/%3E%3C/svg%3E");
}
.checkin-btn.done:hover,
.checkin-btn.done:focus-visible {
  background: var(--ucb-red);
  border-color: var(--ucb-red-dark);
  box-shadow: 0 2px 6px rgba(239, 68, 68, 0.3);
}
.checkin-btn.done:hover .checkin-icon,
.checkin-btn.done:focus-visible .checkin-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z'/%3E%3C/svg%3E");
}
.checkin-btn.is-loading {
  cursor: progress;
  pointer-events: none;
}
.checkin-btn.is-loading .checkin-icon {
  visibility: hidden;
}
.checkin-btn.is-loading::after {
  content: "";
  position: absolute;
  /* inset:0 + margin:auto centers the spinner regardless of box-sizing. */
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  width: 16px;
  height: 16px;
  border: 2px solid var(--ucb-gray-300);
  border-top-color: var(--ucb-brand);
  border-radius: 50%;
  animation: ucb-checkin-spin 0.6s linear infinite;
}
@keyframes ucb-checkin-spin {
  to { transform: rotate(360deg); }
}

/* ── 12b. State Legend ─────────────────────────────────────── */
.state-legend {
  padding: 14px 18px 16px;
  border-top: 1px solid var(--ucb-gray-100);
  background: var(--ucb-gray-50);
}
.state-legend-title {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--ucb-gray-500);
  margin-bottom: 10px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.state-legend-items {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 28px;
}
.state-legend-item {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.state-legend-text {
  font-weight: 600;
  color: var(--ucb-gray-800);
}
.state-legend-sub {
  color: var(--ucb-gray-500);
  font-weight: 500;
}
.checkin-icon-demo {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 2px solid var(--ucb-gray-300);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 18px 18px;
}
.checkin-icon-demo.done {
  background-color: var(--ucb-green-dark);
  border-color: var(--ucb-green-dark);
  box-shadow: 0 2px 6px rgba(16, 185, 129, 0.25);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z'/%3E%3C/svg%3E");
}
.checkin-icon-demo.do {
  background-color: white;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23d4d4d8' d='M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z'/%3E%3C/svg%3E");
}

/* ── 12b. Door Guide (check-in help panel) ─────────────────────
   Collapsible explainer under the check-in list: what a non-ticket row
   means, how a partly refunded order is counted, and the one-scan order
   panel. Collapsed by default so it never pushes the live list around.
   ⚠ The [hidden] rule is load-bearing — the body sets `display`, and an
   author display beats the attribute (convention 33). */
.checkin-help {
  margin-top: 18px;
}
.checkin-help .panel-header {
  cursor: default;
}
.checkin-help-body {
  display: block;
  padding: 4px 22px 24px;
  /* Prose caps at ~900px for line length, then CENTRES in the panel — left-
     ragged against a full-width band reads as a layout bug. box-sizing keeps
     the padding inside the cap. */
  max-width: 944px; /* 900 + the 22px padding either side */
  margin-inline: auto;
  box-sizing: border-box;
}
.checkin-help-body[hidden] {
  display: none;
}
/* Contents strip. Buttons, not links (the dashboard owns location.hash) —
   styled as quiet chips so it reads as navigation, not as actions. */
.checkin-help-toc {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 14px 0 4px;
  padding: 12px 14px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-100);
  border-radius: var(--ucb-radius-sm);
}
.checkin-help-toc-label {
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ucb-gray-500);
  margin-right: 4px;
}
.checkin-help-jump {
  appearance: none;
  border: 1px solid var(--ucb-gray-300);
  background: #fff;
  color: var(--ucb-gray-800);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
}
.checkin-help-jump:hover,
.checkin-help-jump:focus-visible {
  border-color: var(--ucb-brand);
  color: var(--ucb-brand);
}
/* Scrolled-to sections take focus for keyboard users; the outline would
   otherwise ring a whole section of prose. */
.checkin-help-section:focus {
  outline: none;
}
.checkin-help-section:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 6px;
}
.checkin-help-lede {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ucb-gray-700);
  margin: 10px 0 4px;
}
.checkin-help-section {
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid var(--ucb-gray-100);
}
.checkin-help-section:first-of-type {
  border-top: 0;
}
.checkin-help-h {
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--ucb-gray-900);
  margin: 0 0 10px;
}
.checkin-help-body p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ucb-gray-700);
  margin: 0 0 12px;
}
.checkin-help-list {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
}
/* The7/Elementor both set a `disc` marker on `li` at a specificity our
   single class loses to (convention 33) — the id out-specifies both, or the
   row renders with the theme's bullet AND our dot. */
#checkin-help .checkin-help-list,
#checkin-help .checkin-help-list li {
  list-style: none;
}
.checkin-help-list li {
  position: relative;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ucb-gray-700);
  padding: 0 0 0 18px;
  margin-bottom: 10px;
}
.checkin-help-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 9px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ucb-gray-300);
}
.checkin-help-badge {
  display: inline-block;
  margin-right: 8px;
  padding: 2px 9px;
  border: 1px solid var(--ucb-red-light);
  border-radius: 999px;
  background: #fdf2f2;
  color: var(--ucb-red-dark);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  vertical-align: 1px;
}
.checkin-help-note {
  padding: 10px 14px;
  border-left: 3px solid var(--ucb-accent);
  background: var(--ucb-gray-50);
  border-radius: 0 var(--ucb-radius-sm) var(--ucb-radius-sm) 0;
}
.checkin-help-fig {
  margin: 4px 0 20px;
}
.checkin-help-fig img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  box-shadow: var(--ucb-shadow-sm);
}
.checkin-help-fig figcaption {
  margin-top: 6px;
  font-size: 12px;
  color: var(--ucb-gray-500);
}
@media (max-width: 640px) {
  .checkin-help-body {
    padding: 4px 14px 20px;
  }
}

/* ── 13. Two-Column Grid ───────────────────────────────────── */
.content-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-top: 18px;
}

/* ── 14. Collapsible Talent Panel ──────────────────────────── */
.collapse-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 18px;
  background: var(--ucb-gray-50);
  border-bottom: 1px solid var(--ucb-gray-100);
  cursor: pointer;
  user-select: none;
}
.collapse-toggle:hover {
  background: var(--ucb-gray-100);
}
.collapse-toggle:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: -2px;
}
.collapse-title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-600);
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.collapse-arrow {
  font-size: 14px;
  color: var(--ucb-gray-500);
  transition: transform 0.2s;
}
.collapse-arrow.open {
  transform: rotate(180deg);
}
.collapse-body {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}
.collapse-body.open {
  max-height: 2000px;
}

/* ── 15. Talent Tab & Rows ─────────────────────────────────── */
.talent-tab-body {
  padding: 18px;
}
.talent-header-actions {
  display: flex;
  gap: 6px;
}
.talents-wrap {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.talent-row {
  background: white;
  box-shadow: var(--ucb-shadow-sm);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  overflow: hidden;
  min-width: 260px;
  max-width: 400px;
}
/* ⚠ The card clips (overflow:hidden above, so the headshot and the full-width
   Save button respect its rounded corners), and both the notes textarea and
   that Save button sit FLUSH against its edges — so the dashboard's global
   2px OUTWARD focus ring was drawn into the clipped region and came back as a
   sliver along one edge. Draw it inward instead: same width, same colour,
   fully visible, card corners intact.
   Needs the #shows-dashboard prefix to out-specify the global rule's (1,0,0)
   ID selector — a bare .talent-row :focus-visible would lose. */
#shows-dashboard .talent-row :focus-visible {
  outline-offset: -2px;
}

.talent-row.is-misc-talent .talent-status {
  opacity: 0;
  visibility: hidden;
}
.talent-row-form {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 0 20px;
  height: 100%;
}
.talent-row-full {
  flex: 1 1 100%;
}
.talent-row-left {
  flex: 0 0 70px;
}
.talent-row-right {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: left;
  padding-right: 10px;
}
.talent-image img {
  aspect-ratio: 2 / 3;
  width: 100%;
  overflow: hidden;
  display: block;
  object-fit: cover;
}
/* Adds insert one row instead of repainting the tab, so nothing else moves —
   this is the only cue that something arrived. */
.talent-row-added {
  animation: ucb-talent-row-in 2s ease-out;
}
@keyframes ucb-talent-row-in {
  0%, 55% { background: rgba(245, 158, 11, .22); }
  100%    { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .talent-row-added { animation: none; outline: 2px solid rgba(245, 158, 11, .7); }
}
.talent-performer {
  line-height: 1.2em;
  margin-bottom: 5px;
}
.talent-name {
  font-weight: 600;
  font-size: 14px;
}
.talent-status {
  font-size: 14px;
  font-weight: 400;
  line-height: 1.2em;
  margin-bottom: 5px;
}
.talent-attended {
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5em;
}
.talent-attended-label {
  padding-right: 5px;
}
/* "Show on event page" (talents[].display) — show_staff+ only. */
.talent-display {
  font-size: 13px;
  margin-top: 4px;
}
.talent-display-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  user-select: none;
}
.talent-display-label input {
  margin: 0;
  cursor: pointer;
}
.talent-edit-link {
  font-size: 12px;
  display: none;
}
.logged-in .talent-edit-link {
  display: inline;
}
.talent-notes {
  text-align: left;
  margin-top: auto;
}
.talent-notes textarea {
  margin-bottom: 0;
  color: var(--ucb-gray-800);
  resize: none;
  overflow: auto;
  height: 80px;
  line-height: 1.4em;
  width: 100%;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  padding: 8px;
  font-family: inherit;
  font-size: 12px;
}
.talent-notes-save {
  padding: 5px;
  width: 100%;
  font-size: 14px;
  line-height: 1.2em;
  background: var(--ucb-brand);
  color: white;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 600;
}
/* ⚠ This button carries `.btn-secondary` for layout, but it is a RED button.
   `.btn-secondary:hover` sets a near-white background at (0,2,0) and beat
   `.talent-notes-save`'s own (0,1,0) red, so hovering turned it white — with
   white text on top, i.e. an invisible label. Re-assert the brand colour for
   hover/focus at (0,2,0); this rule sits later in the file, so it wins the tie.
   The muted `.btn.is-clean` / `:disabled` states are (0,3,0) and still win over
   BOTH, which is what keeps a nothing-to-save button grey rather than red. */
.talent-notes-save:hover,
.talent-notes-save:focus {
  background: var(--ucb-brand-dark);
  border-color: var(--ucb-brand-dark);
  color: white;
}

.talent-notes-save:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 2px;
}
/* Talent payment fields (admin only) */
/* Conflict dialog body — "theirs" above "yours", both spelled out. A 409 from
   the concurrency guard is a DECISION (keep mine / use theirs), not an error,
   so the two values have to be readable side by side rather than described. */
.talent-conflict {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* One block per conflicted field — several can be decided in a single dialog,
   because Magnific allows only one popup and a queue of them would be worse. */
.talent-conflict-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.talent-conflict-field {
  font-size: 12px;
  font-weight: 700;
  color: var(--ucb-gray-900);
}
.talent-conflict-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  background: var(--ucb-gray-50);
}
.talent-conflict-tag {
  flex: none;
  min-width: 130px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ucb-gray-600);
}
.talent-conflict-val {
  font-size: 13px;
  color: var(--ucb-gray-900);
  word-break: break-word;
}

.talent-payment {
  padding: 6px 10px;
  background: var(--ucb-gray-50);
  border-top: 1px solid var(--ucb-gray-100);
}
.talent-payment-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.talent-payment-checkbox {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ucb-gray-700);
  cursor: pointer;
}
.talent-payment-checkbox input[type="checkbox"] {
  accent-color: var(--ucb-green-dark);
  width: 16px;
  height: 16px;
}
.talent-amount-paid {
  display: flex;
  align-items: center;
  gap: 6px;
}
.talent-amount-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ucb-gray-500);
}
.talent-amount-input {
  width: 90px;
  padding: 4px 8px;
  font-size: 13px;
  font-family: inherit;
  border: 1px solid var(--ucb-border-strong);
  border-radius: 4px;
  background: white;
  color: var(--ucb-gray-800);
}
.talent-amount-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 2px rgba(139, 32, 37, 0.25);
}
.talent-link-close {
  margin: 10px -20px -20px;
}
#talent-link-close {
  display: block;
  width: 100%;
  padding: 8px;
  text-align: center;
  background: var(--ucb-gray-100);
  color: var(--ucb-gray-600);
  text-decoration: none;
  font-weight: 600;
  font-size: 12px;
  border: none;
  cursor: pointer;
}

/* Talent search */
.talent-searchbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 0 0 20px;
}
#talent-search {
  flex: 1 1 auto;
  max-width: 100%;
  padding: 7px 8px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: 4px;
  margin-bottom: 0;
  height: 36px;
  font-family: inherit;
}
/* Clear belongs to the search input, not to the add-button cluster, so it
   stays outlined — but it must not be a different SIZE, which is what made
   the toolbar look accidental. .btn's 15px padding was towering over the
   6px/14px add buttons. */
#talent-search-clear {
  padding: 6px 14px;
  font-size: 12px;
  border-radius: 4px;
  color: var(--ucb-gray-700);
}

#talent-search-panel {
  margin: 0 0 20px;
  padding: 12px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: 6px;
  background: var(--ucb-gray-50);
}

/* ── "+ New Person" panel (scope/SCOPE-door-talent-add.md) ──────────
   Same shell as #talent-search-panel: an inline toolbar panel, not a
   dialog. Deliberate — ucbDialog has no multi-field form type, and the
   sibling search panel already establishes this shape in this tab. */
#talent-new-panel {
  margin: 0 0 20px;
  padding: 12px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: 6px;
  background: var(--ucb-gray-50);
}
.talent-new-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.talent-new-field {
  flex: 1 1 220px;
  min-width: 0;
}
.talent-new-field label {
  display: block;
  margin: 0 0 4px;
  font-weight: 600;
  font-size: 13px;
}
.talent-new-optional {
  font-weight: 400;
  color: var(--ucb-gray-500);
}
/* ID selectors on purpose: The7's main.min.css styles bare form controls at
   real specificity, so a single class here loses the border/padding fight
   (same reason #talent-search above is an ID). */
#talent-new-name,
#talent-new-email {
  width: 100%;
  padding: 7px 8px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: 4px;
  background: #fff;
  color: var(--ucb-gray-900);
  font-size: 14px;
}
/* The theme's placeholder is far too light against white. --ucb-gray-500 is
   4.83:1, the lightest value that still clears WCAG AA for body text.
   `opacity: 1` is load-bearing — Firefox dims placeholders by default. */
#talent-new-name::placeholder,
#talent-new-email::placeholder {
  color: var(--ucb-gray-500);
  opacity: 1;
}
.talent-new-hint,
.talent-new-note {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--ucb-gray-500);
  line-height: 1.45;
}
.talent-new-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
}
/* .btn is `display:block; width:100%` by default (only .btn-secondary/.btn-sm
   opt out), so the primary button spanned the panel and wrapped Cancel to the
   next line. Both buttons size to their own text here. */
.talent-new-actions .btn,
#talent-search-panel .btn {
  display: inline-block;
  width: auto;
  padding: 10px 18px;
  font-size: 13px;
}

/* Conflict block. `display` is left at the browser default so the [hidden]
   attribute actually hides it — an author display here would silently
   no-op it (convention 33). */
.talent-new-conflict {
  margin-top: 12px;
  padding: 10px;
  /* Same amber recipe as the .ucb-panel-dirty "Unsaved" chip above — this
     is the dashboard's established "attention, not error" treatment, and
     --ucb-amber-50/-300 don't exist as tokens. */
  border: 1px solid rgba(245, 158, 11, 0.45);
  border-radius: 6px;
  background: rgba(245, 158, 11, 0.12);
}
.talent-new-conflict[hidden] { display: none; }
.talent-new-conflict-msg {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 600;
  color: #92400e;
}
/* ⚠ Scoped under #event-talents: this list renders inside a `.content`
   wrapper, and The7's `.content ul` (0,1,1) beats a lone class (0,1,0) —
   which silently restores a 20px indent and the disc bullets. Same fight
   as .ucb-tdir-cards in talent-directory.css (convention 33). */
#event-talents .talent-new-cands {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.talent-new-cand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px;
  border-radius: 4px;
  background: #fff;
}
.talent-new-cand-img {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
}
.talent-new-cand-initial {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--ucb-gray-200);
  color: var(--ucb-gray-600);
  font-weight: 700;
}
.talent-new-cand-body {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  line-height: 1.35;
}
.talent-new-cand-name { font-weight: 600; }
.talent-new-cand-badge {
  display: inline-block;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: 1px 6px;
  border-radius: 100px;
  background: var(--ucb-gray-200);
  color: var(--ucb-gray-600);
  vertical-align: middle;
}
.talent-new-cand-badge.is-public {
  background: rgba(21, 128, 61, .12);
  color: #15803d;
}
.talent-new-cand-email {
  display: block;
  color: var(--ucb-gray-500);
  font-size: 12px;
  word-break: break-all;
}
.talents-empty { margin: 0; }

@media (max-width: 600px) {
  .talent-new-field { flex: 1 1 100%; }
  .talent-new-cand { flex-wrap: wrap; }
  .talent-new-cand .talent-new-use { margin-left: 44px; }
}
/* `.add-misc-talent-btn` is the pre-2.33.7 class, kept so a cached copy of the
   old JS still renders a styled button mid-deploy; `.add-placeholder-btn` is
   what the registry-driven buttons use (Misc / Monologist / Photographer). The
   toolbar already flex-wraps, so extra buttons drop to a second line rather
   than squeezing the search input. */
.add-misc-talent-btn,
.add-placeholder-btn,
.add-talent-search-btn,
.add-new-talent-btn {
  background: var(--ucb-gray-800);
  color: white;
  border: none;
  padding: 6px 14px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.add-misc-talent-btn:hover,
.add-placeholder-btn:hover,
.add-talent-search-btn:hover,
.add-new-talent-btn:hover {
  background: var(--ucb-gray-700);
}
.add-placeholder-btn[disabled],
.add-new-talent-btn[disabled] {
  opacity: .6;
  cursor: default;
}
.talent-thumb-wrap {
  position: relative;
  display: inline-block;
  margin-right: 8px;
  flex-shrink: 0;
}
.talent-thumb-sm {
  width: 32px;
  height: 32px;
  object-fit: cover;
  border-radius: 4px;
  display: block;
}
.talent-thumb-preview {
  display: none;
  position: fixed;
  width: 120px;
  height: 120px;
  object-fit: cover;
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  border: none;
  z-index: 999999;
  pointer-events: none;
}
.talent-cats {
  display: block;
  font-size: 11px;
  color: var(--ucb-gray-500);
  text-align: left;
  line-height: 1.3;
}

/* ── 16. QR Scanner ────────────────────────────────────────── */
#qr_code {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  gap: 10px;
  min-height: 180px;
}
#start-qr-scan {
  background: var(--ucb-brand);
  color: white;
  border: none;
  padding: 0.75rem 1.25rem;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
#start-qr-scan:hover {
  background: var(--ucb-brand-dark);
}
#start-qr-scan:focus-visible {
  outline: 2px solid var(--ucb-accent);
  outline-offset: 2px;
}
.qr-video-wrapper {
  position: relative;
  width: 100%;
  max-width: 100%;
  background: #000;
}
.qr-video {
  position: relative;
  width: 100%;
  max-width: 360px;       /* keep the square a sensible size on desktop */
  margin: 0 auto;
  aspect-ratio: 1 / 1;    /* square viewport on every device */
  overflow: hidden;       /* crop the webcam feed to the square */
  display: block;
}
/* html5-qrcode injects a <video> sized to the camera's native aspect ratio
   (4:3/16:9 on desktop webcams), which letterboxed inside the box. Cover-fit
   it so it fills the square and the overflow is cropped. This is display-only —
   decoding reads the raw stream + qrbox region, so cropping doesn't affect scans. */
.qr-video video {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  display: block;
}
.qr-close-button {
  position: absolute;
  top: 5px;
  right: 5px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  border: none;
  border-radius: 50%;
  width: 30px;
  height: 30px;
  font-size: 18px;
  font-weight: bold;
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 10;
  transition: background var(--ucb-transition);
  box-shadow: 0 0 4px 1px rgba(255, 255, 255, 0.76);
  padding: 0;
}
.qr-close-button:hover {
  background: rgba(115, 115, 115, 0.8);
}
.qr-close-button:focus-visible {
  outline: 2px solid white;
  outline-offset: 2px;
}

/* Self-dismissing scan-result banner pinned to the TOP of the live video.
   The camera view is tall, so its bottom is often below the fold when the
   scanner opens — the top stays visible, so that's where the feedback goes.
   Camera stays open for continuous scanning; this banner is the feedback. */
.qr-scan-result {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: 9;                 /* under the × close button (z-index 10) */
  padding: 14px 44px;         /* clear the close button at top-right */
  text-align: center;
  font-size: 16px;
  font-weight: 800;
  line-height: 1.3;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  background: rgba(21, 128, 61, 0.95);   /* success default */
  animation: qr-scan-pop 0.18s ease-out;
}
@keyframes qr-scan-pop {
  from { transform: translateY(-100%); }
  to   { transform: translateY(0); }
}
.qr-scan-result--success { background: rgba(21, 128, 61, 0.95); }   /* green */
.qr-scan-result--warn    { background: rgba(180, 83, 9, 0.95); }    /* amber */
.qr-scan-result--error   { background: rgba(185, 28, 28, 0.96); }   /* red */
.qr-scan-result--pending { background: rgba(30, 64, 175, 0.95); }   /* blue: working */
/* Inline spinner for the "working…" (creating ticket) state. */
.qr-scan-spinner {
  display: inline-block;
  width: 15px;
  height: 15px;
  margin-right: 8px;
  vertical-align: -2px;
  border: 2px solid rgba(255, 255, 255, 0.5);
  border-top-color: #fff;
  border-radius: 50%;
  animation: qr-scan-spin 0.6s linear infinite;
}
@keyframes qr-scan-spin { to { transform: rotate(360deg); } }
/* Status label on one line, the attendee name on its own line below it so a
   name never wraps mid-name. */
.qr-scan-result-label {
  display: block;
  font-size: 13px;
  font-weight: 700;
  opacity: 0.92;
}
.qr-scan-result-name {
  display: block;
  margin-top: 2px;
  font-size: 18px;
  font-weight: 800;
}
/* Advisory third line (student-ID frequency hint) — deliberately quieter than the
   name: it's context for staff, not a verdict. Colour is inherited from the banner's
   own --success/--warn variant, so it can't clash with any of them. */
.qr-scan-result-note {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  font-weight: 600;
  opacity: 0.85;
}

/* ── 17. Manual Ticket Form ────────────────────────────────── */
/* Lives in the narrow left sidebar beneath QR Scanner — fields stack
   vertically full-width. The .manual-ticket-section class is kept as
   a BC hook in case any legacy markup still references it. */
.manual-ticket-section {
  border-top: 1px solid var(--ucb-gray-100);
}
.create-ticket-form {
  padding: 14px 18px 18px;
}
.create-ticket-form-wrapper {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.create-ticket-form-wrapper input,
.create-ticket-form-wrapper select {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  font-size: 13px;
  font-family: inherit;
  color: var(--ucb-gray-700);
  background: var(--ucb-gray-50);
}
.create-ticket-form-wrapper input:focus,
.create-ticket-form-wrapper select:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.25);
}
.create-ticket-form-wrapper input[name="manual-qty"] {
  /* Qty input stays compact even in column layout */
  width: 90px;
  align-self: flex-start;
}
.create-ticket-form-wrapper button {
  width: 100%;
  margin-top: 4px;
}

/* ── 18. Notes Panel ───────────────────────────────────────── */
.notes-panel {
  margin-top: 18px;
}
.notes-header {
  background: linear-gradient(135deg, rgba(245, 158, 11, 0.04) 0%, rgba(245, 158, 11, 0.08) 100%);
}
.notes-title {
  color: var(--ucb-amber-dark);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.notes-body {
  padding: 14px 18px;
}
.notes-textarea,
.notes-log__new-text,
.notes-log__edit-text {
  width: 100%;
  min-height: 50px;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  padding: 8px 12px;
  font-size: 12px;
  color: var(--ucb-gray-700);
  font-family: inherit;
  resize: vertical;
  background: var(--ucb-gray-50);
  line-height: 1.5;
  box-sizing: border-box;
}
.notes-textarea:focus,
.notes-log__new-text:focus,
.notes-log__edit-text:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.25);
}

/* ── 18b. Event Notes Log ──────────────────────────────────────
   Selectors are scoped under #shows-dashboard so they out-specify
   the theme/Elementor `.content ul` rules (which otherwise force a
   left margin + disc bullets onto .notes-log__entries). */
#shows-dashboard .notes-log__entries {
  list-style: none !important;
  margin: 0 0 8px 0 !important;
  padding: 0 !important;
  max-height: 320px;
  overflow-y: auto;
}
#shows-dashboard .notes-log__entries > li {
  list-style: none !important;
  margin-left: 0 !important;
}
#shows-dashboard .notes-log__entry {
  padding: 8px 10px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  background: #fff;
  margin-bottom: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ucb-gray-800, #333);
}
#shows-dashboard .notes-log__entry:last-child {
  margin-bottom: 0;
}
#shows-dashboard .notes-log__meta {
  font-size: 11px;
  color: var(--ucb-gray-500, #888);
  margin-bottom: 4px;
}
#shows-dashboard .notes-log__author {
  color: var(--ucb-gray-800, #333);
  font-weight: 700;
}
#shows-dashboard .notes-log__author--shared {
  color: #6b7280;
  font-style: italic;
}
#shows-dashboard .notes-log__author--legacy {
  color: #9ca3af;
  font-style: italic;
}
#shows-dashboard .notes-log__time {
  font-weight: 400;
}
#shows-dashboard .notes-log__body {
  white-space: pre-wrap;
  word-wrap: break-word;
}
#shows-dashboard .notes-log__entry-actions {
  margin-top: 6px;
  display: flex;
  gap: 8px;
}
#shows-dashboard .notes-log__entry-actions button {
  background: transparent;
  border: none;
  color: var(--ucb-brand, #8B2025);
  font-size: 11px;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}
#shows-dashboard .notes-log__entry-actions button:hover {
  color: var(--ucb-brand-dark, #6B181C);
}
#shows-dashboard .notes-log__empty,
#shows-dashboard .notes-log__loading,
#shows-dashboard .notes-log__error {
  list-style: none !important;
  margin-left: 0 !important;
  padding: 8px 10px;
  font-size: 12px;
  color: var(--ucb-gray-500, #888);
  font-style: italic;
  border: 1px dashed var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  background: var(--ucb-gray-50);
}
#shows-dashboard .notes-log__error {
  color: var(--ucb-brand, #8B2025);
}
#shows-dashboard .notes-log__add-form.hidden {
  display: none;
}

/* ── 19. CSV Export ────────────────────────────────────────── */
/* The exports render as quiet links inside .show-header-links (2.25.x —
   they were oversized buttons in .header-actions). display:contents lets
   the links + separators participate in the row's flex gap directly,
   while the container span still hides as a unit for drafts (`.hidden`'s
   display:none !important out-specifies this). */
.csv-export-links {
  display: contents;
}

/* ── 20. Floating Summary Bar ──────────────────────────────── */
.floating-summary {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--ucb-gray-900);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 20px;
}
.floating-summary .summary-row {
  display: flex;
  gap: 0;
  font-family: 'Roboto', sans-serif;
  font-weight: 700;
  font-size: 18px;
  color: white;
}
.floating-summary .summary-row span {
  padding: 4px 14px;
  text-align: center;
  /* Keep "1782 Total" / "1782 Out" on a single line — without nowrap
     the four-digit DCM totals were wrapping their label to a second
     line and stretching the bar. nowrap + ellipsis is the safety net;
     the mobile rule below tightens font + padding so the row fits on
     a 320px phone even at 5-digit totals. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.floating-summary .ticket-total-label {
  color: white;
  background: var(--ucb-gray-800);
}
.floating-summary .ticket-total-checkedin {
  color: white;
  background: var(--ucb-green-dark);
}
.floating-summary .ticket-total-checkedout {
  color: white;
  /* blue-dark, not blue: white text needs 4.5:1 against this fill (base blue
     was only 3.68:1 — WCAG audit 2026-07). */
  background: var(--ucb-blue-dark);
}

/* ── 21. Session Status ────────────────────────────────────── */
.session-status {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  /* red-dark, not red: white bar text needs 4.5:1 against this fill (base
     red was only 3.76:1 — WCAG audit 2026-07). */
  background: var(--ucb-red-dark);
  color: white;
  text-align: center;
  padding: 10px;
  font-weight: bold;
  z-index: 9999;
}

/* ── 20. Inline Login Form ─────────────────────────────────── */
/* MOVED 2026-08-12 to assets/css/ucb-inline-login.css (handle
   `ucb-inline-login`, registered as a dependency of this stylesheet, so it
   always loads first and the .btn/.btn-primary rules above still own the
   submit button's appearance here).
   The standalone report pages render the same gate markup and needed these
   rules without the rest of this file — see Inline_Login / Report_Access.
   Don't re-add a copy here; edit the shared file. */

/* ── 20a. Login Gate (tabbed) ──────────────────────────────── */
.pin-gate {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  min-height: 60vh;
  padding: 60px 20px 40px;
}
.pin-gate-inner {
  text-align: center;
  max-width: 480px;
  width: 100%;
}
.pin-gate-logo {
  margin-bottom: 28px;
}
.pin-gate-logo .ucb-logo {
  font-size: 32px;
  color: var(--ucb-brand);
}
.pin-gate-logo .comedy-badge {
  background: var(--ucb-accent);
  color: var(--ucb-gray-900);
}
.pin-gate-sub {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--ucb-gray-500);
  margin-top: 8px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}

/* Card shell shared by both login panels */
.pin-gate-card {
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius);
  box-shadow: var(--ucb-shadow-lg);
  overflow: hidden;
  text-align: left;
}

/* Tab bar */
.pin-gate-tabs {
  display: flex;
  border-bottom: 1px solid var(--ucb-gray-200);
  background: var(--ucb-gray-50);
}
.pin-gate-tab {
  flex: 1 1 0;
  padding: 16px 12px;
  background: transparent;
  border: none;
  border-bottom: 3px solid transparent;
  cursor: pointer;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-500);
  transition: color var(--ucb-transition), border-color var(--ucb-transition), background var(--ucb-transition);
}
.pin-gate-tab:hover {
  color: var(--ucb-gray-700);
  background: white;
}
.pin-gate-tab.active,
.pin-gate-tab[aria-selected="true"] {
  color: var(--ucb-brand);
  border-bottom-color: var(--ucb-brand);
  background: white;
}
.pin-gate-tab:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: -4px;
}
.pin-gate-tab + .pin-gate-tab {
  border-left: 1px solid var(--ucb-gray-200);
}

/* Panel body */
.pin-gate-panel {
  display: none;
  padding: 28px 28px 32px;
}
.pin-gate-panel.active {
  display: block;
}
.pin-gate-intro {
  font-size: 14px;
  color: var(--ucb-gray-600);
  margin: 0 0 20px;
  line-height: 1.5;
}
.pin-gate-field-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-500);
  margin: 0 0 6px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.pin-gate-field-label + input {
  margin-bottom: 14px;
}

/* Form layout shared by both tabs */
.pin-form {
  display: block;
}
.pin-input,
/* Doubled class (2026-08-12): the PIN gate's inputs also carry
   .inline-login-input, whose own doubled-class rule in ucb-inline-login.css is
   (0,2,0) and was out-ranking this (0,1,0) block — the gate quietly lost its
   1.5px border, --ucb-gray-900 text and inherited font. Matching that
   specificity hands them back; this file loads AFTER the shared one, so an
   equal-specificity tie resolves here. (Both rules beat The7's
   `input[type="text"]`, which is what either of them is fighting.) */
.pin-gate-input.pin-gate-input {
  width: 100%;
  padding: 12px 14px;
  font-size: 16px;
  font-family: inherit;
  border: 1.5px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  background: var(--ucb-gray-50);
  color: var(--ucb-gray-900);
  transition: border-color var(--ucb-transition), box-shadow var(--ucb-transition);
}
.pin-input {
  text-align: center;
  letter-spacing: 4px;
  font-size: 20px;
  padding: 14px 18px;
}
.pin-input:focus,
/* Doubled to match the shared file's (0,3,0) focus rule — same reason as the
   base block above, so the gate keeps its own ring and white focus fill. */
.pin-gate-input.pin-gate-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.2);
  background: white;
}
/* WCAG 2.4.7 focus visibility (2026-07 audit): defensive explicit fallback —
   the PIN gate is shown pre-authentication and may render before
   #shows-dashboard's wrapper is present. */
.pin-input:focus-visible,
.pin-gate-input:focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 2px;
}
.pin-submit {
  font-size: 16px !important;
  margin-top: 8px;
}
#pin-form .pin-submit {
  font-size: 20px !important;
}
.pin-error,
.pin-gate-error {
  font-size: 13px;
  font-weight: 600;
  color: var(--ucb-red-dark);
  min-height: 20px;
  margin: 4px 0 8px;
}
.pin-gate-error.hidden,
.pin-error.hidden {
  display: none !important;
}

/* Mobile polish */
@media (max-width: 480px) {
  .pin-gate {
    padding: 32px 14px 32px;
  }
  .pin-gate-panel {
    padding: 22px 20px 24px;
  }
  .pin-gate-tab {
    font-size: 12px;
    padding: 14px 8px;
    letter-spacing: 0.5px;
  }
  .setup-times-cluster-fields {
    grid-template-columns: 1fr;
  }
}

/* ── 20b. Per-Button Test Mode ──────────────────────────────── */
/* Send notes */
.send-notes-field {
  max-width: 400px;
  margin: 0 auto 16px;
  text-align: left;
}
.send-notes-label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--ucb-gray-500);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 4px;
  text-align: center;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.send-notes-input {
  width: 100%;
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  padding: 8px 12px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ucb-gray-700);
  background: var(--ucb-gray-50);
  resize: vertical;
  line-height: 1.5;
}
.send-notes-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.25);
}

.test-send-box {
  margin-bottom: 14px;
  text-align: center;
}
.test-send-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  color: var(--ucb-gray-500);
}
.test-send-checkbox {
  accent-color: var(--ucb-amber-dark);
  width: 15px;
  height: 15px;
}
.test-send-input-wrap {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
/* `.test-send-input-wrap` prefix beats The7's `.content input[type="email"]`
   (class + type), which was repainting the text light. */
.test-send-input-wrap .test-send-input {
  border: 2px solid var(--ucb-amber);
  border-radius: 6px;
  padding: 8px 14px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ucb-gray-900);
  background: rgba(245, 158, 11, 0.06);
  width: 280px;
  max-width: 100%;
  text-align: center;
}
.test-send-input-wrap .test-send-input::placeholder {
  color: var(--ucb-gray-500);
  opacity: 1; /* Firefox dims placeholders by default */
}
.test-send-input-wrap .test-send-input:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
}
.test-send-note {
  font-size: 11px;
  font-weight: 600;
  color: var(--ucb-amber-dark);
  max-width: 320px;
}

/* ── 21a. SKU Breakdown Strip (Check-In tab) ──────────────── */
.sku-breakdown {
  padding: 0 0 18px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.sku-breakdown-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 0;
}
.sku-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 13px;
  background: white;
  border: 1px solid var(--ucb-gray-200);
  color: var(--ucb-gray-700);
  line-height: 1.2;
}
.sku-chip strong {
  color: var(--ucb-gray-900);
  font-weight: 700;
}
.sku-chip-total {
  color: var(--ucb-gray-900);
  font-weight: 700;
}
.sku-in {
  color: var(--ucb-green-dark);
  font-weight: 600;
}
.sku-out {
  color: var(--ucb-red-dark);
  font-weight: 600;
}
.sku-livestream {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  padding: 5px 14px 5px 10px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.08);
  border: 1px solid rgba(16, 185, 129, 0.35);
  color: var(--ucb-green-dark);
  line-height: 1.2;
}
.sku-ls-play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  /* green-dark, not green: this ring is a non-text graphic conveying the
     livestream affordance and needs 3:1 against its white-ish surroundings
     (base green was only 2.54:1 — WCAG audit 2026-07). */
  border: 1.5px solid var(--ucb-green-dark);
  flex-shrink: 0;
}
.sku-ls-play::after {
  content: '';
  width: 0;
  height: 0;
  border-top: 3px solid transparent;
  border-bottom: 3px solid transparent;
  border-left: 5px solid var(--ucb-green-dark);
  margin-left: 1px;
}
.sku-ls-badge {
  font-weight: 600;
  color: var(--ucb-green-dark);
}
.sku-ls-detail {
  color: var(--ucb-gray-500);
  font-weight: 500;
}

/* ── 21b. Show Setup Tab ───────────────────────────────────── */
.setup-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-bottom: 18px;
}
.setup-panel-body {
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.setup-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.setup-field-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ucb-gray-500);
  margin-bottom: 2px;
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.setup-field-label-sm {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--ucb-gray-500);
}
.setup-label-accent {
  color: var(--ucb-green-dark);
}
.setup-field-value {
  font-size: 14px;
  font-weight: 600;
  color: var(--ucb-gray-800);
}
.setup-input {
  border: 1px solid var(--ucb-border-strong);
  border-radius: var(--ucb-radius-sm);
  padding: 8px 12px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ucb-gray-900);
  background: var(--ucb-gray-50);
  width: 100%;
}
.setup-input:focus {
  outline: none;
  border-color: var(--ucb-brand);
  box-shadow: 0 0 0 3px rgba(139, 32, 37, 0.25);
}
.setup-input-inline {
  border: none;
  background: none;
  padding: 0;
  font-size: 13px;
  color: var(--ucb-gray-900);
}
.setup-input-inline:focus {
  box-shadow: none;
  border-bottom: 1px solid var(--ucb-brand);
  border-radius: 0;
}
/* Specificity bump so WP theme rules like `input { color: … }` don't
   dim the typed text in setup forms (matches the settings/schedule
   pattern). Also enforce a placeholder color that still meets WCAG AA
   against the input background. */
#shows-dashboard input.setup-input,
#shows-dashboard textarea.setup-input,
#shows-dashboard select.setup-input,
#shows-dashboard input.setup-input-inline {
  color: var(--ucb-gray-900);
}
#shows-dashboard input.setup-input::placeholder,
#shows-dashboard textarea.setup-input::placeholder,
#shows-dashboard input.setup-input-inline::placeholder {
  color: var(--ucb-gray-600);
  opacity: 1;
}
.setup-input-time {
  font-size: 15px;
  font-weight: 600;
  color: var(--ucb-green-dark);
  padding: 8px 10px;
}

/* ── flatpickr theme reset ──────────────────────────────────────
   The7/Elementor styles every <select>/<input> on the site
   (`select:not(.elementor-field)…` adds margin + border + box-sizing),
   which leaks into flatpickr's calendar — most visibly the month dropdown.
   flatpickr mounts the calendar on <body>, so these rules are intentionally
   NOT scoped to #shows-dashboard (this stylesheet only loads on the
   dashboard). !important is needed to beat the theme's specificity. */
.flatpickr-calendar select,
.flatpickr-calendar input {
  margin: 0 !important;
  box-shadow: none !important;
}
.flatpickr-calendar .flatpickr-monthDropdown-months {
  border: none !important;
  border-radius: 0 !important;
  background: transparent !important;
  height: auto !important;
  min-height: 0 !important;
  line-height: normal !important;
  padding: 0 0.5ch !important;
  -webkit-appearance: menulist !important;
  appearance: menulist !important;
}
.flatpickr-calendar .numInputWrapper input,
.flatpickr-calendar .flatpickr-time input {
  border: none !important;
  border-radius: 0 !important;
  background: transparent !important;
  height: auto !important;
  min-height: 0 !important;
}
.setup-input-narrow {
  max-width: 120px;
}
.setup-field-error {
  font-size: 12px;
  color: var(--ucb-red-dark);
  font-weight: 500;
}

/* Contact card — repeatable contact rows.
   The previous single-contact layout wrapped both inputs in an undeclared
   `.setup-contact-info` flex child; with no `flex: 1` it was shrink-to-fit, so
   the inputs collapsed to the browser's default ~180px `size=20` width no
   matter how wide the panel was (which is why `width: 100%` on the name input
   appeared to do nothing). Every row below sets `flex` + `min-width: 0`
   explicitly so the fields fill the card and shrink instead of overflowing. */
.setup-contacts-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 10px;
}
.setup-contact-entry {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
/* Align the remove button to the name input (the first of the two stacked
   fields) rather than the whole row. */
.setup-contact-entry .setup-remove-contact {
  margin-top: 2px;
}
/* The primary contact is the recap's To line — it can be edited or blanked,
   but never removed as a row. Keying off :first-child (rather than marking
   the row in JS) means the rule follows automatically as rows are added and
   removed, with no re-indexing pass.

   `visibility` rather than `display: none` so the button still occupies its
   column and every row's inputs line up on the same right edge. */
.setup-contact-entry-wrap:first-child .setup-remove-contact {
  visibility: hidden;
  pointer-events: none;
}
/* Name over email, both full width. This card is a half-width grid column
   (~470px), so side-by-side columns can't hold a real address without
   truncating it — and the card had vertical room to spare. Stacking spends
   that height on the field that actually needs the pixels. */
.setup-contact-fields {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  gap: 6px;
}
.setup-contact-fields .setup-contact-name-field,
.setup-contact-fields .setup-contact-email-field {
  min-width: 0;
}
.setup-remove-contact {
  flex-shrink: 0;
}
/* Soft "did you mean" caution — a name pasted onto the front of a real
   address is syntactically valid, so this warns without blocking the save. */
.setup-contact-warning {
  font-size: 12px;
  color: var(--ucb-gold-dark, #8a6d1f);
  font-weight: 500;
  margin-top: 4px;
}
.setup-contact-warning button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--ucb-brand);
  text-decoration: underline;
  cursor: pointer;
}
.setup-contacts-hint {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin: 10px 0 0;
  line-height: 1.5;
}
/* Separate stacked rows so two contacts don't read as one four-field block. */
.setup-contact-entry-wrap + .setup-contact-entry-wrap {
  padding-top: 10px;
  border-top: 1px solid var(--ucb-gray-200);
}
/* Recap "Refresh data" button bar (top of the Nightly/Final recap tabs). */
.recap-refresh-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px;
  margin-bottom: 14px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
}
.recap-refresh-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.recap-refresh-asof {
  font-size: 12px;
  color: var(--ucb-gray-600);
  font-weight: 600;
}
.recap-refresh-asof:empty::before {
  content: "Live ticket data";
  color: var(--ucb-gray-600);
}
.recap-refresh-hint {
  font-size: 12px;
  color: var(--ucb-gray-600);
}

/* Contact NAME field — sits beside the email in each contact row. Slightly
   heavier than the address so the person reads first, but the same size so
   the two columns line up. */
.setup-contact-name-input {
  width: 100%;
  font-weight: 600;
  color: var(--ucb-gray-900);
}

/* Recipients pills */
.setup-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.setup-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 12px;
  border-radius: 100px;
  font-size: 12px;
  font-weight: 600;
  border: 1px solid;
}
/* Pill text colors are intentionally darker than the brand hues so they meet
   WCAG 2.1 AA (>=4.5:1) against their light tinted backgrounds. */
.setup-pill-main {
  background: rgba(212, 168, 75, 0.14);
  border-color: rgba(212, 168, 75, 0.4);
  color: #8a5e00;
}
.setup-pill-cc {
  background: rgba(59, 130, 246, 0.1);
  border-color: rgba(59, 130, 246, 0.35);
  color: #1d4ed8;
}
.setup-pill-finance {
  background: rgba(16, 185, 129, 0.1);
  border-color: rgba(16, 185, 129, 0.4);
  color: #047857;
}

/* Recipients repeater */
/* "Always included" hint under the read-only recipient pills. */
.setup-recipients-hint {
  font-size: 11.5px;
  color: var(--ucb-gray-600);
  margin: 8px 0 0;
}
/* Faint divider separating the auto-included pills from the editable
   "Additional recipients" rows. */
.setup-recipients-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0 8px;
  color: var(--ucb-gray-600);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.setup-recipients-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--ucb-gray-200);
}
.setup-recipients-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.setup-recipient-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.setup-recipient-row .setup-input {
  flex: 1;
}
.setup-remove-recipient {
  flex-shrink: 0;
  padding: 4px 8px !important;
  font-size: 16px !important;
  line-height: 1;
}

/* Google Drive card */
.setup-drive-card {
  border-left: 3px solid var(--ucb-blue);
}
.setup-drive-link {
  display: flex;
  align-items: center;
  gap: 10px;
}
.setup-drive-icon {
  font-size: 24px;
}
.setup-drive-link a {
  font-size: 15px;
  font-weight: 600;
  color: var(--ucb-blue-dark);
  text-decoration: none;
}
.setup-drive-link a:hover {
  text-decoration: underline;
}
.setup-drive-empty {
  font-size: 13px;
  color: var(--ucb-gray-500);
  font-style: italic;
}
.setup-drive-desc {
  font-size: 11px;
  color: var(--ucb-gray-500);
  margin-top: 2px;
}
.setup-drive-preview {
  width: 100%;
  height: 420px;
  margin-top: 8px;
  border: 1px solid var(--ucb-gray-300);
  border-radius: 6px;
  overflow: hidden;
}
.setup-drive-preview iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Producer Discounts (promo codes) — Row 1.5 panel on the Setup tab.
   Full-width, accented like the other setup-tab cards (green here, since
   it's a revenue/promo action rather than an info card). */
.setup-promo-panel {
  border-left: 3px solid var(--ucb-green);
}
.setup-promo-hint {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin: 0 0 10px;
  line-height: 1.5;
}
.setup-promo-list {
  display: flex;
  flex-direction: column;
  margin-bottom: 12px;
}
.setup-promo-empty {
  padding: 10px 0;
  margin: 0;
  color: var(--ucb-gray-500);
  font-size: 13px;
  font-style: italic;
}
.setup-promo-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--ucb-gray-100);
  font-size: 13px;
}
.setup-promo-row:last-child {
  border-bottom: none;
}
.setup-promo-row-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.setup-promo-row-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 200px;
  min-width: 0;
}
.setup-promo-row-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.setup-promo-chip {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-weight: 600;
  letter-spacing: 0.3px;
  font-size: 13px;
  color: var(--ucb-gray-800);
  background: var(--ucb-gray-100);
  padding: 2px 8px;
  border-radius: 4px;
}
.setup-promo-amount {
  color: var(--ucb-green-dark);
  font-weight: 600;
}
.setup-promo-expires {
  color: var(--ucb-gray-500);
  font-size: 12px;
}
.setup-promo-expired-pill {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 2px 8px;
  border-radius: 100px;
  background: rgba(239, 68, 68, 0.1);
  color: var(--ucb-red-dark);
}
.setup-promo-meta {
  color: var(--ucb-gray-500);
  font-size: 12px;
}
.setup-promo-emailed {
  font-style: italic;
}
/* Create row — labeled columns: Code | $ off per ticket | Date | Create.
   (There was a Type column until dollars-only; percent-off codes are gone.) */
.setup-promo-create {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--ucb-gray-100);
}
.setup-promo-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.setup-promo-field-code   { flex: 2 1 180px; min-width: 140px; }
.setup-promo-field-amount { flex: 0 1 150px; min-width: 120px; }
.setup-promo-field-date   { flex: 0 1 170px; min-width: 150px; }
.setup-promo-field-btn    { flex: 0 0 auto; }
/* The7's custom.css puts margin-bottom on inputs (`.content input[type=…]`),
   which mis-aligns the flex-end row against the margin-less button — the
   #shows-dashboard id out-specifies it (established pattern, see the
   report-filter overrides). */
#shows-dashboard .setup-promo-field .setup-input {
  width: 100%;
  margin: 0;
}
.setup-promo-code-wrap {
  display: flex;
  gap: 6px;
}
.setup-promo-code-wrap .setup-input {
  flex: 1;
  min-width: 0;
}
.setup-promo-reroll {
  flex: 0 0 auto;
  padding: 8px 10px;
  font-size: 14px;
  line-height: 1;
}
.setup-promo-create .setup-field-help-sm {
  flex-basis: 100%;
  margin-top: 0;
}
.setup-promo-create .setup-field-error {
  flex-basis: 100%;
}

/* Email dialog — recipient chips + optional extra-addresses input. */
.setup-promo-email-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 14px;
}
.setup-promo-email-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: 999px;
  padding: 4px 6px 4px 12px;
}
.setup-promo-email-chip-remove {
  border: none;
  background: var(--ucb-gray-200);
  border-radius: 50%;
  width: 18px;
  height: 18px;
  line-height: 1;
  font-size: 12px;
  cursor: pointer;
  color: var(--ucb-gray-600);
}
.setup-promo-email-chip-remove:hover {
  background: var(--ucb-red-dark);
  color: white;
}
.setup-promo-email-extra-label {
  display: block;
  font-size: 12px;
  color: var(--ucb-gray-500);
  margin-top: 4px;
}
.setup-promo-email-extra-label .setup-input {
  margin-top: 6px;
  width: 100%;
}
.setup-promo-email-dialog-error {
  color: var(--ucb-red-dark);
  font-size: 12px;
  margin-top: 8px;
}

/* Producer Emails (Show Confirmation + Sales Link) — Row 1.5b panel on the
   Setup tab. Same visual language as .setup-promo-* (Producer Discounts,
   just above) but every class is `ucb-pcomm-` prefixed (convention 34 —
   never share selectors with a different dashboard script). Brand-red
   accent since it's the show-confirmation / policy-email surface. */
.ucb-pcomm-panel {
  border-left: 3px solid var(--ucb-brand);
}
/* The show-confirmation panel now mounts into the Show Holds hold-detail
   dialog (UCBDash.mountConfirmationPanel), NOT the Show Setup tab — so these
   rules have to work inside a ucbDialog body as well as in a panel. Mirrors
   .ucb-offer-panel, its neighbour in that dialog. */
.ucb-pcomm-confirm-mount {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--ucb-gray-100);
}
/* Inside the Pitches queue row the step header already provides the label
   and the separation — mirrors .ucb-offer-panel--bare. */
.ucb-pcomm-confirm-mount--bare {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.ucb-pcomm-confirm-heading {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ucb-gray-500);
}
.ucb-pcomm-confirm-help {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--ucb-gray-500);
}
/* Sent-email history (both producer emails), mirroring the recaps' list. */
.ucb-pcomm-sentlog {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--ucb-gray-100);
}
.ucb-pcomm-sentlog[hidden] { display: none; }
.ucb-pcomm-sentlog-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 190px;
  overflow-y: auto;
}
.ucb-pcomm-sentlog-list li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 0;
  font-size: 12.5px;
  color: var(--ucb-gray-600);
  border-bottom: 1px solid var(--ucb-gray-100);
}
.ucb-pcomm-sentlog-list li:last-child { border-bottom: none; }
.ucb-pcomm-sentlog-kind { font-weight: 600; color: var(--ucb-gray-700); }
.ucb-pcomm-sentlog-note { color: var(--ucb-gray-500); font-style: italic; }
/* A send that never arrived. --ucb-red-dark is the TEXT-safe tier (WCAG). */
.ucb-pcomm-sentlog-fail { color: var(--ucb-red-dark); font-weight: 600; }
.ucb-pcomm-sentlog-empty { font-size: 12.5px; color: var(--ucb-gray-500); font-style: italic; }

/* Points from the sales panel to where the confirmation went. */
.ucb-pcomm-elsewhere {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--ucb-gray-100);
  font-size: 12px;
  color: var(--ucb-gray-500);
  line-height: 1.5;
}
.ucb-linkbtn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--ucb-red-dark, #8B2025);
  text-decoration: underline;
  cursor: pointer;
}
.ucb-linkbtn:hover { text-decoration: none; }

.ucb-pcomm-confirm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
}
.ucb-pcomm-confirm-status {
  font-size: 13px;
  color: var(--ucb-gray-600);
}
.ucb-pcomm-status-sent {
  color: var(--ucb-green-dark);
  font-weight: 600;
}
.ucb-pcomm-status-unsent {
  color: var(--ucb-gray-500);
  font-style: italic;
}
.ucb-pcomm-link-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ucb-pcomm-link-wrap {
  display: flex;
  gap: 6px;
}
.ucb-pcomm-link-wrap .setup-input {
  flex: 1;
  min-width: 0;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 12px;
  color: var(--ucb-gray-600);
  background: var(--ucb-gray-50);
}

/* Per-show automatic-updates opt-out. Doubled specificity on the checkbox
   (convention 33): The7 and the Elementor kit both repaint bare inputs. */
.ucb-pcomm-updates-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--ucb-gray-100);
  font-size: 13px;
  color: var(--ucb-gray-700);
}
.ucb-pcomm-updates-row label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
}
.ucb-pcomm-panel .ucb-pcomm-updates-row input[type="checkbox"] {
  width: 16px;
  height: 16px;
  min-height: 0;
  margin: 0;
  flex: none;
  accent-color: var(--ucb-red-dark);
}
.ucb-pcomm-updates-row label:has(input:disabled) {
  opacity: 0.55;
  cursor: default;
}
.ucb-pcomm-updates-status {
  font-size: 12px;
  color: var(--ucb-gray-500);
  font-style: italic;
}

/* Review & Send modal — bespoke overlay (not ucbDialog: needs a locked
   header/footer around an editable `.ucb-recap-body` region), mirroring
   .recap-modal-* (shows-dashboard-recap.js) with the ucb-pcomm- prefix. */
.ucb-pcomm-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.ucb-pcomm-modal {
  background: white;
  border-radius: var(--ucb-radius);
  max-width: 700px;
  width: 100%;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
.ucb-pcomm-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--ucb-gray-200);
  font-weight: 700;
  font-size: 14px;
}
.ucb-pcomm-modal-close {
  background: none;
  border: none;
  font-size: 22px;
  cursor: pointer;
  color: var(--ucb-gray-500);
  padding: 0 4px;
}
.ucb-pcomm-modal-close:hover { color: var(--ucb-gray-800); }
.ucb-pcomm-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 0;
}
.ucb-pcomm-modal-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--ucb-gray-200);
}
.ucb-pcomm-modal-footer-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}
.ucb-pcomm-edit-warning {
  padding: 10px 20px;
  background: #fffbeb;
  border-bottom: 1px solid #fde68a;
  color: #78350f;
  font-size: 12.5px;
  line-height: 1.45;
}
.ucb-pcomm-edit-warning strong { color: #92400e; }

/* Recipients chip dialog (ucbDialog.custom) — shared by Review & Send's
   "Continue to Recipients" step and "Send update now". */
.ucb-pcomm-email-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 14px;
}
.ucb-pcomm-email-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: 999px;
  padding: 4px 6px 4px 12px;
}
.ucb-pcomm-email-chip-remove {
  border: none;
  background: var(--ucb-gray-200);
  border-radius: 50%;
  width: 18px;
  height: 18px;
  line-height: 1;
  font-size: 12px;
  cursor: pointer;
  color: var(--ucb-gray-600);
}
.ucb-pcomm-email-chip-remove:hover {
  background: var(--ucb-red-dark);
  color: white;
}
.ucb-pcomm-email-extra-label {
  display: block;
  font-size: 12px;
  color: var(--ucb-gray-500);
  margin-top: 4px;
}
.ucb-pcomm-email-extra-label .setup-input {
  margin-top: 6px;
  width: 100%;
}
.ucb-pcomm-cc-note {
  margin-top: 10px;
  font-size: 12px;
  color: var(--ucb-gray-500);
  font-style: italic;
}
.ucb-pcomm-test-label {
  display: block;
  font-size: 12px;
  color: var(--ucb-gray-500);
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--ucb-gray-100);
}
.ucb-pcomm-test-label .setup-input {
  margin-top: 6px;
  width: 100%;
}
.ucb-pcomm-email-dialog-error {
  color: var(--ucb-red-dark);
  font-size: 12px;
  margin-top: 8px;
}

/* Show times */
.setup-times-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 14px;
  align-items: start;
}
.setup-times-cluster {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.setup-times-cluster-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--ucb-gray-500);
}
.setup-times-cluster-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  align-items: end;
}
.setup-times-divider {
  width: 1px;
  align-self: stretch;
  margin-top: 20px;
  background: var(--ucb-border-strong);
}
.setup-time-scheduled {
  font-size: 18px;
  font-weight: 700;
  color: var(--ucb-gray-800);
}
.setup-duration {
  font-size: 12px;
  color: var(--ucb-gray-500);
  margin-top: 6px;
}

/* Audit check */
.setup-audit-panel {
  margin-bottom: 18px;
}
.setup-audit-list {
  padding: 0;
}
.setup-audit-empty {
  padding: 18px;
  text-align: center;
  color: var(--ucb-gray-500);
  font-size: 13px;
}
.setup-audit-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--ucb-gray-50);
  font-size: 13px;
  line-height: 1.5;
}
.setup-audit-row:last-child {
  border-bottom: none;
}
.audit-severity {
  flex-shrink: 0;
  font-size: 9px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 2px 8px;
  border-radius: 4px;
  margin-top: 2px;
}
.audit-severity.critical {
  background: rgba(239, 68, 68, 0.1);
  color: var(--ucb-red-dark);
}
.audit-severity.warning {
  background: rgba(245, 158, 11, 0.1);
  color: var(--ucb-amber-dark);
}
.audit-severity.info {
  background: rgba(59, 130, 246, 0.1);
  color: var(--ucb-blue-dark);
}
.audit-severity.pass {
  background: rgba(16, 185, 129, 0.12);
  color: var(--ucb-green-dark);
}
.setup-audit-row.pass {
  background: rgba(16, 185, 129, 0.03);
}
.setup-audit-row.pass > div {
  color: var(--ucb-gray-700);
}
#audit-count.all-done {
  background: rgba(16, 185, 129, 0.12);
  color: var(--ucb-green-dark);
}

/* Checklist */
.checklist-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px 14px;
}
.checklist-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  font-size: 13px;
  color: var(--ucb-gray-600);
  cursor: pointer;
  transition: color var(--ucb-transition);
}
.checklist-item:hover {
  color: var(--ucb-gray-800);
}
.checklist-checkbox {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  accent-color: var(--ucb-green-dark);
  cursor: pointer;
}
.checklist-item.done .checklist-label {
  text-decoration: line-through;
  color: var(--ucb-gray-500);
}
.checklist-label {
  flex: 1 1 auto;
}
.checklist-empty {
  grid-column: 1 / -1;
  font-size: 12px;
  color: var(--ucb-gray-500, #888);
  font-style: italic;
  padding: 6px 0;
}
.checklist-item--custom .checklist-remove {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: var(--ucb-gray-500, #888);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}
.checklist-item--custom .checklist-remove:hover {
  color: var(--ucb-brand, #8B2025);
}
.checklist-custom-add {
  display: flex;
  gap: 6px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--ucb-gray-200);
}
.checklist-custom-add .setup-input {
  flex: 1 1 auto;
}

/* Ticket summary grid */
.setup-ticket-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}
.setup-ticket-card {
  text-align: center;
  padding: 12px 8px;
}
.setup-ticket-label {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--ucb-gray-500);
  margin-bottom: 4px;
}
.setup-ticket-value {
  font-size: 28px;
  font-weight: 800;
  line-height: 1;
}
.setup-ticket-value.ls { color: var(--ucb-brand); }
.setup-ticket-value.ga { color: var(--ucb-green-dark); }
.setup-ticket-value.st { color: var(--ucb-gray-500); }
.setup-ticket-value.ad { color: var(--ucb-amber-dark); }
.setup-ticket-value.co { color: var(--ucb-gray-500); }
.setup-ticket-sub {
  font-size: 11px;
  color: var(--ucb-gray-500);
  margin-top: 4px;
}
.setup-ticket-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--ucb-gray-500);
  font-size: 13px;
  padding: 12px;
}

/* Incident flag */
.setup-incident-panel {
  border: 1px solid var(--ucb-gray-200);
  transition: border-color var(--ucb-transition), background var(--ucb-transition);
  margin-top: 18px;
}
.setup-incident-panel.incident-active {
  border-color: var(--ucb-red-dark);
  background: rgba(239, 68, 68, 0.03);
}
.setup-incident-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
.setup-incident-label {
  font-size: 14px;
  font-weight: 700;
  color: var(--ucb-gray-800);
}
.setup-incident-desc {
  font-size: 12px;
  color: var(--ucb-gray-500);
}
.setup-incident-panel.incident-active .setup-incident-label {
  color: var(--ucb-red-dark);
}

/* Save bar */
.setup-save-bar {
  position: sticky;
  bottom: 0;
  background: white;
  border-top: 1px solid var(--ucb-gray-200);
  padding: 12px 18px;
  z-index: 10;
  margin-top: 18px;
  border-radius: 0 0 var(--ucb-radius) var(--ucb-radius);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.04);
  text-align: center;
}
.setup-save-status {
  font-size: 13px;
  font-weight: 600;
  color: var(--ucb-green-dark);
  margin-bottom: 8px;
}

@media (max-width: 900px) {
  .setup-grid {
    grid-template-columns: 1fr;
  }
  .setup-times-grid {
    grid-template-columns: 1fr;
  }
  .setup-times-divider {
    width: 100%;
    height: 1px;
    margin: 0;
  }
  .checklist-grid {
    grid-template-columns: 1fr;
  }
  .setup-ticket-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ── 21c. Nightly Recap Tab ────────────────────────────────── */
.stats-grid-5 {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 0;
  background: white;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  box-shadow: var(--ucb-shadow-sm);
  overflow: hidden;
}
.recap-section {
  margin-bottom: 24px;
}
.recap-section-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--ucb-gray-100);
}
.recap-icon {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  flex-shrink: 0;
}
.recap-icon.tickets { background: rgba(59, 130, 246, 0.1); }
.recap-icon.cast { background: rgba(139, 32, 37, 0.1); }
.recap-section-title {
  font-size: 17px;
  font-weight: 700;
  color: var(--ucb-gray-800);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.recap-section-count {
  font-weight: 400;
  color: var(--ucb-gray-500);
}

/* Data table */
.data-table {
  width: 100%;
  background: white;
  border-radius: var(--ucb-radius);
  overflow: hidden;
  box-shadow: var(--ucb-shadow-md);
  border: 1px solid var(--ucb-gray-200);
}
.data-table table { width: 100%; border-collapse: collapse; }
.data-table th {
  background: var(--ucb-gray-50);
  padding: 10px 18px;
  text-align: left;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--ucb-gray-500);
  border-bottom: 1px solid var(--ucb-gray-200);
  font-family: 'Knockout 31 Junior Middlewt', 'DM Sans', sans-serif;
}
.data-table th.r { text-align: right; }
.data-table td {
  padding: 10px 18px;
  font-size: 13px;
  border-bottom: 1px solid var(--ucb-gray-100);
  font-variant-numeric: tabular-nums;
}
.data-table td.r { text-align: right; }
.data-table tr:last-child td { border-bottom: none; }
.data-table .total-row td {
  font-weight: 700;
  background: var(--ucb-gray-50);
  border-top: 2px solid var(--ucb-gray-200);
}
.type-label {
  font-weight: 600;
  color: var(--ucb-gray-800);
  display: flex;
  align-items: center;
  gap: 8px;
}
.type-dot {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex-shrink: 0;
}
/* Door-override note on the breakdown table's Student row — the recap emails'
   parenthetical, verbatim. No pill: the row is an aggregate, and pill chrome here
   would read as a per-person status like the check-in list's. Lighter weight than
   the ticket-type name so it annotates rather than competes. */
.recap-override-note {
  font-size: 12px;
  font-weight: 500;
  color: var(--ucb-gray-500);
  white-space: nowrap;
}
.rate-chip {
  display: inline-flex;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 4px;
}
.rate-chip.high { background: rgba(16, 185, 129, 0.1); color: var(--ucb-green-dark); }
.dim { color: var(--ucb-gray-500); }

/* Cast grid */
.cast-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
}
.cast-card {
  background: white;
  border-radius: 10px;
  padding: 12px;
  box-shadow: var(--ucb-shadow-sm);
  border: 1px solid var(--ucb-gray-200);
  display: flex;
  align-items: center;
  gap: 10px;
}
.cast-card.absent {
  border-color: rgba(239, 68, 68, 0.2);
  background: rgba(239, 68, 68, 0.02);
}
.cast-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--ucb-brand) 0%, var(--ucb-brand-light) 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: 700;
  font-size: 14px;
  flex-shrink: 0;
}
.cast-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}
.cast-avatar.absent-av { background: var(--ucb-gray-300); }
.cast-avatar.absent-av .cast-avatar-img {
  opacity: 0.5;
  filter: grayscale(100%);
}
/* gray-500, not gray-400: the avatar's white initials need 4.5:1 against this
   fill (gray-400 was only 3.33:1 — WCAG audit 2026-07). */
.cast-avatar.no-pkt { background: var(--ucb-gray-500); }
.cast-name { font-size: 13px; font-weight: 600; }
.cast-status {
  font-size: 10px;
  font-weight: 700;
  margin-top: 2px;
  padding: 1px 6px;
  border-radius: 3px;
  display: inline-block;
}
.cast-status.present { background: rgba(16, 185, 129, 0.1); color: var(--ucb-green-dark); }
.cast-status.absent-s { background: rgba(239, 68, 68, 0.1); color: var(--ucb-red-dark); }
.cast-status.no-pkt-s {
  background: rgba(245, 158, 11, 0.1);
  color: var(--ucb-amber-dark);
  font-size: 9px;
  margin-left: 4px;
}

/* Livestream panel */
.recap-livestream-panel {
  border-left: 3px solid var(--ucb-brand);
  margin-bottom: 24px;
}
.recap-ls-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--ucb-red);
  flex-shrink: 0;
}
.recap-ls-url {
  font-size: 14px;
  font-weight: 600;
  color: var(--ucb-gray-700);
  text-decoration: none;
}
.recap-ls-url:hover { text-decoration: underline; }

/* Show notes block */
.recap-notes-inner {
  padding: 18px;
  border-left: 3px solid var(--ucb-amber);
  background: rgba(245, 158, 11, 0.03);
  border-radius: 0 var(--ucb-radius-sm) var(--ucb-radius-sm) 0;
  font-size: 13px;
  line-height: 1.6;
}
.recap-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.recap-chip {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 100px;
  font-size: 11px;
  font-weight: 600;
  border: 1px solid var(--ucb-gray-200);
  background: white;
  color: var(--ucb-gray-500);
}
.recap-chip.checked {
  background: rgba(16, 185, 129, 0.1);
  color: var(--ucb-green-dark);
  border-color: rgba(16, 185, 129, 0.3);
}

/* Send block */
.recap-send-block {
  text-align: center;
  padding: 30px 20px 10px;
}
.recap-send-btn {
  /* green-dark, not green: white button text needs 4.5:1 against this fill
     (base green was only 2.54:1 — WCAG audit 2026-07). Hover below moves one
     step darker still (emerald-800) so the hover-darken feedback survives. */
  background: var(--ucb-green-dark) !important;
  color: white !important;
  border-color: var(--ucb-green-dark) !important;
  padding: 14px 40px !important;
  font-size: 15px !important;
  border-radius: 10px !important;
}
.recap-send-btn:hover {
  background: #065f46 !important;
}
/* Re-send: the recap already went out, so sending again is the SECONDARY
   action — outline, not fill, so the "✓ Recap Sent" chip stays the headline.
   (Green-dark on white is 5.6:1.) */
.recap-send-btn.is-resend {
  background: transparent !important;
  color: var(--ucb-green-dark) !important;
  border: 1px solid var(--ucb-green-dark) !important;
  padding: 10px 24px !important;
  font-size: 13px !important;
}
.recap-send-btn.is-resend:hover {
  background: rgba(16, 185, 129, 0.08) !important;
}
.recap-sent-btn {
  background: var(--ucb-gray-100) !important;
  color: var(--ucb-gray-600) !important;
  border-color: var(--ucb-gray-200) !important;
  padding: 14px 40px !important;
  font-size: 15px !important;
  border-radius: 10px !important;
  cursor: default !important;
}
.recap-send-info {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin-top: 8px;
}
.recap-send-info a {
  color: var(--ucb-gray-500);
  text-decoration: underline;
}
.recap-sent-time {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin-top: 4px;
}
.recap-send-warning {
  padding: 14px 20px;
  background: rgba(245, 158, 11, 0.08);
  border: 1px solid rgba(245, 158, 11, 0.25);
  border-radius: var(--ucb-radius-sm);
  color: var(--ucb-amber-dark);
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 12px;
}
.recap-send-warning a {
  color: var(--ucb-brand);
  text-decoration: underline;
}

/* ── Unified Recap Email card (recipients + send in one panel) ── */
.recap-email-card {
  padding: 18px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius);
  background: var(--ucb-gray-50);
  margin-bottom: 18px;
}
.recap-email-card-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ucb-gray-800);
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--ucb-gray-200);
}
/* Send controls sit in the same card, below the recipient summary.
   Flex column (not plain block) so the "Send Again" button can be ORDERED
   below the sent chip + timestamp + "view sent email" line without moving it
   in the DOM — in the not-yet-sent state it's the primary button and must
   stay first. */
.recap-send-row {
  margin-top: 16px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
.recap-send-row .recap-send-btn,
.recap-send-row .recap-sent-btn {
  width: 100%;
  box-sizing: border-box;
}
.recap-send-row .recap-send-warning { order: -2; margin-bottom: 0; }
.recap-send-row .recap-sent-btn     { order: -1; }
/* Re-send drops below the sent state's timestamp + meta line. */
.recap-send-row .recap-send-btn.is-resend { order: 5; width: auto; align-self: center; }
.recap-send-row .recap-send-info,
.recap-send-row .recap-sent-time,
.recap-send-row .recap-sent-meta { margin-top: 0; }
/* Empty text rows would still take a flex gap. */
.recap-send-row .recap-send-info:empty { display: none; }

/* ── Review & Send modal: recipient summary strip ── */
.recap-modal-recipients {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--ucb-gray-200);
}
.recap-modal-recipients:empty { display: none; }
.recap-modal-recipients-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ucb-gray-600);
}
.recap-modal-recipients .setup-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* ── Review & Send modal: test-address toggle row ── */
.recap-modal-testrow {
  padding: 10px 20px 12px;
  border-top: 1px solid var(--ucb-gray-200);
}
.recap-test-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ucb-gray-600);
  cursor: pointer;
}
.recap-test-input-wrap {
  margin-top: 8px;
}
.recap-test-input-wrap .setup-input {
  max-width: 320px;
}

/* Preview modal */
.recap-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.recap-modal {
  background: white;
  border-radius: var(--ucb-radius);
  max-width: 700px;
  width: 100%;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
.recap-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--ucb-gray-200);
  font-weight: 700;
  font-size: 14px;
}
.recap-modal-close {
  background: none;
  border: none;
  font-size: 22px;
  cursor: pointer;
  color: var(--ucb-gray-500);
  padding: 0 4px;
}
.recap-modal-close:hover { color: var(--ucb-gray-800); }
.recap-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 0;
}
.recap-modal-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--ucb-gray-200);
}
.recap-modal-footer-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

/* Editing-mode warning banner inside the Review & Send modal. */
.recap-edit-warning {
  padding: 10px 20px;
  background: #fffbeb;
  border-bottom: 1px solid #fde68a;
  color: #78350f;
  font-size: 12.5px;
  line-height: 1.45;
}
.recap-edit-warning strong { color: #92400e; }

/* Re-send warning banner — shown only when this recap already went out once,
   so nobody sends producers/finance a duplicate without noticing. */
.recap-resend-notice {
  padding: 10px 20px;
  background: rgba(245, 158, 11, 0.08);
  border-bottom: 1px solid rgba(245, 158, 11, 0.35);
  color: var(--ucb-amber-dark);
  font-size: 12.5px;
  line-height: 1.45;
}
.recap-resend-notice strong { color: var(--ucb-amber-dark); }

/* The editable email body region — a dashed outline + soft tint makes it
   obvious which part is being edited (the header/footer are locked). */
.ucb-recap-body.is-editing {
  outline: 2px dashed var(--ucb-amber);
  outline-offset: -2px;
  background: rgba(245, 158, 11, 0.04);
}
.ucb-recap-body.is-editing:focus { outline-color: var(--ucb-brand); }

/* "Last sent by … · View sent email" line under the send button. */
.recap-sent-meta {
  margin-top: 6px;
  font-size: 12px;
  color: var(--ucb-gray-500);
  text-align: center;
}
.recap-sent-meta .recap-view-sent {
  color: var(--ucb-brand);
  font-weight: 600;
  text-decoration: none;
}
.recap-sent-meta .recap-view-sent:hover { text-decoration: underline; }

@media (max-width: 900px) {
  .stats-grid-5 { grid-template-columns: repeat(2, 1fr); }
  .cast-grid { grid-template-columns: 1fr 1fr; }
}

/* ── 21d. Final Recap Tab ──────────────────────────────────── */

/* ── Payout reconciliation ledger ──────────────────────────
   The performer pool and what actually gets paid are two different numbers.
   Reads left→right as an equation: pool → paid out → difference. The third
   cell carries the state, so "is this show balanced?" is answerable at a
   glance without reading the narrative. */
.payout-ledger {
  display: grid;
  grid-template-columns: 1fr 1fr 1.2fr;
  gap: 1px;
  background: var(--ucb-gray-200);
  border: 1px solid var(--ucb-gray-200);
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 14px;
}
.payout-ledger-cell {
  background: #fff;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.payout-ledger-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* gray-500, not gray-400: at 10px this is small text and needs 4.5:1.
     gray-400 measured 1.93:1 on the flagged cell (2026-07 WCAG re-check). */
  color: var(--ucb-gray-500);
}
.payout-ledger-value {
  font-size: 20px;
  font-weight: 700;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  color: var(--ucb-gray-700);
}
.payout-ledger-sub {
  font-size: 11px;
  color: var(--ucb-gray-500);
  line-height: 1.35;
}
/* Third cell states — colour only ever means the difference, never the inputs.
   The tint MUST be opaque: `background` replaces the cell's own #fff, so a
   semi-transparent value composites over .payout-ledger's gray-200 backdrop
   (the grid-gap colour) instead of white — which rendered a muddy #e3dfdc and
   dropped the amber to 2.41:1. Flat colour = amber at 5% over white. */
.payout-ledger-cell.is-balanced .payout-ledger-value { color: var(--ucb-green-dark); }
.payout-ledger-cell.is-flagged  .payout-ledger-value { color: var(--ucb-amber-dark); }
.payout-ledger-cell.is-flagged {
  background: #fdf8f3;
  box-shadow: inset 3px 0 0 var(--ucb-amber);
}
.payout-ledger-cell.is-balanced { box-shadow: inset 3px 0 0 var(--ucb-green); }
@media (max-width: 640px) {
  .payout-ledger { grid-template-columns: 1fr; }
}

/* "Someone typed this number" marker. Shown on manual amounts only — the
   even split is the system's default and needs no badge.

   The tag is taken OUT of flow and hung to the left of the figure. Inline it
   pushed the amount off the column's right edge, so tagged rows no longer
   lined up with each other or with the Total underneath. Absolute positioning
   keeps every figure on one axis whether or not it carries a tag. */
.share-amount {
  position: relative;
  display: inline-block;
}
.amount-set-tag {
  position: absolute;
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 8px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ucb-gray-500);
}
/* An amount that was entered but isn't being paid (performer not present, or
   To Be Paid unchecked). Struck through so the money is visibly accounted for
   rather than silently missing from the total. */
.amount-withheld {
  text-decoration: line-through;
  color: var(--ucb-gray-600);
  font-weight: 600;
}

/* Narrative box */
.final-narrative {
  padding: 14px 18px;
  margin-bottom: 14px;
  background: rgba(139, 32, 37, 0.04);
  border: 1px solid rgba(139, 32, 37, 0.12);
  border-radius: 10px;
  font-size: 13px;
  color: var(--ucb-gray-600);
  line-height: 1.6;
}

/* Performer cell */
.performer-cell {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
}
.performer-cell .cast-avatar {
  width: 32px;
  height: 32px;
  font-size: 12px;
  flex-shrink: 0;
}

/* Payment status badges */
.pay-status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 100px;
  white-space: nowrap;
}

/* Recipients block */
.final-recipients-block {
  padding: 18px;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius);
  margin-bottom: 18px;
  background: var(--ucb-gray-50);
}
.final-routing-text {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin-top: 8px;
}

/* "Manage on Show Setup" note under a recap's recipient pill row */
.recap-recipients-note {
  font-size: 12px;
  color: var(--ucb-gray-600);
  margin-top: 10px;
}
.recap-recipients-note a {
  font-weight: 600;
}
/* Attendee-list download, below the send row: a secondary affordance, so it sits
   under a rule rather than competing with the send button. */
.recap-attach-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--ucb-gray-200);
}
.recap-attach-note {
  flex: 1 1 260px;
  min-width: 0;
  font-size: 12px;
  color: var(--ucb-gray-600);
  line-height: 1.45;
}

/* Audit info */
.final-audit-info {
  padding: 18px;
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.04) 0%, rgba(139, 32, 37, 0.04) 100%);
  border: 1px solid rgba(59, 130, 246, 0.12);
  border-radius: var(--ucb-radius);
  margin-bottom: 18px;
}

/* Inline recoupment edit */
.final-recoup-cell:hover {
  background: var(--ucb-gray-50);
  border-radius: 4px;
}

/* Recoupment split row in the Performer Split Calculation table.
   Display-only — editing now lives on the Setup tab > Payment Terms. */
.recoup-split-cell {
  padding-top: 6px;
}
.recoup-split-label {
  display: inline-block;
  font-size: 13px;
  color: var(--ucb-gray-900);
}
.recoup-split-hint {
  display: inline-block;
  margin-left: 8px;
  font-size: 12px;
  color: var(--ucb-gray-500);
  font-style: italic;
}

/* Payment Terms panel on the Setup tab */
.setup-payment-terms-panel {
  margin-top: 16px;
}
.setup-payment-terms-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.setup-field-help {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ucb-gray-600);
  line-height: 1.5;
}
.setup-field-help-sm {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  color: var(--ucb-gray-600);
  line-height: 1.4;
}

/* Show Info tab — edit core post fields (title, date/time, image,
   description, taxonomies) inline on the dashboard. */
/* One field per ROW. Three columns fitted the fields into roughly a third of
   the panel each, which is narrower than the value they hold: flatpickr's
   altInput renders "Sun, Aug 16, 2026 at 8:00 PM" and it was being clipped
   mid-date, so neither the start nor the end could be read at a glance — on a
   panel with plenty of width to spare. Duration keeps a cap because it holds
   at most three digits. */
.show-info-datetime-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-bottom: 4px;
}
.show-info-duration-cell .setup-input {
  max-width: 160px;
}
.show-info-livestream-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 720px) {
  .show-info-livestream-grid {
    grid-template-columns: 1fr;
  }
}
.show-info-radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 6px 0;
}
.show-info-radio {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ucb-gray-900);
  cursor: pointer;
}
.show-info-toggles {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.show-info-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ucb-gray-900);
  cursor: pointer;
}

/* ── Permalink row (Event_Slug) ──────────────────────────────────────
   Sits under Show Title inside the same panel, but is a separate action
   with its own endpoint and confirm — hence its own visual separation.

   NOTE the [hidden] guards on every flex/grid container here: an author
   `display` beats the UA rule behind the `hidden` ATTRIBUTE, so without
   them `el.hidden = true` silently no-ops (CLAUDE.md convention 33). */
.show-info-permalink {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--ucb-gray-200);
}
.show-info-permalink[hidden] { display: none; }

.show-info-permalink-view {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.show-info-permalink-view[hidden] { display: none; }

.show-info-permalink-url {
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--ucb-gray-700);
  /* Long show slugs must wrap rather than stretch the panel. */
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}
/* Draft/private URLs aren't publicly reachable, so the JS drops the href;
   make it read as text rather than a dead link. */
.show-info-permalink-url.is-inert {
  text-decoration: none;
  cursor: default;
  color: var(--ucb-gray-600);
}

.show-info-permalink-stale {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
  padding: 8px 10px;
  font-size: 12px;
  line-height: 1.45;
  color: #7a4b00;
  background: #fff8e6;
  border: 1px solid #f0d089;
  border-radius: 4px;
}
.show-info-permalink-stale[hidden] { display: none; }
.show-info-permalink-stale-text { flex: 1 1 260px; min-width: 0; }

.show-info-permalink-editor {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
}
.show-info-permalink-editor[hidden] { display: none; }

/* The slug field gets its OWN full-width line rather than being squeezed
   between prefix and suffix the way wp-admin does it — show slugs are long
   (title + date), and a narrow box hides most of what you're editing. The
   line above it is a live preview of the whole resulting URL. */
.show-info-permalink-inputs {
  display: block;
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--ucb-gray-600);
  cursor: text;
}
.show-info-permalink-fix {
  display: block;
  margin-bottom: 4px;
  /* The preview holds a full URL — let it wrap instead of stretching the
     panel or clipping the end. */
  overflow-wrap: anywhere;
  word-break: break-word;
  line-height: 1.4;
}
.show-info-permalink-fix:empty { display: none; }
.show-info-permalink-input.show-info-permalink-input {
  /* Doubled class so this beats .setup-input's own sizing without
     !important. */
  display: block;
  width: 100%;
  max-width: none;
  font-family: inherit;
  font-size: 13px;
}

.show-info-permalink-redirect {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ucb-gray-900);
  cursor: pointer;
}
.show-info-permalink-redirect[hidden] { display: none; }

.show-info-permalink-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.show-info-permalink-actions[hidden] { display: none; }
/* Buttons ship hidden and are revealed per state — same [hidden] trap as
   the containers above, and .btn carries a display of its own. */
.show-info-permalink-btn[hidden] { display: none; }

.show-info-permalink-note {
  display: block;
  font-size: 11px;
  line-height: 1.4;
  color: var(--ucb-gray-600);
}
.show-info-permalink-note[hidden] { display: none; }
.show-info-permalink-note.is-error {
  color: var(--ucb-red-dark);
  font-weight: 500;
}

/* Accounting Inputs panel on Final Recap — two columns for the
   short text fields, full-width row for payment notes. */
/* Three money fields across one row, Payment Notes full width beneath.
   They hold at most a few digits, so a half-width box was mostly empty and
   pushed the notes further down the panel. Payment Notes carries the
   `grid-column: 1 / -1` inline, so it spans whatever this row count is. */
.final-accounting-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  padding: 0 18px 12px;
}
@media (max-width: 1024px) {
  .final-accounting-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .final-accounting-grid { grid-template-columns: 1fr; }
}
/* Only Recoupment carries a helper line; without this its neighbours' inputs
   stretch to match its taller cell. */
.final-accounting-grid .setup-field {
  align-content: start;
}
.final-accounting-grid .setup-field-help {
  margin: 4px 0 0;
  font-size: 11px;
  line-height: 1.4;
}
@media (max-width: 720px) {
  .final-accounting-grid {
    grid-template-columns: 1fr;
  }
}
/* The helper line under Recoupment would otherwise stretch its grid row and
   leave the two neighbours' inputs vertically misaligned. */
.final-accounting-grid .setup-field {
  align-content: start;
}
/* A per-performer amount that the server refused. The field keeps the typed
   figure (losing it would be worse than showing it unsaved), so it has to
   look unsaved — and carry aria-invalid, which is what actually reaches a
   screen reader. Contrast comes from the -dark token tier per convention 46;
   --ucb-red is a fill/border colour, never text. */
.talent-amount-input[aria-invalid="true"] {
  border-color: var(--ucb-red);
  background: rgba(239, 68, 68, 0.06);
}

/* Accounting Inputs save bar. Deliberately NOT .setup-save-bar: that one is
   sticky to the viewport bottom because it closes a whole-tab form, and this
   closes one section partway down a long report — a bar that followed the
   scroll here would hover over unrelated figures. */
.final-accounting-save-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  padding: 0 18px 4px;
}
/* `.btn` is width:100%/display:block by default (only .btn-secondary opts
   out), which stretched this one into a full-width slab across a three-column
   form. The whole-tab save bars want that; a section-level one does not. */
.final-accounting-save-bar .btn {
  width: auto;
  display: inline-block;
  padding: 10px 22px;
}
.final-accounting-save-bar .setup-save-status {
  margin-bottom: 0;
}

/* Deductions row under the Performer Split table: the Recoupment field and
   the Add Special Payment Role button, the two controls that change the
   calculation, kept beside the calculation they change. */
/* Right-aligned action in a .recap-section-head (that rule is already
   display:flex, so margin-left:auto is all it takes). Used by
   + Add Special Payment Role: it adds a line to the table below, so it reads
   as a section action rather than loose furniture under the card. */
.recap-head-action {
  margin-left: auto;
  flex-shrink: 0;
}
/* The inline add-a-role form drops in below the head, above the table. */
.final-add-role-form {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 12px;
  padding: 12px 14px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm, 8px);
}
.final-add-role-form.hidden {
  display: none;
}

/* Caption under the two Netsuite passthrough fields. Sits with the grid it
   describes (the old rule had its own 18px padding and floated free of it). */
.final-accounting-caption {
  margin: -4px 18px 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ucb-gray-500);
}
.final-accounting-caption code {
  font-size: 10.5px;
}

/* Payment Notes log (Final Recap). Append-only list + composer; mirrors the
   event notes log's reading order (newest first) and vocabulary. */
.final-payment-notes {
  padding: 0 18px;
}
.final-payment-notes-hint {
  margin: 0 0 10px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ucb-gray-500);
}
.final-payment-notes-compose {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 12px;
}
.final-payment-notes-compose textarea {
  flex: 1;
  min-height: 44px;
}
.final-payment-notes-compose .btn {
  flex-shrink: 0;
}
.final-payment-notes-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.final-pn-entry {
  padding: 8px 10px;
  border-left: 3px solid var(--ucb-gray-300);
  background: var(--ucb-gray-50, #fafafa);
  border-radius: 0 4px 4px 0;
}
/* Migrated rows are the pre-2.33.0 free-text field carried over wholesale —
   greyed so they read as provenance rather than as somebody's note. */
.final-pn-entry.is-legacy {
  border-left-color: var(--ucb-gray-200, #e5e5e5);
}
.final-pn-entry.is-legacy .final-pn-meta {
  font-style: italic;
}
.final-pn-meta {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 11px;
  color: var(--ucb-gray-500);
  margin-bottom: 3px;
}
.final-pn-actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
}
.final-pn-act {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--ucb-gray-600);
  text-decoration: underline;
  cursor: pointer;
}
.final-pn-act:hover {
  color: var(--ucb-brand, #8B2025);
}
.final-pn-act--danger:hover {
  color: var(--ucb-red, #dc2626);
}
.final-pn-note {
  font-size: 13px;
  color: var(--ucb-gray-900);
  white-space: pre-wrap;
}
.final-pn-empty {
  margin: 0;
  font-size: 12px;
  color: var(--ucb-gray-500);
}

.show-info-image-wrap {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.show-info-image-preview {
  width: 100%;
  min-height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ucb-gray-50);
  border: 1px dashed var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 8px;
}
.show-info-image-empty {
  color: var(--ucb-gray-500);
  font-size: 12px;
  font-style: italic;
}
.show-info-image-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* Description textarea — TinyMCE replaces this, but on first load and
   in fallback mode (TinyMCE failed to init) it shows as a plain textarea
   with monospace styling so HTML is readable. */
.show-info-description {
  font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  min-height: 200px;
}

/* Hierarchical taxonomy checkbox trees */
.show-info-tax-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
@media (max-width: 900px) {
  .show-info-tax-grid {
    grid-template-columns: 1fr;
  }
}
.show-info-tax-col .setup-field-label {
  margin-bottom: 6px;
}
.show-info-tax-tree {
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
  padding: 8px 10px;
  background: var(--ucb-gray-50);
}
.show-info-tax-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ucb-gray-900);
  padding: 3px 0;
  cursor: pointer;
}
.show-info-tax-item input[type="checkbox"] {
  margin: 0;
  flex-shrink: 0;
}
.show-info-tax-empty {
  margin: 4px 0;
  font-size: 12px;
  font-style: italic;
  color: var(--ucb-gray-500);
}

/* Top-of-page indeterminate progress bar — added by the JS submit
   handler when a report filter form is submitted, so the user sees an
   immediate signal that something's happening while the browser does
   a full-page navigation. Removed by the page reload itself. */
body.ucb-page-loading::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 99999;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--ucb-brand) 20%,
    var(--ucb-amber) 50%,
    var(--ucb-brand) 80%,
    transparent 100%);
  background-size: 200% 100%;
  animation: ucb-loading-bar 1.2s ease-in-out infinite;
}
@keyframes ucb-loading-bar {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* Lock-with-edit pattern for contract fields (Payment Cycle, Recoup
   Split, Prepay Amount). The locked row shows the saved value next
   to a small pencil button; clicking the pencil reveals the input. */
.ucb-lockable-locked {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-200);
  border-radius: var(--ucb-radius-sm);
}
.ucb-lockable-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--ucb-gray-900);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ucb-lockable-edit-btn {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  color: var(--ucb-brand);
  background: transparent;
  border: 1px solid transparent;
  padding: 4px 8px;
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
}
.ucb-lockable-edit-btn:hover,
.ucb-lockable-edit-btn:focus {
  color: var(--ucb-brand-dark, #6B181C);
  background: rgba(139, 32, 37, 0.06);
  border-color: rgba(139, 32, 37, 0.18);
  outline: none;
}
.ucb-lockable-editable {
  display: block;
}
.ucb-lockable-editable.hidden,
.ucb-lockable-locked.hidden {
  display: none;
}

/* Cross-tab links — small inline pointers between Setup ↔ Final Recap
   sections so the contract-vs-post-show split doesn't force tab-hunting. */
.ucb-dashboard-tab-link {
  color: var(--ucb-brand);
  text-decoration: none;
  border-bottom: 1px dashed currentColor;
  font-weight: 500;
}
.ucb-dashboard-tab-link:hover,
.ucb-dashboard-tab-link:focus {
  color: var(--ucb-brand-dark, #6B181C);
  border-bottom-style: solid;
}

/* Add special role form: see .final-add-role-form near .recap-head-action —
   it moved up there when the button became a section-head action. */

/* Screen reader only utility */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── 22. Select2 Overrides (scoped) ────────────────────────── */
#shows-dashboard .select2-container {
  width: 100% !important;
  max-width: 100%;
}
/* ⚠ …except inside the picker group, where the select shares one pill with
   the Browse segment. `width: 100% !important` made the select claim the
   group's ENTIRE width, so Browse had nowhere to sit and hung off the right
   edge — 115px past the header on a 380px viewport, taking the whole page
   into horizontal scroll. It needs the same !important to be undone. */
#shows-dashboard .event-picker-group .select2-container {
  width: auto !important;
  flex: 1 1 auto;
  min-width: 0;
}

/* On a phone the two segments stack: the select keeps the full width (it is
   the thing you are actually reading — a truncated show title in a half-width
   pill is useless), and Browse drops to its own full-width row underneath.
   Squeezing both onto one line left the title showing four words. */
@media (max-width: 640px) {
  .event-picker-group { flex-wrap: wrap; }
  #shows-dashboard .event-picker-group .select2-container { flex: 1 1 100%; }
  /* Both halves of the shared pill get their corners back once stacked. */
  .event-picker-group .select2-container--default .select2-selection--single {
    border-top-right-radius: var(--ucb-radius-sm);
    border-bottom-right-radius: var(--ucb-radius-sm);
    border-right: 1px solid rgba(255, 255, 255, 0.22);
  }
  .browse-shows-btn {
    flex: 1 1 100%;
    justify-content: center;
    margin-top: 6px;
    padding: 9px 16px;
    border-left: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--ucb-radius-sm);
  }
}
#shows-dashboard .select2-selection__rendered {
  white-space: normal !important;
  word-break: break-word;
  line-height: 1.2em;
  padding-top: 0.5em;
  padding-bottom: 0.5em;
}
/* ⚠ …except the event picker, which must stay ONE line with an ellipsis.
   The blanket `white-space: normal !important` above carries an !important
   the picker's own rule (§ "Event picker input group") does not, so on a
   narrow screen a long show title wrapped to three lines, grew the pill past
   its 40px height and pushed the header out of shape. Overriding needs the
   same !important — this is not a specificity fight that can be won without
   it. */
#shows-dashboard .event-picker-row .select2-selection__rendered {
  white-space: nowrap !important;
  word-break: normal;
  line-height: 38px;
  padding-top: 0;
  padding-bottom: 0;
}
#shows-dashboard .select2-container--default .select2-selection--single {
  min-height: auto !important;
  height: auto !important;
}
#shows-dashboard .select2-results > .select2-results__options {
  max-height: 50vh;
}
#shows-dashboard .select2-container ul {
  margin-left: 0;
  list-style: none;
}
.shows-dashboard-dropdown .select2-search__field {
  color: #000 !important;
}
.shows-dashboard-dropdown .select2-results__option span {
  font-weight: 400;
  font-size: 14px;
}
.shows-dashboard-dropdown .select2-results__option--highlighted[aria-selected] {
  background: var(--ucb-brand) !important;
}
.shows-dashboard-dropdown .select2-results__option--highlighted[aria-selected] span {
  color: #fff !important;
}
#shows-dashboard .select2-results__group {
  font-size: 14px;
  font-weight: bold;
  color: var(--ucb-gray-500);
  background: var(--ucb-gray-50);
  padding: 10px;
  margin: 0;
  text-transform: uppercase;
  border-top: 1px solid var(--ucb-gray-300);
  border-bottom: 1px solid var(--ucb-gray-300);
}
#shows-dashboard .select2-results .select2-results__options--nested li:nth-child(even) {
  border-top: 1px solid var(--ucb-gray-100);
  border-bottom: 1px solid var(--ucb-gray-100);
}

/* ── 24. Responsive ────────────────────────────────────────── */
/* ── Tablet (≤900px) ── */
@media (max-width: 900px) {
  .content-grid {
    grid-template-columns: 1fr;
  }
  /* Stack check-in panels on small screens: QR first, then audience, then notes.
     `.checkin-layout-left` becomes display:contents so its children flex-order in the parent. */
  #shows-dashboard .checkin-layout {
    display: flex !important;
    flex-direction: column !important;
    gap: 0 !important;
    width: 100% !important;
  }
  #shows-dashboard .checkin-layout > .checkin-layout-left {
    display: contents !important;
    flex: initial !important;
    width: auto !important;
  }
  #shows-dashboard .checkin-layout > #audience-panel,
  #shows-dashboard .checkin-layout > .checkin-layout-left > .panel {
    flex: initial !important;
    margin-bottom: 18px !important;
    width: 100% !important;
  }
  /* Mobile render order: QR → Audience → Manual Ticket → Notes.
     Manual ticket moves after the audience list so the primary
     check-in list stays near the top of the screen; door staff who
     need to create a manual ticket scroll down a bit for it. */
  #shows-dashboard .checkin-layout > .checkin-layout-left > #qr-panel           { order: 1 !important; }
  #shows-dashboard .checkin-layout > #audience-panel                            { order: 2 !important; }
  #shows-dashboard .checkin-layout > .checkin-layout-left > #manual-ticket-form { order: 3 !important; }
  #shows-dashboard .checkin-layout > .checkin-layout-left > #notes-panel        { order: 4 !important; }
  .stats-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .event-selector {
    padding: 10px 16px;
  }
  .event-select {
    min-width: 0;
    width: 100%;
  }
  .tab-content {
    padding: 20px 16px 40px;
  }
  .page-header {
    padding: 16px 0 0;
  }
  .header-inner {
    padding: 0 16px;
  }
  .stats-strip {
    padding: 0;
  }
  .search-input {
    font-size: 16px; /* prevent iOS zoom */
  }
  .audience-name-full {
    font-size: 15px;
  }
  .talents-wrap {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .talent-tab-body {
    padding: 12px;
  }
  .header-actions {
    flex-wrap: wrap;
    gap: 6px;
  }
}

/* ── Mobile (≤600px) ── */
@media (max-width: 600px) {
  /* Event selector full width */
  .event-selector {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    padding: 8px 12px;
  }

  /* Header stacks vertically */
  .header-top {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .header-actions {
    width: 100%;
    justify-content: flex-start;
  }
  #shows-dashboard .show-title {
    font-size: 20px;
  }
  .show-meta {
    gap: 8px;
    font-size: 12px;
  }
  .logo-sub {
    display: none;
  }
  .logo-divider {
    display: none;
  }

  /* Tab-strip scrolling and .main-tab sizing moved to §25a (2026-09-06) —
     the swipe-scroll rule was one of four near-identical copies, and the
     10px/9px type here was the "why is the tab row tiny?" bug. */

  /* Tab content tighter padding */
  .tab-content {
    padding: 16px 12px 50px;
  }

  /* Stat cards 2×2 on mobile */
  .stats-grid {
    grid-template-columns: 1fr 1fr;
  }
  .stat-card {
    padding: 12px 14px;
    border-right: 1px solid var(--ucb-gray-100);
    border-bottom: 1px solid var(--ucb-gray-100);
  }
  .stat-card:nth-child(2n) {
    border-right: none;
  }
  .stat-card:nth-last-child(-n+2) {
    border-bottom: none;
  }
  .stat-card:last-child {
    border-right: none;
  }
  .stat-value {
    font-size: 24px;
  }
  .stat-label {
    font-size: 9px;
  }

  /* SKU breakdown wraps nicely */
  .sku-breakdown {
    padding: 0 0 8px;
  }
  .sku-chip {
    font-size: 11px;
    padding: 3px 8px;
  }

  /* Search bar */
  .search-bar {
    padding: 10px 12px;
  }

  /* Audience filter pills — All / Checked In / Not Arrived. Scrolling is
     §25a's job now; this is sizing. These are pressed with a thumb, mid-show,
     one-handed: 10px type in a 22px-tall pill was the smallest target on the
     busiest screen in the dashboard. */
  .audience-tabs {
    padding: 8px 12px;
    gap: 6px;
  }
  .a-tab {
    min-height: 36px;
    font-size: 12px;
    padding: 0 14px;
    display: inline-flex;
    align-items: center;
  }

  /* Audience list edge-to-edge on mobile */
  .audience-list {
    margin: 0 0 12px;
    border-left: none;
    border-right: none;
    border-radius: 0;
  }
  /* Audience rows — compact single line with tap target on right */
  .audience-row {
    flex-wrap: nowrap;
    gap: 10px;
    padding: 10px 12px;
    align-items: center;
  }
  .audience-num {
    display: none;
  }
  .audience-name-full {
    font-size: 14px;
  }
  .audience-name-email {
    font-size: 11px;
  }
  /* Bigger tap target on touch devices */
  .checkin-btn {
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
  }
  .audience-time {
    min-width: 34px;
    font-size: 11px;
  }
  .state-legend {
    padding: 12px 12px 14px;
  }
  .state-legend-items {
    flex-direction: column;
    gap: 10px;
  }

  /* Panel headers */
  .panel-header {
    padding: 10px 12px;
    flex-wrap: wrap;
    gap: 6px;
  }

  /* QR scanner fills width */
  #qr_code {
    padding: 14px;
    min-height: 140px;
  }

  /* Collapse toggle */
  .collapse-toggle {
    padding: 10px 12px;
  }

  /* Notes */
  .notes-body {
    padding: 12px;
  }

  /* Manual ticket form */
  .create-ticket-form {
    padding: 12px;
  }
  .create-ticket-form-wrapper {
    gap: 8px;
  }

  /* Floating summary bar — port of the legacy plugin's v2.1.5 mobile
     fix. flex: 1 1 0 + min-width: 0 lets the three cells share width
     equally and actually shrink below their content's natural size
     (default min-width: auto wouldn't); white-space: nowrap inherited
     from the base rule keeps each cell to one line; padding tightened
     so 4-5 digit totals fit on a 320px phone. */
  .floating-summary {
    padding: 0;
    box-sizing: border-box;
  }
  .floating-summary .summary-row {
    font-size: 14px;
    width: 100%;
    justify-content: space-between;
    min-width: 0;
  }
  .floating-summary .summary-row span {
    padding: 6px 6px;
    flex: 1 1 0;
    min-width: 0;
  }

  /* Mode toggle compact */
  #mode-toggle-container {
    font-size: 10px !important;
  }

  /* Panels reduce radius on mobile for edge-to-edge feel */
  .panel {
    border-radius: var(--ucb-radius-sm);
  }
}

/* ── Small phone (≤400px) ── */
@media (max-width: 400px) {
  .stats-grid {
    grid-template-columns: 1fr 1fr;
  }
  .stat-value {
    font-size: 20px;
  }
  .audience-row {
    padding: 8px 10px;
    gap: 8px;
  }
  .audience-type {
    padding: 2px 8px;
    font-size: 9px;
  }
  .checkin-btn {
    flex: 0 0 38px;
    width: 38px;
    height: 38px;
  }
  .btn {
    padding: 6px 12px;
    font-size: 11px;
  }
}

/* ════════════════════════════════════════════════════════════
   25. Mobile pass (2026-09-06)
   ════════════════════════════════════════════════════════════
   Phone corrections to the desktop layout above, kept as ONE block on
   purpose. The dashboard renders ten tab strips, several filter rows and a
   dozen data tables that all failed the same handful of ways on a phone;
   written per feature, those fixes drift apart within a release.
   Everything here is additive — nothing above changes shape at desktop
   widths.
   Breakpoints used: 900px = "narrow enough that the chrome must adapt",
   700px = phone. Both already exist above; no new ones introduced.
   ════════════════════════════════════════════════════════════ */

/* ── 25a. Tab strips — ONE scrollable pattern for all ten ─────
   .main-tabs, the seven sub-navs, Day View's inner nav and the timecards
   strip all render more tabs than a phone is wide, and before this they
   behaved three different ways: .main-tabs and .reports-subnav swiped,
   .shows-subnav swiped only under 720px, and .settings-subnav /
   .talent-subnav / .holds-subnav / .dv-subnav / .tc-subnav /
   .ucb-od-subnav simply CLIPPED — measured 1,164px of Settings tabs in a
   324px row, with everything past "Emails" unreachable on a phone.
   (.audience-tabs rides along: not a tablist, but the same three pills in
   the same kind of row.)
   This is the one place the pattern lives. A new tab strip joins the
   selector list; it does not get its own copy.
   Note .dayview-subnav / .dv-subnav / .holds-subnav are declared in
   shows-dashboard-day-view.css and -calendar.css, which both load AFTER
   this file — safe, because neither declares overflow, so there is nothing
   here for them to override. */
.main-tabs,
.shows-subnav,
.settings-subnav,
.reports-subnav,
.talent-subnav,
.dayview-subnav,
.dv-subnav,
.holds-subnav,
.tc-subnav,
.ucb-od-subnav,
.audience-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  /* Spelled out rather than left at the default: `overflow-y: visible`
     beside a non-visible overflow-x computes to `auto`, which would make
     the strip a vertical scroller too and let a swipe rubber-band it. */
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  /* Don't hand the swipe to the page (or to Safari's back gesture) once the
     strip hits its end. */
  overscroll-behavior-x: contain;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
@media (prefers-reduced-motion: reduce) {
  .main-tabs,
  .shows-subnav,
  .settings-subnav,
  .reports-subnav,
  .talent-subnav,
  .dayview-subnav,
  .dv-subnav,
  .holds-subnav,
  .tc-subnav,
  .ucb-od-subnav,
  .audience-tabs {
    scroll-behavior: auto;
  }
}
.main-tabs::-webkit-scrollbar,
.shows-subnav::-webkit-scrollbar,
.settings-subnav::-webkit-scrollbar,
.reports-subnav::-webkit-scrollbar,
.talent-subnav::-webkit-scrollbar,
.dayview-subnav::-webkit-scrollbar,
.dv-subnav::-webkit-scrollbar,
.holds-subnav::-webkit-scrollbar,
.tc-subnav::-webkit-scrollbar,
.ucb-od-subnav::-webkit-scrollbar,
.audience-tabs::-webkit-scrollbar {
  display: none;
}
/* A flex child's default min-width:auto lets a long label squash its
   neighbours instead of extending the scroll. */
.main-tabs > *,
.shows-subnav > *,
.settings-subnav > *,
.reports-subnav > *,
.talent-subnav > *,
.dayview-subnav > *,
.dv-subnav > *,
.holds-subnav > *,
.tc-subnav > *,
.ucb-od-subnav > *,
.audience-tabs > * {
  flex: 0 0 auto;
}

@media (max-width: 900px) {
  /* Trailing-edge fade: the affordance that says "keep swiping". Only the
     RIGHT edge — a symmetric mask dims the first tab, which is the active
     one on arrival and the one that most needs to read as a label. When the
     strip doesn't overflow, its content never reaches the fade, so a short
     strip is untouched. */
  .main-tabs,
  .shows-subnav,
  .settings-subnav,
  .reports-subnav,
  .talent-subnav,
  .dayview-subnav,
  .dv-subnav,
  .holds-subnav,
  .tc-subnav,
  .ucb-od-subnav,
  .audience-tabs {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent 100%);
    /* The JS counterpart is scrollTabIntoStrip() in shows-dashboard.js: it
       parks the newly-selected tab 34px clear of this fade, rather than
       under it. Change the 30px here and change that inset with it. */
  }
  /* Settings is pushed to the far end of the row by margin-left:auto, which
     is already inert once the strip overflows. On a narrow screen that
     happens to fit every tab it is NOT inert — and it would park Settings
     under the fade above, which is the one place a label must not sit. Pack
     the tabs left instead; the row scrolls, so "far end" means nothing here
     anyway. */
  .main-tab--right {
    margin-left: 0;
  }

  /* ── Tab sizing. The top row used to drop to 10px at 600px and 9px at
     400px — tracked uppercase Knockout at 9px is roughly 6px of x-height,
     which is both unreadable and, at 34px tall, under every touch-target
     guideline going. Type stays at a readable size and the row grows to a
     real 46px target; the horizontal scroll above is what absorbs the extra
     width, which is the whole reason the strip scrolls. */
  #shows-dashboard .main-tab {
    display: inline-flex;
    align-items: center;
    min-height: 46px;
    padding: 0 15px;
    font-size: 12px;
    letter-spacing: 0.6px;
  }
  /* ID-scoped (convention 33): two of these sub-navs are styled from files
     that load AFTER this one — staff-timecards.css for .tc-subtab, and an
     inline <style> in class-order-diagnostics-tab.php for .ucb-od-subtab —
     so a plain single-class rule here loses on document order, not on
     specificity, and would silently no-op on exactly two tabs. */
  #shows-dashboard .shows-subtab,
  #shows-dashboard .settings-subtab,
  #shows-dashboard .reports-subtab,
  #shows-dashboard .talent-subtab,
  #shows-dashboard .dayview-subtab,
  #shows-dashboard .holds-subtab,
  #shows-dashboard .dv-subtab,
  #shows-dashboard .tc-subtab,
  #shows-dashboard .ucb-od-subtab {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 14px;
    font-size: 12px;
    letter-spacing: 0.6px;
  }
}

/* ── 25b. Data tables scroll instead of clipping ──────────────
   .data-table uses `overflow: hidden` so its rounded corners clip the
   table. On a phone that turned every wide table into a truncated one:
   measured 441px of Final Recap payout table inside a 348px viewport, with
   the last column (Payment Method) simply gone and no way to reach it.
   overflow-y stays hidden, so the radius still clips. */
@media (max-width: 900px) {
  .data-table {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  /* `width: 100%` makes a table compress to the container and mangle its
     cells rather than scroll. Sizing to content with a 100% floor keeps the
     narrow tables full-bleed and lets the wide ones extend. */
  .data-table table {
    width: auto;
    min-width: 100%;
  }
}

/* ── 25c. Touch targets and text-entry controls ───────────────── */
@media (max-width: 700px) {
  /* iOS Safari zooms the viewport whenever a focused control's computed
     font-size is under 16px, then leaves the page zoomed — which is why
     tapping a search box used to shove the dashboard sideways. There is
     already a one-off `.search-input { font-size: 16px }` above; this is
     the general form of it.
     ⚠ `!important`, and it is earned. 16px is a PLATFORM THRESHOLD, not a
     style preference — a control that misses it by a pixel zooms the page.
     Without it this rule sits at (1,0,1) and quietly loses to any feature that
     sized its own field: measured on ColdTowne dev 2026-09-07, ELEVEN controls
     were still under 16px, including every filter in the Shows browser
     (`#shows-browser .shows-browser-filters input[type="search"]` is (1,2,1))
     and the Talent Approvals search. Enumerating today's offenders would fix
     those eleven and silently miss the twelfth. */
  #shows-dashboard input[type="text"],
  #shows-dashboard input[type="search"],
  #shows-dashboard input[type="email"],
  #shows-dashboard input[type="tel"],
  #shows-dashboard input[type="url"],
  #shows-dashboard input[type="number"],
  #shows-dashboard input[type="password"],
  #shows-dashboard input[type="date"],
  #shows-dashboard input[type="time"],
  #shows-dashboard input:not([type]),
  #shows-dashboard select,
  #shows-dashboard textarea,
  /* Select2's search field is body-appended, i.e. OUTSIDE #shows-dashboard, so
     the rules above can't reach it — and it is the field you type a show name
     into. This file only loads on dashboard/report pages, so the reach is
     those pages. */
  .select2-container--open .select2-search__field {
    font-size: 16px !important;
  }
  /* Checkboxes and radios are 13px by default on both themes — too small to
     hit reliably, and they are how staff toggle real state here. */
  #shows-dashboard input[type="checkbox"],
  #shows-dashboard input[type="radio"] {
    width: 20px;
    height: 20px;
  }
  #shows-dashboard .btn {
    min-height: 44px;
  }
  /* The header quick-links are 12px text with nothing around them; give
     each one a real row to be tapped in without changing how they read. */
  .show-header-links a {
    display: inline-block;
    padding: 3px 0;
  }
}

/* ── 25d. Show hero — it was eating the whole first screen ─────
   Picker + Browse + artwork + title + three meta lines + five quick links
   ran to roughly 630px before the tab content started, on a 660px-tall
   phone viewport. Nothing is removed; it is packed. */
@media (max-width: 700px) {
  .header-inner {
    padding: 12px 16px 14px;
  }
  .event-picker-row {
    margin-bottom: 12px;
  }
  #shows-dashboard .show-title {
    font-size: 20px;
    letter-spacing: 0.3px;
  }
  /* Artwork moves to the trailing edge and shrinks. The title is the thing
     being read; the art is recognition, so it stops taking the first third
     of every line of text. */
  .header-body {
    align-items: flex-start;
    gap: 12px;
  }
  .header-body-text {
    order: 1;
  }
  .show-artwork-btn {
    order: 2;
    width: 86px;
  }
  /* Explicit, because ordering the first two children moves the third: the
     DOM order is artwork → text → actions, so Publish/Schedule would jump
     to the front of the row the moment anything else is given an `order`. */
  .header-actions {
    order: 3;
    width: 100%;
  }
  .show-meta {
    font-size: 12px;
    gap: 0 10px;
  }
  .show-header-links {
    margin-top: 4px;
    /* Wider column gap than desktop: with the separators gone (below), the
       gap is the only thing telling two adjacent links apart. */
    gap: 2px 16px;
    font-size: 12px;
  }
  /* The separators only earn their space on one line. Wrapped over three,
     they read as stray punctuation. */
  .show-header-links-sep {
    display: none;
  }
}

/* ── 25e. Shows browser (the no-selection landing view) ────────
   Seven controls flex-wrapped into a ragged three-and-a-half rows, with
   "From"/"To" labels stranded beside half-width boxes. A grid instead:
   search, then the two filters that pair, then sort, then the date range,
   then Clear. Explicit column spans rather than auto-flow, so the DOM order
   (search, region, status, sort, from, to, clear) lands in that shape. */
@media (max-width: 700px) {
  #shows-browser {
    padding: 16px 16px 36px;
  }
  .shows-browser-head {
    margin-bottom: 10px;
  }
  .shows-browser-title {
    font-size: 20px;
  }
  .shows-browser-filters {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: end;
    gap: 8px;
    margin-bottom: 14px;
  }
  #shows-browser .browser-search,
  #shows-browser .shows-browser-filters #browser-sort,
  #shows-browser .browser-clear-btn {
    grid-column: 1 / -1;
  }
  #shows-browser .browser-search {
    flex: none;
    width: 100%;
    min-width: 0;
  }
  #shows-browser .shows-browser-filters select {
    width: 100%;
  }
  /* Label above the field, not beside it — beside it, "From" and "To" ate a
     third of each cell and the two pickers ended up different widths. */
  .browser-date-label {
    flex-direction: column;
    align-items: stretch;
    gap: 3px;
    font-size: 11px;
    letter-spacing: 0.4px;
    text-transform: uppercase;
  }
  /* ⚠ The label WRAPS its input, and text-transform inherits — so the rule
     above was uppercasing the field's "Any" placeholder into "ANY" too. Reset
     the typography the label sets for its own text; the field keeps the
     filter-row's. */
  #shows-browser .shows-browser-filters .browser-date {
    width: 100%;
    text-transform: none;
    letter-spacing: normal;
  }
  #shows-browser .browser-clear-btn {
    justify-content: center;
    height: 44px;
  }
  .browser-group-title {
    margin: 18px 0 6px;
  }
}

/* Show-artwork lightbox body (ucbDialog.custom). Caps on BOTH axes so a tall
   poster can't push the dialog's Close button off a short phone screen. */
.ucb-artwork-lightbox {
  display: block;
  width: 100%;
  max-height: 60vh;
  object-fit: contain;
  border-radius: 6px;
}

/* ── 25e-bis. flatpickr inside a dialog, on a small phone ──────
   flatpickr ships a FIXED 307.875px calendar. In-page that is harmless — the
   calendar is body-appended and free to overhang. Inside a ucbDialog it is
   `static: true` (convention 19 — it has to be, or Magnific's focus trap and
   flatpickr's fight to a stack overflow), which renders it INLINE, and the
   dialog body is narrower than 308px on anything under ~370px of viewport: the
   last column of days was cut off. Let it fill the dialog instead — the day
   cells size from `flex-basis: 14.2857%`, so seven still fit per row. */
@media (max-width: 700px) {
  .ucb-dialog .flatpickr-calendar,
  .ucb-dialog .flatpickr-rContainer,
  .ucb-dialog .flatpickr-days,
  .ucb-dialog .dayContainer {
    width: 100%;
    max-width: 100%;
    min-width: 0;
  }
}

/* ── 25f. Stragglers that squeeze rather than wrap ─────────────
   A flex row whose children all carry a min-width doesn't wrap on a phone —
   one child collapses to a sliver instead. Anything else found in that
   shape belongs here. */
@media (max-width: 700px) {
  /* The producer sales link, "Copy" and "Review & send update" on one line
     left the URL field showing exactly "http". */
  .ucb-pcomm-link-wrap {
    flex-wrap: wrap;
  }
  .ucb-pcomm-link-wrap .setup-input {
    flex: 1 1 100%;
  }
  .ucb-pcomm-link-wrap .btn {
    flex: 1 1 auto;
  }
}

@media print {
  body { background: white; }
  .wp-admin-bar, .floating-summary, .session-status { display: none; }
  .panel, .stat-card { box-shadow: none; border: 1px solid #ddd; }
}

/* ── 24b. Skeleton Loading Pulse ────────────────────────────── */
.skel-pulse {
  display: inline-block;
  width: 60px;
  height: 24px;
  background: linear-gradient(90deg, var(--ucb-gray-100) 25%, var(--ucb-gray-200) 50%, var(--ucb-gray-100) 75%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.2s ease-in-out infinite;
  border-radius: 4px;
  vertical-align: middle;
}
.skel-pulse.skel-sm {
  width: 80px;
  height: 12px;
}
@keyframes skel-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── 25. Accessibility ─────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  #shows-dashboard *,
  #shows-dashboard *::before,
  #shows-dashboard *::after,
  .collapse-body,
  .collapse-arrow {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
#shows-dashboard :focus-visible {
  outline: 2px solid var(--ucb-brand);
  outline-offset: 2px;
}
#shows-dashboard button:focus:not(:focus-visible),
#shows-dashboard input:focus:not(:focus-visible),
#shows-dashboard select:focus:not(:focus-visible),
#shows-dashboard textarea:focus:not(:focus-visible) {
  outline: none;
}

/* Duplicate-ticket group badge — flags an attendee row whose order was
   over-issued ticket codes (see WooCommerce_Tickera_Ticket_Lock). Every
   code is valid at the door; admissions are capped at the paid quantity. */
.audience-dup-badge {
  display: inline-block;
  margin-top: 3px;
  padding: 1px 8px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.6;
  color: #92400e;
  background: #fef3c7;
  border: 1px solid #f59e0b;
  border-radius: 10px;
}
/* The plain-language line under the badge: what staff can actually DO. Sits on
   the row because a tooltip is unreachable mid-rush (and invisible on touch). */
.audience-dup-note {
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.45;
  color: #92400e;
}

/* Badge turns red once the group hits its paid admission max. */
.audience-dup-badge.is-max {
  color: #7f1d1d;
  background: #fee2e2;
  border-color: #ef4444;
}

/* The order number beside the ticket code. Deliberately lighter and always
   prefixed with the word "Order" — the two numbers sit inches apart on a busy
   row and must never be confused for one another. */
.audience-name-order {
  margin-left: 6px;
  color: #9aa2ae;
  font-weight: 400;
}

/* Ticket code shown on every attendee row. */
.audience-name-code {
  margin-top: 2px;
  font-size: 12px;
  color: #6b7280;
  font-variant-numeric: tabular-nums;
}

/* Expandable surplus-codes panel for a duplicate group. */
.audience-dup-expandwrap {
  padding: 2px 16px 10px 52px;
  border-bottom: 1px solid #eee;
  border-left: 3px solid #f59e0b;
}
/* Was a "Show N more codes" toggle. The codes are now always visible — see
   renderAttendees() — so this is the header line above them. */
.audience-dup-panel-note {
  padding: 4px 0 2px;
  font-size: 12px;
  font-weight: 600;
  color: #92400e;
}
.audience-dup-panel {
  margin-top: 4px;
  padding: 4px 10px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 6px;
}
.audience-dup-extra {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 2px;
}
.audience-dup-extra + .audience-dup-extra { border-top: 1px solid #fef3c7; }
.audience-dup-extra-code {
  font-size: 13px;
  font-weight: 600;
  color: #444;
  font-variant-numeric: tabular-nums;
}
.audience-dup-extra-status {
  flex: 1;
  font-size: 12px;
  color: #6b7280;
}
.audience-dup-extra.checked-in .audience-dup-extra-status {
  color: #137333;
  font-weight: 600;
}

/* Duplicate-group rows share an amber left edge so the order reads as one
   block (the badge itself is shown once, on the group's first row). */
.audience-row--dup {
  border-left: 3px solid #f59e0b;
}

@media (max-width: 640px) {
	/* On a phone each member ran to four or five wrapped lines, so an order
	   with a few codes filled the whole screen. Break the identity onto its
	   own smaller line instead of letting it wrap inside the code line. */
	.ucb-order-group__text { display: block; }
	.ucb-order-group__code { display: block; font-size: 15px; }
	.ucb-order-group__meta { display: block; font-size: 12px; line-height: 1.4; }
	.ucb-order-group__line-head { font-size: 12px; }
	.ucb-order-group__member { align-items: flex-start; }
}

/* Group check-in panel — the purchaser line and per-code identity. The CODE
   is what staff match against a phone screen, so it stays bold and unstruck
   even on a refused row; the reason is muted text beside it, not through it. */
.ucb-order-group__buyer {
  margin: 0 0 10px;
  padding-bottom: 8px;
  font-size: 13px;
  font-weight: 600;
  color: #334155;
  border-bottom: 1px solid #e2e8f0;
}
.ucb-order-group__code {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}
.ucb-order-group__meta { color: #475569; }
.ucb-order-group__member.is-refused .ucb-order-group__code { color: #111827; }

/* ── "Not a ticket" rows ──────────────────────────────────────────────────
   A code the guest really holds — emailed to them — that owns no seat: one
   cancelled when staff edited the order, or traded for gift-card credit.
   Rendered IN PLACE under that guest's real rows, because door staff are
   often new and working a queue: a collapsed section at the bottom of 200
   rows is unfindable, and "you're not on the list" is never the true answer.
   Non-actionable by construction — there is no check-in control to mistap. */
.audience-void-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 16px 10px 20px;
  border-bottom: 1px solid #eee;
  border-left: 4px solid #dc2626;
  background: #fff5f5;
}
.audience-void-mark {
  flex: none;
  width: 22px;
  text-align: center;
  font-size: 15px;
  font-weight: 700;
  color: #dc2626;
  line-height: 1.6;
}
.audience-void-who { flex: 1; min-width: 0; }
/* ⚠ The CODE is the one thing staff compare against the guest's phone, so it
   is the most legible text on the row — NOT struck through and NOT greyed.
   The first version did both and made the single field that matters the
   hardest to read. "Invalid" is carried by the ✕, the badge and the red
   edge, none of which cost legibility. */
.audience-void-code {
  margin-top: 3px;
  font-size: 14px;
  font-weight: 700;
  color: #111827;
  font-variant-numeric: tabular-nums;
}
.audience-void-why {
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.5;
  color: #475569;
}
.audience-void-why strong { color: #991b1b; }
.audience-void-bought {
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.5;
  color: #475569;
}
.audience-void-hint {
  margin-top: 3px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  color: #166534;
}
.audience-void-order {
  display: inline-block;
  margin-left: 4px;
  font-variant-numeric: tabular-nums;
  color: #64748b;
  white-space: nowrap;
}
a.audience-void-order { color: #1d4ed8; text-decoration: underline; }
.audience-void-badge {
  flex: none;
  align-self: center;
  padding: 1px 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .02em;
  line-height: 1.7;
  color: #7f1d1d;
  background: #fee2e2;
  border: 1px solid #fca5a5;
  border-radius: 10px;
  white-space: nowrap;
}
.audience-void-row .audience-void-resolve { flex: none; align-self: center; }
@media (max-width: 640px) {
  .audience-void-row { flex-wrap: wrap; }
  .audience-void-row .audience-void-resolve { width: 100%; }
}

/* ── Reusable hover/focus explainer ───────────────────────────────────────
   MOVED (2026-08-28) to assets/css/ucb-explain.css, handle `ucb-explain`,
   which this stylesheet's enqueue now pulls in — see
   Shows_Dashboard::enqueue_assets(). It was extracted so consumers outside
   this dashboard (ucb-courses' Class Manager first) can use the component
   without copying it. Contextual overrides for it still live in this file
   (.show-scheduled-pill, .show-header-links) and are unaffected.
   Do not re-add the base rules here. */


/* ── DCM bucket filter strip (Check-In) ────────────────────────── */
.dcm-buckets {
  margin: 8px 0 12px;
  padding: 10px 12px;
  background: var(--ucb-gray-50, #f7f7f8);
  border: 1px solid var(--ucb-gray-200, #e3e3e6);
  border-radius: 6px;
}
.dcm-buckets.hidden { display: none; }
.dcm-buckets-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.dcm-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--ucb-border-strong, #767676);
  border-radius: 999px;
  background: #fff;
  color: var(--ucb-gray-800, #303034);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.1s ease, border-color 0.1s ease, color 0.1s ease;
  white-space: nowrap;
}
/* Mobile: allow chip labels to wrap to two lines as a safety net.
   Long bucket labels (or future labels added by other passes) would
   otherwise force horizontal overflow of the chip strip — flex-wrap
   on the parent only kicks in chip-by-chip, not within a single
   nowrap chip. Pair the wrap with a tighter line-height so two-line
   chips don't grow the strip unnecessarily. */
@media (max-width: 720px) {
  .dcm-chip {
    white-space: normal;
    line-height: 1.2;
    text-align: center;
  }
}
.dcm-chip:hover { background: var(--ucb-gray-100, #f0f0f2); border-color: var(--ucb-gray-400, #b8b8bc); }
.dcm-chip:focus-visible {
  outline: 2px solid var(--ucb-brand, #2271b1);
  outline-offset: 2px;
}
.dcm-chip.is-active {
  background: var(--ucb-brand, #2271b1);
  border-color: var(--ucb-brand, #2271b1);
  color: #fff;
}
.dcm-chip.is-active .dcm-chip-count {
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
}
.dcm-chip.is-empty { opacity: 0.55; }
.dcm-chip-label { font-weight: 600; }

/* Explicit "Clear filter" button — only rendered when a non-All chip is
   active. Borderless text button so it doesn't compete visually with the
   real chips; underlined "Clear filter" with an X glyph makes the reset
   action discoverable for staff who don't read "All" as a reset. */
.dcm-clear {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  margin-left: 4px;
  border: none;
  background: transparent;
  color: var(--ucb-red-dark, #b00020);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  border-radius: 6px;
}
.dcm-clear:hover { background: rgba(176, 0, 32, 0.08); }
.dcm-clear:focus-visible {
  outline: 2px solid var(--ucb-red-dark, #b00020);
  outline-offset: 2px;
}
.dcm-clear-x { font-size: 14px; line-height: 1; }
.dcm-clear-label { text-decoration: underline; text-underline-offset: 2px; }
.dcm-chip-count {
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--ucb-gray-200, #e3e3e6);
  color: var(--ucb-gray-700, #4d4d52);
}

/* ── Show Setup: Change History panel ────────────────────────────────
   Collapsed per-event audit trail (ucb_event_change_log). The toggle
   mirrors the .audience-dup-expand text-button pattern; entries echo
   the notes-log author/time typography. */
.change-log-expand {
  background: none;
  border: 0;
  padding: 4px 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--ucb-gray-600);
  cursor: pointer;
}
.change-log-expand:hover { text-decoration: underline; }
.change-log-entries {
  list-style: none;
  margin: 0;
  padding: 0;
}
.change-log__entry {
  padding: 10px 2px;
  border-bottom: 1px solid var(--ucb-gray-100);
  font-size: 13px;
}
.change-log__entry:last-child { border-bottom: none; }
.change-log__author {
  font-weight: 700;
  color: var(--ucb-gray-800);
}
.change-log__time {
  color: var(--ucb-gray-500);
  font-size: 12px;
}
.change-log__summary {
  margin-top: 2px;
  color: var(--ucb-gray-700);
}
.change-log__changes {
  list-style: none;
  margin: 4px 0 0;
  padding: 6px 10px;
  background: var(--ucb-gray-50);
  border: 1px solid var(--ucb-gray-100);
  border-radius: 6px;
}
.change-log__changes li {
  padding: 2px 0;
  color: var(--ucb-gray-600);
  overflow-wrap: anywhere;
}
.change-log__changes li strong {
  color: var(--ucb-gray-800);
  text-transform: capitalize;
}
.change-log__loading,
.change-log__empty {
  color: var(--ucb-gray-500);
  padding: 8px 2px;
  list-style: none;
}
.change-log-more {
  margin-top: 10px;
  width: auto;
}

/* ── Elementor-kit theme compat (Coldtowne) ──────────────────
   The dashboard's own subtree inherits DM Sans from #shows-dashboard, but
   several dashboard components mount on <body> and inherit the THEME's body
   font instead — a serif (Vollkorn) on Elementor-kit sites. Give them the
   dashboard face explicitly, scoped to kit-classed bodies so The7 (UCB)
   keeps its current rendering everywhere. Form fields inside these
   containers pick the font up via Hello Elementor's reset (input { font:
   inherit }). Kit BUTTON rules (.elementor-kit-N button at (0,1,1)) inside
   the dashboard are handled separately by the CSSOM shim in
   assets/js/ucb-elementor-kit-compat.js — see its docblock. */
body[class*="elementor-kit-"] .shows-dashboard-dropdown,
body[class*="elementor-kit-"] .flatpickr-calendar,
body[class*="elementor-kit-"] .dv-tip,
body[class*="elementor-kit-"] .ucb-report-tip,
body[class*="elementor-kit-"].ucb-staff-surface .ucb-dialog {
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
}
/* ⚠ The dialog TITLE needs naming separately: the kit styles headings by
   element (h1-h6), which beats an inherited family on the container, so the
   group check-in panel's "Order #123456" rendered in Coldtowne's Vollkorn
   while every other word in it was DM Sans. Scoped to `.ucb-staff-surface`
   (added by Shows_Dashboard::enqueue_assets) because the same dialog is
   customer-facing elsewhere on the site, where the theme's face is correct. */
body[class*="elementor-kit-"].ucb-staff-surface .ucb-dialog__title {
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
}

/* ── §6 group check-in — every ticket an order holds for this show ────────
   Lives in a ucbDialog.custom() body. Colours come from the dashboard's own
   tokens; the theme shim (convention 33) covers the dialog root already, so
   these need no doubled-class defence. */
.ucb-order-group__line {
	margin: 0 0 14px;
}
.ucb-order-group__line:last-child {
	margin-bottom: 0;
}
.ucb-order-group__line-head {
	font-weight: 600;
	font-size: 13px;
	letter-spacing: .02em;
	text-transform: uppercase;
	opacity: .75;
	margin: 0 0 6px;
}
/* A line that owns no seats: its heading states that, in the same red the
   refused rows under it use, rather than counting admissions of nothing. */
.ucb-order-group__line-head.is-void {
	color: #991b1b;
	opacity: 1;
}
.ucb-order-group__member {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	padding: 7px 8px;
	border-radius: 5px;
	line-height: 1.35;
	cursor: pointer;
}
.ucb-order-group__member + .ucb-order-group__member {
	margin-top: 3px;
}
.ucb-order-group__member.is-in,
.ucb-order-group__member.is-refused {
	cursor: default;
	/* Was .72. Fading is another way of making the text harder to read; state
	   is signalled by colour and the ✓/✕ mark, not by dimming. */
	opacity: 1;
}
.ucb-order-group__member.is-in .ucb-order-group__spacer { color: #137333; font-weight: 700; }
.ucb-order-group__member.is-scanned {
	background: rgba(255, 214, 0, .16);
	box-shadow: inset 0 0 0 1px rgba(255, 214, 0, .45);
}
/* ⚠ NO strike-through anywhere on a refused member. It shipped twice — first
   across the whole line, then across the reason — and both times made text
   people have to READ harder to read, which is the opposite of the point at a
   door. "Unusable" is carried by design instead: a red edge, a red ✕, a tinted
   background and red text. Nothing here costs legibility. */
.ucb-order-group__member.is-refused {
	background: #fef2f2;
	border-left: 3px solid #dc2626;
	border-radius: 4px;
	padding-left: 7px;
}
.ucb-order-group__member.is-refused .ucb-order-group__spacer { color: #dc2626; font-weight: 700; }
.ucb-order-group__member.is-refused .ucb-order-group__meta { color: #991b1b; }
/* "There are no valid tickets left on this order." — the one sentence that
   saves staff reading every row's reason and concluding it themselves. Sits
   under the lines, above the actions, so it reads straight into the
   "Admit anyway" button beneath it. */
.ucb-order-group__none {
	margin-top: 12px;
	padding: 10px 12px;
	border-radius: 6px;
	background: #fef2f2;
	border-left: 3px solid #dc2626;
	color: #7f1d1d;
	font-size: 13px;
	line-height: 1.5;
}

.ucb-order-group__pick,
.ucb-order-group__spacer {
	flex: 0 0 auto;
	width: 16px;
	text-align: center;
	margin-top: 2px;
}
.ucb-order-group__text {
	flex: 1 1 auto;
	min-width: 0;
	word-break: break-word;
}
