/* Colors and type per 26-Allstar_Vault_BrandGuidelines_FINAL.pdf.
   Primary: Vault Blue, Neutral Ivory. Secondary (accent only, never dominant): Navy, Aqua, Stone.
   Hi-Vis Aqua Green is excluded — the guide marks it "requires brand approval." */
:root {
  --vault-blue: #004E73;
  --neutral-ivory: #F9F5F0;
  --navy: #00253E;
  --aqua: #06FEFD;
  --stone: #CBC4C6;

  --bg: var(--neutral-ivory);
  --panel: #ffffff;
  --border: var(--stone);
  --text: var(--navy);
  --muted: #6b7a80;

  /* The 3-level "health" traffic light (compliance %, grading progress, quiz score ranges) —
     one source of truth instead of the same three hexes copy-pasted into page-local <style>
     blocks. Deliberately separate from the "correct/done" green (#1c7a3e, used for interactive-
     module correct answers and path-completion checkmarks) — that's a binary
     completion/correctness signal, not a 3-level gauge, so it keeps its own color. */
  --status-good: #2e6b2e;
  --status-warn: #8a6d00;
  --status-bad: #b3261e;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif; /* guide: Arial is the approved fallback for internal tools */
  background-color: var(--bg);
  color: var(--text);
  /* Subtle repeating texture inspired by the guide's "outlined shapes of the branded Vault
     icon" pattern (p.23) — a plain checkmark/V outline, not the actual logo file (which the
     guide says should never be edited), tiled at very low opacity so it reads as texture,
     not a graphic. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Cpath d='M14 34 L40 60 L82 12' stroke='%23004E73' stroke-width='5' fill='none' stroke-linecap='round' stroke-linejoin='round' opacity='0.035'/%3E%3C/svg%3E");
  background-repeat: repeat;
}
h1, h2, .brand-heading {
  font-family: "Golos Text", Arial, sans-serif; /* guide: Golos is primary typeface for headlines/subheads */
}
/* --- Custom form controls — replace raw browser-default select/checkbox/
   radio appearance with something that actually matches the brand palette,
   applied globally so no per-page markup changes are needed.
   Deliberately placed here, immediately after the base reset and before every page-specific
   rule below — a bare `select`/`input[type="text"]` selector has the exact same specificity
   as plenty of existing rules like `.nav-search input` (class + type = attribute + type, same
   specificity tier), so without this ordering, whichever one happened to appear LATER in the
   file would silently win the tie and clobber the other's border/background/color. Keeping
   this block first means every later, more-specific-or-equal page rule reliably overrides it
   as intended, instead of the outcome depending on where in the file it happens to sit. */
select {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--panel);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23004E73' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 30px !important;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding-top: 7px;
  padding-bottom: 7px;
  padding-left: 9px;
  font-size: 13px;
  color: var(--text);
}
select:focus {
  outline: 2px solid var(--aqua);
  outline-offset: 1px;
}
/* type="date" fell through this whole block until now (only input[type="text"] was covered)
   — both real date inputs in the app (assignments.html's Due Date, path.html's Deadline) were
   silently rendering with the browser's unstyled native date-picker chrome instead of matching
   every other field. */
input[type="text"], input[type="date"] {
  background-color: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 9px;
  font-size: 13px;
  font-family: inherit;
  color: var(--text);
  box-sizing: border-box;
}
input[type="text"]:focus, input[type="date"]:focus {
  outline: 2px solid var(--aqua);
  outline-offset: 1px;
}
header.top {
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  padding: 16px 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
header.top h1 {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 16px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.brand-logo {
  height: 26px;
  width: auto;
  display: block;
}
.brand-logo-suffix {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.03em;
  opacity: 0.85;
  border-left: 1px solid rgba(249, 245, 240, 0.35);
  padding-left: 10px;
}
.brand-logo-large {
  height: 64px;
  width: auto;
  display: block;
  margin-bottom: 4px;
}
header.top .who {
  font-size: 13px;
  color: var(--neutral-ivory);
  display: flex;
  align-items: center;
  gap: 12px;
  opacity: 0.9;
}
header.top button {
  background: transparent;
  border: 1px solid var(--neutral-ivory);
  color: var(--neutral-ivory);
  padding: 6px 12px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 12px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 700;
}
.page-tabs {
  background: var(--navy);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  padding: 0 24px;
}
.nav-search {
  margin-left: auto;
  position: relative;
  padding: 8px 0;
}
.nav-search input {
  width: 220px;
  padding: 6px 10px;
  border: 1px solid rgba(249, 245, 240, 0.3);
  border-radius: 6px;
  background: rgba(249, 245, 240, 0.08);
  color: var(--neutral-ivory);
  font-size: 12px;
  box-sizing: border-box;
}
.nav-search input::placeholder { color: rgba(249, 245, 240, 0.55); }
.nav-search input:focus {
  outline: 2px solid var(--aqua);
  outline-offset: 1px;
  background: rgba(249, 245, 240, 0.15);
}
.nav-search-results {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  width: 300px;
  max-height: 360px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  z-index: 100;
}
@media (max-width: 700px) {
  .nav-search { margin-left: 0; width: 100%; order: 99; }
  .nav-search input { width: 100%; }
  .nav-search-results { width: 100%; }
}
.page-tab {
  display: inline-block;
  padding: 10px 16px;
  color: var(--neutral-ivory);
  opacity: 0.7;
  text-decoration: none;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 700;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  border-bottom: 3px solid transparent;
}
.page-tab.active {
  opacity: 1;
  border-bottom-color: var(--aqua);
}
.page-tab:hover { opacity: 1; }

main {
  max-width: 640px;
  margin: 40px auto;
  padding: 0 20px;
}
/* Pages with a sidebar (everything but /login) wrap <aside> + <main> in .layout instead
   of leaving main centered in a narrow column with empty space on either side. */
.layout {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  max-width: 1320px;
  margin: 0 auto;
  padding: 24px 24px 48px;
}
.layout main {
  flex: 1;
  /* Without this, a flex item's default min-width:auto lets its content (a wide table, an
     unwrapped row) refuse to shrink below its own natural size — the same bug documented on
     .category-manage-column below, here forcing the whole main column wider than the mobile
     viewport instead of letting its contents wrap/scroll within it. */
  min-width: 0;
  max-width: 820px;
  margin: 0;
  padding: 0;
}
/* Collapsing the sidebar frees ~260px — handed to main as a wider (not unlimited) cap, so
   grids/videos/tables genuinely get more room without plain paragraph text (FAQ answers,
   assignment instructions) stretching out to an uncomfortable reading width. */
.layout.sidebar-collapsed main {
  max-width: 1100px;
}
/* Three standalone cards (page-links / Quick Resources / FAQ+Settings) stacked with real
   gaps between them, not one continuous box with internal divider lines — same "distinct
   card, visible page background between" language every other multi-card page already uses. */
.sidebar {
  width: 280px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
  position: sticky;
  top: 24px;
}
.layout.sidebar-collapsed .sidebar {
  width: 48px;
}
.sidebar-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
}
/* Round button straddling the sidebar's right edge (half in, half in the gutter before main),
   vertically centered on the first card/icon (not its top edge) — reference: Cody's screen
   recording of a similar content panel's collapse control. A direct child of .sidebar, not
   nested in .sidebar-full/.sidebar-rail-links, so it stays in the same spot and clickable in
   both states regardless of which of those two is showing. Centered separately per state below
   since the first page-link card (36px tall) and the first rail icon (40px tall) aren't the
   same height. */
.sidebar-collapse-toggle {
  position: absolute;
  top: 23px;
  right: -12px;
  width: 24px;
  height: 24px;
  background: var(--vault-blue);
  border: none;
  border-radius: 50%;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  color: #fff;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  z-index: 1;
}
.sidebar-collapse-toggle:hover { background: var(--navy); }
.layout.sidebar-collapsed .sidebar-collapse-toggle {
  top: 8px;
}
.sidebar-rail-links {
  display: none;
  flex-direction: column;
  gap: 6px;
}
.layout.sidebar-collapsed .sidebar-rail-links {
  display: flex;
}
/* Wraps the three cards that used to be .sidebar's own direct flex children — needs the same
   flex-column + gap so collapsing/expanding it doesn't collapse the spacing between them too. */
.sidebar-full {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
.layout.sidebar-collapsed .sidebar-full {
  display: none;
}
.sidebar-rail-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 40px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--vault-blue);
}
.sidebar-rail-link:hover { border-color: var(--vault-blue); background: var(--neutral-ivory); }
.sidebar-rail-link .vault-icon { width: 18px; height: 18px; }
.sidebar-page-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sidebar-page-links a {
  display: block;
  padding: 10px 14px;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  text-decoration: none;
  border-radius: 8px;
  font-size: 13px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  text-align: center;
}
/* Admin-only inline edit toggle for the page-links stack — sits right in the sidebar
   (Cody's ask: not buried in a separate card elsewhere on the page). Deliberately quiet/
   muted, not styled like the blue action buttons above it, so it doesn't read as "the next
   thing to click" for non-editing use. */
