/* ===================================================================
   Textbook Companion — Design System v2
   Candesic brand: Montserrat, #0069B4 blue, #FEC601 gold, #161924 navy
   =================================================================== */

/* --- Montserrat from Google Fonts --- */
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap');

/* --- CSS Custom Properties --- */
:root {
  --color-primary: #0069B4;
  --color-primary-dark: #00507f;
  --color-primary-light: #e8f4fd;
  --color-primary-50: #f0f7fc;
  --color-accent: #0072BC;
  --color-accent-dark: #005a96;

  --color-navy: #161924;
  --color-navy-mid: #252a3d;
  --color-navy-light: #3c4051;
  --color-text: #212121;
  --color-text-secondary: #5f6368;
  --color-text-light: #9e9e9e;
  --color-surface: #ffffff;
  --color-bg: #f5f7fa;
  --color-border: #e0e4e8;
  --color-border-light: #eef1f5;

  --color-success: #0f8a4f;
  --color-success-bg: #e6f4ed;
  --color-error: #d32f2f;
  --color-error-bg: #fde8e8;
  --color-warning: #e6a200;
  --color-warning-bg: #fff8e1;

  --font-body: 'Montserrat', -apple-system, "Segoe UI", sans-serif;
  --container-max: 1100px;
  --container-wide: 1400px;
  --navbar-h: 68px;
  --radius: 10px;
  --radius-sm: 6px;
  --radius-pill: 999px;
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.06);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.08);
  --shadow-lg: 0 8px 24px rgba(0,0,0,0.12);
  --shadow-card: 0 2px 6px rgba(0,0,0,0.05);
  --transition: 200ms ease;
  --transition-slow: 400ms ease;
}

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--font-body);
  line-height: 1.65;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  margin: 0;
  /* Sticky footer. Without this the footer sits directly under the content,
     so a short page (an empty Resources list, the login form) left it stranded
     mid-screen with blank space beneath it. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body > main { flex: 1 0 auto; }
body > .footer { flex-shrink: 0; }
a { color: var(--color-primary); text-decoration: none; transition: color var(--transition); }
a:hover { color: var(--color-primary-dark); }
img { max-width: 100%; display: block; }
ul, ol { list-style: none; }
button, input, select, textarea { font-family: inherit; font-size: inherit; }
:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* ===================================================================
   LAYOUT
   =================================================================== */
/* width:100% is load-bearing, not decoration. `body` is a flex column for the
   sticky footer, and a flex item with auto cross-axis margins does not stretch
   — the spec sizes it to fit-content instead. So `margin: 0 auto` alone made
   every page as wide as whatever happened to be inside it: dense pages hit the
   1100px cap and looked right, sparse ones (an empty admin list) shrank and
   re-centred, moving the sidebar and every heading with them. */
.container { width: 100%; max-width: var(--container-max); margin: 0 auto; padding: 2.5rem 2rem; }

/* Admin pages get a wider cap than reader pages, and deliberately so. A reader
   page is prose, where a short line length is the point; an admin page is a
   sidebar plus a five-column table, and at the reader width the sidebar eats a
   fifth of it and the table starts wrapping cells that have no business
   wrapping. Same `margin: 0 auto`, so it stays centred -- only the ceiling
   changes. */
.container-wide { max-width: var(--container-wide); }

/* ===================================================================
   NAVBAR — transparent over hero, solid on scroll
   =================================================================== */
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 2.5rem;
  height: 68px;
  background: var(--color-navy);
  position: sticky;
  top: 0;
  z-index: 100;
  transition: background 0.4s ease, box-shadow 0.4s ease;
}
/* When over the hero on home page, the JS adds .navbar--transparent */
.navbar--transparent { background: transparent; box-shadow: none; }
/* Scrolling past the hero lands on the same navy every other page uses, so the
   bar has exactly two appearances: transparent over the hero, or navy. It used
   to turn white here and light blue once signed in, which is why no two pages
   looked alike. */
.navbar--scrolled { background: var(--color-navy); box-shadow: 0 1px 8px rgba(0,0,0,0.18); }

.nav-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 700;
  font-size: 1.05rem;
  color: #fff;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
/* Wiley leads the lockup, Candesic supports it. Marc's ask, and the reason is
   positioning rather than taste: he wants Wiley staff and readers to read this
   as a Wiley property that Candesic runs, not a Candesic site about a book.

   The two files have very different aspect ratios -- Candesic is a 6.7:1
   wordmark, Wiley a 3.1:1 stacked mark -- so matching them by height alone
   leaves Candesic three times wider. Wiley is therefore set taller than
   Candesic, which is what brings the two to comparable visual weight. */
.nav-brand img { height: 26px; width: auto; }
.nav-brand img.nav-wiley-logo { height: 38px; width: auto; }
.nav-brand-sep { font-size: 1.4rem; color: #8a9bb0; margin: 0 0.15rem; line-height: 1; user-select: none; }
.nav-links { display: flex; align-items: center; gap: 0.15rem; }
.nav-links a {
  color: rgba(255,255,255,0.9);
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0.45rem 0.85rem;
  border-radius: var(--radius-pill);
  transition: background var(--transition), color var(--transition);
}
.nav-links a:hover,
.nav-links a.active { background: rgba(255,255,255,0.15); color: #fff; }
.nav-links a.nav-cta {
  background: var(--color-accent);
  color: var(--color-navy);
  font-weight: 600;
}
.nav-links a.nav-cta:hover { background: var(--color-accent-dark); }
.nav-user {
  display: flex;
  align-items: center;
  margin-left: 0.5rem;
  padding-left: 0.75rem;
  border-left: 1px solid rgba(255,255,255,0.2);
}

/* Account control: avatar, name, caret. One target instead of two links. */
.nav-account {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: rgba(255,255,255,0.9);
  background: none;
  border: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background var(--transition);
}
.nav-account:hover { background: rgba(255,255,255,0.15); color: #fff; }
.nav-caret { opacity: 0.7; flex-shrink: 0; transition: transform var(--transition); }
.nav-account[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }

.account-menu { min-width: 232px; padding: 6px; }
.account-head {
  margin: 0 0 4px;
  padding: 8px 10px 10px;
  border-bottom: 1px solid var(--color-border-light);
}
.account-name { display: block; font-size: 13.5px; font-weight: 600; color: var(--color-text); }
.account-email { display: block; font-size: 12px; color: var(--color-text-secondary); }
.account-menu .menu-item { display: block; text-decoration: none; }

/* Hamburger */
.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
  color: #fff;
}
.nav-toggle span {
  display: block;
  width: 24px;
  height: 2px;
  background: currentColor;
  margin: 5px 0;
  border-radius: 2px;
  transition: transform var(--transition), opacity var(--transition);
}
.nav-toggle.open span:nth-child(1) { transform: rotate(45deg) translate(5px, 5px); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: rotate(-45deg) translate(5px, -5px); }

/* ===================================================================
   FOOTER
   =================================================================== */
.footer {
  background: var(--color-navy);
  color: rgba(255,255,255,0.6);
  padding: 2.5rem 2rem;
  text-align: center;
  font-size: 0.85rem;
  /* auto, not a fixed gap: on a short page flex pushes it to the bottom; on a
     long one it still clears the content. */
  margin-top: auto;
}
.footer a { color: rgba(255,255,255,0.8); }
.footer a:hover { color: var(--color-accent); }

/* ===================================================================
   HERO — dark gradient, full-width, bold typography
   =================================================================== */
.hero {
  background: linear-gradient(135deg, var(--color-navy) 0%, #0c2340 50%, var(--color-primary-dark) 100%);
  color: #fff;
  text-align: center;
  padding: calc(5rem + var(--navbar-h)) 2rem 4.5rem;
  width: 100vw;
  margin-top: calc(-2.5rem - var(--navbar-h));
  margin-left: calc(50% - 50vw);
  margin-right: 0;
  margin-bottom: 2.5rem;
  position: relative;
}
/* subtle overlay texture */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 30% 20%, rgba(0,105,180,0.2) 0%, transparent 60%);
  pointer-events: none;
}
.hero > * { position: relative; z-index: 1; }
.hero h1 {
  font-size: 2.75rem;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: #fff;
  margin-bottom: 0.5rem;
  line-height: 1.15;
}
.hero .subtitle {
  font-size: 1.2rem;
  color: var(--color-accent);
  font-weight: 600;
  margin-bottom: 1rem;
  letter-spacing: 0.02em;
}
.hero-description {
  max-width: 600px;
  margin: 0 auto 2rem;
  color: rgba(255,255,255,0.8);
  font-size: 1rem;
  line-height: 1.7;
  font-weight: 400;
}
.hero-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
}
/* Solid white, navy text. The hero is a dark blue gradient, so this is the only
   fill on the palette that is unambiguously the primary action -- the previous
   accent-blue-on-blue with navy text was the lowest-contrast button of the four
   and read as disabled. */
.btn-hero-primary {
  background: #fff;
  color: var(--color-navy);
  font-weight: 600;
  padding: 0.75rem 2rem;
  font-size: 0.95rem;
  box-shadow: 0 2px 10px rgba(0,0,0,0.18);
}
.btn-hero-primary:hover { background: #eaf2f8; color: var(--color-navy); }

.hero .btn-secondary {
  background: transparent;
  color: #fff;
  border: 2px solid rgba(255,255,255,0.4);
  padding: 0.7rem 2rem;
  font-size: 0.95rem;
}
.hero .btn-secondary:hover { border-color: #fff; background: rgba(255,255,255,0.1); color: #fff; }

/* Buying the book is a different decision from using the site, and it leaves
   for Wiley or Amazon. Its own row, below the site actions and lighter than
   them, with a label so the two small buttons do not need to carry "Buy on". */
.hero-buy {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-top: 1.5rem;
}

.hero-buy-label {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.6);
  margin-right: 0.15rem;
}

/* ===================================================================
   BUTTONS
   =================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.65rem 1.5rem;
  border-radius: var(--radius-pill);
  font-size: 0.88rem;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: background var(--transition), box-shadow var(--transition), transform 100ms ease;
  line-height: 1.4;
  text-decoration: none;
}
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn.loading { opacity: 0.6; cursor: not-allowed; pointer-events: none; }

.btn-primary {
  background: var(--color-primary);
  color: #fff;
  box-shadow: 0 2px 6px rgba(0,105,180,0.2);
}
.btn-primary:hover { background: var(--color-primary-dark); box-shadow: 0 4px 12px rgba(0,105,180,0.25); color: #fff; }
.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}
.btn-secondary:hover { background: var(--color-bg); border-color: #c0c0c0; color: var(--color-text); }
.btn-ghost { background: transparent; color: var(--color-primary); }
.btn-ghost:hover { background: var(--color-primary-light); }
.btn-sm { padding: 0.35rem 0.9rem; font-size: 0.78rem; }
.btn-approve { background: var(--color-success); color: #fff; }
.btn-approve:hover { background: #0a7040; color: #fff; }
.btn-reject { background: var(--color-error); color: #fff; }
.btn-reject:hover { background: #b71c1c; color: #fff; }

/* ===================================================================
   CARDS
   =================================================================== */
/* auto-fit, not auto-fill. auto-fill keeps the empty tracks, so two cards in a
   three-track row sat hard left with a third of the page blank beside them --
   which is what made Resources and Quizzes read as narrower than every other
   page even though the container is identical. auto-fit collapses the empty
   track and the real cards take the width. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1.5rem;
  margin: 2rem 0;
}
.feature-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 2rem;
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--transition), transform var(--transition);
}
.feature-card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
.feature-card h3 {
  font-size: 1.1rem;
  font-weight: 700;
  margin-bottom: 0.6rem;
  color: var(--color-navy);
}
.feature-card p {
  font-size: 0.9rem;
  color: var(--color-text-secondary);
  line-height: 1.65;
}

.file-card, .quiz-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.75rem;
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--transition);
  display: flex;
  flex-direction: column;
}
.file-card:hover, .quiz-card:hover { box-shadow: var(--shadow-md); }
.quiz-card:hover { transform: translateY(-3px); }
.file-card h3, .quiz-card h3 { font-size: 1.05rem; font-weight: 600; color: var(--color-navy); margin-bottom: 0.5rem; }
.file-meta { font-size: 0.8rem; color: var(--color-text-light); margin-bottom: 1.25rem; }
.resource-card { display: flex; flex-direction: column; }
.resource-desc { font-size: 0.9rem; color: var(--color-text); line-height: 1.55; flex: 1; margin-bottom: 0.75rem; }
.resource-meta { font-size: 0.78rem; color: var(--color-text-secondary); margin-bottom: 1rem; }
.quiz-card p { font-size: 0.9rem; color: var(--color-text-secondary); margin-bottom: 1.25rem; flex: 1; }
/* .resource-card was missing from this list. It is a column flex container, so
   its button stretched to the full card width. That went unnoticed while cards
   were a third of the page; once a lone card fills the row the button became a
   1100px bar. */
.file-card .btn, .quiz-card .btn { margin-top: auto; align-self: flex-start; }
/* The resource card now holds two buttons side by side, so the row is what
   pushes to the bottom rather than a single stretched button. */
.resource-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: auto; align-items: center; }
.resource-actions .btn { margin-top: 0; }

