/* ═══════════════════════════════════════════════════════════════
   THEMING CONTRACT (2026-09-05). This file holds the LIGHT theme only.
   Every dark-mode rule lives in dark.css, which each page links with
   media="(prefers-color-scheme: dark)" and shared/theme.js flips to
   `all` / `not all` when a person picks Dark or Light by hand. Never add
   `@media (prefers-color-scheme: dark)` here — scripts/check-theme-split.mjs
   fails the build if you do. Put dark variants in dark.css instead.
   ═══════════════════════════════════════════════════════════════ */
/* ── Variables ─────────────────────────────────────────────── */
:root {
  --accent:       #2870a0;
  --accent-mid:   #1f4366;
  --accent-dark:  #24324b;
  --accent-deep:  #1a2940;
  --accent-light: rgba(40,112,160,.1);
  --red:          #ef4444;
  --red-light:    rgba(239,68,68,.08);
  --gray:         #8e8e93;
  --amber:        #f59e0b;
  --amber-text:   #b45309;   /* amber dark enough for WCAG AA as text on light surfaces */
  --green:        #16a34a;
  --green-text:   #15803d;   /* AA as text on the light glass surfaces */
  --text:         #1c1c1e;
  --text-secondary: #6e6e73; /* darkened from #8e8e93 for AA contrast on glass cards */
  --white:        #ffffff;
  --glass:        rgba(255,255,255,.72);
  --glass-strong: rgba(255,255,255,.85);
  --glass-border: rgba(255,255,255,.45);
  --glass-blur:   blur(24px) saturate(180%);
  --glass-shadow: 0 8px 40px rgba(0,0,0,.06), 0 1px 3px rgba(0,0,0,.04);
  --dark-glass:   rgba(255,255,255,.08);
  --dark-border:  rgba(255,255,255,.12);
  --border:       rgba(0,0,0,.06);
  --radius:       18px;
  --radius-sm:    14px;
  --radius-pill:  100px;
  --spring:       cubic-bezier(.175,.885,.32,1.275);
  --ease:         cubic-bezier(.25,.1,.25,1);
  --ease-out:     cubic-bezier(0,.55,.45,1);
  --header-h:     108px;
  --nav-h:        48px;
  /* Display face for headings and hero numbers only. Body copy stays on
     the system stack (it is what the OS renders fastest and what auditors
     read most). One self-hosted variable woff2 (Outfit, SIL OFL, latin
     subset, 32 KB) — the CSP allows font-src 'self' and nothing else. */
  --font-display: 'Outfit', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 500 800;
  font-display: swap;
  src: url('/assets/fonts/outfit-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Reset ─────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  background: linear-gradient(160deg, #e4eef6 0%, #dce6f0 35%, #eaeff4 70%, #e0eaf2 100%);
  background-attachment: fixed;
  color: var(--text);
  min-height: 100vh;
  padding-bottom: 80px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(0,0,0,.12); border-radius: 3px; }

/* ── Welcome Overlay ───────────────────────────────────────── */
.welcome-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: linear-gradient(160deg, #162236 0%, #1f3550 40%, #1a3a5c 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity .6s var(--ease-out);
}
.welcome-overlay.fade-out {
  opacity: 0;
  pointer-events: none;
}

.welcome-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  padding: 36px;
  max-width: 440px;
  width: 100%;
}

.welcome-logo {
  width: min(280px, 72%);
  height: auto;
  display: block;
}

.speech-bubble {
  background: rgba(255,255,255,.12);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  backdrop-filter: blur(24px) saturate(150%);
  color: #fff;
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1.55;
  text-align: center;
  padding: 20px 28px;
  border-radius: 22px;
  border: 1px solid rgba(255,255,255,.18);
  position: relative;
  box-shadow: 0 12px 40px rgba(0,0,0,.2), inset 0 1px 0 rgba(255,255,255,.15);
  letter-spacing: -.01em;
}
.speech-bubble::after {
  content: '';
  position: absolute;
  bottom: -11px;
  left: 50%;
  transform: translateX(-50%);
  border-left: 12px solid transparent;
  border-right: 12px solid transparent;
  border-top: 12px solid rgba(255,255,255,.12);
}

.ari-img {
  width: 220px;
  height: auto;
  image-rendering: pixelated;
  filter: drop-shadow(0 8px 24px rgba(0,0,0,.35));
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
.ari-img.ari-beam-down { animation: ari-beam-down 1.8s var(--ease-out, ease-out) both; }
.ari-img.ari-idle       { animation: ari-idle-float 3.4s ease-in-out infinite; }
.ari-img.ari-beam-up   { animation: ari-beam-up 1.6s var(--ease-out, ease-out) both; }

/* 3D Ari (model-viewer). Scales with the viewport so it fits the card
   on phones without extra breakpoints; reuses the same beam/idle motion
   as the old 2D Ari via the shared keyframes below. */
.ari-model {
  /* Wrapper div (shared/welcome.js): poster <img> underneath, three.js
     <canvas> cross-faded on top once the first real frame renders. The
     wrapper is what GSAP/the CSS keyframes animate, so a 3D failure
     mid-beam never strands the animation — the canvas just goes away. */
  position: relative;
  width: min(280px, 80vw);
  height: min(340px, 46vh);
  background-color: transparent;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
  filter: drop-shadow(0 8px 24px rgba(0, 0, 0, .35));
}
.ari-model .ari-poster,
.ari-model canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* The box is fixed; contain keeps the still frame's aspect ratio inside
   exactly the same box, so every animation and breakpoint below applies
   unchanged whether the 3D canvas ever arrives or not. */
.ari-model .ari-poster {
  object-fit: contain;
  transition: opacity .35s ease;
}
.ari-model canvas {
  opacity: 0;
  transition: opacity .35s ease;
}
.ari-model.ari-3d-live canvas { opacity: 1; }
.ari-model.ari-3d-live .ari-poster { opacity: 0; }

.ari-model.ari-beam-down { animation: ari-beam-down 1.8s var(--ease-out, ease-out) both; }
.ari-model.ari-idle       { animation: ari-idle-float 3.4s ease-in-out infinite; }
.ari-model.ari-beam-up   { animation: ari-beam-up 1.6s var(--ease-out, ease-out) both; }

@keyframes ari-beam-down {
  0%   { transform: translateY(-110vh) scaleY(1.6) scaleX(.6); opacity: 0; filter: drop-shadow(0 0 28px rgba(144,228,244,.9)) brightness(1.6); }
  55%  { transform: translateY(0) scaleY(1.05) scaleX(.95); opacity: 1; filter: drop-shadow(0 0 18px rgba(144,228,244,.75)) brightness(1.2); }
  78%  { transform: translateY(0) scaleY(.96) scaleX(1.04); filter: drop-shadow(0 8px 24px rgba(0,0,0,.35)) brightness(1); }
  100% { transform: translateY(0) scale(1); opacity: 1; filter: drop-shadow(0 8px 24px rgba(0,0,0,.35)); }
}

@keyframes ari-idle-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

@keyframes ari-beam-up {
  0%   { transform: translateY(0) scale(1); opacity: 1; filter: drop-shadow(0 8px 24px rgba(0,0,0,.35)); }
  25%  { transform: translateY(0) scaleY(1.1) scaleX(.92); filter: drop-shadow(0 0 18px rgba(144,228,244,.75)) brightness(1.25); }
  100% { transform: translateY(-110vh) scaleY(1.8) scaleX(.55); opacity: 0; filter: drop-shadow(0 0 28px rgba(144,228,244,.9)) brightness(1.7); }
}

.welcome-stage-hidden {
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity .5s var(--ease-out), transform .5s var(--spring);
}
.welcome-stage-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  transition: opacity .5s var(--ease-out), transform .5s var(--spring);
}

/* shared/welcome.js sets this on the card when GSAP is driving the
   sequence. The stage classes stay on — they still own pointer-events, and
   they remain the whole animation when GSAP is absent — but their CSS
   transitions have to go: GSAP writes opacity/transform inline on every
   frame, and a transition on a property being set 60 times a second
   smears each write toward the next instead of honoring it. The two
   engines also disagree about easing, which shows up as the button
   drifting past its mark and settling back. */
.welcome-gsap .welcome-stage-hidden,
.welcome-gsap .welcome-stage-visible,
.welcome-gsap .welcome-btn { transition: none; }
/* :active feedback is the one transition worth keeping — it responds to
   the finger, not to the timeline. */
.welcome-gsap .welcome-btn:active { transition: transform .12s var(--spring); }

@media (prefers-reduced-motion: reduce) {
  .ari-img.ari-beam-down,
  .ari-img.ari-idle,
  .ari-img.ari-beam-up,
  .ari-model.ari-beam-down,
  .ari-model.ari-idle,
  .ari-model.ari-beam-up { animation: none; }
}

.welcome-btn {
  padding: 14px 40px;
  border-radius: var(--radius-pill);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid rgba(255,255,255,.2);
  background: rgba(40,112,160,.85);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  color: #fff;
  font-family: inherit;
  letter-spacing: -.01em;
  transition: transform .35s var(--spring), opacity .4s var(--ease-out), box-shadow .3s var(--ease);
  box-shadow: 0 6px 24px rgba(40,112,160,.3), inset 0 1px 0 rgba(255,255,255,.2);
}
.welcome-btn:hover {
  box-shadow: 0 8px 32px rgba(40,112,160,.4), inset 0 1px 0 rgba(255,255,255,.25);
}
.welcome-btn:active { transform: scale(.96); }
.welcome-btn.hidden {
  opacity: 0;
  transform: translateY(12px) scale(.95);
  pointer-events: none;
}
.welcome-btn.visible {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

/* ── Site Header ────────────────────────────────────────────── */
.site-header {
  background: rgba(26,41,64,.88);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  color: #fff;
  position: sticky;
  top: 0;
  z-index: 200;
  border-bottom: 1px solid rgba(255,255,255,.08);
}

.header-inner {
  max-width: 960px;
  margin: 0 auto;
  padding: 14px 20px 12px;
}

.header-top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 10px;
}
/* Brand wave mark sits to the left of the title; the trailing group
   (user actions / audit fields) is pushed to the far right. */
.header-top > .dash-user,
.header-top > .header-fields { margin-left: auto; }

.header-logo {
  height: 34px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

/* Back-to-dashboard link injected on every zone audit page (audit-engine.js).
   The native shell injects its own #lpa-back-btn; this shares the id so only
   one ever renders. */
.zone-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 7px 14px;
  min-height: 36px;
  border: 1px solid rgba(255,255,255,.25);
  border-radius: var(--radius-pill);
  background: rgba(255,255,255,.1);
  color: #fff;
  font-size: .78rem;
  font-weight: 600;
  font-family: inherit;
  text-decoration: none;
  letter-spacing: -.01em;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .25s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.zone-back-btn:hover { background: rgba(255,255,255,.18); }
.zone-back-btn:active { transform: scale(.96); }

.site-header h1 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -.02em;
  color: #fff;
  background: linear-gradient(135deg, #7098c0, #2870a0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.header-fields {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.header-fields label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.header-fields span {
  font-size: .65rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: rgba(255,255,255,.7);
  font-weight: 500;
}

.header-fields input {
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.12);
  color: #fff;
  padding: 8px 12px;
  border-radius: 10px;
  font-size: .85rem;
  min-width: 170px;
  font-family: inherit;
  transition: all .3s var(--ease);
}
.header-fields input::placeholder { color: rgba(255,255,255,.5); }

@keyframes glow-pulse {
  0%, 100% { box-shadow: 0 0 8px rgba(40,112,160,.4), 0 0 20px rgba(40,112,160,.15); }
  50%      { box-shadow: 0 0 14px rgba(40,112,160,.7), 0 0 30px rgba(40,112,160,.25); }
}
.header-fields input.needs-attention {
  border-color: var(--accent);
  animation: glow-pulse 2s ease-in-out infinite;
}
.header-fields input.needs-attention::placeholder {
  color: rgba(40,112,160,.6);
}
.header-fields input:focus {
  outline: none;
  background: rgba(255,255,255,.14);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.2);
}
.header-fields input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(1) opacity(.5);
}

/* ── Collapsed audit identity ────────────────────────────────
   Date and Auditor Name are SET-ONCE fields: audit-engine.js fills the
   date with today and auth-guard.js fills the name from the allowlist,
   so on a normal audit nobody touches either one. They were still
   holding ~120px of a 812px phone screen for all 43 questions — with
   the header, section nav and summary footer together taking 53% of
   the viewport, only about two and a half questions fit at a time.

   Once the first answer lands they fold into one tappable summary
   ("Aug 4 · James Jensen"); tapping it restores the real fields. The
   state lives on <body> so the --header-h fallback can key off it too. */
.header-idcard {
  display: none;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.12);
  color: rgba(255,255,255,.92);
  font-family: inherit;
  font-size: .82rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .3s var(--ease);
}
.header-idcard:hover { background: rgba(255,255,255,.16); }
.header-idcard:active { transform: scale(.97); }
.header-idcard-edit {
  font-size: .7rem;
  font-weight: 500;
  color: rgba(255,255,255,.55);
}
.fields-collapsed .header-fields { display: none; }
.fields-collapsed .header-idcard { display: inline-flex; }

/* Progress bar.
   WRAPS ON PURPOSE. The track is the only flexible item in a row whose
   other members (#progress-label, .save-indicator, and the Spot Check
   toggle audit-engine.js appends here) are all white-space:nowrap. On a
   375px screen they overflowed the row, and since an empty div has a
   min-content width of 0 the track shrank to EXACTLY 0px — the progress
   bar simply did not render on the phone, which is the device the whole
   audit is walked on. flex-wrap + a real min-width means it can always
   be seen; when the row is tight the trailing controls drop to a second
   line instead of eating the bar. */
.progress-bar-wrap {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
}

.progress-track {
  flex: 1 1 140px;
  min-width: 120px;
  height: 6px;
  background: rgba(255,255,255,.1);
  border-radius: 3px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #2870a0, #5dd8ea);
  border-radius: 3px;
  transition: width .5s var(--ease-out);
  box-shadow: 0 0 12px rgba(40,112,160,.35);
}

#progress-label {
  font-size: .72rem;
  color: rgba(255,255,255,.72);
  white-space: nowrap;
  /* Was min-width:140px, which is what starved .progress-track of the
     space it needed to render at all. The text is nowrap, so it already
     reserves exactly what it needs. */
  min-width: 0;
  margin-left: auto;
  text-align: right;
  font-weight: 500;
}

/* Auto-save indicator — sits beside the progress label. Confirms every
   localStorage write so auditors can trust that a tab eviction won't lose
   work; flips to a warning if the write actually failed (quota/private).

   Its slot is RESERVED, not grown into. It only has text after the first
   save, and on a phone that late arrival pushed the Spot Check toggle
   onto a second header row — the header jumped ~19px on every autosave,
   i.e. on every single answer. A fixed slot means it fades in and out in
   place. The error state is the one exception: it is a long sentence, it
   is rare, and it is worth a reflow. */
.save-indicator {
  flex: 0 0 auto;
  width: 4.4rem;
  text-align: right;
  overflow: hidden;
  font-size: .68rem;
  font-weight: 600;
  color: rgba(144,228,244,.85);
  white-space: nowrap;
  opacity: 0;
  transition: opacity .4s var(--ease);
}
.save-indicator.visible { opacity: 1; }
.save-indicator.save-error { color: #fca5a5; width: auto; flex: 0 1 auto; }

/* ── Section Nav ────────────────────────────────────────────── */
.section-nav {
  background: rgba(31,67,102,.78);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  position: sticky;
  top: var(--header-h);
  z-index: 190;
  border-bottom: 1px solid rgba(255,255,255,.06);
  overflow-x: auto;
  scrollbar-width: none;
}
.section-nav::-webkit-scrollbar { display: none; }

.section-nav-inner {
  display: flex;
  max-width: 960px;
  margin: 0 auto;
  padding: 6px 12px;
  gap: 4px;
}

.nav-tab {
  padding: 7px 14px;
  font-size: .76rem;
  font-weight: 600;
  color: rgba(208,239,247,.92);
  background: transparent;
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: all .3s var(--ease);
  font-family: inherit;
  letter-spacing: -.01em;
}
.nav-tab:hover {
  color: #fff;
  background: rgba(255,255,255,.08);
}
.nav-tab.active {
  color: #fff;
  background: rgba(40,112,160,.2);
  box-shadow: inset 0 0 0 1px rgba(40,112,160,.25);
}

/* ── Main Content ───────────────────────────────────────────── */
#audit-body {
  max-width: 960px;
  margin: 0 auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ── Audit Section Card ─────────────────────────────────────── */
.audit-section {
  scroll-margin-top: calc(var(--header-h) + var(--nav-h) + 12px);
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--glass-shadow);
  position: relative;
}
.audit-section::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(255,255,255,.25) 0%, transparent 50%, rgba(255,255,255,.05) 100%);
  pointer-events: none;
}

.section-header {
  background: rgba(40,112,160,.05);
  border-bottom: 1px solid rgba(0,0,0,.04);
  padding: 14px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  position: relative;
}

.section-header h2 {
  font-size: .9rem;
  font-weight: 700;
  color: var(--accent-dark);
  letter-spacing: -.01em;
}

.section-stats {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
}

/* "All OK" — fills the rest of a section with its positive answer. Sits
   between the title and the stats; small and outlined so it never competes
   with the answer buttons below it, and gone the moment the section has
   nothing left to fill. */
.section-allok-btn {
  margin-left: auto;
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  border: 1.5px solid rgba(40,112,160,.45);
  background: rgba(255,255,255,.7);
  color: var(--accent);
  font: inherit;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .12s ease, border-color .12s ease, transform .1s ease;
}
.section-allok-btn:hover { background: rgba(40,112,160,.08); border-color: var(--accent); }
.section-allok-btn:active { transform: scale(.95); background: rgba(40,112,160,.16); }
.section-allok-btn[hidden] { display: none; }
.section-header h2 + .section-allok-btn { margin-left: 0; }
.section-header .section-stats { margin-left: auto; }

/* ── Question Rows ──────────────────────────────────────────── */
.question-list { display: flex; flex-direction: column; }

.question-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 14px 20px;
  border-bottom: 1px solid rgba(0,0,0,.04);
  transition: background .35s var(--ease);
  position: relative;
}
.question-row:last-child { border-bottom: none; }
.question-row:hover { background: rgba(0,0,0,.015); }
/* Answered rows carry a left rail as well as a tint. The tint alone was
   4%/3% alpha — effectively invisible on a phone in gallery light, which
   is exactly when you are scanning for the row you skipped. */
.question-row.answered-yes { background: rgba(40,112,160,.055); box-shadow: inset 3px 0 0 0 rgba(40,112,160,.55); }
.question-row.answered-no  { background: rgba(239,68,68,.05);   box-shadow: inset 3px 0 0 0 rgba(239,68,68,.55); }
.question-row.answered-na  { background: rgba(0,0,0,.025);      box-shadow: inset 3px 0 0 0 rgba(107,114,128,.5); }
.question-row.answered-na .question-text { color: var(--text-secondary); }

/* A "No" with no department picked: recorded, but collectIssueEmailPayloads()
   will skip it, so no one is told. Mark it while it can still be fixed. */
