/*
 * VoluntX design system v2 (see handoff.md Phase 10 and tokens.css's
 * header). Component classes only;
 * color/type/radius tokens live in tokens.css as Bootstrap --bs-* variable
 * overrides, so every plain `card`/`table`/`btn`/`badge` in the 34 existing
 * views re-themes with zero markup changes. Anything here is for shapes the
 * mockups introduced that Bootstrap has no equivalent for: the sidebar
 * shell, KPI stat cards, status chips, the data-mono table treatment.
 *
 * CSP is style-src 'self' with no 'unsafe-inline' -- no style="" anywhere
 * in this app, including here (Bootstrap's own compiled CSS is the only
 * exception, since it ships as an external stylesheet). Percentage widths
 * use the .vx-fill-* steps from tokens.css instead.
 */

/* ---- Fonts --------------------------------------------------------------
 * @import must precede every other rule in the file (CSS spec) or the
 * browser silently drops it -- this pair used to sit after the `body`
 * rule below, which meant bootstrap-icons and the self-hosted fonts never
 * actually loaded: every icon rendered as an empty glyph, which is why
 * the notification bell / theme toggle looked "invisible". */
@import url("../vendor/fonts/fonts.css");
@import url("../vendor/bootstrap-icons/bootstrap-icons.css");

body {
  background-color: var(--bs-body-bg);
}

/* ---- App shell: sidebar + topbar ---------------------------------------- */
.vx-shell {
  display: flex;
  min-height: 100vh;
}

.vx-sidebar {
  width: var(--vx-sidebar-width);
  flex-shrink: 0;
  background-color: var(--vx-surface-container-low);
  border-right: 1px solid var(--vx-outline-variant);
  display: flex;
  flex-direction: column;
  padding: var(--vx-space-md) var(--vx-space-sm);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.vx-sidebar-brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--vx-space-sm);
  padding: 0 var(--vx-space-sm);
  margin-bottom: var(--vx-space-lg);
}

.vx-sidebar-logo {
  display: flex;
  align-items: center;
  gap: var(--vx-space-sm);
  min-width: 0;
}

.vx-sidebar-brand .vx-brand-title {
  color: var(--vx-primary-bright);
}

/* Circular light backing plate for the dark-line-art VoluntX mark, so it
   stays visible whether it sits on the true-black dark shell or a light
   report page -- the source PNG itself has no dark-mode variant. */
.vx-logo-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background-color: #f8fafc;
  border: 1px solid var(--vx-outline-variant);
  overflow: hidden;
}

.vx-logo-badge img {
  width: 70%;
  height: 70%;
  object-fit: contain;
}

.vx-logo-badge-lg {
  width: 4rem;
  height: 4rem;
}

.vx-sidebar-toggle {
  flex-shrink: 0;
}

.vx-sidebar-nav {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  overflow-y: auto;
}

.vx-sidebar-link {
  display: flex;
  align-items: center;
  gap: var(--vx-space-sm);
  padding: 0.5rem 0.75rem;
  border-radius: var(--bs-border-radius);
  color: var(--vx-on-surface-variant);
  text-decoration: none;
  border-right: 2px solid transparent;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.vx-sidebar-link:hover {
  background-color: var(--vx-surface-container-high);
  color: var(--vx-on-surface);
}

.vx-sidebar-link.active {
  color: var(--vx-primary-bright);
  background-color: var(--vx-surface-container-high);
  border-right-color: var(--vx-primary-bright);
  font-weight: 600;
}

.vx-sidebar-link .bi {
  font-size: 1.1rem;
  width: 1.25rem;
  text-align: center;
}

/* Collapsible submenu group header -- a <button data-bs-toggle="collapse">
   styled identically to a plain .vx-sidebar-link so expanding "Roster" or
   "Administration" doesn't look different from a real nav link. */
.vx-sidebar-group-toggle {
  width: 100%;
  border: none;
  background: none;
  text-align: left;
}

.vx-sidebar-caret {
  margin-left: auto;
  font-size: 0.8rem !important;
  width: auto !important;
  transition: transform 0.15s ease;
}

.vx-sidebar-group-toggle[aria-expanded="true"] .vx-sidebar-caret {
  transform: rotate(180deg);
}

.vx-sidebar-group {
  margin-top: auto;
  padding-top: var(--vx-space-md);
  border-top: 1px solid var(--vx-outline-variant);
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.vx-sidebar-group form {
  margin: 0;
}

.vx-sidebar-group .vx-sidebar-link {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-right: 2px solid transparent;
}

.vx-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.vx-topbar {
  height: var(--vx-topbar-height);
  position: sticky;
  top: 0;
  z-index: 30;
  background-color: var(--bs-body-bg);
  border-bottom: 1px solid var(--vx-outline-variant);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--vx-space-md);
  padding: 0 var(--vx-space-lg);
}

.vx-crumb-list {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--vx-on-surface-variant);
}

