/* Material 3 component layer. Mobile-first: every interactive target is >=48dp,
   layouts are single-column until 720px, and the type scale is the M3 one.
   Icons are inline SVG (see templates/_icons.html) rather than the Material
   Symbols webfont -- no third-party request from a student's phone on campus
   wifi, and nothing to fail on a captive portal. */

/* ---- type scale ---------------------------------------------------------- */
:root {
  --md-sys-typescale-font: system-ui, -apple-system, "Segoe UI", Roboto,
                           "Helvetica Neue", Arial, sans-serif;

  --md-sys-shape-xs: 4px;  --md-sys-shape-sm: 8px;  --md-sys-shape-md: 12px;
  --md-sys-shape-lg: 16px; --md-sys-shape-xl: 28px; --md-sys-shape-full: 999px;

  --md-sys-elevation-1: 0 1px 2px rgba(0,0,0,.30), 0 1px 3px 1px rgba(0,0,0,.15);
  --md-sys-elevation-2: 0 1px 2px rgba(0,0,0,.30), 0 2px 6px 2px rgba(0,0,0,.15);
  --md-sys-elevation-3: 0 1px 3px rgba(0,0,0,.30), 0 4px 8px 3px rgba(0,0,0,.15);

  --md-sys-motion-standard: cubic-bezier(.2, 0, 0, 1);
}

.display-large  { font: 400 3.5625rem/4rem var(--md-sys-typescale-font); letter-spacing:-.015em; }
.display-medium { font: 400 2.8125rem/3.25rem var(--md-sys-typescale-font); }
.display-small  { font: 400 2.25rem/2.75rem var(--md-sys-typescale-font); }
.headline-large { font: 400 2rem/2.5rem var(--md-sys-typescale-font); }
.headline-medium{ font: 400 1.75rem/2.25rem var(--md-sys-typescale-font); }
.headline-small { font: 400 1.5rem/2rem var(--md-sys-typescale-font); }
.title-large    { font: 400 1.375rem/1.75rem var(--md-sys-typescale-font); }
.title-medium   { font: 500 1rem/1.5rem var(--md-sys-typescale-font); letter-spacing:.009em; }
.title-small    { font: 500 .875rem/1.25rem var(--md-sys-typescale-font); letter-spacing:.007em; }
.body-large     { font: 400 1rem/1.5rem var(--md-sys-typescale-font); letter-spacing:.031em; }
.body-medium    { font: 400 .875rem/1.25rem var(--md-sys-typescale-font); letter-spacing:.018em; }
.body-small     { font: 400 .75rem/1rem var(--md-sys-typescale-font); letter-spacing:.033em; }
.label-large    { font: 500 .875rem/1.25rem var(--md-sys-typescale-font); letter-spacing:.007em; }
.label-medium   { font: 500 .75rem/1rem var(--md-sys-typescale-font); letter-spacing:.042em; }
.label-small    { font: 500 .6875rem/1rem var(--md-sys-typescale-font); letter-spacing:.045em; }

/* ---- accessibility foundations ------------------------------------------- */
/* A visible focus indicator on every interactive element. M3's own guidance and
   WCAG 2.4.11 both want the ring to survive against the element it surrounds,
   so it is drawn as an outline plus an offset ring in the opposite tone. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--md-sys-color-primary);
  outline-offset: 2px;
  border-radius: var(--md-sys-shape-xs);
}
/* Never remove the indicator for keyboard users; only suppress the mouse ring. */
:where(a, button, summary):focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: absolute; left: 8px; top: -100px; z-index: 20;
  padding: 12px 20px; border-radius: var(--md-sys-shape-sm);
  background: var(--md-sys-color-inverse-surface);
  color: var(--md-sys-color-inverse-on-surface);
  font: 500 1rem/1.5 var(--md-sys-typescale-font);
  transition: top .15s var(--md-sys-motion-standard);
}
.skip-link:focus { top: 8px; }

/* Users who ask the OS for more contrast get heavier borders and no
   low-opacity text, rather than the default tonal surfaces. */
@media (prefers-contrast: more) {
  .card, .chip, .field input, .field select, .field textarea {
    border: 2px solid var(--md-sys-color-on-surface) !important;
  }
  .card__sub, .list-item__sub, .field__label, .field__help,
  .top-app-bar__sub { color: var(--md-sys-color-on-surface) !important; }
  .btn { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: -2px; }
  .divider { background: var(--md-sys-color-on-surface); }
}

/* ---- base ---------------------------------------------------------------- */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--md-sys-color-background);
  color: var(--md-sys-color-on-background);
  font: 400 1rem/1.5rem var(--md-sys-typescale-font);
  -webkit-font-smoothing: antialiased;
  padding-bottom: env(safe-area-inset-bottom);
}
a { color: var(--md-sys-color-primary); text-decoration: none; }

