/* ============================================================
   CLIP UI — mobile-first component kit
   Replaces Syncfusion Blazor. Built on rural-premium.css tokens.

   Conventions
   -----------
   - Every interactive control is >= 44px tall on touch.
   - Layout is mobile-first: base rules are the phone layout,
     media queries add the desktop layout on top.
   - Two breakpoints only:
       --bp-md  768px   dialog becomes a centred modal (below: bottom sheet)
       --bp-lg 1024px   ClipTable becomes a table    (below: card list)
   ============================================================ */

:root {
  --clip-bp-md: 768px;
  --clip-bp-lg: 1024px;

  /* Minimum comfortable touch target. Do not shrink these. */
  --clip-touch: 44px;
  --clip-touch-sm: 36px;

  --clip-field-bg: var(--bg-inset, rgba(0, 0, 0, 0.2));
  --clip-field-border: var(--border-strong, #3a4a7a);
  --clip-focus-ring: 0 0 0 3px var(--accent-gold-muted, rgba(184, 150, 90, 0.35));

  --clip-z-dialog: 1000;
  --clip-z-popup: 1100;
  --clip-z-toast: 1200;
}

/* ============================================================
   1. FIELD SHELL — label + control + hint/error
   Shared by every input component so spacing stays consistent.
   ============================================================ */

.clip-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: var(--space-md, 1rem);
  min-width: 0; /* lets fields shrink inside flex/grid rows */
}

.clip-field__label {
  font-family: var(--font-family-body);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--text-secondary);
  line-height: 1.3;
}

.clip-field__req {
  color: var(--danger);
  margin-left: 0.15rem;
}

.clip-field__hint {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
}

.clip-field__error {
  font-size: var(--font-size-xs);
  color: var(--danger);
  font-weight: 500;
}

.clip-field--invalid .clip-input,
.clip-field--invalid .clip-select,
.clip-field--invalid .clip-combo__input {
  border-color: var(--danger);
}

/* Horizontal field rows that collapse to stacked on phones. */
.clip-field-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 var(--space-md);
}

@media (min-width: 768px) {
  .clip-field-row--2 { grid-template-columns: 1fr 1fr; }
  .clip-field-row--3 { grid-template-columns: 1fr 1fr 1fr; }
  .clip-field-row--4 { grid-template-columns: repeat(4, 1fr); }
}

/* ============================================================
   2. TEXT INPUTS / TEXTAREA / SELECT
   Native elements — they get the correct mobile keyboard and
   the OS picker for free, which is the whole point.
   ============================================================ */

.clip-input,
.clip-select,
.clip-textarea {
  width: 100%;
  min-height: var(--clip-touch);
  padding: 0.5rem 0.75rem;
  background: var(--clip-field-bg);
  color: var(--text-primary);
  border: 1px solid var(--clip-field-border);
  border-radius: var(--radius-md);
  font-family: var(--font-family-body);
  /* 16px minimum: anything smaller makes iOS Safari zoom on focus. */
  font-size: max(16px, var(--font-size-sm));
  line-height: 1.4;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
  appearance: none;
}

.clip-textarea {
  min-height: calc(var(--clip-touch) * 2);
  resize: vertical;
  padding-top: 0.6rem;
}

.clip-input:focus-visible,
.clip-select:focus-visible,
.clip-textarea:focus-visible {
  outline: none;
  border-color: var(--accent-gold);
  box-shadow: var(--clip-focus-ring);
}

.clip-input::placeholder,
.clip-textarea::placeholder { color: var(--text-muted); opacity: 1; }

.clip-input:disabled,
.clip-select:disabled,
.clip-textarea:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  background: rgba(0, 0, 0, 0.35);
}

.clip-input[readonly] { background: rgba(0, 0, 0, 0.35); }

/* Native date/time inputs: force the OS control to be visible on dark */
.clip-input[type="date"],
.clip-input[type="time"],
.clip-input[type="datetime-local"] { color-scheme: dark; }

