/* Shared dashboard shell (sidebar + topbar + content) for organizer and
   admin pages -- see shared/dashboard-shell.js.

   The palette lives in shared/design-tokens.css, which this file assumes is
   present. Every page that links this one links that one too, and
   shared/page-chrome.js injects both together for pages it attaches the
   shell to at runtime, so there is no path that gets the shell without the
   tokens. Each token below is still written with a fallback literal, so a
   page that somehow loads only this sheet degrades to the old palette
   rather than to unstyled black-on-white. */

.dashboard-shell {
  display: flex;
  min-height: 100vh;
  background: var(--bg, #eef2f7);
}

.dashboard-sidebar {
  flex: 0 0 232px;
  width: 232px;
  background: var(--sidebar-bg, #0f172a);
  /* A 1px diagonal hatch at ~1.3% white. Invisible as a pattern; it just
     stops a 232px column of flat near-black from looking like a dead area
     of the screen next to the tinted page. */
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.013) 0,
    rgba(255, 255, 255, 0.013) 1px,
    transparent 1px,
    transparent 9px
  );
  border-right: none;
  display: flex;
  flex-direction: column;
  padding: 0;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.dashboard-sidebar-brand {
  display: block;
  text-decoration: none;
  padding: 18px 16px 15px;
  border-bottom: 1px solid var(--sidebar-line, rgba(255, 255, 255, 0.07));
}

/* Eight alternating squares in two rows -- a chessboard reduced to the
   smallest mark that still reads as one, since chess programs are what most
   organizations on here run. Decorative only, hidden from assistive tech. */
.dashboard-sidebar-mark {
  display: flex;
  gap: 2.5px;
  margin-bottom: 11px;
}

.dashboard-sidebar-mark-col {
  display: flex;
  flex-direction: column;
  gap: 2.5px;
}

.dashboard-sidebar-mark-cell {
  width: 5px;
  height: 5px;
  border-radius: 1px;
  background: rgba(255, 255, 255, 0.14);
}

.dashboard-sidebar-mark-cell.on {
  background: rgba(99, 102, 241, 0.44);
}

.dashboard-sidebar-brand-row {
  display: flex;
  align-items: center;
  gap: 7px;
}

.dashboard-sidebar-brand-name {
  font-weight: 700;
  color: #ffffff;
  font-size: 18px;
  letter-spacing: -0.02em;
}

.dashboard-sidebar-brand-beta {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  background: rgba(99, 102, 241, 0.25);
  color: #a5b4fc;
  border-radius: 4px;
  padding: 2px 5px;
}

.dashboard-nav {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 10px 9px;
}

.dashboard-nav-group-label {
  padding: 0 10px;
  margin-bottom: 4px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #64748b;
}

.dashboard-nav-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.dashboard-nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 13px;
  border-radius: var(--radius-control, 8px);
  color: var(--sidebar-text, #94a3b8);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 400;
  border: none;
  background: transparent;
  cursor: pointer;
  text-align: left;
  width: 100%;
  font-family: inherit;
  transition: background 0.12s, color 0.12s;
}

.dashboard-nav-item:hover {
  background: var(--sidebar-hover-bg, rgba(255, 255, 255, 0.05));
  color: var(--sidebar-text-hover, #cbd5e1);
}

.dashboard-nav-item.active {
  background: var(--sidebar-active-bg, rgba(99, 102, 241, 0.18));
  color: var(--sidebar-active-text, #ffffff);
  font-weight: 600;
}

/* The active marker is a bar on the sidebar's own edge rather than a border
   on the item, so it doesn't inset the label and knock the active row's text
   out of alignment with the rest of the list. */
.dashboard-nav-item.active::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 18px;
  border-radius: 0 3px 3px 0;
  background: var(--accent, #6366f1);
}

.dashboard-nav-icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
}

.dashboard-sidebar-footer {
  padding: 12px 14px;
  border-top: 1px solid var(--sidebar-line, rgba(255, 255, 255, 0.07));
  font-size: 12px;
  color: #64748b;
  /* Pinned to the bottom of the column rather than trailing the nav items. */
  margin-top: auto;
}

/* The site footer lives here now (see page-chrome.js). Its own rules centre it in a
   1080px content column with generous padding, none of which suits a 232px dark rail. */
.dashboard-sidebar-footer .site-footer {
  max-width: none;
  margin: 0;
  padding: 0;
  font-size: 11px;
  line-height: 1.5;
  color: #64748b;
  display: grid;
  gap: 4px;
}

.dashboard-sidebar-footer .site-footer .app-version {
  color: var(--sidebar-text, #94a3b8);
}

/* Callers pass raw markup as footerHtml (Admin Portal passes an "API Docs"
   link), and a link there inherits the page's default link colour -- dark blue
   on near-black, effectively invisible. The sidebar owns the contrast of
   anything inside it. */
.dashboard-sidebar-footer a {
  color: var(--sidebar-text, #94a3b8);
  text-decoration: none;
}

.dashboard-sidebar-footer a:hover {
  color: var(--sidebar-text-hover, #cbd5e1);
  text-decoration: underline;
}

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

.dashboard-topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line, #e2e8f0);
  padding: 14px 30px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* Rendered as an <h1> only on pages that have no page heading of their own
   (Admin Portal), and as a plain <div> everywhere else -- see titleTag in
   shared/dashboard-shell.js. Styling is identical either way. */
.dashboard-topbar-title {
  margin: 0;
  font-weight: 700;
  color: var(--ink, #1e293b);
  font-size: 18px;
  letter-spacing: -0.01em;
}

.dashboard-topbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.dashboard-mobile-toggle {
  display: none;
  border: 1px solid var(--accent-line, #c7d2fe);
  background: var(--accent-bg, #eef2ff);
  color: var(--accent-strong, #4f46e5);
  border-radius: var(--radius-control, 8px);
  width: 36px;
  height: 36px;
  line-height: 1;
  padding: 0;
  font-size: 18px;
  font-weight: 700;
  cursor: pointer;
}

.dashboard-user-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line, #e2e8f0);
  background: #fff;
  border-radius: var(--radius-pill, 999px);
  padding: 5px 9px;
  cursor: pointer;
  /* A <button> does not inherit font-family, so without this the account button -- and the
     user's own name inside it -- rendered in the browser default while the whole rest of
     the page was Inter. It sits in the shared topbar, so that was every dashboard. */
  font-family: inherit;
}

.dashboard-user-btn:hover {
  border-color: var(--line-strong, #cbd5e1);
}

.dashboard-user-name {
  color: var(--muted, #475569);
  font-size: 13px;
  font-weight: 500;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The gradient is the one place the app shows both brand hues together --
   it reads as an identity mark at 28px where a flat tint would just look
   like an empty circle. */
.dashboard-avatar {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-pill, 999px);
  border: none;
  object-fit: cover;
  background: linear-gradient(135deg, var(--accent, #6366f1), var(--violet, #8b5cf6));
  color: #ffffff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.03em;
  flex: 0 0 auto;
}

.dashboard-user-badge {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: #dc2626;
  box-shadow: 0 0 0 2px #ffffff;
  pointer-events: none;
}

.dashboard-menu-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  min-width: 180px;
  background: #fff;
  border: 1px solid var(--line, #e2e8f0);
  border-radius: 10px;
  box-shadow: 0 12px 24px rgba(15, 23, 42, 0.12);
  padding: 6px;
  z-index: 1000;
  display: none;
}

.dashboard-menu-dropdown.open { display: block; }

.dashboard-menu-item {
  width: 100%;
  text-align: left;
  border: none;
  background: transparent;
  color: var(--ink, #1e293b);
  padding: 8px 10px;
  border-radius: var(--radius-control, 8px);
  cursor: pointer;
  font: inherit;
  text-decoration: none;
  display: block;
}

.dashboard-menu-item:hover { background: var(--accent-bg, #eef2ff); }

.dashboard-content {
  flex: 1 1 auto;
  padding: 24px 30px 40px;
  max-width: 1120px;
  width: 100%;
  box-sizing: border-box;
}

/* Page header. Shell pages open with an unboxed title + one-line explanation
   sitting directly on the page background -- never inside a card, which is what
   made older pages read as a stack of nested boxes. */
.dashboard-page-title {
  margin: 0 0 4px;
  /* Down from 32px. At the old size the page title competed with the topbar
     title directly above it and dominated the summary row below; the page
     reads as one hierarchy now rather than two headings stacked. */
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--ink, #1e293b);
}

.dashboard-page-lede {
  margin: 0 0 20px;
  color: var(--muted, #475569);
  font-size: 13.5px;
  max-width: 68ch;
  line-height: 1.55;
}

/* Label above a content block, the shell's alternative to boxing every section
   in its own titled card ("Quick Links", "Recent Programs", "By program", ...).
   Lived as an identical local copy in dashboard.html and reminders.html until
   check-in became the third user. */
.dashboard-section-title {
  margin: 26px 0 12px;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink, #1e293b);
  letter-spacing: -0.01em;
}

/* The quieter alternative to .dashboard-section-title: an uppercase micro-label
   for a block that needs naming but shouldn't read as a new chapter ("Quick
   actions", "By program"). Takes an optional right-aligned action link. */
.dashboard-section-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 24px 0 11px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--faint, #94a3b8);
}

.dashboard-section-label-action {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent-strong, #4f46e5);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
}

.dashboard-section-label-action:hover { text-decoration: underline; }

.dashboard-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin: 18px 0;
}

/* Stat card.
   The left edge is a 4px accent rule rather than a full tinted card: it lets a
   row of six read as one family at a glance while still colour-coding each
   metric, and it keeps the number itself on white where it stays legible.
   Set the accent per card with `style="--stat-accent: var(--emerald)"`, or
   with one of the .stat-card--* modifiers below. */
.stat-card {
  position: relative;
  overflow: hidden;
  background: var(--panel, #fff);
  border: 1px solid var(--line, #e2e8f0);
  border-left: 4px solid var(--stat-accent, var(--accent, #6366f1));
  border-radius: var(--radius-card, 12px);
  padding: 16px 18px 16px 20px;
}

.stat-card-label {
  font-size: 10.5px;
  color: var(--faint, #94a3b8);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.stat-card-value {
  /* tabular-nums so a row of counters doesn't jitter its own width as values
     update on refresh. */
  font-variant-numeric: tabular-nums;
  font-size: 30px;
  line-height: 1.05;
  font-weight: 700;
  color: var(--ink, #1e293b);
  margin-top: 7px;
}

.stat-card-meta {
  font-size: 11.5px;
  color: var(--faint, #94a3b8);
  line-height: 1.4;
  margin-top: 5px;
}

.stat-card--indigo  { --stat-accent: var(--accent, #6366f1); }
.stat-card--emerald { --stat-accent: var(--emerald, #10b981); }
.stat-card--violet  { --stat-accent: var(--violet, #8b5cf6); }
.stat-card--amber   { --stat-accent: var(--amber, #f59e0b); }
.stat-card--sky     { --stat-accent: var(--sky, #0ea5e9); }
.stat-card--rose    { --stat-accent: var(--rose, #f43f5e); }

/* Card -- the neutral container for a table or a list of rows. Deliberately
   has no title slot: a titled card is the boxed-in-a-box pattern these
   dashboards moved away from, so the heading goes above it as a
   .dashboard-section-label or .dashboard-section-title instead. */
.dashboard-card {
  background: var(--panel, #fff);
  border: 1px solid var(--line, #e2e8f0);
  border-radius: var(--radius-card, 12px);
  overflow: hidden;
}

/* Table header. Pairs with .dashboard-card for tables that sit inside one --
   the tinted strip does the separating, so no double border at the top edge. */
.dashboard-card table { border-collapse: collapse; width: 100%; }

.dashboard-card thead th,
.dashboard-table-head {
  background: var(--panel-subtle, #f8fafc);
  border-bottom: 1px solid var(--line, #e2e8f0);
  padding: 10px 18px;
  text-align: left;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--faint, #94a3b8);
  white-space: nowrap;
}

.dashboard-card tbody td {
  padding: 13px 18px;
  border-bottom: 1px solid var(--line, #e2e8f0);
  font-size: 13.5px;
  color: var(--ink, #1e293b);
  vertical-align: middle;
}

.dashboard-card tbody tr:last-child td { border-bottom: none; }

/* The line between a section label and its card -- a count, a total, whatever the
   table below adds up to. Sits outside the card, because a titled card is the
   boxed-in-a-box pattern these dashboards moved away from. */
.dashboard-section-note {
  margin: -2px 0 10px;
  font-size: 12.5px;
  color: var(--muted, #64748b);
}

/* Money and counts right-align, so figures compare down the column instead of
   being read digit by digit from a ragged left edge. */
.dashboard-card th.dashboard-num,
.dashboard-card td.dashboard-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Status pill. One ramp per meaning, matching the stat-card accents so a
   colour reads the same in both places. */
.dashboard-pill {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: 5px;
  padding: 2px 8px;
  background: var(--pill-bg, var(--accent-bg, #eef2ff));
  color: var(--pill-text, var(--accent-text, #3730a3));
  border: 1px solid var(--pill-line, var(--accent-line, #c7d2fe));
}

.dashboard-pill--published,
.dashboard-pill--success {
  --pill-bg: var(--emerald-bg, #ecfdf5);
  --pill-text: var(--emerald-text, #065f46);
  --pill-line: var(--emerald-line, #a7f3d0);
}

.dashboard-pill--draft,
.dashboard-pill--warn {
  --pill-bg: var(--amber-bg, #fffbeb);
  --pill-text: var(--amber-text, #92400e);
  --pill-line: var(--amber-line, #fde68a);
}

.dashboard-pill--danger {
  --pill-bg: var(--rose-bg, #fff1f2);
  --pill-text: var(--rose-text, #9f1239);
  --pill-line: var(--rose-line, #fecdd3);
}

/* Buttons.
   Three roles, one geometry. Everything shares --btn-* from design-tokens.css,
   so a page adopting these can't drift on radius, padding or weight the way the
   per-page .btn copies did.

   Pick by what the button does, not by where it sits: -primary for the one
   action a view exists to perform, -danger for something destructive, and the
   base .dashboard-btn for everything else. A view with two primaries has no
   primary. */
.dashboard-btn,
.dashboard-btn-primary,
.dashboard-btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border-radius: var(--btn-radius, 8px);
  padding: var(--btn-padding, 9px 14px);
  font-family: inherit;
  font-size: var(--btn-font-size, 13px);
  font-weight: var(--btn-font-weight, 600);
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
}

.dashboard-btn {
  background: var(--panel, #fff);
  color: var(--ink, #1e293b);
  border: 1px solid var(--line, #e2e8f0);
}

.dashboard-btn:hover:not(:disabled) {
  border-color: var(--line-strong, #cbd5e1);
  background: var(--panel-subtle, #f8fafc);
}

.dashboard-btn-primary {
  background: var(--accent-strong, #4f46e5);
  color: #fff;
  border: 1px solid var(--accent-strong, #4f46e5);
}

.dashboard-btn-primary:hover:not(:disabled) { background: #4338ca; border-color: #4338ca; }

/* Tinted rather than filled: destructive actions sit in table rows next to
   ordinary ones, and a row of solid red reads as an error state rather than as
   an available action. The colour still says what it is. */
.dashboard-btn-danger {
  background: var(--rose-bg, #fff1f2);
  color: var(--rose-text, #9f1239);
  border: 1px solid var(--rose-line, #fecdd3);
}

.dashboard-btn-danger:hover:not(:disabled) { background: #ffe4e6; border-color: #fda4af; }

.dashboard-btn:disabled,
.dashboard-btn-primary:disabled,
.dashboard-btn-danger:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

/* Tinted icon tile, for quick-action rows and empty states. Colour comes from
   --tile-accent so one rule serves every ramp. */
.dashboard-icon-tile {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--tile-accent, var(--accent, #6366f1));
  background: color-mix(in srgb, var(--tile-accent, var(--accent, #6366f1)) 12%, transparent);
}

/* "Attached" mode -- used by shared/page-chrome.js to put this shell around a
   page that was built for the flat top-nav (checkin, tools, offerings, ...)
   without restructuring its markup. Rather than requiring the page's <main> to
   become a flex child of .dashboard-main (which would mean rewriting the body
   of every migrated page), the sidebar is taken out of flow and the body is
   simply inset by its width, so each page's existing `.wrap` keeps its own
   max-width, margins, and centering untouched.

   The inset is all this sets: deliberately no `background`, since several
   migrated pages (tools, reminder-templates, waiver-templates, volunteering)
   paint their own gradient on <body> and overriding it would flatten them. */
body.dashboard-shell-attached {
  padding-left: 232px;
}

/* The rail, painted before any JavaScript runs -- see shared/shell-preboot.js for why.
   On pages the sidebar is attached to, it is created by JS 30-110ms into the navigation,
   and until then the whole viewport is the light page tint: the left 232px flashes navy,
   light, navy on every click.

   Layered as a background-image over whatever colour the page already gives its body,
   rather than replacing it. `html[data-shell-rail] body` outranks a page's own bare
   `body` rule on specificity, so this holds even though page styles come after this
   sheet -- and a shorthand `background: var(--bg)` there cannot reset it away.

   The padding matches .dashboard-shell-attached exactly, so when JS does attach the
   shell there is nothing left to move. */
html[data-shell-rail='1'] body {
  padding-left: 232px;
  background-image: linear-gradient(
    to right,
    var(--sidebar-bg, #0f172a) 0,
    var(--sidebar-bg, #0f172a) 232px,
    transparent 232px
  );
  background-repeat: no-repeat;
  background-attachment: fixed;
}

@media (max-width: 900px), (hover: none) and (pointer: coarse) and (max-width: 1100px) {
  /* Off-canvas below this width, so there is no rail to reserve. */
  html[data-shell-rail='1'] body {
    padding-left: 0;
    background-image: none;
  }
}

/* Width alone does not identify a phone.
   Reported from Android Chrome in portrait: the sidebar sat on screen taking half of it. A phone
   browser can report a layout viewport well above 900px -- desktop-site mode is around 980 -- and
   a large phone in landscape is 844-956, so the width test missed both and the desktop rail
   appeared on a handset. `(hover: none) and (pointer: coarse)` asks about the device instead of
   guessing from its width; the 1100px cap keeps a real tablet's rail. The rail rule below is the
   exact complement, so no viewport can land between the two and get a drawer with no way to open
   it -- the drawer and its toggle are gated by the same query.

   The loading overlay (shared/page-transition.js) is a full-viewport `inset: 0`,
   which under this shell dims and blurs the sidebar along with the page. That reads
   as the whole window reloading -- exactly the impression the shell is meant not to
   give, and plainly wrong once the sidebar is the one part that genuinely is not
   being reloaded. Inset past the rail so the sidebar stays live and legible and the
   loading state belongs to the content column, which is what is actually loading.

   Higher specificity than the injected `.page-transition-overlay` rule it narrows,
   so sheet order does not matter. */
@media (min-width: 901px) and (hover: hover), (min-width: 1101px) {
  body.dashboard-shell-attached #pageTransitionOverlay,
  body:has(> .dashboard-shell) #pageTransitionOverlay {
    left: 232px;
  }
}

body.dashboard-shell-attached > .dashboard-sidebar {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  height: auto;
  z-index: 20;
}

/* Attached pages keep whatever background they already painted (see above), so
   the ones that didn't paint one need the page tint applied here -- otherwise
   they'd sit on the browser's white next to a navy sidebar, which is the one
   combination that looks broken rather than merely different. Pages with their
   own gradient override this from their own <style>, which wins on cascade
   order (shared/page-chrome.js inserts this sheet first). */
body.dashboard-shell-attached {
  background: var(--bg, #eef2f7);
}

@media (max-width: 900px), (hover: none) and (pointer: coarse) and (max-width: 1100px) {
  body.dashboard-shell-attached {
    padding-left: 0;
  }
  .dashboard-sidebar {
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    z-index: 20;
    transform: translateX(-100%);
    transition: transform 0.18s ease;
    box-shadow: 0 0 0 rgba(0, 0, 0, 0);
  }
  .dashboard-sidebar.open {
    transform: translateX(0);
    box-shadow: 20px 0 40px rgba(15, 23, 42, 0.18);
  }
  .dashboard-mobile-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .dashboard-content {
    padding: 18px 16px 32px;
  }
}
