/* ================================ */
/* PALETTE TOKENS                   */
/* ================================ */

/* The brand red is identity only — logo, active nav, primary actions, focus.
   Data wears its own colour (--series-*), so chrome and information never
   compete, and red stays available to mean "bad". */
:root {
  /* Brand */
  --brand:             #6a1b09;
  --brand-hover:       #8a2a12;

  /* Shell surfaces */
  --page-bg:           #f9f9f7;
  --surface:           #ffffff;
  --surface-alt:       #f0efec;

  /* Sidebar: a mid slate panel — chrome, distinct from both the white cards
     and the page plane, without the weight of a near-black block */
  --sidebar-bg:        #3f4147;
  --sidebar-ink:       rgba(255,255,255,0.85);
  --sidebar-ink-quiet: rgba(255,255,255,0.70);
  --sidebar-ink-loud:  #ffffff;
  --sidebar-active:    rgba(255,255,255,0.16);
  --sidebar-hover:     rgba(255,255,255,0.10);

  /* Ink */
  --ink:               #0b0b0b;
  --ink-secondary:     #52514e;
  --ink-muted:         #898781;
  --ink-on-dark:       #c3c2b7;

  /* Lines */
  --hairline:          #e1e0d9;
  --border:            #d8d7d1;

  /* Data — one series, stepped from a single blue ramp */
  --series-1:          #2a78d6;
  --series-1-hover:    #256abf;
  --series-1-selected: #1c5cab;

  /* The KPI tile cap: --series-1 mixed half and half with white, on request.
     It is its own token rather than a lightened --series-1 because that base
     step is also the fill of meter bars and legend swatches, where the colour
     IS the data and has to clear 3:1 against the card. This one does not - it
     measures about 2:1 on the card and less against the tinted title band it
     caps. That is fine here and only here: every tile wears the same cap, so
     it encodes nothing and is decorative under WCAG 1.4.11. Named for its use,
     not its lightness, so it does not get borrowed for a mark that means
     something. */
  --series-1-cap:      #95bceb;

  /* Ground for the KPI tile title band. Pitched at the same lightness as the
     status tints below, so a full-width band of it never competes with the
     number it labels. */
  --series-1-tint:     #eef4fc;

  /* Categorical slots 2-4, for the website analytics dashboard, which compares
     things a single hue cannot (public vs admin traffic, edits by section).
     Assigned in this fixed order and never cycled — a 5th category folds into
     "Other" rather than inventing a hue.

     Validated as a set against the white card surface: every pair clears the
     deuteranopia/protanopia/tritanopia separation floor and 3:1 contrast, which
     is why the gold is this dark and the berry this deep. Do not lighten one
     without re-validating the whole set. */
  --series-2:          #0d8f86;  /* teal   */
  --series-3:          #a3175e;  /* berry  */
  --series-4:          #a67f00;  /* gold   */

  /* Sequential ramp, light to dark, for ordered magnitude — completeness bands,
     adoption meters. One hue only: a rainbow would imply category, not degree. */
  --seq-1:             #d3e2f7;
  --seq-2:             #95bcea;
  --seq-3:             #4a89da;
  --seq-4:             #1c5cab;

  /* Status — reserved, never used for a series */
  --status-good:       #0ca30c;
  --status-warning:    #fab219;
  --status-critical:   #d03b3b;

  /* Status text/tints (darker steps, for text on the pale tints) */
  /* Darkened from #1e8449, which cleared 4.5:1 on white by a hair (4.72) and
     missed it (4.26) once the KPI title band put a faint tint behind it. Every
     use of this token is text or a border on a light surface, so the darker step
     is a uniform improvement - measured 6.13 on white, 5.54 on the band tint. */
  --status-good-ink:      #19703d;
  --status-good-tint:     #eafaf1;
  --status-good-line:     #a9dfbf;
  --status-critical-ink:  #b03a2e;
  --status-critical-tint: #fdedec;
  --status-critical-line: #f5b7b1;

  /* Chip steps: the fill of a small solid status badge, where the state has to
     survive being read at 20px and in greyscale. They are a deliberate LIGHTNESS
     LADDER rather than three independent colours - measured relative luminance
     0.34 critical / 0.54 good / 0.85 warning, an even 1.53:1 step between
     neighbours. Restyling one without re-measuring the other two collapses the
     ladder and leaves hue as the only signal, which is what these exist to
     avoid.

     THE LADDER IS SPENT. It is bounded by white at the top and, at the bottom,
     by the glyph: a fill under ~0.20 luminance needs a white glyph instead of a
     near-black one, so lightening raises the floor, which shrinks the span,
     which flattens the steps - about 0.05 of step per visible increment. These
     values were lightened on request from an earlier 1.6:1 set and the floor was
     lowered to 1.5:1 deliberately, not by drift. 1.5 is a judgement, not a
     standard: adjacent greys that close are still separable side by side but no
     longer at a glance. Do not spend it further without saying so out loud.

     The amber is the binding constraint - at 0.85 it is 1.05:1 against the KPI
     title band, so that chip is defined entirely by its ring. Another step up
     and it is a white disc.

     All three take the near-black --ink glyph; each clears 4.5:1 on its own fill
     (7.22 / 11.02 / 16.90). --status-warning-chip sits with the rest of the
     amber family further down. */
  --status-good-chip:     #57da84;
  --status-critical-chip: #eb7d70;
}

/* ================================ */
/* LOGIN FORM                       */
/* ================================ */

.login-container {
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: var(--page-bg);
  padding: 20px;
}

.login-form {
  background: white;
  padding: 30px 35px;
  width: 320px;
  border-radius: 10px;
  box-shadow: 0 4px 15px rgba(0,0,0,0.1);
  display: flex;
  flex-direction: column;
}

.login-logo img{
  width: 70%;
}

.login-form h2 {
  text-align: center;
  margin-bottom: 20px;
  font-size: 30px;
  color: var(--ink);
}

.login-form label {
  margin-bottom: 6px;
  font-weight: 600;
  color: var(--ink-secondary);
}

.login-form input {
  padding: 10px;
  margin-bottom: 20px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 18px;
  outline: none;
  transition: 0.2s;
}

.login-form input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 4px rgba(106,27,9,0.3);
}

.login-status{
  margin-top: 6px;
  font-weight: 600;
  color: var(--brand);
}