/* ===================================================================
   FORMS
   =================================================================== */
.form-group { margin-bottom: 1rem; }
.form-group label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: 0.3rem;
}
.form-group .form-hint { font-size: 0.78rem; color: var(--color-text-light); margin-top: 0.2rem; }

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="tel"],
input[type="url"],
input[type="file"],
select,
textarea {
  display: block;
  width: 100%;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  background: var(--color-surface);
  color: var(--color-text);
  transition: border-color var(--transition), box-shadow var(--transition);
}
input:focus, select:focus, textarea:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(0,105,180,0.1);
  outline: none;
}
textarea { resize: vertical; min-height: 80px; }
select { cursor: pointer; }

.auth-form {
  max-width: 440px;
  margin: 2.5rem auto;
  background: var(--color-surface);
  padding: 2.5rem 2rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  border: none;
  border-top: 3px solid var(--color-accent);
}
.auth-form h1 {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--color-navy);
  margin-bottom: 1.75rem;
  text-align: center;
}
.auth-form .form-footer {
  text-align: center;
  margin-top: 1.5rem;
  font-size: 0.85rem;
  color: var(--color-text-secondary);
}
.auth-form button[type="submit"] {
  width: 100%;
  padding: 0.75rem;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-size: 0.95rem;
  font-weight: 600;
  margin-top: 0.75rem;
  transition: background var(--transition);
}
.auth-form button[type="submit"]:hover { background: var(--color-primary-dark); }

/* Auth page — heading above card */
.auth-page { max-width: 480px; margin: 2.5rem auto; }
.auth-page .auth-form { margin: 0; max-width: none; }
.auth-header { text-align: center; margin-bottom: 1.75rem; }
.auth-title {
  font-size: 1.85rem;
  font-weight: 700;
  color: var(--color-navy);
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin-bottom: 0.4rem;
}
.auth-tagline { font-size: 0.92rem; color: var(--color-text-secondary); line-height: 1.5; }
.auth-form .form-group { margin-bottom: 1.25rem; }

/* ===================================================================
   ALERTS
   =================================================================== */
.alert, .error, .alert-error {
  padding: 0.75rem 1rem;
  border-radius: var(--radius-sm);
  margin-bottom: 1.25rem;
  font-size: 0.88rem;
}
.error, .alert-error {
  color: var(--color-error);
  background: var(--color-error-bg);
  border: 1px solid rgba(211,47,47,0.15);
}
.success, .alert-success {
  color: var(--color-success);
  background: var(--color-success-bg);
  border: 1px solid rgba(15,138,79,0.15);
  border-left: 3px solid var(--color-success);
  padding: 0.75rem 1rem;
  border-radius: var(--radius-sm);
  margin-bottom: 1.25rem;
  font-size: 0.88rem;
}

/* ===================================================================
   DATA TABLES
   =================================================================== */
.data-table {
  width: 100%;
  border-collapse: collapse;
  margin: 1rem 0;
  background: var(--color-surface);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.data-table th, .data-table td {
  padding: 0.75rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--color-border-light);
  font-size: 0.85rem;
}
.data-table th {
  background: var(--color-navy);
  color: #fff;
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.data-table tbody tr { transition: background var(--transition); }
.data-table tbody tr:hover { background: var(--color-primary-50); }
.data-table tbody tr:last-child td { border-bottom: none; }
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--radius); }

/* ===================================================================
   NEWS
   =================================================================== */
.news-post {
  background: var(--color-surface);
  padding: 1.75rem;
  border-radius: var(--radius);
  border-left: 4px solid var(--color-primary);
  margin: 1.25rem 0;
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--transition);
}
.news-post:hover { box-shadow: var(--shadow-md); }
/* margin-top: 0 matters. The global `h2 { margin-top: 2rem }` was landing
   inside the card on top of its own 1.75rem of padding, which is where the
   band of white above every post title came from. */
.news-post h2 { font-size: 1.15rem; font-weight: 600; color: var(--color-navy); margin: 0 0 0.3rem; }
.news-post time { font-size: 0.78rem; color: var(--color-text-light); display: block; margin-bottom: 0.75rem; }
.post-body { font-size: 0.9rem; color: var(--color-text-secondary); line-height: 1.7; }

/* ===================================================================
   FAQ
   =================================================================== */
.faq-topic { margin: 2rem 0; }
/* h3 since 2026-07-30: the topic now sits under a section heading, so it dropped
   a level. Both selectors are kept so the rule survives either markup. */
.faq-topic h2,
.faq-topic h3 {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-navy);
  margin-bottom: 0.75rem;
  padding-bottom: 0.5rem;
  border-bottom: 3px solid var(--color-accent);
  display: inline-block;
}
.faq-item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin: 0.6rem 0;
  overflow: hidden;
  transition: box-shadow var(--transition);
}
.faq-item:hover { box-shadow: var(--shadow-sm); }
.faq-item summary {
  cursor: pointer;
  font-weight: 600;
  padding: 1rem 1.25rem;
  font-size: 0.92rem;
  color: var(--color-navy);
  display: flex;
  justify-content: space-between;
  align-items: center;
  list-style: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+";
  font-size: 1.3rem;
  font-weight: 300;
  color: var(--color-accent);
  flex-shrink: 0;
  margin-left: 1rem;
  transition: transform var(--transition);
}
.faq-item[open] summary::after { content: "\2212"; }
.faq-answer {
  padding: 0 1.25rem 1.25rem;
  font-size: 0.9rem;
  color: var(--color-text-secondary);
  line-height: 1.7;
  border-top: 1px solid var(--color-border-light);
  padding-top: 1rem;
}

/* ===================================================================
   QUIZ
   =================================================================== */
.quiz-progress { color: var(--color-text-secondary); font-size: 0.85rem; margin-bottom: 0.5rem; }
.progress-bar {
  height: 6px;
  background: var(--color-border);
  border-radius: 3px;
  margin-bottom: 1.75rem;
  overflow: hidden;
}
.progress-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--color-primary), var(--color-accent));
  border-radius: 3px;
  transition: width var(--transition-slow);
}

.quiz-form {
  background: var(--color-surface);
  padding: 2.5rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.question-text { font-size: 1.1rem; font-weight: 500; margin-bottom: 1.5rem; color: var(--color-text); line-height: 1.6; }

.mcq-options { display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 1.75rem; }
.mcq-option {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.9rem 1.1rem;
  background: var(--color-bg);
  border: 2px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
  font-size: 0.92rem;
  line-height: 1.5;
}
.mcq-option:hover { border-color: var(--color-primary); background: var(--color-primary-light); }
.mcq-option input[type="radio"] { width: auto; margin-top: 3px; accent-color: var(--color-primary); flex-shrink: 0; outline: none; }
.mcq-option input[type="radio"]:focus,
.mcq-option input[type="radio"]:focus-visible { outline: none; box-shadow: none; }
.mcq-option:focus-within { border-color: var(--color-accent); box-shadow: 0 0 0 2px var(--color-accent); }
.mcq-option.selected { border-color: var(--color-primary); background: var(--color-primary-light); box-shadow: 0 0 0 1px var(--color-primary); }
.mcq-option.selected:focus-within { box-shadow: 0 0 0 2px var(--color-accent); }

.numerical-input { margin-bottom: 1.5rem; }
.numerical-input label { display: block; font-weight: 600; margin-bottom: 0.3rem; font-size: 0.88rem; }
.numerical-input input { max-width: 240px; }

.feedback { padding: 1.75rem; border-radius: var(--radius); margin: 1.5rem 0; }
.feedback.correct { background: var(--color-success-bg); border: 1px solid rgba(15,138,79,0.2); }
.feedback.incorrect { background: var(--color-error-bg); border: 1px solid rgba(211,47,47,0.2); }
.feedback strong { font-size: 1.05rem; display: block; margin-bottom: 0.5rem; }
.feedback .correct-answer { font-weight: 600; margin: 0.5rem 0; }
.feedback .explanation {
  font-style: italic;
  color: var(--color-text-secondary);
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid rgba(0,0,0,0.06);
  font-size: 0.88rem;
  line-height: 1.65;
}
.feedback .btn { margin-top: 1.25rem; }

/* Left-aligned, not centred. The 680px column is right for answering one
   question at a time, but centring it inside the page container moved the h1
   ~150px right of where it sits on every other page, so the title jumped as you
   went from Quizzes into a quiz. The column stays; only the offset goes. */
/* No max-width. This was 680px, which left a quiz card floating in the left
   two thirds of the page with dead space beside it -- the same complaint as
   the eight caps removed above. Options read as one line each at full width. */
.quiz-wrap {}
.quiz-actions { display: flex; gap: 0.75rem; margin-top: 1.5rem; flex-wrap: wrap; }

.score-summary {
  text-align: center;
  padding: 3rem;
  background: linear-gradient(135deg, var(--color-navy) 0%, #0c2340 100%);
  border-radius: var(--radius);
  margin: 1.5rem 0;
  box-shadow: var(--shadow-lg);
  color: #fff;
}
.score-summary .score { font-size: 3rem; font-weight: 700; margin-bottom: 0.25rem; }
.score-summary .score-label { font-size: 0.95rem; color: rgba(255,255,255,0.7); }

.review-item { padding: 1.25rem; margin: 0.75rem 0; border-radius: var(--radius); border-left: 4px solid; }
.review-item.correct { background: var(--color-success-bg); border-left-color: var(--color-success); }
.review-item.incorrect { background: var(--color-error-bg); border-left-color: var(--color-error); }
.review-item .question-text { font-size: 0.95rem; margin-bottom: 0.5rem; }
.review-item p { font-size: 0.85rem; margin: 0.25rem 0; }
.review-item .correct-answer { font-weight: 600; color: var(--color-success); }
.review-item .explanation { font-style: italic; color: var(--color-text-secondary); margin-top: 0.5rem; font-size: 0.83rem; }

/* ===================================================================
   ACCOUNT
   =================================================================== */
.account-info {
  background: var(--color-surface);
  padding: 1.75rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  margin-bottom: 2rem;
}
/* Same shell as .account-info, so the two panels on the account page line up.
   The form inside stays a readable column rather than stretching a password
   field across the whole page. */
.account-panel {
  background: var(--color-surface);
  padding: 1.75rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  margin-bottom: 2rem;
}
.account-panel form { max-width: 440px; }

/* minmax(0, 1fr), not 1fr. A `1fr` track will not shrink below its min-content
   width, and an email address is one unbreakable token -- so at 360px the value
   column refused to fit in the 220px left beside the label and pushed the whole
   page into horizontal scroll. The overflow-wrap is the other half: letting the
   track shrink is no use if the address inside it still cannot break. */
.account-info .info-grid { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: 0.5rem 1rem; font-size: 0.9rem; }
.account-info .info-label { font-weight: 600; color: var(--color-text-secondary); }
.account-info .info-value { color: var(--color-text); overflow-wrap: anywhere; }

/* On a phone, stack them. A 140px label column out of 360 leaves an email
   address a column too narrow to sit on one line however it wraps. */
@media (max-width: 480px) {
  .account-info .info-grid { grid-template-columns: 1fr; gap: 0.1rem; }
  .account-info .info-label:not(:first-child) { margin-top: 0.65rem; }
}

.status-badge {
  display: inline-flex;
  padding: 0.2rem 0.65rem;
  border-radius: var(--radius-pill);
  font-size: 0.73rem;
  font-weight: 600;
  text-transform: capitalize;
}
.status-badge.pending { background: var(--color-warning-bg); color: var(--color-warning); }
.status-badge.approved { background: var(--color-success-bg); color: var(--color-success); }
.status-badge.rejected { background: var(--color-error-bg); color: var(--color-error); }

/* ===================================================================
   ADMIN
   =================================================================== */
.admin-layout { display: grid; grid-template-columns: 220px 1fr; gap: 2rem; align-items: start; }
/* min-width:0 is the whole fix for the admin pages being different widths.
   A grid item defaults to min-width:auto, meaning it refuses to shrink below
   its content's min-content size. A wide table therefore pushed the 1fr column
   past the page container, taking the sidebar with it -- so Users sat wider and
   further left than Content, and on Quizzes a second table rendered narrower
   than the first purely because of what was inside it. With this, the column is
   the same width on every page and .table-wrap's overflow-x actually applies. */
.admin-content { min-width: 0; }
.admin-nav {
  background: var(--color-surface);
  padding: 1.25rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  position: sticky;
  top: 84px;
}
.admin-nav h3 {
  font-size: 0.73rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-light);
  margin-bottom: 0.75rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--color-border-light);
  font-weight: 700;
}
.admin-nav a {
  display: block;
  padding: 0.5rem 0.75rem;
  color: var(--color-text-secondary);
  font-size: 0.85rem;
  font-weight: 500;
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}
.admin-nav a:hover { background: var(--color-bg); color: var(--color-text); }
.admin-nav a.active { background: var(--color-primary-light); color: var(--color-primary); font-weight: 600; }

