/* ============================================================================
   App styles — base reset + component classes for visual atoms/domain pieces.
   Layout primitives (Box/Stack/Grid) are inline-styled from tokens, so they
   are NOT styled here. Everything below consumes tokens.css.
   ============================================================================ */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--color-frame); }
body {
  font-family: var(--font-body);
  color: var(--color-ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.tnum { font-variant-numeric: tabular-nums; }

/* ----------------------------------------------------------------- Board */
.board {
  width: 100vw; height: 100vh; overflow: hidden;
  background: var(--app-bg);
  padding: var(--board-pad);
  display: flex; flex-direction: column;
}

/* --------------------------------------------------------------- Typography */
.t-display  { font-family: var(--font-display); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); line-height: var(--leading-tight); color: var(--color-ink); }
.t-heading  { font-family: var(--font-display); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); color: var(--color-ink); margin: 0; }
.t-eyebrow  { font-family: var(--font-display); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); font-size: var(--text-lg); color: var(--color-primary); }
.t-label    { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-ink-soft); }
.t-mute     { color: var(--color-ink-mute); }
.t-mono     { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------------- Card */
.card {
  background: var(--color-card);
  border: 1px solid var(--color-line-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.card--raised {
  color: var(--color-on-primary);
  background: linear-gradient(135deg, var(--color-primary), oklch(0.45 0.12 40));
  border: none;
  box-shadow: var(--shadow-raised);
}

/* --------------------------------------------------------------- StatNumber */
.stat { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--display-md); line-height: var(--leading-none); color: var(--color-ink); letter-spacing: var(--tracking-tight); }
.stat__unit { font-size: var(--text-xl); font-weight: var(--weight-semibold); color: var(--color-ink-mute); margin-left: var(--space-1); }
.stat--xl { font-size: var(--display-lg); font-weight: var(--weight-extrabold); color: var(--color-primary); }

/* --------------------------------------------------------------------- KPI */
.kpi__label { display: flex; align-items: center; gap: var(--space-2-5); font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--color-ink-soft); }
.kpi__icon  { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; background: oklch(0.95 0.05 70); color: var(--color-primary); }
.kpi__meta  { font-size: var(--text-sm); color: var(--color-ink-mute); display: flex; align-items: center; gap: var(--space-2); }

/* ------------------------------------------------------------------- Delta */
.delta { font-weight: var(--weight-semibold); }
.delta--up   { color: var(--color-up); }
.delta--down { color: var(--color-down); }

/* -------------------------------------------------------------------- Pill */
.pill {
  display: inline-flex; align-items: center; gap: var(--space-1-5);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
  background: oklch(0.93 0.02 70); color: var(--color-ink-soft);
}
.pill--sm { padding: 2px var(--space-2); font-size: var(--text-xs); }
.pill.cat-volunteer { background: var(--cat-volunteer-bg); color: var(--cat-volunteer-fg); }
.pill.cat-pet_owner { background: var(--cat-petowner-bg);  color: var(--cat-petowner-fg);  }
.pill.cat-fosterer  { background: var(--cat-fosterer-bg);  color: var(--cat-fosterer-fg);  }
.pill.cat-internal  { background: oklch(0.93 0.01 70);     color: var(--color-ink-soft);   }
/* Direction tags. Outlined rather than filled so they read as an annotation on
   the row and cannot be mistaken for one of the filled category pills beside
   them — the two sit in the same cell. Letter-spaced because they are initialisms
   at wall-board distance. */
.pill--dir { background: none; border: 1px solid currentColor; letter-spacing: 0.06em; }
.pill--outbound { color: var(--color-primary); }
.pill--internal { color: var(--color-ink-mute); }
.pill--wait { background: var(--color-wait-bg); color: var(--color-wait-fg); }
.pill--live { background: var(--color-card); border: 1px solid var(--color-line-soft); color: var(--color-ink-soft); box-shadow: var(--shadow); padding: var(--space-2) var(--space-3-5); }

/* --------------------------------------------------------------------- Dot */
.dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; background: var(--color-ink-mute); }
.dot.cat-volunteer { background: var(--cat-volunteer); }
.dot.cat-pet_owner { background: var(--cat-petowner); }
.dot.cat-fosterer  { background: var(--cat-fosterer); }
.dot.st-available  { background: var(--color-available); }
.dot.st-oncall     { background: var(--color-oncall); }
.dot.st-away       { background: var(--color-away); }
.dot.st-break      { background: var(--color-break); }
.dot.st-offline    { background: var(--color-offline); }
.pulse { position: relative; }
.pulse::after { content: ""; position: absolute; inset: 0; border-radius: 50%; animation: pulse 2s infinite; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 oklch(0.66 0.14 145 / 0.5); }
  70%  { box-shadow: 0 0 0 10px oklch(0.66 0.14 145 / 0); }
  100% { box-shadow: 0 0 0 0 oklch(0.66 0.14 145 / 0); }
}

