/* Admin styling that Unfold's pre-compiled Tailwind bundle does not
   include. Unfold ships a fixed CSS build, so utilities it never compiled
   (border-primary-*, tabular-nums, divide-*, inset-y-*) are simply absent —
   writing them in a template silently does nothing. These few rules are
   defined explicitly instead, keyed off Unfold's own CSS custom properties so
   they follow the configured palette and the light/dark toggle.

   Loaded via UNFOLD["STYLES"].

   Dark mode benchmarks soft tinted KPI washes, glassy charcoal panels, and
   generous radii — adapted to the amber school-bus brand rather than neon. */

/* ---------------------------------------------------- dashboard shell */
.dashboard-shell {
  position: relative;
}

.dark .dashboard-shell::before {
  content: "";
  pointer-events: none;
  position: absolute;
  inset: -1.5rem -1rem auto;
  height: 22rem;
  background:
    radial-gradient(
      60% 80% at 20% 0%,
      rgb(var(--color-primary-500) / 0.07),
      transparent 70%
    ),
    radial-gradient(
      50% 70% at 85% 10%,
      rgb(56 120 180 / 0.08),
      transparent 65%
    );
  z-index: 0;
}

.dark .dashboard-shell > * {
  position: relative;
  z-index: 1;
}

/* ---------------------------------------------------------- stat tiles */
.stat-tile {
  position: relative;
  overflow: hidden;
  border-radius: 1rem;
  transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

/* The amber rule down the left edge. One piece of colour, so a row of eight
   tiles stays scannable instead of becoming eight competing blocks. */
.stat-tile::before {
  content: "";
  position: absolute;
  inset-block: 12%;
  inset-inline-start: 0;
  width: 3px;
  border-radius: 9999px;
  background: rgb(var(--color-primary-500));
}

.dark .stat-tile::before {
  background: linear-gradient(
    180deg,
    rgb(var(--color-primary-300)),
    rgb(var(--color-primary-500))
  );
  box-shadow: 0 0 14px rgb(var(--color-primary-500) / 0.4);
}

.stat-tile:hover {
  border-color: rgb(var(--color-primary-400));
}

.dark .stat-tile:hover {
  border-color: rgb(255 255 255 / 0.16);
  transform: translateY(-2px);
  box-shadow:
    0 1px 0 rgb(255 255 255 / 0.08) inset,
    0 16px 36px rgb(0 0 0 / 0.4);
}

/* Figures line up column-to-column only with tabular figures; proportional
   digits make a stat row look ragged. */
.stat-value,
.tabular {
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------- panel cards */
/* A hairline under each panel header, matching the card border. */
.panel-head {
  border-bottom: 1px solid rgb(var(--color-base-200));
}

.dark .panel-head {
  border-bottom-color: rgb(255 255 255 / 0.07);
}

/* Row separators inside panels. :not(:first-child) rather than a divide-y
   utility, so the first row keeps its padding without a stray top rule. */
.panel-rows > *:not(:first-child) {
  border-top: 1px solid rgb(var(--color-base-100));
}

.dark .panel-rows > *:not(:first-child) {
  border-top-color: rgb(255 255 255 / 0.06);
}

/* --------------------------------------------------------- page title */
.page-title {
  border-inline-start: 3px solid rgb(var(--color-primary-500));
  padding-inline-start: 0.875rem;
}

/* ------------------------------------------------- card surfaces (dark) */
/* Unfold's pre-compiled bundle contains almost no dark: variants — there is
   no .dark\:bg-base-900 rule in it at all — so `dark:bg-base-900` in a
   template is inert. Surfaces and KPIs are defined here instead.

   Inspired by layered charcoal dashboards: cards sit above a near-black
   ground as cooler ink panels with hairline borders, while KPI tiles carry
   a soft tone wash (like tinted hero cards) without leaving the brand. */
.dark {
  --sb-card-hi: 52 56 68;
  --sb-card: 40 44 56;
  --sb-card-lo: 32 36 46;
  --sb-card-border: 255 255 255;
  --sb-card-shine: 255 255 255;
}

.dark .surface {
  border-radius: 1rem;
  background:
    linear-gradient(
      160deg,
      rgb(var(--sb-card-hi) / 0.92) 0%,
      rgb(var(--sb-card) / 0.96) 55%,
      rgb(var(--sb-card-lo)) 100%
    );
  border-color: rgb(var(--sb-card-border) / 0.09);
  box-shadow:
    0 1px 0 rgb(var(--sb-card-shine) / 0.06) inset,
    0 12px 32px rgb(0 0 0 / 0.32);
}

.dark .surface .text-base-900,
.dark .surface .stat-value {
  color: rgb(var(--color-base-50));
}

.dark .surface .text-base-500,
.dark .surface .text-base-600,
.dark .surface .text-base-700 {
  color: rgb(168 174 186);
}

.dark .surface a.text-base-900 {
  color: rgb(var(--color-base-50));
}

.dark .surface a.text-base-900:hover {
  color: rgb(var(--color-primary-400));
}

/* =====================================================================
   KPI tiles, trend chips, meters and status pills.

   Tailwind cannot express these from a template because Unfold's bundle is
   pre-compiled: no arbitrary values, no tone-keyed colour sets. Defining them
   here also keeps the tone vocabulary in one place — a template asks for
   tone="green" and never repeats a hex.
   ===================================================================== */

/* Tone palette. Each tone gives an icon foreground and a tinted ground,
   stated once for light and once for dark. */
.tone-amber  { --tone: 245 179 1;   --tone-bg: 254 243 199; }
.tone-green  { --tone: 22 163 74;   --tone-bg: 220 252 231; }
.tone-blue   { --tone: 37 99 235;   --tone-bg: 219 234 254; }
.tone-purple { --tone: 147 51 234;  --tone-bg: 243 232 255; }
.tone-red    { --tone: 220 38 38;   --tone-bg: 254 226 226; }
.tone-slate  { --tone: 100 116 139; --tone-bg: 241 245 249; }

.dark .tone-amber  { --tone: 251 191 36;  --tone-bg: 90 58 8; }
.dark .tone-green  { --tone: 74 222 128;  --tone-bg: 12 58 32; }
.dark .tone-blue   { --tone: 96 165 250;  --tone-bg: 28 48 96; }
.dark .tone-purple { --tone: 196 140 255; --tone-bg: 58 28 96; }
.dark .tone-red    { --tone: 251 113 133; --tone-bg: 78 24 36; }
.dark .tone-slate  { --tone: 148 163 184; --tone-bg: 40 48 64; }

/* --------------------------------------------------------- KPI tile */
.kpi {
  display: flex;
  align-items: flex-start;
  gap: 0.875rem;
  padding: 1.125rem 1.25rem;
  border-radius: 1rem;
  background: #fff;
  border: 1px solid rgb(var(--color-base-200));
  transition: border-color 160ms ease, transform 160ms ease, box-shadow 160ms ease;
}

/* Soft tone-washed cards in dark mode — same idea as pastel hero KPIs,
   but grounded so eight tiles stay calm together. */
.dark .kpi {
  background:
    radial-gradient(
      120% 90% at 0% 0%,
      rgb(var(--tone) / 0.34) 0%,
      rgb(var(--tone) / 0.08) 42%,
      transparent 68%
    ),
    linear-gradient(
      155deg,
      rgb(var(--sb-card-hi)) 0%,
      rgb(var(--sb-card)) 55%,
      rgb(var(--sb-card-lo)) 100%
    );
  border-color: rgb(var(--tone) / 0.28);
  box-shadow:
    0 1px 0 rgb(var(--sb-card-shine) / 0.08) inset,
    0 0 0 1px rgb(var(--tone) / 0.06) inset,
    0 14px 34px rgb(0 0 0 / 0.34);
}

.kpi:hover {
  border-color: rgb(var(--tone, var(--color-primary-400)));
  transform: translateY(-1px);
}

.dark .kpi:hover {
  border-color: rgb(var(--tone) / 0.5);
  transform: translateY(-2px);
  box-shadow:
    0 1px 0 rgb(var(--sb-card-shine) / 0.1) inset,
    0 0 0 1px rgb(var(--tone) / 0.14) inset,
    0 18px 40px rgb(0 0 0 / 0.42);
}

/* The rounded icon square. Tinted ground, tone-coloured glyph — the pattern
   that makes a row of tiles readable at a glance. */
.kpi-icon {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 2.625rem;
  height: 2.625rem;
  border-radius: 0.75rem;
  background: rgb(var(--tone-bg));
  color: rgb(var(--tone));
}

.dark .kpi-icon {
  background: rgb(var(--tone) / 0.18);
  box-shadow:
    0 0 0 1px rgb(var(--tone) / 0.28) inset,
    0 8px 18px rgb(var(--tone) / 0.16);
}

.kpi-icon .material-symbols-outlined { font-size: 1.3rem; }

.kpi-label {
  font-size: 0.75rem;
  color: rgb(var(--color-base-500));
  line-height: 1.2;
}

.dark .kpi-label { color: rgb(168 174 186); }

.kpi-value {
  margin-top: 0.3rem;
  font-size: 1.625rem;
  font-weight: 650;
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--color-base-900));
}

