/*
 * Site layout + reusable components.
 *
 * Theme-agnostic: every colour, font, space, radius, and shadow comes from a
 * CSS custom property defined by the active yearly theme (themes/iedYYYY.css).
 * Do NOT hard-code colours/sizes here or in page templates — add or use a token.
 */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  color: var(--color-text);
  /* Subtle brand-tinted app background (Task 41a); falls back to the flat
     surface when a theme does not define --app-bg. */
  background: var(--app-bg, var(--color-bg));
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Sticky footer: header + main + footer fill at least the viewport. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a {
  color: var(--color-primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* --- Typography --------------------------------------------------------- */

h1,
h2,
h3 {
  line-height: 1.25;
  /* Stronger navy/anthracite heading colour for hierarchy (Task 41a); falls
     back to the body text colour when the theme has no dedicated heading token. */
  color: var(--color-heading, var(--color-text));
}

h1 {
  font-size: 1.7rem;
  font-weight: 750;
  letter-spacing: -0.02em;
}

h2 {
  font-size: 1.2rem;
  margin-top: var(--space-5);
}

h3 {
  font-size: 1.02rem;
  margin: var(--space-4) 0 var(--space-2);
}

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

/* --- Layout ------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
}

/* Thin brand accent rule across the very top of the header (Task 41a). */
.site-header::before {
  content: "";
  display: block;
  height: 3px;
  background: var(--gradient-brand, var(--color-primary));
}

.site-header-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  color: var(--color-text);
}

.brand:hover {
  text-decoration: none;
}

.brand-logo {
  /* The mark includes the wordmark, so it is wider and needs more height than the
     old dot-plus-text lockup. Capped by width too, so a replacement master file
     with different proportions cannot blow out the header. */
  height: 38px;
  width: auto;
  max-width: 230px;
  display: block;
}

@media (max-width: 560px) {
  .brand-logo {
    height: 30px;
    max-width: 150px;
  }
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
  margin-left: auto;
}

.site-nav a {
  text-decoration: none;
  color: var(--color-text);
  font-weight: 500;
  padding: 0.4rem 0.7rem;
  border-radius: var(--radius-pill);
  transition: background 0.15s ease, color 0.15s ease;
}

.site-nav a:hover {
  background: var(--color-primary-soft);
  color: var(--color-primary-strong);
  text-decoration: none;
}

.site-main {
  width: 100%;
  max-width: 1080px;
  margin: var(--space-6) auto;
  padding: 0 var(--space-4);
  flex: 1 0 auto;
}

/* --- Footer / institutional branding ------------------------------------ */

.site-footer {
  flex-shrink: 0;
  width: 100%;
  margin-top: var(--space-7);
  color: var(--color-muted);
  font-size: 0.85rem;
}

/* Identity + channels. Generous vertical space is the point: the footer used to
   be a single cramped row that repeated the same three facts side by side. */
.footer-main {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--space-7) var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
  text-align: center;
}

.footer-title {
  margin: 0;
  color: var(--color-text);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.footer-sub {
  margin: 0.35rem 0 0;
}

.footer-social {
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
}

.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  text-decoration: none;
  transition: background 0.15s ease, transform 0.15s ease;
}

.social-link:hover,
.social-link:focus-visible {
  background: var(--color-primary-strong);
  transform: translateY(-1px);
  text-decoration: none;
}

.social-link img {
  width: 19px;
  height: 19px;
  /* The vendored glyphs are black; the circle is coral, so invert them to white
     rather than shipping recoloured copies of someone else's artwork. */
  filter: invert(1);
}

/* LinkedIn's mark was withdrawn from the icon package at the brand's request, so
   its circle carries a short text mark instead. Same shape, same rhythm. */
.social-text {
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: -0.02em;
}

/* Institution band, in the spirit of the public event page. */
.footer-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-4);
  background: #131316;
  color: #d7d9de;
}

.footer-org-mark {
  color: #ffffff;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 0.8rem;
}

.footer-org-dept {
  font-size: 0.8rem;
}

.footer-link {
  margin-left: auto;
  color: var(--color-primary);
  font-weight: 600;
}

.footer-link:hover {
  color: #ffffff;
}

@media (max-width: 640px) {
  .footer-link {
    /* No auto margin on one line: the band wraps and the link would jump to an
       odd position. */
    margin-left: 0;
  }
}

/* Accessible name for an icon-only control. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Page header & utilities ------------------------------------------- */

.page-header {
  margin-bottom: var(--space-5);
}

.page-header h1 {
  margin: 0 0 var(--space-2);
  position: relative;
  padding-bottom: var(--space-2);
}

/* Short brand accent under the page title for a stronger, event-like hierarchy
   (Task 41a). Purely decorative. */
.page-header h1::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 2.5rem;
  height: 3px;
  border-radius: var(--radius-pill);
  background: var(--gradient-brand, var(--color-primary));
}

.page-header .muted {
  margin: 0;
}

.code,
.event-code {
  font-family: var(--font-mono);
  font-weight: 700;
}

.event-code {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-2);
  letter-spacing: 0.02em;
}

.event-code.is-large {
  font-size: 1.7rem;
  padding: 0.3rem 0.8rem;
  letter-spacing: 0.06em;
}

/* Extra-large code for projected public monitors. */
.event-code.is-xl {
  font-size: 2.8rem;
  padding: 0.35rem 1rem;
  letter-spacing: 0.06em;
}

/* Readable queue list for public monitors. */
.queue-list {
  font-size: 1.15rem;
  line-height: 2;
}

/* A horizontal row of actions (buttons/links) with consistent spacing. */
.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin: var(--space-3) 0;
}

/* Inline action group inside a table cell (e.g. Edit + Remove). Keeps the
   buttons together and wraps cleanly on narrow screens; the wrapped <form>s
   carry no default margin so they align with adjacent links. */
.cell-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.cell-actions form {
  margin: 0;
}

/* One compact navigation action per administrative row (Task 46f): kept on one
   line, as narrow as its button, and aligned to the row's end so long names or
   missing values never push it out of line. */
.col-action {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

.col-action .btn + .btn {
  margin-left: var(--space-2);
}

/* Compact summary statistics (e.g. a dashboard header). */
.stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5) var(--space-6);
}

.stat {
  display: flex;
  flex-direction: column;
}

.stat-value {
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.stat-label {
  color: var(--color-muted);
  font-size: 0.85rem;
}

/* --- Cards / grids / panels -------------------------------------------- */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
}

.card > :first-child {
  margin-top: 0;
}

.card > :last-child {
  margin-bottom: 0;
}

/* --- Student schedule hero (Task 40b) ----------------------------------- */

.schedule-hero-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* Task 59a: a compact identity/check-in card rather than a tall hero. */
.card.schedule-hero {
  padding: var(--space-4) var(--space-5);
}

.schedule-hero h1 {
  margin: 0;
}

.schedule-hero .action-row {
  margin-bottom: 0;
}

.phase-badge {
  font-size: 0.95rem;
  padding: 0.3rem 0.7rem;
  background: var(--color-primary-soft);
  color: var(--color-primary-strong);
  white-space: nowrap;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-4);
}