/* Select needs a chevron since we removed the native appearance */
.clip-select {
  padding-right: 2.25rem;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23a8a195'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 16px;
  cursor: pointer;
}

.clip-select option { background: var(--bg-surface); color: var(--text-primary); }

/* Input with a leading icon (search fields) */
.clip-input-group { position: relative; display: flex; align-items: center; }
.clip-input-group .clip-input { padding-left: 2.5rem; }
.clip-input-group__icon {
  position: absolute;
  left: 0.85rem;
  color: var(--text-muted);
  pointer-events: none;
  font-size: 0.9rem;
}
.clip-input-group__clear {
  position: absolute;
  right: 0.4rem;
  width: var(--clip-touch-sm);
  height: var(--clip-touch-sm);
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-full);
}
.clip-input-group__clear:hover { color: var(--text-primary); background: var(--bg-chip); }

/* ============================================================
   3. BUTTONS
   ============================================================ */

.clip-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--clip-touch);
  padding: 0.5rem 1.1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-family: var(--font-family-body);
  font-size: var(--font-size-sm);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition-fast), border-color var(--transition-fast), opacity var(--transition-fast);
  -webkit-tap-highlight-color: transparent;
}

.clip-btn:focus-visible { outline: none; box-shadow: var(--clip-focus-ring); }
.clip-btn:disabled, .clip-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

.clip-btn--primary { background: var(--accent-gold); color: var(--on-accent); }
.clip-btn--primary:hover:not(:disabled) { background: var(--accent-gold-hover); color: var(--on-accent); }

.clip-btn--secondary { background: transparent; color: var(--accent-gold); border-color: var(--accent-gold); }
.clip-btn--secondary:hover:not(:disabled) { background: var(--accent-gold-muted); color: var(--accent-gold); }

.clip-btn--subtle { background: var(--bg-chip); color: var(--text-primary); border-color: var(--border); }
.clip-btn--subtle:hover:not(:disabled) { background: var(--bg-elevated); }