.question-row.issue-unrouted { box-shadow: inset 3px 0 0 0 var(--amber); }
.question-row.issue-unrouted .issue-type-label::after {
  content: ' — pick one, or nobody is notified';
  color: var(--amber-text);
  font-weight: 600;
}
.question-row { scroll-margin-top: calc(var(--header-h) + var(--nav-h) + 16px); }
.question-row.row-flash-missing {
  animation: row-flash-missing 1.6s var(--ease, ease-out);
}
@keyframes row-flash-missing {
  0%   { background: rgba(245,158,11,.0);  box-shadow: inset 0 0 0 0 rgba(245,158,11,0); }
  15%  { background: rgba(245,158,11,.22); box-shadow: inset 3px 0 0 0 rgba(245,158,11,.9); }
  60%  { background: rgba(245,158,11,.18); box-shadow: inset 3px 0 0 0 rgba(245,158,11,.7); }
  100% { background: rgba(245,158,11,0);   box-shadow: inset 0 0 0 0 rgba(245,158,11,0); }
}

/* Missing-answer toast (bottom-center, above summary footer) */
.missing-toast {
  position: fixed;
  left: 50%;
  bottom: calc(80px + env(safe-area-inset-bottom, 0px));
  transform: translate(-50%, 20px);
  background: #111827;
  color: #fff;
  font-size: .88rem;
  font-weight: 600;
  padding: 12px 18px;
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(0,0,0,.25);
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s var(--ease, ease-out), transform .3s var(--spring, cubic-bezier(.34,1.56,.64,1));
  z-index: 900;
  max-width: calc(100% - 32px);
  text-align: center;
  line-height: 1.35;
}
.missing-toast.open {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Draft-restored banner — shown by audit-firebase.js when a crash-recovery
   snapshot is loaded back into the form, so the pre-filled answers aren't a
   mystery. Sits at the top of the audit body, dismissible. */
.restore-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 4px;
  padding: 12px 16px;
  background: rgba(40,112,160,.08);
  border: 1px solid rgba(40,112,160,.3);
  border-left: 4px solid var(--accent);
  border-radius: 12px;
  color: var(--text);
  font-size: .85rem;
  line-height: 1.4;
}
.restore-banner-text { flex: 1; min-width: 0; }
.restore-banner-text strong { color: var(--accent); }
.restore-banner-dismiss {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,.05);
  color: var(--text-secondary);
  font-size: .8rem;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
}
.restore-banner-dismiss:hover { background: rgba(0,0,0,.1); color: var(--text); }

/* ── Open Issues board (campus-health issue lifecycle) ─────── */
.open-summary {
  font-size: .9rem;
  color: var(--text-secondary);
  margin-bottom: 12px;
}
.open-summary strong { color: var(--text); font-size: 1.05rem; }
.open-filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
}
.open-issue-warning {
  background: rgba(245,158,11,.12);
  border: 1px solid rgba(245,158,11,.4);
  color: var(--amber-text);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: .82rem;
  font-weight: 600;
  margin-bottom: 12px;
}
.open-issue-list { display: flex; flex-direction: column; gap: 10px; }
.open-issue {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius-sm);
  box-shadow: var(--glass-shadow);
  padding: 12px 14px;
}
.open-issue.is-resolved {
  border-left-color: var(--green);
  opacity: .78;
}
.open-issue-top {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.issue-dept-tag {
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #fff;
  background: var(--gray);
  border-radius: var(--radius-pill);
  padding: 3px 9px;
}
/* Same department palette as the audit form's routing buttons. */
.dept-facilities   { background: rgba(37,99,235,.9); }
.dept-creative     { background: rgba(147,51,234,.9); }
.dept-guestservices{ background: rgba(234,88,12,.9); }
.dept-zooops       { background: rgba(22,163,74,.9); }
.dept-it           { background: rgba(14,165,233,.9); }
.open-issue-zone { font-weight: 700; font-size: .9rem; }
.open-issue-date { font-size: .78rem; color: var(--text-secondary); margin-left: auto; }
.open-issue-dupes {
  font-size: .7rem;
  font-weight: 700;
  color: var(--amber-text);
  background: rgba(245,158,11,.14);
  border-radius: var(--radius-pill);
  padding: 2px 7px;
}
.open-issue-q { font-size: .88rem; font-weight: 600; margin-bottom: 4px; }
.open-issue-notes {
  font-size: .84rem;
  color: var(--text-secondary);
  background: rgba(0,0,0,.03);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  margin-bottom: 6px;
  white-space: pre-wrap;
}
.open-issue-meta { font-size: .74rem; color: var(--text-secondary); }
.open-issue-resolved-line {
  margin-top: 6px;
  font-size: .8rem;
  font-weight: 700;
  color: var(--green-text);
}
.open-issue-resolved-note {
  font-size: .8rem;
  color: var(--text-secondary);
  font-style: italic;
  margin-top: 2px;
}
.open-issue-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
}
.open-issue-btn {
  min-height: 40px;
  font-size: .82rem;
  padding: 8px 16px;
}
.open-issue-resolve-form { margin-top: 10px; }
.open-issue-label {
  display: block;
  font-size: .74rem;
  font-weight: 700;
  color: var(--text-secondary);
  margin-bottom: 4px;
}
.open-issue-input {
  width: 100%;
  font-size: .88rem;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--text);
}
@media (max-width: 640px) {
  .open-issue-date { margin-left: 0; }
  /* Comfortable tap targets on the phones this is used on. */
  .open-issue-btn { min-height: 44px; flex: 1 1 auto; }

  /* The view switcher is a non-wrapping inline-flex pill row. At five tabs it
     just fit a phone; the sixth ("Open Issues") overflowed off-screen and
     ended up unreachable — partly covered by the sticky header. Let it wrap
     instead of scrolling so every tab stays visible and tappable. */
  .range-toggle {
    display: flex;
    flex-wrap: wrap;
    row-gap: 4px;
    max-width: 100%;
    border-radius: var(--radius-sm);
  }
  .range-toggle-btn { min-height: 40px; }
  /* Keep a scrolled-to tab clear of the sticky header. */
  .dash-heading-row { scroll-margin-top: calc(var(--header-h, 108px) + 12px); }
}