.dark .kpi-value { color: #fff; }

/* ------------------------------------------------------- trend chip */
.trend {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  margin-left: 0.5rem;
  padding: 0.0625rem 0.375rem;
  border-radius: 9999px;
  font-size: 0.6875rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

.trend-up   { background: rgb(220 252 231); color: rgb(22 101 52); }
.trend-down { background: rgb(254 226 226); color: rgb(153 27 27); }
.dark .trend-up   { background: rgb(16 70 40 / 0.85); color: rgb(134 239 172); }
.dark .trend-down { background: rgb(90 24 36 / 0.85); color: rgb(252 165 165); }

/* ------------------------------------------------------------ meter */
.meter {
  height: 0.375rem;
  border-radius: 9999px;
  background: rgb(var(--color-base-200));
  overflow: hidden;
}

.dark .meter { background: rgb(255 255 255 / 0.08); }

.meter > span {
  display: block;
  height: 100%;
  border-radius: 9999px;
  background: rgb(var(--tone));
}

/* ------------------------------------------------------ status pill */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: 9999px;
  font-size: 0.6875rem;
  font-weight: 600;
  white-space: nowrap;
  background: rgb(var(--tone-bg));
  color: rgb(var(--tone));
}

/* A quiet pulse on the live indicator: motion is the cheapest way to say
   "this is now" — but only for users who have not asked for less of it. */
.pill-live::before {
  content: "";
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 9999px;
  background: currentColor;
  animation: pill-pulse 2s ease-in-out infinite;
}

@keyframes pill-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .pill-live::before { animation: none; }
  .kpi:hover,
  .dark .kpi:hover,
  .dark .stat-tile:hover {
    transform: none;
  }
}