.login-form button {
  padding: 12px;
  background: var(--brand);
  border: none;
  color: white;
  font-size: 20px;
  border-radius: 6px;
  cursor: pointer;
  transition: 0.2s;
  margin-bottom: 10px;
}

.login-form button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.login-form button:hover:not(:disabled) {
  background: var(--brand-hover);
}

/* ================================ */
/* BASE / GLOBAL                    */
/* ================================ */

* {
  box-sizing: border-box;
}

body {
  background-color: var(--page-bg);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  font-family: 'Segoe UI', Arial, sans-serif;
  margin: 0;
  min-height: 100vh;
  padding: 0;
}

/* ================================ */
/* PAGE LAYOUT                      */
/* ================================ */

.page-container {
  display: flex;
  flex-direction: row;
  min-height: 100vh;
}

/* Main wrapper: everything right of sidebar */
.main-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  overflow-x: hidden;
}

/* ================================ */
/* SIDEBAR                          */
/* ================================ */

.sidebar {
  background: var(--sidebar-bg);
  color: var(--sidebar-ink-loud);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  padding: 24px 20px;
  width: 240px;
  min-width: 240px;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
}

.sidebar__top {
  margin-bottom: 32px;
}

.sidebar__logo img {
  width: 100%;
  max-width: 160px;
  border-radius: 4px;
}

.sidebar__heading {
  font-size: 28px;
  font-weight: 700;
  margin: 12px 0 0 0;
  letter-spacing: 0.5px;
}

.sidebar__content {
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* ================================ */
/* SIDEBAR NAV / DROPDOWNS          */
/* ================================ */

.dropdown {
  margin-bottom: 2px;
}

.dropdown__button {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  background: none;
  border: none;
  color: var(--sidebar-ink);
  font-size: 19px;
  padding: 10px 12px;
  text-align: left;
  cursor: pointer;
  border-radius: 6px;
  transition: background 0.2s, color 0.2s;
}

.dropdown__button.active {
  background-color: var(--sidebar-active);
  color: var(--sidebar-ink-loud);
  font-weight: 600;
}

.dropdown__button:hover {
  background-color: var(--sidebar-hover);
  color: var(--sidebar-ink-loud);
}

/* A CSS-drawn chevron rather than a ▼ glyph. Two reasons the glyph lost: a filled
   triangle is ~100% ink where a letterform is ~25%, so at the same nominal size it
   carried several times the weight of the label beside it; and its metrics drifted
   with whichever font on the machine supplied U+25BC. currentColor so it brightens
   with the label on hover/active for free. */
.dropdown__arrow {
  flex: none;
  width: 8px;
  height: 8px;
  margin-left: 10px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  /* The nudge is folded into the transform rather than a margin so that one
     property animates — a rotated square corner sits low against the text. */
  transform: translateY(-2px) rotate(45deg);
  opacity: 0.55;
  transition: transform 0.2s ease;
}

.dropdown__button[aria-expanded="true"] .dropdown__arrow {
  transform: translateY(2px) rotate(-135deg);
}

.dropdown__menu {
  display: none;
  list-style: none;
  margin: 0;
  padding: 4px 0 4px 16px;
}

.dropdown__menu.show {
  display: block;
}

.dropdown__item {
  padding: 6px 12px;
  color: var(--sidebar-ink-quiet);
  cursor: pointer;
  font-size: 18px;
  border-radius: 4px;
  transition: background 0.15s, color 0.15s;
}

.dropdown__item:hover {
  color: var(--sidebar-ink-loud);
  background: var(--sidebar-hover);
}

/* ================================ */
/* TOP BAR                          */
/* ================================ */

.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 32px;
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
}

.topbar__title {
  font-size: 35px;
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}

.topbar__right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.topbar__greeting {
  font-size: 18px;
  color: var(--ink-secondary);
  font-weight: 500;
}

/* ================================ */
/* LOGOUT (in top bar)              */
/* ================================ */

.logout {
  display: flex;
  align-items: center;
  gap: 4px;
  position: relative;
}

/* Matches .dropdown__arrow — the portal has one disclosure idiom, not two. The
   button holds no text now, so it needs to centre its own drawn chevron. */
.logout__dropdown-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid var(--border);
  color: var(--ink-secondary);
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 6px;
  transition: background 0.2s, border-color 0.2s;
}

.logout__dropdown-arrow::after {
  content: "";
  display: block;
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.2s ease;
}

.logout__dropdown-arrow[aria-expanded="true"]::after {
  transform: translateY(2px) rotate(-135deg);
}

.logout__dropdown-arrow:hover {
  background-color: var(--surface-alt);
  border-color: var(--border);
}

/* A dropdown panel, not another item in the flex row. While it was in flow, showing
   it inserted ~91px into a right-aligned row: everything shifted 95px left and the
   button landed exactly under the cursor that had just clicked the caret, so a second
   or slightly-late click logged you out. `.logout` was already position:relative —
   the anchor existed and was never used. Geometry mirrors .tooltip-content.
   Hidden here rather than by JS, so it cannot flash before commonScript.js runs. */
.logout__logout-btn {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 10;
  white-space: nowrap;
  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
  padding: 6px 14px;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  background-color: var(--surface);
  color: var(--brand);
  border: 1px solid var(--brand);
  transition: background-color 0.2s, color 0.2s;
}

/* Same idiom as the sidebar chevron: aria-expanded is the single source of truth
   and CSS reacts to it. The panel is the caret's immediate sibling on every page. */
.logout__dropdown-arrow[aria-expanded="true"] + .logout__logout-btn {
  display: block;
}

.logout__logout-btn:hover {
  background-color: var(--brand);
  color: var(--surface);
}

/* ================================ */
/* DASHBOARD                        */
/* ================================ */

.dashboard {
  padding: 24px 32px;
  flex: 1;
}

/* ================================ */
/* STAT CARDS (KPI tiles)           */
/* ================================ */

.dashboard__stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}

/* The dashboard KPI row needs wider tracks than the analytics ones. Its metric
   names are long (INACTIVE RECEIVERS (30 DAYS), DOWNLOADS WITH NO ACTIVITY)
   and wrapped to three lines in a 200px track, which stepped the title bands
   and knocked the numbers off a shared baseline.
   Do not try to solve that by shrinking the label instead: auto-fill packs MORE
   columns as the viewport grows, so the track is 203px at 1600 and 254px at
   1366 — measured — and at 1600 even a 13px label still wrapped to three lines.
   Track width is the lever, label size is not. Scoped to the dashboard because
   the analytics KPI rows have short labels and read better packed tighter. */