.sidebar-edit-links-btn {
  background: none;
  border: 1px dashed var(--border);
  color: var(--muted);
  padding: 6px 10px;
  border-radius: 8px;
  font-size: 11px;
  font-family: "Golos Text", Arial, sans-serif; font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  cursor: pointer;
  width: 100%;
}
.nav-link-edit-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px;
}
.nav-link-edit-row .drag-handle {
  cursor: grab;
  color: var(--muted);
  font-size: 14px;
}
.nav-link-edit-input {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 12px;
  font-family: "Golos Text", Arial, sans-serif;
}
.sidebar-tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  margin-bottom: 12px;
}
.sidebar-tab {
  flex: 1;
  background: none;
  border: none;
  padding: 8px 4px;
  font-size: 11px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
}
.sidebar-tab.active {
  color: var(--vault-blue);
  border-bottom-color: var(--vault-blue);
}
.sidebar-panel input[type="text"],
.sidebar-panel input[type="password"],
.sidebar-panel select {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  box-sizing: border-box;
}
.sidebar-results {
  margin-top: 10px;
  max-height: 320px;
  overflow-y: auto;
}
.sidebar-result {
  display: block;
  padding: 6px 0;
  font-size: 13px;
  color: var(--vault-blue);
  text-decoration: none;
  border-bottom: 1px solid var(--border);
}
.sidebar-faq-item {
  border-bottom: 1px solid var(--border);
  padding: 8px 0;
  font-size: 13px;
}
.sidebar-faq-item p { margin: 4px 0; color: var(--muted); }
.sidebar-panel h4 {
  margin: 0 0 8px;
  font-size: 12px;
  font-family: "Golos Text", Arial, sans-serif; font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}
/* Quick Resources — its own standalone card, between the page-links card and the FAQ/
   Settings card. Capped at 4 pins, so every item gets a fixed-size row rather than a
   scrolling list. */
.sidebar-quick-resources h4 {
  margin: 0 0 8px;
  font-size: 12px;
  font-family: "Golos Text", Arial, sans-serif; font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.qr-add-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--vault-blue);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.qr-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
}
.qr-item a {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
/* Same visual language as .assignment-card-thumb (Vault logo on a Vault Blue tile, small icon
   badge) — just square and small enough for 4 of them to stack in a 280px sidebar. */
.qr-thumb {
  position: relative;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: 6px;
  background: var(--vault-blue); /* guide: reversed logo only approved on Vault Blue, not Navy */
  display: flex;
  align-items: center;
  justify-content: center;
}
.qr-thumb img { width: 60%; object-fit: contain; }
.qr-thumb .vault-icon {
  position: absolute;
  bottom: -3px;
  right: -3px;
  background: rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--vault-blue);
}
.qr-thumb .vault-icon svg { width: 10px; height: 10px; }
.qr-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.qr-unpin-btn {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 14px;
  cursor: pointer;
  flex-shrink: 0;
  padding: 2px 4px;
}
.qr-add-form select { margin-bottom: 6px; }
@media (max-width: 900px) {
  .layout { flex-direction: column; }
  /* Stacked below main, not above it — .sidebar is first in source order (it's the sticky
     side rail at wider widths), but stacked full-width on mobile that put FAQ/Settings/quick
     links ahead of the page's actual content, pushing it hundreds of pixels down the screen. */
  /* .layout's align-items: flex-start is what makes the row layout work at desktop widths
     (children keep their own heights instead of stretching to match each other), but in this
     stacked column layout that same property stops main from stretching to the container's
     width — it shrinks to its content's natural (max-content) size instead, same problem
     .sidebar's width: 100% below already fixes; main needs the same explicit width. */
  .layout main { order: 1; width: 100%; }
  .sidebar { width: 100%; position: static; order: 2; }
  /* The collapse-to-a-rail idea only makes sense when the sidebar sits beside main and
     collapsing hands that width back — below this breakpoint .layout already stacks the
     sidebar full-width above main, so there's no side-by-side space to reclaim. Force the
     full sidebar regardless of a collapsed preference saved at a wider viewport. */
  .layout.sidebar-collapsed .sidebar { width: 100%; }
  .layout.sidebar-collapsed .sidebar-full { display: flex; }
  .layout.sidebar-collapsed main { max-width: 640px; }
  .layout.sidebar-collapsed .sidebar-rail-links { display: none; }
  .sidebar-collapse-toggle { display: none; }
}
.folder-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
}
.folder-card {
  display: flex;
  flex-direction: column;
  background: var(--neutral-ivory);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 18px 14px;
  text-align: center;
}
.folder-card:hover { border-color: var(--vault-blue); }
/* Real <button> now does the "open this folder" work (keyboard/screen-reader accessible,
   unlike the plain clickable <div> this used to be) — reset to look identical to the old
   div-based card, since .folder-card (the outer shell) still carries all the visual styling.
   flex: 1 lets it grow to fill whatever height the CSS Grid row stretches the card to, so the
   Rename/Delete row below it lands at the same bottom edge on every card in the row regardless
   of how many lines a given folder name wraps to. Also a flex column itself (not just block)
   so the "N documents" count inside it can be pinned to the bottom via margin-top: auto below
   — otherwise the count would still land at a different height per card based on how many
   lines the folder name wrapped to, even with the button itself uniformly sized. */