/* Tool cards in a grid lift slightly on hover for affordance. */
.grid .card {
  margin-bottom: 0;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.grid .card:hover {
  box-shadow: var(--shadow-lg);
  transform: translateY(-2px);
}

.panel {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-4);
  margin: var(--space-4) 0;
  background: var(--color-surface);
}

/* Destructive actions, de-emphasized and separated inside an edit/details panel
   so a Remove button is never a primary, always-visible table action. */
.danger-zone {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

/* A standalone danger card (e.g. the /staff/ reset tool) set clearly apart from
   the card grid above it so it reads as a separate danger section (Task 41b-fix2). */
.danger-section {
  margin-top: var(--space-7);
  border-color: var(--color-danger);
}

.empty {
  color: var(--color-muted);
  font-style: italic;
}

.form-section {
  margin: var(--space-4) 0;
}

/* --- Forms / controls --------------------------------------------------- */

label {
  font-weight: 600;
  font-size: 0.92rem;
}

/* Django's {{ form.as_p }} wraps each field in a <p>; give them breathing room. */
.form-section p {
  margin: 0 0 var(--space-4);
}

input[type="text"],
input[type="number"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
select,
textarea {
  display: block;
  width: 100%;
  max-width: 28rem;
  margin-top: var(--space-1);
  padding: 0.5rem 0.65rem;
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

textarea {
  min-height: 5rem;
  resize: vertical;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-focus);
}

input[type="checkbox"],
input[type="radio"] {
  width: auto;
  margin-right: var(--space-2);
  accent-color: var(--color-primary);
}

.helptext {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-muted);
  font-size: 0.82rem;
}

.errorlist {
  margin: var(--space-1) 0;
  padding-left: 1.1rem;
  color: var(--color-danger);
  font-size: 0.85rem;
}

/* --- Tables ------------------------------------------------------------- */

.table,
table {
  border-collapse: collapse;
  margin-top: var(--space-2);
  width: 100%;
  font-size: 0.95rem;
}

.table th,
.table td,
table th,
table td {
  border-bottom: 1px solid var(--color-border);
  padding: 0.55rem 0.7rem;
  text-align: left;
  vertical-align: top;
}

.table thead th,
table thead th {
  background: var(--color-surface-2);
  border-bottom: 1px solid var(--color-border-strong);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-muted);
}

/* Zebra striping for readability, and a brand-tinted hover so the pointed-at
   row stands out over the stripes (Task 41a). */
.table tbody tr:nth-child(even),
table tbody tr:nth-child(even) {
  background: var(--color-row-alt, transparent);
}

.table tbody tr:hover,
table tbody tr:hover {
  background: var(--color-primary-soft);
}

/* --- Responsive table wrap + stacked actions (Task 41b-fix) ------------- */

/* Wrap a wide table so it scrolls WITHIN its card at any width, instead of the
   table (or its action buttons) spilling outside the card/page. */
.table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* --- Compact, non-overflowing item list (Task 41b-fix) ----------------- */

/* A stacked list of compact items used inside a dashboard card (e.g. booked
   interviews) in place of a wide table that would break the card width. */
.mini-list {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.mini-item {
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
}

.mini-item-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.mini-item-title {
  font-weight: 600;
}

/* Keep each privacy link intact when the pair wraps to two lines. */
.privacy-links a {
  white-space: nowrap;
}

/* --- Buttons ------------------------------------------------------------ */

/* The base look of .btn and of any submit button. The submit selector sits in
   :where(), which adds no specificity: on a <button type="submit"> a variant class
   declared below (.btn-primary, .btn-danger, .btn-success, .btn-ghost, .btn-sm)
   must win, as it does on a link. As a plain `button[type="submit"]` (0,1,1) it
   outranked every one-class variant (0,1,0), so destructive submit buttons rendered
   white (Task 70a). */
.btn,
:where(button[type="submit"]) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  padding: 0.5rem 1rem;
  min-height: 2.5rem;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease,
    box-shadow 0.15s ease, transform 0.05s ease;
}

.btn:hover,
:where(button[type="submit"]):hover {
  background: var(--color-surface-2);
  text-decoration: none;
}

.btn:active,
:where(button[type="submit"]):active {
  transform: translateY(1px);
}

.btn-primary {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-primary-contrast);
}

.btn-primary:hover {
  background: var(--color-primary-strong);
  border-color: var(--color-primary-strong);
}

.btn-secondary {
  background: var(--color-surface);
}

.btn-success {
  background: var(--color-success);
  border-color: var(--color-success);
  color: #fff;
}

.btn-success:hover {
  background: var(--color-success);
  filter: brightness(0.94);
}

.btn-danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: #fff;
}

.btn-danger:hover {
  background: var(--color-danger);
  filter: brightness(0.94);
}

/* Quieter destructive variant: keeps the danger colour as an outline so a Cancel
   action reads as destructive without shouting like a solid red block. Used for
   the first step of a confirmed cancellation (the confirm page keeps solid). */
.btn-danger.btn-quiet {
  background: transparent;
  border-color: var(--color-danger);
  color: var(--color-danger);
}

.btn-danger.btn-quiet:hover {
  background: var(--color-danger);
  color: #fff;
  filter: none;
}

.btn:disabled,
.btn[disabled],
.is-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: none;
}

/* --- Button polish (Task 41a) ------------------------------------------ */

/* Solid buttons get a subtle lift + hover elevation so primary/danger actions
   read as tappable and a little more event-like (still flat-ish, not glossy). */
.btn-primary,
.btn-danger,
.btn-success {
  box-shadow: var(--shadow-sm);
}

.btn-primary:hover,
.btn-danger:hover,
.btn-success:hover {
  box-shadow: var(--shadow-card);
}

/* An outline (ghost) button variant for low-emphasis actions. */
.btn-ghost {
  background: transparent;
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.btn-ghost:hover {
  background: var(--color-primary-soft);
  border-color: var(--color-primary);
  color: var(--color-primary-strong);
}

/* Compact action button for dense rows/cells. */
.btn-sm {
  min-height: 2rem;
  padding: 0.3rem 0.7rem;
  font-size: 0.85rem;
}

/* --- Login panel -------------------------------------------------------- */

/* A single, centred login panel: local credentials first, then an optional
   Google option below a separator. No external assets are used. */
.auth-card {
  max-width: 26rem;
  margin: var(--space-5) auto;
}

/* Event-oriented brand accent bar across the top of hero/auth cards (Task 41a).
   Applied to the login/logout/CSRF auth cards and the student/live hero cards so
   the main entry points feel branded without any external asset. */
.auth-card,
.schedule-hero,
.live-hero,
.live-offstage {
  position: relative;
  overflow: hidden;
}

.auth-card::before,
.schedule-hero::before,
.live-hero::before,
.live-offstage::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--gradient-brand, var(--color-primary));
}

/* A faint brand wash behind hero cards for a warmer, event-like surface. */
.schedule-hero,
.live-hero,
.live-offstage {
  background-image: var(--gradient-hero);
  background-repeat: no-repeat;
}

