:root{
  --bg:#f7f8fa; --card:#fff; --ink:#12161c; --muted:#5f6b7a; --line:#e3e7ed;
  --ok:#0f8a4a; --ok-bg:#e6f6ec; --warn:#b26a00; --warn-bg:#fdf2e0; --bad:#c02b2b; --bad-bg:#fdeaea;
  --accent:#1f5fd0; --accent-bg:#eaf1fd; --shadow:0 1px 2px rgba(16,24,40,.06),0 1px 3px rgba(16,24,40,.04);
}
@media (prefers-color-scheme:dark){
  :root{--bg:#0f1319;--card:#161b23;--ink:#e6eaf0;--muted:#96a2b3;--line:#252c37;
        --ok:#4ade80;--ok-bg:#12291c;--warn:#fbbf24;--warn-bg:#2b2110;--bad:#f87171;--bad-bg:#2d1616;
        --accent:#7aa8f5;--accent-bg:#15243d;--shadow:none;}
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);
  font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,sans-serif;}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
header.top{background:var(--card);border-bottom:1px solid var(--line);padding:14px 24px;
  display:flex;align-items:baseline;gap:18px;flex-wrap:wrap;position:sticky;top:0;z-index:10}
header.top h1{font-size:16px;margin:0;letter-spacing:-.01em}
header.top nav{display:flex;gap:16px;font-size:13px}
.crumb{color:var(--muted);font-size:12px}
main{max-width:1500px;margin:0 auto;padding:22px 24px 80px}
/* A data table wants width; prose does not. 1500px is right for the reading pages and
   left 400px of a 1900px screen unused on the one page that is nothing but a table. */
body.wide main{max-width:1860px}
h2{font-size:15px;margin:30px 0 10px;letter-spacing:-.01em}
h2 .sub{font-weight:400;color:var(--muted);font-size:12px;margin-left:8px}
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);
  padding:16px;margin-bottom:16px;overflow-x:auto}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(155px,1fr));gap:12px;margin-bottom:6px}
