/* FoxOS hub — dispatch board.
 *
 * The records here are already tickets: TASK-0001, COMP-0001, a priority, a due
 * date, a status. The visual system leans into that rather than hiding it in a
 * generic dashboard. One signature device, used everywhere:
 *
 *   the ticket rail — a coloured left edge keyed to urgency, the record id set
 *   in mono as the ticket number, and an OVERDUE stamp where it applies.
 *
 * Ground is navy derived from the AEOfox #02235B, not neutral slate. Orange
 * (#DE3707) is spent only on the primary action and on overdue; everything else
 * stays quiet so those two read instantly.
 *
 * Typeface stack matches brianmercier.com so the screenshots sit natively in the
 * portfolio page. Fontshare, display=swap, real fallbacks — a font timeout must
 * never blank the board.
 */

/* ── tokens ──────────────────────────────────────────────────────────────── */
:root {
  --ink: #08121f;
  --slab: #0e1b2c;
  --slab-2: #14263c;
  --rule: #1c3350;
  --rule-2: #27466b;

  --paper: #e4ebf4;
  --dim: #7e93b0;
  --faint: #55698a;

  --ember: #de3707;
  --ember-lit: #ff6a3d;
  --navy: #02235b;
  --brass: #e0a33c;
  --sage: #35a16b;
  --rust: #c4402e;

  --tint-ember: #2b0f08;
  --tint-brass: #2a2110;
  --tint-sage: #0d2519;
  --tint-steel: #0f2337;

  --display: 'Clash Grotesk', 'Satoshi', system-ui, -apple-system, sans-serif;
  --sans: 'Satoshi', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Consolas, monospace;

  --r: 10px;
  --shadow: 0 1px 2px rgb(0 0 0 / .4), 0 8px 24px -12px rgb(0 0 0 / .6);
  --speed: 120ms;
}

/* Light is a warm paper, not an inverted grey — it has to look chosen, not
   like the dark theme with the lights turned on. */
:root[data-theme='light'] {
  --ink: #f2f0ec;
  --slab: #fff;
  --slab-2: #f7f5f1;
  --rule: #e0ddd5;
  --rule-2: #cbc7bd;

  --paper: #14212f;
  --dim: #5d6b7d;
  --faint: #8b96a4;

  --ember-lit: #c22f05;

  --tint-ember: #fdece7;
  --tint-brass: #fbf1dc;
  --tint-sage: #e6f4ec;
  --tint-steel: #eaf0f7;

  --shadow: 0 1px 2px rgb(20 33 47 / .06), 0 8px 24px -14px rgb(20 33 47 / .18);
}

* { box-sizing: border-box; margin: 0; }

/* The UA sheet's `[hidden] { display: none }` loses to any author rule that
   sets display — `label { display: block }` below, `.picker-list` further
   down. Both have already been bugs here. State it once, with authority, so
   el.hidden means hidden everywhere. */
[hidden] { display: none !important; }

body {
  background: var(--ink);
  color: var(--paper);
  font: 15px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; }

/* Dates, values and ids are compared down a column — they must not jitter. */
.num, .idcell, time, .kpi-n { font-variant-numeric: tabular-nums; }

h1, h2, h3 { font-family: var(--display); font-weight: 600; letter-spacing: -.02em; line-height: 1.1; }
h1 { font-size: 27px; }
h2 { font-size: 15px; letter-spacing: -.01em; }
h3 { font-size: 17px; }

/* The eyebrow does structural work: it labels a region in the board's own
   vocabulary. Mono + tracking because these read as stencilled equipment
   labels, which is the world this tool lives in. */
.eyebrow {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: .15em; text-transform: uppercase; color: var(--faint);
}

.muted { color: var(--dim); }
.sub { color: var(--dim); font-size: 12.5px; margin-top: 2px; }

/* ── console bar ─────────────────────────────────────────────────────────── */
.topnav {
  display: flex; align-items: center; gap: 16px; padding: 0 16px; height: 52px;
  background: var(--slab); border-bottom: 1px solid var(--rule);
  position: sticky; top: 0; z-index: 5;
}
.brand {
  display: flex; align-items: center; gap: 9px; text-decoration: none;
  font-family: var(--display); font-weight: 600; font-size: 17px; letter-spacing: -.01em;
  flex: none;
}
.brand img { display: block; width: 26px; height: 26px; }