/* ------------------------------------------------------------------ Avatar */
.avatar { position: relative; display: inline-grid; place-items: center; }
.avatar__disc {
  position: relative;
  width: var(--av, 72px); height: var(--av, 72px); border-radius: 50%;
  display: grid; place-items: center;
  background: linear-gradient(135deg, oklch(0.85 0.06 70), oklch(0.78 0.07 50));
  color: oklch(0.30 0.06 50);
  font-family: var(--font-display); font-weight: var(--weight-bold);
  font-size: calc(var(--av, 72px) * 0.36);
  border: 3px solid var(--ring, var(--color-available));
  box-shadow: var(--shadow-avatar);
}
.avatar__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  border-radius: 50%; object-fit: cover;
}
.avatar__pip {
  position: absolute; right: 2px; bottom: 2px;
  width: calc(var(--av, 72px) * 0.30); height: calc(var(--av, 72px) * 0.30);
  border-radius: 50%; background: var(--ring, var(--color-available));
  border: 3px solid var(--color-card);
}
.avatar__name  { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-ink); text-align: center; max-width: calc(var(--av,72px) + 16px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.avatar__state { font-size: var(--text-2xs); color: var(--color-ink-mute); text-transform: uppercase; letter-spacing: var(--tracking-wide); font-weight: var(--weight-medium); }

/* ---------------------------------------------------------------- Call rows */
.calls-head { display: flex; align-items: baseline; justify-content: space-between; padding: var(--space-5) var(--space-6) var(--space-3); border-bottom: 1px solid var(--color-line-soft); }
.call-row { padding: var(--space-2-5) var(--space-6); border-bottom: 1px solid var(--color-row-line); }
/* The three trailing columns are fixed, not `auto`. Each row is an independent
   grid, so a content-sized column is only as wide as THAT row's content: an
   outbound row carrying an OUT pill sized its tail wider than an inbound row
   without one, and because the middle two columns are `fr` they absorbed the
   difference — the arrow and everything right of it slid ~29px left on exactly
   the rows that had the extra pill. Rows in a list have to agree on their
   columns, and content sizing is a promise they cannot keep.
   Widths are the widest content each slot can hold, measured in the browser at
   the board's own 1920x1080: OUT is 48px, "Pet Profile" is the longest category
   short at 92px, and "1h02m03s" is 80px of mono. A few px of headroom each so a
   font fallback cannot clip them. The type scale is fixed px (tokens.css), so
   these do not need to scale either. */
.call-row__main { display: grid; grid-template-columns: 26px 1.4fr 24px 1.2fr 50px 96px 84px; align-items: center; gap: var(--space-4); }
.call-row__num { width: 26px; height: 26px; border-radius: 50%; background: oklch(0.93 0.03 70); color: var(--color-ink-soft); display: grid; place-items: center; font-size: var(--text-xs); font-weight: var(--weight-bold); font-family: var(--font-mono); }
.who__name { font-weight: var(--weight-semibold); color: var(--color-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.who__meta { font-size: var(--text-sm); color: var(--color-ink-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.call-row__arrow { color: var(--color-primary); opacity: 0.6; }
/* Reserved slots, kept even when the row has no pill to put in them, so that the
   category pill starts at the same x on an inbound row as on an outbound one. */
.call-row__dir, .call-row__cat { display: inline-flex; align-items: center; min-width: 0; }
/* A call the office placed. The edge is what makes it scannable in a list that is
   mostly inbound; the row itself is otherwise identical. Internal traffic gets the
   quieter edge — there is more of it, and it is the least interesting thing on a
   board about serving callers. */
.call-row--placed  { box-shadow: inset 3px 0 0 var(--color-ink-mute); }
.call-row--outbound { box-shadow: inset 3px 0 0 var(--color-primary); }
/* Right-aligned because it is a column of numbers of different lengths: 6s under
   12m34s reads as a column only if they end at the same place. */
.call-row__dur { font-family: var(--font-mono); font-weight: var(--weight-semibold); color: var(--color-ink); font-size: var(--text-md); text-align: right; }
/* Each place the call reached is a chip, coloured by what happened there — see
   trailState() in domain.js for the six states and the fields they read.
   Chips rather than running text because full names are two words: separated by a
   space, "Sue Morse Helen Bott Sarah Vandervliet" has no readable boundaries.
   Wraps rather than truncates — a ring group of a dozen is one hop, and clipping
   it would hide the one that answered. */
.call-trail { margin: var(--space-1-5) 0 0 42px; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5); min-width: 0; color: var(--color-ink-mute); font-size: var(--text-2xs); }
.call-trail__node {
  display: inline-block; max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 1px var(--space-2); border: 1px solid transparent; border-radius: var(--radius-pill);
  /* Stays at 12px, not the 11px the chrome around it uses: this is a 1080p wall
     display read from across a room, and the chip padding already buys the
     separation that a smaller size would have to give back. */
  font-size: var(--text-xs); font-weight: var(--weight-medium); line-height: 1.65;
}
.call-trail__node--queue   { background: var(--trail-queue-bg);   color: var(--trail-queue-fg);   border-color: color-mix(in oklch, var(--trail-queue-fg) 20%, transparent); font-weight: var(--weight-semibold); }
.call-trail__node--talking { background: var(--trail-talking-bg); color: var(--trail-talking-fg); border-color: color-mix(in oklch, var(--trail-talking-fg) 28%, transparent); font-weight: var(--weight-semibold); }
.call-trail__node--passed  { background: var(--trail-passed-bg);  color: var(--trail-passed-fg);  border-color: color-mix(in oklch, var(--trail-passed-fg) 20%, transparent); }
.call-trail__node--ringing { background: var(--trail-ringing-bg); color: var(--trail-ringing-fg); border-color: color-mix(in oklch, var(--trail-ringing-fg) 32%, transparent); font-weight: var(--weight-semibold); animation: trail-ring 1.6s var(--ease-standard) infinite; }
.call-trail__node--missed  { background: var(--trail-missed-bg);  color: var(--trail-missed-fg);  border-color: color-mix(in oklch, var(--trail-missed-fg) 18%, transparent); }
.call-trail__node--unknown { background: var(--trail-unknown-bg); color: var(--trail-unknown-fg); border-color: color-mix(in oklch, var(--trail-unknown-fg) 18%, transparent); }
/* The live model knows where the call is but not who answered, so this is the one
   mark it can make. Nothing else keys off is-current — the colour states already
   fold it in. */
.call-trail__node--unknown.is-current { color: var(--color-ink); font-weight: var(--weight-semibold); }

/* Ringing is the only state that is still happening, and the only one worth
   motion. Slow and shallow: this sits on a wall all day. */
@keyframes trail-ring { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
@media (prefers-reduced-motion: reduce) { .call-trail__node--ringing { animation: none; } }

.call-trail__sep { opacity: .5; flex: 0 0 auto; font-size: var(--text-xs); }

/* Places that alerted together. The brackets are decorative — the group carries an
   aria-label saying so — and the members inside are not separated by the arrow,
   because no call travelled between them. */
.call-trail__group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5); }
.call-trail__group::before,
.call-trail__group::after { color: var(--color-ink-mute); opacity: .45; font-size: var(--text-xs); }
.call-trail__group::before { content: "["; }
.call-trail__group::after  { content: "]"; }

/* ------------------------------------------------------------ Queue panel */
.byrow { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--color-line-soft); }
.byrow__name { display: flex; align-items: center; gap: var(--space-2-5); min-width: 0; font-weight: var(--weight-semibold); font-size: var(--text-base); color: var(--color-ink); }
.byrow__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.byrow .v { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-xl); color: var(--color-ink); line-height: 1; }
.byrow .l { font-size: var(--text-3xs); color: var(--color-ink-mute); text-transform: uppercase; letter-spacing: var(--tracking-wide); white-space: nowrap; }

/* ---------------------------------------------------------------- Header */
.brand__org { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-2xl); color: var(--color-ink); line-height: var(--leading-tight); white-space: nowrap; }
.brand__sub { font-size: var(--text-xs); color: var(--color-ink-mute); letter-spacing: var(--tracking-wide); text-transform: uppercase; font-weight: var(--weight-medium); }
.clock__time { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--display-sm); color: var(--color-ink); line-height: 1; }
.clock__sec  { font-size: var(--text-2xl); color: var(--color-ink-mute); margin-left: var(--space-1); }
.clock__date { font-size: var(--text-sm); color: var(--color-ink-mute); font-weight: var(--weight-medium); white-space: nowrap; text-align: right; }