.dashboard > .dashboard__stats {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.stat-card {
  position: relative;
  background: var(--surface);
  border-radius: 10px;
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  /* Stat tiles carry data, so they wear the series colour, not the brand.
     The accent caps the tile rather than running down its left edge. A left
     rail is the state channel everywhere else here (.inbox__row selection,
     .msg--internal), and every KPI tile carries the same colour, so on a
     dashboard it encoded nothing while diluting the idiom where it does mean
     something. A cap also runs with the reading order inside a tile, label
     then number, instead of across it.

     The cap takes the lightened --series-1-cap step, not --series-1 - see that
     token for why the two cannot be the same value. */
  border-top: 4px solid var(--series-1-cap);
  transition: box-shadow 0.2s, transform 0.15s;
}

.stat-card:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  transform: translateY(-2px);
  z-index: 5;
}

/* The title band. Without it the label and the value read as one undivided
   block, so the label looks like part of the data. It is bled out to the tile
   edges with negative margins against the card padding, which keeps the band
   full width without restructuring 29 tiles across three pages.
   Do NOT reach for overflow: hidden on the card to clip it — that would also
   clip the stat tooltip, which is deliberately positioned against the card
   (see .stat-card .tooltip-content below). The 10px top radius is the card
   radius, which puts the band curve just inside the card curve rather than
   letting a square corner of tint spill past it. */
.stat-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin: -20px -24px 16px;
  padding: 12px 24px;
  background: var(--series-1-tint);
  border-bottom: 1px solid var(--hairline);
  border-radius: 10px 10px 0 0;
}

.stat-card__header .stat-card__label {
  margin-bottom: 0;
}

/* Anchor the stat tooltip to the card, not the icon, so it starts centred
   over the tile rather than hanging off the right edge. positionTooltip()
   in dashboardScript.js nudges it back on screen from there. */
.stat-card .tooltip-wrapper {
  position: static;
}

.stat-card .tooltip-content {
  left: 50%;
  right: auto;
  transform: translateX(-50%);
}

.stat-card__label {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink-secondary);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  margin-bottom: 8px;
  /* line-height is stated rather than left at normal because min-height is in
     em and normal is font-metric dependent, so the reserve would drift with
     the font. Two lines are held open so the band bottoms — and therefore the
     numbers — align across a row whose labels wrap to different depths. */
  line-height: 1.3;
  min-height: 2.6em;
}

.stat-card__value {
  font-size: 40px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.1;
}

.stat-card__unit {
  font-size: 15px;
  color: var(--ink-secondary);
  margin-top: 4px;
}

/* ================================ */
/* CHART CARDS                      */
/* ================================ */

.dashboard__charts {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  margin-bottom: 24px;
}

.dashboard__table-section {
  margin-bottom: 24px;
}

.chart-card {
  background: var(--surface);
  border-radius: 10px;
  padding: 20px 24px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
}

.chart-card--wide {
  max-width: 720px;
}

.chart-card__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.chart-card__title {
  font-size: 19px;
  font-weight: 600;
  color: var(--ink);
  margin: 0;
}

/* ================================ */
/* BAR CHART CANVAS                 */
/* ================================ */

.barChart {
  width: 100%;
  max-width: 100%;
  height: 220px;
  display: block;
  cursor: crosshair;
}

/* ================================ */
/* CHART TOOLTIP (hover/click)      */
/* ================================ */

.chart-tooltip {
  position: fixed;
  pointer-events: none;
  z-index: 9999;
  background: var(--ink);
  color: var(--surface);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 16px;
  line-height: 1.5;
  box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
  max-width: 220px;
  white-space: nowrap;
}

.chart-tooltip.visible {
  opacity: 1;
  transform: translateY(0);
}

.chart-tooltip__label {
  font-weight: 600;
  color: var(--ink-on-dark);
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}

.chart-tooltip__value {
  font-size: 25px;
  font-weight: 700;
  color: var(--surface);
  margin-top: 2px;
}

.chart-tooltip__detail {
  font-size: 14px;
  color: var(--ink-muted);
  margin-top: 4px;
}

/* Selected bar info panel below chart */
.chart-card__selected {
  margin-top: 12px;
  padding: 10px 14px;
  background: var(--surface-alt);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  font-size: 16px;
  color: var(--ink);
  display: none;
}

.chart-card__selected.visible {
  display: flex;
  align-items: center;
  gap: 16px;
}

.chart-card__selected-label {
  font-weight: 600;
  color: var(--series-1-selected);
}

.chart-card__selected-value {
  font-size: 23px;
  font-weight: 700;
  color: var(--ink);
}

.chart-card__selected-pct {
  font-size: 15px;
  color: var(--ink-secondary);
}

/* ================================ */
/* TOOLTIP                          */
/* ================================ */

.tooltip-wrapper {
  position: relative;
  display: inline-flex;
  cursor: pointer;
  flex-shrink: 0;
}

/* A real button, not a span: it is the only route to the verdict, so it has to
   be reachable by keyboard and have an accessible name. renderInsight writes
   that name; the markup ships a fallback for the window before insights load. */
.info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  background: none;
  border-radius: 50%;
  border: 1.5px solid var(--ink-muted);
  color: var(--ink-secondary);
  font-family: sans-serif;
  /* 500, not 700. The glyph is the darkest thing in a filled chip, so it was
     doing much of the work of making the chip read heavy. Weight has no bearing
     on contrast ratio, so this lightens the chip without spending anything from
     the lightness ladder or the 4.5:1 figures below. */
  font-weight: 500;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s, background-color 0.2s, box-shadow 0.2s;
}

.info-icon:hover {
  border-color: var(--brand);
  color: var(--brand);
}