/* ── Monthly champion board (dashboard) ─────────────────────── */
.champion-board {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.champion-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--glass-shadow);
  padding: 10px 14px;
  font-size: .9rem;
  color: var(--text);
}
.champion-row-first {
  background: linear-gradient(90deg, rgba(245,158,11,.14), var(--glass-strong));
  border-color: rgba(245,158,11,.4);
}
.champion-medal { font-size: 1.15rem; width: 28px; text-align: center; flex: none; }
.champion-rank {
  display: inline-block;
  width: 22px; height: 22px; line-height: 22px;
  border-radius: 50%;
  background: var(--accent-light);
  color: var(--accent-mid);
  font-size: .75rem; font-weight: 700; text-align: center;
}
.champion-name { font-weight: 700; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.champion-stats { color: var(--text-secondary); font-size: .78rem; flex: none; }
.champion-empty {
  color: var(--text-secondary);
  font-size: .85rem;
  padding: 20px;
  text-align: center;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border-radius: var(--radius-sm);
}

/* ── Offline queue pill (shared/offline-queue.js) ───────────
   Persistent "N waiting to send" indicator. Sits above the zone pages'
   fixed submit footer; on footer-less pages it just floats a little
   higher than strictly necessary, which beats overlapping anything. */
.queue-pill {
  position: fixed;
  left: 16px;
  bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  z-index: 940; /* under .toast-stack (950) so toasts stay readable */
  border: 0;
  border-radius: 999px;
  padding: 10px 16px;
  background: #b45309;
  color: #fff;
  font-size: .8rem;
  font-weight: 700;
  line-height: 1.3;
  box-shadow: 0 8px 24px rgba(0,0,0,.28);
  cursor: pointer;
  max-width: calc(100vw - 32px);
  text-align: left;
}
.queue-pill:disabled { opacity: .7; cursor: default; }
.queue-pill:hover:not(:disabled) { background: #92400e; }

/* ── App toasts (shared/toast.js) ───────────────────────────── */
.toast-stack {
  position: fixed;
  top: calc(14px + env(safe-area-inset-top, 0px));
  right: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 950;
  max-width: min(360px, calc(100vw - 32px));
  pointer-events: none;
}
.app-toast {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 11px 16px;
  border-radius: 14px;
  background: #111827;
  color: #fff;
  font-size: .84rem;
  font-weight: 600;
  line-height: 1.4;
  box-shadow: 0 10px 30px rgba(0,0,0,.25);
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity .25s var(--ease, ease-out), transform .3s var(--spring, ease-out);
  pointer-events: auto;
}
.app-toast.open { opacity: 1; transform: translateY(0); }
.app-toast-success { background: #0c5132; }
.app-toast-error   { background: #7f1d1d; }
.app-toast-warning { background: #78350f; }

.question-num {
  min-width: 28px;
  height: 28px;
  background: rgba(0,0,0,.04);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .7rem;
  font-weight: 700;
  color: var(--text-secondary);
  flex-shrink: 0;
  margin-top: 1px;
  transition: all .35s var(--ease);
}
.answered-yes .question-num { background: rgba(40,112,160,.15); color: var(--accent); }
.answered-no  .question-num { background: rgba(239,68,68,.12); color: var(--red); }

.question-content { flex: 1; min-width: 0; }

.question-text {
  font-size: .87rem;
  line-height: 1.5;
  color: var(--text);
  margin-bottom: 8px;
  letter-spacing: -.01em;
}

/* ── Response Buttons ───────────────────────────────────────── */
.response-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.resp-btn {
  padding: 5px 18px;
  border-radius: var(--radius-pill);
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  border: 1.5px solid;
  background: transparent;
  /* Snappy color transition — slow fades made the button look "ghosted"
     on iOS during the press → release window. Transform is excluded so the
     press feels instantaneous (no mid-state shrink/grow). */
  transition: background-color .12s ease, color .12s ease,
              border-color .12s ease, box-shadow .15s ease;
  font-family: inherit;
  line-height: 1.5;
  letter-spacing: -.01em;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
}

.btn-yes { border-color: rgba(40,112,160,.65); color: var(--accent); }
.btn-yes:hover { background: rgba(40,112,160,.08); border-color: var(--accent); }
/* Pressed state (mid-tap) — preview the selected look so there's no
   "transparent ghost" frame between touch and the .active class landing. */
.btn-yes:active {
  background: rgba(40,112,160,.18);
  border-color: var(--accent);
  color: var(--accent);
}
/* SOLID FILL, and a glyph. This was previously an outline-only treatment
   (colored border + bold colored text + inset ring). It looked cleaner,
   but answered and unanswered then differed only by border weight and a
   4%-alpha row tint, and the whole signal was carried by hue — which is
   the one channel that fails for red/green colorblind auditors and the
   first to wash out under gallery glare. Filled vs unfilled is a
   luminance difference: it survives both. The ::before glyph is the
   redundant non-color cue. */
.btn-yes.active,
.btn-no.active,
.btn-rating.active { color: #fff; font-weight: 700; }
.btn-yes.active::before,
.btn-no.active::before {
  margin-right: 5px;
  font-weight: 700;
}
.btn-yes.active::before { content: '\2713'; }  /* ✓ */
.btn-no.active::before  { content: '\2715'; }  /* ✕ */

.btn-yes.active {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 12px rgba(40,112,160,.28);
}

.btn-no { border-color: rgba(239,68,68,.55); color: var(--red); }
.btn-no:hover { background: rgba(239,68,68,.06); border-color: var(--red); }
.btn-no:active {
  background: rgba(239,68,68,.15);
  border-color: var(--red);
  color: var(--red);
}
.btn-no.active {
  background: var(--red);
  border-color: var(--red);
  box-shadow: 0 0 12px rgba(239,68,68,.28);
}

/* N/A — "this question does not apply today". Deliberately the quietest of
   the three: a neutral outline that fills to slate, never blue or red, so a
   row of N/As reads as "skipped for a reason" rather than as good or bad
   news. Same filled-vs-unfilled luminance cue as Yes/No (see above). */
.btn-na {
  border-color: rgba(0,0,0,.22);
  color: var(--text-secondary);
  font-size: .74rem;
  padding-left: 12px;
  padding-right: 12px;
}
.btn-na:hover { background: rgba(0,0,0,.05); border-color: rgba(0,0,0,.35); }
.btn-na:active { background: rgba(0,0,0,.1); color: var(--text); }
.btn-na.active {
  background: #6b7280;
  border-color: #6b7280;
  color: #fff;
  font-weight: 700;
}
.btn-na.active::before { content: '\2013'; margin-right: 5px; font-weight: 700; } /* – */

/* Icon-only. As a "+ note" pill (~80px) it no longer fit beside Yes / No /
   N/A on a 375px phone, so the response row wrapped and every question
   cost a second line — 43 questions of it. A 34px round glyph fits. */
.note-toggle {
  margin-left: auto;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .95rem;
  line-height: 1;
  color: var(--text-secondary);
  cursor: pointer;
  background: rgba(0,0,0,.03);
  border: 1px solid rgba(0,0,0,.08);
  border-radius: 50%;
  padding: 0;
  font-family: inherit;
  transition: background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.note-toggle:hover { background: rgba(0,0,0,.06); color: var(--text); }
.note-toggle.has-note { color: var(--amber-text); background: rgba(245,158,11,.12); border-color: rgba(245,158,11,.3); }
.note-toggle:active { transform: scale(.92); }
.note-toggle.hidden { display: none; }

/* ── Notes ──────────────────────────────────────────────────── */
.notes-wrap {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height .35s var(--ease), margin-top .35s var(--ease), opacity .25s var(--ease);
}
.notes-wrap.open {
  max-height: 200px;
  margin-top: 8px;
  opacity: 1;
}
/* Applied for one frame when the note is opened by tap: the textarea must be
   fully visible the instant focus() runs, or mobile Safari won't raise the
   keyboard. Closing still animates. */
.notes-wrap.no-anim { transition: none; }

.notes-input {
  width: 100%;
  min-height: 52px;
  padding: 10px 14px;
  border: 1px solid rgba(0,0,0,.08);
  border-radius: var(--radius-sm);
  font-size: .84rem;
  font-family: inherit;
  color: var(--text);
  resize: vertical;
  background: rgba(0,0,0,.02);
  transition: all .3s var(--ease);
}
.notes-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.12);
  background: #fff;
}

/* ── Chips ──────────────────────────────────────────────────── */
.chip {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: .72rem;
  font-weight: 600;
}
.chip-yes   { background: rgba(40,112,160,.1); color: var(--accent); }
.chip-no    { background: rgba(239,68,68,.08); color: var(--red); }
.chip-na    { background: rgba(0,0,0,.06); color: var(--text-secondary); font-style: italic; }
.chip-blank { background: rgba(0,0,0,.04); color: var(--text-secondary); }
.chip-na[hidden] { display: none; }

/* ── Summary Footer ─────────────────────────────────────────── */
.summary-footer {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  background: rgba(255,255,255,.75);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border-top: 1px solid rgba(0,0,0,.06);
  box-shadow: 0 -4px 24px rgba(0,0,0,.04);
  z-index: 200;
}

.summary-inner {
  max-width: 960px;
  margin: 0 auto;
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.summary-label {
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-secondary);
  white-space: nowrap;
  font-weight: 600;
}

.summary-chips {
  display: flex;
  gap: 6px;
  flex: 1;
  flex-wrap: wrap;
}

.summary-chips .chip {
  font-size: .78rem;
  padding: 4px 12px;
}

.action-row { display: flex; align-items: center; gap: 8px; }

/* Print and Clear stay one tap away on phones without permanently taking a
   third footer row. Native <details>/<summary> supplies keyboard activation,
   focus behavior and an announced expanded/collapsed state without custom
   menu JavaScript. Desktop keeps the original visible utility buttons. */
.footer-more { display: none; position: relative; }
.footer-more > summary { list-style: none; }
.footer-more > summary::-webkit-details-marker { display: none; }
.footer-more-menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + 10px);
  min-width: 168px;
  padding: 8px;
  display: grid;
  gap: 6px;
  border: 1px solid rgba(0,0,0,.1);
  border-radius: var(--radius-sm);
  background: rgba(255,255,255,.98);
  box-shadow: 0 12px 36px rgba(0,0,0,.2);
}
.footer-more-menu .btn { width: 100%; justify-content: flex-start; }

.btn {
  padding: 8px 18px;
  border-radius: var(--radius-pill);
  font-size: .82rem;
  font-weight: 600;
  cursor: pointer;
  border: none;
  transition: all .25s var(--spring);
  font-family: inherit;
  white-space: nowrap;
  letter-spacing: -.01em;
}
.btn:active { transform: scale(.95); }

.btn-export {
  background: var(--accent-dark);
  color: #fff;
  box-shadow: 0 2px 8px rgba(36,50,75,.2);
}
.btn-export:hover { background: var(--accent-mid); box-shadow: 0 4px 12px rgba(36,50,75,.25); }

/* Submit-ready: every visible question is answered. The button goes from
   the dark navy "there's more to do" to the bright accent with a halo, and
   pops once so the change is noticed without looking at the progress bar.
   audit-engine.js updateSubmitReady() toggles this and swaps the label. */
.btn-export.is-ready {
  background: var(--accent);
  box-shadow: 0 0 0 4px rgba(40,112,160,.18), 0 4px 14px rgba(40,112,160,.35);
  animation: submit-ready-pop .45s cubic-bezier(.2,.9,.3,1.3) 1;
}
.btn-export.is-ready:hover { background: var(--accent-dark); }
@keyframes submit-ready-pop {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .btn-export.is-ready { animation: none; }
}

.btn-print {
  background: rgba(0,0,0,.04);
  color: var(--text);
  border: 1px solid rgba(0,0,0,.08);
}
.btn-print:hover { background: rgba(0,0,0,.07); }

/* Jump to the next unanswered question. Finishing a 43-question zone used
   to mean scrolling the whole form hunting for the row you skipped; the
   only help was a toast at submit time, after you thought you were done.
   Hidden (via [hidden]) the moment nothing is left. */
.btn-next-open {
  background: rgba(245,158,11,.14);
  color: var(--amber-text);
  border: 1px solid rgba(245,158,11,.35);
  font-variant-numeric: tabular-nums;
}
.btn-next-open:hover { background: rgba(245,158,11,.22); }
.btn-next-open[hidden] { display: none; }

/* DESTRUCTIVE ONLY. .btn-clear used to be the de-facto "secondary
   button": Admin, ← Dashboard, Campus Health, Report a Bug, Refresh and
   Cancel all wore it, so three or four red pills sat in a row in the
   header with no hierarchy and nothing there was actually destructive.
   Red now means red — Clear an audit, Clear an issue draft, Log Out.
   Everything else uses .btn-quiet below. */
.btn-clear {
  background: rgba(239,68,68,.08);
  color: var(--red);
  border: 1px solid rgba(239,68,68,.12);
}
.btn-clear:hover { background: rgba(239,68,68,.14); }

/* Neutral secondary. Sits on the dark site header and on light page
   surfaces, so it is built from translucent neutrals rather than a fixed
   color pair, and inherits the surrounding text color. */
.btn-quiet {
  background: rgba(255,255,255,.1);
  color: inherit;
  border: 1px solid rgba(255,255,255,.16);
}
.btn-quiet:hover { background: rgba(255,255,255,.18); }
/* Outside the dark header the same neutral has to darken instead. */
main .btn-quiet,
.dash-main .btn-quiet {
  background: rgba(0,0,0,.045);
  color: var(--text);
  border-color: rgba(0,0,0,.09);
}
main .btn-quiet:hover,
.dash-main .btn-quiet:hover { background: rgba(0,0,0,.08); }

.site-header .btn-quiet { color: rgba(255,255,255,.92); }

/* Primary action button — used by the dashboard modals, the admin panel,
   and the onboarding card. (Was referenced everywhere but never defined,
   so these buttons rendered with no background.) */
.btn-primary {
  background: var(--accent-dark);
  color: #fff;
  box-shadow: 0 2px 8px rgba(36,50,75,.2);
}
.btn-primary:hover { background: var(--accent-mid); box-shadow: 0 4px 12px rgba(36,50,75,.25); }
.btn-primary:disabled { opacity: .55; cursor: not-allowed; }

/* ── Issue Panel (No answers) ──────────────────────────────── */
.issue-panel {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height .4s var(--ease), margin-top .4s var(--ease), opacity .3s var(--ease);
}
.issue-panel.open {
  max-height: 600px;
  margin-top: 12px;
  opacity: 1;
}

.issue-type-label {
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 8px;
  letter-spacing: -.01em;
}

.issue-type-row {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
/* Five-up grid with a glyph per department. As a wrapping row of pills
   the five chips broke into two uneven lines with "IT" orphaned; a grid
   gives every department the same tile and the icon carries the meaning
   before the colour does. */
.issue-type-row.issue-type-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
}
.issue-type-row.issue-type-grid .issue-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 9px 4px 7px;
  border-radius: var(--radius-sm);
  min-height: 62px;
  font-size: .68rem;
  line-height: 1.1;
  text-align: center;
  overflow-wrap: normal;
  word-break: keep-all;
}
/* A 375px phone cannot fit five labelled tiles without breaking words;
   let them flow 3 + 2 at equal widths instead. */
@media (max-width: 480px) {
  .issue-type-row.issue-type-grid { grid-template-columns: repeat(auto-fit, minmax(78px, 1fr)); }
}
.issue-btn-icon { display: block; color: var(--dept-color, var(--text-secondary)); transition: color .2s var(--ease); }
.issue-btn.active .issue-btn-icon { color: #fff; }
.issue-btn-facilities { --dept-color: #2563eb; }
.issue-btn-creative   { --dept-color: #9333ea; }
.issue-btn-guest      { --dept-color: #ea580c; }
.issue-btn-zooops     { --dept-color: #16a34a; }
.issue-btn-it         { --dept-color: #0ea5e9; }
.issue-type-row.issue-type-grid .issue-btn:not(.active) { border-color: color-mix(in srgb, var(--dept-color) 35%, transparent); }
@supports not (color: color-mix(in srgb, red, blue)) {
  .issue-type-row.issue-type-grid .issue-btn:not(.active) { border-color: rgba(0,0,0,.1); }
}

.issue-btn {
  padding: 6px 16px;
  border-radius: var(--radius-pill);
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  border: 1.5px solid rgba(0,0,0,.08);
  background: rgba(0,0,0,.02);
  transition: all .25s var(--spring);
  font-family: inherit;
  color: var(--text);
  letter-spacing: -.01em;
}
.issue-btn:hover { background: rgba(0,0,0,.05); }
.issue-btn:active { transform: scale(.93); }

.issue-btn-facilities.active {
  background: rgba(37,99,235,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 20px rgba(37,99,235,.25);
}
.issue-btn-creative.active {
  background: rgba(147,51,234,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 20px rgba(147,51,234,.2);
}
.issue-btn-guest.active {
  background: rgba(234,88,12,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 20px rgba(234,88,12,.2);
}
.issue-btn-zooops.active {
  background: rgba(22,163,74,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 20px rgba(22,163,74,.2);
}
.issue-btn-it.active {
  background: rgba(14,165,233,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 20px rgba(14,165,233,.2);
}

.issue-notes {
  width: 100%;
  min-height: 52px;
  padding: 10px 14px;
  border: 1px solid rgba(0,0,0,.08);
  border-radius: var(--radius-sm);
  font-size: .84rem;
  font-family: inherit;
  color: var(--text);
  resize: vertical;
  background: rgba(0,0,0,.02);
  margin-bottom: 12px;
  transition: all .3s var(--ease);
}
.issue-notes:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.12);
  background: #fff;
}

.photo-upload-area { margin-bottom: 12px; }
.photo-input { display: none; }

.photo-requirement {
  margin: 7px 0 0;
  color: var(--text-secondary);
  font-size: .76rem;
  line-height: 1.35;
}
.photo-required-missing .photo-upload-btn {
  color: var(--red);
  border-color: var(--red);
  background: rgba(231,76,60,.07);
  box-shadow: 0 0 0 3px rgba(231,76,60,.1);
}
.photo-required-missing .photo-requirement {
  color: var(--red);
  font-weight: 650;
}

.photo-upload-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  border: 1.5px dashed rgba(0,0,0,.12);
  background: rgba(0,0,0,.02);
  color: var(--text-secondary);
  transition: all .25s var(--ease);
}
.photo-upload-btn:hover {
  background: rgba(0,0,0,.05);
  border-color: var(--accent);
  color: var(--text);
}
.photo-upload-btn:active { transform: scale(.97); }

.photo-preview-wrap {
  position: relative;
  display: inline-block;
  margin-top: 10px;
}

.photo-preview {
  max-width: 200px;
  max-height: 150px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(0,0,0,.06);
  display: block;
  box-shadow: 0 4px 16px rgba(0,0,0,.08);
}

.photo-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  border: 2px solid #fff;
  font-size: .7rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  transition: transform .2s var(--spring);
  box-shadow: 0 2px 8px rgba(239,68,68,.3);
}
.photo-remove:active { transform: scale(.9); }

/* ── Reference example image (per-question "what it looks like") ──────
   A small thumbnail under the prompt for items that are hard to identify.
   Tapping opens .ref-lightbox (built in audit-engine.js). */
.ref-example {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  margin: 0 0 12px;
  padding: 5px 14px 5px 5px;
  background: rgba(40,112,160,.05);
  border: 1px solid rgba(40,112,160,.16);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font: inherit;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .15s var(--spring);
}
.ref-example:hover { background: rgba(40,112,160,.1); border-color: rgba(40,112,160,.32); }
.ref-example:active { transform: scale(.98); }
.ref-example:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.ref-example-thumb {
  width: 58px;
  height: 58px;
  flex: none;
  object-fit: cover;
  border-radius: calc(var(--radius-sm) - 4px);
  display: block;
  background: rgba(0,0,0,.05);
  box-shadow: 0 2px 8px rgba(0,0,0,.1);
}
.ref-example-cap {
  display: flex;
  flex-direction: column;
  font-size: .8rem;
  font-weight: 700;
  color: var(--accent);
  line-height: 1.25;
}
.ref-example-sub {
  font-size: .68rem;
  font-weight: 500;
  color: var(--text-secondary);
  letter-spacing: .01em;
}

/* Full-screen viewer */
.ref-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(28px, env(safe-area-inset-top, 0px)) 24px max(28px, env(safe-area-inset-bottom, 0px));
  background: rgba(10,14,22,.82);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity .2s var(--ease);
}
.ref-lightbox.open { opacity: 1; }
.ref-lightbox-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  max-width: 100%;
  max-height: 100%;
}
.ref-lightbox-img {
  max-width: 100%;
  max-height: calc(100vh - 150px);
  border-radius: var(--radius-sm);
  box-shadow: 0 24px 70px rgba(0,0,0,.55);
  object-fit: contain;
}
.ref-lightbox-cap {
  color: #fff;
  font-size: .9rem;
  font-weight: 600;
  text-align: center;
  max-width: 640px;
  line-height: 1.4;
  text-shadow: 0 1px 4px rgba(0,0,0,.5);
}
.ref-lightbox-close {
  position: absolute;
  top: -16px;
  right: -16px;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: #fff;
  color: #111;
  border: none;
  font-size: 1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  box-shadow: 0 4px 18px rgba(0,0,0,.4);
  transition: transform .15s var(--spring);
}
.ref-lightbox-close:active { transform: scale(.9); }

.btn-send-email {
  background: rgba(37,99,235,.9);
  color: #fff;
  border-radius: var(--radius-pill);
  box-shadow: 0 4px 16px rgba(37,99,235,.2);
}
.btn-send-email:hover {
  background: rgba(37,99,235,1);
  box-shadow: 0 6px 20px rgba(37,99,235,.3);
}

/* ── Rating Buttons (1-5 scale) ─────────────────────────────── */
.rating-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  font-size: .72rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 4px;
}
.rating-anchors { font-weight: 500; }

.btn-rating {
  min-width: 38px;
  text-align: center;
  border-color: rgba(0,0,0,.12);
  color: var(--text-secondary);
}
.btn-rating:hover { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.2); }
.btn-rating.active.rating-low {
  background: var(--red);
  color: #fff;
  border-color: var(--red);
  box-shadow: 0 0 16px rgba(239,68,68,.25);
}
.btn-rating.active.rating-mid {
  background: #f59e0b;
  color: #fff;
  border-color: #f59e0b;
  box-shadow: 0 0 16px rgba(245,158,11,.25);
}
.btn-rating.active.rating-high {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  box-shadow: 0 0 16px rgba(40,112,160,.3);
}

/* ── Auth Pages (Login / Signup) ────────────────────────────── */
.auth-body {
  background: linear-gradient(160deg, #162236 0%, #1f3550 40%, #1a3a5c 100%);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

/* WebGL caustics behind the login card (shared/caustics.js). The canvas is
   inserted as body's first child and pinned behind everything; the
   .auth-body gradient stays as the backdrop for every case where the
   canvas is never created — no WebGL, reduced motion, Save-Data. The card's
   own backdrop-filter blurs whatever is back here, which is why the effect
   can stay this subtle and still read. */
.auth-caustics {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  display: block;
  pointer-events: none;
}

.auth-container {
  width: 100%;
  max-width: 400px;
  /* Above the canvas. Without this the card is composited underneath it. */
  position: relative;
  z-index: 1;
}

.auth-card {
  background: rgba(255,255,255,.1);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  backdrop-filter: blur(24px) saturate(150%);
  border: 1px solid rgba(255,255,255,.15);
  border-radius: var(--radius);
  padding: 36px 30px;
  box-shadow: 0 16px 48px rgba(0,0,0,.25), inset 0 1px 0 rgba(255,255,255,.12);
  text-align: center;
}

.auth-logo {
  display: block;
  width: min(260px, 78%);
  height: auto;
  margin: 0 auto 18px;
}

.auth-title {
  font-size: 1.4rem;
  font-weight: 700;
  color: #fff;
  letter-spacing: -.02em;
  background: linear-gradient(135deg, #7098c0, #2870a0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  margin-bottom: 4px;
}

.auth-subtitle {
  font-size: .82rem;
  color: rgba(255,255,255,.45);
  margin-bottom: 28px;
  font-weight: 500;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.auth-input {
  width: 100%;
  padding: 12px 16px;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 12px;
  color: #fff;
  font-size: .9rem;
  font-family: inherit;
  transition: all .3s var(--ease);
}
.auth-input::placeholder { color: rgba(255,255,255,.5); }
.auth-input:focus {
  outline: none;
  background: rgba(255,255,255,.14);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.2);
}

.auth-btn {
  width: 100%;
  padding: 13px;
  border-radius: var(--radius-pill);
  background: rgba(40,112,160,.85);
  color: #fff;
  font-size: .95rem;
  font-weight: 600;
  font-family: inherit;
  border: 1px solid rgba(255,255,255,.15);
  cursor: pointer;
  transition: all .25s var(--spring);
  box-shadow: 0 4px 20px rgba(40,112,160,.25);
  margin-top: 4px;
}
.auth-btn:hover { box-shadow: 0 6px 28px rgba(40,112,160,.35); }
.auth-btn:active { transform: scale(.97); }
.auth-btn:disabled { opacity: .6; cursor: not-allowed; }

.auth-toggle {
  font-size: .8rem;
  color: rgba(255,255,255,.5);
  margin-top: 8px;
}
.auth-toggle a { color: var(--accent); text-decoration: none; font-weight: 600; }
.auth-toggle a:hover { text-decoration: underline; }

.auth-forgot {
  font-size: .8rem;
  margin-top: 4px;
  text-align: center;
}
.auth-forgot a { color: rgba(255,255,255,.65); text-decoration: none; }
.auth-forgot a:hover { color: #2870a0; text-decoration: underline; }
.auth-legal { margin-top: 18px; }

.auth-hint {
  font-size: .75rem;
  color: rgba(255,255,255,.45);
  text-align: left;
  margin: -4px 0 0 4px;
}

/* Password field with an inline Show/Hide toggle */
.auth-pass-wrap { position: relative; }
.auth-pass-wrap .auth-input { padding-right: 64px; }
.pass-toggle {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  padding: 4px 10px;
  border: 0;
  border-radius: 8px;
  background: rgba(255,255,255,.1);
  color: rgba(255,255,255,.65);
  font-size: .72rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}
.pass-toggle:hover { background: rgba(255,255,255,.18); color: #fff; }

.auth-error {
  color: #fca5a5;
  font-size: .8rem;
  margin-top: 12px;
  min-height: 20px;
}
.auth-error.success {
  color: #86efac;
}

/* ── Bug Report Modal ─────────────────────────────────────── */
.bug-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: rgba(15, 25, 40, .55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.bug-modal-card {
  background: #fff;
  border-radius: var(--radius);
  padding: 28px;
  max-width: 520px;
  width: 100%;
  box-shadow: 0 20px 60px rgba(0,0,0,.25);
}
.bug-modal-title {
  font-size: 1.2rem;
  font-weight: 700;
  margin: 0 0 6px;
  color: var(--text);
  letter-spacing: -.01em;
}
.bug-modal-sub {
  font-size: .88rem;
  color: var(--text-secondary);
  margin: 0 0 16px;
}
.bug-modal-textarea {
  width: 100%;
  min-height: 140px;
  padding: 12px 14px;
  border: 1px solid rgba(0,0,0,.1);
  border-radius: var(--radius-sm);
  font-size: .9rem;
  font-family: inherit;
  color: var(--text);
  resize: vertical;
  background: rgba(0,0,0,.02);
  transition: border-color .2s var(--ease);
}
.bug-modal-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.15);
}
.bug-modal-msg {
  font-size: .82rem;
  margin-top: 10px;
  min-height: 18px;
}
.bug-modal-msg.error { color: #dc2626; }
.bug-modal-msg.success { color: #16a34a; }
.bug-modal-msg.warning { color: #b45309; }
.bug-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 18px;
}

/* ── Dashboard ─────────────────────────────────────────────── */
.dash-user {
  display: flex;
  align-items: center;
  gap: 12px;
}
.dash-user span {
  font-size: .85rem;
  color: rgba(255,255,255,.7);
  font-weight: 500;
}

.dash-main {
  max-width: 960px;
  margin: 0 auto;
  padding: 24px 20px 40px;
}

.system-warning {
  width: 100%;
  margin: 0 0 18px;
  padding: 12px 14px;
  border: 1px solid rgba(245,158,11,.35);
  border-left: 4px solid var(--amber);
  border-radius: 12px;
  background: rgba(255,251,235,.94);
  color: #7c2d12;
  font-size: .85rem;
  font-weight: 650;
  line-height: 1.35;
}
.system-warning[hidden] { display: none; }

.dash-section { margin-bottom: 32px; }

.dash-heading {
  font-size: .85rem;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: 14px;
}

.audit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
}

/* GRID, not a flex row. The card used to be `display:flex;
   justify-content:space-between` with the "This week" pill absolutely
   positioned in the top-right corner — where it overlapped the arrow by
   16px on a phone. A two-column grid gives the badge its own row, so the
   pill and the arrow cannot collide no matter how long a zone title is,
   and leaves a place for the status line to live. */
.audit-card {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    'badge  badge'
    'title  arrow'
    'status status';
  align-items: center;
  gap: 2px 10px;
  padding: 14px 18px 13px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  text-decoration: none;
  color: var(--text);
  transition: all .25s var(--spring);
  position: relative;
  overflow: hidden;
}
.audit-card::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(255,255,255,.2) 0%, transparent 60%);
  pointer-events: none;
}
.audit-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 36px rgba(0,0,0,.1);
}
.audit-card:active { transform: scale(.97); }

.audit-card-title {
  grid-area: title;
  font-size: .88rem;
  font-weight: 600;
  letter-spacing: -.01em;
}

.audit-card-arrow {
  grid-area: arrow;
  font-size: 1.1rem;
  color: var(--accent);
  font-weight: 700;
}

/* When was this zone last audited, and by whom. The cards carried no
   state at all before — fourteen identical rows — while the data was
   already being served to campus-health. Empty until zone-completions
   answers, so a slow or failed read just leaves the card as it was. */
.audit-card-status {
  grid-area: status;
  font-size: .7rem;
  line-height: 1.35;
  color: var(--text-secondary);
  min-height: 1em;
}
.audit-card-status:empty { display: none; }
.zone-status-done { color: var(--accent); font-weight: 650; }
.zone-status-never { color: var(--amber-text); font-weight: 600; }

/* ── Assigned-this-week pulse ──────────────────────────────────
   Cards for the zones this user owns this week (per the Monday email)
   pulse blue until that audit is submitted. The base rule already carries
   a visible blue ring, so the marker stays legible even when the pulse
   animation is suppressed by prefers-reduced-motion. */
.audit-card-assigned {
  border-color: rgba(47,128,237,.7);
  box-shadow: 0 0 0 1px rgba(47,128,237,.25), var(--glass-shadow);
  animation: assignedPulse 1.8s ease-in-out infinite;
}
@keyframes assignedPulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(47,128,237,.25), 0 0 6px rgba(47,128,237,.15), var(--glass-shadow); }
  50%      { box-shadow: 0 0 0 2px rgba(47,128,237,.5), 0 0 20px rgba(47,128,237,.45), var(--glass-shadow); }
}

/* The "This week" pill is hidden by default and only shown on assigned,
   not-yet-completed cards. It occupies its own grid row rather than
   floating over the corner, so it can never sit on top of the arrow. */
.audit-card-badge { display: none; }
.audit-card-assigned .audit-card-badge {
  grid-area: badge;
  display: inline-block;
  justify-self: start;
  margin-bottom: 4px;
  font-size: .56rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: #2f80ed;
  background: rgba(47,128,237,.12);
  border: 1px solid rgba(47,128,237,.35);
  padding: 2px 7px;
  border-radius: 999px;
  pointer-events: none;
}

/* ── First-visit onboarding card ───────────────────────────── */
.onboard-card {
  padding: 20px 22px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(47,128,237,.35);
  border-left: 4px solid #2f80ed;
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
}
.onboard-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 10px;
}
.onboard-steps {
  margin: 0 0 14px;
  padding-left: 20px;
  color: var(--text-secondary);
  font-size: .88rem;
  line-height: 1.55;
}
.onboard-steps li { margin-bottom: 6px; }
.onboard-steps strong { color: var(--text); }

/* "Your zones this week" banner above the audit grid */
.assignment-banner {
  margin: -6px 0 14px;
  padding: 10px 14px;
  border: 1px solid rgba(47,128,237,.35);
  border-radius: 12px;
  background: rgba(47,128,237,.08);
  color: var(--text);
  font-size: .85rem;
}
.assignment-banner[hidden] { display: none; }
.assignment-banner strong { color: #2f80ed; }

/* Web Push opt-in row under the assigned-zone grid (shared/push.js) */
.push-reminder-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding: 10px 14px;
  border: 1px dashed rgba(47,128,237,.35);
  border-radius: 12px;
  background: rgba(47,128,237,.05);
}
.push-reminder-row[hidden] { display: none; }
.push-reminder-text {
  flex: 1 1 220px;
  font-size: .85rem;
  color: var(--text);
  opacity: .85;
}
.push-reminder-row .btn { white-space: nowrap; }

/* Every assigned zone submitted this week — banner flips green via JS */
.assignment-banner-done {
  border-color: rgba(39, 174, 96, .45);
  background: rgba(39, 174, 96, .1);
}
.assignment-banner-done strong { color: #27ae60; }

/* History */
.history-empty {
  color: var(--text-secondary);
  font-size: .85rem;
  padding: 20px;
  text-align: center;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
}

.history-table {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--glass-shadow);
}

.history-row {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  padding: 12px 18px;
  border-bottom: 1px solid rgba(0,0,0,.04);
  font-size: .82rem;
  align-items: center;
}
.history-row:last-child { border-bottom: none; }

.history-header {
  font-weight: 700;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-secondary);
  background: rgba(0,0,0,.02);
}

.history-audit { font-weight: 600; }
.history-date { color: var(--text-secondary); }
.history-name { color: var(--text-secondary); }

/* GREEN, not brand blue. The "good" band used to render in var(--accent),
   which is the same blue as every heading, link and arrow on the page —
   so a healthy score carried no more signal than the chrome around it and
   good/ok/low never read as one scale. Green/amber/red does. */
.score-good { color: var(--green-text); font-weight: 700; }
.score-ok { color: var(--amber-text); font-weight: 700; }
.score-low { color: var(--red); font-weight: 700; }

/* Proportional meter under a health score. Banding alone collapses 89%
   and 100% into the same swatch; length distinguishes them, and gives a
   grid of cards something a manager can scan without reading numbers. */
.health-meter {
  height: 5px;
  border-radius: 3px;
  background: rgba(0,0,0,.07);
  overflow: hidden;
  margin: 8px 0 10px;
}
.health-meter-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: currentColor;
  transition: width .6s var(--ease-out);
}

/* Score trend vs the previous audit of the same zone */
.score-delta {
  display: inline-block;
  margin-left: 6px;
  font-size: .7rem;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  vertical-align: 1px;
}
.score-delta-up   { color: #087f67; background: rgba(34,211,168,.14); }
.score-delta-down { color: var(--red); background: var(--red-light); }
.score-delta-flat { color: var(--text-secondary); background: rgba(0,0,0,.05); }

@media (max-width: 640px) {
  .audit-grid { grid-template-columns: 1fr; }
  .history-row { grid-template-columns: 1fr 1fr; gap: 4px; font-size: .78rem; }
  .history-header { display: none; }
  .dash-user span { font-size: .75rem; }
}

/* ── Campus Health promo card (dashboard) ──────────────────── */
.campus-health-card {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 20px 22px;
  background: linear-gradient(135deg, rgba(40,112,160,.18) 0%, rgba(31,67,102,.12) 100%);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(40,112,160,.35);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  text-decoration: none;
  color: var(--text);
  transition: all .25s var(--spring);
}
.campus-health-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 36px rgba(40,112,160,.18);
}
.campus-health-card:active { transform: scale(.98); }
.campus-health-icon {
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent);
  color: #fff;
  border-radius: 12px;
  flex-shrink: 0;
}
.campus-health-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}
.campus-health-title {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -.01em;
}
.campus-health-sub {
  font-size: .8rem;
  color: var(--text-secondary);
}
.campus-health-arrow {
  font-size: 1.2rem;
  color: var(--accent);
  font-weight: 700;
}
.campus-health-note {
  font-size: .75rem;
  color: var(--text-secondary);
  margin-bottom: 12px;
  margin-top: -6px;
}