/* Section headings inside an admin page. The page title comes from
   base_admin.html, so every h2 here is a section and gets one treatment. */
.admin-content h2 { font-size: 1.15rem; font-weight: 700; color: var(--color-navy); margin-bottom: 1rem; margin-top: 2.5rem; }
.admin-content h2:first-child { margin-top: 0; }
.admin-content .page-header + h2,
.admin-content .flash + h2 { margin-top: 0; }
/* Two answer forms sit side by side under a submitted question, one per
   destination. They were inline-styled to full width when there was only one. */
.question-answer-form { max-width: 100%; margin-bottom: 0.75rem; }
.form-hint { font-size: 0.85rem; color: var(--color-text-secondary); margin: -0.25rem 0 0.75rem; }
.consent-refused {
  font-size: 0.9rem;
  color: var(--color-text-secondary);
  background: var(--color-warning-bg);
  border-left: 3px solid var(--color-warning);
  padding: 0.75rem 1rem;
  border-radius: 4px;
  margin-bottom: 0.75rem;
}

/* From readers, on the FAQ page. The dashboard shows the same cards inside a
   full-bleed band; here they sit in the page container like everything else. */
.faq-featured { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--color-border); }
.faq-featured .fqa-grid { margin-top: 1.25rem; }
.section-lead { color: var(--color-text-secondary); font-size: 0.95rem; margin-top: 0.35rem; }

/* --- Questions and answers page ---------------------------------------
   Two kinds of content live here: answers the authors wrote, and questions
   readers sent in. They used to run together as one column of headings, so the
   page read as a single undifferentiated list. Each is now a labelled block. */
.qa-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1.5rem 0 0.5rem;
}
.qa-jump a {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-navy);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  text-decoration: none;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.qa-jump a:hover {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-sm);
}

.qa-block { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--color-border); }
.qa-block:first-of-type { margin-top: 2rem; }
.qa-block-head { margin-bottom: 1.25rem; }
.qa-block-title {
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--color-navy);
  margin: 0.15rem 0 0;
  line-height: 1.3;
}
.qa-eyebrow {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-accent);
  margin: 0;
}
/* Reader-contributed blocks carry a muted eyebrow, so a glance down the page
   separates "the authors wrote this" from "a reader asked this". */
.qa-eyebrow--readers { color: var(--color-text-secondary); }
.qa-block .fqa-grid { margin-top: 1.25rem; }
.qa-block .faq-topic:first-of-type { margin-top: 0; }

/* The ask form, now a sub-block inside "From readers" rather than a section of
   its own. Ruled off so it reads as a distinct thing to do without claiming to
   be a third subsection. */
.qa-ask { margin-top: 2.5rem; padding-top: 1.75rem; border-top: 1px dashed var(--color-border); }
.qa-sub-title {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--color-navy);
  margin: 0 0 0.35rem;
}

.section-count {
  margin-left: 0.5rem;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--color-text-light);
}
.thread-back { margin-bottom: 1.25rem; }

/* Forms fill the content column like everything else. The 600px cap made a
   form visibly narrower than the table beneath it on the same page. */
.admin-form {
  max-width: 100%;
  background: var(--color-surface);
  padding: 1.75rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  margin-bottom: 1.5rem;
}

.question-card { background: var(--color-surface); padding: 1.5rem; border-radius: var(--radius); box-shadow: var(--shadow-card); margin: 0.75rem 0; }
.question-card.pending { border-left: 4px solid var(--color-warning); }
.question-card.published { border-left: 4px solid var(--color-success); opacity: 0.7; }
.question-card.dismissed { border-left: 4px solid var(--color-text-light); opacity: 0.5; }
.question-card blockquote {
  background: var(--color-bg);
  padding: 0.75rem 1rem;
  border-radius: var(--radius-sm);
  margin: 0.75rem 0;
  font-style: italic;
  color: var(--color-text-secondary);
  border-left: 3px solid var(--color-accent);
}
.question-meta { font-size: 0.78rem; color: var(--color-text-light); margin-bottom: 0.5rem; }
.question-actions { margin-top: 1rem; }
.question-actions .btn { margin-right: 0.5rem; margin-bottom: 0.5rem; }
.inline-form { display: inline-block; margin-right: 0.5rem; }
.password-reset-form { display: inline-flex; align-items: center; gap: 0.5rem; }
.password-reset-form input { width: 160px; padding: 0.35rem 0.6rem; font-size: 0.8rem; }

/* ===================================================================
   PAGE HEADINGS
   =================================================================== */
.page-header { margin-bottom: 2rem; }
.page-header h1 { font-size: 1.85rem; font-weight: 700; color: var(--color-navy); letter-spacing: -0.015em; }
.page-header p { color: var(--color-text-secondary); font-size: 0.95rem; margin-top: 0.35rem; }
h1 { font-size: 1.85rem; font-weight: 700; color: var(--color-navy); margin-bottom: 1rem; }
h2 { font-size: 1.25rem; font-weight: 600; color: var(--color-navy); margin-bottom: 0.75rem; margin-top: 2rem; }
h3 { font-size: 1.05rem; font-weight: 600; color: var(--color-navy); }

.error-page { padding: 3rem 0 5rem; max-width: 620px; }
.error-code {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--color-accent);
  margin-bottom: 0.35rem;
}
.error-lead { color: var(--color-text-secondary); font-size: 0.98rem; line-height: 1.65; margin-bottom: 1.75rem; }
.error-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

.empty-state { text-align: center; padding: 3.5rem 1.5rem; color: var(--color-text-light); }
.empty-state p { font-size: 0.95rem; margin-bottom: 1rem; }

.section { margin-top: 2.5rem; }
.section-title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-navy);
  margin-bottom: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 3px solid var(--color-accent);
  display: inline-block;
}

/* ===================================================================
   RESPONSIVE
   =================================================================== */
@media (max-width: 768px) {
  .container { padding: 1.5rem 1rem; }
  .navbar { padding: 0 1rem; }
  /* The lockup plus the hamburger is close to the full width of a 360px phone,
     so both marks step down. The ratio between them is kept. */
  .nav-brand img { height: 21px; }
  .nav-brand img.nav-wiley-logo { height: 31px; }
  .nav-toggle { display: flex; flex-direction: column; justify-content: center; }
  .nav-links {
    display: none;
    flex-direction: column;
    position: absolute;
    top: 68px;
    left: 0; right: 0;
    background: var(--color-navy);
    padding: 0.5rem 1rem 1rem;
    box-shadow: 0 4px 16px rgba(0,0,0,0.2);
    z-index: 99;
  }
  .nav-links.open { display: flex; }
  .nav-links a { padding: 0.7rem 0.85rem; width: 100%; border-radius: var(--radius-sm); }
  .nav-user {
    margin-left: 0; padding-left: 0; border-left: none;
    padding-top: 0.5rem; border-top: 1px solid rgba(255,255,255,0.12);
    width: 100%; flex-direction: column; align-items: stretch;
  }
  .hero { padding: calc(3rem + var(--navbar-h)) 1.25rem 2.5rem; margin-top: calc(-1.5rem - var(--navbar-h)); margin-bottom: 1.5rem; }
  .hero h1 { font-size: 1.75rem; }
  .hero .subtitle { font-size: 1rem; }
  .card-grid { grid-template-columns: 1fr; }
  .admin-layout { grid-template-columns: 1fr; }
  .admin-nav {
    position: static;
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.75rem 1rem; overflow-x: auto;
  }
  .admin-nav h3 { margin-bottom: 0; border: none; padding: 0; }
  .admin-nav ul { display: flex; gap: 0.25rem; }
  .admin-nav a { white-space: nowrap; }
  .table-wrap { margin: 0 -1rem; padding: 0 1rem; }
  .score-summary .score { font-size: 2.25rem; }
  .score-summary { padding: 2rem; }
  .quiz-form { padding: 1.5rem; }
}

@media (max-width: 480px) {
  .hero h1 { font-size: 1.5rem; }
  .hero-actions { flex-direction: column; align-items: center; }
  .hero-actions .btn { width: 100%; }
  .auth-form { margin: 1rem auto; padding: 1.75rem 1.5rem; }
  .auth-page { margin-top: 1.5rem; }
  .auth-title { font-size: 1.5rem; }
  .score-summary .score { font-size: 1.85rem; }
}

