/* ============================================================
   Camp Quest Portal – Brand Design System
   Brand Colors: #0084b7 (Blue) · #20948b (Teal) · #fad97a (Yellow)
   Typography:   Omnes Bold (headlines) → Nunito 900 fallback
                 Nunito Sans (body)
   ============================================================ */

/* ------------------------------------------------------------------
   1. Design Tokens / CSS Custom Properties
   ------------------------------------------------------------------ */
:root {
  /* Brand palette */
  --cq-primary:        #0084b7;   /* Blue  – buttons, links, CTAs          */
  --cq-primary-dark:   #006a93;   /* ~10 % darker – hover / active states  */
  --cq-primary-darker: #00527a;   /* ~20 % darker – pressed states         */
  --cq-primary-light:  #e6f4fa;   /* Tint  – light bg, chips               */
  --cq-secondary:      #20948b;   /* Teal  – accents, secondary elements   */
  --cq-secondary-dark: #197870;   /* Teal hover                            */
  --cq-secondary-light:#e6f5f4;   /* Teal tint                             */
  --cq-highlight:      #fad97a;   /* Yellow – callouts, badges, highlights */
  --cq-highlight-dark: #f5c432;   /* Yellow hover/active                   */

  /* Neutrals */
  --cq-dark:   #1a2533;
  --cq-gray:   #4a5568;
  --cq-border: #dee2e6;
  --cq-light:  #f8f9fa;
  --cq-white:  #ffffff;

  /* Typography scale */
  --cq-font-heading: 'Nunito', 'Omnes', sans-serif;
  --cq-font-body:    'Nunito Sans', sans-serif;
  --cq-font-size-base: 0.9375rem;   /* 15 px */

  /* Spacing / radii */
  --cq-radius-sm: 0.375rem;
  --cq-radius:    0.5rem;
  --cq-radius-lg: 0.75rem;

  /* Shadows */
  --cq-shadow-sm: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);
  --cq-shadow:    0 4px 12px rgba(0,0,0,.10);
  --cq-shadow-lg: 0 8px 24px rgba(0,0,0,.12);
}

/* ------------------------------------------------------------------
   2. Base / Reset
   ------------------------------------------------------------------ */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  height: 100%;
}

body {
  font-family: var(--cq-font-body);
  font-size: var(--cq-font-size-base);
  color: var(--cq-dark);
  background-color: #f4f7f9;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

body > main { flex: 1 0 auto; }

/* Lighten placeholder text so it's clearly distinct from real input */
.form-control::placeholder { opacity: 0.45; }

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--cq-font-heading);
  font-weight: 900;
  color: var(--cq-dark);
  letter-spacing: -0.01em;
}

a {
  color: var(--cq-primary);
  text-decoration: none;
  transition: color .15s ease;
}
a:hover { color: var(--cq-primary-dark); }

/* ------------------------------------------------------------------
   3. Bootstrap Overrides — map Bootstrap variables to CQ tokens
   ------------------------------------------------------------------ */

/* Primary color overrides */
.btn-primary {
  background-color: var(--cq-primary) !important;
  border-color:     var(--cq-primary) !important;
  color: #fff !important;
  font-weight: 600;
  border-radius: var(--cq-radius);
  transition: background-color .15s ease, border-color .15s ease,
              box-shadow .15s ease, transform .1s ease;
}
.btn-primary:hover,
.btn-primary:focus {
  background-color: var(--cq-primary-dark) !important;
  border-color:     var(--cq-primary-dark) !important;
  box-shadow: 0 4px 10px rgba(0, 132, 183, .35) !important;
  transform: translateY(-1px);
}
.btn-primary:active {
  background-color: var(--cq-primary-darker) !important;
  border-color:     var(--cq-primary-darker) !important;
  transform: translateY(0);
}

.btn-outline-primary {
  color:        var(--cq-primary) !important;
  border-color: var(--cq-primary) !important;
  font-weight: 600;
  border-radius: var(--cq-radius);
  transition: background-color .15s ease, color .15s ease, transform .1s ease;
}
.btn-outline-primary:hover,
.btn-outline-primary:focus {
  background-color: var(--cq-primary) !important;
  color: #fff !important;
  transform: translateY(-1px);
}
/* Bootstrap btn-check pattern (tag/skill/badge filter chips).  Without
   this rule, the project's !important text color above wins over
   Bootstrap's :checked selector — the chip flips to a filled primary
   background but text stays dark blue → unreadable.  Override here
   matches the :hover/:focus treatment above. */