/* ---------------------------------------------------------------- Footer */
.footer { display: flex; align-items: center; justify-content: space-between; padding-top: var(--space-4); color: var(--color-ink-mute); font-size: var(--text-sm); }
.pager__idx { font-family: var(--font-display); font-weight: var(--weight-bold); color: var(--color-primary); }
.pdot { width: 34px; height: 6px; border-radius: var(--radius-pill); background: oklch(0.78 0.04 60 / 0.5); overflow: hidden; }
.pdot--active { background: var(--color-primary); }
/* Dots render as <button> when clickable (rotation screens). */
button.pdot { border: 0; padding: 0; cursor: pointer; }
button.pdot:hover:not(.pdot--active) { background: oklch(0.68 0.06 60 / 0.8); }

/* Footer toggles (lock the rotation / manager view). Deliberately quiet: they
   sit on a board that is mostly read from across a room, so they read as chrome
   until pressed, and the pressed state is the only one that takes colour. */
.viewbtn {
  border: 1px solid var(--color-line-soft); background: none; cursor: pointer;
  padding: 2px var(--space-2-5); border-radius: var(--radius-pill);
  font: inherit; font-size: var(--text-xs); font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide); color: var(--color-ink-mute);
  line-height: 1.7; white-space: nowrap;
}
.viewbtn:hover { color: var(--color-ink-soft); border-color: var(--color-line); }
.viewbtn--on {
  background: var(--color-primary); border-color: var(--color-primary);
  color: var(--color-on-primary);
}
.viewbtn--on:hover { color: var(--color-on-primary); }