@media print {
  .navbar, .footer, .nav-toggle, .btn { display: none; }
  body { background: #fff; color: #000; }
  .container { max-width: 100%; padding: 0; }
  .hero { background: none; color: #000; padding: 1rem 0; margin: 0; }
  .hero h1, .hero .subtitle { color: #000; }
}

/* ===================================================================
   HOME PAGE — hero split, welcome, CTA band
   =================================================================== */

.hero--split { text-align: left; }
.hero-split-inner {
  display: flex;
  align-items: center;
  gap: 3.5rem;
  max-width: var(--container-max);
  margin: 0 auto;
  position: relative;
  z-index: 1;
}
.hero-cover-col { flex: 0 0 auto; }
.hero-book-cover {
  width: 220px;
  border-radius: var(--radius);
  box-shadow: 0 16px 48px rgba(0,0,0,0.4);
}
.hero-content-col { flex: 1; min-width: 0; }
.hero--split .hero-description { margin-left: 0; margin-right: 0; max-width: 520px; }
.hero--split .hero-actions { justify-content: flex-start; }

.welcome-section {
  max-width: 700px;
  margin: 3rem auto 2.5rem;
  text-align: center;
}
.welcome-section h2 { font-size: 1.5rem; margin-top: 0; margin-bottom: 1rem; }
.welcome-section p { color: var(--color-text-secondary); font-size: 0.95rem; line-height: 1.75; margin-bottom: 0.75rem; }
.welcome-sig { font-style: italic; color: var(--color-text-light); }

.about-section { max-width: 780px; margin: 2.5rem auto; }
.about-section h2 { margin-top: 0; margin-bottom: 1.25rem; }
.about-section p { color: var(--color-text-secondary); font-size: 0.95rem; line-height: 1.75; margin-bottom: 1rem; }

.authors-section { max-width: 780px; margin: 2.5rem auto; }
.authors-section h2 { margin-top: 0; margin-bottom: 1.5rem; }
.authors-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
.author-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 2rem;
  box-shadow: var(--shadow-card);
}
.author-photo { width: 160px; height: 160px; object-fit: cover; border-radius: var(--radius); margin: 0 auto 1.25rem; }
.author-name { font-size: 1rem; font-weight: 700; color: var(--color-navy); margin-bottom: 0.75rem; text-align: center; }
.author-bio { font-size: 0.88rem; color: var(--color-text-secondary); line-height: 1.7; }

/* The home page's own `.cta-band` lived here. It said the same thing as the
   dashboard's band in a different shape, so both pages now include
   _candesic_cta.html and .dash-cta-band is the only version. */

.btn-accent { background: var(--color-accent); color: var(--color-navy); font-weight: 600; }
.btn-accent:hover { background: var(--color-accent-dark); color: var(--color-navy); }
.btn-outline-white { background: transparent; color: #fff; border: 2px solid rgba(255,255,255,0.45); }
.btn-outline-white:hover { border-color: #fff; background: rgba(255,255,255,0.1); color: #fff; }

.btn-buy { background: rgba(0, 114, 188, 0.5); color: #fff; border: none; padding: 0.75rem 2rem; font-size: 0.95rem; }
.btn-buy:hover { background: rgba(0, 114, 188, 0.7); color: #fff; }

@media (max-width: 768px) {
  .hero--split { text-align: center; }
  .hero-split-inner { flex-direction: column; gap: 2rem; }
  .hero-book-cover { width: 160px; margin: 0 auto; }
  .hero--split .hero-actions { justify-content: center; }
  .hero--split .hero-buy { justify-content: center; }
  .hero--split .hero-description { max-width: 100%; }
  .authors-grid { grid-template-columns: 1fr; }
}

/* ===================================================================
   DASHBOARD — READER AREA
   =================================================================== */
.dash-wrap {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 2rem;
}

.dash-section {
  padding: 3rem 0;
}

.dash-section--alt {
  background: var(--color-surface);
}

/* Eyebrow label: blue bar + small-caps label */
.dash-eyebrow {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--color-primary);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.dash-eyebrow::before {
  content: '';
  display: inline-block;
  width: 18px;
  height: 2px;
  background: var(--color-primary);
  flex-shrink: 0;
}
.dash-eyebrow--white { color: rgba(255,255,255,0.75); }
.dash-eyebrow--white::before { background: var(--color-accent); }

.dash-section-header { margin-bottom: 1.75rem; }

.dash-section-title {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--color-navy);
  line-height: 1.15;
  margin: 0 0 0.5rem;
}

.dash-section-sub {
  color: var(--color-text-secondary);
  font-size: 0.92rem;
  line-height: 1.65;
  margin: 0;
}

.dash-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.5rem;
  box-shadow: var(--shadow-card);
}

.dash-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.dash-grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

/* Welcome */
.dash-welcome { padding: 3rem 0 2rem; }

.dash-welcome-inner {
  display: flex;
  gap: 3rem;
  align-items: flex-start;
}

.dash-welcome-text { flex: 1; }

.dash-h1 {
  font-size: 2rem;
  font-weight: 700;
  color: var(--color-navy);
  line-height: 1.15;
  margin: 0 0 0.85rem;
}

.dash-welcome-text p {
  color: var(--color-text-secondary);
  font-size: 0.95rem;
  line-height: 1.72;
  margin-bottom: 0.6rem;
}

.dash-sig {
  font-style: italic;
  font-size: 0.88rem;
  color: var(--color-text-light);
}

/* The welcome note runs the full column now. It used to share the row with an
   instructor card, which squeezed the authors' words into two thirds of the
   width for instructors and left a ragged gap for everyone else. */
.dash-welcome-lead {
  color: var(--color-text-secondary);
  font-size: 0.95rem;
  line-height: 1.72;
  margin-bottom: 0.6rem;
}

/* --- Instructor status strip -----------------------------------------
   One shape, three states (approved / pending / not asked), always in the same
   place, so a reader's instructor status never changes the shape of the page
   above the fold. */
.dash-strip-wrap { padding-bottom: 0.5rem; }

.instr-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  background: var(--color-primary-50);
  border: 1px solid rgba(0, 105, 180, 0.18);
  border-radius: var(--radius);
  padding: 1.125rem 1.5rem;
}

.instr-strip--pending,
.instr-strip--invite {
  background: var(--color-surface);
  border-color: var(--color-border);
}

.instr-strip-text { min-width: 15rem; flex: 1; }

.instr-strip-title {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--color-navy);
  margin: 0 0 0.2rem;
}

.instr-strip-sub {
  font-size: 0.85rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
  margin: 0;
}

/* A control that is deliberately inert. Greyed and not clickable, but still
   rendered, because it answers "did my request go through?" without the reader
   having to email anyone. The reason arrives on hover via `title`. */
.btn.is-disabled,
.btn.is-disabled:hover {
  background: var(--color-border);
  color: var(--color-text-light);
  box-shadow: none;
  cursor: not-allowed;
  pointer-events: auto;
}

/* --- Feature tiles ---------------------------------------------------
   Square-ish cards, one per destination. Each carries a line saying what is
   behind it and how much of it there is: a tile that reads "Quizzes" and
   nothing else is a nav item with a border round it. */
.tile-grid {
  display: grid;
  /* auto-fit, not auto-fill -- auto-fill keeps empty tracks and leaves the row
     hugging the left on wide screens. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
}

.tile {
  display: flex;
  flex-direction: column;
  min-height: 190px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.5rem;
  box-shadow: var(--shadow-card);
  text-decoration: none;
  transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition);
}

.tile:hover {
  border-color: var(--color-primary);
  box-shadow: 0 6px 18px rgba(0, 105, 180, 0.14);
  transform: translateY(-2px);
}

.tile-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius);
  background: var(--color-primary-light);
  color: var(--color-primary);
  margin-bottom: 1.125rem;
  flex-shrink: 0;
}

.tile-title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--color-navy);
  margin-bottom: 0.4rem;
}

.tile-sub {
  font-size: 0.85rem;
  line-height: 1.55;
  color: var(--color-text-secondary);
}

/* A quiet way out of a section that shows only the first few of something. */
.dash-more { margin-top: 1.5rem; }

.dash-welcome-aside { flex: 0 0 260px; }

.dash-aside-label {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--color-navy);
  margin-bottom: 0.35rem;
}

.dash-aside-sub {
  font-size: 0.82rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
  margin-bottom: 0;
}

/* Model cards */
.model-card-inner {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
}

.model-icon {
  width: 44px;
  height: 44px;
  background: var(--color-bg);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--color-primary-dark);
}

.model-info { flex: 1; }

.model-title {
  font-size: 0.97rem;
  font-weight: 700;
  color: var(--color-navy);
  line-height: 1.35;
  margin: 0 0 0.3rem;
}

.model-desc {
  font-size: 0.85rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
  margin: 0 0 0.3rem;
}

.model-meta {
  font-size: 0.75rem;
  color: var(--color-text-light);
  margin: 0;
}

.model-action { margin-top: 1rem; }

.btn-ghost-blue {
  background: transparent;
  color: var(--color-primary-dark);
  border: 1px solid var(--color-primary);
}
.btn-ghost-blue:hover {
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
}

/* Placeholder blocks */
.placeholder-block {
  background: var(--color-bg);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
  padding: 2.5rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.placeholder-label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--color-text-light);
  letter-spacing: 0.06em;
}

/* Ask form */
/* Full width, to line up with the FAQ cards above it. The old 680px cap made the
   form read as a narrow column pinned to the left of a much wider page. */
.ask-form-wrap { max-width: none; }

/* News cards */
.news-card-tag {
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--color-primary);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.65rem;
}

.news-card-title {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--color-navy);
  line-height: 1.35;
  margin: 0 0 0.4rem;
}

.news-card-body {
  font-size: 0.88rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
  margin: 0;
}

.news-card-date {
  font-size: 0.75rem;
  color: var(--color-text-light);
  margin-top: 0.75rem;
}

/* CTA band */
.dash-cta-band {
  background: linear-gradient(120deg, var(--color-navy), var(--color-navy-mid));
  padding: 3rem 0;
  margin-top: 0;
}

.dash-cta-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
}

.dash-cta-title {
  font-size: 1.3rem;
  font-weight: 700;
  color: #fff;
  margin: 0.25rem 0 0;
  line-height: 1.3;
}

.dash-cta-actions {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  flex-shrink: 0;
}

@media (max-width: 768px) {
  .dash-wrap { padding: 0 1rem; }
  .dash-section { padding: 2rem 0; }
  .dash-welcome { padding: 2rem 0 1.5rem; }
  .dash-welcome-inner { flex-direction: column; gap: 1.5rem; }
  .dash-welcome-aside { flex: none; width: 100%; }
  .dash-grid-2, .dash-grid-3 { grid-template-columns: 1fr; }
  .dash-section-title { font-size: 1.35rem; }
  .dash-h1 { font-size: 1.6rem; }
  .dash-cta-inner { flex-direction: column; align-items: flex-start; }
}

/* ===================================================================
   TOC PARTIAL (_toc.html)
   =================================================================== */

/* Front / back matter: label + inline item list */
.toc-matter {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem 0.85rem;
  margin-bottom: 1.1rem;
}
.toc-matter--back { margin-top: 1.1rem; margin-bottom: 0; }

.toc-matter-label {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-text-light);
  flex-shrink: 0;
}

.toc-matter-list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 0;
}
.toc-matter-list li {
  font-size: 0.82rem;
  color: var(--color-text-secondary);
  padding-right: 1.1rem;
  position: relative;
}
.toc-matter-list li::after {
  content: '\00B7';
  position: absolute;
  right: 0.35rem;
  color: var(--color-border);
}
.toc-matter-list li:last-child::after { display: none; }