.btn-check:checked + .btn-outline-primary,
.btn-check:active + .btn-outline-primary {
  background-color: var(--cq-primary) !important;
  color: #fff !important;
}
.btn-check:checked + .btn-outline-success {
  background-color: var(--bs-success, #198754) !important;
  color: #fff !important;
}
.btn-check:checked + .btn-outline-info {
  background-color: var(--bs-info, #0dcaf0) !important;
  color: #fff !important;
}

.btn-secondary {
  background-color: var(--cq-secondary) !important;
  border-color:     var(--cq-secondary) !important;
  color: #fff !important;
  font-weight: 600;
  border-radius: var(--cq-radius);
}
.btn-secondary:hover,
.btn-secondary:focus {
  background-color: var(--cq-secondary-dark) !important;
  border-color:     var(--cq-secondary-dark) !important;
}

.btn-outline-secondary {
  color:        var(--cq-gray) !important;
  border-color: var(--cq-border) !important;
  font-weight: 600;
  border-radius: var(--cq-radius);
}
.btn-outline-secondary:hover {
  background-color: var(--cq-light) !important;
  border-color:     var(--cq-gray) !important;
}

/* All buttons consistent rounding */
.btn {
  border-radius: var(--cq-radius);
  font-family: var(--cq-font-body);
}

/* Text / bg utilities */
.bg-primary        { background-color: var(--cq-primary)   !important; }
.bg-secondary      { background-color: var(--cq-secondary)  !important; }
.text-primary      { color: var(--cq-primary) !important; }
.text-secondary    { color: var(--cq-secondary) !important; }
.border-primary    { border-color: var(--cq-primary) !important; }

/* Badges */
.badge.bg-primary  { background-color: var(--cq-primary)  !important; }
.badge.bg-secondary{ background-color: var(--cq-secondary) !important; }

/* Form controls */
.form-control:focus,
.form-select:focus {
  border-color: var(--cq-primary);
  box-shadow: 0 0 0 .2rem rgba(0, 132, 183, .2);
}

/* Links in tables / subtle contexts */
.table a { color: var(--cq-primary); }
.table a:hover { color: var(--cq-primary-dark); text-decoration: underline; }

/* ------------------------------------------------------------------
   4. Navbar
   ------------------------------------------------------------------ */
.cq-navbar {
  background-color: var(--cq-primary) !important;
  box-shadow: var(--cq-shadow);
  padding-top: .65rem;
  padding-bottom: .65rem;
  /* Sit above Bootstrap .sticky-top (z-index: 1020) so our dropdowns
     (org switcher, user menu) render in front of sticky sidebars —
     otherwise the registration card on session-detail covers them. */
  position: relative;
  z-index: 1030;
}

.cq-navbar .navbar-brand {
  padding: 0;
  line-height: 1;
}

.cq-navbar .navbar-brand img {
  height: 40px;
  width: auto;
}

/* Nav links on primary-blue background — must pass WCAG AA */
.cq-navbar .nav-link {
  color: rgba(255,255,255,.9) !important;
  font-weight: 600;
  padding: .4rem .75rem;
  border-radius: var(--cq-radius-sm);
  transition: background-color .15s ease, color .15s ease;
}
.cq-navbar .nav-link:hover,
.cq-navbar .nav-link:focus {
  color: #fff !important;
  background-color: rgba(255,255,255,.15);
}
.cq-navbar .nav-link.active {
  color: #fff !important;
  background-color: rgba(255,255,255,.2);
}

/* Toggler on brand-blue background */
.cq-navbar .navbar-toggler {
  border-color: rgba(255,255,255,.5);
}
.cq-navbar .navbar-toggler-icon {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255%2c255%2c255%2c0.9%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* Dropdown menus */
.cq-navbar .dropdown-menu {
  border: none;
  box-shadow: var(--cq-shadow-lg);
  border-radius: var(--cq-radius);
  padding: .5rem 0;
}
.cq-navbar .dropdown-item {
  font-size: .9rem;
  padding: .45rem 1rem;
  transition: background-color .12s;
}
.cq-navbar .dropdown-item:hover {
  background-color: var(--cq-primary-light);
  color: var(--cq-primary);
}

/* When an embedded video iframe goes fullscreen, drop the aspect-ratio /
   min-height constraints applied inline for mobile sizing. Without these
   overrides, the inline `aspect-ratio: 16/9; min-height: 320px` rules
   (used to keep Drive's preview player from over-scaling on mobile)
   would keep the iframe 16:9-shaped even in fullscreen, making the player
   appear to just zoom in within its original frame. */
iframe:fullscreen {
  width: 100vw !important;
  height: 100vh !important;
  max-width: none !important;
  max-height: none !important;
  aspect-ratio: auto !important;
  min-height: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
}

/* Org switcher button — sits outside the collapse so it's always visible.
   Styled to match the navbar primary background (semi-transparent over
   the org's theme color). */
.cq-navbar .cq-org-switcher-btn {
  background-color: rgba(255, 255, 255, 0.15);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.3);
  font-weight: 500;
  padding: .35rem .75rem;
  transition: background-color .15s;
}
.cq-navbar .cq-org-switcher-btn:hover,
.cq-navbar .cq-org-switcher-btn:focus,
.cq-navbar .cq-org-switcher-btn[aria-expanded="true"] {
  background-color: rgba(255, 255, 255, 0.28);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.5);
}
.cq-navbar .cq-org-switcher-btn .dropdown-toggle::after,
.cq-navbar .cq-org-switcher-btn::after {
  margin-left: .35rem;
}

/* Sign-up pill button in navbar */
.cq-navbar .btn-signup {
  background-color: var(--cq-highlight);
  color: var(--cq-dark) !important;
  border: none;
  font-weight: 700;
  padding: .35rem 1rem;
  border-radius: 2rem;
  font-size: .875rem;
  transition: background-color .15s ease, transform .1s ease;
}
.cq-navbar .btn-signup:hover {
  background-color: var(--cq-highlight-dark);
  transform: translateY(-1px);
}

/* ------------------------------------------------------------------
   5. Sidebar (affiliate + central portals)
   ------------------------------------------------------------------ */
.cq-sidebar {
  border-radius: var(--cq-radius-lg);
  box-shadow: var(--cq-shadow-sm);
  overflow: hidden;
  background: var(--cq-white);
}

.cq-sidebar-header {
  background: linear-gradient(135deg, var(--cq-primary), var(--cq-secondary));
  color: #fff;
  padding: .85rem 1rem;
  font-size: .7rem;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  font-family: var(--cq-font-heading);
}

.cq-sidebar-nav .list-group-item {
  border: none;
  border-left: 3px solid transparent;
  padding: .6rem 1rem;
  font-size: .875rem;
  font-weight: 600;
  color: var(--cq-gray);
  background: transparent;
  transition: color .12s, background-color .12s, border-left-color .12s;
}
.cq-sidebar-nav .list-group-item i {
  opacity: .7;
  transition: opacity .12s;
}
.cq-sidebar-nav .list-group-item:hover {
  background-color: var(--cq-primary-light);
  color: var(--cq-primary);
  border-left-color: var(--cq-primary);
}
.cq-sidebar-nav .list-group-item:hover i { opacity: 1; }
.cq-sidebar-nav .list-group-item.active {
  background-color: var(--cq-primary-light) !important;
  color: var(--cq-primary) !important;
  border-left-color: var(--cq-primary) !important;
  font-weight: 700;
}
.cq-sidebar-nav .list-group-item.active i { opacity: 1; }

/* Central admin sidebar: teal accent */
.cq-sidebar-central .cq-sidebar-header {
  background: linear-gradient(135deg, var(--cq-dark), #2d3748);
}
.cq-sidebar-central .list-group-item:hover {
  background-color: var(--cq-secondary-light);
  color: var(--cq-secondary);
  border-left-color: var(--cq-secondary);
}
.cq-sidebar-central .list-group-item.active {
  background-color: var(--cq-secondary-light) !important;
  color: var(--cq-secondary) !important;
  border-left-color: var(--cq-secondary) !important;
}

/* Sidebar collapsible section headers */
.cq-sidebar-section {
  font-size: .65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: #94a3b8;
  padding: .75rem 1rem .25rem;
  margin-top: .25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  user-select: none;
  transition: color .15s;
  background: none;
  border: none;
  border-top: 1px solid #e2e8f0;
  width: 100%;
  text-align: left;
  font-family: inherit;
}
.cq-sidebar-section:first-child {
  border-top: none;
  margin-top: 0;
}

/* ------------------------------------------------------------------
   6. Cards
   ------------------------------------------------------------------ */
.card {
  border: 1px solid rgba(0,0,0,.06);
  border-radius: var(--cq-radius-lg);
  box-shadow: var(--cq-shadow-sm);
  background: var(--cq-white);
}
.card-header {
  font-family: var(--cq-font-heading);
  font-weight: 700;
  border-bottom: 1px solid rgba(0,0,0,.06);
}
.card-header.bg-primary {
  background: linear-gradient(135deg, var(--cq-primary), var(--cq-secondary)) !important;
  color: #fff !important;
  border-bottom: none;
}
.card-header.bg-dark {
  background: var(--cq-dark) !important;
  color: #fff !important;
}

/* Stat cards (dashboard) */
.stat-card {
  border-left: 4px solid var(--cq-primary);
  border-radius: var(--cq-radius-lg);
}
.stat-card.teal  { border-left-color: var(--cq-secondary); }
.stat-card.yellow{ border-left-color: var(--cq-highlight); }
.stat-card .stat-value {
  font-family: var(--cq-font-heading);
  font-size: 2.25rem;
  font-weight: 900;
  color: var(--cq-primary);
  line-height: 1;
}

/* ------------------------------------------------------------------
   7. Tables
   ------------------------------------------------------------------ */
.table {
  font-size: .875rem;
}
.table > thead {
  background-color: #f0f4f8;
}
.table > thead th {
  font-family: var(--cq-font-heading);
  font-weight: 700;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--cq-gray);
  border-bottom: 2px solid var(--cq-border);
  padding: .65rem .75rem;
}
.table > tbody tr:hover {
  background-color: var(--cq-primary-light);
  transition: background-color .1s;
}
.roster-table th {
  background-color: #f0f4f8;
  font-weight: 700;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .05em;
}

/* ------------------------------------------------------------------
   8. Badges & Status Chips
   ------------------------------------------------------------------ */
.badge {
  font-family: var(--cq-font-body);
  font-weight: 700;
  letter-spacing: .02em;
  border-radius: 2rem;
  padding: .3em .65em;
}

.badge-complete  { background-color: #198754; color: #fff; }
.badge-pending   { background-color: var(--cq-highlight); color: var(--cq-dark); }
.badge-waitlist  { background-color: var(--cq-secondary); color: #fff; }

/* Status color helpers */
.status-published { color: #198754; font-weight: 700; }
.status-draft     { color: var(--cq-gray); }
.status-closed    { color: #dc3545; font-weight: 700; }

/* ------------------------------------------------------------------
   9. Page Header / Hero Section
   ------------------------------------------------------------------ */
.cq-page-hero {
  background: linear-gradient(135deg, var(--cq-primary) 0%, var(--cq-secondary) 100%);
  color: #fff;
  padding: 3rem 0 2.5rem;
  margin-bottom: 2rem;
}
.cq-page-hero h1,
.cq-page-hero .h1 {
  color: #fff;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
}

/* Public home page search hero */
.cq-home-hero {
  background: linear-gradient(135deg, var(--cq-primary) 0%, var(--cq-secondary) 100%);
  padding: 4rem 2rem;
  border-radius: var(--cq-radius-lg);
  color: #fff;
  margin-bottom: 2.5rem;
}
.cq-home-hero h1 { color: #fff; font-size: clamp(2rem, 5vw, 3rem); }
.cq-home-hero .lead { color: rgba(255,255,255,.85); font-size: 1.1rem; }

/* ------------------------------------------------------------------
   10. Form Builder
   ------------------------------------------------------------------ */
.field-builder-item {
  border: 1px solid var(--cq-border);
  border-radius: var(--cq-radius);
  padding: 1rem;
  margin-bottom: .75rem;
  background: var(--cq-white);
  transition: border-color .15s;
}
.field-builder-item:hover {
  border-color: var(--cq-primary);
  box-shadow: 0 0 0 3px rgba(0,132,183,.08);
}

/* ------------------------------------------------------------------
   11. Capacity Bar
   ------------------------------------------------------------------ */
.capacity-bar {
  height: 6px;
  border-radius: 3px;
  background: #e9ecef;
  overflow: hidden;
}
.capacity-bar-fill {
  height: 100%;
  border-radius: 3px;
  background: var(--cq-primary);
  transition: width .3s ease;
}
.capacity-bar-fill.nearly-full { background: var(--cq-highlight); }
.capacity-bar-fill.full        { background: #dc3545; }

/* ------------------------------------------------------------------
   12. Checklist / Registration flow
   ------------------------------------------------------------------ */
.checklist-item-complete { opacity: .7; }
.checklist-item-pending  { font-weight: 600; }

.checklist-step {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: .75rem 0;
  border-bottom: 1px solid var(--cq-border);
}
.checklist-step:last-child { border-bottom: none; }

.checklist-icon {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .9rem;
  flex-shrink: 0;
}
.checklist-icon.complete  { background: #d1fae5; color: #198754; }
.checklist-icon.pending   { background: var(--cq-primary-light); color: var(--cq-primary); }
.checklist-icon.blocked   { background: #fee2e2; color: #dc3545; }

/* ------------------------------------------------------------------
   13. Alerts — map to brand palette
   ------------------------------------------------------------------ */
.alert-info {
  background-color: var(--cq-primary-light);
  border-color: rgba(0,132,183,.25);
  color: var(--cq-primary-darker);
}
.alert-success {
  background-color: #d1fae5;
  border-color: #a7f3d0;
  color: #065f46;
}
.alert-warning {
  background-color: #fffbeb;
  border-color: var(--cq-highlight);
  color: #92400e;
}

/* ------------------------------------------------------------------
   14. Footer
   ------------------------------------------------------------------ */
.cq-footer {
  background-color: var(--cq-white);
  border-top: 1px solid var(--cq-border);
  padding: 1.5rem 0;
}
.cq-footer-logo img { height: 32px; width: auto; opacity: .8; }
.cq-footer small { color: #6b7280; }

/* ------------------------------------------------------------------
   15. Affiliate logo placeholder
   ------------------------------------------------------------------ */
.affiliate-logo-placeholder {
  height: 160px;
  background: linear-gradient(135deg, var(--cq-primary), var(--cq-secondary));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3rem;
  color: var(--cq-white);
}

/* ------------------------------------------------------------------
   16. HTMX loading indicator
   ------------------------------------------------------------------ */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator  { display: inline-block; }
.htmx-request.htmx-indicator   { display: inline-block; }

/* ------------------------------------------------------------------
   17. Print styles
   ------------------------------------------------------------------ */
@media print {
  .cq-navbar, .cq-footer, .cq-sidebar, .cq-sidebar-col, .btn, .no-print { display: none !important; }
  body { background: #fff; color: #000; }
  .card { border: 1px solid #ccc !important; box-shadow: none !important; }
}

/* ------------------------------------------------------------------
   18. Responsive — Mobile-first PWA optimizations
   ------------------------------------------------------------------ */

/* ── Touch targets: minimum 44×44 px (WCAG 2.5.5) ── */
@media (max-width: 991.98px) {
  .btn, .dropdown-item, .list-group-item-action {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  /* Nav links: enforce touch target height without overriding Bootstrap display */
  .nav-link {
    min-height: 44px;
  }
  .cq-sidebar-nav .list-group-item {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
  .cq-sidebar-section {
    min-height: 44px;
  }
}

/* ── Sidebar → off-canvas on mobile ── */
@media (max-width: 767.98px) {
  .cq-sidebar-col {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1045;
    width: 280px;
    height: 100vh;
    overflow-y: auto;
    background: var(--cq-white);
    box-shadow: var(--cq-shadow-lg);
    transform: translateX(-100%);
    transition: transform 0.25s ease-in-out;
  }
  .cq-sidebar-col.show {
    transform: translateX(0);
  }
  .cq-sidebar-backdrop {
    display: none;
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    z-index: 1044;
    background: rgba(0,0,0,.4);
  }
  .cq-sidebar-backdrop.show {
    display: block;
  }
  .cq-sidebar-col .cq-sidebar {
    border-radius: 0;
    box-shadow: none;
  }
  /* Close button inside off-canvas sidebar */
  .cq-sidebar-close {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--cq-border);
  }
  .cq-sidebar-close button {
    background: none;
    border: none;
    font-size: 1.25rem;
    padding: 0.5rem;
    color: var(--cq-gray);
    cursor: pointer;
    min-height: 44px;
    min-width: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* Sidebar toggle button (fixed FAB-style) */
  .cq-sidebar-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    bottom: 1rem;
    left: 1rem;
    z-index: 1040;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--cq-primary);
    color: #fff;
    border: none;
    box-shadow: var(--cq-shadow-lg);
    font-size: 1.2rem;
    cursor: pointer;
    transition: background 0.15s, transform 0.1s;
  }
  .cq-sidebar-toggle:hover {
    background: var(--cq-primary-dark);
  }
  .cq-sidebar-toggle:active {
    transform: scale(0.95);
  }

  /* Stat cards */
  .stat-card .stat-value { font-size: 1.75rem; }

  /* Stack cards in a single column */
  .row-cols-md-2, .row-cols-md-3, .row-cols-lg-3 {
    --bs-columns: 1;
  }

  /* Compact page headings */
  h1, .h1 { font-size: 1.5rem; }
  h2, .h2 { font-size: 1.25rem; }

  /* Full-width buttons on mobile */
  .btn-group-mobile .btn {
    width: 100%;
    margin-bottom: 0.25rem;
  }
}

/* Hide sidebar toggle on desktop */
@media (min-width: 768px) {
  .cq-sidebar-toggle { display: none !important; }
  .cq-sidebar-close { display: none !important; }
  .cq-sidebar-backdrop { display: none !important; }
}

/* ── Form improvements for mobile ── */
@media (max-width: 767.98px) {
  .form-control, .form-select {
    font-size: 1rem; /* Prevent iOS zoom on focus */
    min-height: 44px;
  }

  /* Stack form actions */
  .form-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .form-actions .btn {
    width: 100%;
  }
}

/* ── PWA standalone mode tweaks ── */
@media (display-mode: standalone) {
  /* Extra top padding when in standalone (no browser chrome) */
  .cq-navbar {
    padding-top: max(0.65rem, env(safe-area-inset-top));
  }
  body {
    /* Respect safe areas (notch, home indicator) */
    padding-bottom: env(safe-area-inset-bottom);
  }
}

/* ── Safe area support for PWA ── */
@supports (padding: env(safe-area-inset-top)) {
  .cq-navbar {
    padding-left: max(0.75rem, env(safe-area-inset-left));
    padding-right: max(0.75rem, env(safe-area-inset-right));
  }
}

/* ── Announcements easter egg ──
   Camp tradition: saying "announcements" obliges everyone to sing the
   Announcements Song. Clicking the megaphone on the announcements card
   pops the first line as a toast (see static/js/main.js) and wiggles
   the icon. */
.announcement-egg {
  cursor: pointer;
  text-decoration: none;
}

.announcement-egg:hover .bi-megaphone-fill {
  transform: scale(1.1);
}

.announcement-egg .bi-megaphone-fill {
  display: inline-block;
  transition: transform 0.15s ease;
}

@keyframes cq-wiggle {
  0%, 100% { transform: rotate(0deg); }
  20%      { transform: rotate(-14deg); }
  40%      { transform: rotate(10deg); }
  60%      { transform: rotate(-8deg); }
  80%      { transform: rotate(5deg); }
}

.cq-wiggle {
  animation: cq-wiggle 0.55s ease-in-out;
}

/* First reduced-motion block in this file. The joke degrades to text,
   not to nothing: the toast still fires, the icon just holds still. */
@media (prefers-reduced-motion: reduce) {
  .cq-wiggle {
    animation: none;
  }
  .announcement-egg .bi-megaphone-fill,
  .announcement-egg:hover .bi-megaphone-fill {
    transition: none;
    transform: none;
  }
}

/* ── Floating stack for JS-fired toasts ──
   Flash messages rendered by Django stay in page flow near the top, where
   the reader lands after a redirect. Toasts raised by JS (cqShowToast) are
   different: they answer a control the reader just used, which may be far
   down a long page, so they float in the viewport instead of scrolling away
   with the document. Bootstrap's toast layer is z-index 1090; .cq-navbar is
   1030 and not sticky. */
.cq-toast-stack {
  position: fixed;
  /* Anchored to the bottom, not the top: at scroll-top a top-right stack
     covers the navbar's user menu and org switcher for the full 8s the
     toast lives, which measured as a real regression (toast x816-1264 over
     the user menu at x1044-1198). The navbar is not sticky, so the bottom
     edge is never contested. */
  bottom: calc(1rem + env(safe-area-inset-bottom));
  right: 1rem;
  z-index: 1090;
  width: min(28rem, calc(100vw - 2rem));
  display: flex;
  flex-direction: column;
  gap: .5rem;
  /* The stack spans a wide empty area; only the toasts themselves should
     swallow clicks, or it would block the page underneath. */
  pointer-events: none;
}

.cq-toast-stack .alert {
  pointer-events: auto;
  margin-bottom: 0;
}

/* ── Announcements easter egg: the reply bubble ──
   Anchored to the megaphone by JS (see cqShowEggBubble in main.js), which
   sets top/left. Fixed rather than absolute so it is not clipped by the
   narrow sidebar column the announcements card sits in.

   Opacity is never animated, and that is the point. The entrance animates
   transform only, so the bubble is opaque at every instant of it -- including
   time zero, which is where an animation sits forever in a tab that produces
   no frames. An earlier draft faded in from opacity 0 and measured as
   permanently invisible under exactly that condition. Whatever goes wrong
   here, the failure mode is "no movement", never "silently invisible" --
   which is the bug this feature already shipped once. */
.cq-egg-bubble {
  position: fixed;
  z-index: 1090;
  max-width: min(20rem, calc(100vw - 2rem));
  padding: .5rem .75rem;
  border-radius: .75rem;
  background: var(--bs-warning-bg-subtle, #fff3cd);
  border: 1px solid var(--bs-warning-border-subtle, #ffe69c);
  color: var(--bs-body-color, #212529);
  box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
  font-weight: 600;
  /* The bubble is decoration answering a click; it must never swallow one. */
  pointer-events: none;
  opacity: 1;
  animation: cq-egg-pop .18s ease;
}

@keyframes cq-egg-pop {
  from { transform: translateY(-.25rem) scale(.97); }
  to   { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .cq-egg-bubble {
    animation: none;
  }
}

/* Side Quests — the camp filter strip.
   With a dozen affiliates this row is ~14 chips. Left to wrap it fills a
   phone screen and pushes every quest card below the fold, so below `md` it
   becomes one swipeable line instead. `flex-shrink: 0` is load-bearing:
   without it the chips compress to fit and the row never scrolls at all.

   These rules live here rather than in the board template's
   {% block extra_css %} because <body> sets hx-boost and htmx 1.9 drops
   <head> from a boosted response — in extra_css they silently vanish when
   the board is reached from My Quests' "Back to Side Quests" link, and the
   chips squash into slivers at every width. */
.camp-filters {
  flex-wrap: wrap;
}

@media (max-width: 767.98px) {
  .camp-filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: .25rem;
  }

  .camp-filters > .btn {
    flex-shrink: 0;
  }
}

/* Side Quests — the kanban board.
   Shared by the affiliate board (templates/quests/board.html) and the central
   board (templates/quests/central_board.html), which render the same
   quests/_board_content.html partial.

   These rules live here rather than in either template's {% block extra_css %}
   because <body> sets hx-boost and htmx 1.9 keeps only the body of a boosted
   response — in extra_css they vanish whenever the board is reached from a
   sidebar link, and the columns lose `display: flex` and stack full-width.
   See CLAUDE.md, "Things That Will Bite You" #15. */
.quest-board {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  padding-bottom: 1rem;
  align-items: flex-start;
}

.quest-board .quest-column {
  min-width: 240px;
  max-width: 280px;
  flex-shrink: 0;
}

.quest-board .quest-column .card {
  border-top: 3px solid var(--cq-primary, #0d6efd);
}

.quest-board .quest-draggable {
  cursor: grab;
}

/* Scoped to .quest-board on purpose: `sortable-ghost` and `sortable-list` are
   generic SortableJS class names, and the cabin board sets its own
   `.cabin-board .occupant-card.sortable-ghost`. Unscoped, these would reach it. */
.quest-board .sortable-ghost {
  opacity: 0.4;
}

.quest-board .sortable-list {
  min-height: 60px;
}

/* Cabin assignment board — the drag-and-drop kanban.
   Rendered by templates/housing/staff_cabin_board.html via the
   housing/_board_content.html partial.

   Here rather than in that template's {% block extra_css %} for the hx-boost
   reason — see CLAUDE.md #15 and the Side Quests block above.

   The readonly variant was a `{% if is_readonly %}` inside the old inline
   <style>, which a static file cannot express. It is now a class on the
   partial's root element, which is strictly better: the partial is what htmx
   swaps in on every assignment change, so the styling tracks the swapped
   content rather than the value that happened to be true at first paint. */
.cabin-board {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  padding-bottom: 1rem;
  align-items: flex-start;
}

.cabin-board .cabin-column {
  min-width: 220px;
  max-width: 260px;
  flex-shrink: 0;
}

.cabin-board .cabin-column .card {
  border-top: 3px solid var(--cq-primary, #0d6efd);
}

.cabin-board .cabin-column.unassigned-pool {
  min-width: 250px;
}

.cabin-board .cabin-column.unassigned-pool .card {
  border-top-color: #6c757d;
}

.cabin-board .occupant-card {
  cursor: grab;
  border-left: 3px solid transparent;
  transition: all 0.15s;
}

.cabin-board .occupant-card:hover {
  background-color: rgba(var(--bs-primary-rgb), 0.05);
}

.cabin-board .occupant-card.camper {
  border-left-color: var(--cq-primary, #0d6efd);
}

.cabin-board .occupant-card.counselor {
  border-left-color: #198754;
}

.cabin-board .occupant-card.locked {
  opacity: 0.8;
  cursor: default;
}

.cabin-board .occupant-card.sortable-ghost {
  opacity: 0.4;
}

.cabin-board .occupant-card .badge-accessible {
  font-size: 0.65rem;
}

/* Was `{% if is_readonly %}.occupant-card { cursor: default; }{% endif %}`.
   Higher specificity than the `cursor: grab` above, so order does not matter. */
.cabin-board.is-readonly .occupant-card {
  cursor: default;
}

/* .table-stack — the project mechanism for restacking a table into cards
   below `md`, not a Side-Quests-only pattern. Currently used by the central
   earnings table (templates/quests/earnings.html) and the quest-detail
   claims table (templates/quests/_quest_detail_body.html, included by both
   the affiliate and central detail pages) — reach for it first the next time
   a staff table needs to stop scrolling sideways on a phone, rather than
   reinventing the same rules under a new class name.

   Below `md` the header row is hidden and each row becomes a bordered card,
   with every cell printing its own label. The criterion for choosing this
   over a hand-tuned card list is whether the table carries forms. Both
   Side Quests tables do — a bulk-select checkbox and six
   Approve/Decline/Complete forms — so reflowing the one rendering avoids two
   copies of every button that would drift apart. `my_quests.html` is
   read-only, so it takes the other approach: a duplicate, hand-tuned card
   list alongside the desktop table. That duplication is exactly the drift
   risk this comment warns about elsewhere on this file — the branch judged
   it an acceptable trade there specifically because there are no forms to
   duplicate, only display markup.

   Cells opt in explicitly rather than by position, because these two tables
   order their columns differently — earnings leads with a checkbox, the claims
   table with a name:
     data-label="Quest"   -> prints the label, then the value
     class="stack-title"  -> the card's heading, no label
     class="stack-select" -> inline with the heading (the earnings checkbox)
     class="stack-actions"-> a full-width block at the bottom, no label
     no marker            -> plain and unlabelled (the empty-state colspan row)

   These rules live here rather than in either template's {% block extra_css %}
   because <body> sets hx-boost and htmx 1.9 drops <head> from a boosted
   response — see CLAUDE.md item 15. */
@media (max-width: 767.98px) {
  .table-stack,
  .table-stack tbody,
  .table-stack tr,
  .table-stack td {
    display: block;
  }

  .table-stack thead {
    display: none;
  }

  .table-stack tr {
    border: 1px solid var(--cq-border);
    border-radius: .375rem;
    padding: .5rem .75rem;
    margin-bottom: .5rem;
  }

  /* Bootstrap paints every cell white via `.table > :not(caption) > * > *`,
     which sets `background-color: var(--bs-table-bg)` (default #fff) and — in
     Bootstrap 5.3 — also an inset `box-shadow: inset 0 0 0 9999px
     var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))`
     for striping/hover, keyed off the same custom property chain. Overriding
     `background-color` alone would leave that box-shadow free to repaint the
     cell, so the custom property itself is reset instead — it flows through
     both rules at once and leaves the card's own surface showing, including
     under `.stack-title`, whose `display: inline-block` would otherwise draw
     a white box hugging just the text.

     `--bs-table-bg-state` is the second half of the same problem and needs its
     own reset: `.table-hover > tbody > tr:hover > *` sets it to
     `--bs-table-hover-bg`, and the box-shadow above resolves
     `var(--bs-table-bg-state, var(--bs-table-bg-type, ...))` — consulting
     `-state` FIRST, so neutralising `--bs-table-bg` alone does not stop hover
     repainting the card. Measured in Chrome at 375px: hovering a stacked row
     put `rgba(0, 0, 0, 0.075) 0 0 0 9999px inset` on every cell, drawing a
     wash that stopped short of the card's own padding and — on `.stack-title`,
     which is `inline-block` — a grey box hugging just the camper's name.
     Below `md` each row is already a bordered card, so it needs no hover
     shading; above `md` nothing here applies and `table-hover` behaves
     normally. Do not "fix" this by dropping `table-hover` from a table — that
     would change the desktop rendering too, and do not collapse the reset
     below into the `.table-stack` block: see the specificity note there. */
  .table-stack {
    --bs-table-bg: transparent;
  }

  /* Must out-specify Bootstrap's own hover rule, not merely sit above these
     cells. `--bs-table-bg` above works by inheritance because Bootstrap only
     READS it, in the low-specificity base rule below. Hover is different: it
     SETS `--bs-table-bg-state` on the cell itself via
     `.table-hover > tbody > tr:hover > *` — (0,2,2) — so a declaration on the
     ancestor `.table-stack` — (0,1,0) — loses outright and the wash still
     paints. Measured, not reasoned: the ancestor-only form was tried first in
     the browser and changed nothing. This selector is (0,3,2). */
  .table-stack.table-hover > tbody > tr:hover > * {
    --bs-table-bg-state: transparent;
  }

  /* Bootstrap styles cells through `.table > :not(caption) > * > *`, which ties
     with `.table-stack td` on specificity and would be decided by load order.
     This selector wins outright instead. */
  .table-stack > tbody > tr > td {
    border: 0;
    padding: .125rem 0;
  }

  .table-stack td[data-label]::before {
    content: attr(data-label);
    display: inline-block;
    width: 7.5rem;
    color: var(--cq-gray);
    font-size: .875rem;
  }

  .table-stack .stack-select,
  .table-stack .stack-title {
    display: inline-block;
    vertical-align: middle;
  }

  .table-stack .stack-select {
    margin-right: .5rem;
  }

  .table-stack .stack-title {
    font-weight: 600;
  }

  .table-stack .stack-actions {
    padding-top: .5rem;
  }
}

/* Report print rules — scoped to .cq-report container.
 *
 * These live here and NOT in {% block extra_css %}. templates/base.html sets
 * hx-boost="true" without htmx's head-support extension, so on any in-app
 * navigation htmx keeps only the response <body> and discards the parsed
 * <head>. Rules placed in extra_css work on a hard reload and vanish for every
 * user who arrives by clicking a link — which is every user.
 * tests/test_extra_css_boost_safe.py enforces this repo-wide.
 *
 * Report content is wrapped in <div class="cq-report"> (templates/reporting/_report_body.html).
 * All rules below are scoped to that container and affect only reports, not other pages.
 * Chrome-hiding rules (navbar, footer, sidebar, buttons) are in section 17 (line 664).
 *
 * There is no `a[href]::after { content: none }` here any more. It was written
 * to counter Bootstrap 4's print reboot, which appended the URL after every
 * link; Bootstrap 5 dropped that rule, and this project loads 5.3.3
 * (templates/base.html:31). Verified against the file actually served:
 *
 *   $ curl -s https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css \
 *       | grep -c 'a\[href\]'
 *   0
 *
 * Its only `@media print` block is the `.d-print-*` display utilities. The
 * rule countered nothing, so it is gone rather than left to read as though
 * some behaviour depended on it.
 */
@media print {
  .cq-report form { display: none !important; }
  .cq-report .pagination { display: none !important; }
  .cq-report .card { border: none !important; box-shadow: none !important; }
  .cq-report table { font-size: 9pt; }
  .cq-report thead { display: table-header-group; }
}
