/* Portal stylesheet. The look follows Material Design 3 (m3.material.io).

   Three files, in this order on every page:
     carbon-tokens.css  GENERATED IBM Carbon colour tokens (light, dark, high contrast).
                        Never edit by hand; see scripts/generate_carbon_tokens.py.
     app.css            this file: system tokens (shape, elevation, state,
                        motion, type) and the structural layout of every page.
     m3-components.css  the Material 3 component styles: type scale, buttons,
                        text fields, cards, chips, navigation, dialogs.
   Staff pages also load staff.css between app.css and m3-components.css.

   Rules that keep it safe for this product:
   - Colours are only ever Material roles (--md-sys-color-*), used in their
     intended pairs (on-X on X), which is what keeps contrast above 4.5:1 in
     light, dark and high-contrast modes. No raw hex values below, except the white chip behind the logo.
   - No inline styles and no third-party fonts or scripts (CSP, and A10 for
     student pages). The type stack starts with Roboto, the Material default,
     which is on every Android phone, and falls back to the system font.
   - State layers (hover, focus, press) are drawn with color-mix over the
     component's own content colour, as the Material state spec describes. */

:root {
  /* Shape scale */
  --md-sys-shape-corner-extra-small: 4px;
  --md-sys-shape-corner-small: 8px;
  --md-sys-shape-corner-medium: 12px;
  --md-sys-shape-corner-large: 16px;
  --md-sys-shape-corner-extra-large: 28px;
  --md-sys-shape-corner-full: 9999px;

  /* Elevation levels 1 to 3 (levels 0 is none). Tonal surface containers carry
     most of the depth; the shadow is the secondary cue. */
  --md-sys-elevation-1: 0 1px 2px rgb(0 0 0 / 0.3), 0 1px 3px 1px rgb(0 0 0 / 0.15);
  --md-sys-elevation-2: 0 1px 2px rgb(0 0 0 / 0.3), 0 2px 6px 2px rgb(0 0 0 / 0.15);
  --md-sys-elevation-3: 0 1px 3px rgb(0 0 0 / 0.3), 0 4px 8px 3px rgb(0 0 0 / 0.15);

  /* State layer opacities */
  --md-sys-state-hover: 8%;
  --md-sys-state-focus: 10%;
  --md-sys-state-pressed: 10%;

  /* Motion */
  --md-sys-motion-easing-standard: cubic-bezier(0.2, 0, 0, 1);
  --md-sys-motion-easing-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
  --md-sys-motion-duration-short2: 100ms;
  --md-sys-motion-duration-short4: 200ms;
  --md-sys-motion-duration-medium2: 300ms;

  /* Type. Roboto is the Material default; Noto Sans Devanagari covers Hindi
     where the device has it. Line heights are multiplied by --md-lang-height,
     which Material asks for in taller scripts (Hindi is about 7% taller). */
  --md-ref-typeface-plain: Roboto, "Segoe UI", system-ui, -apple-system,
    "Noto Sans Devanagari", "Nirmala UI", sans-serif;
  --md-lang-height: 1;

  /* The older names every existing rule in this file and in the templates
     still uses, now defined as Material roles. */
  --bg: var(--md-sys-color-surface);
  --surface: var(--md-sys-color-surface-container-lowest);
  --surface-muted: var(--md-sys-color-surface-container-low);
  --text: var(--md-sys-color-on-surface);
  --text-muted: var(--md-sys-color-on-surface-variant);
  --border: var(--md-sys-color-outline-variant);
  --accent: var(--md-sys-color-primary);
  --accent-bg: var(--md-sys-color-primary);
  --on-accent: var(--md-sys-color-on-primary);
  --badge-open-bg: var(--md-sys-color-primary-container);
  --badge-open-fg: var(--md-sys-color-on-primary-container);
  --badge-scheduled-bg: var(--md-sys-color-tertiary-container);
  --badge-scheduled-fg: var(--md-sys-color-on-tertiary-container);
  --badge-closed-bg: var(--md-sys-color-surface-container-highest);
  --badge-closed-fg: var(--md-sys-color-on-surface-variant);
  --health-ok-bg: var(--md-sys-color-success-container);
  --health-ok-fg: var(--md-sys-color-on-success-container);
  --brand-red: var(--md-sys-color-error);
  --brand-orange: var(--md-sys-color-tertiary);
  --success: var(--md-sys-color-success);
  --danger: var(--md-sys-color-error);
  --danger-bg: var(--md-sys-color-error);
  --danger-soft: var(--md-sys-color-error-container);
  --radius: var(--md-sys-shape-corner-medium);
  --shadow-sm: none;
  --scrim: color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent);
}