/* WCAG 1.4.1: a link inside a run of prose must be tellable from that prose by
   something other than color. Links shaped like controls opt out -- a button,
   a chip or a list row is already distinguishable by its box. admin.css has
   carried this rule for the console since the desktop shell landed; without
   the same rule here every page on the mobile shell was one prose link away
   from a serious violation, and /admin/login duly became one. */
p a:not(.btn):not(.chip):not(.list-item):not(.skip-link),
li:not(.list-item) a:not(.btn):not(.chip):not(.skip-link) {
  text-decoration: underline;
  text-underline-offset: 2px;
}
svg.icon { width: 24px; height: 24px; fill: currentColor; flex: none; display: block; }
svg.icon--sm { width: 20px; height: 20px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0; padding: 0; margin: -1px;
}

/* Branding ------------------------------------------------------------------ */
.wordmark { display: inline-flex; align-items: center; gap: 8px; }
.wordmark__text {
  font: 600 calc(var(--wm, 28px) * .95)/1 var(--md-sys-typescale-font);
  letter-spacing: -.02em; color: var(--md-sys-color-on-surface);
}
.cat { display: block; flex: none; }
.cat-strip { display: flex; justify-content: center; gap: 4px; flex-wrap: wrap; }

/* The typed code shown on the projector for anyone who cannot scan. */
.typed-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700; letter-spacing: .18em;
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  padding: .25em .6em; border-radius: var(--md-sys-shape-sm);
  display: inline-block;
}

/* ---- layout -------------------------------------------------------------- */
.scaffold { min-height: 100dvh; display: flex; flex-direction: column; }
.content { flex: 1; padding: 16px; max-width: 840px; width: 100%; margin: 0 auto; }
.content--narrow { max-width: 480px; }
.content--nav { padding-bottom: 96px; }   /* clear the bottom nav bar */
.stack > * + * { margin-top: 16px; }
.row { display: flex; gap: 12px; flex-wrap: wrap; }
.row > .grow { flex: 1 1 160px; min-width: 0; }
.spacer { flex: 1; }
.center { text-align: center; }

/* ---- top app bar --------------------------------------------------------- */
.top-app-bar {
  display: flex; align-items: center; gap: 4px;
  min-height: 64px; padding: 8px 4px 8px 4px;
  background: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
  position: sticky; top: 0; z-index: 5;
  padding-top: calc(8px + env(safe-area-inset-top));
}
.top-app-bar--scrolled { background: var(--md-sys-color-surface-container); box-shadow: var(--md-sys-elevation-1); }
.top-app-bar__title { flex: 1; min-width: 0; padding: 0 8px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.top-app-bar__sub { color: var(--md-sys-color-on-surface-variant); }

/* ---- icon button (48dp target) ------------------------------------------- */
.icon-btn {
  width: 48px; height: 48px; border: 0; background: none; cursor: pointer;
  border-radius: var(--md-sys-shape-full);
  color: var(--md-sys-color-on-surface-variant);
  display: inline-flex; align-items: center; justify-content: center;
  position: relative; flex: none;
}
.icon-btn::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: currentColor; opacity: 0; transition: opacity .15s var(--md-sys-motion-standard);
}
.icon-btn:hover::before { opacity: .08; }
.icon-btn:focus-visible::before { opacity: .10; }
.icon-btn:active::before { opacity: .10; }