.kpi{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:13px 15px;box-shadow:var(--shadow)}
.kpi .label{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.kpi .value{font-size:25px;font-weight:600;margin-top:3px;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.kpi .note{font-size:11px;color:var(--muted);margin-top:2px}
/* width:auto, not 100%. A table of six short values - a call id, an agent, a
   disposition, a length, a turn count, a score - needs about 540px of content, and
   stretching it across 1418px put 200px of empty space between every value and the
   heading above it. max-width keeps a text-heavy table inside its card, where the
   prose column wraps as before. */
table{width:auto;max-width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.04em;
  color:var(--muted);padding:7px 9px;border-bottom:1px solid var(--line);white-space:nowrap}
td{padding:7px 9px;border-bottom:1px solid var(--line);vertical-align:top}
tr:last-child td{border-bottom:none}
tbody tr:hover{background:var(--accent-bg)}
.num{text-align:right;font-variant-numeric:tabular-nums}
.pill{display:inline-block;padding:1px 8px;border-radius:99px;font-size:11px;font-weight:600;white-space:nowrap}
.pill.ok{background:var(--ok-bg);color:var(--ok)} .pill.warn{background:var(--warn-bg);color:var(--warn)}
.pill.bad{background:var(--bad-bg);color:var(--bad)}
.pill.na{background:var(--line);color:var(--muted)}
.pill.info{background:var(--accent-bg);color:var(--accent)}
.bar{position:relative;height:16px;background:var(--line);border-radius:4px;min-width:90px;overflow:hidden}
.bar>span{position:absolute;inset:0 auto 0 0;border-radius:4px}
.bar>span.ok{background:var(--ok)} .bar>span.warn{background:var(--warn)} .bar>span.bad{background:var(--bad)}
.bar em{position:absolute;right:5px;top:-1px;font-style:normal;font-size:10px;font-variant-numeric:tabular-nums;
  color:var(--ink);mix-blend-mode:difference}
.heat td.cell{text-align:center;font-variant-numeric:tabular-nums;font-size:12px;font-weight:600;
  border:1px solid var(--card);min-width:52px}
.muted{color:var(--muted)}
.small{font-size:12px}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}
.split{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.split3{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
/* A grid item defaults to min-width:auto, so it refuses to shrink below its own
   content and pushes the whole page sideways instead - which is how a single-column
   .split still measured 548px inside a 375px screen. */
.split>*,.split3>*,.chartgrid>*,.kpis>*{min-width:0}
@media(max-width:980px){.split,.split3{grid-template-columns:1fr}}
.turn{display:grid;grid-template-columns:82px 52px 1fr;gap:10px;padding:6px 0;border-bottom:1px solid var(--line)}
.turn:last-child{border-bottom:none}
.turn .who{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.turn.agent .who{color:var(--accent)} .turn.customer .who{color:var(--ok)}
.turn.unknown .who{color:var(--muted)}
.turn .ts{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}
.turn .native{color:var(--muted);font-size:12px;margin-top:2px}
blockquote{margin:5px 0 0;padding:6px 10px;border-left:3px solid var(--line);
  background:var(--bg);border-radius:0 5px 5px 0;font-size:12px;color:var(--muted)}
/* The attention strip: what is stopping this from working, on every page. It sits
   between the header and the content rather than inside a card, because a blocker that
   scrolls out of view is one nobody acts on. Colour carries the same meaning as
   everywhere else - red stops work, amber lost something, blue is only waiting. */
.attention{max-width:1500px;margin:14px auto 0;padding:0 24px;display:grid;gap:8px}
body.wide .attention{max-width:1860px}
.alert{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  border:1px solid;border-left-width:4px;border-radius:8px;padding:10px 14px;font-size:13px}
.alert-msg{flex:1 1 320px;min-width:0}
.alert-msg strong{font-weight:600}
.alert-msg span{color:var(--muted)}
.alert-cta{flex:0 0 auto;font-weight:600;white-space:nowrap}
.alert.block{background:var(--bad-bg);border-color:var(--bad)}
.alert.block .alert-cta{color:var(--bad)}
.alert.warn{background:var(--warn-bg);border-color:var(--warn)}
.alert.warn .alert-cta{color:var(--warn)}
.alert.info{background:var(--accent-bg);border-color:var(--accent)}
.alert-more{font-size:12px;color:var(--muted);padding:2px 2px 0}
.banner{border-radius:10px;padding:12px 15px;margin-bottom:16px;font-size:13px;border:1px solid}
.banner.info{background:var(--accent-bg);border-color:var(--accent);color:var(--ink)}
.banner.warn{background:var(--warn-bg);border-color:var(--warn);color:var(--ink)}
audio{width:100%;margin-top:8px}
.signalgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
@media(max-width:1100px){.signalgrid{grid-template-columns:repeat(2,1fr)}}
.sig{border:1px solid var(--line);border-radius:9px;padding:12px;background:var(--card)}
.sig h4{margin:0 0 3px;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.sig .who{font-size:10px;color:var(--muted);margin-bottom:8px;font-style:italic}
.sig .big{font-size:22px;font-weight:600;letter-spacing:-.02em}

/* ── data-viz palette (validated: CVD ΔE 11.3 protan / 27.6 normal on the
      adjacent pairlist; amber is sub-3:1 on white by design, so every segment
      carries a visible numeric label — the relief rule) ────────────────────── */
:root{
  --viz-surface:#fff;
  --viz-good:#0ca30c; --viz-warn:#fab219; --viz-crit:#d03b3b;
  --viz-neutral:#d8d8d2;                 /* diverging / "no data" midpoint */
  --viz-seq-400:#3987e5; --viz-seq-450:#2a78d6; --viz-seq-550:#1c5cab;
  --viz-seq-200:#9ec5f4; --viz-seq-100:#cde2fb;
  --viz-grid:#e8ebf0; --viz-axis:#b9c0cc;
}
@media (prefers-color-scheme:dark){
  :root{
    --viz-surface:#161b23;
    --viz-neutral:#383835;
    --viz-seq-400:#3987e5; --viz-seq-450:#256abf; --viz-seq-550:#1c5cab;
    --viz-seq-200:#1c5cab; --viz-seq-100:#184f95;
    --viz-grid:#252c37; --viz-axis:#3c4553;
  }
}
/* min(430px,100%) so the track can fall below 430px on a narrow screen. A bare
   minmax(430px,1fr) makes the column 430px wide whatever the container, overflowing
   every phone. */
.chartgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(430px,100%),1fr));gap:16px}
@media(max-width:920px){.chartgrid{grid-template-columns:1fr}}
.chart svg{display:block;width:100%;height:auto;overflow:visible}
.chart .glabel{font-size:11px;fill:var(--muted)}
.chart .gval{font-size:11px;font-weight:600;fill:var(--ink);font-variant-numeric:tabular-nums}
.chart .gaxis{stroke:var(--viz-axis);stroke-width:1}
.chart .ggrid{stroke:var(--viz-grid);stroke-width:1}
.chart rect,.chart circle{transition:opacity .12s}
.chart g:hover rect,.chart g:hover circle{opacity:.78}
.legend{display:flex;gap:14px;flex-wrap:wrap;margin-top:9px;font-size:11px;color:var(--muted)}
.legend i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:5px;vertical-align:-1px}
.chartnote{font-size:11px;color:var(--muted);margin-top:8px;line-height:1.45}

/* ── upload & jobs ────────────────────────────────────────────────────────── */
/* display:block is load-bearing: a <label> defaults to display:inline, which
   collapsed the box to a ~24px sliver. The inner text overflowed and LOOKED like a
   drop zone, but only that sliver was clickable, so the file picker never opened. */
.dropzone{display:block;cursor:pointer;
  border:1.5px dashed var(--rule-2,var(--line));border-radius:9px;padding:22px;
  text-align:center;background:var(--bg);transition:border-color .15s,background .15s}
.dropzone.over{border-color:var(--accent);background:var(--accent-bg)}
.field{display:grid;gap:5px;margin-bottom:12px}
.field label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted)}
.field input,.field select{padding:8px 10px;border:1px solid var(--line);border-radius:7px;
  background:var(--card);color:var(--ink);font:inherit;font-size:13px;width:100%}