.auth-card h1 {
  margin-top: var(--space-2);
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.auth-submit {
  width: 100%;
}

/* Task 46a: with both the institutional and the Google option available, two
   full-width buttons sit one under the other. Without this they touch, reading
   as one control split in half. */
.auth-submit + .auth-submit {
  margin-top: var(--space-2);
}

/* "or" divider between the local form and the sign-in provider buttons. */
.auth-sep {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0;
  color: var(--color-muted);
  font-size: 0.9rem;
}

.auth-sep::before,
.auth-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

/* Google button: white surface, dark text, and a small multi-colour "G" mark
   drawn locally (no image/CDN). */
.btn-google {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.g-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  font-weight: 700;
  font-size: 0.8rem;
  color: #fff;
  /* Google-ish four-colour ring approximated with a conic gradient. */
  background: conic-gradient(
    #ea4335 0deg 90deg,
    #fbbc05 90deg 180deg,
    #34a853 180deg 270deg,
    #4285f4 270deg 360deg
  );
}

.auth-help {
  margin-top: var(--space-4);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* --- Status badges ------------------------------------------------------ */

.badge {
  display: inline-block;
  padding: 0.12rem 0.6rem;
  border-radius: var(--radius-pill);
  font-size: 0.78rem;
  font-weight: 600;
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface-2);
  color: var(--color-muted);
  white-space: nowrap;
}

/* Compact vertical stack of small status badges in one table cell (Task 36h). */
.badge-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
}

.badge-success {
  background: var(--color-success-soft, rgba(31, 138, 76, 0.12));
  border-color: var(--color-success);
  color: var(--color-success);
}

.badge-warning {
  background: var(--color-warning-soft, rgba(138, 90, 0, 0.12));
  border-color: var(--color-warning);
  color: var(--color-warning);
}

.badge-danger {
  background: var(--color-danger-soft, rgba(192, 57, 43, 0.12));
  border-color: var(--color-danger);
  color: var(--color-danger);
}

/* Info + primary status pills (Task 41a) round out the status palette so a
   neutral/informational or brand-accented state has a consistent shape/colour. */
.badge-info {
  background: var(--color-info-soft, rgba(37, 99, 168, 0.12));
  border-color: var(--color-info);
  color: var(--color-info-strong, var(--color-info));
}

.badge-primary {
  background: var(--color-primary-soft);
  border-color: var(--color-primary);
  color: var(--color-primary-strong);
}

/* --- Staff live dashboard (Task 37b) ----------------------------------- */

/* Vertical spacing between the dashboard's stacked section cards. */
.live-section {
  margin-bottom: var(--space-5);
}

/* --- Live dashboard redesign (Task 40f) -------------------------------- */

/* Live hero / status strip. */
.live-hero-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.live-hero-title {
  margin: var(--space-1) 0 0;
}

.live-hero-status {
  font-weight: 600;
  color: var(--color-danger);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.8rem;
}

/* Small pulsing "live" dot; respects reduced-motion. */
.live-hero-dot {
  display: inline-block;
  width: 0.6rem;
  height: 0.6rem;
  margin-right: 0.4rem;
  border-radius: 50%;
  background: var(--color-danger);
  animation: live-pulse 1.8s ease-in-out infinite;
}

@keyframes live-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .live-hero-dot { animation: none; }
}

.live-hero-meta {
  margin: var(--space-2) 0 var(--space-3);
}

/* KPI cards: responsive grid that collapses to 1–2 columns on a phone. */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.kpi {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.kpi-value {
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.1;
}

.kpi-label {
  color: var(--color-muted);
  font-size: 0.8rem;
}

/* Accent + attention variants (a thin left rule keeps it token-only). */
.kpi-accent { border-left: 3px solid var(--color-primary); }
.kpi-warn { border-left: 3px solid var(--color-danger); }

/* Compact live cards (Now interviewing / Next up / Company status / activities). */
.live-now-card,
.live-next-card,
.live-company-card,
.live-activity-card {
  margin-bottom: 0;
}

.live-now-company,
.live-next-company,
.live-company-name {
  font-weight: 600;
}

.live-now-student {
  margin: var(--space-2) 0 var(--space-1);
}

.live-now-name {
  margin-left: var(--space-2);
}

.live-next-time {
  font-weight: 600;
  font-size: 1.05rem;
}

.live-next-student {
  margin-top: var(--space-1);
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: baseline;
}

.live-company-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* A labelled key/value line inside a company status card. */
.live-company-row {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-2);
  font-size: 0.9rem;
}

.live-company-label {
  flex: 0 0 3rem;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 0.72rem;
  padding-top: 0.15rem;
}

.live-company-progress,
.live-activity-stats {
  margin-top: var(--space-3);
  font-size: 0.85rem;
}

/* --- Off-stage (non-live) state, staff dashboard (Task 40f) ------------- */
.live-offstage {
  text-align: center;
  padding: var(--space-7) var(--space-5);
}

.live-offstage-phase {
  margin-bottom: var(--space-4);
}

.live-offstage-title {
  margin: 0 0 var(--space-3);
  font-size: 2rem;
}

.live-offstage-lead {
  font-size: 1.1rem;
  max-width: 42ch;
  margin: 0 auto var(--space-3);
}

.live-offstage-help {
  max-width: 48ch;
  margin: 0 auto var(--space-5);
}

.live-offstage-actions {
  justify-content: center;
}

.live-offstage-note {
  margin-top: var(--space-5);
}

/* Alerts rendered as a compact, readable list (no bullets). */
.alert-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* A current/next interview cell on the company board: small stacked lines
   (time, status, User ID, name, matricola) that stay legible inside a table. */
.live-interview {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.2rem;
  font-size: 0.9rem;
}

.live-interview-time {
  font-weight: 600;
  white-space: nowrap;
}

.live-interview-name {
  font-size: 0.9rem;
}

/* --- Messages & inline warnings ---------------------------------------- */

.messages {
  list-style: none;
  margin: var(--space-4) auto 0;
  padding: 0 var(--space-4);
  max-width: 1080px;
  width: 100%;
}

.msg {
  border: 1px solid var(--color-border);
  border-left-width: 4px;
  border-radius: var(--radius);
  padding: 0.65rem 0.85rem;
  margin-bottom: var(--space-2);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

/* Soft, colour-tinted message backgrounds (Task 41a) so success/error/warning/
   info read at a glance — the left rule already carries the semantic colour, so
   the tint reinforces rather than being the only signal. */
.msg-success {
  border-left-color: var(--color-success);
  background: var(--color-success-soft, var(--color-surface));
}

.msg-error,
.msg-danger {
  border-left-color: var(--color-danger);
  background: var(--color-danger-soft, var(--color-surface));
}

.msg-warning {
  border-left-color: var(--color-warning);
  background: var(--color-warning-soft, var(--color-surface));
}

.msg-info {
  border-left-color: var(--color-info, var(--color-primary));
  background: var(--color-info-soft, var(--color-surface));
}

.warning {
  color: var(--color-warning);
  background: rgba(138, 90, 0, 0.08);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius);
  padding: 0.65rem 0.85rem;
}

/* --- QR check-in code --------------------------------------------------- */

.qr-code {
  margin: var(--space-4) 0;
}

/* Constrain the inline SVG to a readable, scannable size. The QR's own colours
   are baked into the generated SVG (dark on light) for reliable scanning. */
.qr-code svg {
  width: 220px;
  height: auto;
  max-width: 100%;
}

/* Student home check-in identity (Task 59, compacted in 59a): the Student ID and
   the QR with its caption side by side; on narrow screens they stack and the QR is
   centred. The QR keeps a white quiet zone so it scans on the tinted background. */
