/* =============================================================================
   crm.css — the CRM module

   Two dashboards and one search box: the day, and then one client. The visual
   job of the client half is a screen read in the five seconds between the phone
   ringing and the rep saying hello, so the order on screen is the order of that
   moment:

     who is this  →  what do I owe them  →  what do I say  →  what do I sell

   Shared components (card, table, badge, switch, chip) come from css/app.css
   untouched; everything here is page-scoped.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   The search — the only control that is always on the page
   -------------------------------------------------------------------------- */
.cs { position: relative; max-width: 680px; margin: 0 0 18px; }

.cs__box {
  display: flex; align-items: center; gap: 10px;
  padding: 0 12px;
  /* The portal paints every search field on its own ground; this is the same
     field, only bigger, so it takes the same colour rather than inventing one. */
  background: var(--color-search-bg);
  border: 1px solid var(--color-control-border);
  border-radius: 7px;
  transition: border-color 120ms, background 120ms, box-shadow 120ms;
}
.cs__box:focus-within {
  background: var(--color-surface);
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-50);
}
.cs__box > svg { width: 19px; height: 19px; flex: none; color: var(--color-text-subtle); }

/* Element-qualified in app.css (input[type="search"]), so a class on its own
   loses and the field paints a second rectangle inside its own box. */
.cs__box .cs__input {
  flex: 1; min-width: 0;
  padding: 13px 0; border: 0; background: transparent;
  font-family: inherit; font-size: 15px; color: var(--color-text);
}
.cs__input:focus { outline: none; }
.cs__input::placeholder { color: var(--color-text-subtle); }
.cs__input::-webkit-search-cancel-button { display: none; }

.cs__clear {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  border: 0; border-radius: 5px; background: transparent; cursor: pointer;
  color: var(--color-text-subtle);
}
.cs__clear:hover { background: var(--color-border); color: var(--color-text); }
.cs__clear svg { width: 15px; height: 15px; }

.cs__menu {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0; right: 0;
  padding: 5px;
  background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: 7px;
  box-shadow: var(--shadow-lg);
}
.cs__row {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: 5px;
  background: transparent; font: inherit; text-align: left; cursor: pointer;
}
.cs__row:hover { background: var(--color-primary-50); }
.cs__row .avatar { width: 32px; height: 32px; flex: none; }
.cs__row-t { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.cs__row-n { font-size: 14px; font-weight: 600; color: var(--color-text); }
.cs__row-s { font-size: 12px; color: var(--color-text-muted); }
.cs__row-go { flex: none; color: var(--color-text-subtle); display: inline-flex; }
.cs__row-go svg { width: 16px; height: 16px; }
.cs__row:hover .cs__row-go { color: var(--color-primary); }
.cs__none { padding: 12px 10px; font-size: 13px; color: var(--color-text-muted); }

/* -----------------------------------------------------------------------------
   Before a client is picked — the day's dashboard

   The landing view answers one question, who do I call today and why, so the
   visual weight goes to the queue and everything else on it is support. The
   four book-wide tabs behind Today are browsing rather than doing, and are
   styled by app.css exactly as they were on the page they came from.
   -------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
   The search row

   The box and the last three clients opened share one line. On its own the box
   caps at 560px and leaves the right half of the page empty, which is the first
   thing anybody notices; the chips fill it with the only other thing worth
   reaching for before a name is typed.
   -------------------------------------------------------------------------- */
.ct-find { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 18px; margin-bottom: var(--page-gap); }
.ct-find .cs { flex: 1 1 360px; max-width: 560px; margin: 0; }

.ct-recent { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 0; }
.ct-recent__l {
  margin-right: 2px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--color-text-subtle);
}
.ct-recent__chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px 6px 6px; border-radius: 7px;
  background: var(--color-control); border: 1px solid var(--color-control-border);
  font: inherit; font-size: 13px; cursor: pointer; color: var(--color-text);
}
.ct-recent__chip:hover { border-color: var(--color-primary); color: var(--color-primary-700); }
.ct-recent__chip .avatar { width: 24px; height: 24px; font-size: 10px; }

/* The book at a glance — the Dashboard's own KPI row, borrowed whole. The tab
   strip below already reserves 10px over itself; 16px here wins the collapse
   and matches the gap the cards use, so the row reads as its own band. */
.crm-kpis { margin-bottom: 16px; }

/* -----------------------------------------------------------------------------
   Today — seven cards, and nothing that scrolls

   A card is a question answered by a number, then the top of the list that
   number counts. The list itself is never on the dashboard: clicking a card
   slides it in from the right. That is the whole rule here, and it is what
   keeps the panel to one screen no matter how long any of the lists get.

   Three columns, not four. Four fitted the cards on one screen and then spent
   the saving on ellipses: at a quarter of the page every preview row cut its
   client off mid-name — "2 slabs Calacatta · Elite Ki…" — and a row you cannot
   finish reading is not a preview, it is a hint that you have to click. A third
   of the page carries the longest line any of these cards holds, so the third
   row of cards is the price and it is the right way round.
   -------------------------------------------------------------------------- */
.dgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
/* Six cards fill two rows of three exactly, so the seventh takes the last row
   whole rather than leaving a third of it empty — and two progress bars and an
   outcome line are the one thing here that reads better the wider it gets. */
.dcard--wide { grid-column: 1 / -1; }

/* A tile inside the shell, so it takes the control ground and lets the shell be
   the white one — a white tile on a white panel is a hairline pretending to be a
   box (memory.md §13). */
.dcard {
  display: flex; flex-direction: column; gap: 7px;
  padding: 12px 14px 10px;
  background: var(--color-control);
  border: 1px solid var(--color-control-border); border-radius: 7px;
  font: inherit; text-align: left; text-decoration: none; color: inherit;
  cursor: pointer;
  transition: border-color 120ms, box-shadow 120ms;
}
.dcard:hover { border-color: var(--color-primary); box-shadow: var(--shadow-sm); }
.dcard:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

.dcard__h { display: flex; align-items: center; gap: 8px; }
.dcard__h > svg { flex: none; width: 16px; height: 16px; color: var(--color-primary); }
.dcard__t { font-size: 13px; font-weight: 600; }
.dcard__go { flex: none; width: 15px; height: 15px; margin-left: auto; color: var(--color-text-subtle); }
.dcard:hover .dcard__go { color: var(--color-primary); }

/* Value first, then what it counts, tight — a number pushed to the far side of
   the card stops being read with its own label. */
.dcard__n { display: flex; align-items: baseline; gap: 7px; font-size: 13px; color: var(--color-text-muted); }
.dcard__v { font-size: 22px; font-weight: 700; line-height: 1; color: var(--color-text); }

/* The breakdown under the number is a sentence, not a row of chips. Boxing each
   fragment put three bordered pills in a card that already carries an icon, a
   figure and three preview rows, and once one of them was red and one amber the
   card was mostly decoration. They read as one muted line separated by dots,
   and the emphasis is carried by weight and by a single colour: red, and only
   for the thing that is actually late. */
.dcard__sub { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 7px; font-size: 11px; color: var(--color-text-subtle); }
.dcard__flag { display: inline-flex; align-items: baseline; gap: 7px; }
.dcard__flag + .dcard__flag::before { content: "\00B7"; color: var(--color-text-subtle); opacity: 0.5; }
.dcard__flag--hot  { color: var(--color-danger); font-weight: 600; }
.dcard__flag--warn { color: var(--color-text-muted); font-weight: 600; }

/* Three rows at most, one line each. The preview is there to make the number
   concrete, not to be worked from. */