:lang(hi) {
  --md-lang-height: 1.07;
}

@media screen and (prefers-color-scheme: dark) {
  /* The logo files are opaque white-background PNGs; on a dark page they'd
     be white rectangles, so they sit on a white rounded chip instead. */
  .brand-mark,
  .landing-logo {
    background: #fff;
    border-radius: var(--md-sys-shape-corner-medium);
    padding: 3px;
  }

  .landing-logo {
    padding: 10px;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  line-height: 1.5;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--surface);
  color: var(--accent);
  padding: 0.6rem 1rem;
  border-radius: 0 0 6px 0;
}

/* A label, caption, or status text a sighted user doesn't need (the
   visible text/layout already carries it) but a screen reader still
   needs announced — e.g. a table's caption or an icon-only field's
   label. Off-screen, not display:none, so it's still read. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link:focus {
  left: 0;
}

/* apps.feedback.templatetags.icons — every {% icon %} call renders one of
   these. Sized to sit on the text baseline next to the label it's paired
   with, color inherited from whatever wraps it (stroke="currentColor"). */
.icon {
  display: inline-block;
  vertical-align: -3px;
  flex-shrink: 0;
}

/* Color modifiers for a standalone status icon (CSP's style-src forbids
   inline style="color:…", so this is a class, not an attribute). */
.icon-success { color: var(--success); }
.icon-danger { color: var(--brand-red); }
.icon-warn { color: var(--brand-orange); }

.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding: 0.85rem 1.5rem;
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--accent);
}

.brand-mark {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  object-fit: contain;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.9em;
}

.user-email {
  display: none;
}

@media (min-width: 560px) {
  .user-email {
    display: inline;
  }
}

.site-nav form {
  margin: 0;
  display: inline-flex;
}

.link-button {
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
}

button.link-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

.link-button:hover {
  text-decoration: underline;
}

@media (max-width: 480px) {
  .brand-text {
    font-size: 1rem;
  }
}

.staff-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.5rem;
  padding: 0.65rem 1.5rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.92em;
}

.staff-nav a {
  color: var(--text-muted);
  text-decoration: none;
  font-weight: 500;
  padding-bottom: 0.2rem;
  border-bottom: 2px solid transparent;
}

.staff-nav a:hover {
  color: var(--accent);
}

.staff-nav a.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.container {
  flex: 1;
}

.site-footer {
  padding: 1.25rem 1.5rem;
  border-top: 1px solid var(--border);
  margin-top: 2rem;
}

.site-footer p {
  max-width: 720px;
  margin: 0 auto;
}

/* --- Response-rate nudge (student-facing, brief A5's "completion counts
   are always safe to show" extended to the enrolled students themselves —
   never who has responded, only how many). Bucketed width classes instead
   of an inline style="width:%" attribute, which CSP's style-src would
   block. --- */
.progress-track {
  background: var(--border);
  border-radius: 999px;
  height: 8px;
  overflow: hidden;
  margin: 0.5rem 0 0.35rem;
}

.progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 999px;
}

.progress-text {
  margin: 0 0 0.6rem;
  font-size: 0.9em;
  color: var(--text-muted);
}

.pct-0 { width: 0%; }
.pct-10 { width: 10%; }
.pct-20 { width: 20%; }
.pct-30 { width: 30%; }
.pct-40 { width: 40%; }
.pct-50 { width: 50%; }
.pct-60 { width: 60%; }
.pct-70 { width: 70%; }
.pct-80 { width: 80%; }
.pct-90 { width: 90%; }
.pct-100 { width: 100%; }