/* ── Top-of-dashboard card row ── */
.top-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-items: stretch;
}
.top-cards .campus-health-card { width: 100%; }

.spot-issue-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 20px 22px;
  background: linear-gradient(135deg, rgba(234,88,12,.16) 0%, rgba(220,38,38,.10) 100%);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(234,88,12,.35);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  color: var(--text);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: all .25s var(--spring);
  width: 100%;
}
.spot-issue-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 36px rgba(234,88,12,.18);
}
.spot-issue-card:active { transform: scale(.98); }
.spot-issue-icon {
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(234,88,12,.9);
  color: #fff;
  border-radius: 12px;
  flex-shrink: 0;
}
.spot-issue-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}
.spot-issue-title {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -.01em;
}
.spot-issue-sub {
  font-size: .8rem;
  color: var(--text-secondary);
}
.spot-issue-arrow {
  font-size: 1.4rem;
  font-weight: 700;
  color: rgba(234,88,12,.9);
  line-height: 1;
}

@media (max-width: 720px) {
  .top-cards { grid-template-columns: 1fr; }
}

/* ── Spot-an-Issue modal extras ────────────────────────────── */
.issue-modal-card {
  max-width: 560px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}
.issue-field-label {
  display: block;
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin: 14px 0 6px;
}
.issue-field-label:first-of-type { margin-top: 4px; }

.issue-type-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}

.issue-select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid rgba(0,0,0,.1);
  border-radius: var(--radius-sm);
  font-size: .9rem;
  font-family: inherit;
  color: var(--text);
  background: rgba(0,0,0,.02);
  transition: border-color .2s var(--ease);
}
.issue-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.15);
}

/* ── Campus Health grid ────────────────────────────────────── */
.health-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
}
.health-card {
  display: flex;
  flex-direction: column;
  padding: 16px 18px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  text-decoration: none;
  color: var(--text);
  transition: all .25s var(--spring);
  min-height: 180px;
}
.health-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 36px rgba(0,0,0,.1);
}
.health-card:active { transform: scale(.98); }
.health-card--stale {
  background: rgba(142,142,147,.08);
  border-style: dashed;
}
.health-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.health-card-title {
  font-size: .92rem;
  font-weight: 700;
  letter-spacing: -.01em;
}
.health-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
/* Matches .score-good — green rather than the brand blue, so the dot and
   the number agree and the four states read as one scale. */
.health-dot--good { background: var(--green); box-shadow: 0 0 0 4px rgba(22,163,74,.15); }
.health-dot--ok { background: var(--amber); box-shadow: 0 0 0 4px rgba(245,158,11,.15); }
.health-dot--low { background: var(--red); box-shadow: 0 0 0 4px rgba(239,68,68,.15); }
.health-dot--stale { background: var(--gray); box-shadow: 0 0 0 4px rgba(142,142,147,.15); }

.health-card-body { flex: 1; }
.health-score-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 10px;
}
.health-score {
  font-size: 1.8rem;
  font-weight: 800;
  letter-spacing: -.02em;
}
.health-score-raw {
  font-size: .78rem;
  color: var(--text-secondary);
}
.health-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.health-meta-row {
  display: flex;
  justify-content: space-between;
  font-size: .78rem;
}
.health-meta-label {
  color: var(--text-secondary);
  font-weight: 500;
}
.health-empty-msg {
  font-size: .85rem;
  color: var(--text-secondary);
  padding: 18px 0;
  text-align: center;
}
.health-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid rgba(0,0,0,.05);
  font-size: .75rem;
}
.health-count {
  color: var(--text-secondary);
  font-weight: 500;
}
.health-avg {
  color: var(--accent);
  font-weight: 700;
}
.health-start {
  color: var(--accent);
  font-weight: 600;
}

@media (max-width: 640px) {
  .health-grid { grid-template-columns: 1fr; }
}

/* ── Range toggle (7d / 30d) ───────────────────────────────── */
.dash-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.dash-heading-row .dash-heading { margin: 0; }
.dash-heading-actions {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  /* Let the scrollable view strip inside shrink to the phone width
     instead of forcing this flex item out to its max-content width. */
  min-width: 0;
  max-width: 100%;
}
/* "Display on TV" — a round icon-only button in the site header's
   .dash-user group (campus-health only). It composes .btn-quiet for the
   header look; this just squares it up and centres the glyph. */
.btn-tv {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 50%;
  text-decoration: none;
  flex-shrink: 0;
}
.btn-tv svg { display: block; width: 18px; height: 18px; }
/* Phones give every .btn a 44px min-height (touch targets); grow the width
   to match so the icon button stays a circle, not an oval. */
@media (max-width: 640px) {
  .btn-tv { width: 44px; height: 44px; }
}
.range-toggle {
  display: inline-flex;
  padding: 3px;
  background: rgba(0,0,0,.06);
  border-radius: 999px;
  border: 1px solid var(--glass-border);
}
.range-toggle-btn {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 6px 14px;
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-secondary);
  border-radius: 999px;
  cursor: pointer;
  transition: background .2s var(--spring), color .2s var(--spring), transform .15s var(--spring);
}
.range-toggle-btn:hover { color: var(--text); }
.range-toggle-btn:active { transform: scale(.96); }
.range-toggle-btn.is-active {
  background: var(--glass-strong);
  color: var(--text);
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
}

/* Campus-health view strip (This Week … Open Issues). Six tabs never fit a
   phone, and letting them shrink wrapped labels into two uneven rows. Below
   721px the strip becomes ONE row that scrolls sideways with no visible
   scrollbar; the wrapper paints a right-edge fade (hidden by app.js once
   scrolled to the end) so the overflow is discoverable. The "Needs
   Attention / By Zone" sort toggle is a plain .range-toggle and is untouched. */
.range-toggle-scroll {
  position: relative;
  min-width: 0;
  max-width: 100%;
}
.range-toggle--views { max-width: 100%; }
.range-toggle--views .range-toggle-btn {
  flex: 0 0 auto;
  white-space: nowrap;
}
@media (max-width: 720px) {
  .range-toggle--views {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: 3px;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .range-toggle--views::-webkit-scrollbar { display: none; }
  .range-toggle--views .range-toggle-btn { scroll-snap-align: start; }
  .range-toggle-scroll::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 40px;
    border-radius: 0 999px 999px 0;
    background: linear-gradient(to right, rgba(228,238,246,0), rgba(228,238,246,.94));
    pointer-events: none;
    transition: opacity .2s var(--ease);
  }
  .range-toggle-scroll.is-at-end::after { opacity: 0; }
}


/* ── Aquarium Overall Health ───────────────────────────────── */
.campus-total-card {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) 2fr;
  gap: 24px;
  align-items: center;
  padding: 20px 24px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
}
.campus-total-main {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.campus-total-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.campus-total-label {
  font-size: .85rem;
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: .02em;
  text-transform: uppercase;
}
.campus-total-score {
  font-size: 3.2rem;
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1;
}
.campus-total-sub {
  font-size: .78rem;
  color: var(--text-secondary);
  margin-top: 2px;
}
/* The zones the headline average does NOT cover. */
.campus-total-gap { color: var(--amber-text); font-weight: 650; }
.campus-total-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
.campus-total-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  background: rgba(255,255,255,.35);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  min-width: 0;
}
.campus-total-stat-value {
  font-size: 1.2rem;
  font-weight: 800;
  letter-spacing: -.01em;
}
.campus-total-stat-label {
  font-size: .72rem;
  color: var(--text-secondary);
  font-weight: 500;
}

@media (max-width: 720px) {
  .campus-total-card { grid-template-columns: 1fr; gap: 16px; padding: 18px; }
  .campus-total-stats { grid-template-columns: repeat(2, 1fr); }
  .campus-total-score { font-size: 2.6rem; }
}

/* ── Campus Health water-orb hero (three.js) ────────────────────
   Dark "underwater window" above the stats card, painted by
   LPAScenes.mountSea (campus-health/app.js). The gradient below is
   not a placeholder: it is the finished look for the moments BEFORE
   the canvas mounts and AFTER a lost WebGL context removes it — the
   DOM overlay (label / % / denominator) works on either background. */
.campus-sea {
  position: relative;
  height: clamp(200px, 52vw, 280px);
  margin-bottom: 14px;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.08);
  box-shadow: var(--glass-shadow);
  background:
    radial-gradient(ellipse 70% 60% at 50% 0%, #1e3a5c 0%, rgba(30,58,92,0) 60%),
    linear-gradient(180deg, #1b3452 0%, #16243a 55%, #101d30 100%);
}
.campus-sea-canvas,
.campus-sea canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.campus-sea-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 12px;
  text-align: center;
  pointer-events: none;
}
.campus-sea-label {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255,255,255,.78);
  text-shadow: 0 1px 8px rgba(6,20,32,.8);
}
/* The number sits ON the water, which turns teal exactly when the score
   is good — so the digits stay white for contrast in every band and the
   status color arrives as a glow instead of a fill. */
.campus-sea-score {
  font-size: clamp(2.8rem, 11vw, 3.6rem);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1;
  color: #ffffff;
  text-shadow: 0 2px 16px rgba(6,20,32,.75);
}
.campus-sea-score.is-good  { text-shadow: 0 2px 16px rgba(6,20,32,.6), 0 0 26px rgba(34,211,168,.75); }
.campus-sea-score.is-ok    { text-shadow: 0 2px 16px rgba(6,20,32,.6), 0 0 26px rgba(245,158,11,.8); }
.campus-sea-score.is-low   { text-shadow: 0 2px 16px rgba(6,20,32,.6), 0 0 26px rgba(239,68,68,.85); }
.campus-sea-score.is-stale { color: rgba(255,255,255,.72); }
.campus-sea-sub {
  font-size: .78rem;
  color: rgba(255,255,255,.72);
  text-shadow: 0 1px 8px rgba(6,20,32,.8);
  max-width: min(80%, 420px);
}
/* The amber "not yet audited" gap needs its dark-background shade here
   (--amber-text is tuned for the light glass card). */
.campus-sea-sub .campus-total-gap { color: #fcd34d; }

/* While the hero is live it IS the headline: the glass card below drops
   its duplicate big number and keeps the stats strip. */
.campus-total--sea .campus-total-main { display: none; }
.campus-total--sea .campus-total-card { grid-template-columns: 1fr; }

/* ── Audit Summary Overlay ──────────────────────────────────── */
.summary-overlay {
  position: fixed;
  inset: 0;
  z-index: 998;
  background: rgba(0,0,0,.35);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.summary-overlay.open { opacity: 1; }
/* While fading out (or in), nothing inside is tappable — prevents a
   confirm click landing during the close animation. */
.summary-overlay:not(.open) { pointer-events: none; }

.summary-card {
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  max-width: 480px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  padding: 28px;
  box-shadow: 0 24px 64px rgba(0,0,0,.18);
  position: relative;
}

/* Close (✕) for the review modal — same exit as "Edit Audit", just where
   people expect it. Removed once a submission is in flight. */
.summary-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,.05);
  color: var(--text-secondary);
  font-size: .85rem;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
}
.summary-close:hover { background: rgba(0,0,0,.1); color: var(--text); }

.summary-title {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 2px;
  letter-spacing: -.02em;
}

.summary-audit-name {
  font-size: .82rem;
  color: var(--text-secondary);
  margin: 0 0 20px;
  font-weight: 500;
}

.summary-stats {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;
}

.summary-stat {
  flex: 1;
  text-align: center;
  background: rgba(0,0,0,.03);
  border-radius: var(--radius-sm);
  padding: 14px 8px;
}

.summary-stat-num {
  display: block;
  font-size: 1.8rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.02em;
}

.summary-stat-label {
  display: block;
  font-size: .68rem;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-top: 4px;
  font-weight: 600;
}

.summary-progress-label {
  font-size: .75rem;
  color: var(--text-secondary);
  margin-bottom: 6px;
  font-weight: 500;
}

.summary-progress-track {
  height: 6px;
  background: rgba(0,0,0,.06);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 20px;
}

.summary-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #2870a0, #5dd8ea);
  border-radius: 3px;
  transition: width .5s var(--ease-out);
}

.summary-issues {
  margin-bottom: 20px;
}

.summary-issues-title {
  font-size: .78rem;
  font-weight: 700;
  color: var(--red);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin: 0 0 10px;
}

.summary-issue {
  background: rgba(239,68,68,.04);
  border: 1px solid rgba(239,68,68,.1);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-bottom: 8px;
}

/* An issue with no department picked is recorded but never emailed.
   Call it out before submit, not after. */
.summary-unrouted-warn {
  background: rgba(245,158,11,.12);
  border: 1px solid rgba(245,158,11,.35);
  color: var(--amber-text);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  margin-bottom: 10px;
  font-size: .8rem;
  font-weight: 600;
  line-height: 1.45;
}
.summary-issue-unrouted {
  background: rgba(245,158,11,.07);
  border-color: rgba(245,158,11,.32);
}
.summary-issue-nodept { color: var(--amber-text); font-weight: 700; }

.summary-issue-q {
  font-size: .84rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 4px;
  line-height: 1.4;
}

.summary-issue-meta {
  font-size: .75rem;
  color: var(--text-secondary);
}

.summary-issue-badge {
  display: inline-block;
  background: rgba(239,68,68,.1);
  color: var(--red);
  font-weight: 700;
  font-size: .7rem;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  margin-right: 6px;
}

.summary-issue-notes {
  font-size: .78rem;
  color: #4b5563;
  font-style: italic;
  margin-top: 6px;
}

.summary-allclear {
  background: rgba(40,112,160,.06);
  border: 1px solid rgba(40,112,160,.15);
  border-radius: var(--radius-sm);
  padding: 16px;
  text-align: center;
  font-size: .88rem;
  font-weight: 600;
  color: var(--accent);
  margin-bottom: 20px;
}

.summary-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.summary-submit-error {
  padding: 12px 14px;
  margin-bottom: 12px;
  background: var(--red-light);
  border: 1px solid rgba(239,68,68,.25);
  border-radius: var(--radius-sm);
  color: var(--red);
  font-size: .85rem;
  font-weight: 500;
}

.summary-btn-submit {
  width: 100%;
  padding: 14px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: #fff;
  font-size: .95rem;
  font-weight: 600;
  box-shadow: 0 4px 20px rgba(40,112,160,.25);
}
.summary-btn-submit:hover { box-shadow: 0 6px 28px rgba(40,112,160,.35); }

.summary-btn-edit {
  width: 100%;
  padding: 12px;
  border-radius: var(--radius-pill);
  background: rgba(0,0,0,.04);
  color: var(--text);
  font-size: .88rem;
  font-weight: 600;
  border: 1px solid rgba(0,0,0,.08);
}
.summary-btn-edit:hover { background: rgba(0,0,0,.07); }

/* Success screen */
.success-screen {
  text-align: center;
  padding: 20px 0;
}

.success-check {
  margin-bottom: 20px;
  animation: success-pop .5s var(--spring);
}