/* ------------------------------------------------------------ table */
.data-table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }

.data-table th {
  padding: 0 1.25rem 0.5rem;
  text-align: left;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgb(var(--color-base-500));
}

.dark .data-table th { color: rgb(168 174 186); }

.data-table td {
  padding: 0.625rem 1.25rem;
  border-top: 1px solid rgb(var(--color-base-100));
  color: rgb(var(--color-base-700));
}

.dark .data-table td {
  border-top-color: rgb(255 255 255 / 0.06);
  color: rgb(196 201 212);
}

.data-table tbody tr:hover td { background: rgb(var(--color-base-50)); }
.dark .data-table tbody tr:hover td { background: rgb(255 255 255 / 0.04); }

.data-table .num { text-align: right; font-variant-numeric: tabular-nums; }

/* KPI grid. Unfold's bundle has md:grid-cols-4 but not sm:/xl: variants, so
   the responsive steps are declared here rather than silently collapsing to a
   single column. */
.kpi-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px)  { .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .kpi-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.125rem; } }

/* ------------------------------------------------- table / map toggle */
/* One control, rendered the same on a changelist and on a map page, so
   switching between them does not feel like two different screens. Unfold
   ships a pre-built Tailwind bundle, so these live here rather than as
   utility classes that would silently do nothing. */
.view-toggle {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid rgb(var(--color-base-300));
  border-radius: 0.5rem;
  overflow: hidden;
  background: rgb(var(--color-base-50));
}

.dark .view-toggle {
  border-color: rgb(var(--color-base-700));
  background: rgb(var(--color-base-900));
}

.view-toggle__option {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.4rem 0.85rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.25rem;
  color: rgb(var(--color-base-600));
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.12s ease, color 0.12s ease;
}

.dark .view-toggle__option {
  color: rgb(var(--color-base-300));
}

.view-toggle__option + .view-toggle__option {
  border-left: 1px solid rgb(var(--color-base-300));
}

.dark .view-toggle__option + .view-toggle__option {
  border-left-color: rgb(var(--color-base-700));
}

.view-toggle__option:hover {
  background: rgb(var(--color-base-100));
  color: rgb(var(--color-base-900));
}

.dark .view-toggle__option:hover {
  background: rgb(var(--color-base-800));
  color: rgb(var(--color-base-100));
}

/* The active half carries the brand amber. Text is near-black rather than
   white: amber is a light colour, and white on it fails contrast. */
.view-toggle__option.is-active,
.view-toggle__option.is-active:hover {
  background: rgb(var(--color-primary-500));
  color: rgb(var(--color-base-950));
}

.view-toggle__icon {
  font-size: 1.05rem;
  line-height: 1;
}

/* ------------------------------------------------------------- maps */
/* Tall enough to be worth looking at, and it grows with the window rather
   than sitting at a fixed height that wastes a large screen. */
.map-canvas {
  width: 100%;
  height: clamp(26rem, calc(100vh - 20rem), 46rem);
  border: 1px solid rgb(var(--color-base-200));
  border-radius: 0.5rem;
  background: rgb(var(--color-base-100));
}

.dark .map-canvas {
  border-color: rgb(var(--color-base-800));
  background: rgb(var(--color-base-900));
}

/* Google's own controls render light; keep the surrounding chrome calm. */
.map-canvas .gm-style {
  border-radius: 0.5rem;
}

.map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
  margin-top: 0.75rem;
  font-size: 0.75rem;
  color: rgb(var(--color-base-500));
}

.dark .map-legend {
  color: rgb(var(--color-base-400));
}

.map-legend__swatch {
  display: inline-block;
  width: 1.75rem;
  height: 0.25rem;
  border-radius: 999px;
  vertical-align: middle;
  margin-right: 0.375rem;
}