.info-icon:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* ---- Verdict on the trigger --------------------------------------- */
/* The grade is computed on load but used to be visible only once the tooltip was
   open, so a user had to hover all twelve to find the one worth reading.
   data-verdict is written by renderInsight and is the single source of truth;
   the fill is a rule keyed off it.

   The glyph stays "i" on every state. It was briefly swapped for the verdict
   mark, and that was wrong twice over: a bare cross in a circle reads as "close"
   or "error", and it spent the one glyph everybody already reads as "there is an
   explanation here".

   The chip is FILLED rather than outlined because 1.5px of stroke gives a hue no
   area to register in - the amber ring read as a slightly darker grey ring, not
   as amber. The -ink steps are the wrong tool here for the same reason: they are
   tuned for text, so they are dark and desaturated by design.

   With the glyph now constant, hue is the only channel left on screen, and green
   against red is exactly the pair that collapses under the common colour
   deficiencies. So the fills are a LIGHTNESS LADDER as well as three hues - the
   --status-*-chip steps, at measured luminance 0.85 amber / 0.54 green / 0.34
   red, an even 1.53:1 apart, which survives greyscale. Red stays the darkest
   rung so it still anchors the row.

   All three carry the near-black --ink glyph. That is not a free choice: a fill
   below ~0.18 luminance needs white and one above ~0.20 needs near-black, and
   the ladder deliberately sits entirely in the upper band so one glyph colour
   serves all of it (7.22 / 11.02 / 16.90 against their own fills).

   The border is the -ink step rather than the fill: a light chip on the pale
   blue title band is only 1.05-2.5:1 against it, so the ring is what gives the
   chip an edge (5.4:1) and what carries the hue at full saturation. Neutral
   keeps the plain grey ring - nothing was graded, and no fill says that more
   honestly than a grey fill would. */
.info-icon[data-verdict="good"] {
  background: var(--status-good-chip);
  border-color: var(--status-good-ink);
  color: var(--ink);
}

.info-icon[data-verdict="watch"] {
  background: var(--status-warning-chip);
  border-color: var(--status-warning-ink);
  color: var(--ink);
}

.info-icon[data-verdict="poor"] {
  background: var(--status-critical-chip);
  border-color: var(--status-critical-ink);
  color: var(--ink);
}

/* Hover adds a halo instead of recolouring, so the feedback cannot break the
   contrast pairings above - the plain .info-icon:hover would turn the glyph
   brand red on top of a coloured fill. Specificity puts these ahead of it. */
.info-icon[data-verdict="good"]:hover {
  color: var(--ink);
  border-color: var(--status-good-ink);
  box-shadow: 0 0 0 3px var(--status-good-line);
}

.info-icon[data-verdict="watch"]:hover {
  color: var(--ink);
  border-color: var(--status-warning-ink);
  box-shadow: 0 0 0 3px var(--status-warning-line);
}

.info-icon[data-verdict="poor"]:hover {
  color: var(--ink);
  border-color: var(--status-critical-ink);
  box-shadow: 0 0 0 3px var(--status-critical-line);
}

.tooltip-content {
  visibility: hidden;
  opacity: 0;
  position: absolute;
  z-index: 10;
  width: 240px;
  padding: 10px 12px;
  background-color: var(--ink);
  color: var(--surface);
  border-radius: 6px;
  font-size: 16px;
  line-height: 1.4;
  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
  bottom: calc(100% + 8px);
  right: 0;
  transition: opacity 0.2s ease, visibility 0.2s ease;
}

.tooltip-wrapper:hover .tooltip-content,
.tooltip-wrapper:focus-within .tooltip-content {
  visibility: visible;
  opacity: 1;
}

/* WCAG 1.4.13: content revealed on focus has to be dismissible without moving
   focus, so Escape sets this class rather than blurring the button - a blur
   would throw a keyboard user back to the start of the tab order. Same
   specificity as the rule above and placed after it, so it wins. Cleared on
   focusout in dashboardScript.js. */
.tooltip-wrapper--dismissed:focus-within .tooltip-content {
  visibility: hidden;
  opacity: 0;
}

/* Flipped below its tile when there is no room above (set by positionTooltip) */
.tooltip-content--below {
  bottom: auto;
  top: calc(100% + 8px);
}

/* ================================ */
/* TOOLTIP INSIGHTS                 */
/* ================================ */
/* The dashboard tooltips read a metric rather than define it: what it
   measures, how it compares with the related tiles, then a verdict. */

.dashboard .tooltip-content {
  width: 300px;
  max-width: calc(100vw - 16px);
  font-size: 15px;
  padding: 12px 14px;
}

.insight__what {
  color: var(--ink-on-dark);
  line-height: 1.45;
}

.insight__context {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid rgba(255,255,255,0.14);
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.insight__line {
  color: var(--surface);
  line-height: 1.4;
}

.insight__line strong {
  font-weight: 700;
}

.insight__verdict {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid rgba(255,255,255,0.14);
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* Status colours are reserved for verdicts and always ship with the icon and
   word in .insight__badge, so colour is never the only signal. */
.insight__badge {
  align-self: flex-start;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid currentColor;
}

.insight__takeaway {
  color: var(--surface);
  line-height: 1.45;
}

.insight__verdict--good .insight__badge    { color: var(--status-good); }
.insight__verdict--watch .insight__badge   { color: var(--status-warning); }
.insight__verdict--poor .insight__badge    { color: var(--status-critical); }
.insight__verdict--neutral .insight__badge { color: var(--ink-muted); }

/* ================================ */
/* DATA TABLE                       */
/* ================================ */

.tableChart table {
  width: 100%;
  border-collapse: collapse;
  font-size: 18px;
}

.tableChart th {
  background: var(--surface-alt);
  color: var(--ink-secondary);
  font-weight: 600;
  font-size: 15px;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  padding: 10px 14px;
  text-align: left;
  border-bottom: 2px solid var(--hairline);
}

.tableChart td {
  padding: 10px 14px;
  border-bottom: 1px solid var(--surface-alt);
  color: var(--ink);
  white-space: nowrap;
}

.tableChart tr:hover td {
  background: var(--page-bg);
}

/* ================================ */
/* FOOTER                           */
/* ================================ */

footer {
  background-color: var(--surface);
  border-top: 1px solid var(--hairline);
  padding: 12px 32px;
  text-align: center;
}

footer a {
  color: var(--brand);
  text-decoration: none;
  font-size: 16px;
}

footer a:hover {
  text-decoration: underline;
}

footer p {
  margin: 4px 0 0;
  color: var(--ink-secondary);
  font-size: 15px;
}

/* ================================ */
/* SETUP FORM CARD                  */
/* ================================ */

.setup-form-card {
  background: var(--surface);
  border-radius: 10px;
  padding: 28px 32px;
  max-width: 640px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  margin-bottom: 24px;
}

.setup-form-card__title {
  font-size: 25px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 6px 0;
}

.setup-form-card__desc {
  font-size: 18px;
  color: var(--ink-secondary);
  margin: 0 0 24px 0;
}

/* ================================ */
/* FORM ELEMENTS                    */
/* ================================ */

.form-group {
  margin-bottom: 20px;
}

.form-group label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink-secondary);
  margin-bottom: 6px;
}