/* --- Sign-in landing page --- */
.landing-hero {
  text-align: center;
  padding-top: 2rem;
}

.landing-logo {
  width: 100%;
  max-width: 220px;
  height: auto;
  margin: 0 auto 1.5rem;
  display: block;
}

.landing-hero .button {
  font-size: 1rem;
}

.button-google {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
}

.google-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  background: #fff;
  border-radius: 4px;
}

.container {
  max-width: 720px;
  margin: 0 auto;
  padding: 1.5rem;
}

.button {
  display: inline-block;
  padding: 0.6rem 1.2rem;
  background: var(--accent-bg);
  color: var(--on-accent);
  border: none;
  border-radius: 6px;
  text-decoration: none;
  font: inherit;
  font-size: 1rem;
  cursor: pointer;
}

/* A text link or button with an {% icon %} in front of it — print/
   export/remind/hide actions across every staff and results template.
   Placed after .button/.link-button so it wins their `display` when
   combined on the same element (e.g. class="button action-link"). */
.action-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* Every data-confirm button is, by definition, an irreversible action
   (see static/js/confirm_forms.js) — giving it a visibly different,
   outlined-red treatment means Cancel/Purge/Hide/Confirm-and-apply read as
   distinct from routine buttons at a glance, not just on click. */
button[data-confirm] {
  background: var(--surface);
  color: var(--danger);
  border: 1px solid var(--danger);
  border-radius: 6px;
  padding: 0.4rem 0.8rem;
  font: inherit;
  cursor: pointer;
}

button[data-confirm]:hover {
  background: var(--danger-soft);
}

button[data-confirm]:disabled,
button:disabled {
  opacity: 0.6;
  cursor: default;
}

/* --- Client-side table filter (static/js/table_filter.js) --- */
.table-filter {
  margin-top: 1rem;
  max-width: 320px;
}

.table-filter-status {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.85em;
  color: var(--text-muted);
}

/* Every <table> is wrapped in this — lets a wide table scroll horizontally
   on a narrow screen instead of overflowing the page or clipping. The
   table itself keeps display:table (the wrapper scrolls, not the table),
   so its column layout is untouched. */
.table-scroll {
  position: relative; /* keeps visually-hidden labels inside the scroll box, not the page */
  overflow-x: auto;
  overflow-y: hidden;
  margin-top: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  background: var(--surface);
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1rem;
}

.table-scroll table {
  margin-top: 0;
}

.table-scroll thead th {
  background: var(--surface-muted);
}

th, td {
  text-align: left;
  padding: 0.5rem;
  border-bottom: 1px solid var(--border);
}

.table-scroll tbody tr:last-child td {
  border-bottom: none;
}

.muted { color: var(--text-muted); }

.notice {
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: 1rem;
  background: var(--surface);
}

.notice-success { color: var(--success); }
.notice-error { color: var(--danger); }

/* --- Stat tiles (F1/F5 dashboards): the handful of headline numbers a
   staff member actually came to check, before the detail tables below.
   A plain flex row of cards, not a grid — reflows naturally at any width
   with no extra media query needed. --- */
.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 1rem 0 1.5rem;
}

.stat-tile {
  flex: 1 1 160px;
  padding: 0.85rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  background: var(--surface);
}

.stat-tile-value {
  display: block;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--accent);
  line-height: 1.2;
}

.stat-tile-label {
  display: block;
  font-size: 0.85em;
  color: var(--text-muted);
  margin-top: 0.15rem;
}

.stat-tile-warn .stat-tile-value { color: var(--brand-red); }

/* --- Student home cards --- */

.card-list {
  list-style: none;
  padding: 0;
  margin: 0 0 1.5rem;
}

.card {
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: 0.75rem;
  background: var(--surface);
}

.card .button {
  margin-top: 0.5rem;
}

/* Left-border accent per student-home section (brief S2's four groups) —
   color alone is never the only signal (each section already has its own
   heading), just a faster visual sort when scanning several cards. */
.card-awaiting { border-left-color: var(--accent); }
.card-completed { border-left-color: var(--success); }
.card-not-available { border-left-color: var(--brand-red); }
.card-opening-soon { border-left-color: var(--brand-orange); }