.clip-btn--danger { background: var(--danger); color: #2b0d0d; }
.clip-btn--danger:hover:not(:disabled) { background: #ff8f8f; }

.clip-btn--success { background: var(--success); color: #06280f; }
.clip-btn--success:hover:not(:disabled) { background: #6ee79a; }

.clip-btn--ghost { background: transparent; color: var(--text-secondary); }
.clip-btn--ghost:hover:not(:disabled) { background: var(--bg-chip); color: var(--text-primary); }

.clip-btn--sm { min-height: var(--clip-touch-sm); padding: 0.3rem 0.75rem; font-size: var(--font-size-xs); }
.clip-btn--lg { min-height: 52px; padding: 0.75rem 1.75rem; font-size: var(--font-size-base); }
.clip-btn--block { width: 100%; }

/* Icon-only button: keep the tap target square and full size */
.clip-btn--icon {
  padding: 0;
  width: var(--clip-touch);
  height: var(--clip-touch);
  min-height: var(--clip-touch);
}
.clip-btn--icon.clip-btn--sm { width: var(--clip-touch-sm); height: var(--clip-touch-sm); min-height: var(--clip-touch-sm); }

/* Button rows: stack full-width on phones, inline from tablet up. */
.clip-btn-row { display: flex; flex-direction: column; gap: var(--space-sm); }
.clip-btn-row > .clip-btn { width: 100%; }

@media (min-width: 768px) {
  .clip-btn-row { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .clip-btn-row > .clip-btn { width: auto; }
  .clip-btn-row--end { justify-content: flex-end; }
}

/* ============================================================
   4. CHECKBOX + SWITCH
   ============================================================ */

.clip-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: var(--clip-touch);
  cursor: pointer;
  user-select: none;
}
.clip-check input[type="checkbox"] {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  accent-color: var(--accent-gold);
  cursor: pointer;
}
.clip-check__label { font-size: var(--font-size-sm); color: var(--text-primary); line-height: 1.3; }
.clip-check input:disabled ~ .clip-check__label { opacity: 0.55; }

.clip-switch {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-height: var(--clip-touch);
  cursor: pointer;
  user-select: none;
}
/* Visually hidden but still focusable and screen-reader visible */
.clip-switch input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.clip-switch__track {
  position: relative;
  width: 46px;
  height: 26px;
  flex: 0 0 46px;
  background: var(--bg-chip);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.clip-switch__thumb {
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  background: var(--text-secondary);
  border-radius: var(--radius-full);
  transition: transform var(--transition-fast), background var(--transition-fast);
}
.clip-switch input:checked + .clip-switch__track { background: var(--accent-gold); border-color: var(--accent-gold); }
.clip-switch input:checked + .clip-switch__track .clip-switch__thumb { transform: translateX(20px); background: var(--on-accent); }
.clip-switch input:focus-visible + .clip-switch__track { box-shadow: var(--clip-focus-ring); }
.clip-switch input:disabled + .clip-switch__track { opacity: 0.5; }
.clip-switch__label { font-size: var(--font-size-sm); color: var(--text-primary); line-height: 1.3; }

/* ============================================================
   5. COMBO (searchable select)
   Phone: full-screen sheet so the on-screen keyboard cannot
   cover the option list. Tablet+: anchored popup.
   ============================================================ */

.clip-combo { position: relative; }

.clip-combo__input { cursor: text; padding-right: 2.25rem; }
.clip-combo__toggle {
  position: absolute;
  right: 0.25rem;
  top: 50%;
  transform: translateY(-50%);
  width: var(--clip-touch-sm);
  height: var(--clip-touch-sm);
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
}

.clip-combo__panel {
  position: fixed;
  inset: 0;
  z-index: var(--clip-z-popup);
  display: flex;
  flex-direction: column;
  background: var(--bg-primary);
}

.clip-combo__search-bar {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm);
  padding-top: max(var(--space-sm), env(safe-area-inset-top));
  border-bottom: 1px solid var(--border);
  background: var(--bg-surface);
}
.clip-combo__search-bar .clip-input { flex: 1; }

.clip-combo__list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  flex: 1;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

.clip-combo__option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--clip-touch);
  padding: 0.6rem 0.9rem;
  color: var(--text-primary);
  font-size: var(--font-size-sm);
  cursor: pointer;
  border-bottom: 1px solid var(--border-subtle);
}
.clip-combo__option:hover,
.clip-combo__option[aria-selected="true"] { background: var(--bg-chip); }
.clip-combo__option--active { background: var(--accent-gold-muted); }
.clip-combo__option--empty { color: var(--text-muted); cursor: default; justify-content: center; }

.clip-combo__group {
  padding: 0.4rem 0.9rem;
  font-size: var(--font-size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  background: var(--bg-inset);
  position: sticky;
  top: 0;
}

@media (min-width: 768px) {
  .clip-combo__panel {
    position: absolute;
    inset: auto 0 auto 0;
    top: calc(100% + 4px);
    max-height: 320px;
    background: var(--bg-surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
  }
  /* On desktop the field itself is the search box. */
  .clip-combo__search-bar { display: none; }
}

/* ============================================================
   6. DIALOG
   Native <dialog>: free focus trap, Esc handling and top-layer
   stacking (no z-index war with the rest of the page).
   Phone: bottom sheet. Tablet+: centred modal.
   ============================================================ */

.clip-dialog {
  padding: 0;
  border: none;
  background: transparent;
  max-width: 100vw;
  max-height: 100dvh;
  width: 100%;
  margin: 0;
  /* pin to the bottom for the sheet layout */
  position: fixed;
  inset: auto 0 0 0;
  overflow: visible;
}

.clip-dialog::backdrop {
  background: rgba(10, 10, 20, 0.72);
  backdrop-filter: blur(2px);
}

.clip-dialog__panel {
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  color: var(--text-primary);
  border-top: 1px solid var(--border-strong);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  max-height: 92dvh;
  box-shadow: var(--shadow-lg);
  animation: clip-sheet-in 220ms cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes clip-sheet-in {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

/* Grab handle — signals "drag me down to dismiss" on touch. */
.clip-dialog__grip {
  width: 40px;
  height: 4px;
  border-radius: var(--radius-full);
  background: var(--border-strong);
  margin: 0.5rem auto 0;
  flex: none;
}

.clip-dialog__header {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md);
  border-bottom: 1px solid var(--border);
  flex: none;
}

.clip-dialog__title {
  margin: 0;
  flex: 1;
  font-family: var(--font-family-heading);
  font-size: var(--font-size-xl);
  letter-spacing: 0.02em;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.clip-dialog__body {
  padding: var(--space-md);
  overflow-y: auto;
  flex: 1;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

.clip-dialog__footer {
  display: flex;
  flex-direction: column-reverse; /* primary action ends up on top on phones */
  gap: var(--space-sm);
  padding: var(--space-md);
  padding-bottom: max(var(--space-md), env(safe-area-inset-bottom));
  border-top: 1px solid var(--border);
  background: var(--bg-surface);
  flex: none;
}
.clip-dialog__footer > .clip-btn { width: 100%; }

@media (min-width: 768px) {
  /* Centre by making the dialog fill the viewport and laying the panel out
     inside it. `margin: auto` cannot centre here: the dialog is fixed with
     inset:0, so it stretches full width and the margin has nothing to
     distribute, leaving the panel pinned to the left. */
  .clip-dialog {
    inset: 0;
    margin: 0;
    width: 100vw;
    max-width: 100vw;
    height: 100dvh;
    max-height: 100dvh;
  }

  /* Only when open - a closed <dialog> must keep the UA's display:none. */
  .clip-dialog[open] {
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .clip-dialog__panel {
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    max-height: 90dvh;
    min-width: 420px;
    animation: clip-modal-in 160ms ease-out;
  }
  @keyframes clip-modal-in {
    from { opacity: 0; transform: scale(0.97); }
    to   { opacity: 1; transform: scale(1); }
  }
  .clip-dialog__grip { display: none; }
  .clip-dialog__footer { flex-direction: row; justify-content: flex-end; }
  .clip-dialog__footer > .clip-btn { width: auto; }

  .clip-dialog--sm .clip-dialog__panel { width: 420px; }
  .clip-dialog--md .clip-dialog__panel { width: 640px; }
  .clip-dialog--lg .clip-dialog__panel { width: 900px; }
  .clip-dialog--xl .clip-dialog__panel { width: min(1200px, 95vw); }
}

/* Full-screen variant — used where a dialog hosts a whole editor. */
.clip-dialog--full { inset: 0; max-height: 100dvh; }
.clip-dialog--full .clip-dialog__panel {
  height: 100dvh;
  max-height: 100dvh;
  border-radius: 0;
  border: none;
}
@media (min-width: 768px) {
  .clip-dialog--full .clip-dialog__panel { width: min(1200px, 95vw); height: 90dvh; border-radius: var(--radius-lg); }
}

/* ============================================================
   7. TOAST
   Bottom-anchored on phones — top-right is out of thumb reach.
   ============================================================ */

.clip-toast-host {
  position: fixed;
  z-index: var(--clip-z-toast);
  left: var(--space-sm);
  right: var(--space-sm);
  bottom: calc(var(--space-sm) + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  pointer-events: none;
}

@media (min-width: 768px) {
  .clip-toast-host {
    left: auto;
    right: var(--space-lg);
    bottom: var(--space-lg);
    width: 380px;
  }
}

.clip-toast {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.75rem 0.9rem;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-strong);
  border-left: 4px solid var(--accent-gold);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: clip-toast-in 200ms ease-out;
}

@keyframes clip-toast-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

.clip-toast--success { border-left-color: var(--success); }
.clip-toast--error   { border-left-color: var(--danger); }
.clip-toast--warning { border-left-color: var(--warning); }
.clip-toast--info    { border-left-color: var(--info); }

.clip-toast__icon { flex: none; margin-top: 0.15rem; }
.clip-toast--success .clip-toast__icon { color: var(--success); }
.clip-toast--error   .clip-toast__icon { color: var(--danger); }
.clip-toast--warning .clip-toast__icon { color: var(--warning); }
.clip-toast--info    .clip-toast__icon { color: var(--info); }

.clip-toast__body { flex: 1; min-width: 0; }
.clip-toast__title { font-weight: 700; font-size: var(--font-size-sm); }
.clip-toast__text { font-size: var(--font-size-sm); color: var(--text-secondary); overflow-wrap: anywhere; }
.clip-toast__close {
  flex: none;
  width: var(--clip-touch-sm);
  height: var(--clip-touch-sm);
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.clip-toast__close:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.08); }

/* ============================================================
   8. TABS
   Phone: horizontally scrollable strip with snap.
   ============================================================ */

.clip-tabs__list {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  border-bottom: 1px solid var(--border);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.clip-tabs__list::-webkit-scrollbar { display: none; }

.clip-tabs__tab {
  flex: none;
  scroll-snap-align: start;
  min-height: var(--clip-touch);
  padding: 0.5rem 1rem;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  color: var(--text-secondary);
  font-family: var(--font-family-body);
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.clip-tabs__tab:hover { color: var(--text-primary); }
.clip-tabs__tab[aria-selected="true"] { color: var(--accent-gold); border-bottom-color: var(--accent-gold); }
.clip-tabs__tab:focus-visible { outline: none; box-shadow: var(--clip-focus-ring); border-radius: var(--radius-sm); }

.clip-tabs__panel { padding-top: var(--space-md); }

/* ============================================================
   9. TABLE
   Below --clip-bp-lg the same column definitions render as
   cards; above it they render as a real table. Column Priority
   drives which fields appear where.
   ============================================================ */

.clip-table__toolbar {
  display: flex;
  /* Wrap rather than stack. Stacking gave every toolbar button its own
     full-width row - three rows of Excel / CSV / PDF before any data - which
     wastes the part of a phone screen you can actually see. The search box
     still takes a row of its own because it is flex:1. */
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.clip-table__toolbar > .clip-table__search {
  flex: 1 1 100%;
  /* An input's intrinsic min-width is content-based; without this it
     collapses to a few characters when it shares a row. */
  min-width: 12ch;
}
@media (min-width: 768px) {
  .clip-table__toolbar > .clip-table__search { flex: 1 1 auto; max-width: 420px; }
}

.clip-table__count { font-size: var(--font-size-xs); color: var(--text-muted); }

.clip-table__empty {
  padding: var(--space-xl) var(--space-md);
  text-align: center;
  color: var(--text-muted);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-md);
}

/* --- card layout (mobile default) --- */
.clip-table__cards { display: flex; flex-direction: column; gap: var(--space-sm); }

.clip-card {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.75rem 0.9rem;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-family: var(--font-family-body);
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.clip-card:hover { border-color: var(--accent-gold); }
.clip-card:focus-visible { outline: none; box-shadow: var(--clip-focus-ring); }
.clip-card--static { cursor: default; }
.clip-card--static:hover { border-color: var(--border); }
.clip-card--selected { border-color: var(--accent-gold); background: var(--bg-elevated); }

.clip-card__top { display: flex; align-items: flex-start; gap: 0.6rem; }
.clip-card__title {
  flex: 1;
  min-width: 0;
  font-size: var(--font-size-base);
  font-weight: 700;
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.clip-card__actions { flex: none; display: flex; gap: 0.25rem; }

/* Some pages put a whole flex row inside the title cell - a name on the
   left, status buttons on the right - which is fine in a wide table cell
   but squeezes the name to a sliver in a card. The Door List rendered
   "Abraham, Cushla (Masterton/NZ )" down four lines with the bracket
   orphaned on its own. Let those rows wrap; the card only exists below
   1024px, so the table layout is unaffected. */
.clip-card__title > .d-flex {
  flex-wrap: wrap;
  gap: 0.4rem;
}
.clip-card__title > .d-flex > * { min-width: 0; }

.clip-card__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.45rem;
}
.clip-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  padding: 0.15rem 0.5rem;
  background: var(--bg-chip);
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  color: var(--text-secondary);
  max-width: 100%;
}
.clip-chip__label { color: var(--text-muted); }
.clip-chip__value { color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.clip-card__details { margin-top: 0.5rem; }
.clip-card__details summary {
  font-size: var(--font-size-xs);
  color: var(--accent-gold);
  cursor: pointer;
  min-height: var(--clip-touch-sm);
  display: flex;
  align-items: center;
}
.clip-card__detail-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: 0.25rem 0;
  font-size: var(--font-size-xs);
  border-bottom: 1px solid var(--border-subtle);
}
.clip-card__detail-row dt { color: var(--text-muted); flex: none; }
.clip-card__detail-row dd { margin: 0; text-align: right; overflow-wrap: anywhere; }

/* --- table layout (>= 1024px) --- */
.clip-table__scroll { display: none; }

@media (min-width: 1024px) {
  .clip-table__cards { display: none; }

  .clip-table__scroll {
    display: block;
    overflow-x: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    /* The row backgrounds below are dark, so the table has to carry its own
       text colour. Without this it inherits the page colour and you get
       black-on-navy on any page that is not already the dark admin shell. */
    background: var(--bg-surface);
    color: var(--text-primary);
  }

  .clip-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--font-size-sm);
    color: var(--text-primary);
  }

  .clip-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    text-align: left;
    font-weight: 700;
    white-space: nowrap;
    border-bottom: 1px solid var(--border-strong);
    padding: 0;
  }

  .clip-table__sort {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    min-height: var(--clip-touch-sm);
    padding: 0.5rem 0.75rem;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    font-weight: 700;
    cursor: pointer;
    text-align: left;
  }
  .clip-table__sort:hover { color: var(--text-primary); }
  .clip-table__sort[aria-sort="ascending"],
  .clip-table__sort[aria-sort="descending"] { color: var(--accent-gold); }
  .clip-table__sort-icon { opacity: 0.5; font-size: 0.75em; }
  .clip-table__sort[aria-sort="ascending"] .clip-table__sort-icon,
  .clip-table__sort[aria-sort="descending"] .clip-table__sort-icon { opacity: 1; }

  .clip-table th.clip-table__th--plain { padding: 0.5rem 0.75rem; }

  .clip-table tbody td {
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
  }

  .clip-table tbody tr { background: var(--bg-surface); }
  .clip-table tbody tr:nth-child(even) { background: var(--bg-inset); }
  .clip-table tbody tr:hover { background: var(--bg-chip); }
  .clip-table tbody tr.clip-table__row--clickable { cursor: pointer; }
  .clip-table tbody tr.clip-table__row--selected { background: var(--accent-gold-muted); }

  .clip-table__align-center { text-align: center; }
  .clip-table__align-right  { text-align: right; }
}

/* --- pager --- */
.clip-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-top: var(--space-md);
  flex-wrap: wrap;
}
.clip-pager__status { font-size: var(--font-size-xs); color: var(--text-muted); }

/* ============================================================
   10. SPINNER
   ============================================================ */

.clip-spinner {
  display: inline-block;
  width: var(--clip-spinner-size, 40px);
  height: var(--clip-spinner-size, 40px);
  border: 3px solid var(--accent-gold-muted);
  border-top-color: var(--accent-gold);
  border-radius: 50%;
  animation: clip-spin 800ms linear infinite;
}
@keyframes clip-spin { to { transform: rotate(360deg); } }

.clip-loading { display: flex; flex-direction: column; align-items: center; gap: var(--space-sm); padding: var(--space-xl) 0; color: var(--text-muted); }

/* ============================================================
   11. DRAWER (off-canvas nav)
   ============================================================ */

.clip-drawer {
  padding: 0;
  border: none;
  background: transparent;
  margin: 0;
  width: 100vw;
  max-width: 100vw;
  max-height: 100dvh;
  height: 100dvh;
  position: fixed;
  inset: 0;
  overflow: visible;
}

/* Only when open - a closed <dialog> must keep the UA's display:none. */
.clip-drawer[open] {
  display: flex;
  justify-content: flex-start;
}
.clip-drawer::backdrop { background: rgba(10, 10, 20, 0.72); }

.clip-drawer__panel {
  display: flex;
  flex-direction: column;
  width: min(85vw, 320px);
  height: 100dvh;
  background: var(--bg-surface);
  border-right: 1px solid var(--border-strong);
  animation: clip-drawer-in 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes clip-drawer-in {
  from { transform: translateX(-100%); }
  to   { transform: translateX(0); }
}

.clip-drawer__header {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md);
  padding-top: max(var(--space-md), env(safe-area-inset-top));
  border-bottom: 1px solid var(--border);
  flex: none;
}
.clip-drawer__body { flex: 1; overflow-y: auto; padding: var(--space-sm) 0; overscroll-behavior: contain; }

/* --- nav tree --- */
.clip-nav { list-style: none; margin: 0; padding: 0; }
.clip-nav__item { border: 0; }

.clip-nav__link,
.clip-nav__toggle {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  min-height: var(--clip-touch);
  padding: 0.5rem var(--space-md);
  background: none;
  border: 0;
  color: var(--text-secondary);
  font-family: var(--font-family-body);
  font-size: var(--font-size-sm);
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.clip-nav__link:hover, .clip-nav__toggle:hover { background: var(--bg-chip); color: var(--text-primary); }
.clip-nav__link.active { color: var(--accent-gold); background: var(--accent-gold-muted); box-shadow: inset 3px 0 0 var(--accent-gold); }
.clip-nav__icon { flex: none; width: 1.15rem; text-align: center; opacity: 0.8; }
.clip-nav__text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.clip-nav__caret { flex: none; font-size: 0.7rem; transition: transform var(--transition-fast); }
.clip-nav__toggle[aria-expanded="true"] .clip-nav__caret { transform: rotate(90deg); }
.clip-nav__children { list-style: none; margin: 0; padding: 0; }
.clip-nav__children .clip-nav__link { padding-left: calc(var(--space-md) + 1.8rem); font-size: var(--font-size-xs); }

/* ============================================================
   13. PAGE SURFACE
   The kit's tokens are a dark theme. Inside the admin shell,
   .control-container already supplies the background and text
   colour. A page reached by its own route has no such wrapper,
   so it needs this or it renders cream-on-white.
   ============================================================ */

.clip-page {
  background: var(--bg-primary);
  color: var(--text-primary);
  min-height: 100%;
}

/* Harmless when nested inside the admin shell - same values. */
.clip-page h1, .clip-page h2, .clip-page h3,
.clip-page h4, .clip-page h5, .clip-page h6 {
  color: var(--text-primary);
}

/* ============================================================
   12. UTILITIES
   ============================================================ */

.clip-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;
}

/* Body scroll lock while a sheet/drawer is open */
body.clip-scroll-locked { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .clip-dialog__panel,
  .clip-drawer__panel,
  .clip-toast,
  .clip-spinner { animation: none; }
}

/* --- table grouping --- */
.clip-group-header {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 0.5rem 0.25rem;
  margin-top: var(--space-sm);
  font-family: var(--font-family-heading);
  font-size: var(--font-size-lg);
  letter-spacing: 0.02em;
  color: var(--accent-gold);
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border-strong);
}

@media (min-width: 1024px) {
  .clip-table tbody tr.clip-table__group,
  .clip-table tbody tr.clip-table__group:hover {
    background: var(--bg-elevated);
  }
  .clip-table tbody tr.clip-table__group td {
    font-family: var(--font-family-heading);
    font-size: var(--font-size-lg);
    letter-spacing: 0.02em;
    color: var(--accent-gold);
    padding: 0.5rem 0.75rem;
  }
}

/* --- sponsor board (CompetitionSponsors) --- */
.sponsor-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}

@media (min-width: 768px)  { .sponsor-board { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px) { .sponsor-board { grid-template-columns: repeat(3, 1fr); } }

.sponsor-group {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-sm);
}

.sponsor-group__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 var(--space-sm);
  font-family: var(--font-family-heading);
  font-size: var(--font-size-lg);
  letter-spacing: 0.02em;
  color: var(--accent-gold);
}

.sponsor-group__count {
  font-family: var(--font-family-body);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  background: var(--bg-chip);
  border-radius: var(--radius-full);
  padding: 0.1rem 0.5rem;
}

.sponsor-group__empty { color: var(--text-muted); font-size: var(--font-size-sm); margin: 0; }

.sponsor-card {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 0.5rem;
  margin-bottom: var(--space-sm);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.sponsor-card__name { flex: 1; min-width: 0; overflow-wrap: anywhere; font-size: var(--font-size-sm); }
.sponsor-card__type { max-width: 150px; }

/* --- stand-allocation search panel (EditRounds) --- */
.sa-search-results { display: flex; flex-direction: column; gap: var(--space-sm); }
.sa-search-empty { color: var(--text-muted); font-size: var(--font-size-sm); }

.sa-search-card {
  padding: 0.6rem 0.75rem;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: grab;
}
.sa-search-card:active { cursor: grabbing; }
.sa-search-card-name { font-weight: 700; font-size: var(--font-size-sm); }
.sa-search-card-time { font-size: var(--font-size-xs); color: var(--text-muted); }
.sa-search-card-btns { display: flex; gap: var(--space-sm); margin-top: 0.5rem; }

/* ============================================================
   Bare table escape hatch

   ClipTable turns into cards below 1024px, but a handful of admin
   pages still render a plain <table>. On a phone those are wider
   than the viewport and drag the whole page sideways with them,
   which breaks every other screen on the page too. This confines
   the overflow to the table.
   ============================================================ */

.clip-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}

/* ============================================================
   Font Awesome fallbacks

   Font Awesome is referenced in ~140 places but has never been
   loaded - there is no <link> for it and no self-hosted font. Every
   <i class="fas fa-*"> therefore renders at zero width.

   Beside a text label that is only a missing decoration. In an
   icon-ONLY control it means an invisible button: the admin menu
   hamburger, the export buttons, print, phone check-in and the clear
   button on ClipTextBox were all blank boxes you had to know were
   there.

   These are glyphs rather than words on purpose. The same icon class
   appears both alone and next to a label ("Excel" on the Classes
   toolbar, bare on the Door List), and CSS cannot tell those apart -
   a text fallback rendered "XLS Excel". A symbol reads correctly in
   both positions.

   Scoped to :empty so nothing with real content is touched. If Font
   Awesome is ever loaded properly, delete this block. Better still,
   replace these few call sites with PortalIcon, which is the inline
   SVG set the portal already uses.
   ============================================================ */

i[class*="fa-"]:empty::before {
  font-family: inherit;
  font-style: normal;
  font-weight: 400;
  line-height: 1;
}

i.fa-bars:empty::before       { content: "\2630"; }        /* hamburger */
i.fa-times:empty::before      { content: "\2715"; }        /* clear / close */
i.fa-print:empty::before      { content: "\1F5A8\FE0E"; }  /* printer */
i.fa-mobile-alt:empty::before { content: "\1F4F1\FE0E"; }  /* phone */

/* Exports all read as "download" rather than naming the format, which
   the adjacent label already does where there is one. */
i.fa-file-pdf:empty::before,
i.fa-file-excel:empty::before,
i.fa-file-csv:empty::before   { content: "\2193"; font-weight: 700; }