.dcard__list { display: flex; flex-direction: column; margin-top: 2px; }
.dcard__r { position: relative; display: flex; align-items: center; gap: 8px; min-width: 0; padding: 5px 0; font-size: 12px; }
.dcard__r + .dcard__r::before {
  content: ""; position: absolute; left: 0; top: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.dcard__r .avatar { flex: none; width: 20px; height: 20px; font-size: 9px; }
.dcard__rn { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dcard__w { flex: none; width: 54px; font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
/* Every card annotates its rows the same way — plain text at the right edge.
   To Call used filled badges here and was the only one that did, which is why
   it came out a different colour in every row: amber for a promise, red for a
   delay, green for a delivery. The reason is worth reading; three pills of
   three hues to say it is not. Red survives, for late and nothing else. */
.dcard__c { flex: none; font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
.dcard__c--late { color: var(--color-danger); }
.dcard__r .badge { flex: none; }
.dcard__out { margin-top: 7px; font-size: 11px; line-height: 1.5; color: var(--color-text-subtle); }

/* Pinned to the bottom so six cards of different content still line up. */
.dcard__more { margin-top: auto; padding-top: 4px; font-size: 12px; font-weight: 600; color: var(--color-primary-700); }

/* -----------------------------------------------------------------------------
   The panels the cards open

   Same rows the dashboard previews, at full length, over the top of it. The
   dashboard keeps its scroll position and its shape while you read one.
   -------------------------------------------------------------------------- */
.so-list .slideover-head h2 { margin: 0; font-size: 17px; }
.so-list .slideover-foot { align-items: center; }
.so-list .slideover-foot .muted { font-size: 12px; }
.so-list .slideover-foot .spacer { flex: 1; }

/* -----------------------------------------------------------------------------
   Running out — the only block on the page with a deadline in it

   A hold expires whether or not anybody acts, which is why it is a strip of its
   own above the queue instead of a row inside it. A countdown has to be legible
   without being read, and it must not be able to scroll away under eight calls.
   -------------------------------------------------------------------------- */
.ct-outs { list-style: none; margin: 0; padding: 0; }
.ct-o { position: relative; display: flex; align-items: center; gap: 14px; padding: 11px 0; }
.ct-o:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.ct-o__clock {
  flex: none; width: 84px;
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.ct-o--now .ct-o__clock { color: var(--color-danger); }
.ct-o__t { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.ct-o__n { font-size: 14px; font-weight: 600; }
.ct-o__spec { font-weight: 400; color: var(--color-text-muted); }
.ct-o__w { font-size: 13px; line-height: 1.55; color: var(--color-text-muted); }
.ct-o__w strong { font-weight: 600; color: var(--color-text); }
.ct-o__who {
  padding: 0; border: 0; background: transparent;
  font: inherit; font-weight: 600; color: var(--color-text); cursor: pointer;
}
.ct-o__who:hover { color: var(--color-primary-700); }
.ct-o > .btn { flex: none; }

/* -----------------------------------------------------------------------------
   The call list — the page

   One queue, whatever the reason. A promise, a birthday, a broken buying
   pattern and a lot that landed this morning all arrive as the same shape of
   row, because a rep works a list from the top and does not want four of them.
   The tag says where a row came from; the sentence says what to do about it.
   -------------------------------------------------------------------------- */
.ct-calls { list-style: none; margin: 0; padding: 0; }
.ct-c__row {
  position: relative; display: flex; align-items: flex-start; gap: 12px; width: 100%;
  padding: 12px 0; border: 0; background: transparent; font: inherit;
  text-align: left; text-decoration: none; color: inherit; cursor: pointer;
}
.ct-c:not(:last-child) .ct-c__row::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.ct-c__row .avatar { width: 34px; height: 34px; flex: none; margin-top: 1px; }
.ct-c__t { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.ct-c__top { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; }
.ct-c__n { font-size: 14px; font-weight: 600; }
.ct-c__why { font-size: 13px; line-height: 1.55; color: var(--color-text-muted); }
.ct-c__when { flex: none; padding-top: 2px; font-size: 12px; font-weight: 600; color: var(--color-text-muted); }
.ct-c__when--hot { color: var(--color-danger); }
.ct-c__row:hover .ct-c__n { color: var(--color-primary-700); }

/* -----------------------------------------------------------------------------
   Stock worth a call

   Two halves of one job. What landed this morning is the call nobody would have
   thought to make; what has been in the yard since February is the call somebody
   should have made already. Neither is worth showing without a name against it,
   so the matched clients sit inside the lot rather than a click away from it.
   -------------------------------------------------------------------------- */
.ct-stock { list-style: none; margin: 0; padding: 0; }
.ct-s { position: relative; display: flex; flex-direction: column; gap: 7px; padding: 11px 0; }
.ct-s:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.ct-s__head { display: flex; flex-direction: column; gap: 2px; }
.ct-s__n { font-size: 13px; font-weight: 600; }
.ct-s__spec { font-size: 12px; color: var(--color-text-muted); }
.ct-s__age { font-weight: 600; color: #B45309; }
.ct-s__wants { display: flex; flex-direction: column; gap: 5px; }
/* A control inside a card cannot take the card's own colour. */
.ct-s__c {
  display: flex; flex-direction: column; gap: 1px;
  padding: 6px 9px; border-radius: 5px;
  background: var(--color-control); border: 1px solid var(--color-control-border);
  font: inherit; font-size: 12px; font-weight: 600; color: var(--color-text);
  text-align: left; text-decoration: none; cursor: pointer;
}
.ct-s__c:hover { border-color: var(--color-primary); color: var(--color-primary-700); }
.ct-s__r { font-size: 11px; font-weight: 400; color: var(--color-text-muted); }

/* -----------------------------------------------------------------------------
   While you were out — read-only, and deliberately so. Nothing here is a task;
   it is the overnight movement that explains why the queue is ordered as it is.
   -------------------------------------------------------------------------- */
.ct-feed { list-style: none; margin: 0; padding: 0; }
.ct-f { position: relative; display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; }
.ct-f:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.ct-f__ico {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 7px;
  background: var(--color-control); color: var(--color-text-muted);
}
.ct-f__ico svg { width: 13px; height: 13px; }
.ct-f__t { flex: 1; min-width: 0; font-size: 13px; line-height: 1.5; color: var(--color-text-muted); }
.ct-f__lnk {
  padding: 0; border: 0; background: transparent;
  font: inherit; font-weight: 600; color: var(--color-text);
  text-decoration: none; cursor: pointer;
}
.ct-f__lnk:hover { color: var(--color-primary-700); }
.ct-f__w { flex: none; padding-top: 2px; font-size: 11px; color: var(--color-text-subtle); }

/* -----------------------------------------------------------------------------
   Your week — activity above, what came of it below. Either half on its own is
   misleading: fifty conversations that raised nothing is not a good week. The
   meters sit on the card itself; this is the one card with no list behind it.
   -------------------------------------------------------------------------- */
/* Terse label, because the meters sit on a card a third of the page wide. */
.ct-p { display: grid; grid-template-columns: 40px minmax(0, 1fr) 52px; align-items: center; gap: 10px; }
.ct-p + .ct-p { margin-top: 8px; }
.ct-p__k { font-size: 12px; color: var(--color-text-muted); }
.ct-p__t { height: 7px; border-radius: 7px; background: var(--color-control); overflow: hidden; }
.ct-p__t > span { display: block; height: 100%; border-radius: 7px; background: var(--color-primary); }
.ct-p__t--low > span { background: var(--color-warn); }
.ct-p__v { font-size: 12px; font-weight: 600; text-align: right; }

/* The rest of CRM. A dashboard that carries a navigation card has given a
   quarter of itself to something nobody reads twice, so these are a footer. */
.ct-else {
  display: flex; align-items: center; flex-wrap: wrap; gap: 9px 16px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--color-border);
}
.ct-else__l {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--color-text-subtle);
}
.ct-else__a {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--color-text-muted); text-decoration: none;
}
.ct-else__a svg { width: 14px; height: 14px; color: var(--color-primary); }
.ct-else__a:hover { color: var(--color-primary-700); }

/* -----------------------------------------------------------------------------
   Notes — what the team wrote down, across the whole book

   The panel reads and never writes, so every client on it is a way out: the
   name is the link, and the note underneath is what somebody wanted the next
   person to know before they picked up the phone.
   -------------------------------------------------------------------------- */
.ct-notes { list-style: none; margin: 0; padding: 0; }
.ct-n { position: relative; display: flex; flex-direction: column; gap: 5px; padding: 11px 0; }
.ct-n:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.ct-n__head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.ct-n__head .avatar { flex: none; width: 24px; height: 24px; font-size: 10px; }
.ct-n__who { font-size: 13px; font-weight: 600; }
.ct-n__c {
  padding: 0; border: 0; background: transparent;
  font: inherit; font-size: 12px; font-weight: 600;
  color: var(--color-primary-700); text-decoration: none; cursor: pointer;
}
.ct-n__c:hover { color: var(--color-primary); }
.ct-n__w { margin-left: auto; flex: none; font-size: 11px; color: var(--color-text-subtle); }
.ct-n__t { font-size: 13px; line-height: 1.55; color: var(--color-text-muted); }

/* ---- table column bounds — generated, see changes/ ----
   The Tasks and Client Activity grids arrived with the tabs they sit in, so
   their pins travel with them. A pin for a table that is not on the page is a
   rule nobody can see is wrong. */
#tbl-flex-2 { table-layout: auto; }
#tbl-flex-2 .col-flex { width: 100%; }   /* Task takes the remainder */
/* Header pins stay scoped to `thead th`: under `table-layout: auto` a width on a
   <td> joins the same column's constraint set as the <th>. */
#tbl-flex-2 thead th.col-who { width: 113px; min-width: 113px; max-width: 113px; }   /* Owner: pinned */
#tbl-flex-2 thead th.col-client { width: 185px; min-width: 185px; max-width: 185px; }   /* Client: pinned */
#tbl-flex-2 thead th.col-due { width: 66px; min-width: 66px; max-width: 66px; }   /* Due: pinned */
#tbl-flex-2 thead th.col-actions { width: 124px; min-width: 124px; max-width: 124px; }   /* Mark done: pinned */
/* The button is the widest thing in its column, so the column is sized to it and
   the row height does not move when a task is done and the label gets shorter. */
#tbl-flex-2 tbody td.col-actions .btn { white-space: nowrap; }
#tbl-flex-2 thead th.col-status { width: auto; min-width: 99px; }   /* Status: 99 → 141 */
#tbl-flex-2 tbody td.col-status > * { width: max-content; max-width: 117px; }

#tbl-flex-3 { table-layout: auto; }
#tbl-flex-3 .col-flex { width: 100%; }   /* Action takes the remainder */
#tbl-flex-3 thead th.col-when { width: 77px; min-width: 77px; max-width: 77px; }   /* When: pinned */
#tbl-flex-3 thead th.col-who { width: 116px; min-width: 116px; max-width: 116px; }   /* By: pinned */
#tbl-flex-3 thead th.col-client { width: 173px; min-width: 173px; max-width: 173px; }   /* Client: pinned */

.cd-link__who {
  padding: 1px 6px; border-radius: 5px;
  background: var(--color-surface-alt); border: 1px solid var(--color-border);
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--color-text-subtle);
}


/* -----------------------------------------------------------------------------
   Who this is

   Three rows above the cards and none of them a card: identity, then the
   numbers, then what is live. Together they are the five-second read the page
   was built for, and none of them costs a click.
   -------------------------------------------------------------------------- */
.cd-hero {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) auto;
  gap: 3px 14px; align-items: center;
  margin-bottom: 10px;
}
.cd-hero__avatar { width: 52px; height: 52px; font-size: 18px; grid-row: span 2; }
.cd-hero__name { margin: 0; font-size: 21px; line-height: 1.15; }
.cd-hero__meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 3px 0 0; }
.cd-hero__metatext { font-size: 12px; color: var(--color-text-muted); }
.cd-hero__do { grid-row: span 2; display: flex; gap: 8px; flex-wrap: wrap; }

/* The contact line. One row, because a rep needs the number, not a directory —
   the label each channel came with rides along as its tooltip. */
.cd-hero__reach {
  grid-column: 2; margin: 0;
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 16px;
  font-size: 13px; color: var(--color-text-muted);
}
.cd-reach { display: inline-flex; align-items: center; gap: 6px; }
.cd-reach > svg { width: 14px; height: 14px; flex: none; color: var(--color-primary); }
.cd-reach--who { color: var(--color-text); }
.cd-reach--who strong { font-weight: 600; }

/* The numbers, birthday first. A date of birth is a fact a rep should not have
   to open anything to see, so it leads the row and turns red on the day. */
.cd-facts {
  display: flex; align-items: center; flex-wrap: wrap;
  padding: 10px 15px; margin-bottom: 8px;
  background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: 7px;
}
.cd-facts .cd-stat,
.cd-fact { padding: 0 16px; border-right: 1px solid var(--color-border-strong); }
.cd-facts > :first-child { padding-left: 0; }
.cd-facts > :last-child { border-right: 0; padding-right: 0; }

.cd-stat { display: inline-flex; align-items: baseline; gap: 6px; }
.cd-stat__v { font-size: 17px; font-weight: 700; color: var(--color-primary-700); }
.cd-stat__l { font-size: 13px; color: var(--color-text-muted); }

.cd-fact {
  display: inline-flex; align-items: baseline; gap: 6px;
  border-top: 0; border-bottom: 0; border-left: 0;
  background: transparent; font: inherit; cursor: pointer;
}
.cd-fact > svg { width: 15px; height: 15px; align-self: center; color: var(--color-primary); }
.cd-fact:hover .cd-stat__v, .cd-fact:hover .cd-stat__l { color: var(--color-primary); }
.cd-fact--bday.is-hot > svg { color: var(--color-danger); }
.cd-fact--bday.is-hot .cd-stat__v { color: var(--color-danger); }
.cd-fact--bday.is-hot .cd-stat__l { color: var(--color-danger); font-weight: 600; }
.cd-fact--gap > svg,
.cd-fact--gap .cd-stat__l { color: var(--color-text-subtle); }
.cd-fact--gap:hover .cd-stat__l { color: var(--color-primary); }

/* -----------------------------------------------------------------------------
   What is live right now

   One fact per chip and no advice in any of them. A birthday is a date, a
   ceiling is a number, and "never polished" is something the client said — all
   three are checkable. What to open with is not, so the page does not say.

   Every chip opens the card that owns the data behind it, which is why there is
   no body text: the explanation is one click away in the place it belongs.
   -------------------------------------------------------------------------- */
.cd-sig { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-bottom: 12px; }
.cd-sig__c {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px; border-radius: 7px;
  background: var(--color-control); border: 1px solid var(--color-control-border);
  font: inherit; font-size: 12px; font-weight: 600; color: var(--color-text);
  cursor: pointer;
}
.cd-sig__c > svg { width: 14px; height: 14px; flex: none; }
.cd-sig__c:hover { border-color: var(--color-primary); }
.cd-sig__c--hot     { background: var(--color-danger-50);  border-color: #FECACA; color: #B91C1C; }
.cd-sig__c--warm    { background: var(--color-warn-50);    border-color: #FDE68A; color: #B45309; }
.cd-sig__c--info    { background: var(--color-primary-50); border-color: #D6E2FA; color: var(--color-primary-700); }
/* A caution is a constraint, not an alarm — it reads as a rule, in grey. */
.cd-sig__c--careful { background: var(--color-surface-alt); border-color: var(--color-border-strong); color: var(--color-text-muted); }
.cd-sig__c--hot:hover, .cd-sig__c--warm:hover,
.cd-sig__c--info:hover, .cd-sig__c--careful:hover { border-color: currentColor; }

/* -----------------------------------------------------------------------------
   Likes and doesn't like — one column inside its panel, not two side by side
   -------------------------------------------------------------------------- */
.cd-taste__h {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin-bottom: 9px;
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
}
.cd-taste__h svg { width: 14px; height: 14px; }
.cd-taste__h--like { color: var(--color-success); }
.cd-taste__h--dislike { color: var(--color-danger); }
.crm-hardex {
  font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: none;
  color: #B91C1C; background: var(--color-danger-50); border-radius: 5px; padding: 1px 5px;
}

/* -----------------------------------------------------------------------------
   Bits the panels share
   -------------------------------------------------------------------------- */
.cd-sub-h {
  display: flex; align-items: center; gap: 7px;
  margin: 0 0 8px; font-size: 13px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted);
}
.cd-sub-h svg { width: 14px; height: 14px; color: var(--color-primary); }
.crm-note { margin: 0; font-size: 13px; line-height: 1.6; color: var(--color-text-muted); }
.crm-foot-ico { width: 13px; height: 13px; vertical-align: -2px; }

/* -----------------------------------------------------------------------------
   Who you are talking to
   -------------------------------------------------------------------------- */
.cd-people { display: flex; flex-direction: column; }
.cd-person {
  position: relative; display: flex; gap: 12px; padding: 12px 0;
}
.cd-person:first-child { padding-top: 0; }
.cd-person:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.cd-person .avatar { width: 38px; height: 38px; flex: none; }
.cd-person__t { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cd-person__top { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.cd-person__name { font-size: 14px; font-weight: 700; }
.cd-person__role { font-size: 12px; color: var(--color-text-muted); }
.cd-person__dob {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  padding: 2px 8px; border-radius: 7px;
  background: var(--color-warn-50); color: #92400E; font-size: 12px;
}
.cd-person__dob { font-size: 13px; }
.cd-person__dob svg { width: 14px; height: 14px; }
.cd-person__dob--gap { background: var(--color-surface-alt); color: var(--color-text-subtle); }
.cd-person__reach { font-size: 13px; color: var(--color-text-muted); }
.cd-person__note { font-size: 14px; line-height: 1.6; }

.cd-personal { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cd-personal li {
  position: relative; padding: 9px 0 9px 20px;
  font-size: 14px; line-height: 1.6;
}
.cd-personal li::before {
  content: ""; position: absolute; left: 6px; top: 15px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--color-primary);
}
.cd-personal li:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}

.cd-pref {
  display: flex; flex-direction: column; gap: 5px;
  padding: 11px 13px; border-radius: 7px;
  background: var(--color-control); border: 1px solid var(--color-control-border);
  border-left: 3px solid var(--color-success);
}
.cd-pref--dislike { border-left-color: var(--color-danger); }
.cd-pref__top { display: flex; align-items: center; gap: 10px; }
.cd-pref__what { font-size: 14px; font-weight: 700; }
.cd-pref__why { font-size: 13px; line-height: 1.55; color: var(--color-text-muted); }
/* Provenance is a footnote, not a heading — it was shouting in caps. */
.cd-pref__src { font-size: 11px; color: var(--color-text-subtle); }

/* Strength, 1 to 5 — the unset marks stay hollow. */
.crm-str { display: inline-flex; gap: 3px; flex: none; }
.crm-str i { width: 8px; height: 8px; border-radius: 50%; background: var(--color-success); display: inline-block; }
.crm-str i.off { background: transparent; box-shadow: inset 0 0 0 1px var(--color-border-strong); }
.cd-pref--dislike .crm-str i { background: var(--color-danger); }
.cd-pref--dislike .crm-str i.off { background: transparent; }

/* -----------------------------------------------------------------------------
   What they keep looking at
   -------------------------------------------------------------------------- */
.cd-looks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cd-look {
  position: relative; display: grid;
  grid-template-columns: 28px minmax(0, 1fr); gap: 4px 10px; align-items: start;
  padding: 10px 0;
}
.cd-look:first-child { padding-top: 0; }
.cd-look:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.cd-look__ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 7px;
  background: var(--color-primary-50); color: var(--color-primary-700);
}
.cd-look__ico svg { width: 14px; height: 14px; }
.cd-look__t { font-size: 14px; line-height: 1.55; }
/* Auto-placement would drop the meta line into the 28px icon column on row 2. */
.cd-look__meta { grid-column: 2; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cd-look__tag {
  flex: none; padding: 2px 7px; border-radius: 5px;
  background: var(--color-surface-alt); border: 1px solid var(--color-border);
  font-size: 11px; color: var(--color-text-muted); white-space: nowrap;
}
.cd-look__when { flex: none; font-size: 11px; color: var(--color-text-subtle); white-space: nowrap; }

/* -----------------------------------------------------------------------------
   Last conversations
   -------------------------------------------------------------------------- */
.cd-talks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cd-talk { position: relative; display: flex; flex-direction: column; gap: 4px; padding: 11px 0; }
.cd-talk:first-child { padding-top: 0; }
.cd-talk:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.cd-talk__head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.cd-talk__when { font-size: 13px; font-weight: 700; }
.cd-talk__kind {
  padding: 1px 7px; border-radius: 5px;
  background: var(--color-surface-alt); border: 1px solid var(--color-border);
  font-size: 11px; color: var(--color-text-muted);
}
.cd-talk__who { font-size: 11px; color: var(--color-text-subtle); }
.cd-talk__text { font-size: 14px; line-height: 1.6; }
.cd-talk__follow {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  padding: 3px 8px; border-radius: 7px;
  background: var(--color-warn-50); color: #92400E; font-size: 11px; font-weight: 600;
}
.cd-talk__follow svg { width: 13px; height: 13px; }

.cd-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.cd-dot--good { background: var(--color-success); }
.cd-dot--neutral { background: var(--color-text-subtle); }
.cd-dot--bad { background: var(--color-danger); }
.cd-dot--none { background: transparent; box-shadow: inset 0 0 0 1px var(--color-border-strong); }

/* -----------------------------------------------------------------------------
   What they have paid
   -------------------------------------------------------------------------- */
.crm-layer--gated {
  display: inline-flex; align-items: center; gap: 6px; flex: none; align-self: flex-start;
  padding: 4px 9px; border-radius: 7px;
  background: var(--color-warn-50); color: #B45309;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
}
.crm-layer--gated svg { width: 13px; height: 13px; }
.crm-masked { color: var(--color-text-subtle); }
.crm-above { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--color-text-subtle); }
.crm-above svg { width: 12px; height: 12px; }
.crm-row--masked td { background: var(--color-surface-alt); }

.cd-tbl-prices .col-date { width: 13%; }
.cd-tbl-prices .col-mat  { width: 36%; }
.cd-tbl-prices .col-qty  { width: 12%; }
.cd-tbl-prices .col-list { width: 11%; }
.cd-tbl-prices .col-paid { width: 11%; }
.cd-tbl-prices .col-disc { width: 17%; }

/* -----------------------------------------------------------------------------
   Dates that matter
   -------------------------------------------------------------------------- */
.cd-dates { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cd-date {
  position: relative; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 10px 0;
}
.cd-date:first-child { padding-top: 0; }
.cd-date:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.cd-date__l { font-size: 14px; font-weight: 600; }
.cd-date__w { font-size: 13px; color: var(--color-text-muted); }
.cd-date__d {
  margin-left: auto; flex: none;
  font-size: 11px; font-weight: 600; color: var(--color-text-subtle); white-space: nowrap;
}
.cd-date--hot .cd-date__d {
  padding: 2px 8px; border-radius: 7px;
  background: var(--color-danger-50); color: #B91C1C;
}
.cd-date--gap .cd-date__l { color: var(--color-text-subtle); font-weight: 500; }
.cd-date__add {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 0; border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: 11px; color: var(--color-primary-700);
}
.cd-date__add:hover { color: var(--color-primary); font-weight: 600; }
.cd-date__add svg { width: 12px; height: 12px; }

/* -----------------------------------------------------------------------------
   What they buy
   -------------------------------------------------------------------------- */
.cd-bars { display: flex; flex-direction: column; gap: 7px; }
.cd-bar { display: grid; grid-template-columns: minmax(0, 96px) 1fr 38px; gap: 10px; align-items: center; }
.cd-bar__k { font-size: 13px; color: var(--color-text); }
.cd-bar__t { height: 7px; border-radius: 5px; background: var(--color-surface-alt); overflow: hidden; }
.cd-bar__t > span { display: block; height: 100%; background: var(--color-primary); border-radius: 5px; }
.cd-bar__p { font-size: 11px; color: var(--color-text-muted); text-align: right; }

.cd-stats { display: flex; flex-direction: column; gap: 8px; }
.cd-stats .cd-stat { align-items: baseline; }
.cd-stats .cd-stat__l { line-height: 1.45; }

.cd-tentative {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 12px; padding: 10px 12px; border-radius: 7px;
  background: var(--color-warn-50); border: 1px solid #FDE68A;
  font-size: 13px; line-height: 1.55; color: #92400E;
}
.cd-tentative svg { width: 15px; height: 15px; flex: none; margin-top: 1px; }

/* The honest empty state: no pattern is claimed, the orders are simply shown. */
.cd-thin {
  display: flex; align-items: flex-start; gap: 9px;
  margin-bottom: 12px; padding: 12px 13px; border-radius: 7px;
  background: var(--color-surface-alt); border: 1px dashed var(--color-border-strong);
  font-size: 13px; line-height: 1.6; color: var(--color-text-muted);
}
.cd-thin svg { width: 16px; height: 16px; flex: none; margin-top: 1px; }

.cd-raw { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cd-raw li {
  position: relative; display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  padding: 9px 0; font-size: 12px;
}
.cd-raw li:not(:last-child)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 50%; height: 1px; background: var(--color-border-strong);
}
.cd-raw__d { font-weight: 600; }
.cd-raw__v { text-align: right; font-weight: 600; }
.cd-raw__m { grid-column: 1 / -1; color: var(--color-text-muted); }
.cd-raw__q { grid-column: 1 / -1; color: var(--color-text-subtle); font-size: 11px; }

/* -----------------------------------------------------------------------------
   What we have for them
   -------------------------------------------------------------------------- */
.cd-offers { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.cd-offer {
  display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 12px; align-items: start;
  padding: 11px 12px; border-radius: 7px;
  background: var(--color-surface); border: 1px solid var(--color-border);
}
.cd-offer--out { background: var(--color-surface-alt); border-style: dashed; }
.cd-offer__score { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.cd-offer__score svg { width: 17px; height: 17px; color: var(--color-danger); }
.cd-offer__num { font-size: 18px; font-weight: 700; color: var(--color-primary-700); }
.cd-offer__meter { display: block; width: 100%; height: 5px; border-radius: 5px; background: var(--color-surface-alt); overflow: hidden; }
.cd-offer__meter > span { display: block; height: 100%; background: var(--color-primary); border-radius: 5px; }
.cd-offer__t { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cd-offer__name { font-size: 14px; font-weight: 700; }
.cd-offer__why { font-size: 13px; line-height: 1.55; color: var(--color-text-muted); }
.cd-offer__avail { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--color-text-subtle); }

/* -----------------------------------------------------------------------------
   Bits borrowed by the cards
   -------------------------------------------------------------------------- */
/* The add control lives in the card header when the card is a list rather than
   a page with its own toolbar. */
.add-row-btn {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 24px; height: 24px;
  border: 0; border-radius: 5px; cursor: pointer;
  background: var(--color-primary); color: #fff;
}
.add-row-btn:hover { background: var(--color-primary-600); }
.add-row-btn svg { width: 15px; height: 15px; stroke-width: 2.6; }

/* =============================================================================
   Responsive
   ========================================================================== */
@media (max-width: 1200px) {
  /* Two, for the same reason the base row is three: a third of this width is
     back under the length of a client's name. */
  .dgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  /* The actions drop under the identity rather than squeezing the name. */
  .cd-hero { grid-template-columns: 52px minmax(0, 1fr); }
  .cd-hero__do { grid-column: 2; grid-row: auto; margin-top: 6px; }
  /* The board stops being one row here, so a full-height column stops being a
     column and becomes a screen of its own. Each one keeps a ceiling instead
     and scrolls under it — five of these stacked is a page, not a board. */
  .wm-col { height: auto; max-height: 340px; }
}

@media (max-width: 768px) {
  .cs { max-width: none; }
  .ct-find .cs { flex-basis: 100%; max-width: none; }
  .dgrid { grid-template-columns: minmax(0, 1fr); }
  .dcard--wide { grid-column: auto; }
  .cd-hero { grid-template-columns: minmax(0, 1fr); }
  .cd-hero__avatar { display: none; }
  .cd-hero__reach,
  .cd-hero__do { grid-column: 1; }
  .cd-hero__do .btn { flex: 1; justify-content: center; }
  .cd-hero__name { font-size: 19px; }
  .page .card-header { flex-wrap: wrap; gap: 10px; }
  .cd-bar { grid-template-columns: minmax(0, 88px) 1fr 34px; }
  /* The countdown keeps its own line and the action goes beside it, so a
     three-line reason never squeezes the row it belongs to. */
  .ct-o { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 12px; }
  .ct-o__clock { grid-column: 1; grid-row: 1; width: auto; }
  .ct-o > .btn { grid-column: 2; grid-row: 1; }
  .ct-o__t { grid-column: 1 / -1; grid-row: 2; }
  /* Touch targets — nothing tappable drops under 44px on a phone. */
  .page .btn,
  .page .fchip,
  .cs__row,
  .ct-s__c,
  .cd-sig__c,
  .ct-recent__chip { min-height: 44px; }
  .add-row-btn { width: 44px; height: 44px; }
  .cs__input { padding: 15px 0; }
}

@media (max-width: 480px) {
  /* The fact row stacks; the dividers between the numbers go with it. */
  .cd-facts { flex-direction: column; align-items: flex-start; gap: 9px; }
  .cd-facts .cd-stat,
  .cd-fact { padding: 0; border-right: 0; }
  .cd-stat__v { font-size: 16px; }
  .cd-person .avatar { display: none; }
  .ct-c__row .avatar { display: none; }
  .cd-offer { grid-template-columns: 38px minmax(0, 1fr); gap: 10px; }
}

/* =============================================================================
   Slide-overs

   Every dialog in this module is a panel. A dialog is a box that has to justify
   its height before it has said anything; a panel has the room, so a form can
   breathe and a list can be the length it is.
   ========================================================================== */
/* One width for the module, forms and lists alike — opening a list and then a
   form should not move the edge of the panel. */
.so-list .slideover { width: min(640px, 100%); }
/* The walkthrough is the one panel sized by its content rather than its form. */
.so-video .slideover { width: min(880px, 100%); }
.so-video .video-embed { margin: 0; }
/* A note under a form row is the row's own footnote, not the next row — it takes
   less than the 14px between rows, and more than nothing. */
.slideover-body :is(.field, .field-grid, .form-row, .fchips) + .crm-note { margin-top: 12px; }
/* Remember This swaps a whole group of fields in under the chips. The group is a
   plain div, so it is not a `.field` and the stacked rhythm above misses it. */
.slideover-body :is(.field, .field-grid, .form-row) + [data-rem-group] { margin-top: 14px; }

/* =============================================================================
   Warmth — the five buckets a relationship moves through

   A column is 233px wide at 1440, so the client name is the one thing on the
   board that can decide a row's height. Left alone it does: "Marble & Co.
   Design Studio" wraps to three lines there, takes the row from 21px to 71px,
   and drags every row under it out of line with the four columns beside it.
   The name is therefore one line and clips; the whole name is in the title.
   ========================================================================== */
/* The temperature runs left to right: grey for a client with no reading yet,
   blue once somebody has reached out, amber as they start answering, green when
   they are buying. Green rather than the hot orange the ramp would otherwise
   end on, because Active is the healthy state and green is what says so
   everywhere else in the portal — the flame beside it is what still carries the
   heat. Dormant is not the cold end of that ramp: it is a client who was warm
   and went out, so it sits outside the run in ice, with a frosted edge and a
   snowflake rather than a fifth step.

   Every hue is mixed against `--color-surface` rather than hard-coded as a
   tint, so the board holds up on the evening theme without a second palette.
   Colour is never the only carrier: each column states its temperature with an
   icon as well. */
.wm-col { --wm: var(--wm-new); position: relative; overflow: hidden; }
.wm-col--new       { --wm: var(--wm-new); }   /* no reading yet */
.wm-col--contacted { --wm: var(--wm-contacted); }   /* cool, but alive */
.wm-col--engaged   { --wm: var(--wm-engaged); }   /* warming */
.wm-col--active    { --wm: var(--wm-active); }   /* hot, and healthy */
.wm-col--dormant   { --wm: var(--wm-dormant); }   /* frozen */

/* The strip along the top edge is the reading itself. */
.wm-col::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 3px;
  background: var(--wm);
}
/* Frost, not a solid bar — the one column that is a state rather than a step. */
.wm-col--dormant::before {
  background: repeating-linear-gradient(90deg, var(--wm) 0 5px, transparent 5px 9px);
}

/* The lighting: a tint that falls off down the header, and a shadow carrying the
   column's own hue so a warm card sits on warm ground. */
.wm-col .card-header {
  background: linear-gradient(to bottom,
    color-mix(in oklab, var(--wm) 13%, var(--color-surface)), var(--color-surface));
  border-bottom-color: color-mix(in oklab, var(--wm) 22%, var(--color-border));
}
.wm-col {
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05),
              0 12px 22px -13px color-mix(in oklab, var(--wm) 85%, transparent);
}
/* Dormant reads through the whole card, not just its edge: a client who went
   out is a different state from a client who has not warmed up yet, and the two
   sit at opposite ends of a row of five. */
/* The board is three deep — shell, column, client — so the middle one carries
   the ground and the two either side of it stay light. Dormant is the one
   column that reads through, so its own tint is mixed over that ground rather
   than over the white it used to sit on. */
.wm-col { background: var(--color-control); }
.wm-col--dormant { background: color-mix(in oklab, var(--wm) 9%, var(--color-control)); }
.wm-col--dormant .wm-card__n { color: var(--color-text-muted); }
.wm-col .card-header h3 { display: flex; align-items: center; gap: 7px; }
.wm-col .card-header h3 svg { width: 15px; height: 15px; flex: none; color: var(--wm); }

/* The count reads as part of the temperature, so it takes the hue too. The ink
   is mixed 45/55 towards the theme's own text colour rather than sitting on the
   hue: at 72% the pale end of the ramp — the ice of Dormant — went unreadable on
   its own tint. Mixing towards `--color-text` rather than a fixed near-black is
   what makes it darken on the light theme and lighten on evening. */
.wm-col__n {
  padding: 1px 8px; border-radius: 7px;
  font-size: 12px; font-weight: 700;
  background: color-mix(in oklab, var(--wm) 18%, var(--color-surface));
  border: 1px solid color-mix(in oklab, var(--wm) 38%, transparent);
  color: color-mix(in oklab, var(--wm) 45%, var(--color-text));
}

/* A column is a column, not a box that stops at its last name. All five run to
   the same depth — down the screen rather than down to the shortest list — so
   the five are read against each other: the space under New's eighth name is
   the reading, and it only says anything while Active is the same height.

   The depth is the screen's, less the chrome above the board (header, page
   title, search, KPI row, tab strip). The 420px floor is what keeps a laptop in
   a browser window from collapsing the board back into the boxes it replaced. */
.wm-col {
  display: flex; flex-direction: column;
  height: max(420px, calc(100vh - 340px));
}
.wm-col .card-header { flex: none; }

/* Only Active outruns the height at 46 names. The scroll sits on the list, not
   on the card, so the header, the count and the temperature strip hold still
   while the names move under them.

   The gap is what makes a client a THING you can pick up rather than a line in
   a list: eight pixels is enough to read each box as separate and not so much
   that a column of eight stops being a column. The list keeps a floor under it
   so a column emptied by dragging is still somewhere you can drop. */
.wm-list {
  display: flex; flex-direction: column; gap: 8px;
  flex: 1 1 auto; min-height: 60px; overflow-y: auto;
}

/* ---------- A client, as a thing you can move ----------------------------
   The column is the card's ground, so the box on it takes the control colour
   rather than the surface it is sitting on — a white box on a white panel is
   not a box. The border is the control's own, which is what carries the
   separation on the evening theme where the two grounds sit closer. */
/* The column is the tinted one now, so the client on it goes the other way up —
   the inversion memory.md §13 allows, and the same separation as before read
   from the other side. */
.wm-card {
  display: flex; align-items: flex-start; gap: 6px;
  min-width: 0; padding: 6px 8px;
  border: 1px solid color-mix(in oklab, var(--color-control-border) 45%, transparent);
  border-radius: 7px;
  background: var(--color-surface);
  cursor: grab;
}
/* Picking a card lifts it TOWARDS the primary, not towards white. White was
   the wrong direction: the column behind it is already white, so the card that
   was being pointed at was the one that disappeared into its own ground. A
   blue tint is a step away from both the card's resting grey and the column,
   and it is the same lift every other pickable row in the portal takes. */
.wm-card:hover {
  border-color: color-mix(in oklab, var(--wm) 55%, var(--color-control-border));
  background: color-mix(in oklab, var(--color-primary) 18%, var(--color-surface));
}
/* The card being carried stays in place and goes quiet, so the column it came
   from still reads while the cursor is somewhere else. */
.wm-card.is-dragging { opacity: 0.4; cursor: grabbing; }

/* The grip says the box can be picked up. It is not the only way to pick one
   up — the whole card drags — so it stays quiet until the cursor is on the
   card that owns it. */
.wm-card__grip { display: inline-flex; flex: none; padding-top: 1px; color: var(--color-border-strong); }
.wm-card__grip svg { width: 13px; height: 13px; }
.wm-card:hover .wm-card__grip { color: var(--color-text-subtle); }

.wm-card__t { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* The name absorbs the clipping and the qualifier does not: "Dallas" truncated
   to "Da..." tells nobody anything, while a clipped company name is still read
   from its first three words. */
.wm-card__n,
.wm-card__q { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wm-card__n { font-size: 13px; font-weight: 500; color: var(--color-text); text-decoration: none; }
.wm-card__q { font-size: 11px; color: var(--color-text-subtle); }
.wm-card:hover .wm-card__n { color: var(--color-primary-700); }

/* The column a card is over answers in its own colour, so where it will land is
   read off the board rather than off the cursor. */
.wm-list.is-over {
  outline: 2px dashed color-mix(in oklab, var(--wm) 60%, transparent);
  outline-offset: -4px;
  border-radius: 7px;
}


/* ===========================================================================
   THE CLIENTS TAB
   The book itself, one row per client, behind the day. The bands and the
   two switches are the Clients page's own, ported rather than shared: both
   pages are up while the move is under way, and a rule reaching across to a
   stylesheet the other page owns is a rule that breaks when that page goes.
   =========================================================================== */

/* Fluid shares. Client and Next Action carry the words, so they take the
   width; the three short columns hold their proportion beside them. */
#tbl-crm-clients thead th.col-client { width: 29%; }
#tbl-crm-clients thead th.col-warmth { width: 12%; }
#tbl-crm-clients thead th.col-lastc  { width: 11%; }
#tbl-crm-clients thead th.col-next   { width: 32%; }
#tbl-crm-clients thead th.col-otasks { width: 16%; }

/* Last column, so it banks right — and its right padding is the left padding
   of the first, which app.css already sets on the last cell. */
#tbl-crm-clients .col-otasks { text-align: right; white-space: nowrap; }
#tbl-crm-clients .col-lastc { white-space: nowrap; }

/* ---------- Warmth, in the Warmth tab's own colours ----------------------
   The same five words that head the five columns one tab across, so a client
   read here and a client read there are plainly the same reading. Pale ground,
   not a filled chip: five of them running down a column is a wall of colour,
   and the word is what is being read. */
.cl-warm {
  --wm: var(--wm-new);
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 7px;
  background: color-mix(in oklab, var(--wm) 13%, var(--color-surface));
  font-size: 11px; font-weight: 500; color: var(--color-text);
}
.cl-warm::before {
  content: ''; width: 6px; height: 6px; flex: none;
  border-radius: 50%; background: var(--wm);
}
.cl-warm--new       { --wm: var(--wm-new); }
.cl-warm--contacted { --wm: var(--wm-contacted); }
.cl-warm--engaged   { --wm: var(--wm-engaged); }
.cl-warm--active    { --wm: var(--wm-active); }
.cl-warm--dormant   { --wm: var(--wm-dormant); }

/* ---------- The next thing owed ------------------------------------------
   The task and the day it is due, stacked: the day is a note on the task, not
   a column of its own, and a client with nothing owed says so in words rather
   than leaving the cell to be read as missing data. */
.cl-next {
  display: block; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px;
}
.cl-next--none { color: var(--color-text-subtle); }
.cl-next__d { display: block; margin-top: 2px; font-size: 11px; color: var(--color-text-muted); }
.cl-next__d--late { color: var(--color-danger); }

/* ---------- The salesperson's band ---------------------------------------
   The rep stated once with their clients stepping in under it. The gap lives
   ABOVE the band and takes the page's own colour rather than the band's: grey
   space above a band only makes the band taller, white space separates. */
#tbl-crm-clients tbody tr.rep-band > td {
  padding: 16px 0 0;
  text-align: left;
  background: transparent;
  border-top: 0;
}
/* The band's own ground closes the row above it; the per-cell mark would be a
   second boundary drawn a pixel away from this one. */
#tbl-crm-clients tbody tr.rep-band > td::after { content: none; }
#tbl-crm-clients tbody tr.rep-band:hover { background: transparent; }
/* The first band opens the table — there is no previous rep to be parted from,
   and the header's own edge is already the line above it. */
#tbl-crm-clients tbody tr.rep-band:first-child > td { padding-top: 0; }
#tbl-crm-clients tbody tr.rep-band:first-child .rep-band__btn { border-top: 0; }
/* The first client is pulled up against its band. A band that only pushed the
   next rep away would leave its own clients no nearer than before. */
#tbl-crm-clients tbody tr.rep-band + tr.client-row > td { padding-top: 4px; }
/* The last row of a band carries no mark: the next band's own full-width
   border already closes it. */
#tbl-crm-clients tbody tr:has(+ tr.rep-band) > td::after { content: none; }

#tbl-crm-clients .rep-band__btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px var(--table-pad-x);
  border: 0; border-top: 1px solid var(--color-border);
  background: var(--color-surface-alt);
  cursor: pointer; font: inherit; text-align: left;
}
#tbl-crm-clients .rep-band__btn svg {
  width: 15px; height: 15px; flex: 0 0 auto;
  color: var(--color-text-subtle); transition: transform 120ms;
}
#tbl-crm-clients .rep-band__btn[aria-expanded="true"] svg { transform: rotate(90deg); }
#tbl-crm-clients .rep-band__name { font-size: 13px; font-weight: 600; color: var(--color-text); }
#tbl-crm-clients .rep-band__btn:hover .rep-band__name { color: var(--color-primary-700); }
/* The count belongs to the name it follows — number first, word after, no gap
   for the eye to cross. */
#tbl-crm-clients .rep-band__count { font-size: 11px; color: var(--color-text-muted); }
#tbl-crm-clients .rep-band__count strong {
  font-weight: 600; color: var(--color-text); font-variant-numeric: tabular-nums;
}
#tbl-crm-clients .rep-band--none .rep-band__name { font-weight: 500; color: var(--color-text-muted); }

/* Inside the band the client steps in — the indent is what says the row
   belongs to the band above it. */
#tbl-crm-clients tbody tr.client-row > td:first-child { padding-left: 30px; }

/* ---------- By Rep off: the rep under the client -------------------------
   The same list read the other way. The bands step aside and the rep follows
   the client down into their own cell, a third line under the name and the
   town — smaller than either, because it answers a question you only ask about
   a client you have already found. It stays out of sight while the bands are
   up: a line repeating the band above it is what the band replaced. */
#tbl-crm-clients .row-rep { display: none; font-size: 10px; color: var(--color-text-subtle); }
#tbl-crm-clients.is-flat .row-rep { display: block; }
#tbl-crm-clients.is-flat tbody tr.rep-band { display: none; }
#tbl-crm-clients.is-flat tbody tr.client-row > td:first-child { padding-left: var(--table-pad-x); }
#tbl-crm-clients.is-flat tbody tr.rep-band + tr.client-row > td { padding-top: 10px; }
/* With no band between them, the client above another client is simply the row
   above, and gets its mark back. */
#tbl-crm-clients.is-flat tbody tr:has(+ tr.rep-band) > td::after { content: ''; }

/* All Open belongs to the bands, so with the bands gone it has nothing left to
   open — but it goes invisible, not away, or the controls beside it jump under
   the cursor on a toggle that was never about them. */
[data-tab-panel="clist"] .toolbar .switch-field.is-vacant { visibility: hidden; }


/* ===========================================================================
   PAGE SETTINGS DIALOGS
   The two company rules about clients and the list of types they can be,
   moved here off the Clients page with the list they govern.
   =========================================================================== */

/* ---------- Client Visibility / Sales Rep Assigning ----------------------
   `.vis-pick` and its parts moved to `css/app.css` when Quotes took the
   same picker for its own visibility rule — one pattern, two callers, so it
   stops being a CRM detail. Nothing page-specific was left behind. */

/* ---------- Client Types --------------------------------------------------
   Two columns, because a client type is two things: what it is called and how
   many clients say they are one. The name is the only one entered — a count is
   arrived at, not typed. Nothing about price appears here; a price list names
   the client types it applies to, and that is stated on Pricing > Price Lists. */
#grid-ctypes { min-width: 340px; }
#grid-ctypes .ct-c-name { width: 70%; }
#grid-ctypes .ct-c-n    { width: 30%; text-align: center; }
#grid-ctypes .input { width: 100%; }

/* Says where price is settled, for the reader who came here looking for it. It
   belongs under the table rather than in the header, where it would answer a
   question nobody had asked yet. */
.ct-note {
  margin: 10px 0 0;
  font-size: 12px; line-height: 1.5;
  color: var(--color-text-muted);
}


/* ===========================================================================
   THE RECORD TABS
   The client page brought its own stylesheet, which covers all of this. The
   one thing it cannot cover is its Activity table: that table was #tbl-flex-2
   there and this page already had a table of that name, so the copy came over
   renamed and its column weights come with it. Keyed by the column's name,
   never its position. */
#tbl-crec-activity :is(th, td).col-when   { width: 9%; }
#tbl-crec-activity :is(th, td).col-client { width: 20%; }
#tbl-crec-activity :is(th, td).col-action { width: 24%; }
#tbl-crec-activity :is(th, td).col-who    { width: 12%; }


/* The record begins where the dashboard ends, and the two are different jobs.
   Attached tabs sit flush against whatever is above them, which here would read
   as a ninth card; the gap is what says the strip belongs to what is under it. */
#cd > .tabs { margin-top: 22px; }




/* ===========================================================================
   THE CRM FRONT TAB
   Two lists and the terms. Both tables put their state column last and right,
   which is where the eye goes when it is scanning for what has moved. */
#tbl-crm-owed   { min-width: 420px; }
#tbl-crm-owed thead th.col-owed-due   { width: 16%; }
#tbl-crm-owed thead th.col-owed-state { width: 26%; }
#tbl-crm-owed .col-owed-state { text-align: right; white-space: nowrap; }

#tbl-crm-flight { min-width: 460px; }
#tbl-crm-flight thead th.col-fl-valid { width: 14%; }
#tbl-crm-flight thead th.col-fl-total { width: 20%; }
#tbl-crm-flight thead th.col-fl-state { width: 28%; }
#tbl-crm-flight .col-fl-state { text-align: right; white-space: nowrap; }
#tbl-crm-flight tbody tr { cursor: pointer; }


/* ===========================================================================
   THE TITLE AS A TRAIL
   On a client the title reads CRM / Elite Kitchens. Only the first half is a
   way back, so only the first half is a link — and it says so by colour and
   weight rather than an underline, which is this portal's rule for any
   clickable word. The client is where you already are, so it stays ink. */
.page-title__up {
  color: var(--color-primary-700);
  font-weight: 500;
  text-decoration: none;
}
.page-title__up:hover { color: var(--color-primary); }
/* The slash belongs to neither name, so it is lighter than both and given the
   air that keeps the two apart. */
.page-title__sep {
  margin: 0 8px;
  color: var(--color-text-subtle);
  font-weight: 400;
}

/* ---------- New / Edit Group dialog --------------------------------------- */
.cg-form-note { margin: 4px 0 0; font-size: 12px; }

/* ==========================================================================
   THE CLIENT GROUPS TAB

   A group is a named list of clients and nothing else. It carries no price and
   no tier: what a client pays is read off their Client Type, which they have
   exactly one of, and a group that could also price would be a second answer to
   a question already answered. So nothing in this panel talks about money —
   the only figures here are how many clients are in a list.
   ========================================================================== */

/* ONE card: a rail that picks a group, and the rest of it that IS that group.
   It was three cards standing side by side, and side by side is all they were —
   nothing said the middle one held the left one's members, and the third read as
   a separate page that happened to be open. A shared ground and a single seam
   between the two say it instead: what is on the right belongs to what is lit on
   the left. No gap, because a gap is what made them three things. */
.cg-split {
  display: grid; align-items: stretch;
  grid-template-columns: minmax(240px, 320px) 1fr;
}
/* The seam. One line, and the rail carries the quieter ground so the eye reads
   the detail side as the front of the card. The rail rounds its own two outer
   corners rather than the card clipping them for it — the card cannot clip,
   because the add result is a layer that has to be free to be taller than the
   group it floats over. */
.cg-rail {
  border-right: 1px solid var(--color-border);
  background: var(--color-surface-alt);
  border-radius: var(--radius-md) 0 0 var(--radius-md);
  display: flex; flex-direction: column; min-width: 0;
}
/* The toolbar comes with the card's own white ground and a top radius, both of
   which would draw a lid across the rail. It takes the rail's ground instead,
   and its field takes white — a control has to differ from what it sits on, and
   on this tint the usual control grey is the tint. */
.cg-rail .toolbar {
  background: transparent;
  border-radius: 0;
}
.cg-rail .toolbar .input { background: var(--color-surface); }
.cg-detail { min-width: 0; }

/* ---------- The group list (master) --------------------------------------- */
.cg-list { display: flex; flex-direction: column; }
.cg-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 10px 12px 10px 14px;
  border: 0; border-bottom: 1px solid var(--color-border);
  background: none; cursor: pointer; text-align: left; font: inherit;
}
.cg-item:last-child { border-bottom: 0; }
.cg-item:hover { background: var(--color-surface); }
/* Which group is open — and the join between the two halves. The open row takes
   the detail side's own ground and reaches across the seam to cover it, so the
   row and the panel read as one shape rather than as a highlight facing a card.
   It is also the only row that changes weight: colour alone would be the whole
   signal on a screen that cannot show it. */
.cg-item[aria-selected="true"] {
  position: relative;
  margin-right: -1px;
  background: var(--color-surface);
  box-shadow: inset 3px 0 0 var(--color-primary);
}
.cg-item[aria-selected="true"] .cg-i-name { font-weight: 600; color: var(--color-primary-700); }

.cg-i-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.cg-i-name { font-size: 13px; font-weight: 500; }
.cg-i-meta { font-size: 11px; color: var(--color-text-muted); }
/* A group without a description is not a lesser group — plenty of them need no
   explaining. Said in the same quiet type, not marked as something missing. */
.cg-i-meta--none { color: var(--color-text-subtle); }
/* The count is the figure the eye runs down, so it holds the right edge and
   gives no ground to a long group name beside it. */
.cg-i-count {
  flex: 0 0 auto; font-size: 12px; color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}
.cg-list-empty { padding: 22px 14px; font-size: 12px; color: var(--color-text-muted); text-align: center; }

/* ---------- The open group (detail) --------------------------------------- */
/* Nothing is chosen when the panel opens: this is a list of groups to be
   recognised, and picking one for the reader would answer the only question
   the pane is asking. */
/* It holds the whole detail side rather than a block at the top of it, so the
   card keeps its shape whether a group is open or not. */
.cg-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 320px; height: 100%; padding: 54px 22px;
  text-align: center; font-size: 13px; color: var(--color-text-muted);
}
.cg-empty svg { width: 26px; height: 26px; color: var(--color-text-subtle); margin-bottom: 10px; }

.cg-head-title { display: flex; align-items: center; gap: 9px; }
.cg-head-title h2 { margin: 0; }
.cg-head-acts { display: flex; align-items: center; gap: 6px; }

/* Columns, because a member row is a name and a line of small type and neither
   of them wants 1200px — one per line left two thirds of the panel empty and
   made a group of eight look like a long list. The count is not fixed: the
   panel takes as many 380px columns as it has room for, which is one on a
   narrow screen and three on a wide one, and the rows never restyle.

   The 420px cap and its scrollbar went with them. It was there so a group of
   forty did not leave the rail beside it looking like a stub, and three
   columns already shorten that list by two thirds. It also cannot come back
   while a member row opens a panel: a scroll box would cut the panel off at
   the bottom of the list, which is exactly where the last rows are. */
.cg-members {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
  overflow-x: clip;   /* the seam only; the panel still escapes downwards */
  /* The last row's rule would otherwise sit a hair above the card's own edge
     and read as a double line; the card border covers it instead. */
  margin-bottom: -1px;
}
.cg-member {
  position: relative;   /* the panel hangs off the row it was opened from */
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px 9px 14px;
  border-bottom: 1px solid var(--color-border);
  /* The seam between columns. A shadow, not a border, so it costs no width and
     the one on the last column falls outside the box and is clipped — no rule
     is left hanging at the right edge. */
  box-shadow: 1px 0 0 var(--color-border);
}
/* The row a panel is open on stays lit while it is being worked on. */
.cg-member.is-open { background: var(--color-surface-alt); z-index: 1; }
.cg-member .avatar { width: 30px; height: 30px; font-size: 11px; flex: 0 0 auto; }
/* The name is the way into every group this client is in, so it is a control
   and says so on hover — a change of colour and weight, never a rule under it. */
.cg-m-body {
  display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1;
  padding: 0; border: 0; background: none; font: inherit;
  text-align: left; cursor: pointer;
}
.cg-m-name { font-size: 13px; font-weight: 500; }
.cg-m-body:hover .cg-m-name { color: var(--color-primary-700); }
.cg-member.is-open .cg-m-name { color: var(--color-primary-700); font-weight: 600; }
/* Where else this client is reached from. The question a member row raises is
   whether taking them out here takes them off everything, and the row answers
   it before the × is pressed rather than after. */
.cg-m-meta { font-size: 11px; color: var(--color-text-muted); }

/* Destructive, so it stays quiet until the row is being worked on. */
.cg-m-off {
  flex: 0 0 auto; padding: 5px;
  border: 0; border-radius: 5px; background: none; cursor: pointer;
  color: var(--color-text-subtle); line-height: 0;
  opacity: 0; transition: opacity 120ms, color 120ms, background 120ms;
}
.cg-m-off svg { width: 15px; height: 15px; }
.cg-member:hover .cg-m-off,
.cg-m-off:focus-visible { opacity: 1; }
.cg-m-off:hover { background: var(--color-danger-50); color: var(--color-danger); }
@media (hover: none) { .cg-m-off { opacity: 1; } }

.cg-members-empty { padding: 30px 16px; text-align: center; font-size: 12px; color: var(--color-text-muted); }

/* ---------- Every group one member is in ----------------------------------
   The row named the other groups and then left the reader to go and find each
   one in the rail to take the client off it — three trips to undo one thing.
   The panel is the same list, made of controls, and it holds THIS group too:
   "what is this client on" and "take them off it" are one question, and a list
   that answered it with a hole where the current group should be would be a
   list the reader has to correct while reading.

   Built as the portal's dropdown is built, because that is what it is. */
.cg-m-pop {
  position: absolute; z-index: 25; top: calc(100% - 4px); left: 54px;
  min-width: 248px; max-width: calc(100% - 68px);
  padding: 6px;
  background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}
.cg-m-pop__row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 6px 6px 10px; border-radius: var(--radius-sm);
  font-size: 13px;
}
.cg-m-pop__row:hover { background: var(--color-primary-50); }
.cg-m-pop__n { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Which of them is the one being looked at. A note on the name, not a badge —
   it is orientation, and there is nothing to press. */
.cg-m-pop__here { flex: 0 0 auto; font-size: 10px; color: var(--color-text-subtle); }
/* Always shown, unlike the × on the row: this panel was opened on purpose, and
   a menu whose items reveal their controls on hover is a menu that looks like
   it has none. */
.cg-m-pop__off {
  flex: 0 0 auto; padding: 4px;
  border: 0; border-radius: 5px; background: none; cursor: pointer;
  color: var(--color-text-subtle); line-height: 0;
  transition: color 120ms, background 120ms;
}
.cg-m-pop__off svg { width: 14px; height: 14px; }
.cg-m-pop__off:hover { background: var(--color-danger-50); color: var(--color-danger); }

/* ---------- Adding clients ------------------------------------------------
   In place, not in a dialog: adding six clients to a group is one job, and a
   dialog that has to be reopened per client turns it into six. The column is a
   search box and nothing else until it is used — a standing list of everyone
   outside the group is a second table of clients beside the members table, and
   the two are not worth telling apart. What appears under the box is the search
   result, and the box stays put as clients are taken from it, because nobody
   adds exactly one.

   It sits under the group's own name, inside the same card, because the group
   it adds to is the one named directly above it. Standing in a card of its own
   it had to repeat that name in its heading to say what it was for. */
.cg-add { padding: 12px 14px; border-bottom: 1px solid var(--color-border); }
.cg-add .search { position: relative; }
.cg-add .search input { padding-left: 32px; }
.cg-add .search svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--color-text-subtle); pointer-events: none;
}
/* The answer floats over the group rather than sitting in it. A result pushed
   the members down the page, so asking who else there is moved the people
   already there — and a strip that is plainly not the group is easier to read
   as a layer over it than as another band inside it. It hangs off the box that
   was typed into, and goes when that box is cleared. */