/* ---------------------------------------------------------- Manager teams */
.team-row { display: grid; grid-template-columns: 1fr 96px 96px; align-items: center; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--color-row-line); }
.team-row__name { font-weight: var(--weight-semibold); color: var(--color-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.team-row__stat { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-xl); color: var(--color-ink); text-align: center; font-variant-numeric: tabular-nums; }
.team-row--head { border-bottom: 1px solid var(--color-line-soft); margin-top: var(--space-4); }
.team-row--head .team-row__name { color: var(--color-ink-mute); font-weight: var(--weight-medium); font-size: var(--text-sm); }
.team-row--head .team-row__stat { font-family: inherit; font-weight: var(--weight-medium); font-size: var(--text-3xs); color: var(--color-ink-mute); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
/* The received calls that are in neither the roster column nor unanswered. */
.team-split { font-size: var(--text-2xs); color: var(--color-ink-mute); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
/* Configured name with no matching PBX user — shown, but visibly inert. */
.team-row--unmatched .team-row__name, .team-row--unmatched .team-row__stat { color: var(--color-ink-mute); opacity: 0.7; }

/* --------------------------------------------------------------- IconBadge */
.icon-badge { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; background: oklch(0.95 0.05 70); color: var(--color-primary); flex: 0 0 auto; }

/* ----------------------------------------------------------------- Stat (mini) */
.stat-mini { display: flex; flex-direction: column; gap: 2px; }
.stat-mini .v { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-4xl); color: var(--color-ink); line-height: 1; }
.stat-mini .l { font-size: var(--text-2xs); color: var(--color-ink-mute); text-transform: uppercase; letter-spacing: var(--tracking-wide); white-space: nowrap; }

/* --------------------------------------------------------------- SectionHeader */
.section-head { display: flex; align-items: center; gap: var(--space-2-5); font-family: var(--font-display); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: var(--tracking-wide); font-size: var(--text-sm); color: var(--color-ink-soft); }
.section-head__swatch { width: 10px; height: 10px; border-radius: 50%; }
.section-head__count { color: var(--color-ink-mute); }

/* ------------------------------------------------------------- Dept hero card */
.dept-hero { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); padding: var(--space-6) var(--space-7); border-radius: var(--radius-lg); color: var(--color-on-primary); box-shadow: var(--shadow-raised); }
.dept-hero__icon { width: 56px; height: 56px; border-radius: 18px; display: grid; place-items: center; background: oklch(1 0 0 / 0.16); color: var(--color-on-primary); flex: 0 0 auto; }
.dept-hero__eyebrow { font-family: var(--font-display); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); font-size: var(--text-xs); color: oklch(0.95 0.04 70 / 0.85); }
.dept-hero__title { margin: 0; font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-5xl); letter-spacing: var(--tracking-display); line-height: 1; white-space: nowrap; }
.dept-hero__num { font-family: var(--font-display); font-weight: var(--weight-extrabold); font-size: var(--display-sm); line-height: 1; }
.dept-hero__lbl { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: oklch(0.95 0.04 70 / 0.85); }