.checkin-identity {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-6);
  margin-top: var(--space-3);
}

.checkin-id p {
  margin: 0 0 var(--space-1);
}

.checkin-id-label {
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.checkin-qr {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
}

.checkin-qr figcaption {
  max-width: 13rem;
  font-size: 0.95rem;
}

.checkin-identity .qr-code {
  margin: 0;
  padding: var(--space-1);
  background: #fff;
  border-radius: var(--radius-sm);
  line-height: 0;
}

.checkin-identity .qr-code svg {
  width: 168px;
}

@media (max-width: 560px) {
  .checkin-identity {
    flex-direction: column;
    align-items: stretch;
  }

  .checkin-qr {
    flex-direction: column;
    gap: var(--space-2);
    text-align: center;
  }

  .checkin-qr figcaption {
    max-width: none;
  }
}

/* --- Staff QR scanner (check-in) --------------------------------------- */

/* Task 83: the activity sits right above the camera, so the operator sees what is
   being checked in while scanning. Not sticky: the site header already is, and on a
   phone a second sticky bar would cover the camera. */
.checkin-activity {
  margin: 0;
}

.checkin-activity select {
  width: 100%;
  font-weight: 600;
}

.checkin-activity + .scanner {
  margin-top: var(--space-2);
}

/* The preview is the scanner's first visible part, right under the selector. On a
   short screen it is capped so the latest result stays in sight below it; decoding
   uses the camera stream, not the displayed size. */
.scanner > .visually-hidden + .scanner-video {
  margin-top: 0;
  max-height: 40vh;
}

/* Wider system fonts can wrap the staff navigation to one more sticky row. */
@media (max-height: 560px) {
  .scanner > .visually-hidden + .scanner-video {
    max-height: 30vh;
  }
}

.scanner {
  margin: var(--space-4) 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface-2);
}

.scanner > :first-child {
  margin-top: 0;
}

/* The scanner shows and hides its parts with the `hidden` attribute (Task 61). The
   browser's own `[hidden] { display: none }` loses to any author `display` rule, so
   .btn, .action-row and .scanner-video kept the camera box, Stop scanner and the
   photo row visible. Scoped here, so `hidden` elsewhere keeps its usual cascade. */
.scanner [hidden] {
  display: none;
}

/* Live camera preview; constrained to a readable, scannable size and stacks
   naturally on mobile. The dark backdrop is just the empty <video> element. */
.scanner-video {
  display: block;
  width: 100%;
  max-width: 360px;
  margin: var(--space-3) 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-text);
  aspect-ratio: 4 / 3;
}

.scanner-status {
  margin: var(--space-2) 0 0;
  color: var(--color-muted);
  font-size: 0.9rem;
}

.scanner-status.is-error {
  color: var(--color-danger);
}

.scanner-status.is-success {
  color: var(--color-success);
}

/* Task 87: a warning about the scanner itself (a photo not read, a code not read yet),
   never a check-in result; and the code being checked in right now. */
.scanner-status.is-warning {
  color: var(--color-warning);
}

.scanner-status.is-pending {
  color: var(--color-text);
  font-weight: 600;
}

/* Result of the latest automatic check-in (Task 73): one large, unambiguous line.
   Green with a check mark for a new check-in, neutral for "already checked in",
   red for anything not recorded. Colour is never the only signal: the icon and the
   sentence say the same. */
.checkin-result {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-3) 0 0;
  padding: var(--space-3);
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-surface);
  font-weight: 600;
  font-size: 1.05rem;
  overflow-wrap: anywhere;
}

.checkin-result-icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--color-muted);
  color: #fff;
  font-size: 1.3rem;
  line-height: 1;
}

.checkin-result.is-success {
  border-color: var(--color-success);
  background: var(--color-success-soft, rgba(31, 138, 76, 0.12));
}

.checkin-result.is-success .checkin-result-icon {
  background: var(--color-success);
}

.checkin-result.is-error {
  border-color: var(--color-danger);
  background: var(--color-danger-soft, rgba(192, 57, 43, 0.12));
}

.checkin-result.is-error .checkin-result-icon {
  background: var(--color-danger);
}

/* Task 87: "already checked in" is information, an unknown outcome (network) a warning;
   both look different from a new check-in and from a refusal. */
.checkin-result.is-neutral {
  border-color: var(--color-info, var(--color-border-strong));
  background: var(--color-info-soft, rgba(37, 99, 168, 0.12));
}

.checkin-result.is-neutral .checkin-result-icon {
  background: var(--color-info, var(--color-muted));
}

.checkin-result.is-warning {
  border-color: var(--color-warning);
  background: var(--color-warning-soft, rgba(138, 90, 0, 0.12));
}

.checkin-result.is-warning .checkin-result-icon {
  background: var(--color-warning);
}

.checkin-history {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  color: var(--color-muted);
  font-size: 0.85rem;
}

.checkin-history .is-error {
  color: var(--color-danger);
}

.checkin-history .is-warning {
  color: var(--color-warning);
}

/* --- Slot selection / booking ------------------------------------------ */

/* Header row that pairs a section title with a small summary on the right. */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.section-head h2 {
  margin: 0;
}

/* Server-rendered GET filter bar (company / time period). */
.filter-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3) var(--space-4);
  margin: var(--space-4) 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface-2);
}

.filter-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.filter-field select {
  margin-top: 0;
  min-width: 12rem;
}

.filter-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Available slots as a responsive grid of compact, tappable cards instead of
   per-company tables. Auto-fill collapses to a single column on narrow screens. */
.slot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-3);
  margin: var(--space-3) 0 var(--space-4);
}

.slot-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
}

.slot-card-company {
  font-weight: 700;
}

.slot-card-time {
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}

/* Push the action to the bottom so cards of differing heights align. */
.slot-card form,
.slot-card .btn {
  margin-top: auto;
}

.slot-card .btn {
  width: 100%;
}

/* "My interviews" as stacked cards with a clear status + cancel action. */
.booking-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.booking-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
}

.booking-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.booking-card-company {
  font-weight: 700;
}

.booking-card-time {
  margin: 0;
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}

.booking-card .btn {
  margin-top: auto;
  width: 100%;
}

/* --- Responsive --------------------------------------------------------- */

@media (max-width: 640px) {
  .site-main {
    margin: var(--space-4) auto;
    padding: 0 var(--space-3);
  }

  .site-header-inner {
    padding: var(--space-3);
  }

  .card {
    padding: var(--space-4);
  }

  /* Tables scroll horizontally only when they cannot fit. */
  .table,
  table {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
    -webkit-overflow-scrolling: touch;
  }

  /* Full-width, comfortably tappable buttons on small screens. */
  .action-row .btn,
  .form-section .btn,
  .form-section button[type="submit"] {
    width: 100%;
  }

  /* Stack the slot filter bar and let its controls fill the width. */
  .filter-form {
    flex-direction: column;
    align-items: stretch;
  }

  .filter-field,
  .filter-field select,
  .filter-actions .btn {
    width: 100%;
    min-width: 0;
    max-width: none;
  }
}