.folder-card-open {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-align: center;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 700;
  font-size: inherit;
  color: var(--vault-blue);
}
.folder-card-actions { display: flex; gap: 6px; justify-content: center; margin-top: 6px; }
/* min-height reserves room for 2 lines even when a folder's count fits on 1 (e.g. plain "15
   documents" vs the longer "0 documents, 10 assignments" some folders show) — otherwise a
   1-line count's text starts lower than a 2-line count's on the same row, even though both
   are bottom-anchored via margin-top: auto above. */
.folder-card .count { display: block; font-size: 11px; line-height: 1.3; min-height: calc(2.6em + 4px); color: var(--muted); font-weight: 400; margin-top: auto; padding-top: 4px; text-transform: none; }
.folder-icon { font-size: 28px; display: block; margin-bottom: 6px; }
.folder-icon.vault-icon { display: block; margin: 0 auto 6px; }
.todo-item, .highlight-item, .pin-item {
  border-bottom: 1px solid var(--border);
  padding: 10px 0;
}
.todo-item:last-child, .highlight-item:last-child, .pin-item:last-child { border-bottom: none; }
.todo-item.overdue { color: #b3261e; }
.todo-item .due { font-size: 12px; text-transform: uppercase; letter-spacing: 0.02em; font-family: "Golos Text", Arial, sans-serif; font-weight: 700; }
/* Bordered-box-with-internal-scroll for a list that can grow long — the same treatment as
   .resource-picker/.cohort-member-picker (border + radius + padding + max-height + overflow),
   this app's dominant convention for this exact problem (also: roleplay-bucket-list, grading's
   user-section-body), used here instead of a "View More" button (that pattern exists too, but
   only in one place — subgallery.js's submission galleries — so this is the more common one to
   match). Padding is 0 (unlike resource-picker's 8-10px) since .todo-item already carries its
   own vertical padding/border-bottom per row; adding box padding too would double up the gap
   at the top and bottom. */
.todo-list-box {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0 10px;
  max-height: 320px;
  overflow-y: auto;
}
.small-btn {
  background: none; border: 1px solid var(--border); color: var(--muted);
  padding: 3px 9px; border-radius: 6px; font-size: 11px; cursor: pointer;
}
/* Same box model as .small-btn, just the danger color — previously defined independently
   (and slightly differently: 4px 10px padding, 12px font) in both resources.html and
   assignments.html. */
.delete-btn {
  background: none; border: 1px solid var(--border); color: var(--status-bad);
  padding: 3px 9px; border-radius: 6px; font-size: 11px; cursor: pointer;
}
/* Borderless "x" unassign glyph, shared by manage-users.html's cohort-path list and
   path.html's assigned-cohorts list — previously the exact same inline style duplicated in
   both files. */
.unassign-x-btn {
  border: none; background: none; color: var(--status-bad); cursor: pointer; font-size: 12px;
}
form.inline {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
form.inline input, form.inline select, form.inline textarea {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
}
label.field-label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
}
form.inline button {
  align-self: flex-start;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  border: none;
  padding: 8px 16px;
  border-radius: 6px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  cursor: pointer;
  font-size: 12px;
}
/* `form.inline button` (0,1,1) outranks plain `.small-btn`/`.delete-btn` (0,1,0), so every
   Cancel/small button living inside a form.inline was silently rendering as the full primary
   blue button instead of the small outlined one — true everywhere this combination occurs
   (home.html, cohorts.html, practice.html, script-roleplays.html, assignments.html), not just
   the "wrong-looking" ones caught by eye. Fixed at the source with a selector that outranks it
   (0,2,1), rather than patching each call site. */
form.inline button.small-btn, form.inline button.delete-btn {
  align-self: auto;
  background: none;
  border: 1px solid var(--border);
  padding: 3px 9px;
  border-radius: 6px;
  font-family: inherit;
  font-weight: normal;
  text-transform: none;
  font-size: 11px;
}
/* Same visual weight as `form.inline button`, usable standalone — several primary confirm
   actions (Assign, Save Members, Add) live in a plain flex row rather than a form.inline (that
   row layout is deliberately horizontal, which form.inline's flex-column would break), so they
   need this rather than the form-scoped rule. */
.primary-btn {
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  border: none;
  padding: 8px 16px;
  border-radius: 6px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  cursor: pointer;
  font-size: 12px;
}
form.inline button.small-btn { color: var(--muted); }
form.inline button.delete-btn { color: var(--status-bad); }
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 24px;
}
.card h2 {
  margin-top: 0;
  color: var(--vault-blue);
  text-transform: uppercase;
  font-size: 20px;
}
/* "Consider It Covered" brand banner — sits above any video-recording widget's action
   controls, below the title/mode selection. Originally added to assignments.html only (Video
   Submission / AI Role Play assignments), confirmed by Cody after a visual check on one
   screen; promoted here (was duplicated in that page's own <style> block) once Practice with
   AI's live recording session needed the exact same treatment, so both stay in sync instead
   of drifting the way other page-local copies have before. */
.assignment-cover-banner {
  background: var(--vault-blue); color: var(--neutral-ivory);
  font-family: 'Golos Text', Arial, sans-serif; font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.03em; text-align: center; font-size: 22px;
  padding: 22px 16px; border-radius: 10px; margin-bottom: 12px;
}
/* Base rule for the "muted" convention used app-wide (span/div/p, any context) — the two
   scoped rules below only ever narrowed the font-size for their specific spot, but never
   actually supplied this base color, so every class="muted" outside .card/.subgallery-info/
   .empty-state rendered in default text color instead of grey. */