/* --- Empty states (no cycles/comments/rows match) — a small icon plus
   the existing .muted text reads less like a stray bug than plain text
   alone, at basically no cost. --- */
.empty-state {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-muted);
  padding: 0.5rem 0;
}

.empty-state .icon { flex-shrink: 0; }

details {
  margin-bottom: 1.5rem;
}

/* --- Feedback form --- */

fieldset {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1rem;
  margin-bottom: 1.5rem;
}

legend {
  font-weight: 600;
  padding: 0 0.4rem;
}

.question {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.question:last-child {
  border-bottom: none;
}

.question-text {
  font-weight: 500;
  margin: 0 0 0.5rem;
  display: block;
}

.required {
  color: var(--danger);
}

.question-error {
  background: var(--danger-soft);
}

.field-error {
  color: var(--danger);
  margin: 0.25rem 0 0;
  font-size: 0.9em;
}

/* Likert/Yes-No radio group, styled as a segmented control — a row of
   pills on desktop (a "grid" of question × option, brief S6), stacked
   one-per-line on narrow screens. Django's default RadioSelect markup is
   `<div id="id_q_N"><div><label><input>text</label></div>...</div>`, not
   the `<ul><li>` this rule set used to target (that never matched
   anything — dead CSS, found and replaced during the M7+ audit).
   `:has()` is used instead of a `:checked` sibling selector because the
   input is a *child* of the label here, not a preceding sibling. */
.question > div {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.6rem;
}

.question > div > div > label:has(input[type="radio"]) {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.92em;
}

.question > div > div > label:has(input[type="radio"]):hover {
  border-color: var(--accent);
}

.question > div > div > label:has(input[type="radio"]:checked) {
  background: var(--accent-bg);
  border-color: var(--accent-bg);
  color: var(--on-accent);
}

.question > div > div > label:has(input[type="radio"]:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The native radio dot is redundant once the whole pill shows selection
   via background — kept in the accessibility tree (not display:none),
   just visually tucked away. */
.question > div > div > label:has(input[type="radio"]) input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

@media (max-width: 480px) {
  .question > div {
    flex-direction: column;
    align-items: stretch;
  }

  .question > div > div > label:has(input[type="radio"]) {
    justify-content: center;
  }
}

/* Students overwhelmingly submit on phones. WCAG 2.5.8 wants a 24px
   minimum target; 44px is the size that's actually comfortable to hit
   with a thumb, so on any touch-primary device the pills get that. */
@media (pointer: coarse) {
  .question > div > div > label:has(input[type="radio"]) {
    min-height: 44px;
  }
}

/* --- Form progress (feedback form header): question count + time
   estimate, a bar that static/js/form_progress.js fills as questions are
   answered, and a live "N required left" line. The bar is aria-hidden
   because the text line below it already says the same thing. --- */
.form-progress {
  margin: 0 0 1.25rem;
}

.form-meta {
  margin: 0 0 0.35rem;
  color: var(--text-muted);
  font-size: 0.92em;
}

/* --- Sign-in landing: the three trust points under the button --- */
.landing-points {
  list-style: none;
  margin: 2rem auto 0;
  padding: 0;
  max-width: 460px;
  text-align: left;
}

.landing-points li {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
  font-size: 0.95em;
}

.landing-points li:first-child {
  border-top: none;
}

.landing-points .icon {
  margin-top: 0.15rem;
}

/* --- Generic staff form fields (quick-add offering, and reusable for any
   future one-off staff form) --- */
.form-field {
  margin-bottom: 1rem;
}

.form-field label {
  display: block;
  font-weight: 500;
  margin-bottom: 0.25rem;
}

.small {
  font-size: 0.85em;
  margin: 0.15rem 0 0;
}

.cohort-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

.cohort-row label {
  margin: 0;
}

.cohort-row select,
.cohort-row input {
  width: auto;
  max-width: 220px;
}

/* --- Staff cycle actions (F4): several small per-row forms side by side --- */
.inline-form {
  display: inline-block;
  margin: 0 0.25rem 0.25rem 0;
}

/* --- Results dashboard (F7) --- */
.distribution {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.9em;
}

.comment-list {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
}

.comment-list li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}

.hidden-comment {
  color: var(--text-muted);
}

.badge {
  display: inline-block;
  padding: 0.1rem 0.4rem;
  border-radius: var(--md-sys-shape-corner-small);
  /* The neutral Material pairing: on-surface-variant on a surface container.
     Status badges below replace both with their own container pair. */
  background: var(--md-sys-color-surface-container-highest);
  color: var(--md-sys-color-on-surface-variant);
  font-size: 0.8em;
  margin-right: 0.4rem;
}

/* Cycle status variants (F4/F5). The status word is always present as
   text, so the tint is a scanning aid, never the only signal. Each text
   color is >= 4.5:1 on its own tint (measured 6.0-10.4:1). */
.badge-open { background: var(--badge-open-bg); color: var(--badge-open-fg); }
.badge-scheduled { background: var(--badge-scheduled-bg); color: var(--badge-scheduled-fg); }
.badge-closed { background: var(--badge-closed-bg); color: var(--badge-closed-fg); }
.badge-cancelled { background: var(--danger-soft); color: var(--danger); }

/* --- Numeric table columns: right-aligned, fixed-width digits, so a
   column of percentages and counts lines up and can be read down. --- */
.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* --- Inline response-rate bar ({% rate_bar %}) — the same track/fill and
   `pct-N` bucket classes as the student-facing nudge, just small enough
   to sit beside the number in a table cell. --- */
.rate-cell {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
}

.progress-track-mini {
  display: inline-block;
  width: 64px;
  height: 6px;
  margin: 0;
  vertical-align: middle;
}

.progress-track-mini .progress-fill {
  display: block;
}

/* --- Breadcrumbs on the completion/results drill-downs --- */
.breadcrumbs ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.4rem;
  margin: 0 0 0.75rem;
  padding: 0;
  font-size: 0.88em;
  color: var(--text-muted);
}