.form-group__required {
  color: var(--status-critical-ink);
}

.form-group input,
.form-group select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 18px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.form-group input:focus,
.form-group select:focus {
  border-color: var(--brand);
  box-shadow: 0 0 4px rgba(106,27,9,0.2);
}

/* Checkbox row — opts out of the full-width sizing the rule above applies */
.form-group--check {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.form-group--check label {
  margin-bottom: 0;
}

.form-group--check input[type="checkbox"] {
  width: auto;
  margin: 0;
  accent-color: var(--brand);
  transform: scale(1.25);
  cursor: pointer;
}

.form-group--check .form-group__hint {
  flex-basis: 100%;
  margin-top: 0;
}

.form-group label .tooltip-wrapper {
  position: relative;
  top: -1px;
}

.form-group label .tooltip-content {
  right: auto;
  left: 0;
  width: 320px;
  white-space: normal;
}

.form-group__hint {
  display: block;
  font-size: 15px;
  color: var(--ink-secondary);
  margin-top: 4px;
}

.form-group__error {
  display: none;
  font-size: 15px;
  color: var(--status-critical-ink);
  margin-top: 4px;
}

.form-actions {
  display: flex;
  gap: 12px;
  margin-top: 28px;
}

/* ================================ */
/* BUTTONS                          */
/* ================================ */

.btn {
  padding: 10px 24px;
  border: none;
  border-radius: 6px;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.2s, opacity 0.2s;
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

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

.btn--primary:hover:not(:disabled) {
  background: var(--brand-hover);
}

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

.btn--secondary:hover {
  background: var(--border);
}

.btn--small {
  padding: 5px 14px;
  font-size: 15px;
  margin-top: 6px;
}

/* ================================ */
/* FORM STATUS MESSAGE              */
/* ================================ */

.form-status {
  display: none;
  margin-top: 20px;
  padding: 12px 16px;
  border-radius: 6px;
  font-size: 18px;
  font-weight: 500;
}

.form-status--success {
  background: var(--status-good-tint);
  color: var(--status-good-ink);
  border: 1px solid var(--status-good-line);
}

.form-status--error {
  background: var(--status-critical-tint);
  color: var(--status-critical-ink);
  border: 1px solid var(--status-critical-line);
}

/* ================================ */
/* SETUP RESULT CARD                */
/* ================================ */

.setup-result {
  background: var(--surface);
  border-radius: 10px;
  padding: 24px 32px;
  max-width: 640px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  border-left: 4px solid var(--status-good-ink);
}

.setup-result__title {
  font-size: 21px;
  font-weight: 700;
  color: var(--status-good-ink);
  margin: 0 0 16px 0;
}

.setup-result__details {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 24px;
  margin-bottom: 20px;
}

.setup-result__field {
  display: flex;
  flex-direction: column;
}

.setup-result__label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-secondary);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  margin-bottom: 2px;
}

.setup-result__value {
  font-size: 18px;
  color: var(--ink);
  word-break: break-all;
}

.setup-result__sections h4 {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink-secondary);
  margin: 0 0 8px 0;
}

.setup-result__sections ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.setup-result__sections li {
  background: var(--surface-alt);
  padding: 4px 12px;
  border-radius: 4px;
  font-size: 16px;
  color: var(--ink-secondary);
}

/* ================================ */
/* SIDEBAR ACTIVE ITEM              */
/* ================================ */

.dropdown__item--active {
  color: var(--surface);
  font-weight: 600;
  background: rgba(255,255,255,0.1);
}

/* ================================ */
/* SIDEBAR NOT-YET-BUILT ITEM       */
/* ================================ */

/* Features that are planned but have no page yet. Shown so the roadmap stays
   visible, but clearly not clickable so a dead click never reads as a bug. */
.dropdown__item--pending {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  opacity: 0.45;
  cursor: not-allowed;
}

.dropdown__item--pending:hover {
  background: none;
  color: var(--sidebar-ink-quiet);
}

.dropdown__item--pending::after {
  content: "Soon";
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border: 1px solid currentColor;
  border-radius: 3px;
  padding: 0 4px;
  opacity: 0.8;
}

/* ================================ */
/* MESSAGE BOX MODAL                */
/* ================================ */

.msgbox-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 10000;
  justify-content: center;
  align-items: center;
}

.msgbox-overlay.visible {
  display: flex;
}

.msgbox {
  background: var(--surface);
  border-radius: 12px;
  padding: 32px 36px;
  max-width: 420px;
  width: 90%;
  text-align: center;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
  animation: msgbox-pop 0.2s ease;
}