.vx-crumb-list li {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.vx-crumb-list li:not(:first-child)::before {
  content: "/";
  color: var(--vx-outline);
}

.vx-crumb-list a {
  color: inherit;
  text-decoration: none;
}

.vx-crumb-list a:hover {
  color: var(--vx-primary-bright);
}

.vx-crumb-list .vx-crumb-current {
  color: var(--vx-on-surface);
}

.vx-content {
  padding: var(--vx-space-md);
  max-width: var(--vx-container-max);
  width: 100%;
  margin: 0 auto;
}

@media (min-width: 768px) {
  .vx-content {
    padding: var(--vx-space-lg);
  }
}

@media (min-width: 1200px) {
  .vx-content {
    padding: var(--vx-space-xl);
  }
}

@media (max-width: 767.98px) {
  .vx-sidebar {
    display: none;
  }
}

/* Desktop sidebar collapse: shrinks to an icon-only rail (see
   --vx-sidebar-width-collapsed in tokens.css) rather than disappearing
   outright, so the toggle button in the brand row -- and the top-level
   route icons -- stay reachable while it's "hidden". Submenus close
   outright at rail width since there's no room to show their labels.
   State is a cookie set by ?sidebar=collapsed|expanded (SetSidebar
   middleware), applied server-side via sidebar_collapsed() to avoid a
   flash of the wrong width on load. */
@media (min-width: 768px) {
  .vx-shell.vx-sidebar-collapsed .vx-sidebar {
    width: var(--vx-sidebar-width-collapsed);
  }

  .vx-shell.vx-sidebar-collapsed .vx-sidebar-label {
    display: none;
  }

  .vx-shell.vx-sidebar-collapsed .vx-sidebar-nav .collapse {
    display: none;
  }

  .vx-shell.vx-sidebar-collapsed .vx-sidebar-link,
  .vx-shell.vx-sidebar-collapsed .vx-sidebar-group-toggle {
    justify-content: center;
  }
}

/* Offcanvas mobile sidebar reuses .vx-sidebar-* classes inside Bootstrap's
   own .offcanvas -- no custom JS needed, see partials/sidebar.php. */
.vx-offcanvas .vx-sidebar {
  display: flex;
  position: static;
  height: 100%;
  width: 100%;
  border-right: none;
}

/* Icon-only topbar buttons (notification bell, theme toggle) -- plain
   Bootstrap has no equivalent size/shape for these. Given a permanent
   resting background/border (not just on :hover) -- a transparent resting
   state made these blend into the topbar entirely, to the point they were
   only discoverable by accident. */
.btn-icon {
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--bs-border-radius-pill, 50%);
  padding: 0;
  border: 1px solid var(--vx-outline-variant);
  background-color: var(--vx-surface-container-high);
  color: var(--vx-on-surface);
}

.btn-icon:hover {
  background-color: var(--vx-surface-container-highest);
  border-color: var(--vx-outline);
  color: var(--vx-primary-bright);
}

/* ---- Page header + breadcrumbs ------------------------------------------ */
.vx-page-header {
  display: flex;
  flex-direction: column;
  gap: var(--vx-space-md);
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: var(--vx-space-lg);
}

@media (min-width: 768px) {
  .vx-page-header {
    flex-direction: row;
    align-items: center;
  }
}

.vx-page-subtitle {
  color: var(--vx-on-surface-variant);
  margin-top: 0.25rem;
}

/* ---- Modular card -------------------------------------------------------- */
.vx-module-card {
  background-color: var(--vx-surface-container);
  border: 1px solid var(--vx-outline-variant);
  border-radius: var(--bs-border-radius-lg);
  display: flex;
  flex-direction: column;
}