.breadcrumbs li + li::before {
  content: "/";
  margin-right: 0.4rem;
  color: var(--border);
}

.breadcrumbs a {
  color: var(--text-muted);
}

.breadcrumbs a:hover {
  color: var(--accent);
}

.breadcrumbs [aria-current="page"] {
  color: inherit;
  font-weight: 500;
}

/* --- Page header: title block on the left, that page's primary actions
   (export, print, remind) on the right, wrapping under it on a narrow
   screen instead of floating in a <p> further down. --- */
.page-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.75rem 1.5rem;
  margin-bottom: 1rem;
}

.page-header h1 {
  margin: 0 0 0.35rem;
}

.page-header p {
  margin: 0 0 0.25rem;
}

.page-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  padding-top: 0.35rem;
}

.page-actions form {
  margin: 0;
}

/* --- Sortable headers (static/js/table_sort.js wraps each header's text
   in this button at runtime). --- */
.sort-btn {
  all: unset;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font: inherit;
  cursor: pointer;
}

.sort-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sort-btn::after {
  content: "";
  display: inline-block;
  width: 0.6em;
  color: var(--text-muted);
  font-size: 0.75em;
}

th[aria-sort="ascending"] .sort-btn::after { content: "\25B2"; }
th[aria-sort="descending"] .sort-btn::after { content: "\25BC"; }

/* --- Confirmation dialog (static/js/confirm_forms.js): the page's one
   native <dialog>, replacing the browser's raw window.confirm box. --- */
.dialog {
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) + 4px);
  padding: 1.25rem 1.5rem;
  max-width: min(420px, calc(100vw - 2rem));
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
  color: inherit;
  background: var(--surface);
}

.dialog::backdrop {
  background: var(--scrim);
}

.dialog p {
  margin: 0 0 1.25rem;
  font-size: 1rem;
  line-height: 1.5;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
}

.dialog .button {
  min-height: 44px;
  padding: 0.55rem 1.1rem;
}

.button-secondary {
  background: var(--surface);
  color: var(--accent);
  border: 1px solid var(--border);
}

.button-danger {
  background: var(--danger-bg);
}