/* ---- buttons ------------------------------------------------------------- */
.btn {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 0 24px; border: 0; cursor: pointer;
  border-radius: var(--md-sys-shape-full);
  font: 500 .875rem/1.25rem var(--md-sys-typescale-font); letter-spacing: .007em;
  background: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary);
  text-decoration: none;
  transition: box-shadow .15s var(--md-sys-motion-standard);
}
.btn::before {
  content: ""; position: absolute; inset: 0; background: currentColor; opacity: 0;
  transition: opacity .15s var(--md-sys-motion-standard);
}
.btn:hover::before { opacity: .08; }
.btn:focus-visible::before { opacity: .10; }
.btn:active::before { opacity: .10; }
.btn:hover { box-shadow: var(--md-sys-elevation-1); }
.btn--full { width: 100%; }
.btn--tonal { background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
.btn--outlined {
  background: transparent; color: var(--md-sys-color-primary);
  border: 1px solid var(--md-sys-color-outline);
}
.btn--outlined:hover { box-shadow: none; }
.btn--text { background: transparent; color: var(--md-sys-color-primary); padding: 0 12px; }
.btn--text:hover { box-shadow: none; }
.btn--error { background: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }
.btn[disabled] { opacity: .38; pointer-events: none; box-shadow: none; }

.fab {
  position: fixed; right: 16px; z-index: 6;
  bottom: calc(96px + env(safe-area-inset-bottom));
  min-width: 56px; height: 56px; padding: 0 20px; gap: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; cursor: pointer; border-radius: var(--md-sys-shape-lg);
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  box-shadow: var(--md-sys-elevation-3);
  font: 500 .875rem/1.25rem var(--md-sys-typescale-font);
}

/* ---- cards --------------------------------------------------------------- */
.card {
  background: var(--md-sys-color-surface-container-low);
  color: var(--md-sys-color-on-surface);
  border-radius: var(--md-sys-shape-md);
  padding: 16px;
}
.card--elevated { background: var(--md-sys-color-surface-container-low); box-shadow: var(--md-sys-elevation-1); }
.card--outlined { background: var(--md-sys-color-surface); border: 1px solid var(--md-sys-color-outline-variant); }
.card--filled   { background: var(--md-sys-color-surface-container-highest); }
.card__title { margin: 0 0 4px; }
.card__sub { margin: 0; color: var(--md-sys-color-on-surface-variant); }
a.card { display: block; color: inherit; position: relative; }
a.card::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: var(--md-sys-color-on-surface); opacity: 0; transition: opacity .15s;
}
a.card:hover::before { opacity: .08; }

.section-title {
  margin: 24px 0 8px; padding: 0 4px;
  color: var(--md-sys-color-on-surface-variant);
}

/* ---- text fields (filled) ------------------------------------------------ */
.field { position: relative; display: block; }
.field input, .field select, .field textarea {
  width: 100%; min-height: 56px; padding: 24px 16px 8px;
  border: 0; border-bottom: 1px solid var(--md-sys-color-on-surface-variant);
  border-radius: var(--md-sys-shape-xs) var(--md-sys-shape-xs) 0 0;
  background: var(--md-sys-color-surface-container-highest);
  color: var(--md-sys-color-on-surface);
  font: 400 1rem/1.5rem var(--md-sys-typescale-font);
  appearance: none;
}
.field select { padding-right: 44px; }
.field textarea { min-height: 96px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-bottom: 2px solid var(--md-sys-color-primary);
  padding-bottom: 7px;
}
.field__label {
  position: absolute; left: 16px; top: 8px; pointer-events: none;
  color: var(--md-sys-color-on-surface-variant);
  font: 400 .75rem/1rem var(--md-sys-typescale-font); letter-spacing: .033em;
  transition: all .15s var(--md-sys-motion-standard);
}
.field input:focus ~ .field__label,
.field select:focus ~ .field__label,
.field textarea:focus ~ .field__label { color: var(--md-sys-color-primary); }
.field__help { display: block; padding: 4px 16px 0; color: var(--md-sys-color-on-surface-variant); }
.field--error input { border-bottom-color: var(--md-sys-color-error); }
.field--error .field__label, .field__help--error { color: var(--md-sys-color-error); }
.field select::-ms-expand { display: none; }
.field__chev {
  position: absolute; right: 12px; top: 18px; pointer-events: none;
  color: var(--md-sys-color-on-surface-variant);
}
/* The student-ID entry is the one field 400 people use under time pressure. */
.field input.hero {
  min-height: 76px; padding-top: 30px;
  font: 500 1.75rem/2.25rem var(--md-sys-typescale-font);
  letter-spacing: .12em; text-align: center;
}
input[type="file"] { padding: 16px; min-height: 56px; }

/* ---- lists --------------------------------------------------------------- */
.list { list-style: none; margin: 0; padding: 0; }
/* Separators are drawn between rows rather than inserted as <hr> elements,
   which would be invalid children of a <ul>. */