/* --- Live screen (Task 37c, restyled in Task 65) ------------------------- */
/* A dedicated full-screen display in the IED visual system: the application's
   light background, navy text and red accent, at presentation sizes (it is read
   from several metres away, so it does not reuse the staff-page scale). Colours
   come from the theme tokens. The page fits the viewport: a long company list
   scrolls inside its panel. Panels are stacked and only the .is-active one shows,
   so with JS disabled the first panel (active in the markup) still renders. */

.kiosk-body {
  margin: 0;
  background: var(--app-bg, var(--color-bg));
}

.kiosk {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
  gap: clamp(0.75rem, 1.6vw, 1.75rem);
  padding: clamp(0.9rem, 2vw, 2.25rem) clamp(1rem, 2.6vw, 3rem);
  background: var(--app-bg, var(--color-bg));
  color: var(--color-text);
  font-family: var(--font-sans);
  line-height: 1.3;
  border-top: clamp(4px, 0.4vw, 6px) solid var(--color-primary);
}

/* Header: logo, edition, state badges on the left; the clock on the right. */
.kiosk-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 2rem);
  padding-bottom: clamp(0.6rem, 1.2vw, 1.2rem);
  border-bottom: 1px solid var(--color-border);
}

.kiosk-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(0.5rem, 1vw, 1rem);
  min-width: 0;
}

.kiosk-logo {
  height: clamp(32px, 3.4vw, 64px);
  width: auto;
  margin-right: clamp(0.25rem, 0.8vw, 0.75rem);
}

.kiosk-event {
  font-size: clamp(1.6rem, 3vw, 3.2rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-heading);
}

.kiosk-clock {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex: none;
  line-height: 1.1;
}

.kiosk-time {
  font-size: clamp(2.2rem, 4.4vw, 4.6rem);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--color-heading);
}

.kiosk-date {
  font-size: clamp(0.85rem, 1.25vw, 1.3rem);
  font-weight: 600;
  color: var(--color-text);
}

.kiosk-updated {
  font-size: clamp(0.75rem, 1vw, 1rem);
  color: var(--color-muted);
}

/* Stage and panels. */
.kiosk-stage {
  flex: 1;
  min-height: 0;
  display: flex;
}

.kiosk-panel {
  display: none;
  flex-direction: column;
  width: 100%;
  min-height: 0;
  gap: clamp(0.75rem, 1.4vw, 1.5rem);
}

.kiosk-panel.is-active {
  display: flex;
}

/* Section title with the application's short red rule underneath. */
.kiosk-panel-title {
  margin: 0;
  font-size: clamp(1.4rem, 2.4vw, 2.5rem);
  font-weight: 800;
  color: var(--color-heading);
}

.kiosk-panel-title::after {
  content: "";
  display: block;
  width: clamp(40px, 3.5vw, 72px);
  height: clamp(3px, 0.3vw, 5px);
  margin-top: clamp(0.35rem, 0.6vw, 0.6rem);
  border-radius: var(--radius-pill);
  background: var(--color-primary);
}

/* A long list pages inside its panel (see the screen's script); the scrollbar
   is hidden because nobody scrolls a wall display. Rows are positioned against
   this box so page breaks can be measured. */
.kiosk-scroll {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
}

.kiosk-scroll::-webkit-scrollbar {
  display: none;
}

/* When a list is paged, the row cut by the bottom edge fades out. */
.kiosk-scroll.is-paged {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), transparent);
}

.kiosk-page {
  margin-left: 0.5em;
  font-size: 0.55em;
  font-weight: 700;
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}

/* Activities now: one card per running activity. */
.kiosk-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(clamp(260px, 30vw, 480px), 1fr));
  gap: clamp(0.75rem, 1.5vw, 1.5rem);
  align-content: start;
}

.kiosk-card {
  display: flex;
  flex-direction: column;
  gap: clamp(0.4rem, 0.7vw, 0.75rem);
  padding: clamp(1rem, 1.8vw, 1.75rem);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

.kiosk-card-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.kiosk-card-title {
  font-size: clamp(1.2rem, 1.9vw, 2rem);
  font-weight: 700;
  color: var(--color-heading);
}

.kiosk-card-meta,
.kiosk-card-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.25rem;
  font-size: clamp(0.95rem, 1.3vw, 1.35rem);
  color: var(--color-muted);
}

.kiosk-card-stats strong {
  color: var(--color-heading);
  font-variant-numeric: tabular-nums;
}

/* Company interview board and upcoming queue: rows on white surfaces. */
.kiosk-board,
.kiosk-queue {
  display: flex;
  flex-direction: column;
  gap: clamp(0.35rem, 0.6vw, 0.65rem);
}

.kiosk-board-row {
  display: grid;
  /* Fixed tracks, so the columns line up from one company to the next. */
  grid-template-columns:
    minmax(0, 2.2fr) minmax(0, 1.5fr) minmax(0, 1.5fr)
    clamp(4.5rem, 7vw, 8rem) clamp(10rem, 16vw, 18rem);
  align-items: center;
  gap: clamp(0.6rem, 1.4vw, 1.5rem);
  padding: clamp(0.45rem, 0.8vw, 0.85rem) clamp(0.9rem, 1.6vw, 1.6rem);
  background: var(--color-surface);
  border-radius: var(--radius-card);
  border-left: clamp(4px, 0.4vw, 6px) solid transparent;
  box-shadow: var(--shadow-sm);
}

/* A company interviewing right now is what to spot across the room: a green edge
   and a soft green surface, plus its "Interviewing" badge (never colour alone). */
.kiosk-board-row.is-running {
  border-left-color: var(--color-success);
  background: linear-gradient(90deg, var(--color-success-soft), var(--color-surface) 45%);
}

.kiosk-board-row.is-idle {
  background: var(--color-surface-2);
  box-shadow: none;
}

.kiosk-board-company,
.kiosk-board-slot,
.kiosk-board-meter {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.kiosk-board-name {
  font-size: clamp(1.15rem, 1.9vw, 2rem);
  font-weight: 700;
  line-height: 1.15;
  color: var(--color-heading);
}

.kiosk-board-where,
.kiosk-board-time {
  font-size: clamp(0.8rem, 1.1vw, 1.15rem);
  color: var(--color-muted);
}

.kiosk-board-caption {
  font-size: clamp(0.65rem, 0.85vw, 0.9rem);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* User ID and time on one line keep the rows compact. */
.kiosk-board-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
}

.kiosk-board-code {
  font-size: clamp(1.05rem, 1.7vw, 1.8rem);
}

.kiosk-board-none {
  font-size: clamp(1.05rem, 1.7vw, 1.8rem);
  color: var(--color-border-strong);
}

.kiosk-board-count {
  font-size: clamp(1.05rem, 1.7vw, 1.8rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-heading);
}

.kiosk-board-total {
  font-weight: 600;
  color: var(--color-muted);
}

.kiosk-board-status {
  justify-self: end;
}

.kiosk-queue-row {
  display: grid;
  grid-template-columns: 4.5em minmax(0, 2fr) minmax(0, 1.2fr) auto;
  align-items: center;
  gap: clamp(0.6rem, 1.4vw, 1.5rem);
  padding: clamp(0.55rem, 1vw, 1rem) clamp(0.9rem, 1.6vw, 1.6rem);
  background: var(--color-surface);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
  font-size: clamp(1.05rem, 1.6vw, 1.7rem);
}

.kiosk-queue-time {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}

.kiosk-queue-company {
  font-weight: 700;
  min-width: 0;
  color: var(--color-heading);
}

.kiosk-queue-where {
  font-size: 0.8em;
  color: var(--color-muted);
}

.kiosk-queue-code {
  justify-self: end;
}

/* The pseudonymous User ID chip, scaled for the screen. */
.kiosk .event-code {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-strong);
  color: var(--color-heading);
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 0.05em 0.45em;
  border-radius: var(--radius-sm);
}