.muted {
  color: var(--muted);
}
.card p.muted {
  color: var(--muted);
  font-size: 14px;
}
.nav-links {
  display: flex;
  gap: 12px;
  margin-top: 16px;
}
.nav-links a {
  display: inline-block;
  padding: 10px 16px;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  text-decoration: none;
  border-radius: 8px;
  font-size: 14px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
form.login {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
form.login label {
  font-size: 13px;
  font-weight: 700;
  color: var(--navy);
}
form.login input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
}
form.login input:focus {
  outline: 2px solid var(--aqua); /* Aqua used sparingly, as an accent, per brand usage rule */
  outline-offset: 1px;
}
form.login button {
  margin-top: 8px;
  padding: 10px 16px;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  border: none;
  border-radius: 6px;
  font-size: 14px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  cursor: pointer;
}
.forgot-password-link {
  display: inline-block;
  margin-top: 12px;
  font-size: 13px;
  font-weight: 700;
  color: var(--vault-blue);
  text-decoration: none;
}
.forgot-password-link:hover { text-decoration: underline; }
.forgot-password-box {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.forgot-password-box input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
}
.forgot-password-box button {
  padding: 9px 14px;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  border: none;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.error {
  /* Not a brand color — semantic error red is a system/utility color, kept outside the brand palette */
  background: #fdecea;
  border: 1px solid #f5c6c2;
  color: #b3261e;
  padding: 10px 12px;
  border-radius: 6px;
  font-size: 13px;
}
.test-accounts {
  margin-top: 20px;
  padding: 12px 14px;
  background: var(--neutral-ivory);
  border: 1px solid var(--stone);
  border-radius: 8px;
  font-size: 12px;
  color: var(--navy);
  line-height: 1.6;
}

/* Brand tagline treatment (guide p.10): Vault Blue text, Golos Extra Bold, all caps, on
   Neutral Ivory only — with the payoff word called out in a rectangular Aqua block. Used
   sparingly (guide: "limit to once per layout") — not something to repeat on every page. */
.brand-tagline {
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--vault-blue);
  font-size: 15px;
  margin: 4px 0 0;
}
.brand-highlight {
  background: var(--aqua);
  color: var(--vault-blue); /* matches the guide's own tagline mockup (p.10/21) — the
    generic accessibility grid on p.14 actually X's every color-on-Aqua text pairing,
    including this one, so the specific tagline example is the more authoritative spec here */
  padding: 1px 7px;
  border-radius: 2px;
}

/* Quick Talk — floating always-on voice button (Rep/Manager pages only). */
.quick-talk-btn {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  border: none;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  font-size: 24px;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
}
.quick-talk-btn:hover { filter: brightness(1.1); }
/* .vault-icon defaults to vault-blue, same as this button's own background — without this
   override the mic icon renders invisible (blue-on-blue) instead of the ivory it should be. */
.quick-talk-btn .vault-icon { color: var(--neutral-ivory); width: 26px; height: 26px; }
.quick-talk-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 37, 62, 0.45);
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.quick-talk-panel {
  background: var(--panel);
  border-radius: 12px;
  width: 100%;
  max-width: 480px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  padding: 18px;
}
.quick-talk-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.quick-talk-header h3 {
  margin: 0;
  color: var(--vault-blue);
  font-family: "Golos Text", Arial, sans-serif;
}
.quick-talk-close {
  background: none;
  border: none;
  font-size: 22px;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: 0 4px;
}
.quick-talk-note {
  font-size: 12px;
  margin: 8px 0 0;
}
.quick-talk-messages {
  /* Hidden per request — no visible running transcript. The underlying message list is
     still tracked in JS (still needed for the conversation-history API calls), this just
     stops rendering it. Errors are surfaced via .quick-talk-status instead so failures
     aren't silently invisible. */
  display: none;
}
.quick-talk-status {
  margin-top: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--vault-blue);
}
.qt-bubble {
  max-width: 85%;
  padding: 8px 12px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.4;
  white-space: pre-wrap;
}
.qt-bubble.rep { align-self: flex-end; background: var(--vault-blue); color: var(--neutral-ivory); border-bottom-right-radius: 3px; }
.qt-bubble.persona { align-self: flex-start; background: var(--neutral-ivory); border: 1px solid var(--border); border-bottom-left-radius: 3px; }
.qt-bubble.typing { align-self: flex-start; color: var(--muted); font-size: 12px; font-style: italic; }
.qt-bubble.error { align-self: stretch; background: #fdecea; border: 1px solid #f5c6c2; color: #b3261e; }

/* Training dashboard widgets — compliance/grade progress bars, on Rep + Manager pages. */
.progress-widget-stats {
  display: flex;
  gap: 24px;
  margin: 10px 0 14px;
}
.progress-stat { text-align: center; }
.progress-stat .num {
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  font-size: 26px;
  color: var(--vault-blue);
  display: block;
}
.progress-stat .label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--muted);
  font-family: "Golos Text", Arial, sans-serif; /* guide: all-caps labels are Golos Bold, not body's Arial */
  font-weight: 700;
}
.progress-bar-track {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  height: 10px;
  overflow: hidden;
}
.charts-row {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 10px;
}
.chart-box {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
}
.chart-box h4 {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--vault-blue);
  font-family: "Golos Text", Arial, sans-serif;
}
.chart-box .chart-canvas-wrap {
  position: relative;
  height: 220px;
}
/* Person/name-by-metric table look — originally local to grading.html (Path Grading Grid +
   Team Compliance), now shared: rep.html/manager.html's "My Grades"/"Class Grades" boxes
   reuse it too, on the same reasoning as the Team Compliance conversion this mirrors (a bar
   chart is fine for spotting an outlier, but "what's the exact number" is what a cell answers
   better than a bar's height can). Promoted here once a third page needed it, same threshold
   this app uses for centralizing anything page-local (see the status-color triad above).

   max-height + overflow: a growing row count shouldn't make the whole page longer — a
   consistent number of rows stays visible (~10-12), the rest reachable by scrolling inside the
   box. The header row is pinned (position: sticky; top: 0) so column labels stay visible while
   scrolling down. The first column is pinned left too (for wide grids with many columns);
   z-index layers it (3) above the plain sticky-top header cells (1) so the top-left corner
   cell, sticky on BOTH axes at once, renders above both directions. */