.list > li + li { border-top: 1px solid var(--md-sys-color-outline-variant); }
.list > li { position: relative; }
.list-item {
  display: flex; align-items: center; gap: 16px;
  min-height: 56px; padding: 8px 16px;
  color: var(--md-sys-color-on-surface); position: relative;
}
a.list-item::before {
  content: ""; position: absolute; inset: 0; background: currentColor;
  opacity: 0; transition: opacity .15s;
}
a.list-item:hover::before { opacity: .08; }
.list-item__body { flex: 1; min-width: 0; }
.list-item__head { display: block; }
.list-item__sub { display: block; color: var(--md-sys-color-on-surface-variant); }
.list-item__trail { color: var(--md-sys-color-on-surface-variant); text-align: right; flex: none; }
.avatar {
  width: 40px; height: 40px; border-radius: var(--md-sys-shape-full); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  font: 500 .875rem/1 var(--md-sys-typescale-font);
}
.avatar--error { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }
.avatar--warn  { background: var(--md-sys-color-tertiary-container); color: var(--md-sys-color-on-tertiary-container); }
.avatar--ok    { background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
.divider { height: 1px; background: var(--md-sys-color-outline-variant); border: 0; margin: 0 16px; }

/* ---- chips --------------------------------------------------------------- */
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 32px; padding: 0 12px; border-radius: var(--md-sys-shape-sm);
  border: 1px solid var(--md-sys-color-outline);
  background: transparent; color: var(--md-sys-color-on-surface-variant);
  font: 500 .875rem/1.25rem var(--md-sys-typescale-font);
  cursor: pointer; text-decoration: none;
}
.chip--selected {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  border-color: transparent;
}
.chip--error { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); border-color: transparent; }
.chip--warn  { background: var(--md-sys-color-tertiary-container); color: var(--md-sys-color-on-tertiary-container); border-color: transparent; }
.chip--ok    { background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); border-color: transparent; }
.chip--static { cursor: default; }
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---- bottom navigation bar ----------------------------------------------- */
.nav-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 6;
  display: flex; justify-content: space-around;
  background: var(--md-sys-color-surface-container);
  padding: 12px 8px calc(16px + env(safe-area-inset-bottom));
}
.nav-item {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  color: var(--md-sys-color-on-surface-variant); text-decoration: none;
  min-height: 48px; padding: 0 4px;
}
.nav-item__pill {
  display: flex; align-items: center; justify-content: center;
  width: 64px; height: 32px; border-radius: var(--md-sys-shape-full);
  transition: background .15s var(--md-sys-motion-standard);
}
.nav-item--active { color: var(--md-sys-color-on-surface); }
.nav-item--active .nav-item__pill {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}

/* ---- snackbar ------------------------------------------------------------ */
.snackbar {
  position: fixed; left: 16px; right: 16px; z-index: 8;
  bottom: calc(96px + env(safe-area-inset-bottom));
  background: var(--md-sys-color-inverse-surface);
  color: var(--md-sys-color-inverse-on-surface);
  border-radius: var(--md-sys-shape-xs); padding: 14px 16px;
  box-shadow: var(--md-sys-elevation-3); max-width: 560px; margin: 0 auto;
}

/* ---- banners / empty states ---------------------------------------------- */
.banner, a.banner {
  display: flex; gap: 12px; padding: 16px;
  border-radius: var(--md-sys-shape-md);
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
}
.banner--info, a.banner--info { background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
/* Outreach is a nudge, not an alarm. Error roles stay reserved for integrity
   flags so the two never read as the same kind of problem. */
.banner--care, a.banner--care { background: var(--md-sys-color-tertiary-container); color: var(--md-sys-color-on-tertiary-container); }

/* Disclosure used for inline forms in list cards. */
details > summary { list-style: none; display: flex; align-items: center; gap: 6px; }
details > summary::-webkit-details-marker { display: none; }
details > summary::after {
  content: ""; width: 8px; height: 8px; margin-left: 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .15s var(--md-sys-motion-standard);
}
details[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.empty { padding: 40px 16px; text-align: center; color: var(--md-sys-color-on-surface-variant); }

/* ---- data table (teacher, wide screens) ---------------------------------- */
.table-wrap { overflow-x: auto; border-radius: var(--md-sys-shape-md); }
table.data { width: 100%; border-collapse: collapse; }
table.data th, table.data td {
  text-align: left; padding: 12px 16px; white-space: nowrap;
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
}
table.data th { color: var(--md-sys-color-on-surface-variant); font: 500 .75rem/1rem var(--md-sys-typescale-font); letter-spacing: .042em; text-transform: uppercase; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8125rem; }

@media (min-width: 720px) {
  .content { padding: 24px; }
  .nav-bar { position: static; justify-content: flex-start; gap: 8px; padding: 8px 24px; }
  .content--nav { padding-bottom: 24px; }
  .fab { bottom: 24px; }
  .snackbar { bottom: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}


/* ---- read-only view-as banner ---------------------------------------------- */
/* Inverse surface pair: the highest-contrast tokens in both themes, matching
  the skip link, so the bar reads over anything it sits above. z-index stays
  below the skip link (20) so "skip to content" is never covered. */
.impersonation-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 10;
  display: flex; align-items: center; justify-content: center; gap: 16px;
  padding: 10px 16px;
  background: var(--md-sys-color-inverse-surface);
  color: var(--md-sys-color-inverse-on-surface);
  font: 500 0.95rem/1.4 var(--md-sys-typescale-font);
}
.impersonation-bar a { color: inherit; font-weight: 700; text-decoration: underline; }
/* Push the page content below the fixed bar only while the bar is present. */
body.view-as .scaffold, body.view-as .aconsole { padding-top: 42px; }