@media (max-width: 600px) {
  .dialog-actions {
    flex-direction: column-reverse;
  }

  .dialog .button {
    width: 100%;
  }
}

/* --- Urgency on awaiting cards ("Closes tomorrow"): the words always
   appear, so the colour is only an accent (4.5:1+ on its tint). --- */
.badge-urgent {
  background: var(--danger-soft);
  color: var(--danger);
  font-weight: 600;
}

.calendar-link {
  margin-left: 0.5rem;
  font-size: 0.9em;
}

/* --- Error pages (400/403/404/429/500) --- */
.error-page {
  text-align: center;
  padding: 2.5rem 0 1rem;
  max-width: 480px;
  margin: 0 auto;
}

.error-icon {
  display: inline-block;
  margin-bottom: 0.5rem;
}

.error-page h1 {
  margin-top: 0;
}

/* --- Staff health page --- */
.health-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.health-item {
  display: flex;
  gap: 0.9rem;
  align-items: flex-start;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--border);
}

.health-item:last-child {
  border-bottom: none;
}

.health-badge {
  flex-shrink: 0;
  min-width: 4.2rem;
  text-align: center;
  margin-right: 0;
  font-weight: 600;
}

.badge-health-ok { background: var(--health-ok-bg); color: var(--health-ok-fg); }
.badge-health-warn { background: var(--badge-scheduled-bg); color: var(--badge-scheduled-fg); }
.badge-health-fail { background: var(--danger-soft); color: var(--danger); }

.health-overall.health-ok { color: var(--health-ok-fg); }
.health-overall.health-warn { color: var(--badge-scheduled-fg); }
.health-overall.health-fail { color: var(--danger); }

/* --- Student response flow: free-text controls. The short-text <input>
   had no rule at all (browser default ~13px, which also makes iOS Safari
   zoom the page on focus); both now share one look, at the body size. --- */
/* Django's Textarea default is rows=10 — most of a phone screen for an
   optional comment. An explicit height wins over `rows`; still resizable. */
.question textarea {
  height: 7rem;
  min-height: 4rem;
  resize: vertical;
}

/* The one button the whole product exists for. Larger than the default
   .button, and full-width on phones (below). */
.button-primary {
  font-size: 1rem;
  padding: 0.75rem 1.5rem;
  min-height: 44px;
}

/* --- Phones (brief S6: mobile-first — most students respond on one).
   Applies to every page, but every rule here is chosen for the student
   flow: landing -> home -> form -> thanks. --- */
@media (max-width: 600px) {
  .container {
    padding: 1rem;
  }

  .site-header,
  .staff-nav {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  h1 {
    font-size: 1.75rem;
    line-height: 1.25;
  }

  h2 {
    font-size: 1.25rem;
  }

  /* The Appendix B notice is required in full (brief S3); tighter type
     keeps it from filling the whole first screen before the questions. */
  .notice-anonymity {
    font-size: 0.9em;
    line-height: 1.45;
    padding: 0.8rem 0.9rem;
  }

  /* Progress stays in view while scrolling a long form, so a student
     always knows what's left without going back to the top. Sticky, not
     fixed, so it never covers the header or the submit button. */
  .form-progress {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--bg);
    margin: 0 -1rem 1rem;
    padding: 0.6rem 1rem 0.5rem;
    border-bottom: 1px solid var(--border);
  }

  .form-progress .progress-track {
    margin-top: 0.35rem;
  }

  fieldset {
    padding: 0.75rem;
  }

  .question {
    padding: 0.85rem 0;
  }

  /* Thumb-sized, full-width primary actions: Sign in, Give feedback,
     Submit feedback. Staff-only controls keep their inline size. */
  .landing-hero .button,
  .card > .button,
  .button-primary {
    display: flex;
    justify-content: center;
    width: 100%;
    min-height: 48px;
  }

  .button-google {
    gap: 0.75rem;
  }

  .landing-hero {
    padding-top: 1rem;
  }

  .landing-logo {
    max-width: 180px;
    margin-bottom: 1rem;
  }

  .stat-tile {
    flex-basis: calc(50% - 0.375rem);
  }
}