.vx-module-card-header {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--vx-outline-variant);
  background-color: var(--vx-surface-container-low);
  border-top-left-radius: var(--bs-border-radius-lg);
  border-top-right-radius: var(--bs-border-radius-lg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--vx-space-sm);
}

.vx-module-card-body {
  padding: 1rem;
}

.vx-chart-card {
  min-height: 20rem;
}

/* ---- KPI stat card -------------------------------------------------------- */
.vx-stat-card {
  background-color: var(--vx-surface-container);
  border: 1px solid var(--vx-outline-variant);
  border-radius: var(--bs-border-radius-lg);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--vx-space-sm);
  min-height: 8rem;
}

.vx-stat-card-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.vx-stat-card-value {
  font-family: "Hanken Grotesk", var(--bs-body-font-family);
  font-weight: 600;
  font-size: 1.5rem;
}

.vx-stat-trend {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  border-radius: var(--bs-border-radius);
  border: 1px solid transparent;
  padding: 0.125rem 0.5rem;
}

.vx-stat-trend.up {
  color: var(--vx-primary-bright);
  background-color: rgba(75, 226, 119, 0.1);
  border-color: rgba(75, 226, 119, 0.2);
}

.vx-stat-trend.down {
  color: var(--bs-danger);
  background-color: rgba(239, 68, 68, 0.1);
  border-color: rgba(239, 68, 68, 0.2);
}

.vx-stat-trend.flat {
  color: var(--vx-on-surface-variant);
  background-color: var(--vx-surface-container-high);
  border-color: var(--vx-outline-variant);
}

/* ---- Status chip ----------------------------------------------------------
   Tinted background + matching border + colored text, never a solid fill --
   sidesteps the white-text-on-saturated-accent contrast problem entirely
   (see tokens.css's note on .btn-primary) and matches DESIGN.md's own
   "10% opacity tint + 1px solid border" chip spec. */
.vx-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-family: "JetBrains Mono", var(--bs-font-monospace);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.1875rem 0.5rem;
  border-radius: var(--bs-border-radius);
  border: 1px solid transparent;
  line-height: 1.4;
}

.vx-chip-success {
  color: var(--vx-primary-bright);
  background-color: rgba(75, 226, 119, 0.1);
  border-color: rgba(75, 226, 119, 0.25);
}

.vx-chip-info {
  color: var(--vx-secondary-bright);
  background-color: rgba(96, 165, 250, 0.12);
  border-color: rgba(96, 165, 250, 0.25);
}

.vx-chip-warning {
  color: #ffda6a;
  background-color: rgba(255, 218, 106, 0.12);
  border-color: rgba(255, 218, 106, 0.25);
}

.vx-chip-danger {
  color: var(--bs-danger);
  background-color: rgba(239, 68, 68, 0.12);
  border-color: rgba(239, 68, 68, 0.25);
}

.vx-chip-neutral {
  color: var(--vx-on-surface-variant);
  background-color: var(--vx-surface-container-high);
  border-color: var(--vx-outline-variant);
}

[data-bs-theme="light"] .vx-chip-warning {
  color: #b45309;
  background-color: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.3);
}

/* ---- Tables ---------------------------------------------------------------
   Restyles Bootstrap's own .table via its --bs-table-* variables (see
   tokens.css) for background/hover/border/stripe. .vx-table layers the
   mockups' sticky header + data-mono cell treatment on top. */
.vx-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background-color: var(--vx-surface-container-low);
  font-family: "JetBrains Mono", var(--bs-font-monospace);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--vx-on-surface-variant);
  border-bottom: 1px solid var(--vx-outline-variant);
}

.vx-table-mono td {
  font-family: "JetBrains Mono", var(--bs-font-monospace);
  font-size: 0.8125rem;
}

/* ---- Pagination ------------------------------------------------------------ */
.vx-pagination .page-link {
  background-color: transparent;
  border-color: var(--vx-outline-variant);
  color: var(--vx-on-surface-variant);
}

.vx-pagination .page-item.active .page-link {
  background-color: rgba(75, 226, 119, 0.1);
  border-color: var(--vx-primary-bright);
  color: var(--vx-primary-bright);
}