.field input:focus,.field select:focus{outline:2px solid var(--accent);outline-offset:1px}
.field .hint{font-size:11px;color:var(--muted)}
.btn{padding:9px 18px;border:1px solid var(--accent);background:var(--accent);color:#fff;
  border-radius:7px;font:inherit;font-size:13px;font-weight:600;cursor:pointer}
.btn:hover{filter:brightness(1.08)}
.btn.ghost{background:var(--accent-bg);color:var(--accent)}
.btn.danger{background:var(--bad-bg);color:var(--bad);border-color:var(--bad)}
.btn:disabled{opacity:.5;cursor:not-allowed}
.prog{height:9px;border-radius:99px;background:var(--line);overflow:hidden;margin:9px 0 6px}
.prog>span{display:block;height:100%;background:var(--accent);border-radius:99px;
  transition:width .5s ease}
.prog.done>span{background:var(--ok)}
.prog.fail>span{background:var(--bad)}
.stages{display:flex;gap:6px;flex-wrap:wrap;margin:10px 0 2px;font-size:11px}
.stages span{padding:2px 9px;border-radius:99px;background:var(--line);color:var(--muted)}
.stages span.on{background:var(--accent-bg);color:var(--accent);font-weight:600}
.stages span.past{background:var(--ok-bg);color:var(--ok)}
.spin{display:inline-block;width:11px;height:11px;border:2px solid var(--accent);
  border-top-color:transparent;border-radius:50%;animation:sp .7s linear infinite;
  vertical-align:-1px;margin-right:6px}
@keyframes sp{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spin{animation-duration:2.4s}.prog>span{transition:none}}

/* ── brand ────────────────────────────────────────────────────────────────── */
/* Brand lockup. The mark is a 2.1:1 horizontal logo whose optical weight sits low,
   so it is matched to the text's cap height rather than its line box - sizing it to
   the full line box made it tower over the title. */
.brand{display:inline-flex;align-items:center;gap:11px;color:inherit;text-decoration:none}
.brand,.brand:hover,.brand *,.brand:hover *{text-decoration:none}
.brandmark{display:block;height:19px;width:auto;flex:none}
.brand>span{padding-left:11px;border-left:1px solid var(--line);line-height:1.15}

/* ── transcripts table ────────────────────────────────────────────────────────
   Rebuilt from twelve narrow columns to eight. The old layout gave 188px to a file
   name that was often empty and 121px to the spoken words, so every row wrapped to
   three lines and stood 69px tall. Related facts now share a cell in two lines - the
   id with its date, the agent with their campaign - and the words take the rest. */