/* Chapter accordion container */
.toc-container {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--color-surface);
}

/* Each chapter <details> */
.toc-item { border-top: 1px solid var(--color-border); }
.toc-item:first-child { border-top: none; }

/* Chapter summary row */
.toc-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.9rem 1.25rem;
  cursor: pointer;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--color-navy);
  list-style: none;
  user-select: none;
  transition: background var(--transition), color var(--transition);
}
.toc-summary:hover { background: var(--color-bg); }
.toc-summary::marker,
.toc-summary::-webkit-details-marker { display: none; }

/* CSS chevron: right-facing ">" that rotates to "v" on open */
.toc-summary::after {
  content: '';
  display: inline-block;
  width: 7px;
  height: 7px;
  border-right: 2px solid var(--color-text-light);
  border-bottom: 2px solid var(--color-text-light);
  transform: rotate(-45deg);
  transition: transform var(--transition), border-color var(--transition);
  flex-shrink: 0;
  margin-left: auto;
}
details[open] > .toc-summary::after {
  transform: rotate(45deg);
  border-color: var(--color-primary);
}
details[open] > .toc-summary {
  background: var(--color-bg);
  color: var(--color-primary-dark);
}

/* Book icon box */
.toc-icon {
  width: 28px;
  height: 28px;
  background: var(--color-bg);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--color-primary);
}
details[open] > .toc-summary .toc-icon { background: var(--color-primary-light); }

.toc-chapter-label { flex: 1; line-height: 1.35; }

.toc-num {
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}

/* Expanded section sub-list */
.toc-sections {
  background: var(--color-bg);
  border-top: 1px solid var(--color-border-light);
  padding: 0.4rem 0 0.5rem;
  list-style: none;
  margin: 0;
}
.toc-section-item {
  font-size: 0.82rem;
  color: var(--color-text-secondary);
  padding: 0.32rem 1.25rem 0.32rem 3.6rem;
  line-height: 1.45;
  position: relative;
}
.toc-section-item::before {
  content: '';
  position: absolute;
  left: 2.55rem;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--color-border);
}

@media (max-width: 768px) {
  .toc-summary { padding: 0.85rem 1rem; font-size: 0.85rem; }
  .toc-section-item { padding-left: 3rem; }
  .toc-section-item::before { left: 2.1rem; }
  .toc-matter { flex-direction: column; gap: 0.25rem; }
  .toc-matter-list { flex-direction: column; gap: 0.2rem; }
  .toc-matter-list li::after { display: none; }
}

/* ===================================================================
   EXERCISES PAGE & DASHBOARD CHAPTER BUTTON ROW
   =================================================================== */

/* Chapter button row — used on both dashboard and exercises page */
.ex-chapter-btns {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* btn-sm variant for the chapter buttons */
.btn-sm {
  padding: 0.35rem 0.85rem;
  font-size: 0.8rem;
}

/* Exercises page: chapter section */
/* Chapters collapse (2026-07-30). They used to be ten always-open sections with
   a row of anchor pills above them: clicking a pill dropped you into the middle
   of a very long page with nothing to click to get back. Collapsed, the whole
   book is one screen and a chapter opens in place. */
.ex-chapter {
  margin-bottom: 0.6rem;
  scroll-margin-top: calc(var(--navbar-h) + 1.5rem);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: box-shadow var(--transition);
}
.ex-chapter:hover { box-shadow: var(--shadow-sm); }

.ex-chapter-header {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.95rem 1.25rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background var(--transition);
}
.ex-chapter-header:hover { background: var(--color-bg); }
.ex-chapter-header::marker,
.ex-chapter-header::-webkit-details-marker { display: none; }

/* Chevron, right-facing when shut and down when open, same as the contents list. */
.ex-chapter-header::after {
  content: '';
  margin-left: auto;
  width: 7px;
  height: 7px;
  border-right: 2px solid var(--color-text-light);
  border-bottom: 2px solid var(--color-text-light);
  transform: rotate(-45deg);
  transition: transform var(--transition);
  flex-shrink: 0;
}
.ex-chapter[open] > .ex-chapter-header::after { transform: rotate(45deg); }
.ex-chapter[open] > .ex-chapter-header { border-bottom: 1px solid var(--color-border); }

/* The chapter now draws the frame, so the question list must not draw a second. */
.ex-chapter > .ex-container {
  border: none;
  border-radius: 0;
}

.ex-chapter-num {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-primary);
  flex-shrink: 0;
}

.ex-chapter-title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-navy);
  margin: 0;
  line-height: 1.25;
}

/* Q&A accordion container */
.ex-container {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--color-surface);
}

.ex-item { border-top: 1px solid var(--color-border); }
.ex-item:first-child { border-top: none; }

.ex-question {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.85rem 1.25rem;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-navy);
  list-style: none;
  user-select: none;
  line-height: 1.5;
  transition: background var(--transition);
}
.ex-question:hover { background: var(--color-bg); }
.ex-question::marker,
.ex-question::-webkit-details-marker { display: none; }

.ex-q-num {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--color-text-light);
  flex-shrink: 0;
  margin-top: 0.2rem;
  font-variant-numeric: tabular-nums;
  min-width: 1.75rem;
}

.ex-q-text { flex: 1; }

/* CSS chevron — same pattern as TOC */
.ex-question::after {
  content: '';
  display: inline-block;
  width: 7px;
  height: 7px;
  border-right: 2px solid var(--color-text-light);
  border-bottom: 2px solid var(--color-text-light);
  transform: rotate(-45deg);
  transition: transform var(--transition), border-color var(--transition);
  flex-shrink: 0;
  margin-left: 0.5rem;
  margin-top: 0.4rem;
}
details[open] > .ex-question::after {
  transform: rotate(45deg);
  border-color: var(--color-primary);
}
details[open] > .ex-question {
  background: var(--color-bg);
  color: var(--color-primary-dark);
}

.ex-answer-body {
  padding: 0.85rem 1.25rem 1rem 3.6rem;
  background: var(--color-bg);
  border-top: 1px solid var(--color-border-light);
  font-size: 0.85rem;
  color: var(--color-text-secondary);
  line-height: 1.65;
}

.ex-flag-note {
  font-style: italic;
  color: var(--color-text-light);
}

@media (max-width: 768px) {
  .ex-chapter-header { flex-direction: column; gap: 0.2rem; }
  .ex-question { padding: 0.85rem 1rem; font-size: 0.83rem; }
  .ex-answer-body { padding: 0.85rem 1rem 0.9rem 1rem; }
}

/* ===================================================================
   FEATURED Q&A PARTIAL (_featured_qa.html)
   =================================================================== */

.fqa-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.fqa-card {
  display: flex;
  flex-direction: column;
}

.fqa-quote-icon {
  color: var(--color-primary);
  margin-bottom: 0.75rem;
  flex-shrink: 0;
}

.fqa-question {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-navy);
  line-height: 1.35;
  margin: 0 0 0.65rem;
}

.fqa-answer {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  line-height: 1.65;
  margin: 0 0 0.75rem;
  flex: 1;
}

.fqa-attribution {
  font-size: 0.8rem;
  font-style: italic;
  color: var(--color-primary-dark);
  margin: 0;
}

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

/* ===================================================================
   ADMIN — FEATURED Q&A PAGE
   =================================================================== */

.admin-fqa-item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1rem 1.25rem;
  margin-bottom: 0.75rem;
}

.admin-fqa-row {
  display: flex;
  gap: 1.25rem;
  align-items: flex-start;
}

.admin-fqa-meta { flex: 1; min-width: 0; }

.admin-fqa-order {
  font-size: 0.72rem;
  color: var(--color-text-light);
  font-variant-numeric: tabular-nums;
}

.admin-fqa-q {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-navy);
  margin: 0.3rem 0 0.2rem;
  line-height: 1.4;
}

.admin-fqa-a {
  font-size: 0.83rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
  margin: 0 0 0.2rem;
}

.admin-fqa-attr {
  font-size: 0.78rem;
  font-style: italic;
  color: var(--color-primary);
  margin: 0;
}

.admin-fqa-btns {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex-shrink: 0;
}

.admin-fqa-edit-wrap { position: relative; }
.admin-fqa-edit-wrap > summary {
  list-style: none;
  cursor: pointer;
  display: block;
}
.admin-fqa-edit-wrap > summary::-webkit-details-marker { display: none; }

.admin-fqa-edit-form {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.25rem;
  min-width: 360px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.12);
}

.admin-fqa-btns .btn { width: 90px; text-align: center; justify-content: center; }
.admin-fqa-btns .inline-form { display: block; margin: 0; }

.btn-danger {
  background: #dc2626;
  color: #fff;
  border-color: #dc2626;
}
.btn-danger:hover {
  background: #b91c1c;
  border-color: #b91c1c;
  color: #fff;
}

/* ===================================================================
   INSTRUCTOR NOTICE  (dashboard, non-instructor users)
   =================================================================== */

.instr-notice {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.875rem 1.25rem;
}

.instr-notice-icon {
  color: var(--color-text-light);
  flex-shrink: 0;
  margin-top: 1px;
}

.instr-notice-text {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
  margin: 0;
}

.instr-notice-text a { color: var(--color-primary); text-decoration: none; }
.instr-notice-text a:hover { text-decoration: underline; }

/* The .back-to-dash pill lived here: fixed, bottom-left, on every page but the
   dashboard. Dashboard is a nav item now, so the pill and its rules are gone. */

/* ===================================================================
   CONSENT CHECKBOXES  (ask forms)
   =================================================================== */

.form-check { margin-bottom: 0.6rem; }

.checkbox-label {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  line-height: 1.5;
  font-weight: 400;
  cursor: pointer;
}

.checkbox-label input[type="checkbox"] {
  width: auto;
  flex-shrink: 0;
  margin-top: 0.2rem;
  accent-color: var(--color-primary);
  cursor: pointer;
}

/* Admin submitted questions — consent flag row */
.consent-flags {
  display: flex;
  gap: 1.25rem;
  margin: 0.35rem 0 0.75rem;
  font-size: 0.82rem;
  color: var(--color-text-secondary);
}

.checkbox-label:has(input[type="checkbox"]:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
}
.checkbox-label input[type="checkbox"]:disabled {
  cursor: not-allowed;
}

/* --- Instructor page --- */
.instr-hero {
  background: linear-gradient(160deg, #00507f, #161924);
  padding: 3.5rem 0 3rem;
}

.instr-hero .dash-eyebrow {
  color: var(--color-primary);
}

.instr-hero-title {
  font-size: 2rem;
  font-weight: 700;
  color: #fff;
  margin: 0.5rem 0 0;
  line-height: 1.15;
}

.instr-hero-sub {
  color: rgba(255,255,255,0.85);
  font-size: 0.9375rem;
  line-height: 1.6;
  margin-top: 0.75rem;
}

/* The authors' standing offer to adopting instructors. Set apart from the
   paragraph above it -- rule, lighter weight, full white -- because it is an
   invitation to reply, not more description of the page. */
.instr-hero-offer {
  color: #fff;
  font-size: 0.9375rem;
  line-height: 1.6;
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(255,255,255,0.18);
}

/* --- Case study cards --- */
.case-card {
  display: flex;
  flex-direction: column;
}

.case-card-title {
  font-size: 0.975rem;
  font-weight: 700;
  color: var(--color-navy);
  margin: 0;
  line-height: 1.35;
}

.case-card-desc {
  font-size: 0.84rem;
  color: #5f6368;
  line-height: 1.6;
  margin: 0.375rem 0 0;
}

.case-card-action {
  margin-top: 1.25rem;
}

/* A published case whose link has not been issued yet. Reads as a status, not
   as a control -- there is nothing to press. */
.case-card-pending {
  display: inline-block;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-text-light);
  font-style: italic;
}