@keyframes msgbox-pop {
  from { transform: scale(0.9); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}

.msgbox__icon {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  margin: 0 auto 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  font-weight: 700;
}

.msgbox__icon--success {
  background: var(--status-good-tint);
  color: var(--status-good-ink);
}

.msgbox__icon--error {
  background: var(--status-critical-tint);
  color: var(--status-critical-ink);
}

.msgbox__title {
  font-size: 23px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 8px 0;
}

.msgbox__message {
  font-size: 18px;
  color: var(--ink-secondary);
  line-height: 1.5;
  margin: 0 0 24px 0;
}

.msgbox__btn {
  min-width: 100px;
}


/* ====================================================== */
/* WEBSITE ANALYTICS                                      */
/* Used by school-site-analytics.html. Everything below   */
/* follows the block__element--modifier naming above and  */
/* the palette contract at the top of this file: data     */
/* wears --series-*, chrome wears the neutrals, and red   */
/* stays free to mean "bad".                              */
/* ====================================================== */

/* ---- Filter bar ------------------------------------- */
/* One row above the content, so every control that changes
   what is on screen sits in a single place. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 16px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 16px 20px;
  margin-bottom: 24px;
}

.filter-bar__group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.filter-bar__group--grow { flex: 1 1 220px; }

.filter-bar__label {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}

.filter-bar__select,
.filter-bar__date,
.filter-bar__search {
  font-family: inherit;
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  min-height: 40px;
}

.filter-bar__select:focus,
.filter-bar__date:focus,
.filter-bar__search:focus {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
  border-color: var(--brand);
}

.filter-bar__dates { display: flex; gap: 8px; }

.filter-bar__actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

/* ---- Preset range chips ------------------------------ */
.range-presets { display: flex; gap: 6px; }

.range-presets__btn {
  font-family: inherit;
  font-size: 14px;
  color: var(--ink-secondary);
  background: var(--surface-alt);
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 6px 14px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.range-presets__btn:hover { background: var(--hairline); }

.range-presets__btn--active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: 600;
}

/* ---- Meter (adoption / distribution bars) ------------ */
/* A horizontal magnitude bar. The label and value wear ink
   tokens, never the series colour: the bar alone carries
   identity, so the text stays readable at any palette. */
.meter-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.meter {
  display: grid;
  grid-template-columns: minmax(140px, 26%) 1fr auto;
  align-items: center;
  gap: 12px;
}

.meter__label {
  font-size: 15px;
  line-height: 1.3;
  color: var(--ink-secondary);
  overflow-wrap: anywhere;
}

.meter__track {
  position: relative;
  height: 14px;
  background: var(--surface-alt);
  border-radius: 4px;
  overflow: hidden;
  display: flex;
}

/* 4px rounded data-end; the other end stays square against the baseline. */
.meter__fill {
  height: 100%;
  background: var(--series-1);
  border-radius: 0 4px 4px 0;
  min-width: 2px;
  transition: width 0.25s ease;
}

/* Two-step meters (populated nested inside enabled) keep a 2px surface gap so
   the segments read as two quantities rather than one blurred bar. */
.meter__fill--strong { background: var(--seq-4); border-radius: 0; }
.meter__fill--weak   { background: var(--seq-2); border-left: 2px solid var(--surface); }

.meter__value {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  min-width: 72px;
  text-align: right;
}

/* Sequential steps, applied in band order by the page script. */
.meter__fill--zero { min-width: 0; width: 0 !important; }

.meter__fill--seq-1 { background: var(--seq-1); }
.meter__fill--seq-2 { background: var(--seq-2); }
.meter__fill--seq-3 { background: var(--seq-3); }
.meter__fill--seq-4 { background: var(--seq-4); }

/* Categorical steps, fixed order, never cycled. */
.meter__fill--cat-1 { background: var(--series-1); }
.meter__fill--cat-2 { background: var(--series-2); }
.meter__fill--cat-3 { background: var(--series-3); }
.meter__fill--cat-4 { background: var(--series-4); }

/* ---- Legend ----------------------------------------- */
/* Present whenever two or more series share a chart, so identity
   is never carried by colour alone. */
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 12px;
}

.legend__item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  color: var(--ink-secondary);
}

.legend__swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  flex: none;
}

.legend__swatch--cat-1 { background: var(--series-1); }
.legend__swatch--cat-2 { background: var(--series-2); }
.legend__swatch--cat-3 { background: var(--series-3); }
.legend__swatch--cat-4 { background: var(--series-4); }
.legend__swatch--seq-2 { background: var(--seq-2); }
.legend__swatch--seq-4 { background: var(--seq-4); }

/* ---- Status badges ----------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}

.badge::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.badge--live {
  color: var(--status-good-ink);
  background: var(--status-good-tint);
  border: 1px solid var(--status-good-line);
}

.badge--draft {
  color: var(--ink-secondary);
  background: var(--surface-alt);
  border: 1px solid var(--border);
}

.badge--no-site {
  color: var(--status-critical-ink);
  background: var(--status-critical-tint);
  border: 1px solid var(--status-critical-line);
}

.badge--stale {
  color: #8a5a00;
  background: #fff6e5;
  border: 1px solid #f2d9a5;
}

/* ---- Data table -------------------------------------- */
/* Wrapped in its own scroller so a wide table never makes the
   page itself scroll sideways. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 16px;
  min-width: 900px;
}

.data-table th,
.data-table td {
  text-align: left;
  padding: 12px 14px;
  border-bottom: 1px solid var(--hairline);
  vertical-align: middle;
}

.data-table thead th {
  background: var(--surface-alt);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-secondary);
  white-space: nowrap;
}

.data-table tbody tr:hover { background: var(--surface-alt); }

.data-table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Sortable headers announce themselves with a caret rather than
   leaving the user to discover them. */
.data-table__sort { cursor: pointer; user-select: none; }

.data-table__sort::after {
  content: "\2195";
  margin-left: 6px;
  opacity: 0.35;
  font-weight: 400;
}

.data-table__sort--asc::after  { content: "\2191"; opacity: 1; }
.data-table__sort--desc::after { content: "\2193"; opacity: 1; }

.data-table__link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--series-1-selected);
  cursor: pointer;
  text-align: left;
}

.data-table__link:hover { text-decoration: underline; }

/* ---- Pagination -------------------------------------- */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 16px;
}

.pager__count {
  font-size: 15px;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* ---- Empty states ------------------------------------ */
.empty-state {
  text-align: center;
  padding: 40px 24px;
  color: var(--ink-muted);
}

.empty-state__title {
  font-size: 18px;
  font-weight: 600;
  color: var(--ink-secondary);
  margin: 0 0 6px 0;
}

.empty-state__body {
  font-size: 15px;
  margin: 0 0 16px 0;
  line-height: 1.5;
}

/* ---- Loading ----------------------------------------- */
.loading-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 32px;
  color: var(--ink-muted);
  font-size: 16px;
}

.spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--hairline);
  border-top-color: var(--series-1);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  flex: none;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.4s; }
  .meter__fill { transition: none; }
  .dropdown__arrow,
  .logout__dropdown-arrow::after { transition: none; }
}

/* ---- School profile header --------------------------- */
.profile-card {
  background: var(--surface);
  border-radius: 10px;
  border-left: 4px solid var(--series-1);
  padding: 20px 24px;
  margin-bottom: 24px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
}

.profile-card__top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.profile-card__name {
  font-size: 26px;
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}