/* --- Wide screens: the form is read-and-click, so a bit more room than
   the default column lets the five Likert pills sit on one line with
   the question text beside them instead of wrapping. --- */
@media (min-width: 900px) {
  .container {
    max-width: 800px;
  }
}

/* Print-friendly report page (brief F7): browser print to PDF, no
   server-side PDF library — hide navigation chrome, keep only content. */
@media print {
  .site-header,
  .staff-nav,
  .breadcrumbs,
  .inline-form,
  .page-actions,
  .table-filter,
  .distribution-chart-wrap,
  a.button,
  .notice a {
    display: none;
  }

  /* Print gets the text distribution, never the canvas. */
  .has-chart .distribution {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    white-space: normal;
  }

  .sort-btn::after {
    content: "";
  }
}

/* --- Offering report: peer benchmark line and comment-theme words --- */
.benchmark {
  margin: -0.25rem 0 1rem;
}

.themes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.25rem;
  margin: 0 0 0.5rem;
}

.themes-label {
  margin-right: 0.35rem;
}

/* --- Audit log filters, calendar weeks, term checklist, pagination --- */
.audit-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 1rem;
  margin-bottom: 1rem;
}

.audit-filters .form-field {
  margin: 0;
}

.pagination {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 1rem;
}

.calendar-week {
  margin-bottom: 1.25rem;
}

.calendar-week h2 {
  margin: 0 0 0.4rem;
  font-size: 1rem;
}

.calendar-current {
  border-left: 3px solid var(--accent);
  padding-left: 0.75rem;
}

.calendar-events {
  list-style: none;
  margin: 0;
  padding: 0;
}

.calendar-events li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.6rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}

.calendar-events li:last-child {
  border-bottom: none;
}

.calendar-day {
  min-width: 6.5rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.checklist {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
  line-height: 1.7;
}

/* --- Header: language switch beside the account links --- */
.header-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.lang-switch {
  margin: 0;
  display: inline-flex;
}

.lang-switch .link-button {
  font-size: 0.9em;
}

/* --- Header: language switch beside the account links --- */
.header-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.lang-switch {
  margin: 0;
  display: inline-flex;
}

.lang-switch .link-button {
  font-size: 0.9em;
}

/* --- Shared page intro and the Help page (students, faculty and staff all see these) --- */
.page-lede {
  max-width: 46rem;
  color: var(--text-muted);
  margin: 0.15rem 0 0;
}

/* --- Help ------------------------------------------------------------------------- */
.help-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}

.help-toc a {
  display: inline-block;
  padding: 0.3rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text);
  text-decoration: none;
  font-size: 0.875rem;
}

.help-toc a:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.help-article {
  max-width: 46rem;
}

.help-article h2 {
  margin-top: 2rem;
  scroll-margin-top: 5rem;
}

.help-article details {
  border-bottom: 1px solid var(--border);
  padding: 0.6rem 0;
}

.help-article summary {
  cursor: pointer;
  font-weight: 600;
}

.help-article details p {
  margin: 0.5rem 0 0.2rem;
}


/* --- Public anonymity page --- */
.anon-section {
  margin-top: 1.75rem;
}

.anon-section h2 {
  margin: 0 0 0.5rem;
  font-size: 1.125rem;
}

.anon-section h3 {
  margin: 1.25rem 0 0;
  font-size: 1rem;
}

.anon-points {
  margin: 0;
  padding-left: 1.2rem;
  line-height: 1.6;
}

.anon-banner {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.5rem 0;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  font-weight: 600;
}

.anon-banner-ok {
  background: var(--health-ok-bg);
  color: var(--health-ok-fg);
}

.anon-banner-fail {
  background: var(--danger-soft);
  color: var(--danger);
  border: 1px solid var(--danger);
}

.anon-checks {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
}

.anon-checks li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}

.anon-checks .icon {
  flex-shrink: 0;
  margin-top: 0.15rem;
}

.anon-ok .icon {
  color: var(--success);
}

.anon-fail {
  color: var(--danger);
  font-weight: 600;
}

.anon-section code {
  font-size: 0.85em;
  overflow-wrap: anywhere;
}