/* ------------------------------------------------------------ Stale overlay */
.stale { position: fixed; inset: 0; display: grid; place-items: center; background: oklch(0.10 0.02 60 / 0.55); color: var(--color-on-primary); font-family: var(--font-display); font-size: var(--text-4xl); z-index: 50; }

/* ------------------------------------------------------------- Diagnostics */
/* Shown on the failure screen (and pinned by ?diag=1). The board has no
   console to read on a TV, so this card is the only channel — it is deliberately
   plain, dense and monospaced rather than styled like the rest of the board. */
.diag {
  width: min(1100px, 92vw); max-height: 74vh; overflow: auto;
  text-align: left;
  background: var(--color-card); border: 1px solid var(--color-line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: var(--space-5) var(--space-6);
}
.diag__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4);
  font-family: var(--font-display); font-weight: var(--weight-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-wide);
  font-size: var(--text-base); color: var(--color-ink-soft);
  padding-bottom: var(--space-3); border-bottom: 1px solid var(--color-line-soft);
}
.diag__retry { color: var(--color-ink-mute); text-transform: none; letter-spacing: 0; font-family: var(--font-mono); }

.diag__fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-1) var(--space-6); padding: var(--space-3) 0; }
.diag__field { display: flex; gap: var(--space-2); align-items: baseline; min-width: 0; font-size: var(--text-md); }
.diag__k { flex: 0 0 34%; color: var(--color-ink-mute); }
.diag__v { flex: 1 1 auto; min-width: 0; color: var(--color-ink); overflow-wrap: anywhere; }

.diag__fail { margin-top: var(--space-2); padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm); background: var(--color-wait-bg); color: var(--color-wait-fg); }
.diag__fail-head { font-weight: var(--weight-semibold); font-size: var(--text-sm); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
.diag__fail-msg { font-size: var(--text-base); overflow-wrap: anywhere; }

.diag__block { padding-top: var(--space-4); }
.diag__block-head { font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--color-ink-mute); padding-bottom: var(--space-2); }
.diag__hint { padding: var(--space-2) 0; border-bottom: 1px solid var(--color-row-line); }
.diag__hint-title { font-weight: var(--weight-semibold); font-size: var(--text-lg); color: var(--color-ink); }
.diag__hint-detail { font-size: var(--text-base); color: var(--color-ink-soft); line-height: var(--leading-normal); overflow-wrap: anywhere; }

.diag__log { font-size: var(--text-sm); }
.diag__log-row { display: flex; gap: var(--space-3); padding: var(--space-1) 0; border-bottom: 1px solid var(--color-row-line); overflow-wrap: anywhere; }
.diag__log-time { flex: 0 0 auto; color: var(--color-ink-mute); }
.diag__log-ok  { color: var(--color-available); }
.diag__log-bad { color: var(--color-break); }

/* ?diag=1 over a live board: pinned, scaled down, never in the way of a click. */
.diag-overlay { position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 60; opacity: 0.97; }
.diag-overlay .diag { width: min(720px, 46vw); max-height: 60vh; }

.stale__why { font-family: var(--font-mono); font-size: var(--text-base); opacity: 0.85; max-width: 80vw; text-align: center; overflow-wrap: anywhere; }