/* ------------------------------------------------------------ typography */
/* Chalkboard — a school product, and the face reads like a classroom board.
 *
 * It is a macOS system font with no webfont to ship, so this is a request,
 * not a guarantee: on Windows/Linux the stack falls through to Comic Neue
 * (if present) and then to the platform sans. Nothing is ever left to the
 * browser's default serif.
 *
 * `--font-body` is applied rather than a blanket `*` rule so the icon font
 * and any monospace block keep their own faces.
 */
:root {
  --font-chalk: "Chalkboard SE", "ChalkboardSE-Regular", "Chalkboard",
                "Comic Neue", "Comic Sans MS", ui-rounded, system-ui,
                -apple-system, "Segoe UI", sans-serif;
}

/* html body — two elements, so this outranks Unfold's `font-sans` utility on
   <body>. Our stylesheet is linked BEFORE Unfold's Tailwind bundle, so equal
   specificity would lose on source order and the font would silently not
   apply. */
html body,
html body .view-toggle__option,
html body button, html body input, html body select,
html body textarea, html body optgroup,
html body h1, html body h2, html body h3,
html body h4, html body h5, html body h6 {
  font-family: var(--font-chalk);
}

/* Chalkboard sits small for its point size and its strokes are light, so it
   needs a touch more size and weight than Inter to stay comfortable. */
html body {
  font-size: 0.9rem;
  letter-spacing: 0.005em;
}

h1, h2, h3, .text-xl, .text-2xl {
  letter-spacing: 0.01em;
}

/* Numbers stay in a face built for them. Chalkboard's digits are uneven in
   width, which makes a column of figures hard to scan and a total hard to
   line up — the one place personality costs more than it gives. */