.cg-add-pop {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.cg-add-pop[hidden] { display: none; }
/* Same columns as the members below it: it is the same kind of row, and a
   single file of names down a panel this wide is what was wrong with it. */
.cg-add-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  max-height: 280px; overflow-y: auto;
  margin-bottom: -1px;   /* the layer's own edge covers the last row's rule */
}
/* Nothing typed, or nobody left to match: no strip, no border, no gap. */
.cg-add-list:empty { display: none; }
.cg-add-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 8px 11px;
  border: 0; border-bottom: 1px solid var(--color-border);
  background: none; cursor: pointer; text-align: left; font: inherit;
  box-shadow: 1px 0 0 var(--color-border);
}
.cg-add-row:hover { background: var(--color-primary-50); }
.cg-add-row .thumb { width: 28px; height: 28px; font-size: 10px; flex: 0 0 auto; }
.cg-add-row .cg-a-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.cg-add-row .cg-a-name { font-size: 13px; font-weight: 500; }
.cg-add-row .cg-a-meta { font-size: 11px; color: var(--color-text-muted); }
/* Also a search result, so it stands on the same layer as one. */
.cg-add-empty {
  padding: 18px 14px; text-align: center; font-size: 12px; color: var(--color-text-muted);
}

@media (max-width: 1100px) {
  /* The rail gives up width before it gives up its place — a group name and a
     count still read at 200px, and stacking too early costs the join. */
  .cg-split { grid-template-columns: minmax(190px, 240px) 1fr; }
}
@media (max-width: 820px) {
  /* Side by side stops working long before the page does — the members pane
     runs out of room for a name and a city on one line. The seam turns
     horizontal so the two halves stay one card. */
  .cg-split { grid-template-columns: 1fr; }
  .cg-rail {
    border-right: 0; border-bottom: 1px solid var(--color-border);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
  }
  .cg-item[aria-selected="true"] { margin-right: 0; margin-bottom: -1px; }
  .cg-empty { min-height: 180px; }
}


/* ===========================================================================
   TASK TYPE
   What kind of task, in both lists that hold one. It is a tag rather than a
   status, so it takes the neutral badge the quote table already uses for
   where a quote came from — read once on the way past, never scanned for. */
.col-ttype .badge { width: max-content; }
/* The mark rides the word rather than competing with it: at the badge's own
   11px the default icon reads as the louder half of the pair. */
.col-ttype .badge svg { width: 13px; height: 13px; flex: none; }

/* The day's queue pins its short columns and lets Task take the slack. */
#tbl-flex-2 thead th.col-ttype { width: 122px; min-width: 122px; max-width: 122px; }

/* The client's own list is fluid shares, so the new column comes out of the
   ones that had width to spare rather than off the task's own. */
#tbl-flex-1 thead th.col-check    { width: 6%; }
#tbl-flex-1 thead th.col-ttype    { width: 13%; }
#tbl-flex-1 thead th.col-flex     { width: 31%; }
#tbl-flex-1 thead th.col-assignee { width: 12%; }
#tbl-flex-1 thead th.col-due      { width: 16%; }
#tbl-flex-1 thead th.col-priority { width: 10%; }
#tbl-flex-1 thead th.col-status   { width: 12%; }