.grading-grid-wrap { overflow: auto; max-height: 400px; margin-top: 14px; }
/* border-collapse: collapse silently breaks position: sticky on th/td in Chromium — a known
   engine quirk. Separate + border-spacing: 0 keeps the collapsed look while sticky still works. */
.grading-grid-table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13px; }
.grading-grid-table th, .grading-grid-table td {
  border: 1px solid var(--border); padding: 7px 12px; text-align: center; white-space: nowrap;
}
.grading-grid-table th.grading-grid-person-col, .grading-grid-table td.grading-grid-person-col {
  text-align: left; position: sticky; left: 0; background: var(--panel); z-index: 1;
}
/* Sticky top goes on <thead> itself, not individual th/td — sticky positioning on table cells
   doesn't stick in Chromium, the same declaration on the row group does.
   z-index 2 (> the sticky body column's 1) so the header row paints above a scrolled-past body
   row's sticky-left cell. th.grading-grid-person-col bumps to 3 on top of that so the one
   corner cell (sticky on both axes) sits above its own header row's siblings too. */
.grading-grid-table thead { position: sticky; top: 0; z-index: 2; }
.grading-grid-table th { background: var(--panel); }
.grading-grid-table th.grading-grid-person-col { z-index: 3; }
.grading-grid-title-row th { font-weight: 700; color: var(--vault-blue); font-size: 12px; }
.grading-grid-cell-done { color: var(--status-good); font-weight: 700; }
.grading-grid-cell-pending { color: var(--status-warn); }
.grading-grid-cell-missing { color: var(--muted); }
.grading-grid-cell-bad { color: var(--status-bad); font-weight: 700; }
/* Home page — Announcements + Highlight side by side, equal widths. */
.home-highlight-row {
  display: flex;
  gap: 16px;
}
.home-highlight-row .card { margin-top: 0; }
@media (max-width: 900px) {
  .home-highlight-row { flex-direction: column; }
}
.progress-bar-fill {
  background: var(--vault-blue);
  height: 100%;
  border-radius: 6px 0 0 6px;
  transition: width 0.3s ease;
}
.cohort-member-row {
  display: grid;
  grid-template-columns: 140px 1fr 100px;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.cohort-member-row:last-child { border-bottom: none; }
.cohort-member-name { font-size: 13px; font-weight: 700; }
.cohort-member-stats { font-size: 12px; color: var(--muted); text-align: right; }
.cohort-select-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.cohort-select-row select { padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; }
.cohort-manage-box {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.cohort-member-picker {
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px;
  margin: 8px 0;
  font-size: 13px;
}
.cohort-member-picker label { display: block; margin-bottom: 5px; }

/* Shared "pick some resources" checkbox list — reused on assignments.html, practice.html
   (persona + Quick Talk), fieldpro.html, and script-roleplays.html. Previously unstyled
   everywhere except a one-off local copy on assignments.html; now global so every picker
   looks and scrolls the same way. Resources are grouped by category (public/util.js's
   resourcePickerHtml()), same alphabetical grouping resources.html's own folder view uses. */
.resource-picker {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  max-height: 220px;
  overflow-y: auto;
}
.resource-picker label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  padding: 3px 0;
  font-weight: normal;
}
.resource-picker .hint { font-size: 12px; color: var(--muted); margin: 0 0 6px; }
.resource-picker-group { margin-bottom: 10px; }
.resource-picker-group:last-child { margin-bottom: 0; }
.resource-picker-group-title {
  font-size: 11px;
  font-family: "Golos Text", Arial, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  font-weight: 700;
  margin-bottom: 2px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.resource-picker-group:first-child .resource-picker-group-title { padding-top: 0; border-top: none; }

/* Manage Users card (manager.html, admin only) — also used by Grading's Sales Reps/District
   Managers/Other and Signature-Based Submissions module sections (see .user-section-body
   comment below). Each toggle+body pair sits in its own bordered .user-section box so several
   of these stacked in one card read as clearly separated groups, not headings running
   together with only margin between them. */
.user-section {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-top: 10px;
}
.user-section:first-child { margin-top: 0; }
.user-section-toggle {
  /* Now a real <button> (was a plain clickable div) — reset browser button chrome so it
     still looks like a plain text heading. Golos, not "inherit" — this all-caps label is a
     Golos Bold callout per the brand guide, not body copy. */
  display: block;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  text-align: left;
  font-family: "Golos Text", Arial, sans-serif;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--vault-blue);
  font-weight: 700;
  margin: 0 0 6px;
  cursor: pointer;
}
/* Same fixed-height, internally-scrolling treatment as the Grading page's tables — shared by
   Manage Users' Active/Deactivated roster and Grading's Sales Reps/District Managers/Other
   submission sections (both use this class), so a growing headcount scrolls inside the box
   instead of making the whole page longer. The Audit Log section overrides this inline with
   its own max-height, unaffected by this rule. */
.user-section-body { margin-bottom: 4px; max-height: 400px; overflow-y: auto; }
.user-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.user-row:last-child { border-bottom: none; }
.user-row .user-info { font-size: 13px; }
.user-row .user-info .email { color: var(--muted); font-size: 12px; }
.user-row .user-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.user-row .user-actions label { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 4px; font-weight: normal; }
/* The path-name link in each Paths & Certificates row had no styling at all, so it fell back
   to the plain browser default: blue for a link you'd never clicked, purple once you had —
   which Cody noticed and reasonably assumed was intentional (it happened to line up with
   which paths he'd personally opened before). Explicitly setting :visited too, not just the
   base color, so it can never drift back to purple regardless of click history. */
#pathList a, #pathList a:visited { color: var(--vault-blue); text-decoration: none; }
#pathList a:hover { text-decoration: underline; }
/* Same bare-link bug as #pathList above, just never checked for elsewhere — any of these
   linking out to a resource/assignment/path the admin had personally clicked before rendered
   purple instead of matching the rest of the app, since nothing here overrode the browser's
   own default link/visited colors. */
#motwContent a, #motwContent a:visited,
#cohortAssignedPathsList a, #cohortAssignedPathsList a:visited,
.sub-row-body a, .sub-row-body a:visited { color: var(--vault-blue); text-decoration: none; }
#motwContent a:hover, #cohortAssignedPathsList a:hover, .sub-row-body a:hover { text-decoration: underline; }
.password-reset-row { display: flex; gap: 6px; align-items: center; margin-top: 6px; }
.password-reset-row input { padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 12px; }

/* Submission galleries — "My Submissions" and "Vault Submissions" on Rep/Manager pages.
   Thumbnail-forward cards, segmented into sections by submission type. */
.subgallery-section { margin-top: 18px; }
.subgallery-section:first-child { margin-top: 0; }
.subgallery-section-title {
  font-size: 13px;
  font-family: "Golos Text", Arial, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  font-weight: 700;
  margin: 0 0 8px;
}
.subgallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
/* .subgallery-type-select previously had its own bolder/uppercase treatment and a larger
   custom chevron — intentionally distinct at the time, later flagged as a "worth a decision"
   inconsistency since every other native <select> in the app (including this one's own
   sibling dropdowns elsewhere) uses the plain global `select {}` style instead. Cody's call:
   match everything else. No rule needed here anymore — it just inherits the global style. */
.subgallery-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel);
  cursor: pointer;
}
.subgallery-thumb-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  background: var(--navy);
  display: flex;
  align-items: center;
  justify-content: center;
}
.subgallery-thumb-wrap video { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.subgallery-thumb-icon { font-size: 32px; }
/* Wraps 1-2 badges (AI score, and DM score once a manager confirms) — plain inline flex row
   by default (e.g. in the modal header); pinned to the thumbnail's corner and stacked
   vertically only when nested inside a card's thumbnail. */
.subgallery-score-badges { display: flex; gap: 4px; }
.subgallery-thumb-wrap .subgallery-score-badges {
  position: absolute;
  top: 8px;
  right: 8px;
  flex-direction: column;
  align-items: flex-end;
}
.subgallery-score-badge {
  padding: 3px 9px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 800;
  color: #fff;
}
.subgallery-score-badge.score-high { background: var(--status-good); }
.subgallery-score-badge.score-mid { background: var(--status-warn); }
.subgallery-score-badge.score-low { background: var(--status-bad); }
.subgallery-score-badge.score-pending { background: var(--muted); }

/* Shared status-dot / stat-card traffic-light rules — previously copy-pasted verbatim into
   page-local <style> blocks in compliance.html, compliance-user.html, and grading.html. */
.status-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 8px; background: var(--border); }
.status-dot.status-good { background: var(--status-good); }
.status-dot.status-warn { background: var(--status-warn); }
.status-dot.status-bad { background: var(--status-bad); }
.stat-card.status-good { background: #eaf3ea; border-color: #cfe3cf; }
.stat-card.status-good .stat-value { color: var(--status-good); }
.stat-card.status-warn { background: #fff8e6; border-color: #f0e0b0; }
.stat-card.status-warn .stat-value { color: var(--status-warn); }
.stat-card.status-bad { background: #fbeaea; border-color: #f0c0c0; }
.stat-card.status-bad .stat-value { color: var(--status-bad); }
.subgallery-info { padding: 10px; }
.subgallery-info strong { display: block; color: var(--vault-blue); font-size: 14px; }
.subgallery-info span.muted { font-size: 12px; }

/* --- Submission detail modal (public/subgallery.js), opened on card click --- */
.submission-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 37, 62, 0.55);
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.submission-modal-panel {
  background: var(--panel);
  border-radius: 12px;
  width: 100%;
  max-width: 1100px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.submission-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  gap: 12px;
}
.submission-modal-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.submission-modal-title strong { font-size: 16px; color: var(--vault-blue); }
.submission-modal-close-btn {
  background: none;
  border: none;
  font-size: 24px;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: 4px 8px;
  flex-shrink: 0;
}
.submission-modal-close-btn:hover { color: var(--text); }
.submission-modal-body {
  display: flex;
  flex-wrap: wrap;
  overflow: hidden;
  flex: 1;
  min-height: 0;
}
.submission-modal-video-wrap {
  flex: 1 1 55%;
  background: var(--navy);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 280px;
}
.submission-modal-video-wrap video {
  width: 100%;
  height: 100%;
  max-height: 80vh;
  object-fit: contain;
}
.submission-modal-feedback {
  flex: 1 1 45%;
  display: flex;
  flex-direction: column;
  min-width: 280px;
  border-left: 1px solid var(--border);
}
.submission-modal-feedback-section {
  flex: 1;
  padding: 16px 18px;
  overflow-y: auto;
  min-height: 0;
}
.submission-modal-feedback-section + .submission-modal-feedback-section {
  border-top: 1px solid var(--border);
}
.submission-modal-feedback-title {
  font-size: 12px;
  font-family: "Golos Text", Arial, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  font-weight: 700;
  margin: 0 0 8px;
}

/* Compact assignment cards — assignments.html. A collapsed tile per assignment (thumbnail +
   title); clicking expands the full instructions/submit-form content in place below it. */
.assignment-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}
.assignment-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel);
}
/* flex: 1 lets the header grow to fill whatever height the grid row stretches the card to
   (same fix as .folder-card-open), so the Edit/Duplicate row below it lands at the same
   bottom edge on every card in the row regardless of how many lines a given title wraps to. */