/* Text fills its container. Prose caps kept getting added here for line-length
   reasons and kept being wrong for this site: the page column is already the
   measure, and a second cap inside it just leaves a ragged half-empty band. */
.chat-wrap {}

.chat-thread {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 420px;
  overflow-y: auto;
  padding: 0.75rem;
  margin-bottom: 1.25rem;
  scrollbar-width: thin;
  scrollbar-color: #c7c7cc transparent;
}

.chat-thread::-webkit-scrollbar { width: 4px; }
.chat-thread::-webkit-scrollbar-track { background: transparent; }
.chat-thread::-webkit-scrollbar-thumb { background: #c7c7cc; border-radius: 4px; }

.chat-bubble {
  max-width: 70%;
  padding: 0.5rem 0.85rem;
  border-radius: 18px;
  line-height: 1.45;
}

.chat-bubble--instructor {
  align-self: flex-end;
  background: #007AFF;
  color: #fff;
  border-bottom-right-radius: 4px;
}

.chat-bubble--author {
  align-self: flex-start;
  background: #E9E9EB;
  color: #1c1c1e;
  border-bottom-left-radius: 4px;
}

.chat-bubble-label {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  margin-bottom: 0.15rem;
  opacity: 0.7;
}

.chat-bubble--instructor .chat-bubble-label { color: rgba(255,255,255,0.9); }
.chat-bubble--author .chat-bubble-label     { color: #8e8e93; }

.chat-bubble-body {
  font-size: 0.875rem;
  line-height: 1.45;
  margin: 0;
  white-space: pre-wrap;
}

.chat-bubble-date {
  font-size: 0.65rem;
  margin-top: 0.2rem;
  opacity: 0.5;
}

.chat-empty {
  padding: 1.25rem 1.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  color: var(--color-text-secondary);
  font-size: 0.9rem;
  margin-bottom: 1.5rem;
}

.chat-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.chat-input {
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--color-navy);
  resize: vertical;
  outline: none;
  transition: border-color var(--transition);
}

.chat-input:focus { border-color: var(--color-primary); }

/* Admin chat thread: flip sides AND colors so author (right) is blue, instructor (left) is grey */
.admin-chat-thread .chat-bubble--instructor {
  align-self: flex-start;
  background: #E9E9EB;
  color: #1c1c1e;
  border-bottom-right-radius: 18px;
  border-bottom-left-radius: 4px;
}
.admin-chat-thread .chat-bubble--author {
  align-self: flex-end;
  background: #007AFF;
  color: #fff;
  border-bottom-left-radius: 18px;
  border-bottom-right-radius: 4px;
}
.admin-chat-thread .chat-bubble--instructor .chat-bubble-label { color: #8e8e93; }
.admin-chat-thread .chat-bubble--author .chat-bubble-label     { color: rgba(255,255,255,0.9); }

/* --- Admin nav badge --- */
.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 9px;
  background: #e53e3e;
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
  margin-left: 0.4rem;
  vertical-align: middle;
  box-sizing: border-box;
}

.ex-gate-note {
    font-size: 0.8rem;
    color: #9aa5b4;
    margin-top: 0.5rem;
    font-style: italic;
}

/* --- Case-study horizontal scroll row --- */
/* A wrapping grid, not a horizontal scroller. There are five cases and there
   will not be many more; a sideways scrollbar hid four of them behind a gesture
   nobody makes on a desktop, and put the one card that cannot be opened in the
   only slot that was visible. */
/* grid-auto-rows: 1fr so every card is the same size, not just the ones
   sharing a row. Without it each row sizes to its own tallest card and the
   five cases step down the page in three different heights. */
.cs-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  grid-auto-rows: 1fr;
  gap: 1.25rem;
}

/* align-items: stretch, not flex-start: the cover column and the body both run
   the full height of the card, which is what lets the button sit on the floor
   rather than directly under a description whose length varies per case. */
.cs-grid .case-card {
  flex-direction: row;
  align-items: stretch;
  gap: 1.25rem;
}

.cs-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Pushed to the bottom so every card's control sits on the same line, however
   long its description runs. */
.cs-grid .case-card-action,
.cs-grid .case-card-pending { margin-top: auto; padding-top: 1rem; }

/* The cover, small. Marc sent the actual case front pages so an instructor can
   recognise the case at a glance rather than read a title. Bordered because
   they are white pages on a white card. */
/* Fixed box, contained rather than cropped. The covers arrive at whatever
   aspect their publisher used -- the UCL one is close to square, the Imperial
   ones are portrait -- and left to themselves they gave every card a different
   cover height. `contain` normalises the footprint without trimming anyone's
   title off the page. */
.cs-card-img { flex-shrink: 0; width: 96px; order: -1; }

.cs-card-img img {
  width: 100%;
  height: 132px;
  object-fit: contain;
  object-position: top;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  display: block;
  background: #fff;
}

.model-action {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

/* --- Guidance modal --- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
}
.modal-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}
.modal-box {
  background: #fff;
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  max-width: 520px;
  width: calc(100% - 2rem);
  max-height: 80vh;
  overflow-y: auto;
  padding: 1.75rem;
}
.modal-header {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1rem;
}
.modal-title {
  flex: 1;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--color-navy);
  margin: 0;
  line-height: 1.35;
}
.modal-close {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--color-text-light);
  padding: 0;
  flex-shrink: 0;
  transition: color var(--transition);
}
.modal-close:hover { color: var(--color-navy); }
.modal-body {
  font-size: 0.9rem;
  color: var(--color-text-secondary);
  line-height: 1.7;
}
/* The body used to be a single pre-wrap text node. It now holds real paragraphs
   and, where the author supplied one, a comparison table — so spacing belongs on
   the elements. pre-wrap here would double every gap. */
.modal-body > p { margin: 0 0 0.85rem; }
.modal-body > p:last-child { margin-bottom: 0; }

/* Wider only when there is a table to hold. A prose-only note reads better narrow. */
.modal-box:has(.model-about-table) { max-width: 720px; }

.model-about-table-wrap {
  overflow-x: auto;
  margin: 0 0 1rem;
}
.model-about-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.83rem;
  line-height: 1.45;
}
.model-about-table th,
.model-about-table td {
  padding: 0.4rem 0.7rem;
  text-align: left;
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}
.model-about-table th {
  color: var(--color-navy);
  font-weight: 700;
  border-bottom-width: 2px;
}
/* The first column carries the row label and is the one that may need to wrap. */
.model-about-table td:first-child,
.model-about-table th:first-child { white-space: normal; }
.model-about-table tbody tr:last-child td { border-bottom: none; }

.pending-icon-badge {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #e8f0fd;
  border: 1px solid rgba(0, 105, 180, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary);
  margin: 0.6rem auto 0.75rem;
}