html body .tabular,
html body td.tabular,
html body .kpi__value,
html body [class*="tabular-nums"] {
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

/* Code, ids and the document editor are monospace regardless. */
html body code, html body pre, html body kbd, html body samp,
html body textarea[name="content"] {
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
}

/* The icon font must never inherit the body face, or every glyph renders as
   its literal ligature text ("dashboard", "map") instead of the symbol. */
.material-symbols-outlined,
.material-symbols-rounded,
.material-symbols-sharp {
  font-family: "Material Symbols Outlined", "Material Symbols Rounded",
               "Material Symbols Sharp" !important;
}

/* -------------------------------------------------------- primary button */
/* Amber is a light colour: white on it measures 2.57:1, well under the 4.5
   WCAG AA needs for body text. Near-black on the same amber is 7.63:1. The
   brand keeps its colour; the label just stops being hard to read. */
/* `.btn-primary.btn-primary` — doubled deliberately. Tailwind's preflight in
 * Unfold's bundle sets `background-color:initial` on every <button>, and this
 * stylesheet is linked BEFORE that bundle, so a single class loses on source
 * order: the button renders transparent and only gains a ground on :hover,
 * where the hover rule finally out-specifies the reset. */
.btn-primary.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  font-weight: 600;
  border-radius: 0.375rem;
  background: rgb(var(--color-primary-500));
  color: rgb(var(--color-base-950));
  border: 1px solid rgb(var(--color-primary-600));
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.btn-primary.btn-primary:hover {
  background: rgb(var(--color-primary-400));
}

.btn-primary.btn-primary:disabled,
.btn-primary.btn-primary[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

.dark .btn-primary.btn-primary {
  border-color: rgb(var(--color-primary-700));
}

/* --------------------------------------------------- map auth failure */
/* Google paints its own grey panel and logs the reason to the console only.
   This says what actually went wrong, in the page. */
.map-auth-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 100%;
  padding: 2rem;
  text-align: center;
}

.map-auth-error .material-symbols-outlined {
  font-size: 2.5rem;
  color: rgb(var(--color-base-400));
}

.map-auth-error__title {
  font-weight: 600;
  color: rgb(var(--color-base-900));
}

.dark .map-auth-error__title { color: rgb(var(--color-base-100)); }

.map-auth-error__body {
  max-width: 34rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: rgb(var(--color-base-600));
}

.dark .map-auth-error__body { color: rgb(var(--color-base-300)); }

.map-auth-error__host {
  font-size: 0.75rem;
  color: rgb(var(--color-base-500));
}

.map-auth-error__host code {
  padding: 0.1rem 0.35rem;
  border-radius: 0.25rem;
  background: rgb(var(--color-base-100));
}

.dark .map-auth-error__host code { background: rgb(var(--color-base-800)); }

/* Google's own console message, surfaced in the page. It names the exact
   error (RefererNotAllowedMapError, ApiNotActivatedMapError, ...) which is
   the difference between guessing and knowing. */
.map-auth-error__reason {
  max-width: 44rem;
  margin-top: 0.5rem;
  padding: 0.5rem 0.75rem;
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
  font-size: 0.7rem;
  line-height: 1.45;
  text-align: left;
  color: rgb(var(--color-base-700));
  background: rgb(var(--color-base-100));
  border-radius: 0.375rem;
  white-space: pre-wrap;
  word-break: break-word;
}

.dark .map-auth-error__reason {
  color: rgb(var(--color-base-200));
  background: rgb(var(--color-base-800));
}

/* ------------------------------------------------------- status badges */
/* The admin marks status with pill badges written from Python as Tailwind
 * utilities: `bg-green-100 text-green-800` and friends. Unfold ships a
 * PREBUILT Tailwind bundle — there is no build step over our Python source,
 * so those class names are only styled if Unfold happens to use them too.
 * Most do not exist: of the families we emit, the bundle carries the
 * `bg-*-100` grounds but none of the `text-*-800` inks, and no dark variant
 * for either. The result is a pale pill with unstyled text on it, which is
 * unreadable on the dark ground.
 *
 * So the badge is a component here instead, with both themes defined and no
 * dependency on what Unfold's build happens to include. `.badge` carries the
 * shape; `.badge--<tone>` carries the colour.
 *
 * Specificity note: this file is linked BEFORE Unfold's bundle, so a single
 * class would lose on source order to any utility of equal weight that the
 * element also carries. Two classes on the selector outrank that.
 */
.badge.badge {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  line-height: 1.25rem;
  white-space: nowrap;
}

a.badge.badge { text-decoration: none; }

/* Tones. Light: a tinted ground with a dark ink. Dark: the relationship is
 * inverted — a deep, desaturated ground with a light ink — because a pastel
 * ground on a near-black page glares and drags the eye off the data. */
.badge--neutral { background: rgb(var(--color-base-200)); color: rgb(var(--color-base-800)); }
.badge--primary { background: rgb(var(--color-primary-100)); color: rgb(var(--color-primary-900)); }
.badge--green   { background: #dcfce7; color: #166534; }
.badge--amber   { background: #fef3c7; color: #92400e; }
.badge--orange  { background: #ffedd5; color: #9a3412; }
.badge--red     { background: #fee2e2; color: #991b1b; }
.badge--blue    { background: #dbeafe; color: #1e40af; }
.badge--purple  { background: #f3e8ff; color: #6b21a8; }
/* "gray" is what the Python calls its neutral tone; alias it. */
.badge--gray    { background: rgb(var(--color-base-200)); color: rgb(var(--color-base-800)); }

.dark .badge--neutral { background: rgb(var(--color-base-800)); color: rgb(var(--color-base-200)); }
.dark .badge--primary { background: rgb(var(--color-primary-900)); color: rgb(var(--color-primary-100)); }
.dark .badge--green   { background: #14532d; color: #bbf7d0; }
.dark .badge--amber   { background: #78350f; color: #fde68a; }
.dark .badge--orange  { background: #7c2d12; color: #fed7aa; }
.dark .badge--red     { background: #7f1d1d; color: #fecaca; }
.dark .badge--blue    { background: #1e3a8a; color: #bfdbfe; }
.dark .badge--purple  { background: #581c87; color: #e9d5ff; }
.dark .badge--gray    { background: rgb(var(--color-base-800)); color: rgb(var(--color-base-200)); }

/* An actionable badge (the "view as" link) should say so on hover. */
a.badge.badge:hover { filter: brightness(1.08); }
.dark a.badge.badge:hover { filter: brightness(1.35); }

/* Inline status marks in prose — the ✓/! list on the impersonation
 * confirmation. Same reason as the badges: `text-green-600` is not in
 * Unfold's bundle, so it would render as unstyled body text. */
.mark-ok   { color: #16a34a; }
.mark-warn { color: #d97706; }
.dark .mark-ok   { color: #4ade80; }
.dark .mark-warn { color: #fbbf24; }

/* --------------------------------------------------- base-* utilities */
/* The admin templates use a `base-*` colour vocabulary — `text-base-500`,
 * `dark:bg-base-900`, `border-base-200` and so on, ~570 occurrences across
 * the templates and the list_display markup in Python.
 *
 * NONE of them exist. Unfold ships a prebuilt Tailwind bundle and nothing
 * compiles Tailwind over this project's source, so a utility only exists if
 * Unfold's own templates happen to use it — and Unfold names its neutrals
 * `text-font-default-light` / `-dark`, never `base-*`. So every one of those
 * classes was a no-op: text fell back to inherited colour, cards fell back
 * to `bg-white` with no dark override.
 *
 * The COLORS dict in config/unfold.py IS emitted, as `--color-base-*` custom
 * properties on :root (see unfold/layouts/skeleton.html). So the tokens are
 * real and only the utility classes were missing. This defines them.
 *
 * `.dark` is the class Unfold puts on <html> for the dark theme, so the
 * `dark:` variants are written as `.dark .dark\:foo` descendant rules.
 *
 * Specificity: this file is linked BEFORE Unfold's bundle, so the doubled
 * class (`.text-base-500.text-base-500`) keeps these from losing on source
 * order to any equal-weight utility. The dark rules carry `.dark` as an
 * extra element so they already outrank their light counterparts.
 */
.bg-base-50.bg-base-50 { background-color: rgb(var(--color-base-50)); }
.text-base-50.text-base-50 { color: rgb(var(--color-base-50)); }
.border-base-50.border-base-50 { border-color: rgb(var(--color-base-50)); }
.divide-base-50 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-50)); }
.bg-base-100.bg-base-100 { background-color: rgb(var(--color-base-100)); }
.text-base-100.text-base-100 { color: rgb(var(--color-base-100)); }
.border-base-100.border-base-100 { border-color: rgb(var(--color-base-100)); }
.divide-base-100 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-100)); }
.bg-base-200.bg-base-200 { background-color: rgb(var(--color-base-200)); }
.text-base-200.text-base-200 { color: rgb(var(--color-base-200)); }
.border-base-200.border-base-200 { border-color: rgb(var(--color-base-200)); }
.divide-base-200 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-200)); }
.bg-base-300.bg-base-300 { background-color: rgb(var(--color-base-300)); }
.text-base-300.text-base-300 { color: rgb(var(--color-base-300)); }
.border-base-300.border-base-300 { border-color: rgb(var(--color-base-300)); }
.divide-base-300 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-300)); }
.bg-base-400.bg-base-400 { background-color: rgb(var(--color-base-400)); }
.text-base-400.text-base-400 { color: rgb(var(--color-base-400)); }
.border-base-400.border-base-400 { border-color: rgb(var(--color-base-400)); }
.divide-base-400 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-400)); }
.bg-base-500.bg-base-500 { background-color: rgb(var(--color-base-500)); }
.text-base-500.text-base-500 { color: rgb(var(--color-base-500)); }
.border-base-500.border-base-500 { border-color: rgb(var(--color-base-500)); }
.divide-base-500 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-500)); }
.bg-base-600.bg-base-600 { background-color: rgb(var(--color-base-600)); }
.text-base-600.text-base-600 { color: rgb(var(--color-base-600)); }
.border-base-600.border-base-600 { border-color: rgb(var(--color-base-600)); }
.divide-base-600 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-600)); }
.bg-base-700.bg-base-700 { background-color: rgb(var(--color-base-700)); }
.text-base-700.text-base-700 { color: rgb(var(--color-base-700)); }
.border-base-700.border-base-700 { border-color: rgb(var(--color-base-700)); }
.divide-base-700 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-700)); }
.bg-base-800.bg-base-800 { background-color: rgb(var(--color-base-800)); }
.text-base-800.text-base-800 { color: rgb(var(--color-base-800)); }
.border-base-800.border-base-800 { border-color: rgb(var(--color-base-800)); }
.divide-base-800 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-800)); }
.bg-base-900.bg-base-900 { background-color: rgb(var(--color-base-900)); }
.text-base-900.text-base-900 { color: rgb(var(--color-base-900)); }
.border-base-900.border-base-900 { border-color: rgb(var(--color-base-900)); }
.divide-base-900 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-900)); }
.bg-base-950.bg-base-950 { background-color: rgb(var(--color-base-950)); }
.text-base-950.text-base-950 { color: rgb(var(--color-base-950)); }
.border-base-950.border-base-950 { border-color: rgb(var(--color-base-950)); }
.divide-base-950 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-950)); }