.assignment-card-header {
  cursor: pointer;
  flex: 1;
}
.assignment-card-thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  background: var(--vault-blue); /* guide: reversed logo only approved on Vault Blue, not Navy */
  display: flex;
  align-items: center;
  justify-content: center;
}
.assignment-card-thumb img { width: 70%; object-fit: contain; }
.assignment-card-icon {
  position: absolute;
  bottom: 8px;
  right: 8px;
  font-size: 18px;
  background: rgba(255, 255, 255, 0.88);
  border-radius: 50%;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.assignment-card-title {
  padding: 10px;
  font-weight: 700;
  color: var(--vault-blue);
  font-size: 14px;
}
/* Same treatment as .folder-card-actions — a centered small-button row under the card's own
   content, admin-only. */
.assignment-card-actions { display: flex; gap: 6px; justify-content: center; padding: 0 10px 10px; }
.assignment-card-expanded {
  border-top: 1px solid var(--border);
  padding: 14px;
}

/* Script Role-Plays — drag handle on each card's header (title row only), used for
   reordering within a category bucket. A narrow grab target so it never fights with
   clicking the audio player or Edit/Remove buttons below it. */
.roleplay-card-header { cursor: grab; }
.roleplay-card-header:active { cursor: grabbing; }
.drag-handle { color: var(--muted); font-size: 14px; }
/* A category can hold any number of role-plays, so past a max height the list scrolls
   internally instead of pushing the rest of the page down — same convention as the Grading
   page's Sales Reps/District Managers/Other lists. Taller than those (each entry here is a
   full audio player + transcript toggle, not a single row) so at least 2 full cards are
   visible before scrolling kicks in. */
.roleplay-bucket-list { max-height: 640px; overflow-y: auto; padding: 2px; }
/* Each role-play its own bordered card — previously just ran together with no border between
   entries, relying on the Download/Show transcript row alone to imply a break. Scoped to
   .roleplay-bucket-list rather than bare .sub-block — that class is shared with
   grading-user.html and fieldpro.html, which have their own (different, partial) .sub-block
   styling; a bare rule here would only partly be overridden by those pages' local <style>
   blocks (e.g. grading-user.html's own rule only sets border-bottom/padding, so this border's
   other 3 sides and border-radius would still leak through) rather than cleanly co-existing. */
.roleplay-bucket-list .sub-block {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  margin-top: 12px;
}
.roleplay-bucket-list .sub-block:first-child { margin-top: 0; }

/* "Manage Categories" columns — assignments.html. Each category (plus a permanent
   Uncategorized column) holds small draggable chips; dropping a chip on a different
   column moves that assignment into it. */
.category-manage-columns {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.category-manage-column {
  flex: 0 0 200px;
  /* Without this, a flex item's default min-width:auto lets its content refuse to shrink
     below its own natural size, overriding flex-basis — exactly what let one column
     ("Interactive Modules", holding a chip titled "Salesperson Code of Conduct Interactive
     Module") render at 339px while every sibling stayed at the intended 204px. That single
     wide column was the actual reason Save/Delete looked "consistent" there and wrapped to
     a second line everywhere else — see .category-chip-label below for the deeper fix. */
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel);
  padding: 10px;
}
/* Name input and Save/Delete now always stack on their own rows — deterministic layout
   instead of flex-wrap's fragile "does it fit on one line" threshold, which is what let
   different columns render their buttons differently even at the same width. */
.category-manage-header {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 8px;
}
.category-manage-header .category-name-input {
  width: 100%;
  box-sizing: border-box;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
}
.category-manage-header-actions { display: flex; gap: 4px; }
.category-manage-header-actions .small-btn { flex: 1; }
.category-manage-chips {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 40px;
}
/* Flat single row (label + delete) — no Edit here anymore, so there's no second row to stack
   above/below (see the render function's own comment for why). */
.category-chip {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  padding: 6px 8px;
  font-size: 12px;
  cursor: grab;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.category-chip:active { cursor: grabbing; }
.category-chip-label {
  /* flex:1 + min-width:0 is what actually makes the overflow/ellipsis below take effect — a
     flex item's default min-width:auto means it won't shrink below its own content's natural
     width no matter what overflow says, so a long unbroken title (confirmed live: this label's
     scrollWidth already equalled its clientWidth, meaning truncation was never firing at all)
     just pushed its whole chip, and the column containing it, wider instead of actually
     truncating. */
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.category-chip-delete {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 14px;
  cursor: pointer;
  flex-shrink: 0;
  padding: 2px 4px;
}
.category-chip-delete:hover { color: #b3261e; }

/* ===================================================================
   Design-system pass (2026-07-20) — brand-guide-grounded visual work:
   a real icon set instead of emoji, custom-styled form controls instead
   of raw browser defaults, a branded confirm dialog instead of the native
   confirm(), and a loading skeleton instead of plain "Loading…" text.
   =================================================================== */

/* --- Icon set (public/icons.js) — inline SVGs colored via currentColor,
   so `color` on this element (or an ancestor) sets the icon color. Per
   the brand guide, icons should read as one consistent set: same size,
   same stroke weight, kept to Vault Blue / Navy / Ivory / Aqua-on-dark. */
.vault-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1em;
  height: 1em;
  color: var(--vault-blue);
  vertical-align: -0.15em;
}
.vault-icon svg { width: 100%; height: 100%; display: block; }

input[type="checkbox"], input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  border: 1.5px solid var(--border);
  background: var(--panel);
  display: inline-block;
  vertical-align: middle;
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
}
input[type="checkbox"] { border-radius: 4px; }
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"]:checked, input[type="radio"]:checked {
  border-color: var(--vault-blue);
  background: var(--vault-blue);
}
input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 5px;
  height: 9px;
  border: solid var(--neutral-ivory);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
input[type="radio"]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 4px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--neutral-ivory);
}
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible {
  outline: 2px solid var(--aqua);
  outline-offset: 1px;
}