.input-invalid { border-color: var(--color-error) !important; }
.field-error { display: block; font-size: 0.8rem; color: var(--color-error); margin-top: 0.25rem; }
.pwd-meter { margin-top: 0.6rem; }
.pwd-meter-bar { height: 4px; background: var(--color-border); border-radius: 2px; overflow: hidden; margin-bottom: 0.35rem; }
.pwd-meter-fill { height: 100%; width: 0; border-radius: 2px; transition: width 0.2s, background 0.2s; }
.pwd-meter-label { font-size: 0.78rem; font-weight: 600; display: block; margin-bottom: 0.3rem; }
.pwd-req-list { list-style: none; padding: 0; margin: 0; font-size: 0.78rem; color: var(--color-text-light); }
.pwd-req-list li { padding-left: 1.2em; position: relative; margin-bottom: 0.15rem; }
.pwd-req-list li::before { content: '\2715'; position: absolute; left: 0; color: var(--color-error); }
.pwd-req-list li.req-met { color: #16a34a; }
.pwd-req-list li.req-met::before { content: '\2713'; color: #16a34a; }

/* --- Page fade-in --- */
@keyframes page-fade-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* NOTE: this leaves #main-content permanently transformed, which makes it the
   containing block for any position:fixed descendant. Anything that must be
   fixed to the viewport -- overlays, modals -- therefore has to live OUTSIDE
   <main>, in base.html. Switching the fill mode does not save you: the element
   holds a transform either way. */
#main-content {
  animation: page-fade-in 250ms ease-out both;
}

@media (prefers-reduced-motion: reduce) {
  #main-content { animation: none; }
}

/* --- User admin action cell --- */
.user-actions-cell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.user-actions-cell .inline-form { display: block; margin: 0; }

.btn-make-admin {
  background: #D3E3FD;
  color: var(--color-navy);
  border: 1px solid #b8d0f9;
  border-radius: var(--radius-pill);
}
.btn-make-admin:hover { background: #b8d0f9; color: var(--color-navy); }

/* ---------------------------------------------------------------------------
   Admin tables: actions and popovers
   Every menu here is a <details> element. No JavaScript, and closing on Escape
   plus keyboard focus come free with the native element.
   --------------------------------------------------------------------------- */

.flash {
    margin: 0 0 20px;
    padding: 12px 16px;
    border-radius: 6px;
    font-size: 14px;
    border: 1px solid transparent;
}
.flash-ok  { background: #ecfdf5; border-color: #a7f3d0; color: #065f46; }
.flash-err { background: #fef2f2; border-color: #fecaca; color: #991b1b; }

/* Actions sit side by side, equal width, centred on the row. */
.data-table td.col-actions, .data-table th.col-actions { text-align: center; white-space: nowrap; }
.action-row {
    display: inline-flex;
    gap: 8px;
    align-items: center;
    justify-content: center;
}
.action-row form { margin: 0; display: inline-flex; }
.action-row .btn, .action-row > details > summary { min-width: 88px; text-align: center; }

/* Overflow menu keeps one column instead of three. */
.data-table th.col-menu, .data-table td.col-menu { width: 44px; text-align: right; }

.menu-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    line-height: 30px;
    text-align: center;
    font-size: 18px;
    color: var(--color-text-light, #6b7280);
    background: none;
    border: 0;
    border-radius: 6px;
    cursor: pointer;
}
.menu-btn:hover { background: #f3f4f6; color: #111827; }
.menu-btn:focus-visible { outline: 2px solid #0072BC; outline-offset: 1px; }

/* Shared shell for anything in the top layer. Fixed and positioned by script,
   which is what keeps it clear of .table-wrap's overflow clipping. */
.panel {
    position: fixed;
    inset: auto;
    margin: 0;
    padding: 8px;
    min-width: 220px;
    max-width: 320px;
    text-align: left;
    color: inherit;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    box-shadow: 0 10px 30px rgba(16, 24, 40, 0.16);
    overflow: visible;
    /* Explicit, never inherited: a panel anchored inside the navbar would
       otherwise pick up its white link colour and render white on white. */
    color: var(--color-text);
}
.panel a, .panel .menu-item { color: var(--color-text); }
.panel .menu-item-danger, .panel a.menu-item-danger { color: #b42318; }
/* The browser paints a popover the instant it opens, but where it belongs is
   only known once app.js has measured it against its anchor. Between those two
   moments it renders at its static position — the top-left of the page the
   first time, or wherever it was last placed on every hover after that, which
   is why a card could appear against the wrong row. Kept invisible until
   app.js adds .is-placed, so there is nothing to see in between.

   visibility, not opacity or display: a visibility:hidden element still has
   layout, and place() needs its real width and height to decide whether to
   flip above the anchor or pull back from the viewport edge. */
.panel:popover-open { display: block; visibility: hidden; }
.panel:popover-open.is-placed { visibility: visible; }
.panel::backdrop { background: transparent; }

.menu-item {
    display: block;
    width: 100%;
    padding: 8px 10px;
    text-align: left;
    font: inherit;
    font-size: 14px;
    color: #111827;
    background: none;
    border: 0;
    border-radius: 5px;
    cursor: pointer;
}
.menu-item:hover { background: #f3f4f6; }
.menu-item-danger { color: #b42318; }
.menu-item-danger:hover { background: #fef2f2; }

.menu-form { padding: 8px 10px 4px; }
.menu-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.menu-form input {
    width: 100%;
    margin-bottom: 8px;
    padding: 7px 9px;
    font: inherit;
    font-size: 13px;
    border: 1px solid #d1d5db;
    border-radius: 5px;
}

.btn-block { display: block; width: 100%; }

.reject-notify { display: block; margin-bottom: 8px; font-size: 13px; font-weight: 500; }
.reject-notify input { margin-right: 6px; }
.reject-panel textarea {
    width: 100%;
    margin-bottom: 8px;
    padding: 6px 8px;
    font: inherit;
    font-size: 13px;
    border: 1px solid #d1d5db;
    border-radius: 5px;
    resize: vertical;
}

/* Status rides along with the role instead of owning a column, since only
   educators ever have one. */
.role-name { text-transform: capitalize; }
.status-dot {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    font-size: 11px;
    font-weight: 600;
    text-transform: capitalize;
    border-radius: 999px;
    vertical-align: middle;
}
.status-dot.pending  { background: #fef3c7; color: #92400e; }
.status-dot.approved { background: #d1fae5; color: #065f46; }
.status-dot.rejected { background: #fee2e2; color: #b42318; }

/* ---------------------------------------------------------------------------
   Person cell + hover profile
   Name over email in one column, everything else on a card, so a row stays one
   line instead of wrapping across three.
   --------------------------------------------------------------------------- */

.table-roomy td { vertical-align: middle; padding-top: 14px; padding-bottom: 14px; }

.person { display: inline-block; outline: none; cursor: default; }
.person:focus-visible { outline: 2px solid #0072BC; outline-offset: 2px; border-radius: 3px; }
.person-name { display: block; font-weight: 600; white-space: nowrap; }
.person-email { display: block; font-size: 12.5px; color: #6b7280; white-space: nowrap; }

.stack-main { display: block; white-space: nowrap; }
.stack-sub { display: block; font-size: 12.5px; color: #6b7280; white-space: nowrap; }
.data-table td.muted { color: #6b7280; white-space: nowrap; }
.cap { text-transform: capitalize; }

.profile-card {
    /* Wide enough for an ordinary institutional address on one line. At 290px
       even mkitten@example.com broke across two, which reads as truncation. */
    width: 360px;
    max-width: min(360px, calc(100vw - 24px));
    padding: 14px 16px;
    white-space: normal;
    pointer-events: none;   /* a tooltip must never eat the click under it */
}
.profile-head {
    margin: 0 0 10px;
    padding-bottom: 8px;
    font-size: 14px;
    font-weight: 700;
    border-bottom: 1px solid #f1f2f4;
}
.profile-card dl {
    display: grid;
    grid-template-columns: 104px 1fr;
    gap: 5px 10px;
    margin: 0;
    font-size: 12.5px;
    line-height: 1.4;
}
.profile-card dt { color: #9ca3af; font-weight: 600; }
.profile-card dd { margin: 0; color: #111827; overflow-wrap: anywhere; }

tr.is-you { background: #f8fafc; }

/* ---------------------------------------------------------------------------
   Confirmation dialogs
   Native <dialog>: real modality, Escape to close, focus trapped, and no
   browser confirm() boxes.
   --------------------------------------------------------------------------- */

dialog.modal {
    /* A global `margin: 0` reset elsewhere in this file defeats the centring a
       native dialog normally gets for free, so pin and centre it explicitly. */
    position: fixed;
    inset: 0;
    margin: auto;
    width: min(440px, calc(100vw - 32px));
    height: fit-content;
    max-height: calc(100vh - 64px);
    padding: 24px;
    border: 0;
    border-radius: 10px;
    box-shadow: 0 20px 50px rgba(16, 24, 40, 0.22);
    background: #fff;
    color: inherit;
}
dialog.modal::backdrop { background: rgba(16, 24, 40, 0.45); }
dialog.modal h3 { margin: 0 0 6px; font-size: 17px; }
dialog.modal .modal-sub {
    margin: 0 0 18px;
    font-size: 13.5px;
    color: #6b7280;
    line-height: 1.5;
}
dialog.modal form { margin: 0; }
.modal-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
dialog.modal input[type="password"],
dialog.modal textarea {
    width: 100%;
    padding: 9px 11px;
    font: inherit;
    font-size: 14px;
    border: 1px solid #d1d5db;
    border-radius: 6px;
}
dialog.modal textarea { margin-bottom: 4px; resize: vertical; }
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 20px;
}

.you-tag {
    margin-left: 6px;
    padding: 1px 6px;
    font-size: 11px;
    font-weight: 600;
    color: #6b7280;
    background: #f3f4f6;
    border-radius: 4px;
}

/* ---------------------------------------------------------------------------
   Admin page furniture: headings, composers, FAQ list
   --------------------------------------------------------------------------- */

.page-head { margin-bottom: 18px; }
.page-head h2 { margin-bottom: 2px; }
.page-sub { margin: 0; font-size: 13.5px; color: #6b7280; line-height: 1.5; max-width: 640px; }

/* Add-forms start collapsed so the page opens on the content, not an empty form. */
.composer { margin-bottom: 26px; }
.composer > summary { list-style: none; cursor: pointer; display: inline-block; }
.composer > summary::-webkit-details-marker { display: none; }
.composer[open] > summary { margin-bottom: 14px; }

.stack-form {
    padding: 18px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    max-width: 720px;
}
.stack-form .field { margin-bottom: 14px; }
.stack-form label {
    display: block;
    margin-bottom: 5px;
    font-size: 12px;
    font-weight: 600;
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.stack-form input[type="text"], .stack-form input:not([type]), .stack-form textarea {
    width: 100%;
    padding: 9px 11px;
    font: inherit;
    font-size: 14px;
    border: 1px solid #d1d5db;
    border-radius: 6px;
}
.stack-form textarea { resize: vertical; }
.stack-form .hint {
    margin: 5px 0 0;
    font-size: 12px;
    color: #9ca3af;
    text-transform: none;
    letter-spacing: 0;
}
.check-inline {
    display: block;
    margin-bottom: 14px;
    font-size: 13.5px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    color: inherit;
}
.check-inline input { margin-right: 7px; }

.topic-head {
    margin: 26px 0 10px;
    padding-bottom: 7px;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #6b7280;
    border-bottom: 1px solid #e5e7eb;
}
.topic-count {
    margin-left: 6px;
    padding: 1px 7px;
    font-size: 11px;
    background: #f3f4f6;
    border-radius: 999px;
}

.faq-list { display: flex; flex-direction: column; gap: 10px; }
.faq-row {
    display: flex;
    gap: 20px;
    align-items: flex-start;
    justify-content: space-between;
    padding: 16px 18px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
}
.faq-row.is-hidden { background: #fafafa; border-style: dashed; }
.faq-row.is-hidden .faq-q, .faq-row.is-hidden .faq-a { opacity: 0.65; }
.faq-body { min-width: 0; }
.faq-q { margin: 0 0 6px; font-weight: 600; font-size: 14.5px; }
.faq-a { margin: 0; font-size: 13.5px; color: #4b5563; line-height: 1.55; }
.faq-actions { display: flex; gap: 6px; flex-shrink: 0; }
.faq-actions form { margin: 0; }

dialog.modal.modal-wide { width: min(620px, calc(100vw - 32px)); }
dialog.modal input[type="text"], dialog.modal input:not([type]) {
    width: 100%;
    margin-bottom: 4px;
    padding: 9px 11px;
    font: inherit;
    font-size: 14px;
    border: 1px solid #d1d5db;
    border-radius: 6px;
}

/* ---------------------------------------------------------------------------
   Dashboard section rail
   A fixed right-hand index of the page's own sections. Collapsed it is a stack
   of short rules; hovering or focusing it reveals the labels. The active
   section is tracked on scroll.
   --------------------------------------------------------------------------- */

.section-rail {
    position: fixed;
    top: 50%;
    right: 18px;
    transform: translateY(-50%);
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 10px 10px 14px;
    border-radius: 10px;
    background: transparent;
    transition: background var(--transition), box-shadow var(--transition);
}
.section-rail:hover,
.section-rail:focus-within {
    background: rgba(255, 255, 255, 0.92);
    box-shadow: var(--shadow-lg);
    backdrop-filter: blur(6px);
}

.rail-item {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    padding: 5px 2px;
    color: var(--color-text-secondary);
    text-decoration: none;
    border-radius: 6px;
}
.rail-label {
    max-width: 0;
    overflow: hidden;
    white-space: nowrap;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    opacity: 0;
    transition: max-width var(--transition-slow), opacity var(--transition);
}
.section-rail:hover .rail-label,
.section-rail:focus-within .rail-label { max-width: 190px; opacity: 1; }

.rail-dash {
    display: block;
    width: 18px;
    height: 2px;
    flex-shrink: 0;
    border-radius: 2px;
    background: var(--color-text-light);
    transition: width var(--transition), background var(--transition);
}
.rail-item:hover .rail-dash { background: var(--color-text-secondary); }
.rail-item.is-active .rail-dash { width: 26px; background: var(--color-accent); }
.rail-item.is-active { color: var(--color-accent); }
.rail-item:hover { color: var(--color-text); }

/* The rail would collide with the content column on narrow screens, and the
   page is short enough there that an index earns nothing. */
@media (max-width: 1280px) { .section-rail { display: none; } }
@media (prefers-reduced-motion: reduce) {
    .rail-label, .rail-dash, .section-rail { transition: none; }
}

/* ===================================================================
   QUIZ ADMIN
   A quiz is a topic, collapsed by default so the page opens as a list of
   quizzes rather than a wall of every question on the site.
   =================================================================== */
.quiz-block {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-bottom: 0.75rem;
}
.quiz-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.9rem 1.1rem; cursor: pointer; list-style: none;
  font-weight: 600; border-radius: var(--radius);
}
.quiz-summary::-webkit-details-marker { display: none; }
/* The triangle is drawn rather than inherited so it can rotate on open. */
.quiz-summary::before {
  content: ""; flex: 0 0 auto; width: 0; height: 0;
  border-left: 5px solid var(--color-text-secondary);
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform var(--transition);
}
.quiz-block[open] > .quiz-summary::before { transform: rotate(90deg); }
.quiz-summary:hover { background: var(--color-bg); }
.quiz-title { flex: 1; }
.quiz-meta { font-weight: 400; font-size: 0.85rem; color: var(--color-text-secondary); }
.quiz-body { padding: 0 1.1rem 1.1rem; }
.col-pos { width: 3rem; text-align: center; }
/* Archived questions stay listed -- they are the record of what was asked -- but
   should not read as live content. */
tr.is-archived td { opacity: 0.55; }

.opt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem 1rem; }
@media (max-width: 640px) { .opt-grid { grid-template-columns: 1fr; } }
/* [hidden] loses to the display rules on .form-group without this. */
[data-when-mcq][hidden], [data-when-numerical][hidden] { display: none !important; }
dialog.modal select, dialog.modal textarea { width: 100%; }

/* ===================================================================
   RESOURCE TYPE SECTIONS
   Present on /resources and /instructor whether or not they hold files.
   =================================================================== */
.res-group { margin-bottom: 2.5rem; }
.res-group:last-child { margin-bottom: 0; }
.res-group-title {
  font-size: 1.1rem; font-weight: 700; color: var(--color-navy);
  margin-bottom: 0.35rem;
}
/* No max-width. This carried a 60ch cap, missed in the sweep that removed the
   others on 2026-07-30. */
.res-group-blurb {
  font-size: 0.9rem; color: var(--color-text-secondary);
  margin-bottom: 1rem;
}
/* An empty section is a statement, so it gets a border and a colour rather than
   looking like a paragraph someone forgot to finish. */
.res-group-empty {
  font-size: 0.9rem; color: var(--color-text-secondary);
  background: var(--color-primary-50);
  border-left: 3px solid var(--color-primary);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 0.75rem 1rem; margin: 0;
}
.resource-card { display: flex; flex-direction: column; }
.resource-desc {
  font-size: 0.9rem; color: var(--color-text); line-height: 1.55;
  flex: 1; margin-bottom: 0.75rem;
}
.resource-meta { font-size: 0.78rem; color: var(--color-text-secondary); margin-bottom: 1rem; }

.page-sub { color: var(--color-text-secondary); font-size: 0.95rem; margin-top: 0.25rem; }
.count-chip {
  display: inline-block; min-width: 1.4rem; padding: 0.05rem 0.4rem;
  background: var(--color-primary-light); color: var(--color-primary);
  border-radius: var(--radius-pill);
  font-size: 0.78rem; font-weight: 700; text-align: center;
  vertical-align: 0.1rem;
}

/* Filtering hides rows, and an auto-layout table measures its columns from the
   rows it can see -- so every filter click re-measured and all four columns
   jumped, even though the table as a whole stayed the same width. Fixed layout
   takes the widths from the first row alone, which is the header, which never
   changes. */
#users-table { table-layout: fixed; }
#users-table th:nth-child(1) { width: 30%; }
#users-table th:nth-child(2) { width: 16%; }
#users-table th:nth-child(3) { width: 28%; }
#users-table th:nth-child(4) { width: 14%; }
#users-table th:nth-child(5) { width: 12%; }
/* Fixed columns cannot grow for a long address, so let one wrap rather than
   spill over the cell next to it. */
#users-table .person-email { overflow-wrap: anywhere; }

/* Role filter pills above the users table. */
.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
.filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.8rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
/* :not(.is-active) matters. The hover rule paints the label the primary blue,
   which is also the selected pill's background -- so hovering the pill you had
   just chosen turned its text invisible. */
.filter-pill:hover:not(:disabled):not(.is-active) {
  border-color: var(--color-primary); color: var(--color-primary);
}
.filter-pill.is-active:hover {
  background: var(--color-primary-dark); border-color: var(--color-primary-dark);
}
.filter-pill.is-active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}
/* A role nobody holds is shown but unclickable, so the set of roles stays
   visible rather than the bar changing shape as people register. */
.filter-pill:disabled { opacity: 0.45; cursor: default; }
.filter-count {
  font-size: 0.75rem;
  font-weight: 700;
  opacity: 0.75;
}

/* Sortable table headers. The arrow is a pseudo-element driven by aria-sort, so
   the accessible state and the visible state cannot disagree. */
.th-sort {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}
.th-sort::after {
  content: "\2195";          /* up-down arrow: sortable, not yet sorted */
  font-size: 0.9em;
  opacity: 0.35;
}
th[aria-sort="ascending"] .th-sort::after  { content: "\2191"; opacity: 1; }
th[aria-sort="descending"] .th-sort::after { content: "\2193"; opacity: 1; }
.th-sort:hover::after { opacity: 0.8; }

/* Required and optional markers on form labels. */
.req-mark { color: var(--color-error); font-weight: 700; }
.opt-mark {
  margin-left: 0.35rem;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--color-text-light);
  text-transform: none;
  letter-spacing: 0;
}
.form-legend { font-size: 0.8rem; color: var(--color-text-light); margin-bottom: 1rem; }

/* The password checklist, built by app.js so signup and the admin reset dialog
   get an identical one. Unmet reads as an outstanding item, met as done. */
.pwd-req-list { margin: 0.4rem 0 0; padding: 0; list-style: none; }
.pwd-req-list li {
  position: relative;
  padding-left: 1.15rem;
  font-size: 0.78rem;
  line-height: 1.7;
  color: var(--color-text-light);
}
.pwd-req-list li::before {
  content: "\2022";
  position: absolute;
  left: 0.15rem;
  color: var(--color-text-light);
}
.pwd-req-list li.req-met { color: var(--color-success); }
.pwd-req-list li.req-met::before { content: "\2713"; left: 0; color: var(--color-success); }

/* Inside a dialog the checklist and any error sit under the input, so the box
   grows rather than the message appearing somewhere else entirely. */
dialog.modal .pwd-req-list { margin-bottom: 0.5rem; }
dialog.modal .field-error { margin-bottom: 0.25rem; }

/* ---------------------------------------------------------------------------
   Toasts
   Confirmations used to render as a banner at the top of the content column,
   which pushed every heading down and made you re-read the page to find out
   what had happened. These sit over the page instead and take themselves away.
   --------------------------------------------------------------------------- */
.toast-stack {
  position: fixed;
  top: 0;
  left: 50%;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  width: max-content;
  max-width: min(90vw, 520px);
  transform: translateX(-50%);
  pointer-events: none;   /* never blocks the navbar underneath it */
}
.toast {
  padding: 0.7rem 1.1rem;
  font-size: 0.9rem;
  font-weight: 500;
  border-radius: 0 0 10px 10px;
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.16);
  pointer-events: auto;
  animation: toast-drop 260ms cubic-bezier(0.2, 0.8, 0.3, 1);
}
.toast-ok  { background: var(--color-success); color: #fff; }
.toast-err { background: var(--color-error);   color: #fff; }
.toast.is-leaving { animation: toast-lift 220ms ease forwards; }

@keyframes toast-drop { from { transform: translateY(-100%); opacity: 0; } }
@keyframes toast-lift { to   { transform: translateY(-100%); opacity: 0; } }

/* Someone who has asked for less motion gets the message without the movement. */
@media (prefers-reduced-motion: reduce) {
  .toast, .toast.is-leaving { animation: none; }
}

/* ===================================================================
   QUIZZES — chapter cards, and the instructors' full set
   -------------------------------------------------------------------
   The chapter cards started life on a separate /exercises page and
   moved here when the two surfaces merged (Marc, 2026-07-30). The
   .ex- prefix is kept because the instructor answer-key page still
   uses it and renaming across both buys nothing.

   No max-width on any prose here. Text takes the full column.
   =================================================================== */

.ex-instructor-note { margin-bottom: 2rem; max-width: none; }

.instr-answer-key { display: flex; flex-wrap: wrap; gap: 0.65rem; }

/* --- The two collapsible groups ---
   Closed by default. With the chapter cards open, the topic group sits below
   ten cards and is never found; closed, the page opens as a choice between two
   kinds of quiz. */
.qz-group {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  margin-bottom: 1rem;
  overflow: hidden;
}

/* qz-, not quiz-. `.quiz-summary` and `.quiz-block` already belong to the
   ADMIN quizzes page further up this file, and reusing the names here meant
   the admin rules applied to the reader page: its `align-items: center`
   centred the text, and its ::before triangle drew a second marker that could
   never rotate, because `.quiz-block[open]` does not match this markup.

   Modelled on .toc-summary, the working <details> on this site, and everything
   is set explicitly rather than relying on defaults. */
.qz-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1.1rem 1.35rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background var(--transition);
}
.qz-summary::marker,
.qz-summary::-webkit-details-marker { display: none; }
.qz-summary:hover { background: var(--color-bg); }
.qz-summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }

.qz-summary-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  text-align: left;
  min-width: 0;
}

.qz-summary-title { font-size: 1.1rem; font-weight: 700; color: var(--color-navy); }
.qz-summary-sub { font-size: 0.9rem; color: var(--color-text-secondary); line-height: 1.5; }

/* Chevron: ">" that rotates to "v" on open. */
.qz-summary::after {
  content: '';
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--color-text-light);
  border-bottom: 2px solid var(--color-text-light);
  transform: rotate(-45deg);
  transition: transform var(--transition), border-color var(--transition);
  flex-shrink: 0;
  margin-left: auto;
}
.qz-group[open] > .qz-summary::after {
  transform: rotate(45deg);
  border-color: var(--color-primary);
}
.qz-group[open] > .qz-summary { background: var(--color-bg); }

.qz-group > .ex-chapter-grid {
  padding: 1.25rem 1.35rem 1.5rem;
  border-top: 1px solid var(--color-border);
}

@media (prefers-reduced-motion: reduce) {
  .qz-summary, .qz-summary::after { transition: none; }
}

/* The instructor-only pointer to the full answer set. Carried over from the
   exercises page, which was where an instructor used to learn it exists. */
.qz-instr-note {
  background: var(--color-primary-light);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1.1rem;
  margin-bottom: 1.5rem;
}
.qz-instr-note p { margin: 0; font-size: 0.88rem; color: var(--color-text); }
.qz-instr-note a { color: var(--color-primary); font-weight: 600; }

.ex-chapter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
}

.ex-chapter-card {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.25rem 1.35rem;
  text-decoration: none;
  transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition);
}

.ex-chapter-card:hover {
  border-color: var(--color-primary);
  box-shadow: 0 6px 18px rgba(0, 105, 180, 0.14);
  transform: translateY(-2px);
}

.ex-chapter-card-num {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-primary);
}

.ex-chapter-card-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-navy);
  line-height: 1.3;
}

.ex-chapter-card-count { font-size: 0.82rem; color: var(--color-text-light); }

/* --- One question at a time --- */
.ex-practice {}

.ex-back {
  display: inline-block;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
  margin-bottom: 0.75rem;
}
.ex-back:hover { text-decoration: underline; }

.ex-progress { margin-bottom: 1rem; }

.ex-progress-text {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-light);
  margin-bottom: 0.5rem;
}

.ex-progress-bar {
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--color-border-light);
  overflow: hidden;
}

.ex-progress-fill {
  display: block;
  height: 100%;
  background: var(--color-primary);
  transition: width var(--transition);
}

.ex-practice-card { padding: 2rem; }

.ex-practice-question {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.6;
  color: var(--color-navy);
  margin: 0;
}

.ex-practice-prompt {
  font-size: 0.85rem;
  color: var(--color-text-light);
  font-style: italic;
  margin: 1.25rem 0 0;
}

/* The answer is only ever in the page once the reader has asked for it, so
   this block simply does not exist until then. */
.ex-practice-answer {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-border);
}

.ex-practice-answer-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin: 0 0 0.5rem;
}

.ex-practice-answer p:last-child {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-text-secondary);
  margin: 0;
}

.ex-practice-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 1.75rem;
}

.ex-practice-instr {
  font-size: 0.82rem;
  color: var(--color-text-light);
  margin-top: 1.5rem;
}
.ex-practice-instr a { color: var(--color-primary); text-decoration: none; }
.ex-practice-instr a:hover { text-decoration: underline; }

.ex-all-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-top: 1.25rem; }