.profile-card__meta {
  margin-top: 8px;
  font-size: 15px;
  color: var(--ink-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}

/* ---- Section checklist ------------------------------- */
.checklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.checklist__row {
  display: grid;
  grid-template-columns: 26px 1fr auto auto;
  align-items: center;
  gap: 12px;
  padding: 11px 4px;
  border-bottom: 1px solid var(--hairline);
}

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

/* The glyph is a redundant encoding beside the colour, so the state
   survives greyscale, colour blindness and print. */
.checklist__icon {
  font-size: 17px;
  font-weight: 700;
  text-align: center;
  line-height: 1;
}

.checklist__row--ok      .checklist__icon { color: var(--status-good-ink); }
.checklist__row--warn    .checklist__icon { color: #8a5a00; }
.checklist__row--missing .checklist__icon { color: var(--ink-muted); }

.checklist__label {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}

.checklist__detail {
  font-size: 14px;
  color: var(--ink-muted);
  text-align: right;
}

.checklist__date {
  font-size: 14px;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  min-width: 96px;
  text-align: right;
}

/* ---- Layout helpers ---------------------------------- */
.analytics-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  margin-bottom: 28px;
}

.analytics-grid--full { grid-template-columns: minmax(0, 1fr); }

.panel {
  background: var(--surface);
  border-radius: 10px;
  padding: 20px 24px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  min-width: 0;
}

.panel__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 16px;
}

.panel__title {
  font-size: 19px;
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}

.panel__note {
  font-size: 13px;
  color: var(--ink-muted);
}

/* Every traffic chart carries one of these, because counting only starts the
   day the middleware ships and a short history otherwise reads as a decline. */
.panel__caption {
  margin-top: 12px;
  font-size: 13px;
  color: var(--ink-muted);
}

.panel__canvas {
  width: 100%;
  height: 240px;
  display: block;
}

.hidden { display: none !important; }

/* ---- Responsive -------------------------------------- */
/* The rest of this stylesheet has no breakpoints; a wide data
   table is what forces them. Charts collapse to one column
   before the sidebar is worth touching. */
@media (max-width: 1180px) {
  .analytics-grid { grid-template-columns: minmax(0, 1fr); }
  .dashboard__charts { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 820px) {
  .filter-bar { flex-direction: column; align-items: stretch; }
  .filter-bar__actions { margin-left: 0; }
  .meter { grid-template-columns: 110px 1fr auto; }
  .checklist__row { grid-template-columns: 22px 1fr; }
  .checklist__detail,
  .checklist__date { grid-column: 2; text-align: left; }
}

/* ---- Coverage grid ----------------------------------- */
/* A subject x year matrix for past papers. Magnitude, so it uses the sequential
   ramp: one hue, light to dark. Never the categorical colours - those mean
   "different thing", and every cell here is the same thing in a different
   quantity.

   The zero cell is deliberately NOT the lightest ramp step. An empty year has to
   read as absence, not as "a little", and --seq-1 against --seq-2 is too close
   to carry that distinction. It gets a dashed outline on the page background
   instead, so a gap looks like a gap. */
.coverage {
  border-collapse: separate;
  border-spacing: 2px;
  font-size: 13px;
}

.coverage__corner,
.coverage__year,
.coverage__subject {
  font-weight: 600;
  color: var(--ink-secondary);
  text-align: left;
  white-space: nowrap;
  padding: 4px 8px;
}

.coverage__year {
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.coverage__subject {
  position: sticky;
  left: 0;
  background: var(--surface);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.coverage__cell {
  width: 46px;
  height: 34px;
  text-align: center;
  vertical-align: middle;
  border-radius: 4px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--ink-primary);
}

/* Three steps, not four. --seq-3 is the one step that carries no readable text
   at this size: dark ink on it is 4.02:1 and white on it is 3.57:1, both under
   the 4.5:1 needed for 13px. Since every cell also prints its exact count, the
   fill is redundant encoding and a three-band ramp costs nothing - so the ramp
   skips the step that would have forced illegible numbers.
   Measured: ink 10.9:1 / 7.3:1 on low and mid, white 6.6:1 on high. */
.coverage__cell--low  { background: var(--seq-1); }
.coverage__cell--mid  { background: var(--seq-2); }
.coverage__cell--high { background: var(--seq-4); color: #ffffff; }

.coverage__cell--zero {
  background: transparent;
  border: 1px dashed var(--border);
  color: var(--ink-muted);
}

/* Row and column totals sit outside the ramp - they are a different measure and
   must not be read as another cell. */
.coverage__total {
  background: var(--surface-alt);
  color: var(--ink-secondary);
  text-align: center;
  font-variant-numeric: tabular-nums;
  border-radius: 4px;
  padding: 4px 8px;
}

.coverage__legend {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
  font-size: 12px;
  color: var(--ink-secondary);
}

.coverage__legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.coverage__swatch {
  width: 16px;
  height: 16px;
  border-radius: 3px;
  display: inline-block;
  flex: none;
}

/* ================================ */
/* SUPPORT INBOX                    */
/* ================================ */
/* A master/detail workflow surface, not a report. The queue on the left is the
   agent's worklist; the thread on the right is where they act. Above 1024px both
   are visible at once — triage and reply without losing your place. Below that
   they swap, using the same hide/show idiom as the analytics drill-down. */

/* Amber steps to match the --status-good/--status-critical pairs already in the
   token block. Used for "awaiting support" and for the internal-note treatment,
   which is the one thing on this page that must never be mistaken for anything
   else. Values match .badge--stale, which already used them inline. */
:root {
  --status-warning-ink:  #8a5a00;
  --status-warning-tint: #fff6e5;
  --status-warning-line: #f2d9a5;
  /* Top rung of the chip lightness ladder - see --status-good-chip. */
  --status-warning-chip: #ffecc2;
}

/* ---- Sidebar unread pill ----------------------------- */
.sidebar__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--status-critical);
  color: #ffffff;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

/* ---- Layout ------------------------------------------ */
.inbox {
  display: grid;
  grid-template-columns: minmax(300px, 380px) minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

.inbox__queue,
.inbox__detail {
  background: var(--surface);
  border-radius: 10px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  min-width: 0;
}

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

/* The queue scrolls inside itself so the composer stays reachable without
   scrolling past 200 threads to find it. */
.inbox__list {
  max-height: calc(100vh - 320px);
  overflow-y: auto;
  overflow-x: hidden;
}

.inbox__queue-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 20px 12px 20px;
  border-bottom: 1px solid var(--hairline);
}

.inbox__queue-title {
  font-size: 17px;
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}

/* ---- Queue rows -------------------------------------- */
/* The whole row is a button. Unlike the analytics tables — where only the name
   cell is clickable so the other cells stay selectable — there is nothing here
   worth copying out of a row, and a 380px target beats a 200px one. */
.inbox__row {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--hairline);
  border-left: 3px solid transparent;
  padding: 12px 18px;
  font: inherit;
  cursor: pointer;
}

.inbox__row:hover { background: var(--surface-alt); }

.inbox__row[aria-current="true"] {
  background: var(--surface-alt);
  border-left-color: var(--series-1-selected);
}

.inbox__row:focus-visible {
  outline: 2px solid var(--series-1-selected);
  outline-offset: -2px;
}

.inbox__row-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 3px;
}