.vh {                                   /* label for screen readers only */
  position:absolute;width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;
}
.nowrap { white-space:nowrap }

.tx table.tight { width:100%; table-layout:auto; border-collapse:collapse }
.tx table.tight td { padding:8px 10px; vertical-align:top; border-top:1px solid var(--line) }
.tx table.tight th { padding:7px 10px; white-space:nowrap }
.tx table.tight tbody tr:hover { background:var(--accent-bg) }

/* Two lines in one cell: the fact, then its context in smaller muted type. */
td.stack { line-height:1.35 }
td.stack .sub2, td.words .sub2 {
  display:block; margin-top:2px;
  font-size:11.5px; color:var(--muted); white-space:nowrap;
}
a.plain { color:inherit; text-decoration:none }
a.plain:hover { color:var(--accent); text-decoration:underline }

th.acts, td.acts { width:1%; white-space:nowrap; padding-right:5px }
td.clip { max-width:190px }
td.clip > a, td.clip .sub2 { display:block; overflow:hidden; text-overflow:ellipsis;
                             white-space:nowrap }

/* width:100% with max-width:0 is what makes one cell absorb the leftover space and
   TRUNCATE instead of demanding its content's width - without max-width:0 a nowrap
   snippet pushed the table to 2368px inside a 1900px window. */
th.words, td.words { width:100%; max-width:0 }
td.words .snip {
  display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  color:var(--muted); font-size:12.5px;
}

/* Small square controls. Two full-size buttons per row were 220px of every row and
   read as the loudest thing on the page. */
.iconbtn {
  display:inline-flex; align-items:center; justify-content:center;
  width:23px; height:23px; padding:0; margin-right:3px;
  border:1px solid var(--line); border-radius:6px;
  background:var(--bg); color:var(--muted);
  font-size:11px; line-height:1; cursor:pointer; text-decoration:none;
  transition:border-color .12s, color .12s, background .12s;
}
.iconbtn:hover { border-color:var(--accent); color:var(--accent); background:var(--accent-bg) }
.iconbtn:focus-visible { outline:2px solid var(--accent); outline-offset:1px }

/* Filters: a grid that wraps predictably. The fixed six-column grid held eight
   controls, so two wrapped onto a line of their own with the button stranded. */
.filterbar {
  display:grid; gap:11px 13px; align-items:end;
  grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
}
.filterbar .wide { grid-column:span 2 }
.filterbar .actions { display:flex; gap:8px; align-items:end }
.filterbar select, .filterbar input { width:100% }

/* The expanded transcript sits under its row, indented to show it belongs to it. */
tr.turnrow > td { background:var(--bg); padding:13px 10px 15px 44px !important }