@keyframes success-pop {
  0% { transform: scale(0); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

.success-title {
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 8px;
}

.success-text {
  font-size: .9rem;
  color: var(--text-secondary);
  margin: 0 0 16px;
}

.success-redirect {
  font-size: .78rem;
  color: var(--text-secondary);
  opacity: .6;
  margin: 0;
}

/* Submit receipt */
.receipt-screen {
  text-align: center;
  padding: 4px 0 0;
}

.receipt-check {
  margin-bottom: 14px;
}

.receipt-title {
  font-size: 1.28rem;
  font-weight: 750;
  color: var(--text);
  margin: 0;
  letter-spacing: 0;
}

.receipt-audit-name {
  font-size: .84rem;
  color: var(--text-secondary);
  margin: 4px 0 18px;
  font-weight: 600;
}

.receipt-score {
  background: linear-gradient(135deg, rgba(40,112,160,.12), rgba(40,112,160,.05));
  border: 1px solid rgba(40,112,160,.2);
  border-radius: 8px;
  padding: 18px 14px;
  margin-bottom: 14px;
}

.receipt-score-value {
  display: block;
  font-size: 3.3rem;
  line-height: .9;
  font-weight: 850;
  color: var(--accent);
  letter-spacing: 0;
}

.receipt-score-label {
  display: block;
  margin-top: 8px;
  font-size: .78rem;
  color: var(--text-secondary);
  font-weight: 650;
}

.receipt-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 16px;
}

.receipt-metric {
  background: rgba(0,0,0,.035);
  border: 1px solid rgba(0,0,0,.06);
  border-radius: 8px;
  padding: 12px 10px;
  min-width: 0;
}

.receipt-metric-wide {
  grid-column: 1 / -1;
  text-align: left;
}

.receipt-metric-label {
  display: block;
  font-size: .66rem;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 750;
  margin-bottom: 5px;
}

.receipt-metric-value {
  display: block;
  font-size: 1.05rem;
  color: var(--text);
  font-weight: 800;
  letter-spacing: 0;
}
.receipt-metric-value.warn { color: var(--amber-text); }

.receipt-status {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: .78rem;
  font-weight: 800;
}

.receipt-status-pending {
  color: #8a5a00;
  background: rgba(245,158,11,.14);
}

.receipt-status-success {
  color: #087f67;
  background: rgba(34,211,168,.14);
}

.receipt-status-error {
  color: var(--red);
  background: var(--red-light);
}

.receipt-status-note {
  display: block;
  margin-top: 7px;
  font-size: .78rem;
  color: var(--text-secondary);
  line-height: 1.35;
}

.receipt-dashboard-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 46px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: #fff;
  font-size: .94rem;
  font-weight: 750;
  text-decoration: none;
  box-shadow: 0 5px 20px rgba(40,112,160,.25);
}

@media (max-width: 480px) {
  .receipt-grid {
    grid-template-columns: 1fr;
  }
}

.hidden { display: none !important; }

/* ── Admin Panel ────────────────────────────────────────────────
   Shares the glass language of the dashboard so the console doesn't read
   as a bolted-on legacy page. (Previously inline CSS in admin/index.html.) */
.admin-main { max-width: 820px; margin: 0 auto; padding: 24px 20px 40px; }

.admin-card {
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  padding: 20px 22px 24px;
  margin-bottom: 18px;
}
.admin-card h2 {
  margin: 0 0 4px;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -.01em;
}
.admin-card .admin-sub { margin: 0 0 16px; color: var(--text-secondary); font-size: .88rem; line-height: 1.45; }
.admin-card-meta { font-size: .72rem; color: var(--text-secondary); font-weight: 500; margin: -10px 0 12px; }

.admin-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 0;
  border-top: 1px solid rgba(0,0,0,.05);
}
.admin-row:first-of-type { border-top: 0; }
.admin-row .label { font-weight: 600; color: var(--text); }
.admin-row .desc { color: var(--text-secondary); font-size: .84rem; line-height: 1.4; }
.admin-state { font-size: .85rem; color: var(--text-secondary); }
.admin-consequence {
  font-size: .8rem;
  color: var(--amber-text);
  background: rgba(245,158,11,.1);
  border: 1px solid rgba(245,158,11,.25);
  border-radius: 10px;
  padding: 8px 12px;
  margin-top: 10px;
}
.admin-consequence[hidden] { display: none; }

.admin-add { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.admin-add .auth-input {
  margin: 0;
  flex: 1 1 220px;
  background: rgba(255,255,255,.7);
  border: 1px solid rgba(0,0,0,.1);
  color: var(--text);
}
.admin-add .auth-input::placeholder { color: var(--text-secondary); }
.admin-add .auth-input:focus {
  background: #fff;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.15);
}
.admin-field-label { display: block; font-size: .78rem; font-weight: 600; color: var(--text-secondary); margin-bottom: 4px; }

.name-input {
  width: 100%;
  max-width: 240px;
  padding: 7px 10px;
  border: 1px solid rgba(0,0,0,.12);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  font-size: .88rem;
  background: rgba(255,255,255,.7);
}
.name-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.15);
  background: #fff;
}

.bulk-box { margin-top: 18px; border-top: 1px solid rgba(0,0,0,.05); padding-top: 14px; }
.bulk-box summary { cursor: pointer; font-weight: 600; color: var(--text-secondary); font-size: .9rem; }
.bulk-box code { background: rgba(0,0,0,.05); padding: 1px 5px; border-radius: 5px; font-size: .82rem; }
.bulk-textarea {
  width: 100%;
  box-sizing: border-box;
  margin: 10px 0;
  padding: 10px 12px;
  border: 1px solid rgba(0,0,0,.12);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, Menlo, monospace;
  font-size: .82rem;
  color: var(--text);
  background: rgba(255,255,255,.7);
}
.bulk-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.15);
  background: #fff;
}
.bulk-fails {
  margin: 6px 0 0;
  padding-left: 18px;
  font-size: .8rem;
  color: var(--red);
  line-height: 1.5;
}

table.allow-table { width: 100%; border-collapse: collapse; }
table.allow-table th, table.allow-table td {
  text-align: left;
  padding: 9px 8px;
  border-bottom: 1px solid rgba(0,0,0,.05);
  font-size: .88rem;
  vertical-align: middle;
  color: var(--text);
}
table.allow-table th {
  color: var(--text-secondary);
  font-weight: 700;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  font-size: .72rem;
  font-weight: 600;
  background: rgba(0,0,0,.05);
  color: var(--text-secondary);
}
.badge.grace { background: rgba(245,158,11,.12); color: var(--amber-text); }
.pill-on { color: #0c7a3f; font-weight: 700; }
.pill-off { color: var(--text-secondary); font-weight: 700; }
.admin-note { font-size: .82rem; color: var(--text-secondary); margin-top: 12px; line-height: 1.45; }

.count-badge {
  display: inline-block;
  min-width: 1.5em;
  margin-left: 6px;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  background: rgba(40,112,160,.1);
  color: var(--accent);
  font-size: .76rem;
  font-weight: 700;
  vertical-align: middle;
  text-align: center;
}
.count-badge.alert { background: rgba(245,158,11,.14); color: var(--amber-text); }
/* The explicit display above would otherwise defeat the hidden attribute. */
.count-badge[hidden] { display: none; }

.table-filter {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 8px;
  padding: 9px 12px;
  border: 1px solid rgba(0,0,0,.12);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: .88rem;
  color: var(--text);
  background: rgba(255,255,255,.7);
}
.table-filter:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(40,112,160,.15);
  background: #fff;
}
.filter-count { font-size: .76rem; color: var(--text-secondary); margin: 0 0 8px; min-height: 1em; }