.navlinks { display: flex; gap: 2px; flex: 1; overflow-x: auto; scrollbar-width: none; }
.navlinks::-webkit-scrollbar { display: none; }
.navlinks a {
  text-decoration: none; color: var(--dim); padding: 7px 11px; border-radius: 8px;
  white-space: nowrap; font-size: 14px; transition: color var(--speed), background var(--speed);
}
.navlinks a:hover { color: var(--paper); background: var(--slab-2); }
.navlinks a.active { color: var(--paper); background: var(--slab-2); box-shadow: inset 0 -2px 0 var(--ember); }

/* Live readout: the board tells you its own state from every page. */
.console-state {
  display: flex; align-items: center; gap: 10px; flex: none;
  font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint); white-space: nowrap;
}
.console-state b { font-weight: 500; color: var(--dim); }
.console-state .hot { color: var(--ember-lit); }
.navsearch { flex: none; }
.navsearch input {
  width: 190px; margin-top: 0; padding: 6px 10px; font-size: 13px;
  background: var(--ink); border-color: var(--rule);
}
.navsearch input::placeholder { color: var(--faint); }
.navsearch input:focus { width: 260px; border-color: var(--ember); }
.navsearch input { transition: width var(--speed), border-color var(--speed); }

.navtools { display: flex; align-items: center; gap: 6px; flex: none; }

/* Sortable headers. The arrow is always in the layout, just transparent until
   the column is the active one — otherwise every header shifts a pixel when you
   sort it, which reads as a bug. */
table.list thead th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
table.list thead th.sortable:hover { color: var(--dim); }
table.list thead th.sortable::after {
  content: '▲'; font-size: 8px; margin-left: 5px; color: transparent; vertical-align: 1px;
}
table.list thead th.sortable[data-dir='asc']::after { color: var(--ember-lit); }
table.list thead th.sortable[data-dir='desc']::after { content: '▼'; color: var(--ember-lit); }

.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border-radius: 8px; cursor: pointer;
  background: transparent; border: 1px solid transparent; color: var(--dim);
  transition: color var(--speed), background var(--speed), border-color var(--speed);
}
.iconbtn:hover { color: var(--paper); background: var(--slab-2); border-color: var(--rule); }
.iconbtn svg { width: 16px; height: 16px; }

/* ── page frame ──────────────────────────────────────────────────────────── */
.wrap { max-width: 1180px; margin: 0 auto; padding: 22px 16px 72px; }
/* On a wide monitor the 1180px cap left the dashboard's three cards squeezing
   their titles into four-word lines while a third of the screen sat empty.
   Still capped — a table measured in metres is no easier to read — just less
   miserly where there is room. */
@media (min-width: 1400px) { .wrap { max-width: 1340px; } }
.pagehead { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.pagehead .actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.flash {
  background: var(--tint-steel); border: 1px solid var(--rule-2); color: var(--paper);
  padding: 9px 13px; border-radius: var(--r); margin-bottom: 14px; font-size: 14px;
}
.flash.error { background: var(--tint-ember); border-color: var(--rust); }

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 14px; }
.card {
  background: var(--slab); border: 1px solid var(--rule); border-radius: var(--r);
  padding: 15px; box-shadow: var(--shadow);
  /* Safety net for the prose a card can hold: file paths, URLs, pasted notes.
     `anywhere` only breaks a word that genuinely will not fit, so ordinary text
     is untouched, and nowrap cells opt out of breaking entirely. */
  overflow-wrap: anywhere;
}
.cardhead { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 11px; }

/* ── KPI strip ───────────────────────────────────────────────────────────── */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 16px; }
.kpi {
  background: var(--slab); border: 1px solid var(--rule); border-radius: var(--r);
  padding: 12px 14px; box-shadow: var(--shadow); position: relative; overflow: hidden;
}
.kpi-n { font-family: var(--display); font-size: 30px; line-height: 1; letter-spacing: -.03em; margin-top: 7px; }
.kpi-sub { font-size: 12px; color: var(--faint); margin-top: 5px; }
.kpi.hot { border-color: var(--ember); }
.kpi.hot .kpi-n { color: var(--ember-lit); }
.kpi.warm .kpi-n { color: var(--brass); }

/* Sparkline sits behind the number, bleeding to the card edge — ambient, not a
   chart. It answers "busier than usual?" and nothing more, so it carries no
   axis and no label. */