.dark .dark\:bg-base-50 { background-color: rgb(var(--color-base-50)); }
.dark .dark\:text-base-50 { color: rgb(var(--color-base-50)); }
.dark .dark\:border-base-50 { border-color: rgb(var(--color-base-50)); }
.dark .dark\:divide-base-50 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-50)); }
.dark .dark\:bg-base-100 { background-color: rgb(var(--color-base-100)); }
.dark .dark\:text-base-100 { color: rgb(var(--color-base-100)); }
.dark .dark\:border-base-100 { border-color: rgb(var(--color-base-100)); }
.dark .dark\:divide-base-100 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-100)); }
.dark .dark\:bg-base-200 { background-color: rgb(var(--color-base-200)); }
.dark .dark\:text-base-200 { color: rgb(var(--color-base-200)); }
.dark .dark\:border-base-200 { border-color: rgb(var(--color-base-200)); }
.dark .dark\:divide-base-200 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-200)); }
.dark .dark\:bg-base-300 { background-color: rgb(var(--color-base-300)); }
.dark .dark\:text-base-300 { color: rgb(var(--color-base-300)); }
.dark .dark\:border-base-300 { border-color: rgb(var(--color-base-300)); }
.dark .dark\:divide-base-300 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-300)); }
.dark .dark\:bg-base-400 { background-color: rgb(var(--color-base-400)); }
.dark .dark\:text-base-400 { color: rgb(var(--color-base-400)); }
.dark .dark\:border-base-400 { border-color: rgb(var(--color-base-400)); }
.dark .dark\:divide-base-400 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-400)); }
.dark .dark\:bg-base-500 { background-color: rgb(var(--color-base-500)); }
.dark .dark\:text-base-500 { color: rgb(var(--color-base-500)); }
.dark .dark\:border-base-500 { border-color: rgb(var(--color-base-500)); }
.dark .dark\:divide-base-500 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-500)); }
.dark .dark\:bg-base-600 { background-color: rgb(var(--color-base-600)); }
.dark .dark\:text-base-600 { color: rgb(var(--color-base-600)); }
.dark .dark\:border-base-600 { border-color: rgb(var(--color-base-600)); }
.dark .dark\:divide-base-600 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-600)); }
.dark .dark\:bg-base-700 { background-color: rgb(var(--color-base-700)); }
.dark .dark\:text-base-700 { color: rgb(var(--color-base-700)); }
.dark .dark\:border-base-700 { border-color: rgb(var(--color-base-700)); }
.dark .dark\:divide-base-700 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-700)); }
.dark .dark\:bg-base-800 { background-color: rgb(var(--color-base-800)); }
.dark .dark\:text-base-800 { color: rgb(var(--color-base-800)); }
.dark .dark\:border-base-800 { border-color: rgb(var(--color-base-800)); }
.dark .dark\:divide-base-800 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-800)); }
.dark .dark\:bg-base-900 { background-color: rgb(var(--color-base-900)); }
.dark .dark\:text-base-900 { color: rgb(var(--color-base-900)); }
.dark .dark\:border-base-900 { border-color: rgb(var(--color-base-900)); }
.dark .dark\:divide-base-900 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-900)); }
.dark .dark\:bg-base-950 { background-color: rgb(var(--color-base-950)); }
.dark .dark\:text-base-950 { color: rgb(var(--color-base-950)); }
.dark .dark\:border-base-950 { border-color: rgb(var(--color-base-950)); }
.dark .dark\:divide-base-950 > :not([hidden]) ~ :not([hidden]) { border-color: rgb(var(--color-base-950)); }