.inbox__row-school {
  font-weight: 700;
  font-size: 15px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inbox__row-time {
  font-size: 12px;
  color: var(--ink-muted);
  flex: none;
  font-variant-numeric: tabular-nums;
}

.inbox__row-summary {
  font-size: 14px;
  color: var(--ink-secondary);
  line-height: 1.4;
  margin-bottom: 6px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.inbox__row-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* ---- Chips ------------------------------------------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 4px;
  padding: 2px 7px;
  background: var(--surface-alt);
  color: var(--ink-secondary);
  border: 1px solid var(--border);
  white-space: nowrap;
}

.chip--feature {
  background: #eef4fd;
  color: var(--series-1-selected);
  border-color: #c5daf5;
}

/* Blocking is the only importance worth colouring — "nice" and "helps" are
   noise if every chip shouts. */
.chip--blocking {
  background: var(--status-critical-tint);
  color: var(--status-critical-ink);
  border-color: var(--status-critical-line);
}

.chip--quiet {
  background: none;
  border-color: transparent;
  color: var(--ink-muted);
  padding-left: 0;
}

/* ---- Status badges ----------------------------------- */
/* Dot plus word, never colour alone — same rule as the analytics tables. The
   four labels are copied verbatim from the school console's HC_STATUS map so an
   agent reads exactly what the school reads. */
.badge--sent {
  color: var(--status-warning-ink);
  background: var(--status-warning-tint);
  border: 1px solid var(--status-warning-line);
}

.badge--reply-received {
  color: var(--series-1-selected);
  background: #eef4fd;
  border: 1px solid #c5daf5;
}

.badge--acknowledged {
  color: var(--ink-secondary);
  background: var(--surface-alt);
  border: 1px solid var(--border);
}

.badge--resolved {
  color: var(--status-good-ink);
  background: var(--status-good-tint);
  border: 1px solid var(--status-good-line);
}

/* ---- Detail header ----------------------------------- */
.inbox__detail-header {
  padding: 18px 24px 14px 24px;
  border-bottom: 1px solid var(--hairline);
}

.inbox__detail-title {
  font-size: 19px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 8px 0;
  line-height: 1.35;
}

.inbox__detail-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.inbox__detail-sub {
  font-size: 13px;
  color: var(--ink-muted);
}

/* ---- Message list ------------------------------------ */
.inbox__messages {
  padding: 20px 24px;
  overflow-y: auto;
  max-height: calc(100vh - 520px);
  min-height: 200px;
}

.msg {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
  align-items: flex-start;
}

.msg--support { flex-direction: row-reverse; }

.msg__avatar {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: #ffffff;
  background: var(--ink-muted);
}

.msg--support .msg__avatar { background: var(--series-1-selected); }

.msg__body {
  max-width: 72%;
  min-width: 0;
}

.msg__bubble {
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface-alt);
  border: 1px solid var(--hairline);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.msg--support .msg__bubble {
  background: #eef4fd;
  border-color: #c5daf5;
}

.msg__meta {
  font-size: 12px;
  color: var(--ink-muted);
  margin-top: 4px;
}

.msg--support .msg__meta { text-align: right; }

/* An internal note is the one thing on this page that must never be mistaken
   for a customer-visible message: full width, no bubble tail, amber ground, and
   a literal label rather than a colour cue on its own. */
.msg--internal {
  flex-direction: row;
  background: var(--status-warning-tint);
  border-left: 3px solid var(--status-warning-ink);
  border-radius: 0 6px 6px 0;
  padding: 10px 14px;
}

.msg--internal .msg__avatar { background: var(--status-warning-ink); }
.msg--internal .msg__body { max-width: 100%; flex: 1; }

.msg--internal .msg__bubble {
  background: none;
  border: none;
  padding: 0;
}

.msg__internal-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--status-warning-ink);
  margin-bottom: 4px;
}

.msg__reopened {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-secondary);
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  margin-bottom: 6px;
}

.msg__attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.msg__attachment {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
  color: var(--series-1-selected);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 8px;
  text-decoration: none;
}

.msg__attachment:hover { background: var(--surface-alt); }

/* ---- Composer ---------------------------------------- */
.composer {
  border-top: 1px solid var(--hairline);
  padding: 14px 24px 18px 24px;
  background: var(--surface);
  border-radius: 0 0 10px 10px;
}

/* The mode switch carries the risk on this page. It gets a visible ground
   change, not just a checked radio, because "which box am I typing in" has to be
   answerable at a glance rather than by reading. */
.composer--internal {
  background: var(--status-warning-tint);
  box-shadow: inset 3px 0 0 var(--status-warning-ink);
}

.composer__modes {
  display: flex;
  gap: 16px;
  margin-bottom: 10px;
}

.composer__mode {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-secondary);
  cursor: pointer;
}

.composer__mode input { accent-color: var(--brand); }

.composer__textarea {
  width: 100%;
  min-height: 84px;
  resize: vertical;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.composer__textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(106, 27, 9, 0.12);
}

.composer__footer {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.composer__count {
  font-size: 12px;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.composer__count--over { color: var(--status-critical-ink); font-weight: 700; }

.composer__actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

.composer__file {
  font-size: 12px;
  color: var(--ink-secondary);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Acknowledge and Resolve are genuinely different and agents will confuse them,
   so each carries its own one-line explanation rather than relying on the verb. */
.composer__hint {
  font-size: 12px;
  color: var(--ink-muted);
  margin: 8px 0 0 0;
  line-height: 1.45;
}

.composer__ack {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}

.composer__ack input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  padding: 7px 10px;
  font: inherit;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: 6px;
}

/* ---- Responsive -------------------------------------- */
@media (max-width: 1024px) {
  .inbox { grid-template-columns: minmax(0, 1fr); }
  .inbox__list { max-height: none; }
  .inbox__messages { max-height: none; }
  /* Below this width the two panes swap instead of sitting side by side; the
     script toggles .inbox--detail-open to pick which one is on screen. */
  .inbox--detail-open .inbox__queue { display: none; }
  .inbox:not(.inbox--detail-open) .inbox__detail { display: none; }
}

@media (min-width: 1025px) {
  .inbox__back { display: none; }
}