/* --- Branded confirm dialog (public/confirmDialog.js), replacing native confirm() --- */
.confirm-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 37, 62, 0.45);
  z-index: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.confirm-panel {
  background: var(--panel);
  border-radius: 12px;
  max-width: 400px;
  width: 100%;
  padding: 20px;
}
.confirm-message {
  margin: 0 0 18px;
  color: var(--text);
  font-size: 15px;
  line-height: 1.5;
  white-space: pre-wrap;
}
.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.confirm-cancel-btn, .confirm-ok-btn {
  padding: 9px 16px;
  border-radius: 6px;
  font-size: 13px;
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  cursor: pointer;
  border: none;
}
.confirm-cancel-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
}
.confirm-ok-btn {
  background: var(--vault-blue);
  color: var(--neutral-ivory);
}
.confirm-ok-btn.danger {
  /* Semantic error red — a system/utility color, not a brand color, same exception
     already used for .error elsewhere in this file. */
  background: #b3261e;
}

/* --- "Get the App on Your Phone" — a quiet, muted trigger (never styled like a primary CTA;
   Cody's explicit ask was "not very front and center") that either fires the real Android
   install prompt or, on iOS where no such API exists, opens an instructions panel reusing
   .confirm-overlay/.confirm-panel as-is rather than inventing a second modal pattern. */
.pwa-install-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  color: var(--muted);
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 4px 0;
}
.pwa-install-trigger:hover { color: var(--vault-blue); }
.pwa-install-trigger svg { width: 15px; height: 15px; }
.pwa-install-panel {
  text-align: center;
}
.pwa-install-icon {
  width: 56px;
  height: 56px;
  border-radius: 12px;
  margin: 0 auto 14px;
  display: block;
}
.pwa-install-title {
  margin: 0 0 16px;
  color: var(--vault-blue);
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  font-size: 15px;
}
.pwa-install-steps {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pwa-install-steps li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--text);
  line-height: 1.4;
}
.pwa-install-steps svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--vault-blue);
}
.pwa-install-close-btn {
  width: 100%;
  padding: 10px;
  border-radius: 6px;
  border: none;
  background: var(--vault-blue);
  color: var(--neutral-ivory);
  font-family: "Golos Text", Arial, sans-serif;
  font-weight: 800;
  font-size: 13px;
  text-transform: uppercase;
  cursor: pointer;
}

/* --- Loading skeleton — replaces plain "Loading…" text with a subtle shimmering
   placeholder block in brand-neutral tones. Usage: '<div class="skeleton-line"></div>'
   (repeat for multiple lines/rows). */