.admin-msg { min-height: 1.2rem; font-size: .88rem; margin: 8px 0 0; }
.admin-msg.error { color: #b3261e; }
.admin-msg.success { color: #0c7a3f; }

/* Request age + activity status indicators */
.age-badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  font-size: .72rem;
  font-weight: 700;
  margin-left: 6px;
}
.age-fresh { background: rgba(34,211,168,.14); color: #087f67; }
.age-aging { background: rgba(245,158,11,.14); color: var(--amber-text); }
.age-old   { background: var(--red-light); color: var(--red); }

.status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: 1px;
}
.status-active   .status-dot { background: #16a34a; }
.status-idle     .status-dot { background: var(--amber); }
.status-inactive .status-dot { background: var(--red); }
.status-active   { color: #0c7a3f; font-weight: 600; font-size: .82rem; white-space: nowrap; }
.status-idle     { color: var(--amber-text); font-weight: 600; font-size: .82rem; white-space: nowrap; }
.status-inactive { color: var(--red); font-weight: 600; font-size: .82rem; white-space: nowrap; }

.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 640px) {
  /* iOS focus-zoom guard: these admin inputs must be ≥16px. */
  .name-input, .bulk-textarea, .table-filter { font-size: 16px; }
  .name-input { max-width: none; }
  table.allow-table { min-width: 560px; }
}

/* ── Print Styles ───────────────────────────────────────────── */
@media print {
  body { padding-bottom: 0; background: #fff; }
  .site-header {
    position: relative;
    background: #24324b !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  /* Gradient text prints as invisible (transparent fill) — force solid. */
  .site-header h1 {
    background: none;
    -webkit-text-fill-color: #fff;
    color: #fff;
  }
  .section-nav,
  .summary-footer,
  .note-toggle,
  .progress-bar-wrap,
  .btn-send-email,
  .photo-upload-btn,
  .photo-remove,
  .zone-back-btn,
  .save-indicator,
  .restore-banner,
  .missing-toast,
  .toast-stack,
  .summary-overlay,
  .bug-modal-overlay,
  .ref-lightbox,
  .ref-example-sub,
  .welcome-overlay { display: none !important; }
  /* Keep the example thumbnail in printouts but flatten its tinted chrome. */
  .ref-example { background: transparent; border-color: rgba(0,0,0,.2); }
  .header-fields input {
    background: transparent;
    border-color: rgba(255,255,255,.4);
    color: #fff;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .issue-panel.open { max-height: none; overflow: visible; opacity: 1; }
  .audit-section { break-inside: avoid; box-shadow: none; backdrop-filter: none; border: 1px solid rgba(0,0,0,.15); }
  .audit-section::before { display: none; }
  .question-row { break-inside: avoid; }
  .question-row.answered-yes { background: rgba(40,112,160,.06) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .question-row.answered-no  { background: rgba(239,68,68,.05) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .btn-yes.active { background: var(--accent) !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .btn-no.active  { background: var(--red) !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .btn-rating.active.rating-low  { background: var(--red) !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .btn-rating.active.rating-mid  { background: var(--amber) !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .btn-rating.active.rating-high { background: var(--accent) !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .notes-wrap.open { max-height: none; opacity: 1; }
  .photo-preview { max-width: 160px; max-height: 120px; }
}

/* ── Responsive ─────────────────────────────────────────────── */
@media (max-width: 640px) {
  /* --header-h is NOT set here any more. It used to be pinned at 180px
     while the stacked mobile header actually renders ~274px, so
     .section-nav (sticky at top:var(--header-h)) sat 94px behind the
     header and was invisible for the whole audit, and every scroll
     anchor undershot by the same amount. shared/layout.js now measures
     the real height and writes the variable; the :root value stays a
     fallback for the first paint and for browsers without
     ResizeObserver. */
  .zone-page { --header-h: 268px; }
  .zone-page.fields-collapsed { --header-h: 132px; }
  .header-top { flex-direction: column; align-items: flex-start; position: relative; }
  /* The back button would otherwise become its own ~50px row in the
     stacked header. Float it over the logo row instead. */
  .header-top .zone-back-btn {
    position: absolute;
    top: 0;
    right: 0;
    min-height: 36px;
    padding: 6px 12px;
  }
  .header-fields { flex-direction: column; gap: 8px; width: 100%; }
  .header-fields label { width: 100%; }
  .header-fields input { min-width: 0; width: 100%; }
  /* Collapsed: the logo yields its row so the title and the identity
     pill share one line. The brand mark is on every other screen; the
     audit form is the one place the pixels are worth more.

     padding-right reserves the lane the absolutely-positioned back
     button occupies — without it the identity pill slides straight
     under "‹ Dashboard". */
  .zone-page.fields-collapsed .header-top {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    padding-right: 118px;
  }
  .zone-page.fields-collapsed .header-logo { display: none; }
  .zone-page.fields-collapsed .header-top .zone-back-btn { top: 2px; }
  .zone-page.fields-collapsed .site-header h1 {
    font-size: 1.05rem;
    flex: 0 0 auto;
  }
  /* The pill takes the leftover width and truncates rather than pushing
     the row wider — a long auditor name must not reflow the header. */
  .zone-page.fields-collapsed .header-idcard {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
  }
  .zone-page.fields-collapsed .header-idcard > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Dashboard-style pages do not need the large stacked brand row on every
     scroll. Keep their title and account controls in a compact two-row header;
     zone pages retain the measured audit-specific layout above. */
  body:not(.zone-page) .site-header .header-inner { padding-top: 10px; padding-bottom: 10px; }
  body:not(.zone-page) .site-header .header-top {
    flex-direction: row;
    align-items: center;
    gap: 8px;
    margin-bottom: 0;
  }
  /* The wave mark used to disappear on phones, leaving the login card as
     the only place the aquarium's brand appeared. Keep it, small. */
  body:not(.zone-page) .site-header .header-logo { height: 22px; }
  body:not(.zone-page) .site-header h1 { flex: 1 1 120px; font-size: 1.05rem; }
  body:not(.zone-page) .site-header .dash-user { margin-left: auto; gap: 6px; }
  body:not(.zone-page) .site-header .dash-user > span { display: none; }
  body:not(.zone-page) .site-header .dash-user .btn { padding-left: 10px; padding-right: 10px; }
  /* The absolute float above exists for the zone pages' stacked header.
     Dashboard-style pages keep a single row, where floating the back
     button drops it on top of whatever else ends the row (on
     Achievements, the injected theme toggle). Keep it in flow, pushed
     right, with the toggle after it. */
  body:not(.zone-page) .site-header .header-top .zone-back-btn {
    position: static;
    order: 1;
    margin-left: auto;
  }
  body:not(.zone-page) .site-header .header-top > .theme-toggle { order: 2; }

  /* Keep the progress bar, its label, the save slot and the Spot Check
     toggle on ONE row. Flexbox decides wrapping from flex-BASIS, before
     any growing, so the basis total is what has to fit: 84 + 50 + 58 +
     104 + 24px of gaps = 320 against ~335px of usable width. Overshoot
     it and the toggle drops to a second row, costing ~19px of header —
     the space this collapse exists to reclaim in the first place. */
  .progress-bar-wrap { gap: 6px 8px; }
  .progress-track { flex: 1 1 84px; min-width: 72px; }
  #progress-label { font-size: .68rem; }
  .save-indicator { width: 3.6rem; }
  .spot-check-toggle {
    margin-left: 0;
    padding: 5px 10px;
    font-size: .68rem;
  }
  .welcome-card { padding: 24px 20px; }
  .speech-bubble { font-size: .95rem; padding: 16px 20px; }
  .ari-img { width: 180px; }
  .ari-model { width: min(220px, 70vw); height: min(260px, 42vh); }
  .summary-inner { gap: 0; padding-top: 8px; }
  .summary-label,
  .summary-chips { display: none; }
  .action-row { width: 100%; gap: 6px; }
  .action-row > .btn-next-open,
  .action-row > .btn-export { flex: 1 1 auto; }
  .footer-desktop-action { display: none !important; }
  .footer-more { display: block; flex: 0 0 auto; }
  .footer-more > summary { display: inline-flex; align-items: center; justify-content: center; gap: 4px; }
  .btn { padding: 7px 14px; font-size: .78rem; }
  .question-row { padding: 12px 16px; }
  .audit-section { border-radius: var(--radius-sm); }
}

/* ── Photo markup modal + dictation button ─────────────────── */
/* shared/photo-markup.js builds .markup-overlay; shared/dictate.js
   toggles .dictate-btn.is-listening. The overlay is deliberately dark
   in BOTH colour schemes: a photo reads best on a near-black ground,
   and the red stroke needs a neutral surround. */
body.markup-open { overflow: hidden; }
/* The "N waiting to send" pill (z-index 940) sat on top of the markup tools
   (700) whenever something was queued. */
body.markup-open .queue-pill { display: none; }

.markup-overlay {
  position: fixed;
  inset: 0;
  z-index: 700;
  display: flex;
  flex-direction: column;
  background: #0b1017;
  color: #fff;
  opacity: 0;
  transition: opacity .2s var(--ease);
  -webkit-user-select: none;
  user-select: none;
  padding-top: env(safe-area-inset-top, 0px);
}
.markup-overlay.open { opacity: 1; }

.markup-head {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  padding: 12px max(16px, env(safe-area-inset-right, 0px)) 8px max(16px, env(safe-area-inset-left, 0px));
}
.markup-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -.01em;
}
.markup-hint {
  font-size: .78rem;
  color: rgba(255,255,255,.62);
  white-space: nowrap;
}

.markup-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #05080c;
}
.markup-canvas {
  display: block;
  max-width: 100%;
  max-height: 100%;
  touch-action: none;
  cursor: crosshair;
  box-shadow: 0 8px 32px rgba(0,0,0,.55);
}

.markup-bar {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px max(16px, env(safe-area-inset-right, 0px)) max(14px, env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
  background: rgba(255,255,255,.05);
  border-top: 1px solid rgba(255,255,255,.1);
}
.markup-tools {
  display: flex;
  gap: 8px;
}
.markup-tool {
  flex: 1 1 0;
  min-width: 44px;
  min-height: 52px;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 6px 4px;
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--radius-sm);
  background: rgba(255,255,255,.06);
  color: #fff;
  font-family: inherit;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: -.01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .25s var(--spring);
}
.markup-tool svg {
  width: 22px;
  height: 22px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.markup-tool:hover { background: rgba(255,255,255,.12); }
.markup-tool:active { transform: scale(.94); }
.markup-tool[aria-pressed="true"] {
  background: var(--red);
  border-color: var(--red);
  color: #fff;
  box-shadow: 0 0 0 3px rgba(239,68,68,.28);
}
.markup-tool:disabled {
  opacity: .38;
  cursor: default;
  transform: none;
}
.markup-tool:focus-visible,
.markup-btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.markup-actions {
  display: flex;
  gap: 10px;
}
.markup-btn {
  flex: 1 1 0;
  min-height: 48px;
  padding: 0 20px;
  border: none;
  border-radius: var(--radius-pill);
  font-family: inherit;
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: -.01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background .2s var(--ease), transform .25s var(--spring);
}
.markup-btn:active { transform: scale(.96); }
.markup-btn-cancel {
  background: rgba(255,255,255,.1);
  color: #fff;
  border: 1px solid rgba(255,255,255,.18);
}
.markup-btn-cancel:hover { background: rgba(255,255,255,.16); }
.markup-btn-save {
  background: var(--accent);
  color: #fff;
  box-shadow: 0 4px 14px rgba(40,112,160,.4);
}
.markup-btn-save:hover { background: #3382b5; }

@media (min-width: 640px) {
  .markup-tools { justify-content: center; }
  .markup-tool {
    flex: 0 0 auto;
    flex-direction: row;
    gap: 8px;
    min-width: 96px;
    min-height: 44px;
    padding: 0 16px;
    font-size: .82rem;
  }
  .markup-actions { justify-content: flex-end; }
  .markup-btn { flex: 0 0 auto; min-width: 128px; }
}
/* Phone held sideways: put tools and actions on one row so the photo
   keeps most of the height. */
@media (orientation: landscape) and (max-height: 500px) {
  .markup-head { min-height: 40px; padding-top: 6px; padding-bottom: 4px; }
  .markup-bar { flex-direction: row; align-items: center; justify-content: space-between; padding-top: 8px; }
  .markup-tools { flex: 1 1 auto; }
  .markup-tool { flex: 0 0 auto; flex-direction: row; gap: 6px; min-height: 44px; padding: 0 12px; }
  .markup-actions { flex: 0 0 auto; }
  .markup-btn { flex: 0 0 auto; min-height: 44px; }
}

/* Dictation toggle. The button itself is styled by whichever row it
   sits in; this section only owns the listening state: red ink and a
   pulsing dot in front of the label. */
.dictate-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 44px;
  min-height: 44px;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
/* dictate.js sets `hidden` where the Web Speech API is missing; the
   display rule above would otherwise win over the UA [hidden] style. */
.dictate-btn[hidden] { display: none !important; }
.dictate-btn::before {
  content: '';
  width: 0;
  height: 0;
  border-radius: 50%;
  background: var(--red);
  transition: width .2s var(--spring), height .2s var(--spring);
}
.dictate-btn.is-listening {
  color: var(--red);
  border-color: var(--red);
  background: var(--red-light);
}
.dictate-btn.is-listening::before {
  width: 9px;
  height: 9px;
  box-shadow: 0 0 0 0 rgba(239,68,68,.55);
  animation: dictate-pulse 1.3s ease-out infinite;
}
@keyframes dictate-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(239,68,68,.55); }
  100% { box-shadow: 0 0 0 10px rgba(239,68,68,0); }
}

@media (prefers-reduced-motion: reduce) {
  .markup-overlay,
  .markup-tool,
  .markup-btn,
  .dictate-btn::before { transition: none; }
  .dictate-btn.is-listening::before {
    animation: none;
    box-shadow: 0 0 0 3px rgba(239,68,68,.3);
  }
}


/* ── Cross-Device / Cross-Browser Optimizations ─────────────── */

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

button, a, label, input, textarea, select,
.photo-upload-btn, .nav-tab {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

button, .photo-upload-btn, .nav-tab, .audit-card, .health-card,
.campus-health-card, .chip, .summary-label {
  -webkit-user-select: none;
  user-select: none;
}

/* Notched-device safe-area padding (iPhone X+, modern Android) */
@supports (padding: max(0px)) {
  body { padding-bottom: max(80px, calc(68px + env(safe-area-inset-bottom))); }

  /* Top / sticky chrome */
  .site-header { padding-top: env(safe-area-inset-top); }
  .header-inner {
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
  }
  .section-nav-inner {
    padding-left: max(12px, env(safe-area-inset-left));
    padding-right: max(12px, env(safe-area-inset-right));
  }

  /* Fixed summary footer — lifts above home-indicator */
  .summary-inner {
    padding-bottom: max(12px, calc(8px + env(safe-area-inset-bottom)));
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
  }

  /* Main scroll regions */
  #audit-body, .dash-main {
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
  }

  /* Auth / landing page — full-bleed, no site-header */
  .auth-body {
    padding-top: max(20px, env(safe-area-inset-top));
    padding-bottom: max(20px, env(safe-area-inset-bottom));
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
  }

  /* Full-screen overlays — keep content off the notch & home-indicator */
  .welcome-overlay {
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
  .summary-overlay {
    padding: max(20px, env(safe-area-inset-top))
             max(20px, env(safe-area-inset-right))
             max(20px, env(safe-area-inset-bottom))
             max(20px, env(safe-area-inset-left));
  }
  .bug-modal-overlay {
    padding: max(20px, env(safe-area-inset-top))
             max(20px, env(safe-area-inset-right))
             max(20px, env(safe-area-inset-bottom))
             max(20px, env(safe-area-inset-left));
  }
}

/* Suppress hover on touch-only devices — prevents sticky hover after tap */
@media (hover: none) {
  .audit-card:hover,
  .health-card:hover,
  .campus-health-card:hover { transform: none; box-shadow: var(--glass-shadow); }
  .btn-yes:hover { background: transparent; border-color: rgba(40,112,160,.65); }
  .btn-no:hover { background: transparent; border-color: rgba(239,68,68,.55); }
  .btn-rating:hover { background: transparent; border-color: rgba(0,0,0,.12); }
  .issue-btn:hover { background: rgba(0,0,0,.02); }
  .note-toggle:hover { background: rgba(0,0,0,.03); color: var(--text-secondary); }
  .nav-tab:hover { background: transparent; color: rgba(208,239,247,.92); }
  .photo-upload-btn:hover { background: rgba(0,0,0,.02); border-color: rgba(0,0,0,.12); color: var(--text-secondary); }
}

/* Respect OS-level reduced-motion preference */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .welcome-overlay { transition: none; }
  .header-fields input.needs-attention { animation: none; }
}

/* Backdrop-filter fallback for browsers without support */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background: rgba(26,41,64,.97); }
  .section-nav { background: rgba(31,67,102,.95); }
  .summary-footer { background: rgba(255,255,255,.96); }
  .auth-card { background: rgba(26,41,64,.9); }
  .audit-section,
  .audit-card,
  .health-card,
  .campus-health-card,
  .history-table,
  .history-empty,
  .summary-card { background: #fff; }
  .speech-bubble { background: rgba(255,255,255,.2); }
  .welcome-overlay,
  .summary-overlay,
  .bug-modal-overlay { background: rgba(10,20,35,.88); }
}

/* Dynamic viewport height — tracks mobile address-bar show/hide */
@supports (height: 100dvh) {
  body, .auth-body { min-height: 100dvh; }
  .welcome-overlay { height: 100dvh; }
}

/* Focus-visible for keyboard users only */
button:focus-visible,
a:focus-visible,
.nav-tab:focus-visible,
.resp-btn:focus-visible,
.issue-btn:focus-visible,
.note-toggle:focus-visible,
.photo-upload-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
button:focus:not(:focus-visible),
a:focus:not(:focus-visible) { outline: none; }

/* ── Severity buttons (in issue panel) ──────────────────── */
.severity-label {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-top: 10px;
  margin-bottom: 8px;
  letter-spacing: -.01em;
}

.severity-row {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}
/* Segmented control: three joined cells, each with its own colour dot, so
   Low / Medium / High read as one scale rather than three loose pills. */
.severity-seg {
  gap: 0;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: rgba(0,0,0,.05);
  border: 1px solid rgba(0,0,0,.06);
  max-width: 360px;
}
.severity-seg .severity-btn {
  flex: 1 1 0;
  border: 0;
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 8px;
}
.severity-seg .severity-btn::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--sev-color);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sev-color) 25%, transparent);
}
.severity-seg .severity-low    { --sev-color: #22c55e; }
.severity-seg .severity-medium { --sev-color: #f59e0b; }
.severity-seg .severity-high   { --sev-color: #ef4444; }
.severity-seg .severity-btn.active::before { background: #fff; box-shadow: 0 0 0 2px rgba(255,255,255,.35); }
.severity-seg .severity-btn:active { transform: none; }

.severity-btn {
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  border: 1.5px solid rgba(0,0,0,.08);
  background: rgba(0,0,0,.02);
  transition: all .25s var(--spring);
  font-family: inherit;
  color: var(--text);
  letter-spacing: -.01em;
}
.severity-btn:hover { background: rgba(0,0,0,.05); }
.severity-btn:active { transform: scale(.93); }

.severity-low.active {
  background: rgba(34,197,94,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 15px rgba(34,197,94,.2);
}
.severity-medium.active {
  background: rgba(245,158,11,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 15px rgba(245,158,11,.2);
}
.severity-high.active {
  background: rgba(239,68,68,.9);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 15px rgba(239,68,68,.2);
}

/* ── Spot Check toggle ──────────────────────────────────── */
.spot-check-toggle {
  padding: 6px 14px;
  margin-left: 12px;
  border-radius: var(--radius-pill);
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
  border: 1.5px solid rgba(0,0,0,.1);
  background: rgba(255,255,255,.5);
  transition: all .25s var(--spring);
  color: var(--text);
  letter-spacing: -.01em;
  white-space: nowrap;
}
.spot-check-toggle:hover { background: rgba(255,255,255,.7); }
.spot-check-toggle.active {
  background: var(--accent);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 12px rgba(40,112,160,.2);
}

body.spot-check-active .spot-check-hidden { display: none !important; }

/* ── Campus Health: Trends View ────────────────────────────── */
.trends-bars {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 20px;
}

.trend-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  background: rgba(0,0,0,.04);
  border-radius: var(--radius-sm);
  padding: 0 12px;
  position: relative;
  overflow: hidden;
}

.trend-bar .bar-fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  background: rgba(0,0,0,.08);
  z-index: 0;
  border-radius: var(--radius-sm);
}

.trend-bar.bar-good .bar-fill { background: rgba(34,197,94,.3); }
.trend-bar.bar-ok .bar-fill { background: rgba(245,158,11,.3); }
.trend-bar.bar-low .bar-fill { background: rgba(239,68,68,.3); }

.trend-bar .bar-pct {
  position: relative;
  z-index: 1;
  font-weight: 600;
  font-size: .8rem;
  color: var(--text);
  min-width: 40px;
  text-align: right;
}

.problems-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.problem-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 12px;
  background: rgba(0,0,0,.03);
  border-radius: var(--radius-sm);
  font-size: .85rem;
}

.score-badge {
  padding: 2px 10px;
  border-radius: 12px;
  font-weight: 600;
  font-size: .75rem;
  background: rgba(0,0,0,.1);
  color: var(--text);
}

.badge-good { background: rgba(34,197,94,.2); color: rgba(34,197,94,1); }
.badge-ok { background: rgba(245,158,11,.2); color: rgba(245,158,11,1); }
.badge-low { background: rgba(239,68,68,.2); color: rgba(239,68,68,1); }

/* ── Campus Health: Calendar View ────────────────────────────── */
.audit-calendar {
  width: 100%;
  border-collapse: collapse;
  font-size: .8rem;
}

.audit-calendar th,
.audit-calendar td {
  padding: 8px 6px;
  text-align: center;
  border: 1px solid rgba(0,0,0,.08);
}

.audit-calendar th {
  background: rgba(0,0,0,.04);
  font-weight: 600;
  color: var(--text-secondary);
}

.cal-zone {
  text-align: left;
  font-weight: 500;
  width: 140px;
  max-width: 140px;
  word-break: break-word;
}

.cal-cell {
  background: #fff;
  position: relative;
  color: var(--text);
}

.cal-cell.cal-none { background: rgba(0,0,0,.04); color: var(--text-secondary); }
.cal-cell.cal-good { background: rgba(34,197,94,.15); color: rgba(34,197,94,1); }
.cal-cell.cal-ok { background: rgba(245,158,11,.15); color: rgba(245,158,11,1); }
.cal-cell.cal-low { background: rgba(239,68,68,.15); color: rgba(239,68,68,1); }

/* ── Campus Health: Issues View ────────────────────────────── */
.issues-bars {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 20px;
}

.issue-bar-row {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: .85rem;
}

.issue-dept {
  width: 140px;
  font-weight: 500;
  flex-shrink: 0;
}

.issue-bar {
  flex: 1;
  height: 28px;
  background: rgba(0,0,0,.04);
  border-radius: var(--radius-sm);
  overflow: hidden;
  position: relative;
}

.issue-bar .bar-fill {
  height: 100%;
  background: rgba(239,68,68,.3);
  border-radius: var(--radius-sm);
}

.issue-count {
  width: 40px;
  text-align: right;
  font-weight: 600;
  flex-shrink: 0;
}

.issues-zones {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.issue-zone {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 12px;
  background: rgba(0,0,0,.03);
  border-radius: var(--radius-sm);
  font-size: .85rem;
}

.issue-badge {
  padding: 2px 8px;
  background: rgba(239,68,68,.2);
  color: rgba(239,68,68,1);
  border-radius: 8px;
  font-weight: 600;
  font-size: .75rem;
}

/* Lighter backdrop-filter on small phones for better frame rate */
@media (max-width: 480px) {
  .site-header { -webkit-backdrop-filter: blur(16px) saturate(160%); backdrop-filter: blur(16px) saturate(160%); }
  .section-nav { -webkit-backdrop-filter: blur(14px) saturate(150%); backdrop-filter: blur(14px) saturate(150%); }
  .summary-footer { -webkit-backdrop-filter: blur(16px) saturate(160%); backdrop-filter: blur(16px) saturate(160%); }
}

/* Mobile: prevent iOS focus-zoom (inputs must be ≥16px) + larger tap targets */
@media (max-width: 640px) {
  .auth-input,
  .header-fields input,
  .notes-input,
  .issue-notes,
  .bug-modal-textarea,
  #bug-description { font-size: 16px; }
  /* Standard buttons (admin Add/Grant/Log Out, modal actions) meet the 44px
     minimum touch-target guideline on phones. */
  .btn { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
  .resp-btn { padding: 8px 22px; min-height: 44px; min-width: 64px; font-size: .9rem; }
  .note-toggle { padding: 8px 14px; min-height: 44px; font-size: .78rem; }
  .issue-btn { padding: 10px 16px; min-height: 44px; }
  .severity-btn { padding: 8px 14px; min-height: 44px; }
  .spot-check-toggle { padding: 8px 16px; min-height: 44px; font-size: .8rem; }
  .btn-rating { min-height: 44px; min-width: 44px; }
  .photo-upload-btn { padding: 10px 18px; min-height: 44px; }
  .nav-tab { padding: 11px 16px; min-height: 40px; font-size: .82rem; }
  /* Mobile press feedback: keep secondary controls' subtle squish, but
     skip it on .resp-btn — its color preview (see .btn-yes:active /
     .btn-no:active) is the press signal there, no shrink needed. */
  .issue-btn:active,
  .severity-btn:active,
  .note-toggle:active,
  .btn-rating:active { transform: scale(.94); }
  .photo-preview { max-width: 100%; max-height: 180px; }
}

/* Tablets too: iOS zooms any focused field under 16px. The 640px block above
   misses iPads (768–1024px portrait), which auditors use on the floor. */
@media (max-width: 1024px) {
  .notes-input,
  .issue-notes,
  .bug-modal-textarea,
  .issue-select,
  .header-fields input,
  .auth-input,
  .name-input,
  .bulk-textarea,
  .table-filter { font-size: 16px; }
}

/* Short-viewport landscape — compact welcome card so buttons stay visible */
@media (max-height: 500px) and (orientation: landscape) {
  .welcome-card { gap: 12px; padding: 14px; flex-direction: row; flex-wrap: wrap; justify-content: center; }
  .ari-img { width: 110px; }
  .ari-model { width: min(150px, 34vw); height: min(150px, 40vh); }
  .speech-bubble { font-size: .85rem; padding: 10px 14px; }
  .welcome-btn { padding: 10px 28px; font-size: .9rem; }
}

/* ══ Achievements ══════════════════════════════════════════════
   Medallion collection (/achievements/), the dashboard entry card,
   and the full-screen unlock celebration. Mobile-first: the grid is
   2-up on phones, the celebration is sized with clamp() + safe-area
   padding, and every tap target is card-sized. */

/* ── Dashboard entry card ── */
.achv-card {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 22px;
  background: linear-gradient(135deg, rgba(246,195,68,.18) 0%, rgba(180,124,24,.10) 100%);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(214,158,46,.45);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  text-decoration: none;
  color: var(--text);
  transition: all .25s var(--spring);
  grid-column: 1 / -1;
}
.achv-card:hover { transform: translateY(-2px); box-shadow: 0 12px 36px rgba(214,158,46,.22); }
.achv-card:active { transform: scale(.98); }
.achv-card-medal {
  width: 46px; height: 46px;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 0 2px rgba(214,158,46,.5), 0 4px 14px rgba(180,124,24,.35);
}
.achv-card .campus-health-arrow { color: #b4791a; }
.achv-card-title { font-size: 1rem; font-weight: 700; letter-spacing: -.01em; }
.achv-card-sub { font-size: .8rem; color: var(--text-secondary); }

/* ── Collection page ── */
.achv-main { max-width: 720px; }
.achv-progress-line {
  font-size: .85rem;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .08em;
  margin-bottom: 14px;
}
/* One .achv-group per Achievements.groups entry: a small uppercase
   heading with an "x of y" count, then that group's grid. */
.achv-collection { display: flex; flex-direction: column; gap: 26px; }
.achv-group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.achv-group-head .achv-group-title { margin: 0; }
.achv-group-count {
  font-size: .72rem;
  font-weight: 700;
  color: var(--text-secondary);
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.achv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 14px;
}
/* Phones: always two across, never one lonely column of 60vw medals. */
@media (max-width: 640px) {
  .achv-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}
.achv-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  padding: 18px 14px 16px;
  border-radius: var(--radius);
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.achv-item .achv-medal {
  width: min(110px, 60vw);
  aspect-ratio: 1;
  border-radius: 50%;
  display: block;
  position: relative;   /* anchors .achv-ring */
}
.achv-item .achv-medal-img {
  width: 100%; height: 100%;
  border-radius: 50%;
  display: block;
}
.achv-item-title { font-size: .92rem; font-weight: 800; letter-spacing: -.01em; line-height: 1.2; }
.achv-item-desc { font-size: .74rem; color: var(--text-secondary); line-height: 1.35; }
.achv-item-date {
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: #b4791a;
  margin-top: 2px;
}

/* Earned: full-color medallion on a glass card with a gold lift. */
.achv-earned {
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(214,158,46,.4);
  box-shadow: var(--glass-shadow);
  transition: transform .25s var(--spring), box-shadow .25s var(--spring);
}
.achv-earned:hover { transform: translateY(-2px); box-shadow: 0 12px 32px rgba(214,158,46,.25); }
.achv-earned:active { transform: scale(.97); }
.achv-earned .achv-medal { box-shadow: 0 0 24px rgba(246,195,68,.45), 0 4px 16px rgba(0,0,0,.25); }

/* Locked: an embossed silhouette — the art stays, desaturated and sunk
   into a recessed disc with an inset ring — on a quiet glass card. */
.achv-locked {
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  cursor: default;
}
.achv-locked .achv-medal {
  background: rgba(12,17,26,.06);
  box-shadow:
    inset 0 0 0 3px rgba(12,17,26,.14),
    inset 0 3px 10px rgba(0,0,0,.3),
    0 1px 0 rgba(255,255,255,.7);
}
.achv-locked .achv-medal-img { filter: grayscale(1) brightness(.35) contrast(1.1) opacity(.55); }
.achv-locked .achv-item-title { color: rgba(20,26,36,.72); }
.achv-locked .achv-item-desc { color: rgba(20,26,36,.55); }
.achv-item-locked-tag { color: rgba(20,26,36,.5); }

/* In progress: a ring around the recessed disc, drawn clockwise from
   12 o'clock; the caption below carries the "7 / 10 audits" numbers. */
.achv-ring {
  position: absolute;
  inset: -7px;
  width: calc(100% + 14px);
  height: calc(100% + 14px);
  transform: rotate(-90deg);
  pointer-events: none;
  overflow: visible;
}
.achv-ring circle { fill: none; stroke-width: 5; }
.achv-ring-track { stroke: rgba(12,17,26,.1); }
.achv-ring-fill {
  stroke: var(--accent);
  stroke-linecap: round;
  animation: achv-ring-draw .9s var(--ease-out) both;
}
/* `from` only: the animation ends at the element's own dasharray. */
@keyframes achv-ring-draw { from { stroke-dasharray: 0 289.03; } }
.achv-in-progress .achv-medal { box-shadow: inset 0 0 0 3px rgba(12,17,26,.1), inset 0 3px 10px rgba(0,0,0,.26); }
.achv-item-progress { color: var(--accent); font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .achv-ring-fill { animation: none; }
}


/* ── Unlock celebration ── */
.achv-overlay {
  position: fixed;
  inset: 0;
  z-index: 12000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at 50% 38%, rgba(26,41,64,.9) 0%, rgba(7,13,22,.96) 70%);
  opacity: 0;
  transition: opacity .32s var(--ease);
  padding: max(24px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left));
}
.achv-overlay.achv-open { opacity: 1; }
.achv-confetti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.achv-burst {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 420px;
  perspective: 900px;
}
.achv-eyebrow {
  font-size: .8rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .22em;
  color: #f6c344;
  margin-bottom: 18px;
  text-shadow: 0 0 18px rgba(246,195,68,.5);
}
.achv-medal-wrap {
  width: clamp(180px, 56vw, 250px);
  aspect-ratio: 1;
  border-radius: 50%;
  filter: drop-shadow(0 0 34px rgba(246,195,68,.45));
  /* Anchors .achv-shine and .achv-coin; the circular overflow clip is what
     keeps the shine sweep inside the medal instead of streaking across the
     copy underneath it. */
  position: relative;
  overflow: hidden;
  transform-style: preserve-3d;
}
.achv-medal-wrap .achv-medal-img {
  width: 100%; height: 100%;
  border-radius: 50%;
  display: block;
}
/* Specular sweep. GSAP drives xPercent across the face once, just after the
   medal lands; it starts parked off-frame and invisible so a no-GSAP page
   (where JS sets display:none) never shows a stray bar. */
.achv-shine {
  position: absolute;
  top: -25%;
  left: 0;
  width: 55%;
  height: 150%;
  pointer-events: none;
  opacity: 0;
  transform: translateX(-140%) rotate(18deg);
  background: linear-gradient(
    100deg,
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,.10) 35%,
    rgba(255,255,255,.55) 50%,
    rgba(255,255,255,.10) 65%,
    rgba(255,255,255,0) 100%);
  mix-blend-mode: screen;
}
/* The 3D coin, when it makes its deadline. Sits exactly over the PNG and
   cross-fades in; both stay in the box so neither swap causes a reflow. */
.achv-coin {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  display: block;
  opacity: 0;
  background: transparent;
  pointer-events: none;
  --poster-color: transparent;
  --progress-bar-color: transparent;
  --progress-mask: transparent;
}
.achv-flip-in { animation: achv-flip 1.05s var(--spring) both; }
@keyframes achv-flip {
  0%   { transform: rotateY(720deg) scale(.12); opacity: 0; }
  55%  { opacity: 1; }
  100% { transform: rotateY(0) scale(1); opacity: 1; }
}
.achv-burst-title {
  margin-top: 20px;
  font-size: 1.45rem;
  font-weight: 800;
  letter-spacing: -.01em;
  color: #fff;
}
.achv-burst-desc {
  margin-top: 6px;
  font-size: .95rem;
  font-weight: 600;
  color: rgba(255,255,255,.85);
}
.achv-burst-flavor {
  margin-top: 12px;
  font-size: .85rem;
  font-style: italic;
  line-height: 1.5;
  color: rgba(246,195,68,.85);
}
.achv-tap-hint {
  margin-top: 26px;
  font-size: .78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: rgba(255,255,255,.55);
  animation: achv-hint-pulse 1.8s ease-in-out infinite;
}
@keyframes achv-hint-pulse {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .achv-flip-in { animation: none; }
  .achv-tap-hint { animation: none; }
  .achv-overlay { transition: none; }
  /* No sweep and no coin under reduced motion. shared/achievements.js
     already declines to build either, but the medal is also reachable via
     the CSS fallback path — belt and braces on the one preference where
     getting it wrong is the whole complaint. */
  .achv-shine { display: none; }
  .achv-coin { display: none; }
}

/* ═══════════════════════════════════════════════════════════════
   DARK THEME

   Why this exists at all: this app is walked around Deep Sea, Oceans
   and Penguins — galleries that are deliberately dark, with guests in
   them. Staff were holding a full-brightness white phone in there for
   the length of a 43-question audit, which wrecks their own night
   vision and lights up the room next to the exhibits. The <meta
   name="theme-color"> has been #1a2940 the whole time, so the browser
   chrome was already dark around a white page.

   `screen and` is load-bearing: without it this would also apply when
   printing from a dark-scheme machine and override the @media print
   block above, which deliberately forces white.

   Structure: redefine the tokens first, then fix the surfaces that
   hard-code black/white overlay literals rather than using a token.
   The site header, login card and Ari welcome are already
   white-on-dark and need almost nothing.
   ═══════════════════════════════════════════════════════════════ */


/* ── Admin: checklist editor ─────────────────────────────────── */
.qe-editor { display: flex; flex-direction: column; gap: 14px; margin-top: 12px; }
.qe-section {
  border: 1px solid rgba(0,0,0,.08);
  border-radius: var(--radius);
  background: rgba(255,255,255,.55);
  padding: 12px;
}
.qe-section-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.qe-section-title { flex: 1 1 auto; font-weight: 700; }
.qe-section-id { font-size: .72rem; color: var(--text-secondary); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.qe-q {
  display: grid;
  grid-template-columns: 54px 1fr auto;
  grid-template-areas: "id text actions" "id flags actions";
  gap: 6px 10px;
  align-items: start;
  padding: 8px 0;
  border-top: 1px solid rgba(0,0,0,.05);
}
.qe-q-id { grid-area: id; font-size: .72rem; color: var(--text-secondary); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; padding-top: 10px; }
.qe-q-text { grid-area: text; resize: vertical; min-height: 44px; }
.qe-q-flags { grid-area: flags; display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: .78rem; color: var(--text-secondary); }
.qe-q-flags label { display: inline-flex; align-items: center; gap: 5px; }
.qe-q-actions { grid-area: actions; display: flex; flex-direction: column; gap: 4px; }
.qe-mini { padding: 4px 9px; font-size: .78rem; line-height: 1.2; }
.qe-add-q { margin-top: 8px; }
@media (max-width: 640px) {
  .qe-q { grid-template-columns: 1fr auto; grid-template-areas: "id actions" "text actions" "flags actions"; }
}

/* ══════════════════════════════════════════════════════════════
   Focus mode (2026-09-05) — shared/focus-mode.js
   One question per screen: full-screen overlay, one glass card with
   the question in the display face, big answer buttons, and a swipe
   gesture (right = Yes, left = No) with YES / NO stamps. The
   "Resume focus" pill floats above the footer after a No sends the
   auditor back to the long form. Dark-mode variants at the end of
   this block.
   ══════════════════════════════════════════════════════════════ */

/* Body scroll is locked while the overlay is up. */
html.focus-mode-open, body.focus-mode-open { overflow: hidden !important; }

.focus-overlay {
  position: fixed;
  inset: 0;
  z-index: 945;               /* over the footer (200) + missing-toast (900), under toasts (950) + the ref lightbox (1000) */
  display: flex;
  flex-direction: column;
  background: rgba(243,246,250,.97);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  backdrop-filter: blur(22px) saturate(160%);
  color: var(--text);
  overscroll-behavior: contain;
  padding-top: env(safe-area-inset-top, 0px);
}

/* ── Top bar ──────────────────────────────────────────────────── */
.focus-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px 6px;
}
.focus-close {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--glass-strong);
  color: var(--text);
  font-size: 1.05rem;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: transform .15s var(--spring), background-color .15s var(--ease-out);
}
.focus-close:hover { background: rgba(0,0,0,.06); }
.focus-close:active { transform: scale(.92); }
.focus-top-mid { flex: 1 1 auto; min-width: 0; }
.focus-eyebrow {
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-secondary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.focus-count {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
}
.focus-progress {
  height: 3px;
  margin: 0 14px 4px;
  border-radius: 3px;
  background: rgba(0,0,0,.08);
  overflow: hidden;
}
.focus-progress-fill {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--accent);
  transition: width .35s var(--ease-out);
}

/* ── Stage + card ─────────────────────────────────────────────── */
.focus-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 16px;
  perspective: 1200px;
}
.focus-card {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--glass-strong);
  border: 1px solid var(--glass-border, rgba(0,0,0,.06));
  border-radius: calc(var(--radius) + 6px);
  box-shadow: var(--glass-shadow, 0 8px 40px rgba(0,0,0,.08));
  overflow: hidden;
  touch-action: pan-y;        /* vertical = native scroll inside the card; horizontal = ours */
  -webkit-user-select: none; user-select: none;
  will-change: transform;
  transform-origin: 50% 110%;
  transition: transform .45s var(--spring), opacity .2s var(--ease-out), box-shadow .2s var(--ease-out);
  outline: none;
}
.focus-card:focus-visible { box-shadow: var(--glass-shadow, 0 8px 40px rgba(0,0,0,.08)), 0 0 0 3px var(--accent-light); }
.focus-card.is-dragging,
.focus-card.no-transition { transition: none; }
.focus-card.past-threshold { box-shadow: 0 18px 50px rgba(0,0,0,.18); }
@keyframes focus-card-enter {
  from { opacity: 0; transform: translateY(14px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
/* `backwards`, not `both`: a finished animation that keeps filling forwards
   outranks the inline transform/opacity the swipe sets, so from the second
   card on the card neither followed the finger nor flew out. */
.focus-card.focus-card-enter { animation: focus-card-enter .32s var(--ease-out) backwards; }

/* Swipe stamps — fade in with the drag distance (opacity set by JS). */
.focus-stamp {
  position: absolute;
  top: 18px;
  z-index: 2;
  padding: 4px 12px;
  border: 3px solid;
  border-radius: 10px;
  font-family: var(--font-display);
  font-size: 1.9rem;
  font-weight: 800;
  letter-spacing: .08em;
  line-height: 1;
  opacity: 0;
  pointer-events: none;
  background: rgba(255,255,255,.85);
}
.focus-stamp-yes { left: 18px;  color: var(--green-text); border-color: var(--green-text); transform: rotate(-12deg); }
.focus-stamp-no  { right: 18px; color: var(--red);        border-color: var(--red);        transform: rotate(12deg); }

.focus-qview { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.focus-qview[hidden] { display: none; }
.focus-card-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* A scroll container starts its own touch-action; without this the card's
     pan-y stops here and a sideways swipe that begins on the question text
     is cancelled by the browser instead of answering. */
  touch-action: pan-y;
  padding: 22px 22px 6px;
}
.focus-qnum {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; height: 30px; padding: 0 9px;
  border-radius: var(--radius-pill);
  background: var(--accent-light);
  color: var(--accent);
  font-size: .82rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.focus-qtext {
  margin: 12px 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 4.8vw, 1.75rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -.01em;
  color: var(--text);
  text-wrap: balance;
}

/* Reference image — same affordance as the row's .ref-example, bigger. */
.focus-ref {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  margin: 16px 0 4px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgba(0,0,0,.03);
  color: var(--text);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform .15s var(--spring), background-color .15s var(--ease-out);
}
.focus-ref[hidden] { display: none; }
.focus-ref:hover { background: rgba(0,0,0,.06); }
.focus-ref:active { transform: scale(.98); }
.focus-ref-img {
  flex: 0 0 auto;
  width: 84px; height: 84px;
  object-fit: cover;
  border-radius: 10px;
  background: rgba(0,0,0,.06);
}
.focus-ref-cap { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.focus-ref-cap-main { font-size: .9rem; font-weight: 600; line-height: 1.3; }
.focus-ref-cap-sub  { font-size: .76rem; color: var(--text-secondary); }

/* ── Answer buttons ───────────────────────────────────────────── */
.focus-answers {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "yes yes" "no na";
  gap: 10px;
  padding: 12px 16px 6px;
}
.focus-ans {
  min-height: 56px;
  padding: 0 12px;
  border-radius: 16px;
  border: 2px solid transparent;
  background: transparent;
  font-family: inherit;
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.2;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s var(--spring), background-color .15s var(--ease-out),
              color .15s var(--ease-out), border-color .15s var(--ease-out), box-shadow .15s var(--ease-out);
}
.focus-ans:active { transform: scale(.96); }
.focus-ans:focus-visible { outline: 3px solid var(--accent-light); outline-offset: 2px; }
.focus-ans-yes {
  grid-area: yes;
  min-height: 66px;
  font-size: 1.2rem;
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 8px 22px rgba(40,112,160,.28);
}
.focus-ans-yes:hover { filter: brightness(1.06); }
.focus-ans-yes[aria-pressed="true"] { box-shadow: 0 0 0 4px var(--accent-light), 0 8px 22px rgba(40,112,160,.28); }
.focus-ans-yes[aria-pressed="true"]::before { content: '\2713\00a0'; }
.focus-ans-no {
  grid-area: no;
  border-color: var(--red);
  color: var(--red);
}
.focus-ans-no:hover { background: var(--red-light, rgba(239,68,68,.08)); }
.focus-ans-no[aria-pressed="true"] { background: var(--red); color: #fff; }
.focus-ans-no[aria-pressed="true"]::before { content: '\2715\00a0'; }
.focus-ans-na {
  grid-area: na;
  border-color: rgba(0,0,0,.18);
  color: var(--text-secondary);
}
.focus-ans-na:hover { background: rgba(0,0,0,.05); }
.focus-ans-na[aria-pressed="true"] { background: #6e6e73; border-color: #6e6e73; color: #fff; }

/* Rating rows: five equal cells + anchors underneath. */
.focus-answers.is-rating {
  grid-template-columns: repeat(5, 1fr);
  grid-template-areas: none;
  gap: 8px;
}
.focus-ans-rate {
  border-color: rgba(0,0,0,.18);
  color: var(--text);
  font-size: 1.25rem;
  font-variant-numeric: tabular-nums;
}
.focus-ans-rate:hover { background: rgba(0,0,0,.05); }
.focus-ans-rate-low[aria-pressed="true"]  { background: var(--red);   border-color: var(--red);   color: #fff; }
.focus-ans-rate-mid[aria-pressed="true"]  { background: var(--amber, #f59e0b); border-color: var(--amber, #f59e0b); color: #fff; }
.focus-ans-rate-high[aria-pressed="true"] { background: var(--green); border-color: var(--green); color: #fff; }
.focus-rate-anchors {
  grid-column: 1 / -1;
  display: flex; justify-content: space-between;
  font-size: .74rem; color: var(--text-secondary);
  padding: 0 4px;
}
.focus-hint {
  padding: 4px 16px 14px;
  text-align: center;
  font-size: .74rem;
  color: var(--text-secondary);
}

/* ── Done card ────────────────────────────────────────────────── */
.focus-done {
  padding: 36px 24px 24px;
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.focus-done[hidden] { display: none; }
.focus-done-glyph {
  width: 64px; height: 64px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--green);
  color: #fff;
  font-size: 2rem; font-weight: 800;
  box-shadow: 0 10px 26px rgba(22,163,74,.3);
}
.focus-done-title {
  margin: 8px 0 0;
  font-family: var(--font-display);
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: -.01em;
}
.focus-done-sub { margin: 0; color: var(--text-secondary); font-size: .95rem; max-width: 32ch; }
.focus-done-btn {
  margin-top: 14px;
  width: 100%;
  min-height: 60px;
  border: 0;
  border-radius: 16px;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 1.1rem; font-weight: 700;
  cursor: pointer;
  box-shadow: 0 8px 22px rgba(40,112,160,.28);
  transition: transform .12s var(--spring);
}
.focus-done-btn:active { transform: scale(.97); }

/* ── Bottom controls ──────────────────────────────────────────── */
.focus-controls {
  flex: 0 0 auto;
  display: flex;
  gap: 10px;
  padding: 8px 16px calc(14px + env(safe-area-inset-bottom, 0px));
}
.focus-nav {
  flex: 1 1 0;
  min-height: 48px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--glass-strong);
  color: var(--text);
  font-family: inherit;
  font-size: .95rem; font-weight: 600;
  cursor: pointer;
  transition: transform .12s var(--spring), opacity .15s var(--ease-out), background-color .15s var(--ease-out);
}
.focus-nav:hover { background: rgba(0,0,0,.05); }
.focus-nav:active { transform: scale(.96); }
.focus-nav:disabled { opacity: .38; cursor: default; transform: none; }
.focus-nav-skip { flex: 0 0 auto; padding: 0 22px; color: var(--text-secondary); }

/* ── Resume pill (long form, after a No) ───────────────────────── */
@keyframes focus-resume-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.focus-resume {
  position: fixed;
  right: 14px;
  bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  z-index: 210;                /* above the footer (200), under toasts */
  min-height: 44px;
  padding: 10px 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--accent-dark, #24324b);
  color: #fff;
  font-family: inherit;
  font-size: .84rem; font-weight: 700;
  cursor: pointer;
  box-shadow: 0 10px 30px rgba(0,0,0,.25);
  animation: focus-resume-in .35s var(--spring) both;
  white-space: nowrap;
}
.focus-resume[hidden] { display: none; }
.focus-resume:active { transform: scale(.96); }

/* ── Reduced motion ───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .focus-card, .focus-ans, .focus-nav, .focus-close, .focus-ref, .focus-done-btn, .focus-progress-fill { transition: none; }
  .focus-card.focus-card-enter, .focus-resume { animation: none; }
  .focus-hint { display: none; }
}
.focus-overlay.reduced-motion .focus-hint,
.focus-card.is-rating .focus-hint { display: none; }

/* ── Dark-mode variants for everything above ─────────────────── */


/* ══════════════════════════════════════════════════════════════
   Visual refresh (2026-09-03)
   Display face on the big words; "your week" hero; quick-action row;
   zone cards that carry state; compact answered rows; illustrated
   empty states. Dark-mode variants at the end of this block.
   ══════════════════════════════════════════════════════════════ */

/* ── Display typography ──────────────────────────────────────── */
.week-hero-title,
.health-score,
.campus-total-score,
.campus-sea-score,
.onboard-title,
.summary-title,
.achv-title,
.welcome-card h2,
.auth-title,
.auth-card h2 { font-family: var(--font-display); }

/* ── "Your week" hero ────────────────────────────────────────── */
.week-hero {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 20px 22px;
  margin-bottom: 14px;
  border-radius: var(--radius);
  color: #fff;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(112,152,192,.35) 0%, transparent 55%),
    linear-gradient(135deg, #1f4366 0%, #1a2940 100%);
  box-shadow: 0 16px 40px rgba(26,41,64,.28);
  position: relative;
  overflow: hidden;
}
/* Faint wave mark, bottom-right, behind the text. */
.week-hero::after {
  content: '';
  position: absolute;
  right: -18px;
  bottom: -26px;
  width: 150px;
  height: 150px;
  background: url('/assets/brand/llpa-wave-white.png') center / contain no-repeat;
  opacity: .07;
  pointer-events: none;
}
.week-hero-main { flex: 1 1 auto; min-width: 0; position: relative; }
.week-hero-eyebrow {
  display: block;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255,255,255,.62);
  margin-bottom: 4px;
}
.week-hero-title {
  font-size: 1.55rem;
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.15;
  color: #fff;
  margin: 0 0 6px;
}
.week-hero-amp { color: rgba(255,255,255,.45); font-weight: 500; }
.week-hero-sub {
  font-size: .85rem;
  color: rgba(255,255,255,.8);
  margin: 0;
}
/* The old banner text is redundant inside the hero; keep the node for
   its "all done" state and screen readers only. */
.week-hero .assignment-banner {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  margin: 0; padding: 0; border: 0;
}
.week-hero-ring {
  position: relative;
  flex-shrink: 0;
  width: 96px;
  height: 96px;
}
.week-hero-ring svg { display: block; width: 100%; height: 100%; }
.week-ring-track { stroke: rgba(255,255,255,.16); }
.week-ring-fill  { stroke: #7fd1ff; transition: stroke-dashoffset .8s var(--ease-out); }
.week-hero-ring.is-done .week-ring-fill { stroke: #22d3a8; }
.week-ring-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: -.02em;
}
@media (max-width: 640px) {
  .week-hero { padding: 18px 18px; gap: 14px; }
  .week-hero-title { font-size: 1.35rem; }
  .week-hero-ring { width: 80px; height: 80px; }
  .week-ring-label { font-size: 1.05rem; }
}

/* ── Quick-action row (replaces the three stacked promo cards) ─── */
.quick-actions {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
@media (max-width: 720px) { .top-cards.quick-actions { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.quick-action,
.top-cards .quick-action {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 14px 12px;
  min-height: 0;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
  color: var(--text);
  text-decoration: none;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition: transform .25s var(--spring), box-shadow .25s var(--spring);
}
.quick-action:hover { transform: translateY(-2px); box-shadow: 0 12px 32px rgba(0,0,0,.1); }
.quick-action:active { transform: scale(.97); }
.quick-action-icon {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 12px;
  color: #fff;
  flex-shrink: 0;
}
.quick-action .campus-health-icon { background: var(--accent); }
.quick-action .spot-issue-icon { background: #ea580c; }
.quick-actions .achv-card { grid-column: auto; background: var(--glass-strong); border-color: rgba(214,158,46,.35); }
.quick-actions .achv-card .quick-action-title { color: var(--text); }
.quick-action .achv-card-icon { background: rgba(214,158,46,.16); }
.quick-action .achv-card-medal { width: 40px; height: 40px; border-radius: 50%; display: block; box-shadow: 0 2px 8px rgba(0,0,0,.2); }
.quick-action-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.quick-action .quick-action-title { font-size: .84rem; font-weight: 700; letter-spacing: -.01em; }
.quick-action .quick-action-sub { font-size: .7rem; color: var(--text-secondary); line-height: 1.25; }
@media (max-width: 400px) {
  .quick-action .quick-action-sub { display: none; }
  .quick-action { padding: 12px 10px 10px; gap: 8px; }
  .quick-action .quick-action-title { font-size: .76rem; }
}

/* ── Zone cards that carry state ─────────────────────────────── */
.audit-card {
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    'badge  badge  badge'
    'glyph  title  score'
    'meter  meter  meter'
    'status status arrow';
  gap: 4px 10px;
  padding: 14px 16px 12px;
}
.audit-card-glyph {
  grid-area: glyph;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 10px;
  background: var(--accent-light);
  color: var(--accent);
}
.audit-card-glyph:empty { display: none; }
.audit-card-glyph svg { display: block; }
.audit-card-title { font-size: .95rem; font-weight: 700; }
.audit-card-score {
  grid-area: score;
  font-family: var(--font-display);
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--text-secondary);
}
.audit-card-score:empty { display: none; }
.audit-card-score.score-band-good { color: var(--green-text); }
.audit-card-score.score-band-ok   { color: var(--amber-text); }
.audit-card-score.score-band-low  { color: var(--red); }
.audit-card-meter {
  grid-area: meter;
  display: block;
  height: 5px;
  border-radius: 3px;
  background: rgba(0,0,0,.07);
  overflow: hidden;
  margin-top: 4px;
}
.audit-card-meter i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 3px;
  background: var(--gray);
  transition: width .7s var(--ease-out);
}
.audit-card-meter.meter-band-good i { background: var(--green); }
.audit-card-meter.meter-band-ok i   { background: var(--amber); }
.audit-card-meter.meter-band-low i  { background: var(--red); }
.audit-card-meter.meter-band-none   { background: repeating-linear-gradient(90deg, rgba(0,0,0,.07) 0 6px, transparent 6px 10px); }
.audit-card-arrow { grid-area: arrow; align-self: end; }
.audit-card-status { grid-area: status; align-self: end; }
.audit-card-assigned .audit-card-glyph { background: rgba(47,128,237,.14); color: #2f80ed; }

/* ── Compact answered rows ───────────────────────────────────── */
/* Once a question is answered the row is a record, not a control: pull
   the padding in and shrink the pills so a 43-question walk gets shorter
   as it goes, while every answer stays one tap from being changed. */
.question-row { padding: 12px 18px; gap: 12px; }
.question-row.answered-yes,
.question-row.answered-na { padding-top: 9px; padding-bottom: 9px; }
.question-row.answered-yes .question-text,
.question-row.answered-na .question-text { font-size: .82rem; margin-bottom: 5px; }
.question-row.answered-yes .resp-btn:not(.active),
.question-row.answered-na  .resp-btn:not(.active) { opacity: .55; padding-top: 3px; padding-bottom: 3px; }
.question-row.answered-yes .resp-btn.active,
.question-row.answered-na  .resp-btn.active { padding-top: 3px; padding-bottom: 3px; }
.question-row.answered-yes .note-toggle:not(.has-note),
.question-row.answered-na  .note-toggle:not(.has-note) { opacity: .6; width: 30px; height: 30px; }
.question-text { margin-bottom: 7px; }
.response-row { gap: 6px; }
@media (max-width: 400px) {
  .resp-btn { padding-left: 14px; padding-right: 14px; }
}

/* ── Illustrated empty states ────────────────────────────────── */
.empty-state {
  position: relative;
  padding: 28px 20px 26px;
  overflow: hidden;
}
.empty-state::before {
  content: '';
  display: block;
  width: 56px;
  height: 56px;
  margin: 0 auto 10px;
  background: url('/assets/brand/llpa-wave-color.png') center / contain no-repeat;
  opacity: .55;
}
.empty-state::after {
  content: '';
  position: absolute;
  inset: auto -10% -70% -10%;
  height: 120px;
  border-radius: 50%;
  background: radial-gradient(60% 60% at 50% 50%, rgba(40,112,160,.14), transparent 70%);
  pointer-events: none;
}

/* ── Dark-mode variants for everything above ─────────────────── */


/* ══════════════════════════════════════════════════════════════
   Questionnaire refresh (2026-09-05)
   Per-zone theming, header glyph, focus-mode entry, segmented
   progress, folding sections, write-up helpers, question glyphs,
   tablet layout, spot-check identity, review receipt.
   ══════════════════════════════════════════════════════════════ */

/* ── Per-zone theme tokens (body[data-zone] set by generate-zones) ── */
.zone-page { --zone-a: rgba(31,67,102,.94); --zone-b: rgba(26,41,64,.96); --zone-accent: #7fd1ff; }
body[data-zone="discoverutah"]   { --zone-a: rgba(112,62,34,.94);  --zone-b: rgba(52,30,20,.96);  --zone-accent: #f4b26b; }
body[data-zone="retail"]         { --zone-a: rgba(82,46,110,.94);  --zone-b: rgba(40,22,58,.96);  --zone-accent: #d8b4fe; }
body[data-zone="deepsea"]        { --zone-a: rgba(16,44,86,.95);   --zone-b: rgba(8,22,44,.97);   --zone-accent: #67e8f9; }
body[data-zone="penguins"]       { --zone-a: rgba(35,80,104,.94);  --zone-b: rgba(18,42,60,.96);  --zone-accent: #bae6fd; }
body[data-zone="oceans"]         { --zone-a: rgba(21,94,138,.94);  --zone-b: rgba(11,47,71,.96);  --zone-accent: #7dd3fc; }
body[data-zone="firstfloor"]     { --zone-a: rgba(41,58,84,.94);   --zone-b: rgba(24,34,52,.96);  --zone-accent: #cbd5e1; }
body[data-zone="secondfloor"]    { --zone-a: rgba(46,64,92,.94);   --zone-b: rgba(26,38,58,.96);  --zone-accent: #cbd5e1; }
body[data-zone="jsa1"]           { --zone-a: rgba(31,77,58,.94);   --zone-b: rgba(16,42,32,.96);  --zone-accent: #86efac; }
body[data-zone="jsa2"]           { --zone-a: rgba(28,88,64,.94);   --zone-b: rgba(14,44,32,.96);  --zone-accent: #86efac; }
body[data-zone="eeco"]           { --zone-a: rgba(46,42,110,.94);  --zone-b: rgba(22,20,60,.96);  --zone-accent: #c4b5fd; }
body[data-zone="koigarden"]      { --zone-a: rgba(122,47,26,.94);  --zone-b: rgba(58,22,12,.96);  --zone-accent: #fdba74; }
body[data-zone="tukis"]          { --zone-a: rgba(15,95,92,.94);   --zone-b: rgba(9,51,48,.96);   --zone-accent: #5eead4; }
body[data-zone="expeditionasia"] { --zone-a: rgba(107,61,18,.94);  --zone-b: rgba(51,32,10,.96);  --zone-accent: #fcd34d; }
body[data-zone="parkinglot"]     { --zone-a: rgba(58,63,71,.94);   --zone-b: rgba(31,35,40,.96);  --zone-accent: #e2e8f0; }
body[data-zone="plaza"]          { --zone-a: rgba(107,78,18,.94);  --zone-b: rgba(51,39,10,.96);  --zone-accent: #fde68a; }

.zone-page .site-header { background: linear-gradient(160deg, var(--zone-a) 0%, var(--zone-b) 100%); }
.zone-page .section-nav { background: color-mix(in srgb, var(--zone-b) 82%, transparent); }
.zone-page .progress-fill,
.zone-page .progress-seg b { background: linear-gradient(90deg, color-mix(in srgb, var(--zone-accent) 60%, #2870a0), var(--zone-accent)); }
.zone-page .nav-tab.active { background: color-mix(in srgb, var(--zone-accent) 22%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--zone-accent) 35%, transparent); }

/* Zone glyph beside the title (filled by audit-engine initVisualExtras). */
.header-zone-glyph {
  width: 36px; height: 36px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 11px;
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.14);
  color: var(--zone-accent);
}
.header-zone-glyph:empty { display: none; }
.header-zone-glyph svg { display: block; }
@media (max-width: 640px) {
  .zone-page.fields-collapsed .header-zone-glyph { width: 30px; height: 30px; border-radius: 9px; }
}

/* ── Spot-check identity ─────────────────────────────────────── */
body.spot-check-active .site-header { background: linear-gradient(160deg, rgba(146,84,14,.95) 0%, rgba(74,42,8,.97) 100%); }
body.spot-check-active .section-nav { background: rgba(74,42,8,.82); }
body.spot-check-active .site-header::after {
  content: 'Spot check';
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  background: #f59e0b;
  color: #1c1c1e;
  font-size: .6rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 3px 12px 4px;
  border-radius: 0 0 9px 9px;
  pointer-events: none;
}
.spot-check-toggle.active { background: #f59e0b; color: #1c1c1e; box-shadow: 0 0 14px rgba(245,158,11,.35); }

/* ── Section nav: scrolling tabs + pinned Focus button ───────── */
.section-nav { display: flex; align-items: center; justify-content: center; overflow: visible; }
.section-nav-inner { flex: 0 1 960px; min-width: 0; overflow-x: auto; scrollbar-width: none; margin: 0; }
.section-nav-inner::-webkit-scrollbar { display: none; }
.focus-nav-btn {
  display: none;
  flex-shrink: 0;
  align-items: center;
  gap: 6px;
  margin: 0 10px 0 4px;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.1);
  color: #fff;
  font: inherit;
  font-size: .74rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background .2s var(--ease), transform .15s var(--spring);
}
.focus-nav-btn:hover { background: rgba(255,255,255,.18); }
.focus-nav-btn:active { transform: scale(.96); }
body.has-focus-mode .focus-nav-btn { display: inline-flex; }
/* Tabs done / with an issue carry a glyph, not just a colour. */
.nav-tab.is-done::before { content: '\2713'; margin-right: 5px; color: #22d3a8; font-weight: 800; }
.nav-tab.is-done.has-issue::before { content: '!'; color: #fbbf24; }
.nav-tab.is-done { color: rgba(255,255,255,.8); }

/* ── Segmented progress (one segment per section) ────────────── */
.progress-track.is-segmented { display: flex; gap: 3px; background: transparent; overflow: visible; }
.progress-track.is-segmented #progress-fill { display: none; }
.progress-seg { flex: 1 1 0; height: 100%; background: rgba(255,255,255,.14); border-radius: 3px; overflow: hidden; }
.progress-seg b { display: block; height: 100%; width: 0; border-radius: 3px; transition: width .45s var(--ease-out); }
.progress-seg.is-done b { background: #22d3a8; }

/* ── Folding finished sections ───────────────────────────────── */
.audit-section.is-complete > .section-header { cursor: pointer; }
.audit-section.is-complete > .section-header::after {
  content: '';
  width: 8px; height: 8px;
  border-right: 2px solid var(--text-secondary);
  border-bottom: 2px solid var(--text-secondary);
  transform: rotate(45deg);
  margin-left: 4px;
  transition: transform .25s var(--ease);
  flex-shrink: 0;
}
.audit-section.is-complete.is-expanded > .section-header::after { transform: rotate(-135deg); }
.audit-section.is-complete:not(.is-expanded) > .question-list { display: none; }
.audit-section.is-complete > .section-header h2::before { content: '\2713'; color: var(--green-text); margin-right: 8px; font-weight: 800; }
.audit-section.is-complete > .section-header { background: rgba(22,163,74,.06); }
.section-done-summary { display: none; }

/* ── Write-up helpers ────────────────────────────────────────── */
.phrase-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 8px; }
.phrase-chip {
  font: inherit;
  font-size: .72rem;
  font-weight: 600;
  padding: 6px 11px;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(40,112,160,.3);
  background: rgba(40,112,160,.06);
  color: var(--accent);
  cursor: pointer;
  transition: background .15s var(--ease), transform .12s var(--spring);
  -webkit-tap-highlight-color: transparent;
}
.phrase-chip:hover { background: rgba(40,112,160,.14); }
.phrase-chip:active { transform: scale(.94); }
.dictate-btn {
  display: none;
  margin-left: auto;
  width: 34px; height: 34px;
  align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(0,0,0,.1);
  background: rgba(0,0,0,.04);
  color: var(--text-secondary);
  cursor: pointer;
  padding: 0;
}
body.has-dictate .dictate-btn { display: inline-flex; }
.photo-preview-wrap { position: relative; }
.photo-markup-btn {
  display: none;
  position: absolute;
  left: 8px; bottom: 8px;
  align-items: center; gap: 5px;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  border: 0;
  background: rgba(0,0,0,.62);
  color: #fff;
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
body.has-markup .photo-preview-wrap .photo-markup-btn { display: inline-flex; }

/* ── Question-kind glyph ─────────────────────────────────────── */
.question-kind { display: inline-flex; vertical-align: -3px; margin-right: 7px; color: var(--accent); opacity: .85; }
.question-kind svg { display: block; }
.answered-no .question-kind { color: var(--red); }

/* ── Tablet / desktop layout ─────────────────────────────────── */
.audit-outline { display: none; }
@media (min-width: 900px) {
  /* Wide rows: text left, answers right, write-ups on their own line. */
  .question-row { align-items: center; }
  .question-content { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 18px; }
  .question-text { flex: 1 1 320px; margin-bottom: 0; }
  .question-content > .ref-example { flex: 0 0 auto; order: 1; }
  .question-content > .response-row,
  .question-content > .rating-label { flex: 0 0 auto; order: 2; }
  .question-content > .rating-label { flex-basis: 100%; }
  .question-content > .notes-wrap,
  .question-content > .issue-panel { flex: 1 1 100%; order: 3; }
  .question-row .note-toggle { margin-left: 4px; }
}
@media (min-width: 1000px) {
  .audit-layout {
    display: grid;
    grid-template-columns: 224px minmax(0, 1fr);
    gap: 0 22px;
    max-width: 1220px;
    margin: 0 auto;
    padding: 0 20px;
  }
  .audit-layout > #audit-body { max-width: none; margin: 0; padding: 20px 0; }
  .audit-outline {
    display: block;
    position: sticky;
    top: calc(var(--header-h) + var(--nav-h) + 20px);
    align-self: start;
    margin-top: 20px;
    padding: 12px;
    background: var(--glass-strong);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius);
    box-shadow: var(--glass-shadow);
  }
  .outline-title { font-size: .66rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--text-secondary); padding: 4px 8px 8px; }
  .outline-item {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 2px 8px;
    width: 100%;
    padding: 8px 8px 9px;
    border: 0;
    border-radius: 12px;
    background: transparent;
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }
  .outline-item:hover { background: rgba(0,0,0,.04); }
  .outline-name { font-size: .8rem; font-weight: 600; }
  .outline-left { font-size: .68rem; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
  .outline-item.is-done .outline-left { color: var(--green-text); font-weight: 700; }
  .outline-item.has-issue .outline-left { color: var(--amber-text); }
  .outline-track { grid-column: 1 / -1; height: 4px; border-radius: 2px; background: rgba(0,0,0,.07); overflow: hidden; }
  .outline-fill { display: block; height: 100%; width: 0; background: var(--accent); transition: width .4s var(--ease-out); }
  .outline-item.is-done .outline-fill { background: var(--green); }
}

/* ── Review receipt ──────────────────────────────────────────── */
.summary-score { display: flex; align-items: center; gap: 16px; margin: 4px 0 16px; }
.summary-score-ring { position: relative; width: 88px; height: 88px; flex-shrink: 0; }
.summary-score-ring svg { display: block; width: 100%; height: 100%; }
.summary-ring-track { stroke: rgba(0,0,0,.08); }
.summary-ring-fill { stroke: var(--gray); transition: stroke-dashoffset .8s var(--ease-out); }
.summary-score--good .summary-ring-fill { stroke: var(--green); }
.summary-score--ok .summary-ring-fill { stroke: var(--amber); }
.summary-score--low .summary-ring-fill { stroke: var(--red); }
.summary-score-num {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -.03em;
}
.summary-score--good .summary-score-num { color: var(--green-text); }
.summary-score--ok .summary-score-num { color: var(--amber-text); }
.summary-score--low .summary-score-num { color: var(--red); }
.summary-score-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.summary-score-label { font-size: .68rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--text-secondary); }
.summary-score-sub { font-size: .82rem; color: var(--text); }
.summary-compare { font-size: .76rem; color: var(--text-secondary); min-height: 1em; }
.summary-delta { font-weight: 700; }
.summary-delta.up { color: var(--green-text); }
.summary-delta.down { color: var(--red); }
.summary-issue.has-photo { display: flex; gap: 12px; align-items: flex-start; }
.summary-issue-thumb { width: 60px; height: 60px; border-radius: 10px; object-fit: cover; flex-shrink: 0; box-shadow: 0 2px 8px rgba(0,0,0,.15); }
.summary-issue-body { min-width: 0; flex: 1 1 auto; }
.summary-issue-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.summary-issue-dept { display: inline-flex; align-items: center; gap: 4px; font-weight: 600; }
.summary-issue-dept .issue-btn-icon { width: 14px; height: 14px; }
.summary-issue-sev { font-size: .68rem; font-weight: 700; padding: 2px 8px; border-radius: 999px; }
.summary-issue-sev.sev-low { background: rgba(34,197,94,.14); color: var(--green-text); }
.summary-issue-sev.sev-medium { background: rgba(245,158,11,.16); color: var(--amber-text); }
.summary-issue-sev.sev-high { background: rgba(239,68,68,.14); color: var(--red); }
.summary-issue-section { color: var(--text-secondary); }

/* ── Dark-mode variants ──────────────────────────────────────── */


/* ── Appearance toggle (shared/theme.js) ─────────────────────── */
html[data-theme="light"] { color-scheme: light; }
html[data-theme="dark"]  { color-scheme: dark; }
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.1);
  color: rgba(255,255,255,.92);
  cursor: pointer;
  flex-shrink: 0;
  transition: background .2s var(--ease), transform .15s var(--spring);
}
.theme-toggle:hover { background: rgba(255,255,255,.18); }
.theme-toggle:active { transform: scale(.94); }
.theme-toggle-icon { display: flex; }
.theme-toggle-icon svg { display: block; }
@media (max-width: 640px) { .site-header .theme-toggle { width: 44px; height: 44px; } }
/* Zone footer "More" menu variant: a normal menu row with a label. */
.theme-toggle.theme-toggle--menu {
  width: 100%;
  height: auto;
  border-radius: var(--radius-pill);
  justify-content: flex-start;
  gap: 8px;
  color: var(--text);
  background: rgba(0,0,0,.04);
  border-color: rgba(0,0,0,.08);
}
.theme-toggle--menu .theme-toggle-text { font-size: .8rem; font-weight: 600; }