.vx-pagination .page-item.disabled .page-link {
  color: var(--vx-outline);
  background-color: transparent;
}

/* ---- Profile / role card --------------------------------------------------- */
.vx-profile-card {
  background-color: var(--vx-surface-container-low);
  border: 1px solid var(--vx-outline-variant);
  border-radius: var(--bs-border-radius-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.vx-profile-card-avatar {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--bs-border-radius);
  border: 2px solid var(--vx-surface-container-high);
  background-color: var(--vx-surface-container-high);
  color: var(--vx-on-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Hanken Grotesk", var(--bs-body-font-family);
  font-weight: 600;
  flex-shrink: 0;
}

.vx-profile-card-footer {
  margin-top: auto;
  padding: 0.75rem 1rem;
  background-color: var(--vx-surface-container);
  border-top: 1px solid var(--vx-outline-variant);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.vx-rank-badge {
  width: 1.5rem;
  height: 1.5rem;
  font-size: 0.6875rem;
}

/* ---- Profile grid (Top Volunteers page) -----------------------------------
   Wraps .vx-profile-card into a responsive card grid -- the one real
   layout gap this redesign found: KPI rows already have Bootstrap's
   row/col-* to lean on, but nothing wraps variable-width card tiles.
   Hover is a border-color shift + translateY only, deliberately not the
   heavy box-shadow the reference mockup used -- this design system's own
   elevation rule is tonal layers/outlines, not drop shadows. */
.vx-profile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
  gap: var(--vx-space-md);
}

.vx-profile-grid .vx-profile-card {
  transition: transform 0.15s ease, border-color 0.15s ease;
}

.vx-profile-grid .vx-profile-card:hover {
  transform: translateY(-2px);
  border-color: var(--vx-outline);
}

/* ---- Activity feed (dashboard "recent activity" panel) --------------------
   Left-border-accent timeline list. Reusable later for the admin audit
   log, which currently renders as a plain table. */
.vx-activity-feed {
  display: flex;
  flex-direction: column;
  gap: var(--vx-space-sm);
}

.vx-activity-item {
  display: flex;
  gap: var(--vx-space-sm);
  padding-left: var(--vx-space-sm);
  border-left: 2px solid var(--vx-outline-variant);
}

.vx-activity-item.unread {
  border-left-color: var(--vx-primary-bright);
}

.vx-activity-time {
  flex-shrink: 0;
  width: 3.25rem;
  text-align: right;
  color: var(--vx-on-surface-variant);
}

/* ---- Segmented toggle (analytics Monthly/Yearly switch) -------------------
   Plain <a> links styled as a two-option switch, built from the same
   tint-token pattern as .vx-chip/.vx-stat-trend -- no JS, no Bootstrap
   btn-check radio group, consistent with every other filter in the app
   being a plain link. */
.vx-segmented {
  display: inline-flex;
  gap: 0.125rem;
  padding: 0.1875rem;
  background-color: var(--vx-surface-container-low);
  border: 1px solid var(--vx-outline-variant);
  border-radius: var(--bs-border-radius-lg);
}

.vx-segmented a {
  padding: 0.25rem 0.75rem;
  border-radius: var(--bs-border-radius);
  color: var(--vx-on-surface-variant);
  text-decoration: none;
  font-family: "JetBrains Mono", var(--bs-font-monospace);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.vx-segmented a:hover {
  color: var(--vx-on-surface);
}

.vx-segmented a.active {
  background-color: rgba(75, 226, 119, 0.1);
  color: var(--vx-primary-bright);
  font-weight: 700;
}

/* ---- dev/styleguide.php swatches (not used elsewhere) ------------------- */
.vx-swatch {
  width: 8rem;
  height: 4rem;
}

.vx-swatch-lowest { background-color: var(--vx-surface-container-lowest); }
.vx-swatch-low { background-color: var(--vx-surface-container-low); }
.vx-swatch-mid { background-color: var(--vx-surface-container); }
.vx-swatch-high { background-color: var(--vx-surface-container-high); }
.vx-swatch-highest { background-color: var(--vx-surface-container-highest); }

/* ---- Empty state ------------------------------------------------------------ */
.vx-empty-state {
  text-align: center;
  padding: var(--vx-space-xl) var(--vx-space-md);
  color: var(--vx-on-surface-variant);
}

.vx-empty-state .bi {
  font-size: 2rem;
  color: var(--vx-outline);
  margin-bottom: var(--vx-space-sm);
  display: inline-block;
}

/* ---- Auth shell -------------------------------------------------------------- */
.auth-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  position: relative;
  overflow: hidden;
}

.auth-card {
  width: 100%;
  max-width: 26rem;
  position: relative;
  z-index: 1;
}

.auth-shell-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}

@media (prefers-reduced-motion: reduce) {
  .auth-shell-canvas {
    display: none;
  }
}

/* ---- Flash / alerts ----------------------------------------------------------- */
.flash {
  padding: 0.75rem 1rem;
  border-radius: var(--bs-border-radius);
  margin-bottom: 1rem;
  border: 1px solid transparent;
}

.flash-success {
  background-color: rgba(75, 226, 119, 0.1);
  color: var(--vx-primary-bright);
  border-color: rgba(75, 226, 119, 0.25);
}

.flash-error {
  background-color: rgba(239, 68, 68, 0.1);
  color: var(--bs-danger);
  border-color: rgba(239, 68, 68, 0.25);
}

.flash-warning {
  background-color: rgba(255, 218, 106, 0.12);
  color: #ffda6a;
  border-color: rgba(255, 218, 106, 0.3);
}

[data-bs-theme="light"] .flash-warning {
  color: #b45309;
  background-color: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.3);
}