.kpi svg.spark { position: absolute; right: 0; bottom: 0; width: 62%; height: 30px; opacity: .5; }
.kpi svg.spark path { fill: none; stroke: var(--rule-2); stroke-width: 1.5; }

/* ── tables ──────────────────────────────────────────────────────────────── */
.tablewrap { overflow-x: auto; }
table.list { width: 100%; border-collapse: collapse; }
table.list td, table.list th { padding: 9px 8px; border-top: 1px solid var(--rule); text-align: left; vertical-align: top; }

/* `width: 100%` is a ceiling a table will ignore: auto layout never renders
   narrower than min-content, so a title with one long unbreakable word plus a
   nowrap date column pushes the table past its card. `anywhere` (not
   `break-word`) is the one that also shrinks the min-content measurement, which
   is what actually lets the table fit.
   Cells that must stay intact — dates, ticket ids — carry white-space: nowrap,
   which suppresses breaking entirely, so they are unaffected.
   This shows up hardest at OS text scaling above 100%: every minimum grows
   while the card stays a share of the viewport. */
table.list td { overflow-wrap: anywhere; }
table.list thead th {
  border-top: 0; border-bottom: 1px solid var(--rule-2); color: var(--faint); padding-bottom: 7px;
  font-family: var(--mono); font-size: 10.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
}
table.list tbody tr:first-child td { border-top: 0; }
.rowlink { cursor: pointer; transition: background var(--speed); }
.rowlink:hover td { background: var(--slab-2); }
.num { text-align: right; white-space: nowrap; color: var(--dim); font-size: 13.5px; }
.idcell { font-family: var(--mono); font-size: 11.5px; white-space: nowrap; color: var(--faint); }

/* The ticket rail. A row's left edge carries its urgency, so the eye finds the
   late work before it reads a word. Applied via a cell border rather than a
   pseudo-element so it survives inside a scrolling table. */
tr.rail > td:first-child { border-left: 3px solid transparent; padding-left: 10px; }
tr.rail-overdue > td:first-child { border-left-color: var(--ember); }
tr.rail-today > td:first-child { border-left-color: var(--brass); }
tr.rail-open > td:first-child { border-left-color: var(--rule-2); }
tr.rail-done > td:first-child { border-left-color: var(--sage); }

.stamp {
  display: inline-block; margin-left: 7px; padding: 1px 5px; border-radius: 3px;
  font-family: var(--mono); font-size: 9.5px; font-weight: 500; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ember-lit); border: 1px solid var(--ember);
  vertical-align: 1.5px;
}