/* Badges: semantic colours only; the text always carries the meaning. */
.kiosk-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.3em 0.9em;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: clamp(0.75rem, 1.05vw, 1.1rem);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.kiosk-pill-live,
.kiosk-pill-active {
  background: var(--color-success-soft);
  border-color: var(--color-success);
  color: var(--color-success);
}

.kiosk-pill-demo {
  background: var(--color-warning-soft);
  border-color: var(--color-warning);
  color: var(--color-warning);
}

.kiosk-pill-waiting {
  background: var(--color-surface);
  border-color: var(--color-heading);
  color: var(--color-heading);
}

.kiosk-pill-neutral,
.kiosk-pill-idle,
.kiosk-pill-no_slots,
.kiosk-pill-no_bookings {
  background: var(--color-surface-2);
  border-color: var(--color-border-strong);
  color: var(--color-muted);
}

/* The pulsing dot inside the Event live badge. */
.kiosk-live-dot {
  width: 0.6em;
  height: 0.6em;
  border-radius: 50%;
  background: var(--color-success);
  box-shadow: 0 0 0 0 var(--color-success-soft);
  animation: kiosk-pulse 2.4s ease-out infinite;
  flex: none;
}

@keyframes kiosk-pulse {
  0% { box-shadow: 0 0 0 0 var(--color-success); }
  70% { box-shadow: 0 0 0 0.55em transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .kiosk-live-dot { animation: none; }
}

/* Empty states: a deliberate message panel, not a stray line of small text. */
.kiosk-empty {
  margin: 0;
  padding: clamp(1.5rem, 4vw, 4rem) clamp(1rem, 3vw, 3rem);
  background: var(--color-surface);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-card);
  text-align: center;
  font-size: clamp(1.2rem, 2.2vw, 2.3rem);
  font-weight: 600;
  color: var(--color-muted);
}

/* Footer: panel indicators and a quiet brand line. */
.kiosk-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.kiosk-dots {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* The active indicator is longer as well as red, so it does not rely on colour. */
.kiosk-dot {
  width: clamp(10px, 1vw, 16px);
  height: clamp(10px, 1vw, 16px);
  padding: 0;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--color-border-strong);
  cursor: pointer;
  transition: width 0.2s ease;
}

.kiosk-dot.is-active {
  width: clamp(28px, 2.6vw, 44px);
  background: var(--color-primary);
}

.kiosk-brand {
  font-size: clamp(0.75rem, 1vw, 1.05rem);
  color: var(--color-muted);
}

/* Off-stage screen (Task 40f): the same chrome, a calm centred message. */
.kiosk-offstage-stage {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-6);
  text-align: center;
}

.kiosk-offstage-mark {
  display: block;
  width: clamp(52px, 6vw, 88px);
  height: clamp(52px, 6vw, 88px);
  margin: 0 auto clamp(0.75rem, 1.6vw, 1.4rem);
  border-radius: 50%;
  border: clamp(4px, 0.45vw, 7px) solid var(--color-primary-soft);
  border-top-color: var(--color-primary);
}

.kiosk-offstage-title {
  margin: 0;
  font-size: clamp(2rem, 5vw, 4rem);
  color: var(--color-heading);
}

.kiosk-offstage-lead {
  margin: 0;
  max-width: 36ch;
  font-size: clamp(1.1rem, 2.3vw, 1.9rem);
}

.kiosk-offstage-help {
  margin: 0;
  max-width: 40ch;
  font-size: clamp(0.95rem, 1.8vw, 1.35rem);
  color: var(--color-muted);
}

/* --- Company live interview timer (Task 43b) -------------------------------
   Colour-coded countdown on /company/schedule/, shown only during event_live.
   Every rule references a theme token (with a fallback) so a future edition
   restyles it by editing the theme file alone. */