/* ---- Push notification permission prompt --------------------------------------- */
.vx-push-prompt {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  border-radius: var(--bs-border-radius);
  background-color: var(--vx-surface-container);
  border: 1px solid var(--vx-outline-variant);
}

.vx-push-prompt-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* ---- Camera QR scanner (coordinator presence scan) ---------------------------- */
.vx-camera-preview {
  position: relative;
  overflow: hidden;
  border-radius: var(--bs-border-radius);
  border: 1px solid var(--vx-outline-variant);
  background-color: #000;
}

.vx-camera-preview video {
  display: block;
  width: 100%;
  max-height: 320px;
  object-fit: cover;
}

/* ---- Live volunteer search (roster add-to-queue) ------------------------------
   Bootstrap's own .list-group already themes correctly in both color modes --
   this only needs to float it under the search input. */
.vx-search-results {
  position: absolute;
  z-index: 20;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 0.25rem;
  max-height: 220px;
  overflow-y: auto;
}

/*
 * Table -> card pattern for narrow screens. Each cell needs a
 * `data-label="Column name"` attribute (used as the ::before content).
 * Applied as a class on the <table> itself (the form every view now uses,
 * normalised from the previous wrapper-div-or-table-class inconsistency).
 */
@media (max-width: 767.98px) {
  .table-responsive-cards,
  .table-responsive-cards thead,
  .table-responsive-cards tbody,
  .table-responsive-cards tr,
  .table-responsive-cards td {
    display: block;
    width: 100%;
  }

  .table-responsive-cards thead {
    position: absolute;
    top: -9999px;
    left: -9999px;
  }

  .table-responsive-cards tr {
    margin-bottom: 1rem;
    border: 1px solid var(--vx-outline-variant);
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--vx-surface-container);
    padding: 0.5rem 0;
  }

  .table-responsive-cards td {
    text-align: right;
    padding-left: 45%;
    position: relative;
    border: none;
    border-bottom: 1px solid var(--vx-outline-variant);
  }

  .table-responsive-cards td:last-child {
    border-bottom: none;
  }

  .table-responsive-cards td::before {
    content: attr(data-label);
    position: absolute;
    left: 0.75rem;
    width: 40%;
    text-align: left;
    font-weight: 600;
    color: var(--vx-on-surface-variant);
  }
}

.toast-container {
  z-index: 1090;
}

/*
 * Fixed-width form/card containers, named after the rem value -- a
 * style="max-width: ...rem" attribute is inline style and CSP's style-src
 * 'self' (no unsafe-inline) drops it silently.
 */
.mw-20 { max-width: 20rem; }
.mw-24 { max-width: 24rem; }
.mw-28 { max-width: 28rem; }
.mw-30 { max-width: 30rem; }
.mw-40 { max-width: 40rem; }
.mw-48 { max-width: 48rem; }