@keyframes skeleton-shimmer {
  0% { background-position: -200px 0; }
  100% { background-position: calc(200px + 100%) 0; }
}
.skeleton-line {
  height: 14px;
  border-radius: 4px;
  margin: 8px 0;
  background: linear-gradient(90deg, var(--stone) 0%, #e4dfe0 50%, var(--stone) 100%);
  background-size: 200px 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
  opacity: 0.5;
}
.skeleton-line.short { width: 40%; }
.skeleton-line.medium { width: 70%; }

/* --- Empty states — an icon over a message instead of a bare line of muted text.
   Usage: emptyState("inbox", "No announcements yet.") from icons.js. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 20px 12px;
  text-align: center;
}
.empty-state .vault-icon {
  font-size: 26px;
  color: var(--stone);
}
.empty-state p.muted {
  margin: 0;
}

/* --- My Paths tiles — rep.html/manager.html. Assigned courses (cohorts with Week/Day
   content) the logged-in person must complete, linking to /path/:id. */
.path-tile-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.path-tile {
  flex: 1;
  min-width: 220px;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  text-decoration: none;
  color: inherit;
  display: block;
  background: var(--panel);
}
.path-tile:hover { border-color: var(--vault-blue); }
.path-tile .path-tile-name { font-weight: 700; color: var(--vault-blue); }
.path-tile .path-tile-host { font-size: 12px; color: var(--muted); margin: 2px 0 8px; }
.path-tile .path-tile-progress { font-size: 12px; color: var(--muted); }

/* --- Rich text (Quill) — editing chrome + static rendered output for the long-form
   content fields (assignment instructions/grading criteria, FAQ answers, resource/path
   descriptions, FieldPro notes, submission comments). Rendered output reuses Quill's own
   .ql-editor class (from the CDN stylesheet) for list/alignment styling, minus the
   editor-only border/background, so editing and display always look consistent. */
.rich-editor-mount {
  background: #fff;
  border-radius: 6px;
  margin-bottom: 4px;
}
.rich-editor-mount .ql-toolbar {
  border-color: var(--border);
  border-radius: 6px 6px 0 0;
}
.rich-editor-mount .ql-container {
  border-color: var(--border);
  border-radius: 0 0 6px 6px;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 14px;
}
.rich-content.ql-editor {
  padding: 0;
  font-family: Arial, Helvetica, sans-serif;
  font-size: inherit;
  white-space: normal;
}
.rich-content.ql-editor p { margin: 0 0 6px; }

/* --- Certificate card — the actual visual design (double border navy/aqua, boxed "Certificate
   of Completion" eyebrow, real Vault logo, single V watermark, signature-style name line with
   diamond markers, two-column Date/Signer footer, "Consider it Covered" tagline). Shared here
   so both the real per-rep certificate popup (path.html) and the Certificate Bank preview
   (cohorts.html) render the identical design — only the modal chrome around it (overlay,
   close button, print button) stays page-specific since only path.html needs those. */
.certificate-frame { background: var(--navy); padding: 8px; border-radius: 4px; }
.certificate-inner {
  background: var(--neutral-ivory); border: 3px solid var(--aqua); border-radius: 2px;
  padding: 36px 44px; position: relative; overflow: hidden; text-align: center;
}
.certificate-watermark {
  position: absolute; top: 50%; left: 50%; width: 65%;
  transform: translate(-50%, -50%); pointer-events: none;
}
.certificate-content { position: relative; z-index: 1; }
.certificate-eyebrow-box {
  display: inline-block; border-top: 1.5px solid var(--vault-blue); border-bottom: 1.5px solid var(--vault-blue);
  padding: 4px 22px; margin: 0 auto 16px;
}
.certificate-eyebrow-box span {
  font-size: 11px; font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase; color: var(--vault-blue);
  font-family: "Golos Text", Arial, sans-serif;
}
.certificate-logo { height: 50px; margin: 0 auto 16px; display: block; }
.certificate-headline {
  font-family: "Golos Text", Arial, sans-serif; font-weight: 800; color: var(--navy);
  margin: 0 0 14px; font-size: 42px; line-height: 1;
}
.certificate-certifies-line { margin: 0 0 4px; font-size: 14px; color: var(--vault-blue); }
.certificate-name-line {
  position: relative; border-bottom: 2px solid var(--vault-blue);
  margin: 0 auto 16px; padding-bottom: 6px; max-width: 420px;
}
.certificate-name-line::before, .certificate-name-line::after {
  content: "◆"; color: var(--vault-blue); position: absolute; bottom: -7px; font-size: 12px;
  /* was var(--aqua) — Aqua text on Neutral Ivory is a rejected pairing per the guide's
     accessibility grid; matches the adjacent border/eyebrow colors instead. */
}
.certificate-name-line::before { left: -18px; }
.certificate-name-line::after { right: -18px; }
.certificate-name {
  font-family: "Golos Text", Arial, sans-serif; font-weight: 700; font-size: 20px; color: var(--navy);
}
.certificate-body-text { margin: 0 0 24px; font-size: 13px; color: var(--vault-blue); line-height: 1.5; }
.certificate-footer-row { display: flex; justify-content: space-between; gap: 30px; margin-bottom: 20px; }
.certificate-footer-col { flex: 1; text-align: center; }
.certificate-footer-line {
  border-bottom: 1.5px solid var(--vault-blue); padding-bottom: 4px; margin-bottom: 4px;
  min-height: 20px; font-family: "Golos Text", Arial, sans-serif; font-weight: 700; color: var(--navy); font-size: 15px;
}
.certificate-footer-label {
  margin: 0; font-size: 10px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--vault-blue);
  font-family: "Golos Text", Arial, sans-serif;
}
.certificate-tagline { margin: 0; }

/* Certificate Bank preview — a shrunk, non-interactive rendering of the same certificate-frame
   markup at its native 720px design width, scaled down with `zoom` (simplest way to shrink an
   absolute-px design proportionally; Chromium/Edge/Safari support it, which covers this app's
   actual users). */
.certificate-preview-wrap { zoom: 0.55; width: 720px; margin: 10px 0; pointer-events: none; }
/* At 0.55 this renders ~396px wide — fine anywhere above phone width, but wider than a
   375px screen itself, pushing the whole page into horizontal scroll. Shrink it further
   below ~480px so the preview (never interactive — pointer-events: none) fits the screen
   instead of overflowing it. */
@media (max-width: 480px) {
  .certificate-preview-wrap { zoom: 0.44; }
}
.rich-content.ql-editor p:last-child { margin-bottom: 0; }