/* ── badges ──────────────────────────────────────────────────────────────── */
.badge {
  display: inline-block; padding: 2.5px 9px; border-radius: 999px; white-space: nowrap;
  font-family: var(--mono); font-size: 10.5px; font-weight: 500; letter-spacing: .04em;
  background: var(--slab-2); color: var(--dim); border: 1px solid transparent;
}
.badge.p-high { background: var(--tint-ember); color: var(--ember-lit); border-color: #5c2113; }
.badge.p-medium { background: var(--tint-brass); color: var(--brass); border-color: #4a3a17; }
.badge.p-low { background: var(--tint-sage); color: var(--sage); border-color: #1a4430; }
/* 'Open' is the resting state of almost every task, so colouring it warm made a
   whole board look like it needed attention. The rail already carries urgency.
   Brass stays for the states that genuinely want an eye: a follow-up that is
   due, a post that is ready to go. */
.badge.s-due, .badge.s-ready { background: var(--tint-brass); color: var(--brass); }
.badge.s-open { background: var(--slab-2); color: var(--dim); }
.badge.s-snoozed, .badge.s-draft { background: var(--slab-2); color: var(--dim); }
.badge.s-scheduled, .badge.s-inprogress { background: var(--tint-steel); color: #6fb6e8; }
.badge.s-posted, .badge.s-complete, .badge.s-completed, .badge.s-won { background: var(--tint-sage); color: var(--sage); }
.badge.s-error, .badge.s-cancelled, .badge.s-lost { background: var(--tint-ember); color: var(--ember-lit); }
.badge.st-inbox { background: var(--slab-2); color: var(--dim); }
.badge.st-research { background: var(--tint-steel); color: #6fb6e8; }
.badge.st-commit, .badge.st-build { background: var(--tint-brass); color: var(--brass); }
.badge.st-launch, .badge.st-live { background: var(--tint-sage); color: var(--sage); }
.badge.st-killed, .badge.st-parked { background: var(--tint-ember); color: var(--ember-lit); }

/* The dark-theme badge inks are tuned for a navy ground; on paper the blue and
   the brass both fall under 4.5:1. Darken those two rather than re-tinting the
   whole set. */
:root[data-theme='light'] .badge.p-high { border-color: #f3c4b5; }
:root[data-theme='light'] .badge.p-medium { border-color: #ecd9a8; color: #8a6410; }
:root[data-theme='light'] .badge.p-low { border-color: #b8dfc8; color: #1c7146; }
:root[data-theme='light'] .badge.s-due,
:root[data-theme='light'] .badge.s-open,
:root[data-theme='light'] .badge.s-ready { color: #8a6410; }
:root[data-theme='light'] .badge.s-scheduled,
:root[data-theme='light'] .badge.s-inprogress,
:root[data-theme='light'] .badge.st-research,
:root[data-theme='light'] .feed-ico.created { color: #1c5f92; }
:root[data-theme='light'] .badge.s-posted,
:root[data-theme='light'] .badge.s-complete,
:root[data-theme='light'] .badge.s-completed,
:root[data-theme='light'] .badge.s-won,
:root[data-theme='light'] .badge.st-launch,
:root[data-theme='light'] .badge.st-live { color: #1c7146; }

/* ── buttons ─────────────────────────────────────────────────────────────── */
.btn {
  background: var(--slab-2); color: var(--paper); border: 1px solid var(--rule-2);
  border-radius: 8px; padding: 7px 14px; cursor: pointer; font: 500 14px var(--sans);
  text-decoration: none; display: inline-block; white-space: nowrap;
  transition: background var(--speed), border-color var(--speed), transform var(--speed);
}
.btn:hover { border-color: var(--dim); }
.btn:active { transform: translateY(1px); }
.btn.small { padding: 5px 11px; font-size: 13px; }
.btn.primary { background: var(--ember); border-color: var(--ember); color: #fff; }
.btn.primary:hover { background: var(--ember-lit); border-color: var(--ember-lit); }
.btn.good { background: var(--sage); border-color: var(--sage); color: #fff; }
.btn.danger { background: var(--rust); border-color: var(--rust); color: #fff; }
.btn.ghost { background: transparent; border-color: var(--rule); color: var(--dim); }
.btn.ghost:hover { color: var(--paper); border-color: var(--rule-2); }

/* One visible focus treatment for every interactive thing, keyboard only. */
:focus-visible { outline: 2px solid var(--ember-lit); outline-offset: 2px; border-radius: 4px; }

.quicklinks { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 14px; align-items: center; }
.quicklinks a, .quicklinks button {
  background: var(--slab); border: 1px solid var(--rule); border-radius: 999px;
  padding: 5px 13px; font-size: 13px; text-decoration: none; color: var(--dim); cursor: pointer;
  transition: color var(--speed), border-color var(--speed);
}
.quicklinks a:hover, .quicklinks button:hover { color: var(--paper); border-color: var(--rule-2); }
/* Deliberately not mono: "link" in JetBrains Mono at 12px reads as "11nk". */
.quicklinks .addlink { color: var(--faint); font-size: 12.5px; }

/* ── login ───────────────────────────────────────────────────────────────── */
.login-card {
  max-width: 370px; margin: 12vh auto; background: var(--slab);
  border: 1px solid var(--rule); border-radius: 14px; padding: 30px; text-align: center;
  box-shadow: var(--shadow);
}
.login-card img { width: 46px; height: 46px; margin-bottom: 12px; }
.login-card h1 { font-size: 24px; }
.login-card form { text-align: left; margin-top: 18px; display: grid; gap: 13px; }

/* ── forms ───────────────────────────────────────────────────────────────── */
label { display: block; font-size: 12.5px; color: var(--dim); }
input, textarea, select {
  width: 100%; max-width: 100%; margin-top: 4px; background: var(--ink); color: var(--paper);
  border: 1px solid var(--rule-2); border-radius: 8px; padding: 8px 10px; font: inherit;
  transition: border-color var(--speed);
}
/* A textarea defaults to resize:both, and the grip writes an inline width that
   the modal does not clip — one drag and a notes field hangs 300px out over the
   page, and it stays that way. Growing downward is the useful direction anyway;
   the width is the modal's to decide. */
textarea { resize: vertical; min-height: 68px; }
input:hover, textarea:hover, select:hover { border-color: var(--dim); }
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--ember); }
input[type=search] { margin-top: 0; }

.picker { position: relative; display: block; }
.picker-list {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 30; margin-top: 3px;
  background: var(--slab-2); border: 1px solid var(--rule-2); border-radius: 8px;
  max-height: 220px; overflow-y: auto; display: block; box-shadow: var(--shadow);
}
/* The `display: block` above would beat the UA sheet's [hidden] rule; the
   global `[hidden] { display: none !important }` at the top now covers this and
   every other case, so no per-component restatement is needed. */
.picker-list button {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  color: var(--paper); padding: 8px 10px; cursor: pointer; font: inherit;
}
.picker-list button:hover { background: var(--slab); }
.picker-list button .muted { font-family: var(--mono); font-size: 11px; }
.picker-empty { display: block; padding: 8px 10px; font-size: 13px; }

/* A number field with its actions on the same line — snooze-by-N and friends,
   where the button belongs to the value beside it rather than to the form. */
.inline-act { display: flex; gap: 6px; align-items: center; margin-top: 4px; }
.inline-act input { width: 86px; margin-top: 0; }

.checks { border: 1px solid var(--rule-2); border-radius: 8px; padding: 8px 12px 10px; }
.checks legend { font-size: 12.5px; color: var(--dim); padding: 0 4px; }
.check { display: inline-flex; align-items: center; gap: 5px; margin: 4px 12px 2px 0; font-size: 13.5px; color: var(--paper); }
.check input { width: auto; margin: 0; accent-color: var(--ember); }

/* Groups the audit-intake fields without burying them — closed by default so
   the common path stays short, one click to the full record. */
details.fieldset { border: 1px solid var(--rule); border-radius: 8px; padding: 0 12px; }
details.fieldset > summary {
  cursor: pointer; padding: 9px 0; list-style: none; color: var(--dim); font-size: 13px;
  display: flex; align-items: center; gap: 7px;
}
details.fieldset > summary::-webkit-details-marker { display: none; }
details.fieldset > summary::before { content: '+'; font-family: var(--mono); color: var(--faint); }
details.fieldset[open] > summary::before { content: '−'; }
details.fieldset[open] > summary { border-bottom: 1px solid var(--rule); margin-bottom: 11px; }
details.fieldset .cols { padding-bottom: 12px; }

/* ── modal ───────────────────────────────────────────────────────────────── */
.overlay {
  position: fixed; inset: 0; background: rgb(2 8 16 / .68); backdrop-filter: blur(2px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 6vh 12px; z-index: 20; overflow-y: auto;
  animation: fade var(--speed) ease-out;
}
.modal {
  background: var(--slab); border: 1px solid var(--rule-2); border-radius: 13px;
  width: 100%; max-width: 580px; box-shadow: 0 24px 64px -20px rgb(0 0 0 / .8);
  animation: rise 160ms cubic-bezier(.2, .8, .3, 1);
}
@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

.modalhead { padding: 15px 19px; border-bottom: 1px solid var(--rule); display: flex; align-items: center; gap: 10px; }
.modalhead h3 { font-family: var(--mono); font-size: 12.5px; font-weight: 500; letter-spacing: .1em; color: var(--dim); }
.modalbody { padding: 17px 19px; display: grid; gap: 13px; overflow-wrap: anywhere; }
/* The company card lists work-product paths as <code>; those are exactly the
   unbreakable strings that push a modal open. */
.modalbody code { font-family: var(--mono); font-size: 12px; color: var(--dim); }
.modalbody .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 11px; }
.modalfoot { padding: 14px 19px; border-top: 1px solid var(--rule); display: flex; gap: 8px; flex-wrap: wrap; }

/* ── deals board ─────────────────────────────────────────────────────────── */
/* Fourteen stages stacked vertically buried the shape of the pipeline. As a
   board it reads in one glance, and a card can be dragged to the next stage —
   which is the same POST /advance the modal button fires. */
.board { display: flex; gap: 11px; overflow-x: auto; padding-bottom: 14px; scroll-snap-type: x proximity; }
/* The OS scrollbar under a dark board is a bright grey slab. Slim it and tint
   it to the panel so the pipeline, not the chrome, is what you see. */
.board { scrollbar-width: thin; scrollbar-color: var(--rule-2) transparent; }
.board::-webkit-scrollbar { height: 8px; }
.board::-webkit-scrollbar-track { background: transparent; }
.board::-webkit-scrollbar-thumb { background: var(--rule-2); border-radius: 99px; }
.board::-webkit-scrollbar-thumb:hover { background: var(--dim); }
.col {
  flex: 0 0 246px; scroll-snap-align: start; background: var(--slab);
  border: 1px solid var(--rule); border-radius: var(--r); display: flex; flex-direction: column;
}
/* Empty stages narrow rather than disappear. Fourteen full-width columns is a
   lot of scrolling for a pipeline that is busy in three places, but hiding the
   empty ones would hide the shape — where the work is bunched, and where it is
   not, is the thing the board is for. */
.col.empty { flex-basis: 130px; background: transparent; border-style: dashed; }
.col.empty .colhead { border-bottom-color: transparent; }
.col.empty h2 { color: var(--faint); font-size: 12px; }
.colhead { padding: 11px 12px 9px; border-bottom: 1px solid var(--rule); }
.colhead .n { float: right; font-family: var(--mono); font-size: 11px; color: var(--faint); }
.colhead h2 { font-size: 13px; line-height: 1.25; padding-right: 22px; }
/* Columns share a floor height rather than shrink-wrapping their cards. Two
   reasons: a 60px stage next to a 300px one reads as a broken layout, and a
   drop target you have to aim at is a bad drop target. */
.colbody { padding: 9px; display: grid; gap: 8px; min-height: 210px; align-content: start; }
.col.over .colbody { background: var(--tint-steel); border-radius: 0 0 var(--r) var(--r); }

.deal {
  background: var(--slab-2); border: 1px solid var(--rule); border-left: 3px solid var(--rule-2);
  border-radius: 7px; padding: 9px 10px; cursor: grab;
  transition: border-color var(--speed), transform var(--speed);
}
.deal:hover { border-color: var(--rule-2); border-left-color: var(--ember); }
.deal.dragging { opacity: .4; cursor: grabbing; }
.deal .t { font-size: 13.5px; line-height: 1.3; overflow-wrap: anywhere; }
.deal .co { color: var(--dim); font-size: 12px; margin-top: 3px; overflow-wrap: anywhere; }
.deal .foot { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; gap: 8px; }
.deal .v { font-family: var(--mono); font-size: 12px; color: var(--paper); }
.colsum { font-family: var(--mono); font-size: 11px; color: var(--faint); padding: 0 12px 10px; }

.boardhint { color: var(--faint); font-size: 12.5px; margin-bottom: 10px; }

/* ── activity feed ───────────────────────────────────────────────────────── */
.feed { display: grid; gap: 0; }
.feed-row { display: grid; grid-template-columns: 22px 1fr auto; gap: 10px; padding: 9px 0; border-top: 1px solid var(--rule); align-items: start; }
.feed-row:first-child { border-top: 0; }
.feed-ico { width: 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; background: var(--slab-2); color: var(--dim); }
.feed-ico svg { width: 12px; height: 12px; }
.feed-ico.created { background: var(--tint-steel); color: #6fb6e8; }
.feed-ico.completed, .feed-ico.published { background: var(--tint-sage); color: var(--sage); }
.feed-ico.advanced, .feed-ico.sent { background: var(--tint-brass); color: var(--brass); }
.feed-ico.deleted { background: var(--tint-ember); color: var(--ember-lit); }
.feed-t { font-size: 13.5px; line-height: 1.4; overflow-wrap: anywhere; }
.feed-when { font-family: var(--mono); font-size: 11px; color: var(--faint); white-space: nowrap; }

.empty { color: var(--dim); font-size: 13.5px; padding: 6px 0; }
.empty b { color: var(--paper); font-weight: 500; }

/* ── responsive ──────────────────────────────────────────────────────────── */
/* The readout is the first thing to go — the search box earns its width, and
   the counts are repeated on the dashboard's KPI strip anyway. */
@media (max-width: 1080px) {
  .console-state { display: none; }
}
@media (max-width: 820px) {
  .navsearch input { width: 130px; }
  .navsearch input:focus { width: 170px; }
}
@media (max-width: 560px) {
  .modalbody .cols { grid-template-columns: 1fr; }
  .wrap { padding: 14px 10px 72px; }
  h1 { font-size: 23px; }
  .kpis { grid-template-columns: 1fr 1fr; }
  .col { flex-basis: 82vw; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