.timer-card {
    margin-top: var(--space-4, 1rem);
    padding: var(--space-4, 1rem);
    border: 1px solid var(--color-border, #e4e6eb);
    border-left-width: 4px;
    border-radius: var(--radius-card, 14px);
    background: var(--color-surface-2, #f3f4f7);
}

.timer-readout {
    display: flex;
    align-items: baseline;
    gap: var(--space-3, 0.75rem);
}

.timer-label {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted, #5b6270);
}

.timer-value {
    font-size: 2rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.timer-meta {
    margin-top: var(--space-2, 0.5rem);
    font-size: 0.9rem;
}

/* State colours: green with time to spare, amber in the last 3 minutes, red in
   the final minute or once the slot end time has passed. */
.timer-ok {
    border-left-color: var(--color-success, #1f8a4c);
    background: var(--color-success-soft, rgba(31, 138, 76, 0.12));
}

.timer-ok .timer-value {
    color: var(--color-success, #1f8a4c);
}

.timer-warning {
    border-left-color: var(--color-warning, #8a5a00);
    background: var(--color-warning-soft, rgba(138, 90, 0, 0.12));
}

.timer-warning .timer-value {
    color: var(--color-warning, #8a5a00);
}

.timer-danger {
    border-left-color: var(--color-danger, #c0392b);
    background: var(--color-danger-soft, rgba(192, 57, 43, 0.12));
}

.timer-danger .timer-value {
    color: var(--color-danger, #c0392b);
}

/* The high-attention final-minute message. Named distinctly from the
   ``timer-warning`` card state so the two never collide. */
.timer-alert {
    margin: var(--space-3, 0.75rem) 0 0;
    padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem);
    border: 0;
    border-radius: var(--radius-sm, 6px);
    background: var(--color-danger, #c0392b);
    color: #ffffff;
    font-weight: 600;
}

/* --- Company schedule clock widget (Task 43d) ------------------------------
   Shows the current local date/time next to the summary stats so a company
   representative can tell at a glance whether a slot is "now". Display only. */
.clock-widget {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2, 0.5rem);
    margin-top: var(--space-3, 0.75rem);
    padding-top: var(--space-3, 0.75rem);
    border-top: 1px solid var(--color-border, #e4e6eb);
}

.clock-date {
    color: var(--color-text-muted, #5b6270);
}

.clock-time {
    font-size: 1.25rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.clock-phase {
    margin-left: auto;
}

/* --- Student profile consent grouping (Task 43d) --------------------------- */
.consent-section .consent-field {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2, 0.5rem);
    margin-bottom: var(--space-3, 0.75rem);
}

.consent-section .consent-field .helptext {
    flex-basis: 100%;
    color: var(--color-text-muted, #5b6270);
    font-size: 0.9rem;
}

/* Live treatment for the staff-console clock (Task 43e): the same widget as the
   company schedule, given a warm accent while the event is running. */
.clock-widget.clock-live {
    border-top-color: var(--color-warning, #8a5a00);
    background: var(--color-warning-soft, rgba(138, 90, 0, 0.12));
    border-radius: var(--radius-sm, 6px);
    padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem);
}

.clock-widget.clock-live .clock-time {
    color: var(--color-warning, #8a5a00);
}

/* --- Staff console event banner (Task 43g) ---------------------------------
   The summary/live cards get a subtle accent edge so the console reads as an
   operational surface. The strong "live" variant is applied by the template only
   when the event is live AND today is an official event day. */
.event-banner {
    border-left: 4px solid var(--color-border-strong, #ccd0d8);
}

.event-banner-live {
    border-left-color: var(--color-warning, #8a5a00);
    background:
        linear-gradient(180deg, var(--color-warning-soft, rgba(138, 90, 0, 0.12)), transparent 55%),
        var(--color-surface, #ffffff);
}

.event-banner-live .stat-value {
    color: var(--color-warning, #8a5a00);
}

/* A small pulsing marker next to the heading while the event is genuinely live. */
.live-dot {
    display: inline-block;
    width: 0.6em;
    height: 0.6em;
    margin-right: 0.35em;
    border-radius: 50%;
    background: var(--color-danger, #c0392b);
    box-shadow: 0 0 0 0 rgba(192, 57, 43, 0.5);
    animation: live-pulse 2.4s ease-out infinite;
}

@keyframes live-pulse {
    70% { box-shadow: 0 0 0 0.7em rgba(192, 57, 43, 0); }
    100% { box-shadow: 0 0 0 0 rgba(192, 57, 43, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .live-dot { animation: none; }
}

/* --- Company directory (Task 43h) -----------------------------------------
   A shared, logged-in browse surface: cards rather than a table, so it stays
   readable on a phone and reads as a directory instead of a report. */
.company-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: var(--space-4, 1rem);
}

.company-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-1, 0.25rem);
    padding: var(--space-4, 1rem) var(--space-5, 1.5rem);
    border: 1px solid var(--color-border, #e4e6eb);
    border-left: 4px solid var(--color-accent, #e2452f);
    border-radius: var(--radius-card, 14px);
    background: var(--color-surface, #ffffff);
    box-shadow: var(--shadow-sm, 0 1px 2px rgba(20, 23, 28, 0.06));
    text-decoration: none;
    color: inherit;
}

.company-card:hover,
.company-card:focus-visible {
    border-color: var(--color-accent, #e2452f);
    box-shadow: var(--shadow-card, 0 1px 3px rgba(20, 23, 28, 0.06));
}

.company-card-name {
    font-size: 1.05rem;
    font-weight: 700;
}

.company-card-where {
    color: var(--color-text-muted, #5b6270);
    font-size: 0.9rem;
}

.company-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3, 0.75rem);
    margin-top: var(--space-2, 0.5rem);
}

/* The description is sanitized HTML from the Markdown renderer; give its block
   elements sane rhythm without letting it restyle the page. */
.company-description > :first-child {
    margin-top: 0;
}

.company-description > :last-child {
    margin-bottom: 0;
}

.company-description h1,
.company-description h2,
.company-description h3 {
    font-size: 1.1rem;
    margin: var(--space-4, 1rem) 0 var(--space-2, 0.5rem);
}

.company-description ul,
.company-description ol {
    padding-left: 1.4rem;
}

/* Day + time picker for activity times (Task 45g): a select limited to the
   event's configured days beside a time input, read as one "day · time" value
   rather than two stacked full-width controls. */
select.dt-day,
input.dt-time {
  display: inline-block;
  width: auto;
  vertical-align: middle;
}

select.dt-day {
  min-width: 13rem;
  margin-right: var(--space-2);
}

input.dt-time {
  min-width: 8rem;
}

/* Demo Mode (Task 56): shown on every page while the synthetic edition is active. */
.demo-banner {
  background: var(--color-warning);
  color: #fff;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: center;
  padding: 0.4rem var(--space-2, 1rem);
}

.demo-banner a {
  color: inherit;
  text-decoration: underline;
}

/* Section navigation (Task 57, restyled and shared in Task 58): one row of plain
   links under a page or object title, used wherever a staff page splits into
   server-rendered sections. The row sits on a 1px divider; the current section
   (aria-current="page") is red with a 3px underline that covers the divider. No
   pills, no JavaScript. It wraps on narrow screens instead of overflowing. */
.section-nav {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--space-1);
  margin: calc(-1 * var(--space-2)) 0 var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.section-nav a {
  display: inline-block;
  margin-bottom: -1px; /* the active underline replaces the divider */
  padding: 0.55rem 0.85rem;
  border-bottom: 3px solid transparent;
  color: var(--color-text);
  font-weight: 500;
  text-decoration: none;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.section-nav a:hover {
  color: var(--color-primary-strong);
  border-bottom-color: var(--color-border-strong);
  text-decoration: none;
}

.section-nav a:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: -2px;
}

.section-nav a[aria-current="page"] {
  color: var(--color-primary-strong);
  font-weight: 700;
  border-bottom-color: var(--color-primary);
}

.section-nav-count {
  margin-left: 0.2rem;
  color: var(--color-muted);
  font-size: 0.85em;
  font-weight: 500;
}

/* Title block of a sectioned object page: the object first, then its kind. */
.object-header .object-kind {
  margin: 0;
}

.back-link {
  display: inline-block;
  margin-bottom: var(--space-2);
  font-size: 0.92rem;
}

.config-section-title {
  font-size: 1.35rem;
  margin: 0 0 var(--space-4);
}

.config-section .card > h3 {
  font-size: 1.15rem;
}

.config-section .panel h4 {
  font-size: 1.02rem;
  margin: 0 0 var(--space-2);
}

/* Administrator tools in a configuration section (Demo Mode). */
.admin-card {
  border-style: dashed;
  border-color: var(--color-border-strong);
}

.admin-card-kicker {
  margin: 0 0 var(--space-1);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* Top navigation: the current page, where the navigation marks it (Task 59). */
.site-nav a[aria-current="page"] {
  background: var(--color-primary-soft);
  color: var(--color-primary-strong);
}

/* Staff Documentation hub (Task 59): one row per manual, the action on the right,
   stacked on narrow screens. */
.doc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.doc-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--color-border);
}

.doc-item:first-child {
  border-top: 0;
  padding-top: 0;
}

.doc-item p {
  margin: 0;
}

.doc-title {
  font-weight: 700;
}

/* Task 90: sortable table headers - plain links, the arrow on the active column. */
.sort-link {
  color: inherit;
  text-decoration: none;
}

.sort-link:hover,
.sort-link:focus-visible {
  text-decoration: underline;
}

.sort-link.is-active {
  color: var(--color-primary-strong, var(--color-primary));
}

.sort-arrow {
  margin-left: 0.3em;
  font-size: 0.8em;
}

/* Task 82: the ITA and ENG buttons side by side. */
.doc-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Student CV page (Task 63): the current file as a short label/value list. */
.cv-file {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.35rem 1.25rem;
    margin: 0 0 1rem;
}
.cv-file dt {
    font-weight: 600;
}
.cv-file dd {
    margin: 0;
    min-width: 0;
}
.cv-filename {
    overflow-wrap: anywhere;
}

/* Post-event feedback (Task 68): summary list, builder rows, result bars and the
   public questionnaire. Bars are plain elements sized by the server: no chart code. */
.feedback-edition {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}
.feedback-edition select {
    margin-top: 0;
    width: auto;
}
.feedback-summary {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.35rem 1.25rem;
    margin: 0 0 var(--space-4);
}
.feedback-summary dt {
    font-weight: 600;
}
.feedback-summary dd {
    margin: 0;
}
.feedback-blockers {
    color: var(--color-warning);
}
.feedback-questions {
    padding-left: 1.25rem;
}
.feedback-questions > li {
    padding: var(--space-3) 0;
    border-top: 1px solid var(--color-border);
}
.feedback-questions > li:first-child {
    border-top: 0;
}
.feedback-question-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}
.feedback-question-text {
    font-weight: 600;
    overflow-wrap: anywhere;
}
.feedback-options {
    margin: var(--space-2) 0;
    color: var(--color-muted);
}
.feedback-question-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.feedback-question-actions form {
    margin: 0;
}
.feedback-result {
    padding: var(--space-4) 0;
    border-top: 1px solid var(--color-border);
}
.feedback-result h3 {
    margin: 0 0 var(--space-1);
    overflow-wrap: anywhere;
}
.feedback-bars {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}
.feedback-bars th {
    width: 30%;
    padding: 0.25rem 0.75rem 0.25rem 0;
    font-weight: 500;
    text-align: left;
    overflow-wrap: anywhere;
}
.feedback-bar-cell {
    background: var(--color-surface-2);
    border-radius: var(--radius-sm);
}
.feedback-bar {
    display: block;
    height: 0.9rem;
    background: var(--color-primary);
    border-radius: var(--radius-sm);
}
.feedback-count {
    width: 8.5rem;
    padding-left: 0.75rem;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.feedback-texts {
    margin: var(--space-2) 0 0;
    padding-left: 1.25rem;
}
.feedback-texts li {
    margin-bottom: var(--space-2);
    overflow-wrap: anywhere;
}
.feedback-public {
    max-width: 44rem;
    margin: 0 auto;
}
.feedback-note {
    font-size: 0.9rem;
}
.feedback-field {
    margin: 0 0 var(--space-5);
    padding: 0;
    border: 0;
    min-width: 0;
}
.feedback-field legend {
    font-weight: 600;
    margin-bottom: var(--space-2);
    overflow-wrap: anywhere;
}
.feedback-field.has-error legend {
    color: var(--color-danger);
}
.feedback-input ul,
.feedback-input > div {
    list-style: none;
    margin: 0;
    padding: 0;
}
.feedback-input label {
    font-weight: 400;
}
.feedback-input-rating > div {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}
.feedback-input textarea {
    max-width: 100%;
}
@media (max-width: 560px) {
    .feedback-bars th {
        width: 38%;
    }
    .feedback-count {
        width: 6.5rem;
    }
}
.feedback-card-list {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
}
.feedback-card-list li {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--space-2);
    padding: 0.2rem 0;
}
/* Result rows: label, bar and count aligned. */
.feedback-bars th,
.feedback-bars td {
    vertical-align: middle;
}

/* Event-day selection for slot generation (Task 69): one checkbox per day, long
   dates wrap instead of widening the card. */
.slot-days {
    margin: 0 0 var(--space-4);
    padding: 0;
    border: 0;
    min-width: 0;
}
.slot-days legend {
    font-weight: 600;
    font-size: 0.92rem;
    margin-bottom: var(--space-2);
}
.slot-days > div {
    display: grid;
    gap: var(--space-2);
}
.slot-days label {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    font-weight: 400;
    overflow-wrap: anywhere;
}
.slot-days input[type="checkbox"] {
    margin-top: 0.2rem;
    flex: none;
}

/* Event setup calendar (Task 70): the day and what it holds on the left, Edit and
   Remove on the right. Keeps wrapping on phones instead of scrolling sideways. */
.event-days .day-usage {
    font-size: 0.85rem;
    margin-top: 0.15rem;
}
@media (max-width: 640px) {
    .table.event-days,
    .event-days tbody,
    .event-days tr,
    .event-days td {
        display: block;
        white-space: normal;
    }
    .event-days thead {
        display: none;
    }
    .event-days td.col-action {
        width: auto;
        text-align: left;
        border-bottom: 0;
        padding-top: 0;
    }
    .event-days tr {
        border-bottom: 1px solid var(--color-border);
    }
    .event-days td {
        border-bottom: 0;
    }
}

/* Removal impact (Task 70): category and count, counts right-aligned. */
.impact-table {
    max-width: 28rem;
}
.impact-table td.impact-count {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}
@media (max-width: 640px) {
    .table.impact-table {
        display: table;
        white-space: normal;
    }
}

/* Backup & Recovery (Task 71d): label/value facts that wrap instead of widening the
   card, a small status line, page links, and the Staff Home card's figures. */
.backup-facts {
    display: grid;
    grid-template-columns: minmax(12rem, 16rem) 1fr;
    gap: 0.45rem var(--space-4);
    margin: var(--space-3) 0 0;
}
.backup-facts dt {
    font-weight: 600;
    color: var(--color-muted);
}
.backup-facts dd {
    margin: 0;
    min-width: 0;
    overflow-wrap: anywhere;
}
.backup-status-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin: 0 0 var(--space-3);
}
.backup-status-line .badge {
    font-size: 0.9rem;
}
.backup-conditions {
    margin: 0 0 var(--space-3);
    padding-left: 1.2rem;
}
.backup-legend {
    font-size: 0.9rem;
}
.backup-id {
    font-family: var(--font-mono);
    font-size: 0.85rem;
}
.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-3);
}
.backup-card-list {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
}
.backup-card-list li {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0 var(--space-2);
    padding: 0.2rem 0;
}
@media (max-width: 640px) {
    .backup-facts {
        grid-template-columns: 1fr;
        gap: 0.1rem;
    }
    .backup-facts dd {
        margin-bottom: var(--space-2);
    }
}

/* --- Support portal (Task 72) ------------------------------------------- */

.support-card {
  max-width: 40rem;
}

.support-edition {
  margin-top: 0;
}

.support-open {
  color: var(--color-success);
  background: rgba(20, 120, 60, 0.08);
  border: 1px solid var(--color-success);
  border-radius: var(--radius);
  padding: 0.65rem 0.85rem;
  font-weight: 600;
}

.support-activities .mini-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.support-activities .btn {
  white-space: nowrap;
  flex-shrink: 0;
}

/* --- Live interview changes (Task 93B2) ------------------------------------- */
.summary-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.35rem 1rem;
  margin: 0 0 1rem;
}
.summary-list dt { font-weight: 600; }
.summary-list dd { margin: 0; }
.choice {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  margin: 0.35rem 0;
  font-weight: normal;
}
.choice input { margin-top: 0.2rem; flex: none; }
.plain-list { margin: 0; padding-left: 1.1rem; }
.plain-list li { margin: 0.25rem 0; }
@media (max-width: 560px) {
  .summary-list { grid-template-columns: 1fr; }
  .summary-list dd { margin-bottom: 0.5rem; }
}
.choice-group {
  border: 0;
  padding: 0;
  margin: 0 0 1rem;
}
.choice-group legend {
  font-weight: 600;
  padding: 0;
  margin-bottom: 0.35rem;
}