/* `bg-white` is in Unfold's bundle and the cards use it as their light
 * ground, paired with `dark:bg-base-900`. That pairing now works, but only
 * where the dark class was actually written. */
.dark .dark\:hover\:bg-base-800:hover { background-color: rgb(var(--color-base-800)); }
.hover\:bg-base-50:hover { background-color: rgb(var(--color-base-50)); }


/* ------------------------------------------- semantic colour utilities */
/* Same cause as the base-* block above: these are used by the templates and
 * by list_display markup, but are not in Unfold's prebuilt bundle, so they
 * were rendering as nothing. Values are Tailwind's own defaults for these
 * shades, so the light theme looks as originally intended.
 */
.bg-amber-50 { background-color: #fffbeb; }
.bg-green-600 { background-color: #16a34a; }
.border-amber-200 { border-color: #fde68a; }
.border-amber-300 { border-color: #fcd34d; }
.dark .dark\:bg-amber-900 { background-color: #78350f; }
.dark .dark\:bg-amber-950 { background-color: #451a03; }
.dark .dark\:bg-blue-900 { background-color: #1e3a8a; }
.dark .dark\:bg-green-900 { background-color: #14532d; }
.dark .dark\:bg-red-900 { background-color: #7f1d1d; }
.dark .dark\:border-amber-800 { border-color: #92400e; }
.dark .dark\:border-amber-900 { border-color: #78350f; }
.dark .dark\:border-red-900 { border-color: #7f1d1d; }
.dark .dark\:hover\:bg-red-950:hover { background-color: #450a0a; }
.dark .dark\:text-amber-200 { color: #fde68a; }
.dark .dark\:text-amber-400 { color: #fbbf24; }
.dark .dark\:text-blue-200 { color: #bfdbfe; }
.dark .dark\:text-green-200 { color: #bbf7d0; }
.dark .dark\:text-green-400 { color: #4ade80; }
.dark .dark\:text-red-200 { color: #fecaca; }
.dark .dark\:text-red-300 { color: #fca5a5; }
.dark .dark\:text-red-400 { color: #f87171; }
.hover\:bg-amber-50:hover { background-color: #fffbeb; }
.hover\:bg-amber-700:hover { background-color: #b45309; }
.hover\:bg-red-50:hover { background-color: #fef2f2; }
.text-amber-800 { color: #92400e; }
.text-blue-800 { color: #1e40af; }
.text-green-600 { color: #16a34a; }
.text-green-800 { color: #166534; }
.text-red-800 { color: #991b1b; }

/* Hover text colours — the <summary> toggles and inline links. Same reason
 * as above: not in Unfold's bundle, so the hover was a no-op. */
.hover\:text-base-900:hover { color: rgb(var(--color-base-900)); }
.hover\:text-primary-600:hover { color: rgb(var(--color-primary-600)); }
.dark .dark\:hover\:text-base-100:hover { color: rgb(var(--color-base-100)); }
.dark .dark\:hover\:text-primary-400:hover { color: rgb(var(--color-primary-400)); }

/* Legend dots matching the map pins, so the key is read at a glance. */
.map-legend__dot {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 999px;
  vertical-align: middle;
  margin-right: 0.375rem;
  background: #c2410c;
  border: 2px solid #7c2d12;
}

.map-legend__dot--school {
  background: rgb(var(--color-primary-500));
  border-color: #8a5a00;
  width: 0.85rem;
  height: 0.85rem;
}

.map-legend__flow {
  font-style: italic;
}

/* ------------------------------------------------------------- sign-in */
/* The login screen is the one page seen before anything else is trusted, so
   it gets a card rather than a form floating on a dark field. */
.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 2rem 1rem;
  background:
    radial-gradient(60rem 40rem at 50% -10%,
                    rgb(var(--color-primary-500) / 0.10), transparent 70%),
    rgb(var(--color-base-950));
}

.login-card {
  width: 100%;
  max-width: 25rem;
  padding: 2.25rem 2rem 2rem;
  background: rgb(var(--color-base-900));
  border: 1px solid rgb(var(--color-base-800));
  border-radius: 0.9rem;
  box-shadow: 0 18px 45px rgb(0 0 0 / 0.45);
}

.login-logo {
  height: 2.5rem;
  width: auto;
  margin-bottom: 1.5rem;
}

.login-heading {
  font-size: 1.15rem;
  font-weight: 600;
  color: rgb(var(--color-base-50));
}

.login-sub {
  margin-top: 0.15rem;
  font-size: 0.8125rem;
  color: rgb(var(--color-base-400));
}

/* The button was a faint outline: .btn-primary is inline-flex with its own
   padding, so `w-full` never took and the amber never filled. This is a
   block-level button that actually looks pressable, in brand amber with a
   near-black label (white on amber is 2.57:1 and fails WCAG AA). */
.login-submit {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
  padding: 0.7rem 1rem;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: rgb(var(--color-base-950));
  background: rgb(var(--color-primary-500));
  border: 1px solid rgb(var(--color-primary-600));
  border-radius: 0.5rem;
  cursor: pointer;
  transition: background-color 0.12s ease, transform 0.06s ease;
}

.login-submit:hover {
  background: rgb(var(--color-primary-400));
}

.login-submit:active {
  transform: translateY(1px);
}

.login-submit:focus-visible {
  outline: 3px solid rgb(var(--color-primary-300));
  outline-offset: 2px;
}

/* The login page is dark whatever the theme, so its fields must be too —
   Unfold's light-mode field styling is unreadable on this card. */
.login-card input[type="text"],
.login-card input[type="email"],
.login-card input[type="password"] {
  width: 100%;
  padding: 0.6rem 0.75rem;
  color: rgb(var(--color-base-50));
  background: rgb(var(--color-base-950));
  border: 1px solid rgb(var(--color-base-700));
  border-radius: 0.5rem;
}

.login-card input:focus {
  outline: none;
  border-color: rgb(var(--color-primary-500));
  box-shadow: 0 0 0 3px rgb(var(--color-primary-500) / 0.25);
}

.login-card label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: rgb(var(--color-base-200));
}

/* Anchors used as buttons need the text centring a <button> gets free. */
.login-submit--link {
  display: block;
  text-align: center;
  text-decoration: none;
}

.login-submit--link:hover {
  text-decoration: none;
}

/* Nothing to submit yet. Kept clearly amber-derived rather than grey, so it
   reads as "not ready" rather than "broken", and the cursor says why. */
.login-submit:disabled,
.login-submit[aria-disabled="true"] {
  background: rgb(var(--color-primary-500) / 0.35);
  border-color: rgb(var(--color-primary-600) / 0.35);
  color: rgb(var(--color-base-950) / 0.55);
  cursor: not-allowed;
  transform: none;
}

.login-submit:disabled:hover {
  background: rgb(var(--color-primary-500) / 0.35);
}

.login-footnote {
  margin-top: 1.75rem;
  font-size: 0.8125rem;
}

.login-footnote a {
  color: rgb(var(--color-base-400));
  text-decoration: none;
}

.login-footnote a:hover {
  color: rgb(var(--color-base-100));
}

/* Unfold marks required fields with a red asterisk that inherits the dark
   card's colour poorly. */
.login-card .text-red-600,
.login-card .required {
  color: rgb(248 113 113);
}

/* ------------------------------------------------- show/hide password */
.password-wrap {
  position: relative;
  display: block;
}

/* Room for the button, so a long password never runs under it. */
.password-wrap input[type="password"],
.password-wrap input[type="text"] {
  padding-right: 2.75rem;
}

.password-reveal {
  position: absolute;
  top: 50%;
  right: 0.5rem;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: 0.375rem;
  background: transparent;
  color: rgb(var(--color-base-400));
  cursor: pointer;
}

.password-reveal:hover {
  color: rgb(var(--color-base-100));
  background: rgb(var(--color-base-800));
}

.password-reveal:focus-visible {
  outline: 2px solid rgb(var(--color-primary-500));
  outline-offset: 1px;
}

.password-reveal .material-symbols-outlined {
  font-size: 1.15rem;
}