/* ═══════════════════════════════════════════════════════════════════════════
   PHONES AND SMALL TABLETS
   Everything above is built for a wide screen. This section is not a shrink of
   it: a twelve-column table scrolled sideways on a phone is technically
   reachable and practically unusable, so the tables that matter become a card
   per row with each value labelled. Written mobile-last rather than
   mobile-first because the desktop layout already existed and is the one people
   use most; the queries below only ever widen a rule's reach downward.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 760px) {

  /* The wide container is for a data table on a monitor, never on a phone. */
  body.wide main, main { max-width:100%; padding:14px 13px 64px }
  /* The strip matches the content gutter, and its call to action drops onto its own
     line as a full-width tap target rather than a 13px link wedged beside the text. */
  .attention, body.wide .attention { max-width:100%; padding:0 13px; margin-top:12px }
  .alert { gap:4px; padding:9px 12px }
  /* Right-aligned and roomy enough to hit, without the full-width row that cost 50px
     of a phone screen per alert. */
  .alert-cta { margin-left:auto; min-height:34px; display:flex; align-items:center }
  header.top { padding:11px 13px; flex-direction:column; align-items:flex-start; gap:9px }
  header.top h1 { font-size:15px }

  /* Eight nav links will not fit and should not stack into a wall. One row that
     scrolls, with the edge fading so it is obvious there is more. */
  header.top nav {
    width:100%; gap:0; overflow-x:auto; -webkit-overflow-scrolling:touch;
    scrollbar-width:none; flex-wrap:nowrap;
    mask-image:linear-gradient(to right, #000 88%, transparent);
  }
  header.top nav::-webkit-scrollbar { display:none }
  header.top nav a { white-space:nowrap; padding:7px 11px 7px 0; font-size:13.5px }

  h1 { font-size:19px } h2 { font-size:16px; margin-top:22px }
  .sub { display:block; margin-top:3px }

  /* Two tiles across reads better than four squeezed ones. */
  .kpis { grid-template-columns:repeat(auto-fit, minmax(132px,1fr)); gap:9px }
  .chartgrid { grid-template-columns:1fr; gap:11px }
  .kpi .value { font-size:22px }

  /* One control per line. Anything narrower is a guessing game on a phone. */
  .filterbar { grid-template-columns:1fr }
  .filterbar .wide { grid-column:auto }
  .filterbar .actions { margin-top:2px }

  /* 16px stops iOS zooming the whole page in when a field is focused, and 44px
     is the smallest target a finger hits reliably. */
  input, select, textarea { font-size:16px !important; min-height:42px }
  /* Every variant, including .small. An anchor styled as a button is display:inline
     by default, and min-height does nothing to an inline box - which is why one
     "See the results" link stayed 37px while everything around it obeyed. */
  .btn, .btn.small, button, a.btn {
    display:inline-flex; align-items:center; justify-content:center;
    min-height:42px; padding:10px 15px;
  }
  .btn.small { font-size:13px }
  .iconbtn { width:42px; height:42px; font-size:14px; margin-right:6px }

  .card { padding:13px; border-radius:10px }
  textarea { min-height:230px }         /* readable without being the whole page */
  .kpi .note { font-size:11px }

  /* ── the transcripts list becomes one card per call ────────────────────── */
  .tx table.tight, .tx table.tight thead, .tx table.tight tbody,
  .tx table.tight tr, .tx table.tight td { display:block; width:auto }
  .tx table.tight thead { display:none }        /* the labels move into the rows */

  .tx table.tight tbody tr {
    border:1px solid var(--line); border-radius:10px;
    padding:11px 12px; margin-bottom:10px; background:var(--card);
  }
  .tx table.tight tbody tr:hover { background:var(--card) }

  .tx table.tight td {
    border:0; padding:2px 0; max-width:none !important;
    display:flex; gap:10px; align-items:baseline;
  }
  /* Each value says what it is, taken from the header it lost. */
  .tx table.tight td[data-label]::before {
    content:attr(data-label);
    flex:0 0 88px; font-size:11px; text-transform:uppercase;
    letter-spacing:.04em; color:var(--muted);
  }
  .tx table.tight tbody tr { position:relative }
  .tx table.tight td.acts {
    position:absolute; top:7px; right:9px;
    padding:0; margin:0; border:0; width:auto;
  }
  .tx table.tight td.acts::before { content:none }
  /* Keep the call line clear of the corner buttons. :first-of-type matched the
     actions cell itself, so the padding landed on the wrong element and the date
     ran underneath the buttons. */
  .tx table.tight td[data-label="Call"] { padding-right:96px }
  .tx table.tight td.stack { display:flex; flex-wrap:wrap; gap:0 10px; align-items:baseline }
  .tx table.tight td.stack::before { flex:0 0 72px }
  /* A short second value - a date, a turn count, a band - reads better beside the
     first than under it, and saves a line per cell. Only the long ones wrap: a
     campaign name will not sit next to an agent's name on a 375px screen. */
  .tx table.tight td.stack .sub2 {
    flex:0 1 auto; margin:0; min-width:0;
    overflow:hidden; text-overflow:ellipsis;
  }
  .tx table.tight td.stack.clip .sub2 {
    flex:0 0 calc(100% - 82px); margin-left:82px;
  }
  .tx table.tight td.words { display:block; margin-top:5px;
    padding-top:6px; border-top:1px solid var(--line) }
  .tx table.tight td.words::before { display:block; margin-bottom:2px }
  /* Three lines is enough to judge whether a call is worth opening. The full 220
     characters made every card 437px tall, so four calls filled a phone screen. */
  .tx table.tight td.words .snip {
    white-space:normal; overflow:hidden; display:-webkit-box;
    -webkit-line-clamp:3; -webkit-box-orient:vertical;
  }
  .tx table.tight td.stack .sub2, .tx table.tight td.words .sub2 { white-space:normal }
  /* .num right-aligns its content, and that includes the ::before label - so
     LENGTH, PITCH and CUSTOMER sat further right than CALL, AGENT and LANGUAGE and
     the label column came out ragged. On a phone nothing is a column any more, so
     the right-alignment has no job here. */
  .tx table.tight td.num, .tx table.tight td.num::before { text-align:left }
  .tx table.tight td.num { justify-content:flex-start }

  /* Tables elsewhere keep their shape and scroll, with the edge faded so it is
     visible that they do. Stacking every table on every page would be a bigger
     change than this needs to be. */
  .card table:not(.tight) { min-width:520px }
  .card:not(.tx) { overflow-x:auto; -webkit-overflow-scrolling:touch }
  .tx { overflow-x:visible }


  /* ── every other table becomes a card per row ──────────────────────────────
     The class and the data-label attributes are put on by the script in
     base.html, which reads each table's own header row. A table with fewer than
     two headings, or a full-width note row, is left alone. */
  .card table.stacked, .card table.stacked thead, .card table.stacked tbody,
  .card table.stacked tr, .card table.stacked td { display:block; width:auto }
  .card table.stacked { min-width:0 }
  /* Most of these tables put their headings in a bare <tr><th> with no <thead>, so
     hiding thead missed them: the th cells stayed table-cells and their row alone was
     376px wider than the screen. Hiding every th covers both shapes, and the labels
     are already copied onto the cells by then. */
  .card table.stacked thead, .card table.stacked th { display:none }

  .card table.stacked tbody tr, .card table.stacked > tr {
    border:1px solid var(--line); border-radius:10px;
    padding:10px 12px; margin-bottom:9px; background:var(--card);
  }
  .card table.stacked td {
    border:0; padding:3px 0; max-width:none;
    display:flex; gap:10px; align-items:baseline; text-align:left;
  }
  .card table.stacked td::before {
    content:attr(data-label);
    flex:0 0 96px; font-size:11px; text-transform:uppercase;
    letter-spacing:.04em; color:var(--muted); text-align:left;
  }
  .card table.stacked td:not([data-label])::before { content:none }
  /* a value with no label - a note row - takes the full width */
  .card table.stacked td[colspan] { display:block }
  .card table.stacked td.num { justify-content:flex-start }
  /* A 96px label beside a value that will not break is wider than the screen, and
     an anonymous flex item cannot be given min-width:0 - so the value is made
     breakable instead. Call ids and quoted speech are the ones that need it. */
  .card table.stacked td { overflow-wrap:anywhere }
  .card table.stacked td > * { min-width:0; overflow-wrap:anywhere }
  .card table.stacked td .mono,
  .card table.stacked td .pill { white-space:normal }
  /* the label itself never wraps - it is short, and wrapping it breaks the column */
  .card table.stacked td::before { white-space:nowrap }

  /* An expanded transcript should not be indented off the screen. */
  tr.turnrow > td { padding:11px 0 4px !important }
  .turn { grid-template-columns:1fr; gap:2px }
  .turn .who, .turn .ts { font-size:11px }
}

@media (max-width: 420px) {
  .kpis { grid-template-columns:1fr 1fr }
  .tx table.tight td[data-label]::before { flex-basis:76px }
  main { padding:12px 11px 60px }
}
/* ── collapsible filters ──────────────────────────────────────────────────────
   Eight stacked controls are 566px, so on a phone the filters filled the screen
   and the calls began below the fold. They collapse unless something is filtered,
   in which case they stay open so the active filter is visible rather than hidden
   behind a button. */
.filtertoggle { display:none }
@media (max-width: 760px) {
  .filtertoggle {
    display:inline-flex; align-items:center; gap:7px; width:100%;
    justify-content:space-between; margin:0;
  }
  .filters.collapsed .filterbar { display:none }
  .filters .filterbar { margin-top:11px }
  .filtertoggle .chev { transition:transform .15s }
  .filters.collapsed .filtertoggle .chev { transform:rotate(-90deg) }
}
