/* Care Quality Command Center Portal design system */

:root {
  /* Brand */
  --navy-900: #0a1f44;
  --navy-700: #1b3670;
  --blue-600: #2563eb;
  --blue-500: #3b82f6;
  --blue-100: #dbeafe;
  --blue-50:  #eff6ff;
  --orange-600: #ea580c;
  --orange-100: #ffedd5;

  /* HealthyConnect brand. Dignity Blue is the primary action and Coral marks
     the active nav item; Pantone 7693 C and 1635 C. Sky Blue and Sandstone
     are named because the trip planner calls them by name -- its road, its
     sign plates and its sunrise -- and only there; Sky Blue still appears in
     the page wash as a dilution. Coral stays on its one job: it sits a step
     from red, and the trip page uses Sandstone for warmth instead. */
  /* **The action buttons wear the corporate peach gradient** (Andrew, 5
     October 2026), read off myhealthyconnect.ai's own `--gradient-accent`:
     120deg, oklch(74% .12 42) to oklch(68% .15 30). Buttons only -- a
     selected tab, a sign plate and the rail keep Dignity, and danger keeps
     red. One pair of tokens, so every button changes together. */
  --btn-grad:       linear-gradient(120deg, #ea906d 0%, #e6705f 100%);
  --btn-grad-hover: linear-gradient(120deg, #e58460 0%, #de6252 100%);
  --dignity:       #174775;
  --dignity-hover: #123759;
  --coral:         #ea7c63;
  --sky:           #8ac9e5;   /* Pantone 291 C */
  --sandstone:     #f0a693;   /* Pantone 487 C */

  /* Hover states are named by role rather than by scale: navy lifts on hover
     and blue deepens, so a numeric name would assert a direction only one of
     them follows. */
  --navy-hover: #16305a;
  --blue-hover: #1d4ed8;

  /* Neutrals */
  --ink:      #0f172a;
  --ink-2:    #334155;
  /* A step darker than the slate scale these came from: muted text sat close
     enough to the border value that captions read as disabled rather than
     secondary. */
  --ink-3:    #5a6b80;
  --ink-4:    #8b9cb0;
  --line:     #e2e8f0;
  /* The frame a tab row and the pane it opens onto share. Two shades down
     from `--line`, which was too faint to read as an enclosure, and well
     short of the Dignity version, which was more pop than the job needs. One
     token because three rules draw one line: the row's rule, the open tab's
     border and the pane's. */
  --frame:    #bcc8d6;
  /* A field somebody fills in: a shallow well rather than paper. The
     border is a step up from --line, which is invisible on a white
     card -- which is what a page of white inputs on white was. */
  --field:      #f6f8fb;
  --field-line: #ccd6e2;
  --line-2:   #f1f5f9;
  --surface:  #ffffff;
  --canvas:   #f8fafc;

  /* Text and icons on a filled accent ground. The same value as --surface
     today, and deliberately not the same token -- a palette that tints card
     surfaces must not drag the white off a blue button with it. */
  --on-accent: #ffffff;

  /* Status */
  --green-600: #16a34a;
  --green-100: #dcfce7;
  --amber-600: #d97706;
  --amber-100: #fef3c7;
  --red-600:   #dc2626;
  --red-100:   #fee2e2;
  --red-50:    #fef2f2;
  --purple-600:#7c3aed;
  --purple-100:#ede9fe;

  /* Scale */
  --r-sm: 6px;
  --r:    10px;
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06);
  --shadow:    0 1px 3px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .04);
  --sidebar-w: 236px;
  --header-h:  62px;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--blue-600); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- Header ---------- */

.hdr {
  height: var(--header-h);
  background: var(--navy-900);
  display: flex;
  align-items: center;
  position: sticky;
  top: 0;
  z-index: 40;
}

.hdr-brand {
  width: var(--sidebar-w);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 18px;
  height: 100%;
  color: #fff;
}

/* The logo is a 388x128 asset shown at 38px, so it has better than three
   times the pixels a 1x header needs and stays crisp on a 2x display. It is
   a stacked two-line lockup rather than a horizontal one, and 32px left the
   second line at roughly an 8px cap height -- 38px carries it to 10px and
   still leaves 12px of header above and below. It carries the name itself,
   which is why no wordmark sits beside it, and why the .mark and .wordmark
   rules that used to build one here are gone rather than left unreferenced. */
.hdr-brand img { height: 38px; width: auto; }

.hdr-title {
  color: #fff; font-weight: 600; font-size: 16px;
  padding-left: 8px; white-space: nowrap;
  /* "Care Quality Command Center Portal" is twice "Intranet Portal": between
     the phone breakpoint and a wide window it ellipsises rather than pushing
     the user block, and Sign out, off the edge. */
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
}

.hdr-spacer { flex: 1; }

.hdr-user {
  display: flex; align-items: center; gap: 9px;
  padding: 0 22px 0 14px; color: #fff; font-size: 14px;
}

.hdr-user .avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255,255,255,.16);
  display: grid; place-items: center;
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
}

.hdr-user a { color: rgba(255,255,255,.72); font-size: 13px; }
.hdr-user a:hover { color: #fff; text-decoration: none; }

/* ---------- Shell ---------- */

.shell { display: flex; min-height: calc(100vh - var(--header-h)); }

.side {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--line);
  padding: 12px 0 24px;
}

.side a {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 18px;
  color: var(--ink-2); font-size: 14px;
  border-left: 3px solid transparent;
}
.side a:hover { background: var(--line-2); text-decoration: none; }
.side a.active {
  background: var(--blue-600); color: #fff;
  border-left-color: var(--navy-900); font-weight: 600;
}
.side a.child      { padding-left: 34px; font-size: 13.5px; color: var(--ink-2); }
.side a.grandchild { padding-left: 48px; font-size: 13px;   color: var(--ink-3); }
.side a.app::before { content: "\203A"; color: var(--ink-4); font-weight: 700; }
.side a.active.app::before { color: rgba(255,255,255,.7); }

.side .parent {
  padding: 12px 18px 5px;
  font-size: 11px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-4);
}

.main { flex: 1; padding: 26px 32px 48px; max-width: 1180px; min-width: 0; }

/* ---------- Typography ---------- */

h1 { font-size: 26px; font-weight: 700; letter-spacing: -.02em; margin: 0 0 4px; }
h2 { font-size: 17px; font-weight: 650; letter-spacing: -.01em; margin: 28px 0 10px; }
h3 { font-size: 14px; font-weight: 650; margin: 0 0 6px; }
.lede  { color: var(--ink-3); margin: 0 0 20px; }
.muted { color: var(--ink-3); }
.tiny  { font-size: 12.5px; }

code {
  background: var(--line-2); padding: 1px 6px; border-radius: 4px;
  font-size: 12.5px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ---------- Cards ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
}

.card-pad { padding: 18px 20px; }

.card-hd {
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  /* Wraps, and its heading may shrink. A card head is a flex row whose items
     sit at `min-width: auto`, so an import's filename and its state badge ran
     61px off the page at 390 -- the only thing in the portal that escaped by
     more than the header did. Nothing here is lost by wrapping. */
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.card-hd h2, .card-hd h3 { min-width: 0; overflow-wrap: anywhere; }
.card-hd h3 { margin: 0; font-size: 14.5px; }
.card-hd .spacer { flex: 1; }

.grid { display: grid; gap: 14px; }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.grid-metrics { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }

/* Link card (the accent tiles) */
.tile {
  display: block; padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  color: inherit; transition: border-color .12s, box-shadow .12s, transform .12s;
}
.tile:hover {
  text-decoration: none; border-color: var(--blue-500);
  box-shadow: var(--shadow); transform: translateY(-1px);
}
.tile strong { display: block; font-size: 14.5px; margin-bottom: 3px; color: var(--ink); }
.tile span   { font-size: 13px; color: var(--ink-3); line-height: 1.45; }

/* Metric */
.metric { padding: 16px 18px; }
.metric .label {
  font-size: 12px; font-weight: 600; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px;
}
.metric .value { font-size: 30px; font-weight: 700; letter-spacing: -.03em; line-height: 1.1; }
.metric .foot  { font-size: 12.5px; color: var(--ink-3); margin-top: 5px; }
.metric .up    { color: var(--green-600); font-weight: 600; }
.metric .down  { color: var(--red-600);   font-weight: 600; }

/* ---------- Tables ---------- */

.table-wrap { overflow-x: auto; }

table { border-collapse: collapse; width: 100%; font-size: 14px; }

thead th {
  text-align: left; padding: 10px 16px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
  background: var(--canvas); border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

tbody td { padding: 11px 16px; border-bottom: 1px solid var(--line-2); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--blue-50); }

td.right, th.right { text-align: right; }

/* ---------- Badges / pills / dots ---------- */

.badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
.badge.blue   { background: var(--blue-100);   color: var(--blue-600); }
.badge.green  { background: var(--green-100);  color: var(--green-600); }
.badge.amber  { background: var(--amber-100);  color: var(--amber-600); }
.badge.red    { background: var(--red-100);    color: var(--red-600); }
.badge.purple { background: var(--purple-100); color: var(--purple-600); }
.badge.orange { background: var(--orange-100); color: var(--orange-600); }
.badge.grey   { background: var(--line-2);     color: var(--ink-3); }

.dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; margin-right: 6px; }
.dot.green { background: var(--green-600); }
.dot.amber { background: var(--amber-600); }
.dot.grey  { background: var(--ink-4); }

/* ---------- Forms ---------- */

.field { margin-bottom: 13px; }
.field label {
  display: block; font-size: 12.5px; font-weight: 600;
  color: var(--ink-2); margin-bottom: 4px;
}

/* **A field is a well, not paper.** Andrew, on the trip planner and then on
   the rest: the pages are largely white, an input was white with a `--line`
   hairline, and nothing said where the work is. So a field carries an
   off-white fill, a border a step darker, and a hair of inset shadow at the
   top -- and goes **white on focus**, which is the opposite move to the
   folders and means the same thing: this one is live. */
input[type=text], input[type=email], input[type=search], input[type=tel],
input:not([type]), select, textarea {
  width: 100%; padding: 8px 11px;
  border: 1px solid var(--field-line); border-radius: var(--r-sm);
  font: inherit; font-size: 14px; color: var(--ink);
  background: var(--field); box-shadow: inset 0 1px 2px rgba(10, 31, 68, .05);
  transition: border-color .12s, box-shadow .12s;
}
/* **`date`, `time` and `number` take the frame and nothing else.** The reset
   above has never covered them -- which is why one date field rendered in
   browser chrome, a 2px grey border among 1px blue-grey ones -- and giving
   them its width and padding too would move controls all over the portal that
   were measured without it. Several pages size these themselves and still do;
   this only stops them looking foreign. */
input[type=date], input[type=time], input[type=number] {
  border: 1px solid var(--field-line); border-radius: var(--r-sm);
  font: inherit; font-size: 14px; color: var(--ink);
  background: var(--field); box-shadow: inset 0 1px 2px rgba(10, 31, 68, .05);
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--blue-500);
  background: var(--surface); box-shadow: 0 0 0 3px var(--blue-100);
}
/* A box that cannot be typed in is not a field to fill in -- the trip
   planner's link boxes are there to be read and copied -- so it keeps paper. */
input[readonly], textarea[readonly] {
  background: var(--surface); box-shadow: none; border-color: var(--line);
}
input::placeholder, textarea::placeholder { color: var(--ink-4); }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 16px; border-radius: var(--r-sm);
  font: inherit; font-size: 14px; font-weight: 600;
  border: 1px solid transparent; cursor: pointer;
  background: var(--btn-grad); color: var(--on-accent);
  transition: filter .12s;
}
.btn:hover { background: var(--btn-grad-hover); text-decoration: none; }
.btn.ghost { background: var(--surface); color: var(--ink-2); border-color: var(--line); }
.btn.ghost:hover { background: var(--line-2); }
.btn.sm { padding: 5px 11px; font-size: 13px; }

/* ---------- Bits ---------- */

.toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
.toolbar .spacer { flex: 1; }
.toolbar input[type=search] { max-width: 300px; }

.segmented { display: inline-flex; border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; }
.segmented a {
  padding: 6px 13px; font-size: 13px; font-weight: 500;
  color: var(--ink-2); background: var(--surface);
  border-right: 1px solid var(--line);
}
.segmented a:last-child { border-right: none; }
.segmented a:hover { background: var(--line-2); text-decoration: none; }
.segmented a.on { background: var(--blue-600); color: var(--on-accent); }

.empty { padding: 40px 20px; text-align: center; color: var(--ink-3); }
.empty .big { font-size: 15px; font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }

.crumbs { font-size: 13px; color: var(--ink-3); margin-bottom: 10px; }
.crumbs a { color: var(--ink-3); }
.crumbs .sep { padding: 0 6px; color: var(--ink-4); }

/* ---------- Tabs ---------- */
/* Two or more views of one app, drawn as buttons.

   The first version underlined them, on the argument that nothing then has to
   align with the card beneath. It read as text: correct, and not something the
   eye goes to. Andrew asked for tabs that look like they can be pressed, so
   each is a bordered button on the page ground and the one you are on is
   filled in Dignity Blue -- the portal's primary action colour, which is what
   "you are here, and the other is one click away" should look like.

   Still distinct from .segmented, which is a filter toggle: that one is a
   single joined strip with no gaps, because its members are options within one
   control. These are separate destinations, so they are separate buttons.

   It exists because the prospects app expressed the same idea as two adjacent
   links in a .crumbs row, which renders as one word -- the second .crumbs rule
   sets display:flex and nothing supplies a gap, so a separator has to be an
   explicit .sep and there wasn't one.

   The row wraps: prospects will gain an area tab when census data lands, and a
   tab bar that only works at exactly two is a tab bar that gets replaced. */
.tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.tabs a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 15px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2);
  font-size: 13.5px; font-weight: 600; line-height: 1.2;
  box-shadow: var(--shadow-sm);
  transition: background .12s, border-color .12s, color .12s;
}
.tabs a:hover {
  background: var(--line-2); border-color: var(--ink-4); color: var(--ink);
  text-decoration: none;
}
/* The way back to the list as it was left, on a record page. It sits in the
   tab row because it is navigation of the same kind -- but it is not a
   destination, it is a return, so it reads as a quieter thing: no border, no
   fill, and pushed to the far end so it never reads as a seventh tab. */
.tabs .tab-back {
  margin-left: auto; border-color: transparent; background: none;
  box-shadow: none; color: var(--ink-3); font-weight: 600;
}
.tabs .tab-back:hover {
  background: none; border-color: transparent; color: var(--dignity);
  text-decoration: underline; text-underline-offset: 3px;
}
@media (max-width: 560px) {
  /* Wrapped onto its own line, the auto margin would strand it mid-row. */
  .tabs .tab-back { margin-left: 0; padding-left: 0; }
}

.tabs a[aria-current="page"] {
  background: var(--dignity); border-color: var(--dignity);
  color: var(--on-accent); box-shadow: none;
}
.tabs a[aria-current="page"]:hover { background: var(--dignity-hover); border-color: var(--dignity-hover); }
/* How big the thing behind the tab is. A fact about the app, so it does not
   move when a filter does -- the filter row says how many match. On the filled
   tab it is white held back, which is the only way to sit a second weight of
   text on an accent ground without a second token for it. */
.tabs .n { font-size: 11.5px; font-weight: 700; color: var(--ink-4); }
.tabs a:hover .n { color: var(--ink-3); }
.tabs a[aria-current="page"] .n,
.tabs a[aria-current="page"]:hover .n { color: rgba(255, 255, 255, .72); }

.avatar-sm {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--blue-100); color: var(--blue-600);
  display: grid; place-items: center;
  font-size: 11.5px; font-weight: 700; flex-shrink: 0;
}

.row { display: flex; align-items: center; gap: 10px; }

.foot {
  border-top: 1px solid var(--line); background: var(--surface);
  padding: 14px 32px; font-size: 12.5px; color: var(--ink-3);
  display: flex; align-items: center;
}
.foot .spacer { flex: 1; }

@media (max-width: 860px) {
  .side { display: none; }
  .hdr-brand { width: auto; }
  .main { padding: 20px 18px 40px; }
}

/* The header was two pixels too wide on **every page**, at every phone width.
   Nothing in it gave way: the brand is fixed, the title is `nowrap`, and the
   user block is a flex item at `min-width: auto`, so 268px of brand and title
   met a 124px user block in a 390px header.

   The label gives way, not the person. "Care Quality Command Center Portal" sits beside a logo
   that already carries the name -- which is the recorded reason nothing spells
   it out next to the mark -- so on a phone the logo carries it alone. The
   user block may shrink as a backstop for a longer name than this Workspace
   has today, with the name ellipsised rather than the Sign out link pushed
   off the edge. */
@media (max-width: 560px) {
  .hdr-title { display: none; }
  .hdr-user { min-width: 0; padding-right: 14px; }
  .hdr-user > div:last-child { min-width: 0; }
  .hdr-user > div:last-child > div {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* ---------- Collapsible nav sections ---------- */

.nav-disc { display: block; }

.nav-disc > summary {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 18px 8px 34px;
  font-size: 13.5px; color: var(--ink-2);
  border-left: 3px solid transparent;
  cursor: pointer; list-style: none; user-select: none;
}
.nav-disc > summary::-webkit-details-marker { display: none; }
.nav-disc > summary:hover { background: var(--line-2); }

.nav-disc > summary a { color: inherit; flex: 1; }
.nav-disc > summary a:hover { text-decoration: none; }

.nav-disc > summary.active {
  background: var(--blue-600); color: #fff;
  border-left-color: var(--navy-900); font-weight: 600;
}

.caret {
  width: 0; height: 0; flex-shrink: 0;
  border-left: 4.5px solid currentColor;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  opacity: .45;
  transition: transform .15s ease;
}
.nav-disc[open] > summary .caret { transform: rotate(90deg); }
.nav-disc > summary:hover .caret { opacity: .8; }

.nav-disc > a.grandchild { padding-left: 52px; }

/* Active nav links: text must win over the depth-based color rules above. */
.side a.active,
.side a.child.active,
.side a.grandchild.active,
.nav-disc > summary.active,
.nav-disc > summary.active a {
  color: #fff;
}
.side a.active.app::before,
.nav-disc > summary.active .caret { color: rgba(255, 255, 255, .75); }

/* ---------- Accent palette ---------- */

/* Twenty of them, because a section picks its own and near-duplicates would
   defeat the purpose: each is distinguishable from every other at the size
   these actually render, an 8px dot and a 3px rail.

   The names are data -- they are stored in sections.accent and pinned to
   contact types -- so renaming one is a migration rather than a stylesheet
   edit. The first six take their colour from the status tokens instead of
   repeating the value, so the two systems cannot drift apart. */
.a-blue    { --a: var(--blue-600);   --a-bg: #eff6ff; --a-br: #bfdbfe; }
.a-green   { --a: var(--green-600);  --a-bg: #f0fdf4; --a-br: #bbf7d0; }
.a-orange  { --a: var(--orange-600); --a-bg: #fff7ed; --a-br: #fed7aa; }
.a-purple  { --a: var(--purple-600); --a-bg: #f5f3ff; --a-br: #ddd6fe; }
.a-red     { --a: var(--red-600);    --a-bg: #fef2f2; --a-br: #fecaca; }
.a-amber   { --a: var(--amber-600);  --a-bg: #fffbeb; --a-br: #fde68a; }
.a-teal    { --a: #0d9488; --a-bg: #f0fdfa; --a-br: #99f6e4; }
.a-indigo  { --a: #4f46e5; --a-bg: #eef2ff; --a-br: #c7d2fe; }
.a-slate   { --a: #475569; --a-bg: #f8fafc; --a-br: #cbd5e1; }
.a-cyan    { --a: #0891b2; --a-bg: #ecfeff; --a-br: #a5f3fc; }
.a-sky     { --a: #0284c7; --a-bg: #f0f9ff; --a-br: #bae6fd; }
.a-emerald { --a: #059669; --a-bg: #ecfdf5; --a-br: #a7f3d0; }
.a-lime    { --a: #65a30d; --a-bg: #f7fee7; --a-br: #d9f99d; }
.a-rose    { --a: #e11d48; --a-bg: #fff1f2; --a-br: #fecdd3; }
.a-pink    { --a: #db2777; --a-bg: #fdf2f8; --a-br: #fbcfe8; }
.a-fuchsia { --a: #c026d3; --a-bg: #fdf4ff; --a-br: #f5d0fe; }
.a-violet  { --a: #6d28d9; --a-bg: #f5f3ff; --a-br: #ddd6fe; }
.a-brown   { --a: #92400e; --a-bg: #fef3e2; --a-br: #fcd9a5; }
.a-olive   { --a: #4d7c0f; --a-bg: #f4f9e8; --a-br: #cbe58f; }
.a-steel   { --a: #0f766e; --a-bg: #f0fdfa; --a-br: #99f6e4; }

/* ---------- Icons ---------- */

.ico { width: 18px; height: 18px; stroke-width: 2; flex-shrink: 0; }
.ico-lg { width: 22px; height: 22px; }

.ico-box {
  width: 40px; height: 40px; border-radius: var(--r-sm);
  background: var(--a-bg); color: var(--a);
  display: grid; place-items: center; flex-shrink: 0;
}
.ico-box.sm { width: 30px; height: 30px; border-radius: 7px; }

.side .ico { width: 16px; height: 16px; opacity: .62; }
.side a.active .ico, .nav-disc > summary.active .ico { opacity: 1; }
.side a.child .ico, .nav-disc > summary .ico { color: var(--a, var(--ink-3)); opacity: .9; }
.nav-disc > summary.active .ico { color: #fff; }

/* ---------- Accented tiles ---------- */

.tile.accent {
  display: flex; align-items: flex-start; gap: 13px;
  border-left: 3px solid var(--a);
}
.tile.accent:hover { border-color: var(--line); border-left-color: var(--a); }
.tile.accent .body { min-width: 0; }

.card.accent { border-top: 3px solid var(--a); }
.card-hd .ico-box.sm { margin-right: 2px; }

/* ---------- Page head ---------- */

.page-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 18px; }
.page-head .ico-box { width: 46px; height: 46px; border-radius: var(--r); }
.page-head h1 { margin-bottom: 2px; }
.page-head .lede { margin: 0; }
.page-head .spacer { flex: 1; }
.page-head .date { color: var(--ink-3); font-size: 13.5px; white-space: nowrap; padding-top: 6px; }

/* ---------- Section list rows ---------- */

.rows { display: flex; flex-direction: column; }
.rows a {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.rows a:last-child { border-bottom: none; }
.rows a:hover { background: var(--canvas); text-decoration: none; }
.rows .grow { flex: 1; min-width: 0; }
.rows .name { font-weight: 600; font-size: 14px; }
.rows .sub  { font-size: 12.5px; color: var(--ink-3); }
.rows .chev { color: var(--ink-4); }

/* ---------- Icon picker ---------- */

.icon-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: 6px; max-height: 190px; overflow-y: auto;
  padding: 10px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--canvas);
}

.icon-opt {
  aspect-ratio: 1; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2);
  cursor: pointer; padding: 0;
  transition: border-color .1s, color .1s, background .1s;
}
.icon-opt:hover { border-color: var(--blue-500); color: var(--blue-600); }
.icon-opt.on { background: var(--blue-600); color: var(--on-accent); border-color: var(--blue-600); }

.icon-picked { gap: 9px; }
.icon-picked code { font-size: 12.5px; }

/* ---------- App activation picker ---------- */

.app-picks { display: flex; flex-wrap: wrap; gap: 8px; }

.app-pick {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); font-size: 13.5px; cursor: pointer;
}
.app-pick:hover { border-color: var(--blue-500); }
.app-pick input { width: auto; margin: 0; accent-color: var(--blue-600); }

/* The old .caret belonged to a retired disclosure and stays hidden. .nav-disc
   is live again and must not be: retiring a component by hiding its selector
   rather than deleting its rules silently suppressed the replacement. */
.caret { display: none; }

/* ---------- Documentation ---------- */

.doc-layout { display: grid; grid-template-columns: minmax(0, 1fr) 230px; gap: 20px; align-items: start; }
.doc-side { position: sticky; top: calc(var(--header-h) + 20px); }
.doc-toc { padding: 6px 4px 12px; max-height: 60vh; overflow-y: auto; }
.doc-toc ul { list-style: none; padding-left: 14px; margin: 0; }
.doc-toc > ul { padding-left: 12px; }
.doc-toc li { margin: 2px 0; }
.doc-toc a { font-size: 13px; color: var(--ink-2); line-height: 1.4; display: block; padding: 2px 0; }
.doc-toc a:hover { color: var(--blue-600); text-decoration: none; }

.prose { line-height: 1.65; }
.prose > *:first-child { margin-top: 0; }
.prose h1 { font-size: 25px; margin: 0 0 6px; }
.prose h2 {
  font-size: 19px; margin: 30px 0 10px; padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}
.prose h3 { font-size: 15.5px; margin: 22px 0 6px; }
.prose p, .prose ul, .prose ol { margin: 0 0 13px; }
.prose ul, .prose ol { padding-left: 22px; }
.prose li { margin: 4px 0; }
.prose hr { border: none; border-top: 1px solid var(--line); margin: 28px 0; }

.prose code {
  background: var(--line-2); color: #b91c1c;
  padding: 1.5px 5px; border-radius: 4px; font-size: 13px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.prose pre {
  background: var(--ink); color: var(--line);
  padding: 14px 16px; border-radius: var(--r-sm);
  overflow-x: auto; margin: 0 0 15px; font-size: 13px; line-height: 1.55;
}
.prose pre code { background: none; color: inherit; padding: 0; font-size: inherit; }

.prose blockquote {
  margin: 0 0 14px; padding: 10px 16px;
  border-left: 3px solid var(--blue-500); background: var(--blue-50);
  color: var(--ink-2);
}
.prose blockquote p:last-child { margin-bottom: 0; }

.prose table { margin: 0 0 15px; font-size: 13.5px; }
.prose table th { background: var(--canvas); }

.prose a { font-weight: 500; }
.prose strong { font-weight: 650; }

@media (max-width: 1100px) {
  .doc-layout { grid-template-columns: 1fr; }
  .doc-side { position: static; }
}

/* Google profile photos in avatars */
.hdr-user .avatar { overflow: hidden; padding: 0; }
.hdr-user .avatar img,
.avatar-sm img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
.avatar-sm { overflow: hidden; }

/* ---------- RegWatch ---------- */

.rw-item { padding: 16px 20px; border-bottom: 1px solid var(--line-2); border-left: 3px solid transparent; }
.rw-item:last-child { border-bottom: none; }
.rw-high   { border-left-color: var(--orange-600); }
.rw-medium { border-left-color: var(--blue-500); }
.rw-low    { border-left-color: var(--line); }

/* Metadata is docket numbers and CPT codes. Monospace is native to that world. */
.rw-line { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 7px; }
.rw-meta {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .02em;
}
.rw-sep { color: var(--ink-4); font-size: 11px; }

.chip {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em;
  padding: 1px 7px; border-radius: 3px;
  border: 1px solid var(--blue-500); color: var(--blue-600);
}

.rw-title {
  display: inline-block; font-size: 15px; font-weight: 650;
  color: var(--ink); line-height: 1.35; margin-bottom: 6px;
}
.rw-title:hover { color: var(--blue-600); text-decoration: none; }
.rw-ext { width: 13px; height: 13px; margin-left: 5px; opacity: .4; vertical-align: -1px; }

.rw-dek  { margin: 0 0 6px; font-size: 14.5px; color: var(--ink); font-weight: 500; }
.rw-body { margin: 0 0 10px; font-size: 14px; color: var(--ink-2); }

/* Everything above is context for this one line. */
.rw-sowhat {
  display: flex; gap: 10px; align-items: baseline;
  border-top: 1px solid var(--line); padding-top: 9px;
  font-size: 14px; color: var(--ink);
}
.rw-sowhat-label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--orange-600); white-space: nowrap; padding-top: 2px;
}

.rw-quiet {
  display: flex; align-items: center; gap: 9px;
  padding: 22px 20px; color: var(--ink-3); font-size: 14px;
}
.rw-quiet .ico { color: var(--green-600); opacity: .7; }

.rw-more { font-size: 12.5px; margin-left: 12px; }

/* Build time sits quieter than the edition date it follows. */
.rw-built { opacity: .6; }
.rw-built::before { content: "\00b7"; margin: 0 6px 0 2px; opacity: .5; }

/* ---------- Projects ---------- */

/* Health colours are shared by dots, bars and rails so one glance reads
   consistently across the list and the tree. */
.h-on_track { --h: var(--blue-500); }
.h-at_risk  { --h: var(--amber-600); }
.h-overdue  { --h: var(--orange-600); }
.h-blocked  { --h: var(--red-600); }
.h-done     { --h: var(--green-600); }

/* Project list rows */
.pj-row {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 20px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.pj-row:last-child { border-bottom: none; }
.pj-row:hover { background: var(--canvas); text-decoration: none; }
.pj-row .grow { flex: 1; min-width: 0; }
.pj-row .name { display: block; font-weight: 600; font-size: 14px; }
.pj-row .sub  { display: block; font-size: 12.5px; color: var(--ink-3); }
.pj-row .chev { color: var(--ink-4); flex-shrink: 0; }

.pj-health {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--h, var(--ink-4)); flex-shrink: 0;
}

.pj-bar {
  display: block; width: 110px; height: 6px; flex-shrink: 0;
  background: var(--line); border-radius: 3px; overflow: hidden;
}
.pj-bar.wide { width: 100%; height: 8px; border-radius: 4px; }
.pj-fill { display: block; height: 100%; background: var(--h, var(--blue-500)); }
.pj-pct {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: var(--ink-3); width: 38px; text-align: right; flex-shrink: 0;
}

/* Task tree. Indentation carries the hierarchy; the rail makes depth
   scannable without counting pixels. */
.tk-tree { padding: 4px 0; }

.tk {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 20px; border-bottom: 1px solid var(--line-2);
}
.tk:last-child { border-bottom: none; }
.tk:hover { background: var(--canvas); }

.tk-l2 { padding-left: 20px; }
.tk-l3 { padding-left: 46px; background: #fcfdfe; }
.tk-l3::before {
  content: ""; position: absolute; margin-left: -18px;
  width: 1px; height: 20px; background: var(--line);
}

.tk-health { width: 7px; height: 7px; border-radius: 50%;
             background: var(--h, var(--ink-4)); flex-shrink: 0; }

.tk-main { flex: 1; min-width: 0; }
.tk-title { font-size: 14px; font-weight: 550; }
.tk-l3 .tk-title { font-weight: 450; font-size: 13.5px; color: var(--ink-2); }
.tk-notes { display: block; font-size: 12.5px; color: var(--ink-3); margin-top: 1px; }

.tk-warn { width: 14px; height: 14px; color: var(--amber-600); margin-left: 5px; vertical-align: -2px; }

.tk-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.tk-count {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; color: var(--ink-3);
}

.tk-chip {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11.5px; color: var(--ink-3);
}
.tk-chip .ico { width: 13px; height: 13px; }

.tk-due {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; color: var(--ink-3); white-space: nowrap;
}
.tk-due.is-late { color: var(--orange-600); font-weight: 600; }

.tk-unassigned { background: var(--line-2); color: var(--ink-4); }

/* Linked Drive documents sit under their item, indented to match. */
.tk-links { padding: 0 20px 9px 38px; display: flex; flex-wrap: wrap; gap: 8px; }
.tk-links.tk-l3 { padding-left: 64px; }
.tk-link {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; padding: 3px 9px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2);
}
.tk-link:hover { border-color: var(--blue-500); color: var(--blue-600); text-decoration: none; }
.tk-link .ico { width: 13px; height: 13px; opacity: .6; }

/* Activity timeline. Comments and events in one stream. */
.tl { padding: 6px 0; }
.tl-row { display: flex; gap: 12px; padding: 10px 20px; }
.tl-dot {
  width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0;
  background: var(--blue-500);
}
.tl-dot.is-event { background: var(--line); border: 1px solid var(--ink-4); }
.tl-body { flex: 1; min-width: 0; }
.tl-head { display: block; font-size: 13px; }
.tl-when { color: var(--ink-4); font-size: 12px; margin-left: 8px; }
.tl-text { display: block; font-size: 14px; color: var(--ink-2); margin-top: 3px; }

/* A system entry states a fact about the record; a note is somebody recording
   a conversation. One line, muted, icon-led, and no author in bold -- the
   shape is the signal, so it reads as different before it is read at all. */
.tl-row.is-sys { padding-top: 5px; padding-bottom: 5px; }
.tl-sys {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--ink-3);
}
.tl-sys .ico { width: 13px; height: 13px; color: var(--ink-4); flex-shrink: 0; }

/* ---------- Projects: editing controls ---------- */

/* Disclosure blocks used for forms that would otherwise crowd the page. */
.disc > summary { display: inline-flex; list-style: none; cursor: pointer; }
.disc > summary::-webkit-details-marker { display: none; }

/* Status select styled as a badge so it reads as state, not as a form control
   until you go to change it. */
.tk-statusform { margin: 0; }
.tk-status {
  width: auto; padding: 2px 22px 2px 8px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  border-radius: 999px; border: 1px solid transparent; cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='3'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 6px center;
}
.tk-status:focus { box-shadow: 0 0 0 3px var(--blue-100); }
.s-not_started { background-color: var(--line-2);     color: var(--ink-3); }
.s-in_progress { background-color: var(--blue-100);   color: var(--blue-600); }
.s-blocked     { background-color: var(--red-100);    color: var(--red-600); }
.s-in_review   { background-color: var(--purple-100); color: var(--purple-600); }
.s-done        { background-color: var(--green-100);  color: var(--green-600); }
.s-cancelled   { background-color: var(--line-2);     color: var(--ink-4); }

/* Per-item edit panel */
.tk-edit { position: relative; }
.tk-edit > summary {
  list-style: none; cursor: pointer; padding: 3px;
  border-radius: var(--r-sm); color: var(--ink-4); display: inline-flex;
}
.tk-edit > summary::-webkit-details-marker { display: none; }
.tk-edit > summary:hover { background: var(--line-2); color: var(--blue-600); }
.tk-edit[open] > summary { background: var(--blue-100); color: var(--blue-600); }

.tk-panel {
  position: absolute; right: 0; top: 28px; z-index: 20; width: 420px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 8px 24px rgba(15, 23, 42, .12);
  padding: 16px;
}
.tk-panel .field { margin-bottom: 10px; }
.tk-sub {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line);
}
.tk-danger { display: flex; align-items: center; gap: 10px; }
.tk-danger .btn { color: var(--red-600); border-color: var(--red-100); }
.tk-danger .btn:hover { background: var(--red-100); }

/* Add-a-task bar at the foot of the tree */
.tk-addbar { border-top: 1px solid var(--line); padding: 12px 20px; background: var(--canvas); }
.tk-addbar form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.tk-addbar input[name=title] { flex: 1; min-width: 220px; }
.tk-addbar input[name=assignee] { width: 210px; }
.tk-addbar input[type=date] { width: 150px; }

textarea { font: inherit; resize: vertical; }

/* ---------- Projects: task groups ---------- */
/* Each task and its subtasks render as one bounded block. The rail down the
   left carries the task's health colour, so the grouping and the status are a
   single signal rather than two competing ones. */

.tkg-head-bar { display: flex; align-items: baseline; margin: 0 0 12px; }

.tkg {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 4px solid var(--h, var(--line));
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  margin-bottom: 14px;
  overflow: visible;
}

/* Task header. Tinted so it reads as the head of a group, not another row. */
.tkg-head {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 18px;
  background: linear-gradient(to right,
              color-mix(in srgb, var(--h, var(--line)) 7%, transparent), transparent 60%);
  border-bottom: 1px solid var(--line);
  border-radius: 0 var(--r) 0 0;
}

.tkg-title { font-size: 15px; font-weight: 650; letter-spacing: -.01em; }

.tkg-prog { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.tkg-bar {
  display: block; width: 74px; height: 5px;
  background: var(--line); border-radius: 3px; overflow: hidden;
}
.tkg-fill { display: block; height: 100%; background: var(--h, var(--blue-500)); }
.tkg-count {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; color: var(--ink-3);
}

.tkg-notes {
  padding: 10px 18px 0; font-size: 13.5px; color: var(--ink-2);
}

.tkg-links { padding: 10px 18px 0; display: flex; flex-wrap: wrap; gap: 8px; }

/* Subtasks sit on a recessed panel, visually inside the task above them. */
.tkg-subs { background: var(--canvas); border-radius: 0 0 var(--r) 0; }

.tks {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 18px 9px 30px;
  border-bottom: 1px solid var(--line-2);
  position: relative;
}
.tks.is-done .tks-title { color: var(--ink-3); text-decoration: line-through; }

/* Connector: a short tick joining each subtask to the group rail. */
.tks::before {
  content: ""; position: absolute; left: 16px; top: 50%;
  width: 8px; height: 1px; background: var(--line);
}

.tks-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--h, var(--ink-4)); flex-shrink: 0;
}
.tks-main { flex: 1; min-width: 0; }
.tks-title { font-size: 13.5px; color: var(--ink-2); }

.tks-links { padding: 0 18px 9px 38px; background: var(--canvas); }

/* Inline add row, styled to sit quietly until used. */
.tks-add {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 9px 18px 11px 30px;
}
.tks-add input {
  font-size: 13px; padding: 5px 9px;
  background: transparent; border-color: transparent;
}
.tks-add input:hover { border-color: var(--line); background: var(--surface); }
.tks-add input:focus { background: var(--surface); }
.tks-add input[name=title] { flex: 1; min-width: 180px; }
.tks-add input[name=assignee] { width: 180px; }
.tks-add input[type=date] { width: 140px; }
.tks-add .btn { opacity: .55; }
.tks-add:hover .btn, .tks-add:focus-within .btn { opacity: 1; }

/* New-task bar at the foot of the project */
.tkg-newtask form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.tkg-newtask input[name=title] { flex: 1; min-width: 220px; }
.tkg-newtask input[name=assignee] { width: 210px; }
.tkg-newtask input[type=date] { width: 150px; }

/* The edit popover opens leftward inside a group so it never clips. */
.tkg .tk-panel { right: 0; left: auto; }

/* Subtasks read as white rows; hover supplies the position cue. */
.tkg-subs { background: var(--surface); }
.tks { background: var(--surface); }
.tks:hover { background: var(--line-2); }
.tks-links { background: var(--surface); }
.tks-add input:hover { background: var(--canvas); }

.tkg { box-shadow: 0 1px 3px rgba(15, 23, 42, .10), 0 1px 2px rgba(15, 23, 42, .06); }

/* Assignee pickers in the inline add rows keep the quiet treatment. */
.tks-add select, .tkg-newtask select {
  font-size: 13px; padding: 5px 9px; width: 190px;
}
.tks-add select { background: transparent; border-color: transparent; }
.tks-add select:hover { border-color: var(--line); background: var(--surface); }

/* ---------- My work ---------- */

.mw-sec {
  padding: 10px 20px 4px; background: var(--canvas);
  border-bottom: 1px solid var(--line-2);
}
.mw-sec-name {
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
.mw-sec-name:hover { color: var(--blue-600); text-decoration: none; }

.mw-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 20px; border-bottom: 1px solid var(--line-2);
  color: inherit; border-left: 3px solid transparent;
}
.mw-row:last-child { border-bottom: none; }
.mw-row:hover { background: var(--line-2); text-decoration: none; }
.mw-row.is-late { border-left-color: var(--orange-600); }

.mw-level {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-4); width: 54px; flex-shrink: 0;
}
.mw-title { font-size: 14px; font-weight: 500; }

.mw-due {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; color: var(--ink-3); white-space: nowrap;
}
.mw-due.is-soon { color: var(--amber-600); }
.mw-due.is-late { color: var(--orange-600); font-weight: 600; }

.mw-clear {
  display: flex; align-items: center; gap: 9px;
  padding: 22px 20px; color: var(--ink-3); font-size: 14px;
}
.mw-clear .ico { color: var(--green-600); opacity: .7; }

/* ---------- Home: two-column widget row ---------- */

.home-cols {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 16px; align-items: start; margin-bottom: 20px;
}
@media (max-width: 1000px) { .home-cols { grid-template-columns: 1fr; } }

/* Truncate to two lines. The full text is one click away rather than gone. */
.clamp {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

.home-cols .rw-item { padding: 12px 16px; }
.home-cols .rw-title { font-size: 13.5px; }
.home-cols .rw-dek { font-size: 13px; margin-bottom: 4px; }
.home-cols .rw-body { font-size: 13px; }
.home-cols .card-hd { padding: 11px 16px; }

.rw-more-d > summary {
  list-style: none; cursor: pointer;
  font-size: 12px; font-weight: 600; color: var(--blue-600);
  padding: 2px 0;
}
.rw-more-d > summary::-webkit-details-marker { display: none; }
.rw-more-d > summary::after { content: "\2026"; margin-left: 3px; letter-spacing: 1px; }
.rw-more-d[open] > summary::after { content: ""; }
.rw-more-d[open] > summary { color: var(--ink-3); }
.rw-more-d > summary:hover { text-decoration: underline; }

/* Compact My work rows */
.mw-row.is-compact { padding: 9px 16px; gap: 8px; align-items: flex-start; }
.mw-body { flex: 1; min-width: 0; }
.mw-row.is-compact .mw-title { font-size: 13.5px; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mw-sub { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }
.mw-row.is-compact .badge { flex-shrink: 0; margin-top: 1px; }

/* Granted project view: the viewer's own items are picked out. */
.gt-note { display: flex; align-items: flex-start; gap: 10px;
           font-size: 13px; color: var(--ink-2); }
.gt-note .ico { color: var(--blue-600); flex-shrink: 0; margin-top: 2px; }
.tks.is-mine { background: var(--blue-50); }
.tks.is-mine:hover { background: var(--blue-100); }
.tks.is-mine .tks-title { font-weight: 600; color: var(--ink); }

/* Assignee type-ahead in the compact add rows keeps the quiet treatment. */
.tks-add input[name=assignee], .tkg-newtask input[name=assignee] { width: 190px; }

/* ---------- Section project rollup ---------- */

.sr-strip {
  display: flex; gap: 26px; padding: 14px 20px;
  border-bottom: 1px solid var(--line); background: var(--canvas);
}
.sr-stat { display: flex; flex-direction: column; }
.sr-num { font-size: 20px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.sr-num.is-bad  { color: var(--red-600); }
.sr-num.is-warn { color: var(--orange-600); }
.sr-lbl {
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}

.sr-row {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 20px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.sr-row:last-child { border-bottom: none; }
.sr-row:hover { background: var(--canvas); text-decoration: none; }
.sr-row .grow { flex: 1; min-width: 0; }
.sr-row .name { display: block; font-weight: 600; font-size: 13.5px; }
.sr-row .sub  { display: block; font-size: 12px; color: var(--ink-3); }

.sr-more { padding: 10px 20px; border-top: 1px solid var(--line-2); font-size: 12.5px; }

/* Per-project stats replace the section-wide strip. */
.sr-strip { display: none; }

.sr-stats { display: flex; gap: 14px; margin-top: 2px; }
.sr-s {
  font-size: 12px; color: var(--ink-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.sr-s b { font-weight: 700; color: var(--ink-2); font-size: 12.5px; }
.sr-s.is-bad, .sr-s.is-bad b { color: var(--red-600); }
.sr-s.is-warn, .sr-s.is-warn b { color: var(--orange-600); }

/* A zero count still reports, but recedes: present without competing for
   attention with the counts that carry a number worth acting on. */
.sr-s.is-nil, .sr-s.is-nil b { color: var(--ink-4); font-weight: 500; }

/* Drive attachments: detach sits inside the chip, revealed on hover. */
.tk-linkwrap { display: inline-flex; align-items: stretch; }
.tk-linkwrap .tk-link { border-radius: var(--r-sm) 0 0 var(--r-sm); border-right: none; }
.tk-linkwrap form { display: flex; }
.tk-detach {
  border: 1px solid var(--line); border-left: none;
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--surface); color: var(--ink-4);
  cursor: pointer; padding: 0 7px; font-size: 14px; line-height: 1;
}
.tk-detach:hover { background: var(--red-100); color: var(--red-600); border-color: var(--red-100); }

/* File input in the edit panel */
.tk-panel input[type=file] {
  width: 100%; font-size: 12.5px; padding: 6px;
  border: 1px dashed var(--line); border-radius: var(--r-sm);
  background: var(--canvas); cursor: pointer;
}
.tk-panel input[type=file]:hover { border-color: var(--blue-500); }

/* Group badges take the accent of the department they grant, so a badge and
   that department's tile below read as the same thing. */
.badge.grp {
  background: var(--a-bg, var(--blue-50));
  color: var(--a, var(--blue-600));
  border: 1px solid var(--a-br, var(--blue-100));
}
.badge.grp.is-admin {
  background: var(--red-100); color: var(--red-600);
  border-color: var(--red-600); font-weight: 800;
}

/* ---------- Landing page ---------- */
/* Standalone: no nav, no user. The navy carries the brand, the card carries
   the one action. */

body.lp {
  background:
    radial-gradient(1100px 520px at 50% -12%, var(--navy-700) 0%, transparent 62%),
    var(--navy-900);
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 40px 20px;
}

.lp-wrap { width: 100%; max-width: 480px; }

.lp-card {
  background: var(--surface);
  border-radius: 16px;
  padding: 34px 34px 26px;
  box-shadow: 0 18px 50px rgba(6, 15, 38, .40), 0 2px 6px rgba(6, 15, 38, .22);
}

.lp-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 26px; }
/* The same lockup as the header, at the same 38px: the logo carries the name,
   so the .lp-name that spelled out an abbreviation beside it is gone rather
   than left unreferenced. This one sits on the white sign-in card, so it is
   the light asset -- Dignity Blue wordmark -- not the header's white one. */
.lp-brand img { height: 38px; width: auto; }
.lp-sub {
  font-size: 11px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3);
}

.lp-h1 { font-size: 27px; font-weight: 700; letter-spacing: -.025em; margin: 0 0 8px; }
.lp-lede { color: var(--ink-3); font-size: 14.5px; line-height: 1.55; margin: 0 0 24px; }

/* The single action on the page. */
.lp-btn {
  display: flex; align-items: center; justify-content: center; gap: 11px;
  width: 100%; padding: 13px 18px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
  font-size: 15px; font-weight: 600;
  box-shadow: var(--shadow-sm);
  transition: border-color .12s, box-shadow .12s, transform .12s;
}
.lp-btn:hover {
  text-decoration: none; border-color: var(--blue-500);
  box-shadow: 0 3px 10px rgba(37, 99, 235, .16); transform: translateY(-1px);
}
.lp-btn:active { transform: none; }

.lp-note {
  font-size: 12.5px; color: var(--ink-3); text-align: center;
  margin: 12px 0 0; line-height: 1.5;
}
.lp-note strong { color: var(--ink-2); font-weight: 600; }

.lp-feats {
  margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 15px;
}
.lp-feat { display: flex; align-items: flex-start; gap: 12px; }
.lp-feat strong { display: block; font-size: 13.5px; margin-bottom: 1px; }
.lp-feat span { font-size: 12.5px; color: var(--ink-3); line-height: 1.45; }

.lp-foot {
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line-2);
  font-size: 12.5px; color: var(--ink-3); text-align: center;
}

.lp-tag {
  text-align: center; margin-top: 18px;
  font-size: 12px; color: rgba(255, 255, 255, .45); letter-spacing: .02em;
}

@media (max-width: 420px) {
  .lp-card { padding: 26px 22px 20px; }
  .lp-h1 { font-size: 23px; }
}

/* Denied page: reuses the landing card, with a mark that signals a stop
   without being alarming. Being refused is usually an administrative gap,
   not a mistake the person made. */
.dn-mark {
  width: 48px; height: 48px; border-radius: 12px;
  background: var(--amber-100); color: var(--amber-600);
  display: grid; place-items: center; margin-bottom: 18px;
}
.lp-btn .ico { color: var(--ink-3); }

/* ---------- Document library ---------- */

.lb-path {
  display: flex; align-items: center; flex-wrap: wrap; gap: 2px;
  margin-bottom: 12px; font-size: 13.5px;
}
.lb-path a { display: inline-flex; align-items: center; gap: 5px; color: var(--ink-2); }
.lb-path a:hover { color: var(--blue-600); text-decoration: none; }
.lb-path .ico { width: 15px; height: 15px; opacity: .6; }
.lb-sep { color: var(--ink-4); padding: 0 6px; }
.lb-here { font-weight: 600; }

.lb-name { display: inline-flex; align-items: center; gap: 9px; color: inherit; font-size: 14px; }
.lb-name:hover { color: var(--blue-600); text-decoration: none; }
.lb-ico { width: 17px; height: 17px; color: var(--ink-3); flex-shrink: 0; }
.lb-ico.is-folder { color: var(--blue-500); }
.lb-ext { width: 12px; height: 12px; opacity: .35; }

table.lb tbody td { padding: 9px 16px; }

.lb-actions { display: flex; gap: 24px; flex-wrap: wrap; align-items: center; }
.lb-actions form { display: flex; gap: 8px; align-items: center; }
.lb-actions input[type=file] {
  font-size: 12.5px; padding: 6px;
  border: 1px dashed var(--line); border-radius: var(--r-sm);
  background: var(--canvas); cursor: pointer; width: 260px;
}
.lb-actions input[name=name] { width: 200px; }

/* Compact document rows on a department page. */
.lb-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 20px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.lb-row:last-child { border-bottom: none; }
.lb-row:hover { background: var(--canvas); text-decoration: none; }
.lb-row .grow { flex: 1; min-width: 0; }
.lb-row .name { font-size: 13.5px; }

/* Upload and folder creation as separate cards: two forms sharing a row made
   the browser's validation bubble appear against the wrong control. */
.lb-two {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 14px; margin-top: 14px;
}
@media (max-width: 800px) { .lb-two { grid-template-columns: 1fr; } }
.lb-two input[type=file] {
  width: 100%; font-size: 12.5px; padding: 7px;
  border: 1px dashed var(--line); border-radius: var(--r-sm);
  background: var(--canvas); cursor: pointer;
}
.lb-two input[type=file]:hover { border-color: var(--blue-500); }

/* Folders read as containers, not documents: tinted row, filled icon, and a
   chevron implying you go into them rather than open them. */
table.lb tbody tr.is-dir { background: var(--canvas); }
table.lb tbody tr.is-dir:hover { background: var(--blue-50); }
table.lb tbody tr.is-dir td { border-bottom-color: var(--line); }
table.lb tbody tr.is-dir .lb-name { font-weight: 600; }

table.lb tbody tr.is-dir .lb-ico {
  color: var(--blue-600);
  fill: var(--blue-100);
}

table.lb tbody tr.is-dir .lb-name::after {
  content: "\203A";
  margin-left: 7px; color: var(--ink-4);
  font-weight: 700; font-size: 15px; line-height: 1;
}

/* Size is meaningless for a folder; the empty cell reinforces the difference. */
table.lb tbody tr.is-dir td:nth-child(3) { color: var(--ink-4); }

/* ---------- Folder tree ---------- */

/* Two panes as one surface: folders left, contents right, no gap between them
   so it reads as a file manager rather than two adjacent cards. Stretched, so
   an empty folder still looks like a pane instead of collapsing to a header
   strip and letting whatever is below creep up beside the tree. */
/* **The folder pane is yours to size, and it remembers.** It was 236px, and
   measured across the real trees that truncates 12 folder names, the worst
   short by 54px -- so the 15% Andrew asked for (271px) would still have cut
   it. Any fixed number only fixes today's names, because the indent of a
   nested folder eats the width as well as the name does.
   So: a wider default that clears every name we hold, and a handle. Clamped
   between 200 and 460 so the files always keep a usable pane -- the folders
   cannot take the page. The width is a per-viewer convenience and lives in
   `localStorage`, which is what that is for. */
.lb-layout {
  display: grid;
  grid-template-columns: var(--lb-tree-w, 290px) 6px minmax(0, 1fr);
  gap: 0; align-items: stretch;
}
/* A size is one short token and must not wrap: "11.8 KB" over two lines is
   wider than the column it was trying to fit, and reads as two figures. */
/* **The selection bar, and the column it reads.** Upload takes five hundred;
   everything after it took one at a time until this. The bar sits under the
   table rather than over it, because it acts on what is ticked above it. */
/* In the name cell rather than a column of its own: a seventh header would be
   a `<th>` with no link, and this table's header rule turns one of those into
   a flex box -- out of table layout, and the empty column took 266px off the
   name. */
.lb-tick { margin: 0 9px 0 0; cursor: pointer; vertical-align: middle; flex: none; }
}

.lb-size, .lb-size-h { white-space: nowrap; text-align: right; }
.lb-size-h { padding-right: 12px; }

.lb-grip {
  cursor: col-resize; position: relative; z-index: 4;
  background: transparent; border: 0; padding: 0;
}
.lb-grip::before {
  content: ""; position: absolute; inset: 0 2px;
  border-radius: 2px; background: transparent; transition: background .12s;
}
.lb-grip:hover::before, .lb-grip:focus-visible::before,
.lb-layout.is-sizing .lb-grip::before { background: var(--frame); }
.lb-layout.is-sizing { user-select: none; }
/* Below the breakpoint the panes stack, so there is nothing to drag. */
@media (max-width: 900px) { .lb-grip { display: none; } }
@media (max-width: 900px) { .lb-layout { grid-template-columns: 1fr; } }

.lb-tree { position: sticky; top: calc(var(--header-h) + 20px); }
.lb-main { min-width: 0; }

.ft { padding: 6px 0 10px; max-height: 62vh; overflow-y: auto; }

.ft-list { list-style: none; margin: 0; padding: 0; }
.ft-list li { margin: 0; }

/* Depth is a CSS variable so nesting indents without a rule per level. */
.ft-list { --step: 13px; }
/* The indent belongs to the row, not to the link inside it. Matching every
   .ft-list a caught the anchor nested in a summary too, so a folder with
   children was indented twice and sat a level below its siblings. */
.ft-list > li > .ft-leaf-row,
.ft-node > summary {
  padding-left: calc(14px + (var(--d, 0) + 1) * var(--step));
}

.ft-root,
.ft-leaf,
.ft-node > summary {
  display: flex; align-items: center; gap: 7px;
  padding: 5px 12px 5px 14px;
  font-size: 13px; color: var(--ink-2);
  border-left: 2px solid transparent;
  cursor: pointer;
}
.ft-root { padding-left: 14px; font-weight: 600; }
.ft-root:hover, .ft-leaf:hover, .ft-node > summary:hover {
  background: var(--line-2); text-decoration: none;
}

.ft-node > summary { list-style: none; }
.ft-node > summary::-webkit-details-marker { display: none; }
.ft-node > summary a { padding: 0; border: none; flex: 1; color: inherit; }
.ft-node > summary a:hover { text-decoration: none; }

.ft .ico { width: 15px; height: 15px; color: var(--blue-500); flex-shrink: 0; }
.ft-root .ico { color: var(--ink-3); }

.is-current {
  background: var(--blue-50) !important;
  border-left-color: var(--blue-600) !important;
  color: var(--blue-600); font-weight: 600;
}
.is-current .ico { color: var(--blue-600); }

.ft-caret {
  width: 0; height: 0; flex-shrink: 0;
  border-left: 4px solid var(--ink-4);
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transition: transform .12s ease;
}
.ft-node[open] > summary .ft-caret { transform: rotate(90deg); }

/* The base .ft-* rule uses the padding shorthand, which resets padding-left and
   flattens every folder that has children. Restated here so depth indentation
   survives, since equal specificity means source order decides. */
.ft-node > summary,
.ft-list > li > .ft-leaf-row {
  padding-left: calc(14px + (var(--d, 0) + 1) * var(--step, 13px));
}

/* **The listing scrolls sideways again.** This wrapper was forced to
   `overflow: visible` so an absolutely positioned row panel would not be
   clipped -- with the note that "the library table has no wide columns, so the
   wrapper does not need to scroll here". It does: measured at 390, a
   department with ordinary file names pushed the *document* to 526px with
   nothing to drag, and that was before the Size column. The row menus are
   positioned fixed now, exactly as the folder menus already were, so nothing
   needs clipping to be switched off. The card stays visible for the same
   panels' sake. */
.lb-main .card { overflow: visible; }

/* Always open downward. Flipping upward puts the panel under the sticky header
   on short tables, where it cannot be scrolled to. */
.lb-main table.lb tbody tr:last-child .tk-panel { top: 28px; bottom: auto; }

/* ---------- Documentation tiers ---------- */

/* Admin-only material is marked at the container, not per row: the boundary is
   the point, and a badge on every line reads as noise. */
.dc-admin { border-color: var(--red-100); }
.dc-admin .card-hd { background: var(--red-100); border-bottom-color: var(--red-100); }
.dc-admin .card-hd h3 { color: var(--red-600); }
.dc-note {
  padding: 10px 20px; border-top: 1px solid var(--line-2);
  font-size: 12px; color: var(--ink-3);
}

.dc-banner {
  display: flex; align-items: center; gap: 10px;
  border-left: 3px solid var(--red-600);
  font-size: 13px; color: var(--ink-2);
}
.dc-banner .ico { color: var(--red-600); flex-shrink: 0; }

/* Breadcrumbs: the trail is muted, the current page is not, and a restricted
   segment carries its own colour so the tier is visible without reading. */
.crumbs { display: flex; align-items: center; flex-wrap: wrap; }
.crumbs a { color: var(--ink-3); }
.crumbs a:hover { color: var(--blue-600); }
.crumb-here { color: var(--ink); font-weight: 600; }
.crumb-dev {
  color: var(--red-600); font-weight: 600;
  background: var(--red-100); padding: 1px 8px; border-radius: 999px;
  font-size: 12px;
}

/* ---------- Document governance ---------- */

.dg-head {
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 8px;
}

/* Two distinct warnings that can appear together: the document changed after
   it was approved, and a scheduled review is due. Different icons and colours
   so one is not mistaken for the other. */
.dg-warn    { width: 14px; height: 14px; color: var(--orange-600); margin-left: 5px; vertical-align: -2px; }
.dg-due     { width: 14px; height: 14px; color: var(--amber-600);  margin-left: 5px; vertical-align: -2px; }
.dg-overdue { width: 14px; height: 14px; color: var(--red-600);    margin-left: 5px; vertical-align: -2px; }

.dg-drift { color: var(--orange-600); }

.tk-panel .dg-head + form .field { margin-bottom: 8px; }

/* Status cell is the way into a document's governance page. */
.dg-link { color: inherit; display: inline-flex; align-items: center; }
.dg-link:hover { text-decoration: none; }
.dg-set {
  font-size: 12px; color: var(--ink-4);
  border: 1px dashed var(--line); border-radius: 999px; padding: 1px 9px;
}
.dg-link:hover .dg-set { border-color: var(--blue-500); color: var(--blue-600); }

.doc-cols {
  display: grid; grid-template-columns: minmax(0, 1fr) 320px;
  gap: 16px; align-items: start;
}
@media (max-width: 900px) { .doc-cols { grid-template-columns: 1fr; } }

.dg-banner {
  display: flex; align-items: center; gap: 10px;
  border-left: 3px solid var(--orange-600);
  font-size: 13.5px; color: var(--ink-2);
}
.dg-banner .ico { color: var(--orange-600); flex-shrink: 0; }
.dg-banner .grow { flex: 1; }
.dg-banner.is-overdue { border-left-color: var(--red-600); }
.dg-banner.is-overdue .ico { color: var(--red-600); }
.dg-banner.is-due { border-left-color: var(--amber-600); }
.dg-banner.is-due .ico { color: var(--amber-600); }

/* Publication: a stale published copy is a standing condition, not an error,
   so it reads as a note rather than a banner. */
.pb-stale {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--orange-100); border-radius: var(--r-sm);
  font-size: 12.5px; color: var(--ink-2);
}
.pb-stale .ico { width: 15px; height: 15px; color: var(--orange-600); flex-shrink: 0; }

/* ---------- Row action menu ---------- */
/* A list of operations, the way a file manager behaves. Anything needing more
   than one field lives on the document page instead: forms competing for space
   inside a popover was both ungainly and the source of a submission bug. */

.tk-menu {
  position: absolute; right: 0; top: 28px; z-index: 20; min-width: 232px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 8px 24px rgba(15, 23, 42, .14);
  padding: 5px;
}

.tk-mi {
  display: flex; align-items: flex-start; gap: 9px; width: 100%;
  padding: 7px 10px; border-radius: var(--r-sm);
  font-size: 13.5px; color: var(--ink-2); text-align: left;
  background: none; border: none; cursor: pointer; font-family: inherit;
  list-style: none;
}
.tk-mi::-webkit-details-marker { display: none; }
.tk-mi:hover { background: var(--line-2); color: var(--ink); text-decoration: none; }
.tk-mi .ico { width: 15px; height: 15px; color: var(--ink-3); flex-shrink: 0; margin-top: 1px; }
.tk-mi:hover .ico { color: var(--blue-600); }

/* Secondary line explaining what a destination holds. */
.tk-mi em {
  display: block; font-style: normal; font-size: 11.5px;
  color: var(--ink-4); margin-top: 1px;
}

.tk-mi.is-danger { color: var(--red-600); }
.tk-mi.is-danger .ico { color: var(--red-600); }
.tk-mi.is-danger:hover { background: var(--red-100); }

.tk-div { height: 1px; background: var(--line-2); margin: 5px 8px; }

/* A sub-menu with nothing to offer says so rather than drawing an empty
   picker: an empty select is a control that looks broken. */
/* A success, said plainly and not coloured like a refusal. Green enough to
   read as "that worked", quiet enough not to compete with the page. */
.lb-notice {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 16px; padding: 10px 14px;
  border: 1px solid var(--green-300, var(--line));
  border-left: 3px solid var(--green-600);
  border-radius: var(--r); background: var(--surface);
}
.lb-notice .ico { width: 16px; height: 16px; color: var(--green-600); flex: none; }
.lb-notice strong { font-size: 13.5px; color: var(--ink); }

/* The row being carried. Faded rather than removed, so the tree keeps its
   shape while somebody looks for where to put it. */
.ft [data-folder-id][draggable="true"] { cursor: grab; }
.ft .is-lifting { opacity: .45; }

.tk-none { margin: 0; padding: 4px 10px 8px; font-size: 12.5px; color: var(--ink-3); }

/* Rename and move expand in place rather than opening another surface. */
.tk-sub-menu[open] > .tk-mi { background: var(--line-2); color: var(--ink); }
.tk-form { display: flex; gap: 6px; padding: 4px 10px 9px; }
.tk-form input, .tk-form select { font-size: 13px; padding: 5px 8px; flex: 1; min-width: 0; }
.tk-form .btn { flex-shrink: 0; }

/* The menu reads as a surface lifted off the page: tinted rather than white,
   with a heavier shadow, so it is obviously a thing you dismiss. */
.tk-menu {
  background: var(--canvas);
  border-color: var(--ink-4);
  box-shadow: 0 12px 32px rgba(15, 23, 42, .22), 0 2px 6px rgba(15, 23, 42, .12);
}
.tk-mi:hover { background: var(--surface); }
.tk-sub-menu[open] > .tk-mi { background: var(--surface); }
.tk-div { background: var(--line); }

/* Publication state in the file list. A published copy that has fallen behind
   its source is squared off rather than rounded, so the difference reads
   without relying on colour alone. */
.pb-pill {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 6px; padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .03em;
  background: var(--green-100); color: var(--green-600);
  border: 1px solid var(--green-100);
  white-space: nowrap;
}
.pb-pill .ico { width: 12px; height: 12px; }
.pb-pill.is-stale {
  /* Same word, same shape: only the colour changes, so the reader sees a
     publication that needs attention rather than a different state. */
  background: var(--red-100); color: var(--red-600);
  border-color: var(--red-600);
}


.lb-tree > .card {
  border-radius: var(--r) 0 0 var(--r);
  border-right: none;
  box-shadow: none;
}
.lb-main > .card:first-child {
  border-radius: 0 var(--r) var(--r) 0;
  box-shadow: none;
}
.lb-tree > .card .card-hd { border-radius: var(--r) 0 0 0; }

/* The tree pane should not be shorter than the list beside it. */
.lb-tree { align-self: stretch; }
.lb-tree > .card { height: 100%; }

/* Climb-out row: part of the listing, but clearly not a document. */
tr.lb-up td { background: var(--canvas); padding: 7px 16px; }
tr.lb-up a {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; color: var(--ink-3);
}
tr.lb-up a:hover { color: var(--blue-600); text-decoration: none; }
tr.lb-up .ico { width: 15px; height: 15px; }

@media (max-width: 900px) {
  /* No tree on a narrow screen, so folders return to the table. */
  .lb-layout { gap: 14px; }
  .lb-tree > .card, .lb-main > .card:first-child { border-radius: var(--r); border-right: 1px solid var(--line); }
}

/* Folder rows in the table are the narrow-screen fallback only. */
/* "Files in <folder>", drawn only where the card stacks under the tree, so the
   two read as navigation and contents. Beside the tree it would say what the
   tree's highlighted row already says. */
.lb-files-hd { display: none; }
@media (max-width: 900px) {
  /* The tree stays put beside the files on a wide screen; stacked above them
     it would sit over the files as they scroll, which is what it did. */
  .lb-layout .lb-tree { position: static; }
  .lb-files-hd { display: block; padding: 10px 14px 4px; font-weight: 650; font-size: 14px; color: var(--ink); }
}

.lb-main { display: flex; flex-direction: column; }
.lb-main > .card:first-child { flex: 1; min-height: 260px; }

/* The action cards belong under the whole file manager, not beside it. */
.lb-two { clear: both; }

/* Centre the empty state in the pane it now fills. */
.lb-main > .card:first-child .empty {
  display: flex; flex-direction: column; justify-content: center;
  align-items: center; flex: 1; min-height: 200px;
}
.lb-main > .card:first-child .table-wrap { flex: 1; }

.lb-uponly {
  padding: 10px 18px; border-bottom: 1px solid var(--line-2);
  background: var(--canvas);
}
.lb-uponly a {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; color: var(--ink-3);
}
.lb-uponly a:hover { color: var(--blue-600); text-decoration: none; }
.lb-uponly .ico { width: 15px; height: 15px; }

/* ---------- Tree folder menus ---------- */

/* Each folder carries its own actions. Creating a folder is an operation on a
   folder, so it belongs beside one rather than in a permanent card. */
.ft-leaf-row {
  display: flex; align-items: center;
  border-left: 2px solid transparent;
}
.ft-leaf-row > .ft-leaf,
.ft-leaf-row > .ft-root { flex: 1; border-left: none; }
.ft-leaf-row:hover { background: var(--line-2); }
.ft-leaf-row.is-current { background: var(--blue-50); border-left-color: var(--blue-600); }
.ft-leaf-row.is-current > a { background: none; border-left: none; }

.ft-menu { position: relative; flex-shrink: 0; }
.ft-menu > summary {
  list-style: none; cursor: pointer; padding: 3px 8px 3px 4px;
  color: var(--ink-4); display: flex; opacity: 0;
}
.ft-menu > summary::-webkit-details-marker { display: none; }
.ft-menu > summary .ico { width: 15px; height: 15px; }
.ft-leaf-row:hover .ft-menu > summary,
.ft-node > summary:hover .ft-menu > summary,
.ft-menu[open] > summary { opacity: 1; }
.ft-menu > summary:hover { color: var(--blue-600); }
.ft-menu .tk-menu { left: auto; right: -4px; min-width: 244px; }

.nav-disc > summary .ft-menu, .ft-node > summary .ft-menu { margin-left: auto; }

/* ---------- Upload affordance ---------- */

/* **The way in, at the foot of the file pane, always on.** It was a green
   plus that opened a fold, which made the whole upload -- including dropping
   -- conditional on finding a button first. The rules for that disclosure are
   deleted rather than disabled, which is what this file records about retiring
   a component. The bar is left-aligned now that it is permanent content rather
   than an occasional action. */
.lb-foot {
  border-top: 1px solid var(--line); padding: 11px 16px;
  background: var(--canvas); border-radius: 0 0 var(--r) 0;
  /* One row: the upload controls and the sentence take what they need, and
     Trash sits at the far right of it -- Andrew asked for it on the same row
     as the upload buttons, all the way over. */
  display: flex; align-items: center; gap: 12px;
}
.lb-upload {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
}


/* The upload bar belongs at the foot of the pane, not immediately under the
   last row: with a short listing it otherwise floats mid-card. */
.lb-main > .card:first-child { display: flex; flex-direction: column; }
.lb-main > .card:first-child .table-wrap { flex: 0 0 auto; }
.lb-foot { margin-top: auto; }

/* One surface across both panes: the tinted strips made the file manager read
   as several stacked things rather than one. */
.lb-main tr.lb-up td { background: var(--surface); }
.lb-main .lb-foot { background: var(--surface); border-top: none; }
.lb-uponly { background: var(--surface); }

/* Column headers and the Folders heading share a height so the two panes line
   up along the top. */
.lb-tree > .card > .card-hd { padding: 11px 20px; min-height: 42px; }

/* Both pane headers to an identical height. A table cell and a flex header
   compute their own box differently, so the height is set explicitly on each
   rather than inferred from padding. */
.lb-tree > .card > .card-hd {
  height: 44px; padding: 0 20px; min-height: 0;
  border-bottom: 1px solid var(--line);
}

/* The climb-out row is part of the listing, not a section of its own. */
.lb-main tr.lb-up td { border-bottom: none; }

/* Faint column rules so the eye can track across a row without the grid
   becoming the loudest thing on the page. Not on the last column, which holds
   the row menu, and not on the climb-out row, which spans the table. */
.lb-main table.lb thead th:not(:last-child),
.lb-main table.lb tbody td:not(:last-child) {
  border-right: 1px solid var(--line-2);
}
.lb-main table.lb tr.lb-up td { border-right: none; }

/* The empty message sits inside the table so the columns stay visible, and
   fills the pane rather than hugging the header. */
.lb-main tr.lb-none td { border-right: none; border-bottom: none; padding: 0; }
.lb-main tr.lb-none .empty { padding: 48px 20px; }

/* Folder rows and file rows to a common height. They are different elements --
   flex items on the left, table cells on the right -- so neither inherits the
   other's box and both are set explicitly. */
.lb-tree .ft-leaf-row,
.lb-tree .ft-node > summary { min-height: 38px; }
.lb-tree .ft-root,
.lb-tree .ft-leaf,
.lb-tree .ft-node > summary { padding-top: 0; padding-bottom: 0; min-height: 38px; }
.lb-tree .ft-leaf-row > a { display: flex; align-items: center; }

.lb-main table.lb tbody td { height: 38px; padding-top: 0; padding-bottom: 0; }
.lb-main tr.lb-up td { height: 38px; }
.lb-main tr.lb-none td { height: auto; }

/* The tree starts flush with the first file row rather than with its own
   padding, so the two columns align from the top. */
.lb-tree .ft { padding-top: 0; }

/* Sortable column headers. The whole header is the target, and the active one
   carries its direction so the current sort is readable without hovering. */
.lb-main table.lb thead th > a,
.lb-main table.lb thead th:not(:has(a)) {
  display: flex; align-items: center; gap: 5px;
  height: 44px; padding: 0 16px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
.lb-main table.lb thead th > a:hover {
  background: var(--line-2); color: var(--ink); text-decoration: none;
}
.lb-main table.lb thead th.is-sorted > a { color: var(--blue-600); }
.th-dir { width: 13px; height: 13px; stroke-width: 3; }

/* The chevron carries the active sort. Colouring the label as well reads as a
   link, which these are not in any meaningful sense. */
.lb-main table.lb thead th.is-sorted > a { color: var(--ink-3); }
.th-dir { color: var(--ink-2); }

/* The non-sortable headers need the same box as the sortable ones, or the row
   grows to fit whichever is tallest. */
.lb-main table.lb thead th > a { height: 44px; }
.lb-main table.lb thead th:empty,
.lb-main table.lb thead th:not(:has(> a)) {
  padding: 0 16px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}

/* Header cells: the anchor fills the cell as a block rather than a flex item.
   A flex child inside a table cell does not stretch to it, which left the
   sortable headers on a different baseline from the plain ones and pushed the
   row taller than either. */
.lb-main table.lb thead th,
.lb-main table.lb thead th > a,
.lb-main table.lb thead th:not(:has(> a)) {
  display: table-cell;
  height: 44px;
  padding: 0 16px;
  vertical-align: middle;
  white-space: nowrap;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
/* The cell yields its padding to the anchor, which fills it -- so the whole
   header is the click target rather than just its text. */
.lb-main table.lb thead th { padding: 0; }
.lb-main table.lb thead th > a {
  display: block; line-height: 44px; height: 44px; padding: 0 16px;
}
.lb-main table.lb thead th > a:hover { background: var(--line-2); color: var(--ink); }
.th-dir { width: 13px; height: 13px; stroke-width: 3; vertical-align: -2px; margin-left: 3px; }

/* Provenance: a published copy names the department it came from, so the
   Company Library reads as a curated shelf rather than a shared drop box.
   Neutral rather than coloured -- it is a fact about the file, not a state
   needing attention. */
.pv-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
  background: var(--line-2); color: var(--ink-3);
  border: 1px solid var(--line);
  white-space: nowrap;
}
.pv-pill .ico { width: 12px; height: 12px; }

/* The tinted row is enough on its own; the rail alongside it was doing the
   same job twice. */
.lb-tree .ft-leaf-row.is-current,
.lb-tree .is-current { border-left-color: transparent; }

/* Timestamps in a fixed-width face so the columns line up rather than jittering
   with the digits. */
.lb-when {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; white-space: nowrap;
}

/* Provenance in purple: distinct from the green and red of publication state,
   since it is a different kind of fact about the file. */
.pv-pill {
  background: var(--purple-100);
  color: var(--purple-600);
  border-color: var(--purple-100);
}

/* Search sits under the file manager, right-aligned: it is an occasional
   action, so it should not lead the page. */
.lb-search { display: flex; justify-content: flex-end; margin-top: 14px; }
.lb-search form { display: flex; align-items: center; gap: 8px; }
.lb-search input[type=search] { width: 260px; }
.lb-search .btn .ico { width: 15px; height: 15px; }

/* The placeholder was being clipped at the default width. */
.lb-search input[type=search]::placeholder { color: var(--ink-4); }

/* The .btn.sm and a text input compute different heights from their own
   padding, so both are set explicitly here rather than left to agree. */
.lb-search input[type=search],
.lb-search .btn {
  height: 34px;
  padding-top: 0; padding-bottom: 0;
  line-height: 34px;
  box-sizing: border-box;
}
.lb-search .btn { display: inline-flex; align-items: center; }

/* ---------- Publication oversight ---------- */

.ov-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.ov-row:last-child { border-bottom: none; }
.ov-row:hover { background: var(--canvas); text-decoration: none; }
.ov-row .grow { flex: 1; min-width: 0; }
.ov-row .name { display: block; font-weight: 600; font-size: 14px; }
.ov-row .sub { display: block; font-size: 12.5px; color: var(--ink-3); }
.ov-row .chev { color: var(--ink-4); }

.ov-row.is-compact { padding: 10px 16px; }
.ov-row.is-compact .name { font-size: 13.5px; }

.ov-foot {
  padding: 10px 20px; border-top: 1px solid var(--line-2);
  font-size: 12px; color: var(--ink-3);
}

/* Link into the publication view, under the file manager beside search. */
/* **The whole card is the link, so the mark is laid over it rather than put
   in it.** A button nested in an anchor is not two controls; it is one the
   browser resolves however it likes, the same family as a form in a table
   cell. So the mark is a sibling, positioned inside the card's own edge just
   left of the chevron -- it reads as belonging to the card, which it does,
   without being inside the thing that navigates. */
/* **The card is the frame and the link covers it**, which is what lets the
   help mark sit at the end of the title rather than pinned to the right edge
   past the count and the chevron -- where it read as belonging to nothing.
   A button inside an anchor is not two controls, so the anchor stretches an
   empty `::after` over the card instead and the mark sits above it. */
.lb-published {
  margin-top: 14px; position: relative;
  display: flex; align-items: center; gap: 11px;
  padding: 11px 16px; border: 1px solid var(--line);
  border-radius: var(--r); background: var(--surface);
  color: var(--ink-2); box-shadow: var(--shadow-sm);
}
.lb-published:hover { border-color: var(--blue-500); }
.lb-published .ico { width: 15px; height: 15px; color: var(--green-600); }
.lb-published a.lb-pub-go { color: var(--ink); text-decoration: none; }
.lb-published a.lb-pub-go::after { content: ""; position: absolute; inset: 0; }
.lb-published:hover a.lb-pub-go { color: var(--blue-600); }
/* Above the anchor's overlay, or the mark opens the page instead of itself. */
.lb-published .help-dot { position: relative; z-index: 1; }
.lb-published span { flex: 1; min-width: 0; }
.lb-published strong { display: block; font-size: 13.5px; color: var(--ink); }
.lb-published em {
  display: block; font-style: normal; font-size: 12.5px; color: var(--ink-3);
}
.lb-published .chev { color: var(--ink-4); flex: none; }

/* Something waiting reads differently from a healthy state. */
.lb-published.has-work a { border-left: 3px solid var(--red-600); }
.lb-published.has-work .ico:first-child { color: var(--red-600); }

/* Access and publishing side by side, equal width, cards matching height. */
.home-pair {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 16px; align-items: start;
}
@media (max-width: 900px) { .home-pair { grid-template-columns: 1fr; } }
.home-pair > div { display: flex; flex-direction: column; }
.home-pair > div > h2 { margin-top: 0; }
.home-pair .card { flex: 1; }

/* Three personal cards in a row: what is assigned to you, what you owe as a
   publisher, and what you can reach. Equal columns, matched heights. */
.home-trio {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 16px; align-items: stretch; margin-top: 26px;
}
@media (max-width: 1100px) { .home-trio { grid-template-columns: 1fr 1fr; } }
@media (max-width: 760px) { .home-trio { grid-template-columns: 1fr; } }

.home-trio > div { display: flex; flex-direction: column; }
.home-trio .card { flex: 1; }

/* Narrower columns, so the contents tighten to match. */
.home-trio .card-hd { padding: 11px 14px; }
.home-trio .card-pad { padding: 14px; }
.home-trio .mw-row,
.home-trio .ov-row { padding: 9px 14px; }
.home-trio .badge { font-size: 10.5px; }

/* All three personal cards to one height, driven by the tallest rather than by
   whichever happens to have the most rows. */
.home-trio { align-items: stretch; }
.home-trio > div > .card,
.home-trio > div { height: 100%; }
.home-trio .card { display: flex; flex-direction: column; }
.home-trio .card .rows,
.home-trio .card .card-pad { flex: 1; }
.home-trio .ov-foot { margin-top: auto; }

/* The publishing card arrives inside an HTMX target div, one level deeper than
   the others, so the height rules need to reach through it. */
.home-trio > div > div[hx-get] { display: flex; flex-direction: column; flex: 1; }
.home-trio > div > div[hx-get] > .card { flex: 1; }

/* Department page document card: the library's shape rather than its most
   recent churn. Folder shortcuts are how people actually navigate a library. */
.ds-count { font-size: 13.5px; color: var(--ink-3); margin-bottom: 12px; }
.ds-count strong { color: var(--ink); font-weight: 700; }

.ds-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.ds-chips a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--surface);
  font-size: 13px; color: var(--ink-2);
}
.ds-chips a:hover {
  border-color: var(--blue-500); color: var(--blue-600); text-decoration: none;
}
.ds-chips .ico { width: 14px; height: 14px; color: var(--blue-500); }
.ds-chips a.is-more { color: var(--ink-3); border-style: dashed; }

/* Files sit indented under the folders above them, the way a file manager
   shows a level: containers at the margin, contents stepped in. */
.lb-row.is-file { padding-left: 38px; }

/* Solid manila folders. The outline version reads as a generic icon; a filled
   one is instantly a folder. */
.lb-ico.is-folder,
.ds-chips .ico,
.ft .ico,
.lb-name .lb-ico.is-folder,
table.lb tbody tr.is-dir .lb-ico {
  color: #d9a441;
  fill: #f0c46a;
}
.ft-root .ico { color: var(--ink-3); fill: none; }
.lb-tree .is-current .ico { color: #c8912f; fill: #f0c46a; }

/* The section root is a filing cabinet, filled slate: it is the container the
   whole library sits in, not another folder. */
.ft-root .ico,
.lb-path > a:first-child .ico {
  color: var(--ink-2);
  fill: #cbd5e1;
  opacity: 1;
}
.lb-tree .ft-leaf-row.is-rootrow.is-current .ft-root .ico {
  color: var(--ink); fill: #cbd5e1;
}

/* Department page cards: tighter rows. These are summaries meant to be
   scanned, not worked in, so they should not occupy the height of a table. */
.main .card > .rows > a.lb-row,
.main .card > .rows > a.sr-row,
.main .card > .rows > a.ov-row {
  padding-top: 7px; padding-bottom: 7px;
}
.main .card > .rows .name { font-size: 13.5px; }
.main .card > .rows .sub { font-size: 12px; }
.main .card > .rows .lb-ico { width: 16px; height: 16px; }

/* Home cards get the same treatment: they are read at a glance, so the rows
   should be dense enough to take in without scrolling. */
.home-trio .card .rows > a,
.home-trio .card .mw-row,
.home-trio .card .ov-row {
  padding-top: 7px; padding-bottom: 7px;
}
.home-trio .card .name { font-size: 13.5px; }
.home-trio .card .sub,
.home-trio .card .mw-sub { font-size: 11.5px; }

/* The Docket sits full width above them and reads the same way. */
.main > div[hx-get] .rw-item { padding-top: 11px; padding-bottom: 11px; }

/* Folders read as containers, files as their contents: the folder name carries
   weight and full contrast, the file name sits lighter and slightly smaller.
   Indentation alone was not enough to tell them apart at a glance. */
.main .card > .rows > a.lb-row:not(.is-file) .name {
  font-weight: 650;
  color: var(--ink);
  letter-spacing: -.005em;
}
.main .card > .rows > a.lb-row.is-file .name {
  font-weight: 400;
  color: var(--ink-2);
  font-size: 13px;
}

/* A hairline down the indent, so the files visibly hang off the level above. */
.main .card > .rows > a.lb-row.is-file { position: relative; }
.main .card > .rows > a.lb-row.is-file::before {
  content: ""; position: absolute; left: 26px; top: 0; bottom: 0;
  width: 1px; background: var(--line);
}

/* The Drive mark is a filled multicolour glyph, so it ignores the stroke and
   colour rules the Lucide icons use. */
.ico-drive { fill: none; stroke: none; }
.ico-drive path { stroke: none; }
.ico-box .ico-drive { width: 18px; height: 18px; }
.ico-box .ico-drive.ico-lg { width: 22px; height: 22px; }

.ft-menu .tk-menu { z-index: 40; }

/* The tree scrolls again now that its menus escape the container. */
.lb-tree .ft { overflow-y: auto; max-height: 62vh; }
.lb-tree > .card { overflow: hidden; }

/* Refresh sits beside search, both being things you reach for occasionally
   rather than actions on the listing itself. */
.lb-search { gap: 10px; }
.lb-refresh { margin-right: 4px; }
.lb-refresh .btn .ico { width: 15px; height: 15px; }

/* ---------- Docket industry tier ---------- */

/* Visibly a second section, not more of the first. The operational tier says
   what changes today; this says what a leader should know, and conflating them
   would let industry items paper over a quiet regulatory day. */
.rw-tier {
  display: flex; align-items: baseline; gap: 10px;
  padding: 12px 20px 8px; border-top: 1px solid var(--line);
  background: var(--canvas);
}
.rw-tier-label {
  font-size: 11px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-2);
}
.rw-tier-note { font-size: 12px; color: var(--ink-4); }

.rw-item.is-industry { border-left: 2px solid var(--line); }
.rw-item.is-industry .rw-title { font-size: 14px; font-weight: 600; }
.rw-why { font-size: 12.5px; color: var(--ink-3); margin: 4px 0 0; line-height: 1.5; }

/* ---------- Docket cards ---------- */

/* The all-clear stands on its own when there is no regulatory card to hold it,
   so the quiet day still reads as a statement rather than an absence. */
.rw-allclear {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px; margin-bottom: 14px;
  background: var(--green-100); border-radius: var(--r);
  border-left: 3px solid var(--green-600);
  font-size: 13.5px; color: var(--ink-2);
}
.rw-allclear .ico { width: 17px; height: 17px; color: var(--green-600); flex-shrink: 0; }

.rw-tier-note { font-size: 12px; color: var(--ink-4); }

/* Industry items sit in their own card, marked violet against the Docket's
   indigo so the two are distinguishable at a glance. */
.rw-card.is-industry { border-top: 2px solid var(--purple-600); }
.rw-card.is-industry .card-hd { background: var(--purple-100); }
.rw-card.is-industry .card-hd h3 { color: var(--purple-600); }

.rw-item.is-industry {
  padding: 13px 20px; border-bottom: 1px solid var(--line-2); border-left: none;
}
.rw-item.is-industry:last-child { border-bottom: none; }
.rw-item.is-industry:hover { background: var(--canvas); }
.rw-item.is-industry .rw-title { font-size: 14.5px; font-weight: 650; }

.rw-why {
  font-size: 12.5px; color: var(--ink-3); margin: 5px 0 0; line-height: 1.5;
  padding-left: 11px; border-left: 2px solid var(--purple-100);
}

/* Browsers auto-detect what looks like data -- figures, dates, anything
   resembling a phone number -- and wrap it in a link. In a rationale full of
   percentages and dollar amounts that reads as though half the sentence is
   clickable. */
.rw-why a { color: inherit; text-decoration: none; pointer-events: none; }

/* Two duplicate .rw-item.is-industry blocks exist; the later one wins. The
   earlier grey rail is overridden here so the tier's colour is consistent. */
.rw-item.is-industry { border-left: 2px solid var(--purple-100); }

/* The all-clear sits above the industry card and should share its width. */
.rw-allclear { border-radius: var(--r); }

/* The Docket is one app: the regulatory brief and the industry section are two
   parts of a single edition, so they share a frame rather than floating as
   separate cards. */
.rw-frame {
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  background: var(--surface);
}
.rw-frame > .card {
  border: none;
  border-radius: 0;
  box-shadow: none;
  margin-top: 0 !important;
}
/* A rule between the two sections rather than a gap. */
.rw-frame > .card + .card { border-top: 1px solid var(--line); }
.rw-frame .rw-card.is-industry { border-top: 2px solid var(--purple-600); }

/* The industry header needs its own bottom rule: inside the shared frame the
   card's own border was removed, taking the separator with it. */
.rw-frame .rw-card.is-industry > .card-hd {
  border-bottom: 1px solid var(--purple-100);
}

/* ---------- Department tiles ---------- */

/* Ten identical white tiles with a coloured rail read as a wall: the accent is
   present but doing almost nothing. Tinting the whole tile makes the grid
   scannable by colour, which is how people actually find the department they
   want -- by position and hue, not by reading ten labels. */
.tile.accent {
  background: var(--a-bg);
  border: 1px solid var(--a-br);
  border-left: 1px solid var(--a-br);
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.tile.accent:hover {
  border-color: var(--a);
  box-shadow: 0 4px 14px rgba(15, 23, 42, .10);
  transform: translateY(-2px);
}

/* The icon carries the accent at full strength against the tint. */
.tile.accent .ico-box {
  background: var(--surface);
  border: 1px solid var(--a-br);
}
.tile.accent .ico-box .ico { color: var(--a); }

.tile.accent .body strong { color: var(--ink); }
.tile.accent .body span { color: var(--ink-2); }

/* More room between rows than columns, so the grid reads as rows of
   departments rather than an undifferentiated block. */
.grid-auto { row-gap: 14px; }

/* --line at #e2e8f0 is close enough to the page ground that a card's
   border disappears into it and its only edge is a faint shadow.
   Deepening the border gives cards a real edge without drawing more
   lines. */
.card { border-color: #dbe2ea; }
.card { box-shadow: 0 1px 2px rgba(15, 23, 42, .06), 0 1px 3px rgba(15, 23, 42, .04); }

/* ---------- Department dropdown ---------- */

/* A parent with children is a menu, not a destination. It looks like the other
   nav entries until opened, so the sidebar reads the same whether or not you
   are inside a department. */
.nav-disc > summary {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 16px; cursor: pointer; list-style: none;
  color: var(--ink-2); font-size: 14px;
  border-left: 3px solid transparent;
}
.nav-disc > summary::-webkit-details-marker { display: none; }
.nav-disc > summary:hover { background: var(--line-2); color: var(--ink); }
.nav-disc > summary .ico { width: 17px; height: 17px; color: var(--a, var(--ink-3)); }

.nav-caret {
  margin-left: auto; width: 0; height: 0;
  border-left: 4px solid var(--ink-4);
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transition: transform .12s ease;
}
.nav-disc[open] > summary .nav-caret { transform: rotate(90deg); }
.nav-disc[open] > summary { color: var(--ink); font-weight: 600; }

/* Children sit indented under the parent, coloured by their own accent so the
   list is scannable the way the tiles were. */
.nav-disc > a.child { padding-left: 40px; }
.nav-disc > a.child .ico { width: 15px; height: 15px; color: var(--a, var(--ink-3)); }

/* ---------- Department nav hierarchy ---------- */

/* A department and the apps inside it were rendering at the same weight, so
   the apps read as more departments rather than as contents of the one you
   are in. */
.nav-disc > a.child {
  font-size: 14px; font-weight: 600; color: var(--ink);
  padding-top: 8px; padding-bottom: 8px;
}
.nav-disc > a.child:not(.active) .ico { opacity: 1; }

.nav-disc > a.grandchild {
  padding-left: 62px;
  font-size: 12.5px;
  color: var(--ink-3);
  padding-top: 5px; padding-bottom: 5px;
}
.nav-disc > a.grandchild.app::before { font-size: 11px; }

/* The apps belong to the department above them, so the rule goes above the
   next department rather than under the last app -- that way it only appears
   where a boundary actually exists. */
.nav-disc > a.grandchild + a.child {
  border-top: 1px solid var(--line);
  margin-top: 6px; padding-top: 12px;
}
/* And when the open department is last in the list, close the group off. */
.nav-disc > a.grandchild:last-child { margin-bottom: 6px; }

/* ---------- Section headings ---------- */

/* A coloured rule beside a heading groups what follows it without a card
   border, which is what makes a long page read as regions rather than a list. */
.main h2 {
  position: relative; padding-left: 13px;
  font-size: 17px; letter-spacing: -.01em;
}
.main h2::before {
  content: ""; position: absolute; left: 0; top: 3px; bottom: 3px;
  width: 4px; border-radius: 2px; background: var(--navy-900);
}
.main h2.is-attention::before { background: var(--amber-600); }

/* ---------- Primary action ---------- */

/* Dignity Blue, the brand's own blue: it carries more authority than the
   link blue and stops the primary button competing with every link on the
   page, which is what the navy was doing here before the brand had a colour
   of its own. */
.btn:not(.ghost):not(.sm) { background: var(--btn-grad); border-color: transparent; }
.btn:not(.ghost):not(.sm):hover { background: var(--btn-grad-hover); border-color: transparent; }

/* ---------- Warm canvas ---------- */

/* Cool at the top left where the nav sits, warm at the bottom right where
   content ends -- the same direction and weight as the wash it replaces, on
   the brand's two ends instead of a generic blue-grey to peach.

   Both stops are the brand colour heavily diluted toward white: Sky Blue
   #8ac9e5 at 18% and 8%, Coral #ea7c63 at 8% and 18%. Diluted this far so a
   white card still reads as white against it, which is the whole job of a
   page ground. The pure values are far too strong to sit under content and
   are not tokens for that reason. */
body {
  background:
    linear-gradient(150deg,
      #eaf5fa 0%,
      #f6fbfd 30%,
      #fdf4f3 62%,
      #fbe7e3 100%);
  background-attachment: fixed;
}

/* ---------- Contacts ---------- */

.ct-bar {
  display: flex; align-items: center; gap: 14px;
  flex-wrap: wrap; margin-bottom: 16px;
}
.ct-filters { display: flex; gap: 7px; flex-wrap: wrap; flex: 1; }

/* Type filters carry their type's colour, so the filter row doubles as the
   legend for the cards below it. */
.ct-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: 12.5px; color: var(--ink-2);
}
.ct-chip:hover { border-color: var(--a, var(--blue-500)); text-decoration: none; }
.ct-chip .ico { width: 14px; height: 14px; color: var(--a, var(--ink-3)); }
.ct-chip.on {
  background: var(--a-bg, var(--blue-50));
  border-color: var(--a, var(--blue-600));
  color: var(--a, var(--blue-600)); font-weight: 600;
}
.ct-n { color: var(--ink-4); font-size: 11.5px; }
.ct-chip.on .ct-n { color: inherit; }

.ct-search { display: flex; gap: 8px; align-items: center; }
.ct-search input[type=search] { width: 220px; height: 34px; }
.ct-search .btn { height: 34px; }

.ct-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: 14px;
}
.ct-card {
  position: relative; display: flex; gap: 13px;
  padding: 16px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--a, var(--line));
  color: inherit; box-shadow: var(--shadow-sm);
  transition: transform .12s ease, box-shadow .12s ease;
}
.ct-card:hover {
  text-decoration: none; transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(15, 23, 42, .10);
}
.ct-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.ct-name { font-size: 15px; font-weight: 650; letter-spacing: -.01em; }
.ct-role { font-size: 12.5px; color: var(--a, var(--ink-3)); font-weight: 600; }
.ct-org  { font-size: 12.5px; color: var(--ink-3); }
.ct-meta { display: flex; flex-direction: column; gap: 2px; margin-top: 7px; }
.ct-meta span {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--ink-3);
}
.ct-meta .ico { width: 13px; height: 13px; color: var(--ink-4); }
.ct-flag { position: absolute; top: 12px; right: 12px; }

/* Add form: two columns, with the wide fields spanning. */
.ct-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.ct-form .ct-wide { grid-column: 1 / -1; }
@media (max-width: 700px) { .ct-form { grid-template-columns: 1fr; } }

.ct-check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.ct-check input { width: auto; margin-top: 3px; accent-color: var(--green-600); }
.ct-check strong { display: block; font-size: 13.5px; }
.ct-check em { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); }

.ct-add > summary { display: inline-flex; list-style: none; cursor: pointer; }
.ct-add > summary::-webkit-details-marker { display: none; }

.ct-logform { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }

/* Contact methods as tappable rows rather than a table of labels. */
.ct-reach {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 18px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.ct-reach:last-child { border-bottom: none; }
.ct-reach:hover { background: var(--canvas); text-decoration: none; }
.ct-reach .ico { width: 16px; height: 16px; color: var(--ink-3); flex-shrink: 0; }
.ct-reach:hover .ico { color: var(--blue-600); }
.ct-reach strong { display: block; font-size: 13.5px; font-weight: 600; }
.ct-reach em {
  display: block; font-style: normal; font-size: 11.5px; color: var(--ink-4);
}

/* Contacts as rows: a directory is scanned down a column, not browsed as
   cards. The type keeps its colour so the list stays legible at a glance. */
table.ct-table { width: 100%; border-collapse: collapse; }
table.ct-table thead th {
  height: 40px; padding: 0 14px; text-align: left; vertical-align: middle;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
  border-bottom: 1px solid var(--line);
}
table.ct-table tbody td {
  padding: 9px 14px; border-bottom: 1px solid var(--line-2);
  font-size: 13.5px; vertical-align: middle;
}
table.ct-table tbody tr:last-child td { border-bottom: none; }
table.ct-table tbody tr:hover { background: var(--canvas); }
table.ct-table td.muted { color: var(--ink-3); font-size: 13px; }
table.ct-table td.right { text-align: right; }

.ct-link { display: inline-flex; align-items: center; gap: 9px; color: inherit; }
.ct-link:hover { text-decoration: none; }
.ct-link .ico { width: 17px; height: 17px; color: var(--a, var(--ink-3)); flex-shrink: 0; }
.ct-link strong { display: block; font-weight: 600; }
.ct-link:hover strong { color: var(--blue-600); }
.ct-link em {
  display: block; font-style: normal; font-size: 12px; color: var(--ink-3);
}

.ct-tag {
  display: inline-block; padding: 1px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
  background: var(--a-bg, var(--line-2)); color: var(--a, var(--ink-2));
  border: 1px solid var(--a-br, var(--line));
  white-space: nowrap;
}

.ct-num { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
.ct-num a { color: var(--ink-2); }

/* Contact form compacted: a record with twelve fields spread over twelve rows
   cannot be taken in at once, which is the whole point of a detail page. */
.ct-form { gap: 0 12px; }
.ct-form .field { margin-bottom: 9px; }
.ct-form .field label {
  display: block; font-size: 11px; font-weight: 650;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-4); margin-bottom: 2px;
}
.ct-form .field input,
.ct-form .field select,
.ct-form .field textarea {
  padding: 6px 9px; font-size: 13px; line-height: 1.35;
}
.ct-form .field textarea { min-height: 0; }

/* Three columns where there is room: type, org and role read as one line. */
@media (min-width: 900px) {
  .ct-form { grid-template-columns: repeat(3, 1fr); }
  .ct-form .ct-wide { grid-column: 1 / -1; }
}

.ct-check { padding: 8px 0 2px; }
.ct-logform .field { margin-bottom: 8px; }

/* The 1180px cap suited prose but the portal is mostly tables and file
   listings, which were being squeezed while half the screen sat empty. The
   shell now uses the width; a reading measure is applied only where the
   content is actually text. */
.main { max-width: none; padding-right: 40px; }

/* Very wide screens still need a stop, or a table stretches to absurdity. */
@media (min-width: 1900px) { .main { max-width: 1760px; } }

/* Prose keeps its measure regardless of how wide the window is. */
.main .lede,
.main .rw-body,
.main .rw-dek,
.main .doc-body p,
.main .tl-text { max-width: 78ch; }

/* The contact detail page was taller than a screen for a record with twelve
   short fields. Most of that was padding between things that belong together. */
.doc-cols .card { margin-bottom: 12px !important; }
.doc-cols .card-hd { padding: 9px 16px; }
.doc-cols .card-hd h3 { font-size: 14px; }
.doc-cols .card-pad { padding: 12px 16px; }

.ct-form .field { margin-bottom: 7px; }
.ct-form .field label { margin-bottom: 1px; letter-spacing: .03em; }
.ct-form .field input,
.ct-form .field select { height: 30px; padding: 0 9px; }
.ct-form .field textarea { padding: 6px 9px; }

/* The page head takes a third of the screen before any content appears. */
.main .page-head { margin-bottom: 14px; padding-bottom: 12px; }

.ct-reach { padding: 8px 16px; }
.ct-logform { gap: 0 10px; }
.tl-row { padding: 8px 16px; }

/* The global input width makes a checkbox a full-width block, which drops its
   label to the next line. Specific enough here to survive later rules. */
.ct-form .ct-check input[type=checkbox] {
  width: 16px; height: 16px; min-width: 16px;
  margin: 2px 0 0; flex: none;
}
.ct-form .ct-check { align-items: flex-start; }

/* The uppercase caption styling is for field labels. The company-contact
   checkbox uses a label as its container, so it was inheriting all of it --
   block display, uppercase, letter-spacing -- which broke the layout and made
   the description shout. */
.ct-form label.ct-check {
  display: flex; align-items: center; gap: 9px;
  font-size: 13.5px; font-weight: 400; text-transform: none;
  letter-spacing: 0; color: var(--ink-2); margin: 4px 0 10px;
  padding: 9px 12px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--canvas);
}
.ct-form label.ct-check:hover { border-color: var(--green-600); }
.ct-form label.ct-check strong {
  font-size: 13.5px; font-weight: 650; text-transform: none;
  letter-spacing: 0; color: var(--ink);
}
.ct-form label.ct-check em {
  font-size: 12px; text-transform: none; letter-spacing: 0;
  color: var(--ink-3); font-weight: 400;
}

/* Address and notes were as tall as the rest of the form combined. */
.ct-form .ct-wide textarea { min-height: 0; height: 52px; }

/* The interaction form is one line across the foot of the card: a date, a
   kind, and what happened. Stacked, it took more space than the log it feeds. */
.ct-logrow { display: flex; gap: 10px; align-items: flex-end; }
.ct-logrow .field { margin-bottom: 0; }
.ct-logrow .ct-grow { flex: 1; }
.ct-logrow label {
  display: block; font-size: 11px; font-weight: 650; letter-spacing: .03em;
  text-transform: uppercase; color: var(--ink-4); margin-bottom: 1px;
}
.ct-logrow input, .ct-logrow select { height: 32px; }
.ct-logrow .btn { height: 32px; flex: none; }
@media (max-width: 760px) { .ct-logrow { flex-wrap: wrap; } }

/* Details is the substance of the page, so it gets the width. */
.doc-cols { grid-template-columns: minmax(0, 1fr) 340px; }

/* A fixed-height select keeps its own line-height, so the text sat lower than
   the box and clipped. Both are set, with room for the chevron. */
.ct-logrow select {
  height: 32px; line-height: 30px; padding: 0 28px 0 9px;
  min-width: 108px;
}
.ct-logrow input[type=date] { line-height: 30px; padding: 0 9px; }

/* Rows tight against each other: the hairline is the separator, so padding on
   top of it just costs rows on screen. */
table.ct-table tbody td { padding-top: 6px; padding-bottom: 6px; }
table.ct-table tbody tr:hover { background: var(--blue-50); }

.ct-last { white-space: nowrap; font-size: 12.5px; color: var(--ink-3); }
.ct-last span { display: inline-flex; align-items: center; gap: 5px; }
.ct-last .ico { width: 13px; height: 13px; color: var(--green-600); }

/* A Google profile photo where the contact is also a portal user, the type
   icon otherwise. The photo is square-cropped to a circle so a mixed list of
   people and organisations still reads as one column. */
.ct-photo {
  width: 26px; height: 26px; border-radius: 50%;
  object-fit: cover; flex-shrink: 0;
  border: 1px solid var(--line);
}
.ct-photo.lg { width: 40px; height: 40px; border-radius: var(--r-sm); }

/* ---------- Collapsing sidebar ---------- */

/* A rail of icons that widens on hover. The labels are bare text nodes rather
   than wrapped elements, so they are hidden by clipping the rail rather than by
   a selector -- which means no template change and nothing to keep in step.
   Scoped above the mobile breakpoint, where the rail is hidden entirely. */
@media (min-width: 861px) {
  :root { --rail-w: 58px; }

  /* Out of flow, so widening it does not reflow the page. The shell keeps a
     rail-width gutter whether or not the rail is expanded. */
  .shell { padding-left: var(--rail-w); }
  .side {
    position: fixed;
    top: var(--header-h);
    bottom: 0;
    left: 0;
    width: var(--rail-w);
    overflow-x: hidden;
    overflow-y: auto;
    white-space: nowrap;
    z-index: 60;
    transition: width .16s ease, box-shadow .16s ease;
  }
  .side:hover,
  .side:focus-within {
    width: var(--sidebar-w);
    box-shadow: 6px 0 24px rgba(15, 23, 42, .13);
  }

  /* Icons sit centred in the rail and stay put as it opens, so nothing
     shuffles sideways when the labels appear. */
  .side a,
  .side .nav-disc > summary { padding-left: 20px; }
  .side .ico { margin-right: 2px; }

  /* Collapsed, only the top level shows. A child indented to 40px would have
     its icon clipped off the edge, and the rail would be a column of blanks. */
  .side:not(:hover):not(:focus-within) .nav-disc > a.child,
  .side:not(:hover):not(:focus-within) .nav-disc > a.grandchild,
  .side:not(:hover):not(:focus-within) a.child,
  .side:not(:hover):not(:focus-within) a.grandchild {
    display: none;
  }

  /* The section label is text with no icon, so collapsed it is an empty gap.
     A rule reads as a divider instead. */
  .side:not(:hover):not(:focus-within) .parent {
    color: transparent;
    border-top: 1px solid var(--line);
    margin: 8px 14px 4px;
    padding: 0;
    height: 1px;
    overflow: hidden;
  }

  /* The caret would otherwise sit outside the rail and reappear abruptly. */
  .side:not(:hover):not(:focus-within) .nav-caret { opacity: 0; }
  .nav-caret { transition: opacity .16s ease; }

  /* Active state is a filled pill; at rail width it should still read as one
     rather than a stripe running off the edge. */
  .side:not(:hover):not(:focus-within) a.active { border-radius: 0; }
}

/* The first letter of each label was showing at the rail's edge. The icon needs
   about 36px including padding; anything wider starts revealing text. */
@media (min-width: 861px) {
  :root { --rail-w: 52px; }
  .side a,
  .side .nav-disc > summary { padding-left: 17px; padding-right: 0; gap: 40px; }
  .side:hover a,
  .side:focus-within a,
  .side:hover .nav-disc > summary,
  .side:focus-within .nav-disc > summary { gap: 10px; padding-right: 16px; }
}

/* ---------- Sidebar pin ---------- */

.hdr-pin {
  display: grid; place-items: center;
  width: 34px; height: 34px; margin-left: 10px; margin-right: 2px;
  border: none; border-radius: var(--r-sm);
  background: transparent; color: rgba(255, 255, 255, .72);
  cursor: pointer; flex-shrink: 0;
}
.hdr-pin:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.hdr-pin .ico { width: 19px; height: 19px; }
.rail-pinned .hdr-pin { background: rgba(255, 255, 255, .16); color: #fff; }

@media (min-width: 861px) {
  /* Pinned: the rail stays open and the content moves over rather than being
     covered, which is the difference between a pin and a permanent overlay. */
  .rail-pinned .shell { padding-left: var(--sidebar-w); }
  .rail-pinned .side { width: var(--sidebar-w); box-shadow: none; }
  .rail-pinned .side a,
  .rail-pinned .side .nav-disc > summary { gap: 10px; padding-right: 16px; }
  .rail-pinned .side .nav-disc > a.child,
  .rail-pinned .side .nav-disc > a.grandchild,
  .rail-pinned .side a.child,
  .rail-pinned .side a.grandchild { display: flex; }
  .rail-pinned .side .parent {
    color: var(--ink-4); border-top: none; height: auto;
    margin: 14px 0 4px; padding: 0 18px;
  }
  .rail-pinned .side .nav-caret { opacity: 1; }
  .rail-pinned .side a.active { border-radius: 0; }
  .shell { transition: padding-left .16s ease; }
}
/* **On a phone the same button opens the navigation as a drawer.** Below
   861px the rail was `display: none` and this button was hidden with it, so a
   phone had no way to reach any department or app -- every page was a dead
   end past the one somebody was sent to. Reported by a user on 29 September
   2026; it had been so since the rail was built. The button stays, the menu
   slides in from the left over the page, and a tap outside, a link, or Escape
   closes it. Only the phone's own rule is changed: at 861px and up the rail
   and its pin are exactly as they were. */
@media (max-width: 860px) {
  .hdr-pin { margin-left: 6px; }
  .nav-open .side {
    display: block; position: fixed; z-index: 70;
    top: var(--header-h); bottom: 0; left: 0;
    width: min(300px, 86vw); overflow-y: auto;
    background: var(--navy-900); box-shadow: 0 10px 30px rgba(10, 31, 68, .28);
  }
  .nav-open .side a.child,
  .nav-open .side a.grandchild { display: flex; }
  .nav-scrim { display: none; }
  .nav-open .nav-scrim {
    display: block; position: fixed; inset: var(--header-h) 0 0 0; z-index: 65;
    background: rgba(10, 31, 68, .35);
  }
}

/* The collapsed rule carries two pseudo-classes and outweighs the pinned
   override, so pinning left the children hidden. Scoping the hide to the
   unpinned case is cleaner than escalating specificity further. */
@media (min-width: 861px) {
  html:not(.rail-pinned) .side:not(:hover):not(:focus-within) .nav-disc > a.child,
  html:not(.rail-pinned) .side:not(:hover):not(:focus-within) .nav-disc > a.grandchild,
  html:not(.rail-pinned) .side:not(:hover):not(:focus-within) a.child,
  html:not(.rail-pinned) .side:not(:hover):not(:focus-within) a.grandchild {
    display: none;
  }
  .rail-pinned .side:not(:hover):not(:focus-within) .nav-disc > a.child,
  .rail-pinned .side:not(:hover):not(:focus-within) .nav-disc > a.grandchild,
  .rail-pinned .side:not(:hover):not(:focus-within) a.child,
  .rail-pinned .side:not(:hover):not(:focus-within) a.grandchild {
    display: flex;
  }

  /* Same collision on the section label and the caret. */
  .rail-pinned .side:not(:hover):not(:focus-within) .parent {
    color: var(--ink-4); border-top: none; height: auto;
    margin: 14px 0 4px; padding: 0 18px;
  }
  .rail-pinned .side:not(:hover):not(:focus-within) .nav-caret { opacity: 1; }
}

/* ---------- The Docket, at a glance ---------- */

/* On the home page the brief is a headline service, not the page. It reads at
   a smaller size with tighter rows so it can be taken in without scrolling,
   and the full-size treatment stays on /apps/regwatch. */
.main > div[hx-get*="regwatch"] .rw-item { padding: 8px 18px; }
.main > div[hx-get*="regwatch"] .rw-title { font-size: 13.5px; line-height: 1.35; }
.main > div[hx-get*="regwatch"] .rw-line { font-size: 10.5px; margin-bottom: 2px; }
.main > div[hx-get*="regwatch"] .rw-dek { font-size: 12.5px; margin: 3px 0 0; }
.main > div[hx-get*="regwatch"] .rw-body { font-size: 12.5px; }
.main > div[hx-get*="regwatch"] .rw-why {
  font-size: 12px; margin-top: 3px; padding-left: 9px;
}
.main > div[hx-get*="regwatch"] .card-hd { padding: 9px 18px; }
.main > div[hx-get*="regwatch"] .card-hd h3 { font-size: 14px; }
.main > div[hx-get*="regwatch"] .rw-quiet,
.main > div[hx-get*="regwatch"] .rw-allclear { padding: 9px 18px; font-size: 12.5px; }
.main > div[hx-get*="regwatch"] .rw-tier { padding: 8px 18px 5px; }
.main > div[hx-get*="regwatch"] .chip { font-size: 10px; }

/* The expandable "More" on a compact item is the release valve: less on screen
   by default, the whole thing one click away. */
.main > div[hx-get*="regwatch"] .rw-more-d > summary { font-size: 12px; }

/* The headline, its summary and the expander on one line. The summary is cut
   off by the row rather than by a character count, so it uses whatever width
   the screen gives it. */
.main > div[hx-get*="regwatch"] .rw-item { padding: 6px 18px; }
.main > div[hx-get*="regwatch"] .rw-title { display: inline; }

.rw-open > summary {
  display: flex; align-items: baseline; gap: 7px;
  list-style: none; cursor: pointer; min-width: 0;
  margin-top: 1px;
}
.rw-open > summary::-webkit-details-marker { display: none; }

.rw-dek-i {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; color: var(--ink-3);
}
.rw-x {
  flex: none; font-size: 11.5px; font-weight: 600;
  color: var(--blue-600); opacity: .75;
}
.rw-open > summary:hover .rw-x { opacity: 1; text-decoration: underline; }
.rw-open[open] > summary .rw-dek-i { display: none; }
.rw-open[open] > summary .rw-x::after { content: " less"; }
.rw-open[open] > summary .rw-x { font-size: 0; }
.rw-open[open] > summary .rw-x::after { font-size: 11.5px; }

.rw-open[open] > .rw-dek,
.rw-open[open] > .rw-body { margin: 5px 0 0; }

/* Industry rows take the same one-line treatment. */
.main > div[hx-get*="regwatch"] .rw-item.is-industry { padding: 6px 18px; }
.main > div[hx-get*="regwatch"] .rw-item.is-industry .rw-title {
  display: inline; font-size: 13.5px;
}
.rw-open[open] > .rw-why { margin-top: 5px; }

/* Headline and summary on one line. The title is a block anchor and the
   summary a details element, so neither sits beside the other until both are
   items in a flex row. */
.main > div[hx-get*="regwatch"] .rw-item.is-industry,
.main > div[hx-get*="regwatch"] .rw-item:not(.is-industry) {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  align-items: baseline;
  column-gap: 10px;
}
.main > div[hx-get*="regwatch"] .rw-line { grid-column: 1 / -1; }
.main > div[hx-get*="regwatch"] .rw-title {
  grid-column: 1; display: inline; min-width: 0;
}
.main > div[hx-get*="regwatch"] .rw-open {
  grid-column: 2; min-width: 0;
}
/* Opened, the detail spans the row rather than staying in its column. */
.main > div[hx-get*="regwatch"] .rw-open[open] {
  grid-column: 1 / -1;
}

/* The heading was fine at its original size -- it was the space around it that
   made the card feel large. */
.main > div[hx-get*="regwatch"] .card-hd { padding: 7px 18px; }
.main > div[hx-get*="regwatch"] .card-hd h3 { font-size: 15px; }

/* The three cards below take the same treatment. */
.home-trio .card-hd { padding: 8px 14px; }
.home-trio .card-hd h3 { font-size: 14px; }
.home-trio .card .rows > a { padding-top: 6px; padding-bottom: 6px; }
.home-trio .card-pad { padding: 10px 14px; }
.home-trio .ov-foot { padding: 7px 14px; }

/* Assignments grouped by project: name, department, and a count per status. */
.mw-proj {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 14px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.mw-proj:last-child { border-bottom: none; }
.mw-proj:hover { background: var(--canvas); text-decoration: none; }
.mw-proj .grow { flex: 1; min-width: 0; }
.mw-proj .name { display: block; font-size: 13px; font-weight: 600; }

/* The count of items assigned in the project, then a dot per state that has a
   non-zero count. The number sits inside the dot, so the fills are picked for
   contrast against it rather than taken from the status tokens wholesale:
   green at its -600 value clears about 3:1, which is not enough behind an 11px
   numeral, so it steps down a shade. The status tokens themselves are
   untouched -- these are the only rules that use these values, and they are
   the component rather than the palette. */
.cdot {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px;
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--on-accent);
}
.d-not_started { background: var(--ink-3); }
.d-in_progress { background: #15803d; }
.d-in_review   { background: var(--blue-600); }
.d-blocked     { background: var(--red-600); }

/* Overdue is the one dot with a dark numeral. Yellow is a light hue by
   definition: white on it reads at 1.9:1, and the only yellows that carry
   white text are dark enough to read as brown beside the red dot. So the
   colour stays yellow and the number turns to ink, which is 9.3:1 -- the
   clearest of the five. The other four keep white because their fills are
   dark; matching them here would cost the hue or the number. */
.d-overdue { background: #eab308; color: var(--ink); }

/* The department is its own icon in its own accent rather than an abbreviation
   in a chip. The chips varied in width -- NETOPS against EXEC -- so the project
   names started at different places and the column read as ragged; an icon is
   one width, which settles the alignment as a consequence rather than as a
   rule of its own. It sits outside .grow so the name gets the remaining space,
   and carries the full department name as its title, since an icon displays
   no text and the hover is the only place left to name it. */
.mw-proj .mw-dept {
  flex: none;
  width: 20px; height: 20px; border-radius: 6px;
  display: grid; place-items: center;
  background: var(--a-bg, var(--line-2));
  color: var(--a, var(--ink-3));
}
.mw-proj .mw-dept .ico { width: 13px; height: 13px; }

/* The dots sit at the right end of the row and keep their width, so the name
   takes whatever is left. They do not wrap: a row that grew to two lines when
   somebody had work in every state is the raggedness the department icon was
   fixed for, one column over. */
.mw-proj .mw-dots {
  display: flex; align-items: center; gap: 5px;
  flex: none; flex-wrap: nowrap;
}

/* One line per project: the name is cut off with an ellipsis rather than
   wrapping, so the row height stays constant however long a title runs. The
   full name is on hover, and the row links to the project regardless. */
.mw-proj .name {
  display: block; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.mw-proj .grow { min-width: 0; }

/* The card is three columns wide, so its dots are a step smaller than the
   ones on My Projects, which has the room for the full size. */
.mw-proj .cdot { min-width: 17px; height: 17px; padding: 0 4px; font-size: 10.5px; }

/* The shell was held to a full viewport so the in-flow sidebar reached the
   bottom. The sidebar is fixed now, so that only pushed the footer below the
   fold on a short page. A flex column keeps the footer at the bottom when
   content is short and lets it sit after the content when it is long. */
@media (min-width: 861px) {
  body { display: flex; flex-direction: column; min-height: 100vh; }
  .shell { min-height: 0; flex: 1; }
  .foot { flex: none; }
}

/* Making body a flex column turned .shell into a flex item, which stops it
   growing past its computed basis -- so long pages overflowed under a footer
   that looked pinned. The shell needs to size to its content and merely have a
   minimum, not a fixed share of the viewport. */
@media (min-width: 861px) {
  body { display: block; min-height: 100vh; }
  .shell { min-height: calc(100vh - var(--header-h) - 49px); }
}




/* ---------- Navy rail ---------- */

/* The rail joins the header rather than the page: chrome above and to the
   left, content in the middle. Everything in it inverts, since the nav colours
   were built against white. */
.side {
  background: var(--navy-900);
  background-image: none;
  border-right: none;
}

.side a,
.side .nav-disc > summary { color: rgba(255, 255, 255, .78); }
.side a:hover,
.side .nav-disc > summary:hover {
  background: rgba(255, 255, 255, .09);
  color: #fff;
}

/* Accent icons keep their colour but need lifting against the dark ground. */
.side .ico { opacity: .82; }
.side a:hover .ico,
.side .nav-disc[open] > summary .ico { opacity: 1; }

/* Active is a filled block; against navy it reads better as a lighter panel
   than as the blue that worked on white. The marker is Coral -- the mark's
   own colour, spent here and nowhere else, because it sits a short step from
   red and red means stop. */
.side a.active {
  background: rgba(255, 255, 255, .14);
  color: #fff;
  border-left-color: var(--coral);
}
.side a.active .ico { color: #fff; opacity: 1; }

.side .nav-disc[open] > summary { color: #fff; }
.side .nav-caret { border-left-color: rgba(255, 255, 255, .5); }

.side .parent { color: rgba(255, 255, 255, .42); }
.side:not(:hover):not(:focus-within) .parent { border-top-color: rgba(255, 255, 255, .16); }
.rail-pinned .side .parent { color: rgba(255, 255, 255, .42); }

/* Department children in the dropdown. */
.side a.child { color: rgba(255, 255, 255, .72); }
.side a.grandchild { color: rgba(255, 255, 255, .55); }
.side a.grandchild.app::before { color: rgba(255, 255, 255, .35); }
.side .nav-disc > a.grandchild + a.child { border-top-color: rgba(255, 255, 255, .12); }

/* The pinned rail no longer needs a shadow to separate it from content. */
.rail-pinned .side { box-shadow: none; }
.side:hover, .side:focus-within {
  background-image: none;
  box-shadow: 6px 0 24px rgba(6, 15, 38, .35);
}

/* Inside a department, the nav shows that department and its apps rather than
   all ten. Ten identical rows made the current one hard to find, which is the
   one thing the nav has to tell you.
   
   The others return on hovering the group, so switching is still one gesture
   -- hiding them outright would leave no way to move between departments. */
.nav-disc.is-inside > a.child:not(.is-here) { display: none; }
.nav-disc.is-inside.show-all > a.child { display: flex; }

/* A hint that more is behind the hover, so it is discoverable rather than
   something you have to be told about. */
.nav-disc.is-inside > summary::after {
  content: "";
  width: 5px; height: 5px; border-radius: 50%;
  background: rgba(255, 255, 255, .35);
  margin-left: 6px; flex: none;
}
.nav-disc.is-inside.show-all > summary::after { background: rgba(255, 255, 255, .7); }


/* The dot marks a group that has more behind it, and the summary is clickable
   rather than merely a heading. */
.nav-disc.is-inside > summary { cursor: pointer; }
.nav-disc.is-inside > summary:hover::after { background: rgba(255, 255, 255, .55); }

/* The rail's pinned rules set display on every child to counter the collapsed
   state, and outrank the is-inside rule that hides the departments you are not
   in. Restated here with enough specificity to survive both. */
@media (min-width: 861px) {
  .side .nav-disc.is-inside:not(.show-all) > a.child:not(.is-here),
  .rail-pinned .side .nav-disc.is-inside:not(.show-all) > a.child:not(.is-here),
  .rail-pinned .side:not(:hover):not(:focus-within)
    .nav-disc.is-inside:not(.show-all) > a.child:not(.is-here) {
    display: none;
  }
  .side .nav-disc.is-inside.show-all > a.child,
  .rail-pinned .side .nav-disc.is-inside.show-all > a.child,
  .rail-pinned .side:not(:hover):not(:focus-within)
    .nav-disc.is-inside.show-all > a.child {
    display: flex;
  }
}

/* Apps carry their own icon, so the chevron that stood in for one goes. */
.side a.grandchild.app::before { content: none; }
.side a.grandchild .ico { width: 14px; height: 14px; }

/* The department you are in sits at the top of the list, with its apps
   directly beneath it. Ordering is visual only -- the markup stays in the
   order the sections are sorted, so nothing downstream depends on it. */
/* Ordering is done in the template; see base.html. */

/* Apps under a top-level section carry an icon too, so the chevron stand-in
   goes there as well. */
.side a.child.app::before { content: none; }
.side a.child.app .ico { width: 14px; height: 14px; }

/* Deep folders were pushing their action menu under the scrollbar: the rows
   indent but keep their width, so the row runs past the pane. The name takes
   the remaining space and truncates; the menu stays pinned at the right edge
   whatever the depth. */
.lb-tree .ft-leaf-row,
.lb-tree .ft-node > summary { padding-right: 4px; }
.lb-tree .ft-leaf-row > a,
.lb-tree .ft-node > summary > a {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-tree .ft-menu { margin-left: auto; }

/* Room for the scrollbar so it never sits over the menu. */
.lb-tree .ft { scrollbar-gutter: stable; }

/* The menu was sitting flush against the scrollbar, which read as part of the
   chrome rather than as a control. A gap gives it an edge of its own. */
.lb-tree .ft-leaf-row,
.lb-tree .ft-node > summary { padding-right: 12px; }
.lb-tree .ft-menu > summary { padding: 3px 5px; }
.lb-tree .ft-menu > summary:hover {
  background: var(--line-2); border-radius: var(--r-sm);
}

/* Every folder gets a caret so the names align at each level. On a folder with
   nothing inside it is drawn faintly: the shape says "folder", the dimming
   says "nothing to open". */
.ft-caret.is-empty { opacity: .22; }
.lb-tree .ft-leaf-row { gap: 0; }
.lb-tree .ft-leaf-row > .ft-caret { flex: none; }
.lb-tree .ft-leaf-row > .ft-leaf { padding-left: 0; }



/* Rows align; the icon inside a node sat 7px right of a leaf's because the
   anchor within a summary contributes its own gap on top of the row's. */
.lb-tree .ft-node > summary > a { gap: 0; padding-left: 0; }
.lb-tree .ft-node > summary { gap: 7px; }
.lb-tree .ft-leaf-row { gap: 7px; }
.lb-tree .ft-leaf-row > a.ft-leaf { gap: 7px; padding-left: 0; }

/* Company contacts grouped by organisation: several people at one company read
   as one entry rather than as scattered rows. */
.cc-group { margin-bottom: 14px; }
.cc-group .ct-table tbody tr:last-child td { border-bottom: none; }
.cc-owner {
  font-size: 11px; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; color: var(--ink-4);
  white-space: nowrap;
}

/* People sit under their organisation, not level with it: the group header is
   the parent and the rows are its contents, so the indent has to say so. */
.cc-group .ct-table tbody td:first-child { padding-left: 34px; position: relative; }
.cc-group .ct-table tbody td:first-child::before {
  content: ""; position: absolute;
  left: 22px; top: 0; bottom: 0; width: 1px;
  background: var(--line);
}
.cc-group .ct-table tbody tr:last-child td:first-child::before { bottom: 50%; }

/* The header reads as a heading rather than as another row. */
.cc-group .card-hd { background: var(--canvas); }
.cc-group .card-hd h3 { font-size: 14px; }

/* The organisation mark carries more weight than a contact's type icon: it is
   a heading, and the gradient separates it from the flat tinted squares the
   rows use. */
.cc-org-ico {
  background: linear-gradient(145deg, #3b5a94 0%, #1e3a6b 100%);
  color: var(--on-accent);
  box-shadow: 0 1px 3px rgba(15, 23, 42, .22);
  border: none;
}
.cc-org-ico .ico { color: var(--on-accent); opacity: .95; }

/* The header band picks up a hint of the same colour so the mark sits in
   something rather than on it. */
.cc-group .card-hd {
  background: linear-gradient(90deg, rgba(59, 90, 148, .09) 0%, rgba(59, 90, 148, .02) 55%, transparent 100%);
  border-bottom: 1px solid var(--line);
}
.cc-group .card-hd h3 { color: var(--navy-900); font-weight: 650; }

/* Light at the left where the mark and title sit, deepening to the right --
   the reverse of the first attempt, which faded out exactly where the eye
   finishes reading. */
.cc-group .card-hd {
  background: linear-gradient(90deg,
    rgba(59, 90, 148, .03) 0%,
    rgba(59, 90, 148, .12) 55%,
    rgba(59, 90, 148, .27) 100%);
}

/* Pulled back from 27% -- deep enough to read as a gradient, not so deep that
   the count on the right sits in shadow. */
.cc-group .card-hd {
  background: linear-gradient(90deg,
    rgba(59, 90, 148, .03) 0%,
    rgba(59, 90, 148, .10) 55%,
    rgba(59, 90, 148, .20) 100%);
}

/* Anchored to the viewport rather than the document. Attached to the page, a
   short view showed only the cool top-left of the sweep and read as flat blue,
   while a long one showed the whole range -- so the portal changed colour with
   the amount of content. */
body { background-attachment: fixed; }

/* A directory is scanned, so the number of names on a screen is the thing that
   matters. Twenty rows needs the chrome to give as well as the rows: the page
   head and filter bar were taking a fifth of the viewport before the first
   name appeared. */
.ct-table tbody td { padding-top: 3px; padding-bottom: 3px; }
.ct-table tbody td { font-size: 13px; }
.ct-link strong { font-size: 13px; line-height: 1.3; }
.ct-link em { font-size: 11px; line-height: 1.25; }
.ct-photo { width: 22px; height: 22px; }
.ct-link .ico { width: 15px; height: 15px; }
.ct-tag { font-size: 10px; padding: 0 7px; }
.ct-num { font-size: 11.5px; }
.ct-table thead th { height: 32px; }

/* The contacts page head and filters, tightened for the same reason. */
.ct-bar { margin-bottom: 10px; gap: 10px; }
.ct-chip { padding: 3px 10px; font-size: 12px; }
.ct-search input[type=search], .ct-search .btn { height: 30px; }

/* A slim page head: icon, title and description on one line. For pages whose
   content is a list, where the heading is a label rather than an introduction. */
.page-head.is-slim {
  display: flex; align-items: baseline; gap: 10px;
  margin-bottom: 10px; padding-bottom: 8px;
}
.page-head.is-slim h1 { font-size: 19px; margin: 0; letter-spacing: -.02em; }
.page-head.is-slim .lede {
  font-size: 12.5px; color: var(--ink-3); margin: 0; max-width: none;
}
.page-head.is-slim .ico-box {
  align-self: center; width: 26px; height: 26px; border-radius: 7px;
}
.page-head.is-slim .ico-box .ico { width: 15px; height: 15px; }

/* Organisation rows span the table and read as headings within it. */
.cc-table tbody tr.cc-orgrow td {
  padding: 7px 14px;
  background: linear-gradient(90deg,
    rgba(59, 90, 148, .03) 0%,
    rgba(59, 90, 148, .10) 55%,
    rgba(59, 90, 148, .20) 100%);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.cc-table tbody tr.cc-orgrow:hover td { background-color: transparent; }
.cc-table tbody tr.cc-orgrow td > * { vertical-align: middle; }
.cc-orgname {
  font-size: 13.5px; font-weight: 650; color: var(--navy-900);
  margin: 0 9px 0 8px;
}
.cc-table .cc-org-ico { display: inline-grid; width: 22px; height: 22px; }
.cc-table .cc-org-ico .ico { width: 13px; height: 13px; }

/* People sit under their organisation. */
.cc-table tbody tr:not(.cc-orgrow) td:first-child { padding-left: 30px; }

/* Where several departments hold the same contact, the directory shows one and
   counts the rest. The count is a button, and the alternates are hidden rows in
   the same table: a popover inside a scrolling table gets clipped, and an
   alternate should read exactly like the contact it duplicates.

   This was a <details> popover once, and its rules -- .cc-alt > summary, the
   webkit marker, .cc-altbox, .cc-altrow -- outlived it here for a while,
   including a second .cc-alt declaration whose display and position existed
   only to anchor the popover. Deleted rather than left disabled. */
.cc-alt {
  margin-left: 6px; padding: 1px 7px;
  border: none; border-radius: 999px; cursor: pointer;
  font-size: 10.5px; font-weight: 700; font-family: inherit;
  color: var(--blue-600); background: var(--blue-50);
}
.cc-alt:hover { background: var(--blue-100); }
.cc-alt.is-open { background: var(--blue-600); color: var(--on-accent); }

/* An alternate is the same contact kept elsewhere, so it reads as a variant of
   the row above rather than as a separate entry. */
.cc-table tbody tr.cc-altrow-tr td { background: var(--canvas); }
.cc-table tbody tr.cc-altrow-tr td:first-child { padding-left: 52px; position: relative; }
.cc-table tbody tr.cc-altrow-tr td:first-child::before {
  content: ""; position: absolute; left: 38px; top: -2px; height: 50%;
  width: 8px; border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line); border-bottom-left-radius: 3px;
}

/* Beside the name: the count belongs to the person, not to the department that
   happens to own the record shown. */
.cc-table td:first-child .cc-alt { vertical-align: middle; }

/* Fields grouped by what belongs together rather than left to flow: a name is
   two halves of one thing, and the three ways to reach someone read as a set.
   Without explicit spans the three-column grid split them arbitrarily. */
@media (min-width: 900px) {
  .ct-form .ct-half  { grid-column: span 1; }
  .ct-form .ct-third { grid-column: span 1; }

  /* First and last name lead their own row, so the third column stays empty
     rather than pulling an unrelated field up beside them. */
  .ct-form .ct-half:first-of-type { grid-column-start: 1; }
  .ct-form .ct-third:first-of-type { grid-column-start: 1; }
  .ct-form .ct-wide { grid-column: 1 / -1; }
}

/* Explicit rows: each ct-row is its own grid, so a group cannot be broken
   across lines by whatever precedes it. */
.ct-form { display: block; }
.ct-row { display: grid; grid-template-columns: 1fr; gap: 0 12px; }
.ct-row.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
.ct-row .span-2 { grid-column: span 2; }
@media (max-width: 900px) {
  .ct-row.cols-3 { grid-template-columns: 1fr 1fr; }
  .ct-row .span-2 { grid-column: span 2; }
}
@media (max-width: 620px) {
  .ct-row.cols-3 { grid-template-columns: 1fr; }
  .ct-row .span-2 { grid-column: span 1; }
}

/* Apps fold away: they are tools reached from elsewhere, not places you go.
   The rule above separates them from the sections, which are destinations. */
.nav-rule {
  height: 1px; margin: 10px 16px 8px;
  background: rgba(255, 255, 255, .14);
}
.side .nav-apps > summary .ico { color: rgba(255, 255, 255, .78); }
.side .nav-apps > a.child { padding-left: 40px; }
.side .nav-apps > a.child .ico { width: 15px; height: 15px; }

/* Collapsed to the rail there is no room for a divider that reads as anything;
   the gap alone does the work. */
@media (min-width: 861px) {
  .side:not(:hover):not(:focus-within) .nav-rule { margin: 8px 12px; }
}

/* My Projects: the home card without the cap, grouped by department. The same
   dots as the card, at their full size -- the page has the room, and a project
   that reads one way in two places is one thing to learn rather than two. */
.mp-dept { margin-bottom: 14px; }
.mp-row {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 18px; border-bottom: 1px solid var(--line-2); color: inherit;
}
.mp-row:last-child { border-bottom: none; }
.mp-row:hover { background: var(--canvas); text-decoration: none; }
.mp-row .grow { flex: 1; min-width: 0; }
.mp-row .name { display: block; font-size: 14px; font-weight: 600; }
.mp-row .sub { display: block; font-size: 12px; color: var(--ink-3); }
.mp-row .chev { color: var(--ink-4); flex: none; }

.mp-dots { display: flex; gap: 5px; flex: none; flex-wrap: wrap; justify-content: flex-end; }

.mp-late { color: var(--red-600); }

/* Oversight boards: one per question, empty when there is nothing wrong --
   which is the answer an administrator wants most days. */
.ov-board .ov-row .chev { color: var(--ink-4); flex: none; }
.ov-link { display: flex; align-items: center; gap: 12px; color: inherit; }
.ov-link:hover { text-decoration: none; }
.ov-link strong { display: block; font-size: 14px; }
.ov-link em { display: block; font-style: normal; font-size: 12.5px; color: var(--ink-3); }
.ov-link .chev { margin-left: auto; color: var(--ink-4); }

/* Portal Admin tools: an index of what an administrator can do, above the
   table they spend their time in. */
.adm-tools {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 12px; margin-bottom: 20px;
}
.adm-tool {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--a, var(--line));
  color: inherit; box-shadow: var(--shadow-sm);
  transition: transform .12s ease, box-shadow .12s ease;
}
.adm-tool:hover {
  text-decoration: none; transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(15, 23, 42, .10);
}
.adm-tool strong { display: block; font-size: 14px; }
.adm-tool em {
  display: block; font-style: normal; font-size: 12.5px;
  color: var(--ink-3); line-height: 1.4;
}
.adm-tool .chev { margin-left: auto; color: var(--ink-4); flex: none; }

/* The fold that used to wrap the sections table was deleted with it rather
   than left behind. A retired component whose rules survive is a landmine:
   the nav disclosure did exactly this, and rebuilding the department dropdown
   later produced correct markup, correct data and a correct template that
   rendered nothing, because a `display: none` 1,600 lines away was still
   hiding it. */

/* The new-section form spreads across the card rather than stacking in a
   column: eight short fields in one narrow strip is taller than the table it
   sits under. */
.adm-newsec { max-width: none; }
.adm-row {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 0 16px;
}
@media (max-width: 900px) { .adm-row { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .adm-row { grid-template-columns: 1fr; } }
.adm-newsec .field { margin-bottom: 10px; }

/* A tool card that submits rather than navigates. */
.adm-tool-form { display: contents; }
button.adm-tool {
  width: 100%; text-align: left; cursor: pointer; font-family: inherit;
}

/* Who is told when a published document changes. A group maintains itself as
   people join and leave; individuals cover what a group cannot express. */
.pb-subs {
  margin: 0 0 10px; padding: 10px 12px;
  background: var(--canvas); border-radius: var(--r-sm);
  border: 1px solid var(--line);
}
.pb-subs-hd {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 7px;
}
.pb-sub {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; padding: 3px 0;
}
.pb-sub .ico { width: 14px; height: 14px; color: var(--ink-4); }
.pb-sub .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pb-x {
  border: none; background: none; cursor: pointer;
  color: var(--ink-4); font-size: 15px; line-height: 1; padding: 0 4px;
}
.pb-x:hover { color: var(--red-600); }

.pb-subadd { display: flex; gap: 6px; margin-top: 8px; }
.pb-subadd select { width: auto; flex: none; }
.pb-subadd input { flex: 1; min-width: 0; }

.pb-newver > summary,
.pb-hist > summary {
  cursor: pointer; font-size: 12.5px; color: var(--blue-600);
  margin-bottom: 8px;
}
.pb-ver {
  display: flex; align-items: baseline; gap: 9px;
  font-size: 12.5px; padding: 4px 0; border-bottom: 1px solid var(--line-2);
}
.pb-ver:last-child { border-bottom: none; }
.pb-ver .grow { flex: 1; min-width: 0; }

/* Republish is now a small form rather than a lone button: an optional note
   and whether to tell subscribers. */
.pb-republish {
  margin: 0; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface);
}
.pb-republish .field { margin-bottom: 6px; }
.pb-republish .field label { font-size: 12px; color: var(--ink-3); }
.pb-republish .field input { height: 30px; }

/* The version form is a real choice, not an aside. */
.pb-newver > summary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  background: var(--blue-50); border: 1px solid var(--blue-100);
  color: var(--blue-600); font-weight: 600; font-size: 12.5px;
  list-style: none;
}
.pb-newver > summary::-webkit-details-marker { display: none; }
.pb-newver > summary:hover { background: var(--blue-100); }
.pb-newver[open] > summary { background: var(--blue-600); color: var(--on-accent); border-color: var(--blue-600); }

/* Notify picker: groups and people, chosen at publish time rather than after. */
.nt-pick {
  margin: 10px 0; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--canvas);
}
.nt-hd {
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.nt-fixed {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; color: var(--ink-2); padding: 3px 0 6px;
}
.nt-fixed .ico { width: 14px; height: 14px; color: var(--green-600); }
.nt-already {
  font-size: 11.5px; color: var(--ink-3); padding: 4px 0 6px;
  border-top: 1px solid var(--line-2);
}
.nt-already code {
  font-size: 11px; margin-right: 5px; background: var(--surface);
  padding: 1px 5px; border-radius: 4px;
}
.nt-send { padding-top: 4px; }

/* Notify picker: type a name, get an address. Chosen entries become chips
   carrying hidden inputs, so the form submits addresses while the person only
   ever sees names. */
.nt-add { display: flex; gap: 6px; margin: 6px 0; }
.nt-add .nt-kind { width: auto; flex: none; }
.nt-add .nt-input { flex: 1; min-width: 0; }

.nt-chosen { display: flex; flex-wrap: wrap; gap: 5px; }
.nt-chosen:not(:empty) { margin-bottom: 8px; }
.nt-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 4px 2px 9px; border-radius: 999px;
  background: var(--blue-50); border: 1px solid var(--blue-100);
  color: var(--blue-600); font-size: 12px; font-weight: 600;
}
.nt-chipx {
  border: none; background: none; cursor: pointer; padding: 0 3px;
  color: var(--blue-600); font-size: 14px; line-height: 1; opacity: .7;
}
.nt-chipx:hover { opacity: 1; }

/* The document page uses the library's layout unchanged: the panes join as one
   surface. An earlier version added padding between them, which broke the join
   and made this read as a different page rather than the same one with a panel
   open. */

/* Managing a document happens below the folder it lives in rather than on a
   page of its own: the file stays visible, and closing returns you to exactly
   where you were instead of the library root. */
.doc-manage {
  position: relative;
  margin-top: 18px; padding: 18px 20px;
  background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--blue-600); border-radius: var(--r);
  box-shadow: var(--shadow-sm);
}
.doc-close {
  position: absolute; top: 12px; right: 14px;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink-3); background: var(--canvas);
}
.doc-close:hover { background: var(--line-2); color: var(--ink); text-decoration: none; }

/* The file being managed, marked in the listing above. */
table.lb tbody tr.is-managing td { background: var(--blue-50); }
table.lb tbody tr.is-managing td:first-child { box-shadow: inset 3px 0 var(--blue-600); }

/* The two panes stop at the listing; the panel below spans the full width.
   This modifier used to be called .doc-layout, which is the Documentation
   app's own grid: two unrelated pages sharing a class name, each one rule away
   from silently restyling the other. */
.lb-managing { align-items: start; }

/* The panel spans both columns: the tree and listing are the top of the page,
   the document panel is the whole width beneath them. */
.lb-managing > .doc-manage { grid-column: 1 / -1; }

/* The close is the only way out of this panel without navigating away, so it
   has to look like a control rather than a faint mark in a corner. */
.doc-close {
  top: 14px; right: 16px;
  width: 34px; height: 34px;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-2);
  box-shadow: 0 1px 3px rgba(15, 23, 42, .10);
  transition: background .12s, color .12s, border-color .12s;
}
.doc-close .ico { width: 18px; height: 18px; stroke-width: 2.4; }
.doc-close:hover {
  background: var(--red-600); border-color: var(--red-600); color: var(--on-accent);
}

/* ---------- Document panel: one state line, two regions ---------- */
/* The panel was five cards of equal weight -- status, publication,
   subscribers, version history, ownership -- each with its own header and its
   own badge, so nothing led and the document's condition had to be assembled
   from five places. Every state now reads on one line at the top, and the rest
   is two regions: what the document is, and who can see it. Everything on the
   panel is one or the other. */

.dm-head {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 0 44px 14px 0;
  border-bottom: 1px solid var(--line);
  margin-bottom: 16px;
}
.dm-head .ico-box {
  width: 42px; height: 42px; border-radius: var(--r); flex-shrink: 0;
}
.dm-head .spacer { flex: 1; }
.dm-head .btn { flex-shrink: 0; }
.dm-id { min-width: 0; }
.dm-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.dm-meta { margin: 7px 0 0; font-size: 12.5px; color: var(--ink-3); }

/* Drift, a lapsed review and an error sit between the state line and the
   regions: they are conditions of the document, read before anything is done
   to it. */
.dm-alert { margin-bottom: 14px; }
.dm-alert.a-red { border-left: 3px solid var(--a); }
.dm-alert.a-red strong { color: var(--a); }

.dm-region + .dm-region { margin-top: 14px; }
.dm-region .card-hd { padding: 10px 18px; }
.dm-region .card-hd h3 { font-size: 14px; }
.dm-body { padding: 16px 18px; }

/* Controls on the left, the record beside them. Both regions split the same
   way so the panel reads as one thing at two altitudes rather than two
   layouts. */
.dm-split {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px;
  gap: 22px; align-items: start;
}
.dm-split > * { min-width: 0; }
@media (max-width: 1000px) { .dm-split { grid-template-columns: 1fr; } }

/* A group that needs naming but not a header of its own: the point of the
   rework is that there are two headers on this panel, not seven. */
.dm-cap {
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.dm-sep { border-top: 1px solid var(--line-2); margin: 16px 0; }
.dm-note {
  margin: 10px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-3);
}
.dm-note:first-child { margin-top: 0; }
.dm-hint {
  margin-top: 4px; font-size: 11.5px; line-height: 1.45; color: var(--ink-4);
}

/* Status is one control, not a form: the state and the button that sets it. */
.dm-statusform { display: flex; align-items: flex-end; gap: 10px; }
.dm-statusform .field { flex: 1; min-width: 0; margin-bottom: 0; }

.dm-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 620px) { .dm-pair { grid-template-columns: 1fr; } }

/* Bounded: a document with forty events should not decide how tall the region
   is, and the controls beside it should stay on the same screen. */
.dm-side .tl { padding: 0; max-height: 300px; overflow-y: auto; }
.dm-side .tl-row { padding: 7px 0; }

/* Republish and unpublish, side by side, each in its own form -- a form cannot
   contain another form, and the previous markup closed one inside the other
   and left the browser to guess. The unpublish side carries the same bottom
   padding and hairline as the republish box, so the two buttons line up
   without either being nudged by hand. */
.pb-acts { display: flex; align-items: flex-end; gap: 10px; margin-top: 12px; }
.pb-acts .pb-republish { flex: 1; min-width: 0; }
.pb-acts .pb-unpub {
  padding: 10px 0; border-bottom: 1px solid transparent;
}
.pb-republish .ct-check { margin: 4px 0 10px; }

/* Publish and unpublish change what the whole company sees, so they should
   read as consequential rather than as two more grey buttons. */
form[action*="/publish"] > button.btn,
form[action*="/republish"] > button.btn {
  background: var(--blue-600); border-color: var(--blue-600); color: var(--on-accent);
}
form[action*="/publish"] > button.btn:hover,
form[action*="/republish"] > button.btn:hover {
  background: var(--blue-hover); border-color: var(--blue-hover);
}
form[action*="/unpublish"] > button.btn {
  background: var(--surface); border: 1px solid var(--red-100);
  color: var(--red-600);
}
form[action*="/unpublish"] > button.btn:hover {
  background: var(--red-600); border-color: var(--red-600); color: var(--on-accent);
}
form[action*="/unpublish"] > button.btn .ico,
form[action*="/publish"] > button.btn .ico { width: 15px; height: 15px; }

/* Unpublish removes the document from the whole company, so it reads as the
   consequential action it is rather than as a second grey button. */
.btn.is-danger {
  background: var(--red-50);
  border: 1px solid var(--red-100);
  color: var(--red-600);
  border-radius: 999px; font-weight: 650;
}
.btn.is-danger:hover {
  background: var(--red-600); border-color: var(--red-600); color: var(--on-accent);
}


/* A grid column will not shrink below its content unless told it may. The
   contact page is what is left in .doc-cols; the document panel has its own
   two-column region. */
.doc-cols > div { min-width: 0; }
.doc-manage .tl,
.doc-manage .tl-row,
.doc-manage .tl-body { min-width: 0; }
.doc-manage .tl-text,
.doc-manage .tl-head { overflow-wrap: anywhere; }

/* The tree shows the hierarchy and highlights where you are, so the folder
   trail says nothing new on a wide screen. It stays for narrow ones, where the
   tree is hidden and the trail is the only way to see the path or climb out. */
@media (min-width: 901px) {
  .lb-path { display: none; }
}

/* Status pills in the listing: one shape, one capitalisation, one left edge.
   The published pill carried its own left margin, so a row with two pills
   started further right than a row with one -- and the state badge is
   uppercased while the pill was not, which read as two unrelated systems. */
table.lb td .pb-pill { margin-left: 0; text-transform: uppercase; }
table.lb td .badge { text-transform: uppercase; }

/* Spacing between the pills without making the cell a flex container: a table
   cell told to be flex stops behaving as a cell, and the row's remaining width
   renders as a white block. The trap is already recorded; this is the second
   time it has been walked into.

   The published pill carries its own right margin instead, and an empty
   deferred span takes no space, so one pill and two start in the same place. */
table.lb td > span[id^="pub-"]:empty { display: none; }
table.lb td .pb-pill { margin-right: 6px; }

/* The state badge takes the same shape as the published pill: an icon, the
   word, the same padding and radius. Two pills side by side should look like
   one system rather than two. */
table.lb td .badge.lb-state {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .03em;
  white-space: nowrap;
}
table.lb td .badge.lb-state .ico { width: 12px; height: 12px; }

/* The pill shape applies wherever a state is shown, not only inside the
   listing table -- the card headers use the same markup. */
.badge.lb-state {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; white-space: nowrap;
}
.badge.lb-state .ico { width: 12px; height: 12px; }

/* The primary action of a card: a pill in Dignity Blue with white type.

   Everywhere but the document page, which keeps a pale pill matching its
   version control -- the `.doc-manage` rules below. This rule used to state
   that pale pill for every page, and lost the background to the portal's
   `.btn:not(.ghost):not(.sm)` (three classes against two) while keeping its
   blue text, so Convert, Promote, Import and Add all drew #2563eb on #174775
   -- a contrast of about 1.6:1, a button whose label could barely be read.
   Found by rendering and measured with getComputedStyle. The document page
   was spared only because `.doc-manage` adds the third class. */
.btn.is-primary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 16px; border-radius: 999px;
  background: var(--btn-grad); border: 1px solid transparent;
  color: var(--on-accent); font-weight: 600; font-size: 13px;
}
.btn.is-primary:hover {
  background: var(--btn-grad-hover); border-color: transparent;
  color: var(--on-accent);
}

/* The navy primary-button rule further up outranks this on background, so the
   four pills came out dark. Stated with enough specificity to win, since the
   point is that they match the version pill exactly. */
.doc-manage .btn.is-primary {
  background: var(--blue-50);
  border: 1px solid var(--blue-100);
  color: var(--blue-600);
}
.doc-manage .btn.is-primary:hover {
  background: var(--blue-100);
  border-color: var(--blue-500);
  color: var(--blue-600);
}

/* A firmer outline: at one pixel of pale blue the pill read as a label rather
   than something you press. */
.doc-manage .btn.is-primary {
  border: 1.5px solid var(--blue-500);
  font-weight: 650;
}
.doc-manage .btn.is-primary:hover {
  border-color: var(--blue-600);
  background: var(--blue-100);
}

/* The version control is a details summary rather than a button, so it missed
   the border the four buttons got. Same treatment: it is the same kind of
   choice and should look like one. */
.pb-newver > summary {
  border: 1.5px solid var(--blue-500);
  font-weight: 650;
}
.pb-newver > summary:hover {
  border-color: var(--blue-600);
  background: var(--blue-100);
}
.pb-newver[open] > summary {
  border-color: var(--blue-600);
}

/* The listing table could not shrink below its content, so it pushed past the
   document edge and forced a horizontal scrollbar -- which made the page look
   capped when it was actually overflowing. A table in a grid track needs both
   the track and the table told they may shrink. */
.lb-main { min-width: 0; }
.lb-main .table-wrap { max-width: 100%; }
table.lb { table-layout: auto; width: 100%; min-width: 0; }

/* This wrapper must not scroll. The rule above set overflow-x: auto, which
   silently undid the overflow: visible declared for the same selector earlier
   in this file -- and a scroll container clips its absolutely positioned
   children, so the row action menu was cut off at the card's edge. overflow-x:
   auto also forces the computed overflow-y to auto, so the clipping was
   vertical as well, which is how it presented. The name column's ellipsis
   below is what keeps the table inside its track; the scrollbar was treating
   the symptom and breaking the menu to do it. */

/* The file name is the column that should absorb the slack. */
table.lb tbody td:first-child,
table.lb thead th:first-child { max-width: 0; width: 45%; }
table.lb tbody td:first-child .lb-name {
  display: inline-block; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  vertical-align: middle;
}

/* A closed row menu still occupied space in the document's scroll width: it is
   fixed-position and placed by script, so it sat wherever it was last put and
   stretched the page. Hidden until open, so a menu nobody has clicked costs
   nothing. */
.tk-edit:not([open]) > .tk-menu,
.ft-menu:not([open]) > .tk-menu { display: none; }

/* The tree is sticky on the library page so it stays visible while a long
   listing scrolls. On the document page the listing is short and the panel
   below it is long, so sticky makes the tree slide away from the table it
   belongs to. It stays put here. */
.lb-managing .lb-tree { position: static; }

/* Admin stat rows. `.adm-stats` carried no rules at all, so every metric was
   a bare block at full page width with no card behind it -- on this page and
   on access readiness both. Layout comes from `.grid grid-metrics`, the same
   pair Key Metrics uses for its headline tiles; this class only centres them,
   scoped rather than applied to `.metric` itself, which is left-aligned
   elsewhere and shared. */
.adm-stats { margin-bottom: 16px; }
.adm-stats .metric { text-align: center; }
.adm-stats .metric .value { font-size: 26px; font-variant-numeric: tabular-nums; }
.adm-stats .metric .foot { line-height: 1.4; }

/* Library usage. The coverage bar, the file counts and the badges are the
   components the rest of the portal already uses -- .pj-bar, .badge and
   .ct-table -- so what is added here is only the parts that had no shape yet:
   the month strip and the dimming of a department the app was never activated
   on. */
.lu-table td { vertical-align: middle; }

/* Every column but the first holds a number, and a number reads under its own
   heading or not at all. Centred head and cell together: centring one and not
   the other is how a column comes to look misaligned when it is not. */
.lu-table th.mid, .lu-table td.mid { text-align: center; }
.lu-table td.mid { font-variant-numeric: tabular-nums; }

/* Faint column rules, the same border and token as the documents app, so the
   eye can track across a row without the grid becoming the loudest thing on
   the page. Not after the last column, which has nothing to separate it
   from. */
.lu-table thead th:not(:last-child),
.lu-table tbody td:not(:last-child) {
  border-right: 1px solid var(--line-2);
}

/* A row for a department without the library reads as context, not as a
   finding: it is not failing to use the app, it has not been given it. */
.lu-table tr.is-dim td { opacity: .55; }

/* The bar and its percentage sit as one centred unit under the heading. */
.lu-cov { display: flex; align-items: center; justify-content: center; gap: 8px; }

/* Secondary figures go under the number they qualify rather than beside it,
   so the number itself stays on the column's centre line. */
.lu-sub { display: block; margin-top: 3px; }
.lu-n { font-size: 14px; font-weight: 600; }

/* Six months across, oldest on the left, so a department that governed
   everything in March and nothing since reads as a shape rather than as a
   date somebody has to compare. A month with nothing in it keeps its cell:
   the gap is the information. */
.lu-months { display: flex; gap: 3px; justify-content: center; }
.lu-m {
  display: inline-flex; flex-direction: column; align-items: center;
  min-width: 26px; padding: 2px 0 3px;
  border-radius: 4px; background: var(--line);
}
.lu-m b {
  font-size: 11.5px; font-weight: 700; line-height: 1.3;
  font-variant-numeric: tabular-nums; color: var(--ink-3);
  /* An empty month renders no number, and a cell that collapsed to the height
     of its label would break the strip's baseline. */
  min-height: 15px;
}
.lu-m em {
  font-style: normal; font-size: 9.5px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-4); line-height: 1;
}
.lu-m.is-on { background: var(--blue-100); }
.lu-m.is-on b { color: var(--blue-600); }


/* Activity: people who did something, per day.

   A bar chart rather than a sparkline because the reader is comparing days to
   each other, not following a trend, and the numbers involved are small enough
   that a line would be mostly noise. Deliberately no chart library: this is
   one series of integers and a div per day renders it exactly.

   `.is-on` is scoped here rather than reused -- the only rule for that class
   in this file is `.lu-m.is-on`, so a bare `is-on` on an anchor would have had
   no rules at all and looked like nothing was applied. */
.act-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.act-tabs a { color: var(--ink-3); }
.act-tabs a.is-on { color: var(--blue-600); font-weight: 600; }

.act-graph {
  display: flex; align-items: flex-end; gap: 3px;
  height: 96px; margin: 12px 0 8px;
}
.act-col {
  flex: 1 1 0; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; height: 100%;
  min-width: 0;
}
.act-bar {
  width: 100%; background: var(--blue-600); border-radius: 2px 2px 0 0;
  min-height: 2px;
}
/* A day nobody did anything still draws a trace. A zero rendered as no bar at
   all is indistinguishable from a day the graph simply does not cover, which
   is the same mistake as showing a missing comparison as zero. */
.act-bar.is-empty { background: var(--line); min-height: 2px; height: 2px; }
.act-day {
  font-size: 10px; color: var(--ink-4); margin-top: 4px;
  line-height: 1; white-space: nowrap; overflow: hidden;
}

/* Adding a section, at the foot of the table it adds to.

   This was a second top-level fold beside Sections, which read as another
   subject on a page whose subject is the sections. It is now a control on that
   card: a green plus that names itself on hover and opens the same form.

   Green rather than Dignity Blue because it is the one additive action on the
   page and reads against a table of blue app toggles -- and green is outside
   the brand for the same reason the status colours are, which is that it means
   what it means whatever the palette does. */
.adm-addsec { border-top: 1px solid var(--line-2); }
.adm-addsec > summary {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; cursor: pointer; list-style: none;
  color: var(--ink-3); font-size: 13px;
}
.adm-addsec > summary::-webkit-details-marker { display: none; }

.adm-add-plus {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex: none; border-radius: 50%;
  background: var(--green-100); color: var(--green-600);
  border: 1px solid transparent; transition: background .12s, border-color .12s;
}
.adm-add-plus .ico { width: 15px; height: 15px; }
.adm-addsec > summary:hover .adm-add-plus,
.adm-addsec > summary:focus-visible .adm-add-plus {
  background: var(--green-600); color: #fff;
}
.adm-addsec[open] > summary .adm-add-plus { transform: rotate(45deg); }

/* The label is the hover affordance: the plus alone is the resting state, and
   the words arrive when a pointer does. `title` carries the same text for
   anyone who never hovers, and the label is a real element rather than
   generated content so a screen reader reads it either way. */
.adm-add-label, .adm-add-shut { opacity: 0; transition: opacity .12s; }
.adm-addsec > summary:hover .adm-add-label,
.adm-addsec > summary:focus-visible .adm-add-label,
.adm-addsec > summary:hover .adm-add-shut,
.adm-addsec > summary:focus-visible .adm-add-shut { opacity: 1; }
.adm-addsec[open] .adm-add-label { display: none; }
.adm-addsec:not([open]) .adm-add-shut { display: none; }

/* The form sits inside the card, so it takes the card's own padding rather
   than a second border around it. */
.adm-addsec > .adm-newsec { border-top: 1px solid var(--line-2); }

/* An edit panel positioned by script rather than by this stylesheet.

   `.table-wrap` scrolls, and an overflow ancestor clips an absolutely
   positioned child; and on a row near the foot of a long table the panel
   opened below the bottom of the page, reachable only by scrolling, which is
   the thing a popover exists to avoid. Flipping it upward is not the answer --
   that is what put an earlier row panel under the sticky header, where it
   could not be scrolled to at all.

   Fixed instead, placed from the summary's own rectangle and clamped to the
   viewport, so the whole panel is always on screen whatever the row's
   position. A fixed element ignores its container, so the coordinates cannot
   be inherited and have to be computed -- the same conclusion the folder tree
   menu reached.

   z-index clears the header's 40. The mobile rail's 60 still wins, which is
   right: the rail is a navigation surface and this belongs to the page under
   it. A panel taller than the window scrolls inside itself rather than
   overflowing off the top. */
.tk-panel.is-fixed {
  position: fixed; right: auto; z-index: 50;
  max-height: calc(100vh - 24px); overflow-y: auto;
}

/* An app badge that is a control, not a label.

   The Apps column toggles activation, and its badges were styled exactly like
   the Active/Hidden badges two columns over, which are not clickable: no
   border, no hover, and an inline `border:none` that no stylesheet rule could
   have overridden. So the column read as "the apps this section has" rather
   than "click to change", and the feature was there and unfindable. The
   outline and the hover are the whole fix. */
.badge.is-toggle {
  border: 1px solid currentColor; cursor: pointer;
  font-family: inherit; letter-spacing: .04em;
  transition: background .12s, color .12s;
}
.badge.is-toggle.blue:hover { background: var(--blue-600); color: #fff; }
.badge.is-toggle.grey:hover { background: var(--ink-4); color: #fff; }
.badge.is-toggle:focus-visible { outline: 2px solid var(--blue-600); outline-offset: 1px; }

/* A column header that says what its cells do. Lowercase against the header's
   own uppercase, so it reads as an aside rather than as part of the name. */
.th-hint {
  font-weight: 400; text-transform: none; letter-spacing: 0;
  color: var(--ink-4); margin-left: 6px;
}

/* The no-patients boundary on the contact list and the contact form. A quiet
   line rather than a warning box: it is said on every visit, and a box that
   shouts every time is a box people learn to skip. The amber icon is the one
   note of emphasis. */
.ct-boundary {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 12px; font-size: 12.5px; line-height: 1.45; color: var(--ink-3);
}
.ct-boundary .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; color: var(--amber-600); }

/* A type's definition, under the type picker. */
.ct-hint { margin: -2px 0 10px; font-size: 12px; line-height: 1.45; color: var(--ink-3); }
.ct-hint strong { color: var(--ink-2); font-weight: 600; }

/* ------------------------------------------------------------ Trip Planner

   The trip page is somebody's day on the road with their customers, and it is
   drawn as one: a road runs down the page from where they set off to where the
   day ends; every place on it is a sign -- a sunrise at the start, a
   service-sign plate for each stop with a picture of what it is, a checkered
   flag at the finish -- and the drive between two stops is the stretch of road
   between them, with a little car on it and a highway sign giving Google's
   time and distance once the route has been worked out.

   Colour comes from the brand with some licence. Dignity Blue for the signs,
   Sky Blue and Sandstone for warmth -- this is where Sandstone finally lives --
   and two road colours of our own: slate asphalt and highway-sign green.
   Coral is deliberately absent: it keeps its one job on the nav, and it sits
   too close to the red the refusals use.

   Geometry. The road is drawn by each item for its own height, so it runs
   continuously whatever each item contains; the first item starts it at its
   sign and the last ends it there. --rail-x is the road's centre and --node-y
   where an item's sign sits, and the road ends and the signs both read them,
   so they cannot disagree. */

.tp-hero, .tp-run {
  --tp-road: #3d4b5f;          /* asphalt: slate, leaning to the navy */
  --tp-road-soft: #d6dee8;     /* road not yet worked out */
  --tp-sign: #1d6b45;          /* highway-sign green, deeper than status green */
  --tp-sky-wash: color-mix(in srgb, var(--sky) 20%, var(--surface));
  --tp-sand-wash: color-mix(in srgb, var(--sandstone) 16%, var(--surface));
}

/* The trip list and the shared form grid. */
.tp-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0 12px; }
.tp-grid .tp-wide { grid-column: span 2; }
.tp-list { display: flex; flex-direction: column; }
.tp-trip {
  display: flex; align-items: center; gap: 14px; padding: 10px 16px;
  border-top: 1px solid var(--line-2); color: inherit; text-decoration: none;
}
.tp-trip:first-child { border-top: none; }
.tp-trip:hover { background: var(--line-2); text-decoration: none; }
/* A trip's row and its menu. The row is a <details>: the summary holds the
   link, which still opens the day, and an ellipsis that opens a strip under
   the row -- in the flow, so nothing clips it and a phone reads it the same. */
.tp-row { border-top: 1px solid var(--line-2); }
.tp-row:first-child { border-top: none; }
.tp-row > summary { display: flex; align-items: stretch; list-style: none; cursor: default; }
.tp-row > summary::-webkit-details-marker { display: none; }
.tp-row .tp-trip { flex: 1 1 auto; min-width: 0; border-top: none; }
.tp-row-more {
  flex: none; display: flex; align-items: center; justify-content: center;
  align-self: center; width: 40px; height: 32px; margin: 0 12px 0 0; border: 1px solid var(--line);
  border-radius: var(--r-sm); color: var(--ink-3); cursor: pointer;
}
.tp-row-more:hover, .tp-row[open] .tp-row-more {
  color: var(--dignity); border-color: var(--dignity); background: var(--line-2);
}
.tp-row-menu {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 22px;
  /* Right, under the ellipsis that opened it (Andrew, 5 October 2026): the
     strip belongs to the button, and at the left it read as the next row. */
  justify-content: flex-end;
  padding: 10px 12px 14px 16px; background: var(--line-2);
}
.tp-row-act { display: flex; align-items: flex-end; gap: 8px; margin: 0; }
.tp-row-act label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; font-weight: 600; color: var(--ink-2);
}
.tp-row-act label .ico { width: 13px; height: 13px; margin-right: 5px; vertical-align: -2px; }
.tp-row-act input[type="date"], .tp-row-act select {
  width: auto; min-width: 10rem; padding: 6px 9px; border-radius: var(--r-sm);
  font: inherit; font-size: 13px;
}
.tp-row-del { color: var(--red-600); }
.tp-row-note { flex: 1 1 100%; margin: 0; font-size: 12px; color: var(--ink-3); text-align: right; }
.tp-passed { background: #fef3c7; color: #92400e; }
/* Plan a trip's way back into the day being worked on, and a trip's way out. */
.tp-continue {
  display: flex; align-items: center; gap: 9px; margin: 0 0 14px; padding: 9px 13px;
  border: 1px solid var(--frame); border-radius: var(--r-sm); background: var(--line-2);
  color: var(--ink); font-size: 13.5px; text-decoration: none;
}
.tp-continue:hover { border-color: var(--dignity); text-decoration: none; }
.tp-continue .ico { width: 17px; height: 17px; color: var(--dignity); flex: none; }
.tp-views .tp-save-close { margin-left: auto; background: var(--btn-grad); border-color: transparent; color: #fff; }
.tp-views .tp-save-close:hover { background: var(--btn-grad-hover); border-color: transparent; color: #fff; }
@media (max-width: 560px) {
  .tp-row .tp-trip { flex-wrap: wrap; gap: 2px 10px; padding-right: 8px; }
  .tp-row .tp-day { width: auto; }
  .tp-row .tp-what { flex: 1 1 100%; }
  .tp-row-more { margin-right: 8px; }
  .tp-row-menu { flex-direction: column; align-items: stretch; }
  .tp-row-note { text-align: left; }
  .tp-row-act { flex-wrap: wrap; }
  .tp-row-act label { flex: 1 1 100%; }
  .tp-row-act input[type="date"], .tp-row-act select { width: 100%; }
}
.tp-day { flex: none; width: 120px; font-size: 12.5px; color: var(--ink-3); }
.tp-what { flex: 1; min-width: 0; }
.tp-what strong { display: block; font-size: 13.5px; }
.tp-what em { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); }

/* Inputs the base reset does not cover. Scoped here rather than added to the
   reset, which would restyle date fields on pages this change does not own. */
/* Their width and padding is this app's, because the base reset does not
   cover these three types. What a field *looks* like is not: the fill, the
   border and the inset shadow come from the one rule that answers that, so
   these cannot drift a shade away from every other box on the page. */
.tp-run input[type=number], .tp-run input[type=time],
.tp-grid input[type=number], .tp-grid input[type=time], .tp-grid input[type=date],
.tp-complete input[type=number] {
  width: 100%; padding: 8px 11px;
  border-radius: var(--r-sm);
  font: inherit; font-size: 14px; color: var(--ink);
}

/* ---- The greeting ----------------------------------------------------- */

.tp-hero {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 18px;
  margin: 2px 0 16px; padding: 18px 22px;
  border-radius: 14px; border: 1px solid color-mix(in srgb, var(--sky) 45%, var(--surface));
  background: linear-gradient(115deg,
              color-mix(in srgb, var(--sky) 34%, var(--surface)) 0%,
              color-mix(in srgb, var(--sandstone) 30%, var(--surface)) 100%);
}
/* A bend of road across the corner, for the fun of it. */
.tp-hero::after {
  content: ""; position: absolute; right: -60px; bottom: -70px;
  width: 280px; height: 160px; border-radius: 50%;
  border: 16px solid color-mix(in srgb, var(--tp-road) 16%, transparent);
  border-left-color: transparent; border-bottom-color: transparent;
  transform: rotate(-14deg); pointer-events: none;
}
.tp-dateplate {
  flex: none; width: 66px; overflow: hidden; text-align: center;
  background: var(--surface); border: 2px solid var(--dignity); border-radius: 11px;
  box-shadow: var(--shadow);
}
.tp-dateplate-wk {
  display: block; padding: 3px 0; background: var(--dignity); color: var(--on-accent);
  font-size: 11px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
}
.tp-dateplate-day { display: block; padding-top: 3px; font-size: 27px; font-weight: 800; line-height: 1.1; color: var(--dignity); }
.tp-dateplate-mo {
  display: block; padding-bottom: 5px; font-size: 11px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3);
}
.tp-hero-text { position: relative; z-index: 1; min-width: 0; }
.tp-hero h1 { margin: 0; font-size: 25px; font-weight: 750; letter-spacing: -.015em; color: var(--dignity); }
.tp-hero-line { margin: 2px 0 10px; font-size: 15px; color: var(--ink-2); }
.tp-hero-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.tp-hero-chips span {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 11px;
  border-radius: 999px; font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dignity) 14%, transparent);
}
.tp-hero-chips .ico { width: 14px; height: 14px; color: var(--dignity); }
.tp-hero-chips .is-done { background: var(--green-100); color: var(--green-600); }
.tp-hero-chips .is-done .ico { color: var(--green-600); }

/* ---- The day card ----------------------------------------------------- */

.tp-run { margin-bottom: 14px; border-radius: 14px; }
.tp-run-hd {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 14px 20px; border-bottom: 1px solid var(--line);
}
.tp-run-hd form { margin: 0; }
.tp-run-hd .spacer { flex: 1; }
.tp-run-badge {
  flex: none; width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--tp-sky-wash); color: var(--dignity);
}
.tp-run-title h3 { margin: 0; font-size: 15px; font-weight: 700; }
.tp-run-title span { font-size: 12.5px; color: var(--ink-3); }
.tp-run-title.is-inline { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
.tp-run-title.is-inline span { font-size: 12px; font-style: italic; }

.tp-run-meta {
  display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0;
  padding: 8px 20px; font-size: 12.5px; color: var(--ink-3);
  border-bottom: 1px solid var(--line-2);
}

/* Rounded, friendly buttons for this page's own actions. */
.tp-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 14px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--dignity); background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--dignity) 30%, var(--line));
  transition: background .12s, transform .12s;
}
.tp-pill .ico { width: 15px; height: 15px; }
.tp-pill:hover { background: var(--tp-sky-wash); }
.tp-pill:active { transform: translateY(1px); }
.tp-pill.is-primary { background: var(--btn-grad); border-color: transparent; color: var(--on-accent); }
.tp-pill.is-primary:hover { background: var(--btn-grad-hover); }
.tp-pill:disabled { opacity: .45; cursor: default; transform: none; }

/* Taking the day to Google Maps: a green "go" sign. */
.tp-go { padding: 12px 20px; border-bottom: 1px solid var(--line-2); }
.tp-go-links { display: flex; flex-wrap: wrap; gap: 8px; }
.tp-go-btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 7px 16px 7px 12px; border-radius: 10px; text-decoration: none;
  background: var(--tp-sign); color: var(--on-accent);
  box-shadow: inset 0 0 0 2px var(--tp-sign), inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 85%, transparent);
}
.tp-go-btn:hover { text-decoration: none; filter: brightness(1.08); }
/* The same plate as Let's go, in the portal's own action blue rather than
   highway green: two ways to leave with the day, told apart by colour. It is
   a button rather than a link because it opens a window instead of going
   somewhere. */
.tp-go-btn.is-mobile {
  --tp-sign: var(--dignity);
  border: 0; cursor: pointer; font: inherit; text-align: left;
}
.tp-go-btn .ico { width: 20px; height: 20px; }
.tp-go-btn span { display: flex; flex-direction: column; line-height: 1.2; font-size: 11.5px; opacity: .92; }
.tp-go-btn strong { font-size: 14px; opacity: 1; }
.tp-go-note {
  display: flex; align-items: flex-start; gap: 6px;
  margin: 8px 0 0; font-size: 12.5px; color: var(--ink-3);
}
.tp-go-note .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; }
.tp-go-note .ico.is-warn { color: var(--amber-600); }
.tp-go-note .ico.is-ok { color: var(--green-600); }
.tp-go-note.is-quiet { margin-top: 4px; color: var(--ink-4); }

/* A refusal, or a link withheld. These stay plain and serious: red for what
   stopped, amber when nothing failed but the reader should know. */
.tp-alert {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 12px 20px 0; padding: 12px 14px;
  background: var(--red-50); border: 1px solid var(--red-100);
  border-left: 3px solid var(--red-600); border-radius: var(--r-sm);
}
.tp-go .tp-alert { margin: 0; }
.tp-alert > .ico { flex: none; width: 18px; height: 18px; margin-top: 1px; color: var(--red-600); }
.tp-alert strong { display: block; font-size: 13.5px; color: var(--red-600); }
.tp-alert p { margin: 4px 0 0; font-size: 13px; color: var(--ink-2); }
.tp-alert ul { margin: 6px 0 0; padding-left: 18px; font-size: 13px; }
.tp-alert .tp-alert-admin { font-size: 12px; color: var(--ink-3); }
.tp-alert.is-soft { background: var(--amber-100); border-color: var(--amber-100); border-left-color: var(--amber-600); }
.tp-alert.is-soft > .ico, .tp-alert.is-soft strong { color: var(--amber-600); }

/* The day at a glance, above the road it is drawn on. */
.tp-dash-bar {
  margin: 12px 20px 0; padding: 10px 14px; border-radius: var(--r);
  background: var(--tp-sky-wash); border: 1px solid color-mix(in srgb, var(--sky) 40%, var(--surface));
}
.tp-dash { display: flex; flex-wrap: wrap; gap: 6px 20px; margin: 0; font-size: 13px; color: var(--ink-2); }
/* A flex item does not shrink below its content by default, so at a phone
   width each of these was breaking its own words -- "37 min" over two lines
   with the source chip squeezed out of shape beside it. `min-width: 0` lets
   the item shrink and the text wrap where words allow; the chip is held
   whole, because a label that has been squeezed narrower than its own word
   says nothing. The figures on this bar are read as a group, so they wrap as
   whole phrases rather than mid-word. */
.tp-dash-item { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
/* The figure and the label it wears are single words and stay whole; the
   prose between them is what gives way. Without this the figure itself broke
   -- "37 min" over two lines -- which is the one thing on the bar a reader is
   there for. */
.tp-dash-item > strong, .tp-dash-item .tp-src { flex: none; white-space: nowrap; }
.tp-dash-item .ico { width: 16px; height: 16px; color: var(--dignity); }
.tp-dash-note { display: flex; align-items: flex-start; gap: 6px; margin: 6px 0 0; font-size: 12.5px; color: var(--ink-3); }
.tp-dash-note .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; color: var(--dignity); }
.tp-dash-note.is-warn, .tp-dash-note.is-warn .ico { color: var(--amber-600); }

/* Whose figure it is. Google's drive, the rep's own time with a customer. */
.tp-src {
  display: inline-block; padding: 0 6px; border-radius: 999px;
  font-size: 10px; font-weight: 700; line-height: 16px;
  letter-spacing: .04em; text-transform: uppercase; vertical-align: 1px;
}
.tp-src.is-google { background: color-mix(in srgb, var(--tp-sign) 14%, var(--surface)); color: var(--tp-sign); }
.tp-src.is-yours { background: var(--tp-sand-wash); color: color-mix(in srgb, var(--sandstone) 45%, var(--ink)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sandstone) 55%, var(--surface)); }
/* **The third source, and it is deliberately the quietest.** A figure here is
   ours -- a straight line, a measured road factor and an assumed 30 mph -- so
   it is a plain outlined chip rather than the filled plates Google's and the
   rep's own figures wear. It should read as a placeholder for a real answer,
   because that is what it is: "Work out my times" replaces it. Neutral ink,
   no status colour: an estimate is not a warning. */
.tp-src.is-est {
  background: var(--surface); color: var(--ink-3);
  box-shadow: inset 0 0 0 1px var(--line);
}
.tp-dash-note.is-est, .tp-dash-note.is-est .ico { color: var(--ink-3); }
.tp-dash-note.is-est strong { color: var(--ink-2); }

/* Under the departure: how the clock was arrived at, and what to do about it.
   Small, because it is reasoning rather than an answer. */
.tp-end-note {
  display: block; max-width: 46ch; margin-top: 3px;
  font-size: 12px; line-height: 1.45; color: var(--ink-3); font-weight: 400;
}
.tp-end-note strong { color: var(--amber-600); }

/* Which half of the day the candidate panel is showing. Links, not a filter
   toggle: this narrows what is offered and changes nothing about the trip,
   which is the same reason the column folders are not `.segmented`. */
.tp-legs {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin: 0 0 10px; font-size: 12.5px; color: var(--ink-3);
}
.tp-legs a {
  padding: 4px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-2); text-decoration: none;
}
.tp-legs a:hover { border-color: var(--dignity); color: var(--dignity); }
.tp-legs a[aria-current] {
  background: var(--dignity); border-color: var(--dignity); color: var(--on-accent);
}
.tp-legs-said { flex-basis: 100%; }

/* **What this day is looking for.** A disclosure rather than a row of
   checkboxes always on show: most days choose nothing, and the panel's
   neutral order is the default that has to stay easy. Open when something is
   chosen, because then it is explaining the order the rep is reading. */
.tp-crit { margin: 0 0 10px; }
.tp-crit > summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  cursor: pointer; font-size: 12.5px; color: var(--dignity);
  padding: 8px 12px; border: 1.5px solid color-mix(in srgb, var(--dignity) 45%, var(--line));
  border-radius: 8px; background: var(--surface); list-style: none;
}
.tp-crit > summary:hover { background: var(--tp-sky-wash); border-color: var(--dignity); }
.tp-crit > summary:focus-visible { outline: 2px solid var(--dignity); outline-offset: 2px; }
.tp-crit-lead { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; }
.tp-crit-lead .ico { width: 15px; height: 15px; }
.tp-crit-state { color: var(--ink-3); font-weight: 500; }
.tp-crit > summary::-webkit-details-marker { display: none; }
.tp-crit > summary::after { content: " \25be"; margin-left: auto; color: var(--dignity); }
.tp-crit[open] > summary::after { content: " \25b4"; }
.tp-crit > summary b { color: var(--ink); font-weight: 600; }
.tp-crit-form {
  margin-top: 6px; padding: 11px 12px;
  border: 1px solid var(--line-2); border-radius: 8px; background: var(--canvas);
}
/* Said once, above the boxes: what "meets" means and what these describe.
   The area caveat in prose rather than on hover, which is the rule the
   figures themselves already follow. */
.tp-crit-why {
  margin: 0 0 9px; font-size: 12px; line-height: 1.5; color: var(--ink-3);
  max-width: 64ch;
}
.tp-crit-set { display: flex; flex-wrap: wrap; gap: 5px 14px; }
.tp-crit-set label {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; color: var(--ink-2);
}
/* A county figure ties every prospect in one county, so it is marked where
   it is chosen rather than explained after it has surprised somebody. */
.tp-crit-set em {
  font-style: normal; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-4);
}
.tp-crit-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--line-2);
  font-size: 12.5px; color: var(--ink-2);
}
.tp-crit-foot label { display: inline-flex; align-items: center; gap: 6px; }
/* The base form reset makes every select full width. */
.tp-crit-foot select { width: auto; padding: 3px 8px; font-size: 12.5px; }

/* A floor that finds nothing says what it is narrowing from. Not a warning:
   the rep asked a question and this is the answer, with the next one along
   offered as a link. */
.tp-crit-none {
  display: flex; align-items: flex-start; gap: 7px;
  margin: 0 0 10px; padding: 9px 12px;
  border: 1px solid var(--line-2); border-radius: 8px;
  background: var(--surface); font-size: 12.5px; color: var(--ink-2);
}
.tp-crit-none .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; color: var(--ink-4); }

/* A figure column whose signal fired. The mark is the weight and a tint, not
   a status colour: green and red here would be the portal judging a place,
   which is the rule the area figures' direction arrows already follow -- more
   chronic disease is a larger opportunity, not a worse place. This says only
   "this is one of the ones you asked for, and it counted". */
td.pr-num.is-fired {
  font-weight: 700; color: var(--dignity);
  background: color-mix(in srgb, var(--dignity) 6%, transparent);
}

/* Which signals a row met, under its name. Small, because it explains the
   order rather than being the thing a rep reads first. */
.tp-cand-met { margin-top: 2px; font-size: 11.5px; color: var(--ink-3); }
.tp-cand-met b { color: var(--dignity); font-weight: 700; }

/* An estimate is a whole day or none, so one unplaced address takes it away.
   Said where the times would have been, naming the address. */
.tp-unplaced {
  display: flex; align-items: flex-start; gap: 7px;
  margin: 0 0 14px; padding: 9px 12px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); font-size: 12.5px; color: var(--ink-3);
}
.tp-unplaced .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; color: var(--ink-4); }

/* A suggestion from Google: a preview road, warm, apart from the day. */
.tp-suggest {
  margin: 12px 20px 0; padding: 12px 14px 14px; border-radius: 12px;
  background: var(--tp-sand-wash); border: 1px solid color-mix(in srgb, var(--sandstone) 45%, var(--surface));
}
.tp-suggest-hd { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 6px; }
.tp-suggest-hd strong { display: block; font-size: 14px; color: var(--dignity); }
.tp-suggest-hd span { display: block; font-size: 12.5px; color: var(--ink-3); }
.tp-suggest-sign {
  flex: none; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  background: var(--sandstone); color: var(--dignity);
}
.tp-suggest-sign .ico { width: 16px; height: 16px; }
.tp-suggest .tp-dash { margin-top: 6px; }
.tp-suggest-use { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 12px; }
.tp-suggest-use span { font-size: 12.5px; color: var(--ink-3); }

/* ---- The road --------------------------------------------------------- */

.tp-spine {
  --rail-x: 30px;             /* the road's centre, from each item's left edge */
  --gutter: 72px;             /* where an item's content starts */
  --road-w: 14px;
  --road: var(--tp-road-soft);
  --lane: var(--surface);
  list-style: none; margin: 0; padding: 18px 20px 20px;
}
/* Worked out: dark asphalt with Sandstone lane markings. */
.tp-spine.has-times { --road: var(--tp-road); --lane: var(--sandstone); }

.tp-spine > li { position: relative; padding-left: var(--gutter); --node-y: 16px; }
.tp-spine > li::before {
  content: ""; position: absolute; top: 0; bottom: 0;
  left: calc(var(--rail-x) - var(--road-w) / 2); width: var(--road-w);
  background-color: var(--road);
  background-image: repeating-linear-gradient(to bottom, var(--lane) 0 7px, transparent 7px 15px);
  background-size: 2px 100%; background-position: center top; background-repeat: no-repeat;
}
.tp-spine > li:first-child::before { top: var(--node-y); }
.tp-spine > li:last-child::before { bottom: auto; height: var(--node-y); }

/* A stretch of road. With a schedule, a car rides on it and a highway sign
   beside it gives Google's time and distance. */
.tp-leg { min-height: 26px; display: flex; align-items: center; }
.tp-leg.is-short { min-height: 16px; }
.tp-leg.has-drive { min-height: 66px; }
.tp-car {
  position: absolute; z-index: 1; top: 50%;
  left: calc(var(--rail-x) - 15px); width: 30px; height: 30px; margin-top: -15px;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--sky); color: var(--dignity);
  box-shadow: 0 0 0 3px var(--surface), 0 2px 5px color-mix(in srgb, var(--ink) 22%, transparent);
  animation: tp-roll-in .55s ease-out both;
}
.tp-car .ico { width: 17px; height: 17px; }
@keyframes tp-roll-in { from { transform: translateY(-26px); opacity: 0; } to { transform: none; opacity: 1; } }

.tp-sign {
  display: inline-flex; flex-direction: column; align-items: flex-start;
  padding: 4px 11px 5px; border-radius: 7px; line-height: 1.2;
  background: var(--tp-sign); color: var(--on-accent);
  box-shadow: inset 0 0 0 2px var(--tp-sign), inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 88%, transparent);
}
.tp-sign strong { font-size: 14.5px; font-weight: 800; }
.tp-sign span { font-size: 11px; font-weight: 600; opacity: .9; }
.tp-sign.is-mini { flex-direction: row; padding: 2px 9px; font-size: 11.5px; font-weight: 700; }
.tp-sign.is-key { flex-direction: row; padding: 0 7px; font-size: 10.5px; font-weight: 800; border-radius: 4px; vertical-align: 1px; }

/* Signs on the road. */
.tp-mark {
  --mark: 34px;
  position: absolute; z-index: 2;
  left: calc(var(--rail-x) - var(--mark) / 2);
  top: calc(var(--node-y) - var(--mark) / 2);
  width: var(--mark); height: var(--mark); border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 800; line-height: 1;
}
.tp-mark .ico { width: 18px; height: 18px; }

/* Setting off: a sunrise. */
.tp-node.is-start .tp-mark {
  background: var(--sandstone); color: var(--dignity);
  box-shadow: 0 0 0 3px var(--surface), 0 2px 5px color-mix(in srgb, var(--ink) 18%, transparent);
}

/* A stop: a blue service-sign plate with a picture of what it is, and its
   place in the day on a Sandstone tab in the corner. */
.tp-node.is-stop { --node-y: 30px; padding-block: 4px; }
.tp-plate {
  --mark: 40px; border-radius: 10px;
  background: var(--dignity); color: var(--on-accent);
  box-shadow: inset 0 0 0 2px var(--dignity),
              inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 85%, transparent),
              0 0 0 3px var(--surface),
              0 3px 7px color-mix(in srgb, var(--ink) 22%, transparent);
}
.tp-plate .ico { width: 20px; height: 20px; }
.tp-plate b {
  position: absolute; top: -8px; right: -9px;
  min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--sandstone); color: var(--dignity);
  font-size: 11px; font-weight: 800; border: 2px solid var(--surface);
}
/* How the visit went, on the plate itself, so a finished day reads down the road. */
.tp-node.is-visited .tp-plate { background: var(--green-600); box-shadow: inset 0 0 0 2px var(--green-600), inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 85%, transparent), 0 0 0 3px var(--surface); }
.tp-node.is-skipped .tp-plate { background: var(--amber-600); box-shadow: inset 0 0 0 2px var(--amber-600), inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 85%, transparent), 0 0 0 3px var(--surface); }
.tp-node.is-not_reached .tp-plate { background: var(--ink-4); box-shadow: inset 0 0 0 2px var(--ink-4), inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 85%, transparent), 0 0 0 3px var(--surface); }

/* Adding a stop: a blank sign waiting to be filled in. */
.tp-node.is-add { --node-y: 17px; }
.tp-node.is-add .tp-mark {
  border-radius: 9px; background: var(--surface); color: var(--ink-3);
  border: 2px dashed var(--ink-4); box-shadow: 0 0 0 3px var(--surface);
}
.tp-node.is-add:hover .tp-mark { border-color: var(--dignity); color: var(--dignity); }

/* Heading to the finish: a checkered flag. */
.tp-node.is-finish { --node-y: 17px; }
.tp-node.is-finish .tp-mark {
  background: repeating-conic-gradient(var(--ink) 0 25%, var(--surface) 0 50%) 50% / 11px 11px;
  box-shadow: 0 0 0 2px var(--dignity), 0 0 0 5px var(--surface);
}

/* No finish: the day parks at the last stop. */
.tp-node.is-end { --node-y: 16px; }
.tp-node.is-end .tp-mark {
  --mark: 30px; border-radius: 8px; font-size: 16px;
  background: var(--dignity); color: var(--on-accent);
  box-shadow: inset 0 0 0 2px var(--dignity), inset 0 0 0 3.5px color-mix(in srgb, var(--surface) 85%, transparent), 0 0 0 3px var(--surface);
}

/* The start, the finish and the end: places on the road, lighter than a stop. */
.tp-end { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-height: 32px; padding-top: 6px; }
.tp-end-label {
  font-size: 11px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.tp-end-place { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.tp-end-place.is-quiet { font-weight: 400; color: var(--ink-3); }
.tp-end-time { font-size: 12.5px; font-weight: 700; color: var(--dignity); }

/* A stop: its own block, edged and washed in the colour of what it is -- a
   pharmacy green, a practice blue, a lab violet -- so each reads as its own
   visit and two in a row never run together. */
.tp-stop {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 4px solid var(--a, var(--dignity));
  border-radius: 12px; box-shadow: var(--shadow-sm);
}
.tp-stop-hd {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 9px 10px 8px 14px; border-bottom: 1px solid var(--line-2);
  border-radius: 0 11px 0 0;
  background: linear-gradient(to right,
              color-mix(in srgb, var(--a, var(--dignity)) 11%, transparent), transparent 75%);
}
.tp-stop-name { flex: 1; min-width: 0; line-height: 1.35; }
.tp-kicker {
  display: block; font-style: normal; font-size: 10.5px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--a, var(--dignity));
}
.tp-stop-name strong { display: block; font-size: 15px; font-weight: 700; }
.tp-stop-name span { display: block; font-size: 12.5px; color: var(--ink-3); }

.tp-stop-tools { display: flex; gap: 2px; flex: none; }
.tp-stop-tools form { margin: 0; }
.tp-tool {
  width: 28px; height: 28px; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: 999px;
  background: transparent; color: var(--ink-3); cursor: pointer;
}
.tp-tool .ico { width: 15px; height: 15px; }
.tp-tool:hover { background: var(--surface); border-color: var(--line); color: var(--ink); }
.tp-tool.is-remove:hover { color: var(--red-600); }
.tp-tool:disabled { opacity: .3; cursor: default; background: transparent; border-color: transparent; }

.tp-stop-addr {
  display: flex; align-items: flex-start; gap: 6px;
  margin: 0; padding: 8px 14px 0; font-size: 13px; color: var(--ink-2);
}
.tp-stop-addr .ico { flex: none; width: 14px; height: 14px; margin-top: 2px; color: var(--a, var(--ink-4)); }
.tp-stop-flags { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 6px 14px 0; }
/* Other listings of one business on one stop: a quiet line under the address. */
.tp-stop-also { padding: 4px 14px 0; font-size: 12.5px; color: var(--ink-2); }
.tp-stop-also p { display: flex; align-items: baseline; gap: 6px; margin: 0 0 2px; }
.tp-stop-also p > .ico { width: 14px; height: 14px; flex: none; align-self: center; }
.tp-stop-also .tp-also-npi { font-size: 11px; color: var(--ink-3); }
.tp-stop-also .tp-also-visits { font-size: 11.5px; color: var(--ink-3); margin: 2px 0 0 20px; }
.tp-cand-joins { display: block; margin-top: 3px; font-size: 11px; line-height: 1.2; color: var(--ink-3); white-space: nowrap; cursor: help; }


.tp-times {
  display: flex; flex-wrap: wrap; gap: 4px 26px;
  margin: 10px 14px 0; padding: 8px 12px;
  background: var(--canvas); border-radius: 10px;
}
.tp-times div { display: flex; flex-direction: column; }
.tp-times dt { font-size: 11px; font-weight: 600; color: var(--ink-3); }
.tp-times dd { margin: 0; font-size: 15px; font-weight: 750; color: var(--dignity); }
.tp-times .is-yours dd { color: var(--ink); }

.tp-stop-edit { padding: 10px 14px 12px; }
.tp-field { display: block; }
.tp-field > span:first-child {
  display: block; margin-bottom: 4px; font-size: 12px; font-weight: 600; color: var(--ink-2);
}
.tp-field em { font-style: normal; font-weight: 400; color: var(--ink-4); }
.tp-field-notes textarea { min-height: 0; resize: vertical; }
.tp-stop-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; margin-top: 8px; }
.tp-field-dwell { width: 140px; }
.tp-with-unit { display: flex; align-items: center; gap: 6px; }
.tp-with-unit input { width: 80px; }
.tp-with-unit em { font-size: 12.5px; }
.tp-field-outcome { width: 160px; }

.tp-stop-done { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0; padding: 10px 14px 0; font-size: 12.5px; color: var(--ink-3); }
.tp-stop-notes { margin: 0; padding: 8px 14px 12px; font-size: 13px; color: var(--ink-2); white-space: pre-wrap; }
.tp-stop-done:last-child { padding-bottom: 12px; }

/* The compact road inside a suggestion: names and times, no fields. */
.tp-spine.is-compact { --rail-x: 16px; --gutter: 42px; --road-w: 10px; padding: 6px 0 2px; }
.tp-spine.is-compact > li { --node-y: 12px; }
.tp-spine.is-compact .tp-node.is-stop { --node-y: 12px; padding-block: 0; }
.tp-spine.is-compact .tp-mark { --mark: 24px; }
.tp-spine.is-compact .tp-mark .ico { width: 14px; height: 14px; }
.tp-spine.is-compact .tp-plate b { position: static; min-width: 0; height: auto; padding: 0; border: 0; background: none; color: var(--on-accent); font-size: 11px; }
.tp-spine.is-compact .tp-node.is-start .tp-mark,
.tp-spine.is-compact .tp-plate { box-shadow: 0 0 0 3px var(--tp-sand-wash); }
.tp-spine.is-compact .tp-node.is-finish .tp-mark { box-shadow: 0 0 0 2px var(--dignity), 0 0 0 4px var(--tp-sand-wash); }
.tp-spine.is-compact .tp-node.is-end .tp-mark { --mark: 22px; font-size: 12px; }
.tp-spine.is-compact .tp-leg.has-drive { min-height: 30px; }
.tp-spine.is-compact .tp-end { min-height: 24px; padding-top: 1px; }
.tp-compact { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 10px; min-height: 24px; padding-top: 2px; }
.tp-compact strong { font-size: 13.5px; }
.tp-compact span { font-size: 12.5px; color: var(--ink-3); }

/* Adding a stop: the sign on the road unfurls into a small panel. */
.tp-add > summary {
  display: inline-flex; align-items: center; min-height: 34px;
  list-style: none; cursor: pointer;
  font-size: 14px; font-weight: 700; color: var(--dignity);
}
.tp-add > summary::-webkit-details-marker { display: none; }
.tp-add > summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.tp-add[open] > summary { color: var(--ink-2); }
.tp-add-full { margin: 0; padding-top: 8px; font-size: 12.5px; color: var(--ink-3); }
.tp-add-panel {
  margin: 4px 0 6px; padding: 12px 14px 14px; border-radius: 12px;
  background: var(--tp-sky-wash); border: 1px solid color-mix(in srgb, var(--sky) 40%, var(--surface));
}
.tp-tab-input { position: absolute; opacity: 0; pointer-events: none; }
/* Wraps, because three pill labels on one line are 322px and a phone's pane
   is 290. It was `inline-flex` with no wrap, so the third ran off the page. */
.tp-tabs { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.tp-tabs label {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 13px; border-radius: 999px; cursor: pointer;
  font-size: 13px; font-weight: 600; color: var(--dignity);
  background: var(--surface); border: 1px solid color-mix(in srgb, var(--dignity) 25%, var(--line));
}
.tp-tabs label .ico { width: 15px; height: 15px; }
#tp-add-contact:checked ~ .tp-tabs label[for="tp-add-contact"],
#tp-add-prospect:checked ~ .tp-tabs label[for="tp-add-prospect"],
#tp-add-typed:checked ~ .tp-tabs label[for="tp-add-typed"] {
  background: var(--dignity); border-color: var(--dignity); color: var(--on-accent);
}
#tp-add-contact:focus-visible ~ .tp-tabs label[for="tp-add-contact"],
#tp-add-prospect:focus-visible ~ .tp-tabs label[for="tp-add-prospect"],
#tp-add-typed:focus-visible ~ .tp-tabs label[for="tp-add-typed"] {
  outline: 2px solid var(--blue-500); outline-offset: 2px;
}
.tp-tab { display: none; }
#tp-add-contact:checked ~ .tp-tab-contact { display: flex; align-items: flex-end; gap: 10px; }
#tp-add-typed:checked ~ .tp-tab-typed { display: block; }
.tp-tab-contact .tp-field { flex: 1; min-width: 0; }
.tp-tab-typed .tp-field { margin-bottom: 10px; }
.tp-add-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 4px; }
.tp-add-foot span { font-size: 12.5px; color: var(--ink-3); }

/* ---------- The appointment, and the two legs it makes

   The one thing on this page that bounds the day rather than describing it,
   so it is drawn as the reason for the day rather than as one of its calls:
   its own plate, carrying the time it is booked for where the other stops
   carry a number, and a heavier edge on the block. Dignity Blue like the
   other sign plates -- it is the same road -- at the size that says which
   sign a driver reads first. */
.tp-anchor-plate {
  background: var(--dignity); color: var(--on-accent);
  border-radius: 10px; display: grid; place-items: center; gap: 0;
  box-shadow: 0 0 0 3px var(--surface), 0 1px 3px rgb(10 31 68 / .28);
}
.tp-anchor-plate .ico { width: 15px; height: 15px; }
.tp-anchor-plate b { font-size: 9.5px; letter-spacing: .02em; line-height: 1; }
.tp-node.is-anchor .tp-stop { border-width: 2px; }

/* Where one half of the day ends and the other begins. Said once on the road
   rather than on every stop: which leg a stop is on is its position either
   side of the appointment, and a label on each would be that fact written
   down a second time. */
.tp-legmark { display: flex; align-items: center; padding: 6px 0 6px var(--gutter); }
.tp-legmark span {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--ink-3);
  padding: 3px 10px; border-radius: 999px;
  background: var(--surface); border: 1px dashed var(--line);
}

/* "You will not make it." Plain, red and serious, like every other refusal on
   this page -- the playfulness stops where a rep has to act. */
.tp-conflict {
  display: flex; align-items: flex-start; gap: 7px;
  margin: 8px 0 0; padding: 8px 11px; border-radius: 9px;
  font-size: 12.5px; line-height: 1.45;
  color: var(--red-600); background: var(--red-50);
  border: 1px solid var(--red-100);
}
.tp-conflict .ico { width: 15px; height: 15px; flex: none; margin-top: 1px; }
.tp-booked { margin: 8px 0 0; font-size: 12.5px; color: var(--ink-3); }

/* Setting the appointment: its own form, because it posts somewhere else. */
.tp-book { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; margin-top: 8px; }
/* Wide enough for its own label, measured rather than guessed: the hint is
   299px on one line and the field was 192, so "makes this the day's /
   appointment" broke mid-phrase. The row has 1,197px to give and the input
   stays its own size, so the width costs nothing but the label. */
.tp-field-book { flex: 0 1 19rem; }
.tp-field-book input { width: auto; }

/* ---------- A stop, compact

   Andrew's ask: the stops should read tighter. Each was about 415px tall, and
   most of that was two forms stacked one field to a line -- notes, then time
   and outcome, then the appointment -- under an address on a line of its own.
   Now the address, the telephone and the kind with its size share one line,
   the times sit in a slimmer strip, and the two forms share a row that wraps.
   Written after the rules above on purpose: at equal specificity source order
   decides, which this file records three times. */
.tp-stop-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px;
  padding: 7px 12px 0 14px; font-size: 12.5px; color: var(--ink-2);
}
.tp-stop-meta .ico { flex: none; width: 14px; height: 14px; color: var(--a, var(--ink-4)); }
.tp-stop-meta .tp-stop-addr { display: inline-flex; align-items: center; gap: 5px; padding: 0; font-size: 12.5px; }
.tp-stop-phone { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.tp-stop-kind { color: var(--ink-3); }
.tp-stop-kind .tp-nowrap { white-space: nowrap; }

.tp-stop .tp-times { margin: 8px 14px 0; padding: 5px 10px; gap: 2px 22px; }
.tp-stop .tp-times div { flex-direction: row; align-items: baseline; gap: 6px; }
.tp-stop .tp-times dt { font-size: 11px; }
.tp-stop .tp-times dd { font-size: 14px; }
.tp-stop .tp-conflict { margin: 8px 14px 0; }
.tp-stop .tp-booked { margin: 8px 14px 0; }

.tp-stop-forms {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 18px;
  padding: 8px 14px 10px;
}
.tp-stop-forms .tp-stop-edit {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 10px;
  flex: 1 1 34rem; padding: 0;
}
.tp-stop-forms .tp-field > span:first-child { margin-bottom: 2px; font-size: 11.5px; }
.tp-stop-forms .tp-field-notes { flex: 1 1 15rem; }
.tp-stop-forms .tp-field-notes textarea { min-height: 34px; }
.tp-stop-forms .tp-stop-row { margin-top: 0; flex: 0 1 auto; min-width: 0; }
.tp-stop-forms .tp-book { margin-top: 0; flex: 0 1 auto; }
.tp-stop-forms .tp-field-book { flex: 0 1 auto; }

/* ---------- A stop, as one event

   Andrew: the road with a sign per stop reads, but the block beside it did
   not say "all of this is this stop". The card was a white slab with a thin
   rule, the same grey for every prospect, and nothing joined it to its sign.
   So: the card is framed all round in its own colour, not only down one
   edge; a short drive runs from the sign to the card at the sign's height;
   the header carries the stop's number; and the card being worked on -- a
   pointer over it, or a field inside it with focus -- lifts and rings, so
   the eye has one event to be on. Colour comes from what the stop is: a
   prospect's kind, a contact's type. */
.tp-node.is-stop .tp-stop {
  position: relative;
  border: 1.5px solid color-mix(in srgb, var(--a, var(--dignity)) 38%, var(--line));
  border-left: 6px solid var(--a, var(--dignity));
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(10, 31, 68, .06), 0 6px 18px -8px rgba(10, 31, 68, .18);
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
/* The drive from the sign to its card: from the sign's right edge to the
   card's left, at the sign's own height, in the card's colour. Derived from
   the rail's own three properties, so it moves when they do. */
.tp-node.is-stop .tp-stop::before {
  content: ""; position: absolute; z-index: 1;
  top: calc(var(--node-y) - 4px - 2.5px);
  left: calc(var(--rail-x) + 17px - var(--gutter) - 6px);
  width: calc(var(--gutter) - var(--rail-x) - 17px);
  height: 5px; border-radius: 3px;
  background: var(--a, var(--dignity));
}
.tp-node.is-stop .tp-stop:hover,
.tp-node.is-stop .tp-stop:focus-within {
  border-color: color-mix(in srgb, var(--a, var(--dignity)) 70%, var(--line));
  border-left-color: var(--a, var(--dignity));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--a, var(--dignity)) 22%, transparent),
              0 10px 26px -10px rgba(10, 31, 68, .30);
}
.tp-node.is-stop .tp-stop-hd {
  border-radius: 0 12px 0 0;
  border-bottom: 1px solid color-mix(in srgb, var(--a, var(--dignity)) 22%, var(--line-2));
  background: linear-gradient(to right,
              color-mix(in srgb, var(--a, var(--dignity)) 17%, transparent),
              color-mix(in srgb, var(--a, var(--dignity)) 4%, transparent) 70%);
}
.tp-node.is-stop .tp-stop-name strong { font-size: 16px; }
/* Three classes deep on purpose: `.tp-stop-name span` makes every span in the
   name block a grey block, and a modifier of a rule you did not write needs
   at least its specificity -- the recorded trap, met again. */
.tp-stop-name .tp-kicker .tp-stop-no {
  display: inline-block; margin-right: 8px; padding: 1px 8px; border-radius: 999px;
  font-size: 10.5px; color: var(--on-accent); background: var(--a, var(--dignity));
  letter-spacing: .06em;
}
/* The body is the event's detail, a shade off the white of the header's
   neighbours so the card reads as one object rather than a header over a
   form. */
.tp-node.is-stop .tp-stop-meta,
.tp-node.is-stop .tp-stop-forms { background: color-mix(in srgb, var(--a, var(--dignity)) 3%, var(--surface)); }
.tp-node.is-stop .tp-stop-forms { border-radius: 0 0 12px 0; }

/* Earlier / Later: one control in two halves, in the stop's own colour. */
.tp-stop-tools { align-items: center; gap: 8px; }
.tp-order {
  display: inline-flex; align-items: stretch; overflow: hidden;
  border: 1.5px solid color-mix(in srgb, var(--a, var(--dignity)) 55%, var(--line));
  border-radius: 999px; background: var(--surface);
}
.tp-order form { display: flex; margin: 0; }
.tp-order form + form { border-left: 1.5px solid color-mix(in srgb, var(--a, var(--dignity)) 30%, var(--line)); }
.tp-order-btn, .tp-remove {
  display: inline-flex; align-items: center; gap: 4px;
  height: 30px; padding: 0 12px 0 9px;
  border: 0; background: transparent; cursor: pointer;
  font-size: 12px; font-weight: 700; color: var(--a, var(--dignity));
}
.tp-order-btn .ico, .tp-remove .ico { width: 16px; height: 16px; }
.tp-order-btn:hover:not(:disabled) { background: var(--a, var(--dignity)); color: var(--on-accent); }
.tp-order-btn:disabled { color: var(--ink-4); opacity: .45; cursor: default; }
.tp-remove {
  border: 1.5px solid var(--line); border-radius: 999px; color: var(--ink-3);
  background: var(--surface);
}
.tp-remove:hover { color: var(--red-600); border-color: var(--red-100); background: var(--red-50); }
@media (max-width: 560px) {
  /* Icons only where the labels would push the name off the card. */
  .tp-order-btn span, .tp-remove span { display: none; }
  .tp-order-btn, .tp-remove { padding: 0 8px; }
}

/* The stop a write just added: marked where it landed, and the mark fades,
   because it is news rather than a state the stop is in. */
.tp-node.is-new .tp-stop {
  animation: tp-new-stop 2.4s ease-out 1;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--green-600) 55%, transparent), var(--shadow-sm);
}
@keyframes tp-new-stop {
  0%   { box-shadow: 0 0 0 5px color-mix(in srgb, var(--green-600) 45%, transparent), var(--shadow-sm); }
  100% { box-shadow: 0 0 0 2px color-mix(in srgb, var(--green-600) 55%, transparent), var(--shadow-sm); }
}

/* "Added": at the foot of the window, wherever the rep has scrolled to, and
   gone after a few seconds. Green because it is a success, which is what
   green means here whatever the palette does. */
.tp-toast {
  position: fixed; left: 50%; bottom: 22px; z-index: 60;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px;
  max-width: min(92vw, 40rem); padding: 10px 16px;
  border-radius: 12px; font-size: 13.5px; line-height: 1.35;
  color: var(--on-accent); background: var(--green-600);
  box-shadow: 0 10px 30px rgba(10, 31, 68, .25);
  animation: tp-toast 5s ease-in 1 forwards;
}
.tp-toast .ico { flex: none; width: 18px; height: 18px; }
.tp-toast a { color: inherit; font-weight: 700; white-space: nowrap; }
@keyframes tp-toast {
  0%, 80% { opacity: 1; visibility: visible; }
  100%    { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .tp-node.is-new .tp-stop { animation: none; }
}

/* A toast explaining where a stop went needs longer than one saying it
   went; "after the appointment" is the one a rep should not miss, so it is
   Dignity rather than green -- a fact to read, not a success. */
.tp-toast.is-long { animation-duration: 10s; }
.tp-toast.is-after { background: var(--dignity); }

/* The appointment: the one card with a fixed time, visible from anywhere on
   a long day. Four classes, to outrank `.tp-node.is-stop .tp-stop`. */
.tp-node.is-stop.is-anchor .tp-stop {
  border: 2.5px solid var(--dignity);
  border-left: 10px solid var(--dignity);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--dignity) 14%, transparent),
              0 10px 26px -10px rgba(10, 31, 68, .35);
}
.tp-node.is-stop.is-anchor .tp-stop-hd {
  background: var(--dignity); color: var(--on-accent);
  border-bottom-color: var(--dignity);
}
.tp-node.is-stop.is-anchor .tp-stop-name strong,
.tp-node.is-stop.is-anchor .tp-kicker { color: var(--on-accent); }
.tp-node.is-stop.is-anchor .tp-stop-name span:not(.tp-appt-time) { color: color-mix(in srgb, var(--on-accent) 80%, transparent); }
.tp-stop-name .tp-kicker .tp-appt-time {
  display: inline-flex; align-items: center; gap: 5px;
  margin-right: 8px; padding: 2px 10px; border-radius: 999px;
  font-size: 12px; letter-spacing: .04em;
  background: var(--sandstone); color: var(--navy-900);
}
.tp-stop-name .tp-kicker .tp-appt-time .ico { width: 14px; height: 14px; }
.tp-node.is-stop.is-anchor .tp-order { background: var(--surface); }
.tp-node.is-stop.is-anchor .tp-stop::before { height: 7px; }

/* The leaving time, set at the top of the day. */
.tp-leave { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.tp-leave label { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-size: 12.5px; font-weight: 700; color: var(--ink-2); }
.tp-leave input[type=time] {
  height: 30px; padding: 0 8px; border-radius: 8px;
  font: inherit; font-weight: 600; color: var(--ink);
}

/* A move that runs the way there over: the stops worth moving, one press each. */
.tp-overrun { max-width: min(92vw, 34rem); }
.tp-overrun .tp-demo-hd strong { color: var(--red-600); }
.tp-overrun .tp-demo-hd strong .ico { width: 18px; height: 18px; vertical-align: -3px; }
.tp-overrun-list { list-style: none; margin: 10px 18px 0; padding: 0; }
.tp-overrun-list li {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid var(--line-2); font-size: 13px;
}
.tp-overrun-list li > span { min-width: 0; }
.tp-overrun-list .muted { display: block; font-size: 12px; }
.tp-overrun-list form { margin: 0; flex: none; }
.tp-overrun .tp-demo-foot .tp-pill { margin-left: 6px; }

/* A candidate already on the day says so plainly, where the Add was. */
.tp-cand-on {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; font-weight: 700; color: var(--green-600); white-space: nowrap;
}
.tp-cand-on .ico { width: 14px; height: 14px; }

/* The ground a stop stands on, on request. A native dialog, so the browser
   supplies the backdrop, focus and Escape. */
.tp-demo {
  width: min(94vw, 44rem); max-height: 86vh; padding: 0;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface); color: var(--ink);
  box-shadow: 0 24px 60px rgba(10, 31, 68, .3);
}
.tp-demo::backdrop { background: rgba(10, 31, 68, .35); }
.tp-demo-hd {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 14px 10px 18px; border-bottom: 1px solid var(--line-2);
  position: sticky; top: 0; background: var(--surface);
}
.tp-demo-hd > div { flex: 1; min-width: 0; }
.tp-demo-hd strong { display: block; font-size: 16px; }
.tp-demo-hd span { display: block; margin-top: 2px; font-size: 12.5px; color: var(--ink-3); }
.tp-demo-where { margin: 10px 18px 0; font-size: 12.5px; color: var(--ink-2); line-height: 1.45; }
.tp-demo-table { width: calc(100% - 36px); margin: 10px 18px 0; border-collapse: collapse; font-size: 13px; }
.tp-demo-table th {
  padding: 6px 8px; text-align: left; font-size: 10.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3);
  border-bottom: 1px solid var(--line);
}
.tp-demo-table td { padding: 6px 8px; border-bottom: 1px solid var(--line-2); vertical-align: baseline; }
.tp-demo-table .pr-num { text-align: right; white-space: nowrap; }
.tp-demo-table td.muted { font-size: 11.5px; }
.tp-demo-county {
  font-style: normal; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-4);
}
/* Selection criteria: one button on the name row, right of the name with
   white space between, opening the window of figures. Filled when the stop
   was added for something, outlined when it was not. */
.tp-stop-crit {
  flex: none; align-self: center; margin-left: auto;
  display: inline-flex; align-items: center; gap: 5px;
  height: 30px; padding: 0 12px; border-radius: 999px; cursor: pointer;
  font-size: 12px; font-weight: 700; white-space: nowrap;
  color: var(--a, var(--dignity)); background: var(--surface);
  border: 1.5px solid color-mix(in srgb, var(--a, var(--dignity)) 55%, var(--line));
}
.tp-stop-crit .ico { width: 14px; height: 14px; }
.tp-stop-crit.is-set { color: var(--on-accent); background: var(--a, var(--dignity)); border-color: var(--a, var(--dignity)); }
.tp-stop-crit:hover { box-shadow: 0 0 0 3px color-mix(in srgb, var(--a, var(--dignity)) 22%, transparent); }
.tp-node.is-anchor .tp-stop-crit { border-color: var(--surface); }
.tp-node.is-anchor .tp-stop-crit.is-set { background: var(--sandstone); color: var(--navy-900); border-color: var(--sandstone); }
.tp-stop-hd .tp-stop-crit + .tp-stop-tools { margin-left: 0; }
.tp-demo-crit { font-size: 13px; }
/* A figure CMS reports that we hold as an estimate: dotted, so the hover
   saying so is findable. */
.tp-est { text-decoration: underline dotted color-mix(in srgb, currentColor 50%, transparent); text-underline-offset: 3px; cursor: help; }
@media (max-width: 560px) {
  .tp-stop-crit { height: 28px; padding: 0 9px; }
}
.tp-demo-table tr.is-chosen td { background: var(--tp-sky-wash); }
.tp-demo-table tr.is-chosen td:first-child { box-shadow: inset 3px 0 0 var(--dignity); font-weight: 600; }
.tp-demo-chosen {
  font-style: normal; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--dignity);
}
.tp-demo-foot { margin: 12px 18px 16px; font-size: 11.5px; color: var(--ink-3); line-height: 1.5; }
@media (max-width: 560px) {
  .tp-demo-table td.muted, .tp-demo-table th:last-child { display: none; }
}

/* ---------- The three folders, and handing a day over */

/* How many days each folder holds, so the tab says what is behind it. */
.tp-count {
  display: inline-block; margin-left: 5px; padding: 0 6px;
  border-radius: 999px; font-size: 10.5px; font-weight: 700;
  background: color-mix(in srgb, var(--dignity) 10%, var(--surface));
  color: var(--dignity);
}

/* Starting from a day already worked out. A disclosure, because it is the
   second way in and the form above is the first. */
.tp-copy { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 12px; }
.tp-copy > summary {
  cursor: pointer; font-size: 13px; font-weight: 700; color: var(--dignity);
  list-style: none;
}
.tp-copy > summary::-webkit-details-marker { display: none; }
.tp-copy > summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.tp-copy-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 8px 12px; border-bottom: 1px solid var(--line);
}
.tp-copy-row:last-child { border-bottom: 0; }
.tp-copy-row .tp-what { flex: 1 1 14rem; min-width: 0; }
.tp-copy-row input[type="date"] { width: auto; }

/* A day somebody has offered you is a question, not a day you are driving, so
   it sits apart from the list rather than as a row in it. */
.tp-offers { border-bottom: 1px solid var(--line); }
.tp-offers h4 {
  margin: 0 0 8px; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--ink-3);
}
.tp-offer {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 10px; margin-bottom: 6px;
  background: var(--tp-sky-wash);
  border: 1px solid color-mix(in srgb, var(--sky) 40%, var(--surface));
}
.tp-offer .tp-trip { flex: 1 1 18rem; min-width: 0; border: 0; background: none; }
.tp-offered { border-left: 3px solid var(--dignity); }
.tp-offered h3 { margin: 0 0 6px; font-size: 15px; }
.tp-offered p { margin: 0 0 10px; }
.tp-offer-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.tp-hand { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.tp-hand .tp-field { flex: 1 1 18rem; min-width: 0; }
.tp-hand select { width: 100%; }

/* The key to the two sources, at the foot of the day. */
.tp-run-ft {
  display: flex; flex-wrap: wrap; gap: 6px 22px;
  padding: 10px 20px 14px; border-top: 1px solid var(--line-2);
  font-size: 12px; color: var(--ink-3);
}

/* ---- Wrapping up, and the mileage record ------------------------------ */

.tp-explain { margin: 0 0 10px; font-size: 13px; line-height: 1.5; color: var(--ink-2); }
.tp-warn { display: flex; align-items: flex-start; gap: 6px; margin: 0 0 10px; font-size: 12.5px; color: var(--amber-600); }
.tp-warn .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; }
.tp-complete { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.tp-complete .field { margin-bottom: 0; width: 200px; }
.tp-miles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.tp-miles > div { padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; }
.tp-miles .tp-m { display: block; font-size: 22px; font-weight: 750; color: var(--dignity); }
.tp-miles em { display: block; margin-top: 2px; font-style: normal; font-size: 12px; color: var(--ink-3); }
.tp-details > summary { list-style: none; cursor: pointer; }
.tp-details > summary::-webkit-details-marker { display: none; }
.tp-details:not([open]) > summary { border-bottom: none; }

@media (prefers-reduced-motion: reduce) {
  .tp-car { animation: none; }
  .tp-pill { transition: none; }
}
@media (max-width: 760px) {
  .tp-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .tp-grid { grid-template-columns: 1fr; }
  .tp-grid .tp-wide { grid-column: auto; }
  .tp-hero { padding: 14px 16px; gap: 12px; }
  .tp-hero h1 { font-size: 21px; }
  .tp-spine { --rail-x: 22px; --gutter: 54px; --road-w: 12px; padding-inline: 12px; }
  .tp-plate { --mark: 34px; }
  .tp-run-hd, .tp-run-meta, .tp-go, .tp-run-ft { padding-inline: 14px; }
  .tp-alert, .tp-dash-bar, .tp-suggest { margin-inline: 14px; }
  .tp-miles { grid-template-columns: 1fr; }
  #tp-add-contact:checked ~ .tp-tab-contact { flex-direction: column; align-items: stretch; }
  #tp-add-prospect:checked ~ .tp-tab-prospect { flex-direction: column; align-items: stretch; }
}

/* ==========================================================================
   Prospects
   --------------------------------------------------------------------------
   A pipeline of several thousand rows, which is a different object from the
   directories elsewhere in the portal: it is read by filtering and scanning
   down a column rather than by reading rows, so density is the requirement and
   a row that wraps costs more than small type does.

   Reworked rather than extended. The first version inherited `width: 100%` on
   selects from the base form reset and never overrode it, so four short
   filters became four stacked rows and took a third of the page before a
   prospect appeared. Everything here that sets a width or a height says so on
   purpose; nothing relies on what the reset happens to do.

   Nothing here is a warning colour. The one status that could be mistaken for
   one -- "opted out of email" -- is deliberately plain grey beside the address
   it describes: a flag next to a pharmacy's name is read as "stay away"
   whatever the label says, so it sits with the channel it is about and looks
   like the fact it is.
   ========================================================================== */

/* One row. Four short controls, a search box that takes the slack, and the
   matching count pushed to the end where it does not compete with them. */
.pr-filters {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-bottom: 12px;
}
.pr-filters .field { margin: 0; flex: 1 1 220px; min-width: 160px; }
.pr-filters input[type=search] {
  height: 32px; padding: 0 10px; font-size: 13px;
}
/* width:auto is the whole fix: the base reset gives every select 100%, which
   makes each one its own line inside a flex row. */
.pr-filters select {
  width: auto; height: 32px; padding: 0 26px 0 9px; font-size: 13px;
  border-radius: var(--r-sm); color: var(--ink-2);
}
.pr-filters .btn { height: 32px; padding: 0 12px; font-size: 13px; }
/* Shown only when a filter is on. Unfiltered it would repeat the tab. */
.pr-filters .pr-count { margin-left: auto; font-size: 12.5px; color: var(--ink-3); }

/* The list itself.

   table-layout: fixed with a colgroup, so a long pharmacy name cannot widen
   the name column and squeeze the address out of the row: every column keeps
   the width it was given and overflow is an ellipsis with the full value in a
   title. min-width makes a narrow screen scroll the table rather than crush
   seven columns into nothing -- .table-wrap already scrolls. */
table.pr-list { table-layout: fixed; min-width: 1020px; font-size: 12.5px; }
table.pr-list thead th { padding: 7px 10px; font-size: 10.5px; letter-spacing: .04em; }
table.pr-list tbody td { padding: 6px 10px; }
table.pr-list tbody td,
table.pr-list thead th { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
table.pr-list th[aria-sort] a { color: var(--dignity); }
/* The status column is squeezed to its heading (62px in the colgroup), so it
   keeps its left padding and gives the right back: a dot needs no gutter after
   it, and "STATUS" needs every pixel it can have. */
table.pr-list th:first-child, table.pr-list td:first-child { padding-right: 2px; }
td.pr-status { text-align: left; }
table.pr-list .pr-none { color: var(--ink-4); }

/* Name and its marks. The cell is a flex row so the name ellipses while the
   marks beside it stay whole -- an ellipsis through a mark would hide the one
   thing the mark is there to say. */
td.pr-name { display: flex; align-items: center; gap: 6px; }
.pr-nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
         font-weight: 600; }

/* The NPI, and anything else read digit by digit rather than as a word. */
.pr-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; letter-spacing: .01em; color: var(--ink-2);
}

/* The CMS identity is a machine key printed on a record: the scheme, the
   group's PAC ID and the address id, 49 characters at its longest. In the place
   card's grid cell -- about 245px -- `.pr-mono` at 11.5px ran it straight across
   the next column and printed it over the street address. It gets a class of its
   own rather than a smaller `.pr-mono`, because that class also sets the ZIP, NPI
   and tract id cells, which fit their columns already.

   Drawn as the stamped field it is: small spaced lettering on a tinted ground,
   tabular figures so the digits line up, and breaking anywhere so no identity
   can overflow whatever CMS lengthens next. The template offers a <wbr> after
   each colon, so it prefers to break where the id's own parts divide.

   Deliberately NOT uppercased, whatever an official id looks like: 5,703 of the
   20,159 address ids carry lower-case letters, upper-casing one is how two
   addresses become one, and somebody copying a transformed id off the page
   would copy a different place's. */
.mp-ident {
  display: inline-block;
  max-width: 100%;
  margin-top: 3px;
  padding: 3px 7px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px;
  line-height: 1.7;
  letter-spacing: .08em;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  background: var(--canvas);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  overflow-wrap: anywhere;
}

/* Two rows may be one pharmacy enrolled twice, or two pharmacies in one plaza.
   The mark says "look", not "problem", so it is the same grey as the rest of
   the secondary text with an outline rather than a fill, and it keeps the
   question mark: the portal does not know, and a person decides. */
.pr-dup, .pr-out {
  flex: none; display: inline-block; padding: 0 6px;
  border: 1px solid var(--line); border-radius: 999px;
  font-size: 10.5px; line-height: 16px; color: var(--ink-3);
  white-space: nowrap;
}
.pr-dup { cursor: help; }

/* Status, as a bubble in its own column.

   Four tones for six statuses (STATUS_TONE in models.py): the colour says what
   to do about this pharmacy -- green working, amber a soft no, red do not
   approach, purple already a customer -- and the title says which status it
   is. Traffic-light colours, and outside the brand like every other status
   colour here: green means good and red means stop whatever the palette does.

   10px, which is the size the accent dots elsewhere in the portal settle on:
   big enough to read a hue from at a glance down a column, small enough that a
   column of them is not a column of buttons. The inner ring keeps a pale tone
   legible against the row hover. */
.pr-bub {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(15, 23, 42, .12); cursor: help;
}
.pr-bub.is-green  { background: var(--green-600); }
.pr-bub.is-amber  { background: var(--amber-600); }
.pr-bub.is-red    { background: var(--red-600); }
.pr-bub.is-purple { background: var(--purple-600); }
/* Added for the security page's severity dots: low and info, below amber. */
.pr-bub.is-slate  { background: #64748b; }
.pr-bub.is-grey   { background: #94a3b8; }
/* Read-only key/value list for the security finding page. */
.sec-kv { display: grid; grid-template-columns: auto 1fr; gap: 5px 14px; margin: 0; }
.sec-kv dt { color: var(--muted); font-size: 13px; }
.sec-kv dd { margin: 0; }
/* Clickable tally cards on the security Dashboard. */
.sec-card { position: relative; text-decoration: none; color: inherit;
  transition: box-shadow .12s ease, transform .12s ease; }
.sec-card:hover { box-shadow: 0 2px 12px rgba(15, 23, 42, .10); transform: translateY(-1px); }
.sec-card .label .ico { width: 15px; height: 15px; vertical-align: -2px; margin-right: 5px; color: var(--muted); }
.sec-chev { position: absolute; top: 14px; right: 12px; width: 16px; height: 16px; color: var(--muted); }
.sec-card .label { padding-right: 22px; }
.sec-card .foot { white-space: normal; line-height: 1.35; }

/* Which column set is open, drawn as folders.

   Deliberately not the .tabs component above it. Those are destinations and
   look like buttons; these change what is inside the drawer already open, and
   a control that looks identical to one doing a different job teaches people
   that neither means anything. So: the open folder is the same white as the
   pane below it, sits a pixel taller, and erases the rule under itself so the
   two read as one surface. The closed one sits back on the page ground.

   Left, and above the search row, because the search searches whichever
   folder is open. */
.pr-folders {
  display: flex; align-items: flex-end; gap: 3px;
  margin: 0; border-bottom: 1px solid var(--frame);
}
/* The upload row: two ways to choose, the answer to the warnings, and the
   button. A file picker is the browser's own control and is left alone --
   it is a button rather than a box to type in. */
.lb-upload { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 14px; }
/* The two buttons. Each says what it does, so nothing explains them; the
   input sits behind its own label, which is what makes the button open a
   file dialog with no script at all. */
/* `hidden` has to beat a component's own display. `.btn` is an inline-flex, so
   the no-script Upload button stayed on the page after script took it away. */
[hidden] { display: none !important; }

.lb-pick { position: relative; overflow: hidden; cursor: pointer; }
.lb-pick input[type=file] {
  position: absolute; inset: 0; opacity: 0; cursor: pointer;
  width: 100%; height: 100%; font-size: 0;
}
.lb-up-note { flex: 1 1 100%; }
/* Only drawn on a refusal somebody can answer, so it reads as the answer to
   the message above it rather than as a setting. */
.lb-up-yes {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 700; color: var(--ink);
}
.lb-up-yes input { margin: 0; }

/* **The listing frame is the drop target while the control is open.** A zone
   inside the fold is a small square to aim at; this is the thing somebody is
   already looking at, and it says so only while a drop would land. */
/* **The tree pane sits above the file pane, and that is not decoration.**
   `.lb-tree` is `position: sticky`, which creates a stacking context whatever
   its z-index -- so a folder menu inside it, fixed and `z-index: 40`, is
   trapped at the pane's own level rather than floating over the page. While
   `.lb-main` was unpositioned that was invisible; giving it `position:
   relative` for the drop overlay put the file card above the whole tree, and
   every folder menu opened behind it. The panes are ordered explicitly now,
   so the next positioned thing in here cannot do it again. */
.lb-tree { z-index: 3; }
.lb-layout .lb-main { position: relative; z-index: 1; }
.lb-layout .lb-main.is-dropping::after {
  content: "Drop here, into " attr(data-here-name);
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  border: 2px dashed var(--dignity); border-radius: var(--r-md);
  background: color-mix(in srgb, var(--dignity) 8%, var(--surface));
  color: var(--dignity); font-size: 15px; font-weight: 800;
  pointer-events: none;
}

/* **A folder row lit is where the drop will land.** The same ink as the
   frame, drawn on the row itself rather than round the pane, so the two
   answers to "where is this going" never both look true at once. */
.ft [data-drop-folder].is-drop-into {
  outline: 2px dashed var(--dignity); outline-offset: -2px;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--dignity) 12%, transparent);
}

/* **Something to watch while it uploads.** Over the page rather than in the
   fold, because the point is that nobody wonders whether it is doing
   anything -- and it takes the clicks, so a page being uploaded into is not
   also being navigated. */
.lb-progress {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10, 31, 68, .28);
}
.lb-progress-box {
  width: min(92vw, 26rem); padding: 18px 20px;
  border-radius: var(--r-md); background: var(--surface);
  box-shadow: 0 24px 60px rgba(10, 31, 68, .3);
}
.lb-progress-say { display: block; font-size: 15px; color: var(--ink); }
.lb-progress-rail {
  height: 6px; margin: 12px 0 8px; border-radius: 999px;
  background: var(--line); overflow: hidden;
}
.lb-progress-rail i {
  display: block; height: 100%; width: 0;
  background: var(--dignity); transition: width .15s linear;
}
.lb-progress.is-bad .lb-progress-rail i { background: var(--red-600); }
.lb-up-or { font-size: 12.5px; color: var(--ink-4); }
.lb-up-pick { display: inline-flex; align-items: center; gap: 6px; }
.lb-up-pick span { font-size: 12.5px; color: var(--ink-4); }
.lb-up-pick input[type=file] { font-size: 12px; max-width: 15rem; }
.lb-up-ok {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-size: 12.5px; color: var(--ink-3);
}
.lb-up-ok input { width: auto; }
.lb-upload .btn { flex: none; }

/* ---------- A department's apps, introduced ------------------------------

   Prose rather than tiles: a grid of cards under the switcher was the same
   control twice at two sizes. The name is the link, the app's own sentence
   sits under it, what is inside it is folded behind one word, and the figures
   -- where an app offers any -- are chips at the foot.

   **Each app carries its own accent**, from the twenty the portal already
   has and declared in its own manifest. Four entries in one colour read as a
   newspaper column, which is what this looked like before; an app's colour is
   data like its icon, so nothing here invents one and an app that has not
   said takes the department's. The colour does the structural work -- a rail
   down the entry, the medallion, the name, the chips -- and no entry is a box,
   so the switcher above stays the only row of boxes on the page. */
.app-intro { max-width: 68rem; margin: 6px 0 8px; }
.app-intro article {
  position: relative; margin: 0 0 4px; padding: 13px 18px 14px 20px;
  border-radius: var(--r-md);
  background: linear-gradient(100deg,
              color-mix(in srgb, var(--a) 7%, transparent) 0%,
              transparent 62%);
}
/* The rail is the entry's own colour, and it is the only edge it has. */
.app-intro article::before {
  content: ""; position: absolute; left: 0; top: 14px; bottom: 14px;
  width: 3px; border-radius: 3px; background: var(--a);
}
.app-intro h2 {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 6px; font-size: 15.5px; line-height: 1.2;
}
.app-intro h2 .ico-box {
  width: 28px; height: 28px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9px; background: var(--a-bg); color: var(--a);
  box-shadow: inset 0 0 0 1px var(--a-br);
}
.app-intro h2 .ico { width: 16px; height: 16px; }
.app-intro h2 a { color: var(--a); text-decoration: none; }
.app-intro h2 a:hover { text-decoration: underline; }
.app-go {
  display: inline-flex; color: var(--a); opacity: 0;
  transform: translateX(-4px); transition: opacity .12s, transform .12s;
}
.app-go .ico { width: 16px; height: 16px; }
.app-intro article:hover .app-go { opacity: .8; transform: translateX(0); }
.app-intro-lede {
  /* A wider measure as well as smaller type: a sentence that fits should sit
     on one line, and 46rem was breaking these mid-thought. */
  margin: 0 0 8px; max-width: 64rem;
  font-size: 13.5px; line-height: 1.5; color: var(--ink-2);
}
/* **One column, now that the list is folded away.** Two columns were a way
   of not spending height on six items; the disclosure spends none until
   somebody asks for it, so the saving bought nothing and cost the reading --
   a list of name-and-phrase reads down, not across. */
.app-parts {
  margin: 0; padding: 0; list-style: none;
  display: block;
}
.app-parts li {
  font-size: 12.5px; line-height: 1.55; color: var(--ink-3);
  padding-left: 13px; text-indent: -13px; margin-bottom: 2px;
}
.app-parts li::before {
  content: ""; display: inline-block; width: 5px; height: 5px; margin-right: 8px;
  border-radius: 50%; background: var(--a); opacity: .55; vertical-align: 3px;
}
.app-parts strong { color: var(--ink-2); font-weight: 700; }
/* The rest of the description, behind one word. The marker is the text, so
   the browser's own triangle goes -- it points at a list rather than at the
   sentence the reader is being offered. */
.app-more { margin: 0; }
.app-more > summary {
  display: inline-flex; align-items: center; gap: 4px;
  cursor: pointer; list-style: none;
  padding: 3px 10px; border-radius: 999px;
  background: var(--a-bg); box-shadow: inset 0 0 0 1px var(--a-br);
  font-size: 12.5px; font-weight: 700; color: var(--a);
}
.app-more > summary::-webkit-details-marker { display: none; }
.app-more > summary:hover { filter: brightness(.97); }
.app-more .say-less { display: none; }
.app-more[open] .say-more { display: none; }
.app-more[open] .say-less { display: inline; }
.app-more[open] .app-parts { margin-top: 10px; }
/* The figures as chips rather than a sentence: a pointer to be caught at a
   glance, with the number carrying the weight. */
.app-figs {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 10px 0 0; font-size: 12px; color: var(--ink-3);
}
.app-figs .fig {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 3px 10px; border-radius: 999px;
  background: var(--surface); box-shadow: inset 0 0 0 1px var(--line);
}
.app-figs b { color: var(--ink); font-weight: 800; font-size: 12.5px; }
.app-figs .fig.is-lead { background: var(--a-bg); box-shadow: inset 0 0 0 1px var(--a-br); }
.app-figs .fig.is-lead b { color: var(--a); }
.app-figs .quiet { padding: 3px 2px; color: var(--ink-4); }

/* ---------- The department's app switcher --------------------------------

   **A level above the folders, and drawn as one.** A page in Business
   Development can carry three rows: this, the app's own tabs, and the folders
   inside those. Three rows drawn alike would be three answers to where you
   are -- the failure `.segmented` was rejected for -- so this is an app bar
   rather than a folder row: icons, no boxes, and the one you are in marked by
   an underline and the portal's action colour rather than by being joined to
   the page. It sits on the page ground above everything the page draws. */
.app-switch {
  display: flex; flex-wrap: wrap; align-items: stretch; gap: 2px;
  margin: 0 0 16px; border-bottom: 1px solid var(--line);
}
.app-switch a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 13px; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--ink-3); font-size: 13px; font-weight: 700;
  text-decoration: none; white-space: nowrap;
}
/* **The icon carries the app's own colour, the label does not.** An app is
   then recognisable by its mark wherever it is drawn -- the department's
   Overview already is -- while the row still reads as one control: colour
   every label and the bar becomes a paint chart, and which one you are on
   stops being the thing the eye finds. A logo keeps its own colours, which
   is what a logo is for. */
.app-switch a .ico { width: 16px; height: 16px; color: var(--a, currentColor); opacity: .9; }
.app-switch a svg.ico { opacity: 1; }
.app-switch a[aria-current="page"] .ico { opacity: 1; }
.app-switch a:hover { color: var(--ink); background: var(--line-2); text-decoration: none; }
.app-switch a[aria-current="page"] {
  color: var(--dignity); border-bottom-color: var(--dignity);
  background: color-mix(in srgb, var(--dignity) 6%, transparent);
}
.app-switch a[aria-current="page"] .ico { opacity: 1; }
@media (max-width: 560px) {
  .app-switch { gap: 0; }
  .app-switch a { padding: 8px 10px; font-size: 12.5px; }
}

/* **The open folder is the only one drawn as a tab, and the pane closes the
   shape.** The distinction used to be one shade of white against canvas, which
   nobody could see; then it was 2px of Dignity Blue and a bar above, which was
   more pop than the job needs -- and the rule under the row was 2px while the
   tab erased 1px of it, so a hairline of blue ran under the open tab's name
   and read as a second border. It is the quiet version now: the open tab
   carries the same hairline as the pane, its own white fill and ink type, and
   erases exactly as much of the rule as there is; the closed ones carry no
   border, no fill, and greyer type, so they read as the ones you are not on.
   What makes it unmistakable is the pane below, which the border runs round. */
.pr-folders a {
  padding: 5px 16px 6px;
  /* **A closed folder erases nothing, so it sits on the rule rather than over
     it.** The open one is pulled a pixel down to lay its own white on the
     line; a closed one doing the same covers the line with its *fill* for its
     own width, which reads as the frame weakening wherever a folder sits on
     it. Measured: closed feet land 0px past the rule, the open one 1px over. */
  margin-bottom: 0;
  border: 1px solid var(--frame); border-bottom: none;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  background: color-mix(in srgb, var(--frame) 15%, var(--surface));
  color: var(--ink-3);
  font-size: 13px; font-weight: 600; line-height: 1.3;
  /* Depth at the foot: the folder falling away into the row rather than
     standing on it. Inset, so nothing is cast outside its own box. */
  box-shadow: inset 0 -7px 7px -7px rgba(10, 31, 68, .34);
}
.pr-folders a:hover {
  background: var(--surface); color: var(--ink); text-decoration: none;
  box-shadow: inset 0 -4px 6px -7px rgba(10, 31, 68, .16);
}
.pr-folders a[aria-current="page"] {
  background: var(--surface); color: var(--ink); font-weight: 700;
  border-color: var(--frame);
  /* The pane's own colour, laid over the rule, one pixel for one pixel: the
     folder and the pane below it stop being two things. Nothing else may do
     this, which is what leaves the frame whole everywhere else. */
  border-bottom: 1px solid var(--surface);
  margin-bottom: -1px;
  padding-top: 8px; padding-bottom: 7px;
  box-shadow: none;
}
/* **The pane the open folder leads onto, inside the same border.** A bordered
   tab above a bordered card was still two shapes with a gap between them, and
   which page belonged to which tab was left to the reader. The border is piped
   round the whole pane now: the row's rule is its top edge, the open folder
   erases that edge and nothing else does, and the sides and foot close it. */
.pr-pane {
  border: 1px solid var(--frame); border-top: none;
  border-radius: 0 0 var(--r-md) var(--r-md);
  background: var(--surface);
  margin-bottom: 16px;
}
/* **One frame, not two.** A pane holding a single card drew its own border a
   few pixels outside the card's -- two hairlines round one thing. The pane is
   the card there: the card inside it stops drawing a border of its own. A pane
   holding a page of cards keeps its padding and lets them draw theirs. */
.pr-pane > .card:only-child {
  border: none; box-shadow: none; border-radius: 0; margin: 0;
}
.pr-pane.is-page { padding: 14px; }
/* **One frame per page, however many rows of tabs it has.** The app's own row
   is folders now, and the pages under it -- the trips list, the pipeline, the
   directory -- carry a second row of their own. A pane inside a pane would be
   two boxes a dozen pixels apart, which reads as a mistake rather than as a
   hierarchy: the inner row keeps its tabs and its rule, and the outer frame is
   the only box. */
.pr-pane .pr-pane { border: none; padding: 0; margin: 0; border-radius: 0; }
.pr-pane .pr-pane > .card:only-child { border: 1px solid var(--line); border-radius: var(--r-md); }

/* The app's row wears the folder component: a little larger, because it is the
   row that says which part of the app you are in, and the way back to a list
   is a plain link at the end of it rather than a tab of its own. */
.tabs.pr-folders { gap: 3px; }
.tabs.pr-folders a { padding: 6px 16px 8px; font-size: 13px; }
/* Four pixels shorter than the open one, at this row's larger size: the same
   recess the component states, restated here because this rule comes later in
   the file and equal specificity is decided by source order. */
.tabs.pr-folders a:not([aria-current="page"]) { padding-top: 5px; padding-bottom: 8px; }
.tabs.pr-folders a[aria-current="page"] { padding-top: 9px; padding-bottom: 8px; }
.tabs.pr-folders .tab-back {
  margin-left: auto; border: none; background: none; color: var(--dignity);
  font-weight: 700; box-shadow: none;
}
.tabs.pr-folders .tab-back:hover { background: none; text-decoration: underline; }
/* Inside the pane the cards are the content, so the first one starts at the
   padding rather than a margin of its own, and a card that was carrying the
   pane's own border stops drawing a second one round the same thing. */
.pr-pane > .card:first-child { margin-top: 0; }
.pr-pane .pr-in-folder { margin-top: 0; }
.pr-in-folder { margin-top: 14px; }

/* Figures line up on their right edge, which is the only way a column of them
   can be compared by eye. The header goes with them, or it points at nothing. */
table.pr-list td.pr-num, table.pr-list th.pr-num { text-align: right; }
/* Fifteen columns rather than nine, all of them narrow. The floor was 1380px,
   which is wider than the 1274px pane a 1440 window gives, so the folder
   scrolled sideways at the width it is most used at -- found by rendering it.
   The colgroups now size each figure column to its measured heading, so the
   table fits the pane; 1180px is the 1200px pane of a 1366 laptop, and below
   that it scrolls rather than squeezing a figure under its own heading. */
table.pr-list.is-area { min-width: 1180px; }
/* The Areas tab's own table: twelve columns, none of them a street address, so
   it needs less room than the prospect list's area view. */
table.pr-list.is-areas-tab { min-width: 1120px; }

/* ---------- The working list on a phone
 *
 * **Nine columns and a 1,020px floor is a table you drag sideways**, which is
 * what a rep in a car park was doing. The table was never escaping the page --
 * `.table-wrap` contained it exactly as designed -- so nothing was broken;
 * it was simply unusable at 390, which is where it is most used.
 *
 * So below 560 each row stops being a row and becomes a block: the status dot
 * and the name at the top, then every other column as a label and a value on
 * one line. **Nothing is hidden.** Every figure a rep can see at 1440 is
 * there, with the heading it sits under, which is what `data-label` carries --
 * added to the cells and to nothing else, so what the list *shows* is
 * unchanged at every width.
 *
 * The headings go, because each value now carries its own; the sort controls
 * go with them, which is the one thing lost. Sorting nine ways is a desk job,
 * and the filters -- town, ZIP, kind, radius, corridor -- are all still there.
 */
@media (max-width: 560px) {
  table.pr-list, table.pr-stack,
  table.pr-list tbody, table.pr-stack tbody,
  table.pr-list tr, table.pr-stack tr,
  table.pr-list td, table.pr-stack td { display: block; width: auto; }
  /* The floor is what forced the drag; below it there is no table to fit.
     Every floor, by name: `table.pr-list.is-area` is two classes and an
     element, so a rule on `table.pr-list` alone loses to it and the Area
     folder went on dragging at 1,180px while the first folder was fixed. The
     recorded modifier trap, in the component that taught it. */
  table.pr-list,
  table.pr-list.is-area,
  table.pr-list.is-areas-tab,
  table.pr-list.tp-cand-list,
  table.pr-stack { min-width: 0; }
  table.pr-list colgroup, table.pr-list thead, table.pr-stack thead { display: none; }
  table.pr-list tr, table.pr-stack tr {
    padding: 11px 13px; border-bottom: 1px solid var(--line);
    position: relative;
  }
  table.pr-list td, table.pr-stack td {
    padding: 2px 0; border: 0; text-align: left;
    display: flex; align-items: baseline; gap: 8px;
    white-space: normal; overflow: visible; text-overflow: clip;
  }
  table.pr-list td::before, table.pr-stack td::before {
    content: attr(data-label);
    flex: 0 0 8.5rem; color: var(--ink-3);
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .04em;
  }
  /* A cell with no label is the row's own subject: the status dot and the
     name, which read without one -- "Status:" beside a dot says nothing. */
  table.pr-list td[data-label=""]::before,
  table.pr-stack td[data-label=""]::before { content: none; }
  table.pr-list td.pr-status { position: absolute; right: 13px; top: 13px; padding: 0; }
  table.pr-list td.pr-name { padding-right: 26px; }
  table.pr-list td.pr-name .pr-nm { font-size: 14px; white-space: normal; }
  table.pr-list td.pr-num { text-align: left; }
  /* The name and the street are the two a rep reads; they were ellipsised to
     hold a column width that no longer exists. */
  table.pr-list .pr-addr { white-space: normal; overflow: visible; }
}

/* A plain table in a wrap, at a phone width: let it wrap rather than drag.
   Collection's two columns were 518px in a 330px pane purely because one
   label is a sentence. */
@media (max-width: 560px) {
  .table-wrap table td, .table-wrap table th { overflow-wrap: anywhere; }
}

/* The sorts, for the width where the header row that holds them is gone.

   Hidden above 560px rather than shown below it, so the headings stay the one
   control at a width that has room for nine of them, and this is the whole of
   the fallback rather than a second control competing with them. A disclosure
   because a closed summary is one line and already says which sort is on,
   which is the thing a rep reads before deciding to change it. */
.pr-sortby { display: none; }
@media (max-width: 560px) {
  .pr-sortby { display: block; margin: 0 0 8px; }
  .pr-sortby > summary {
    cursor: pointer; font-size: 12.5px; color: var(--ink-2);
    padding: 7px 10px; border: 1px solid var(--line-2); border-radius: 8px;
    background: var(--surface); list-style: none;
  }
  .pr-sortby > summary::-webkit-details-marker { display: none; }
  .pr-sortby > summary::after { content: " \25be"; color: var(--ink-3); }
  .pr-sortby[open] > summary::after { content: " \25b4"; }
  .pr-sortby > summary b { color: var(--ink); font-weight: 600; }
  .pr-sortby ul {
    margin: 6px 0 0; padding: 6px; list-style: none;
    border: 1px solid var(--line-2); border-radius: 8px; background: var(--surface);
    display: flex; flex-wrap: wrap; gap: 6px;
  }
  .pr-sortby li { margin: 0; }
  .pr-sortby a {
    display: block; padding: 7px 10px; font-size: 12.5px;
    border: 1px solid var(--line-2); border-radius: 7px;
    color: var(--ink); text-decoration: none; background: var(--canvas);
  }
  .pr-sortby a[aria-current] {
    background: var(--dignity); border-color: var(--dignity); color: var(--on-accent);
  }
}



/* A row whose figures describe a ZIP code area rather than a census tract,
   because the geocoder could not place the address. It is not a warning -- the
   figures are real -- it is the geography, which has to travel with them. */
.pr-coarse {
  flex: none; display: inline-block; padding: 0 6px;
  border: 1px solid var(--line); border-radius: 999px;
  font-size: 10.5px; line-height: 16px; color: var(--ink-3);
  white-space: nowrap; cursor: help;
}

/* Where a figure came from, under the figure. The trip planner tags every
   number GOOGLE or YOURS for the same reason: a number whose basis is not
   beside it gets read as one the portal measured. */
.pr-basis { display: block; font-size: 11px; color: var(--ink-4); margin-top: 2px; }

/* The key under the area table: what each figure is, what it does not mean,
   and the attribution the Census terms require verbatim. Small, quiet, and
   always there -- a caveat that appears only on hover is a caveat nobody
   reads. */
/* The kind filter, on the ground row because kind composes with the ground.
   Checkboxes rather than a multiple-select: four fit on the row and a rep can
   see what is on without opening anything. */
.pr-kinds { display: inline-flex; gap: 12px; flex-wrap: wrap; align-items: center;
            font-size: 13px; color: var(--ink-2, #3b4453); }
.pr-kinds label { display: inline-flex; gap: 5px; align-items: center;
                  white-space: nowrap; cursor: pointer; }
.pr-kinds input { margin: 0; }

/* The packing list: what a rep reads before loading the car.

   Given rules rather than left as a bare class, which is the trap `adm-stats`
   already taught -- a class a template uses may have no rules at all, and the
   markup reads as though it should work. It sits between the filters and the
   table because that is the order of the act: choose the ground, read what to
   take, then look at where you are going. */
.pr-packing {
  margin: 14px 0 4px; padding: 12px 14px; border-radius: 8px;
  background: var(--wash-1, #f6f8fb); border: 1px solid var(--line-1, #e3e8ef);
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.pr-packing strong { font-size: 15px; }
.pr-packing > .muted { font-size: 13px; }
.pr-packing ul { display: flex; gap: 14px; flex-wrap: wrap; margin: 0; padding: 0;
                 list-style: none; font-size: 13px; }
.pr-packing li b { font-variant-numeric: tabular-nums; }
.pr-packing .btn { margin-left: auto; }

.pr-key { margin-top: 14px; font-size: 12px; color: var(--ink-3); line-height: 1.55; }
.pr-key p { margin: 0 0 8px; }
.pr-key strong { color: var(--ink-2); }
.pr-key b { color: var(--ink-2); font-weight: 600; }
.pr-key span { display: block; margin-left: 14px; }
.pr-attrib { color: var(--ink-4); font-size: 11.5px; }

/* Address and the fact about the channel, on one line. */
td.pr-email { display: flex; align-items: center; gap: 6px; }
.pr-addr { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pr-out { cursor: help; }

.pr-pager {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-top: 14px;
}
.pr-pager .btn { padding: 4px 10px; font-size: 12.5px; }
.pr-pager .muted + .btn { margin-left: 4px; }

/* The record, as label-over-value pairs that wrap to one column on a phone. */
.pr-kv {
  display: grid; gap: 14px 24px;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.pr-kv > div { min-width: 0; }
.pr-kv .muted { display: block; font-size: 11.5px; text-transform: uppercase;
                letter-spacing: .04em; margin-bottom: 2px; }

.pr-log { list-style: none; margin: 0; padding: 0; }
.pr-log > li {
  padding: 10px 0 10px 12px; border-left: 2px solid var(--line);
  font-size: 13px;
}
.pr-log > li + li { margin-top: 2px; }
.pr-log > li strong { font-weight: 600; margin-right: 6px; }
.pr-log > li .muted { font-size: 12px; margin-right: 6px; }
/* A system entry states what the portal did; it must not read as something a
   colleague wrote, so it is lighter and its rail is dotted. */
.pr-log > li.is-system { border-left-style: dotted; color: var(--ink-3); }

/* A message about what just happened. Built on .card .card-pad like the
   library's, so it sits in the page the same way the cards around it do. */
.pr-note { margin-bottom: 14px; border-left: 3px solid var(--green-600); }
.pr-note.is-bad { border-left-color: var(--red-600); }

/* A control that belongs to the line it sits on -- "not the same pharmacy"
   beside the prospect it refers to, rather than under the list. */
.pr-inline { display: inline; margin-left: 8px; }

/* The third way into a day: a prospect, somewhere we do not do business with
   yet. It was the contacts tab's shape -- one picker and a button on a line --
   and that was the fault: a `<select>` option holds one line, so a rep chose a
   stop from a name and a city while kind, size, the tract figures and who to
   ask for were a click away on a page that meant leaving the trip. It is a
   panel now, so it stacks and takes the width rather than sitting on a line. */
#tp-add-prospect:checked ~ .tp-tab-prospect { display: block; }

/* The narrowing row above the panel. Reaching past the fifty on screen is the
   filters, not a bigger cap -- the same answer the picker's cap got -- so
   these sit where the reader looks before scrolling. Every control posts to
   the one form by `form=`, which is outside the day's own forms: a form in
   another form is reparented by the browser, which is recorded in Traps. */
.tp-tab-prospect > .tp-field { display: block; margin-bottom: 10px; }
.tp-narrow {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  margin-top: 6px;
}
/* Every select is 100% wide from the base form reset, and an input in a flex
   row inherits nothing that stops it growing. Both are stated, which is the
   recorded trap about a control row. */
.tp-narrow input[type="search"] { width: auto; flex: 0 1 11rem; min-width: 7rem; }
.tp-narrow .pr-kinds { gap: 6px 12px; }
/* The corridor's own row: it posts somewhere else, so it is its own form and
   sits under the rest of the narrowing rather than inside it. */
.tp-along { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--line); }
.tp-note-mark { margin-left: 2px; font-weight: 700; color: var(--dignity); text-decoration: none; }

/* ---------- The candidate panel

   It shows; it does not rank. So nothing here is a scale, a bar or a tint that
   would read as a judgement of ours about which visit is worth making: it is
   the working list's own table, at the working list's own size, with the
   figures right-aligned so a column can be compared down rather than across.
   The list component is worn rather than copied, for the reason the directory
   wears it -- one stylesheet, and a rep who has used one list can use this. */
.tp-cands { margin-top: 4px; }
.tp-cands-hd {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  margin-bottom: 8px; font-size: 12.5px;
}
.tp-cands-hd strong { font-size: 13px; color: var(--ink); }
/* The panel sits inside the add-stop wash, so the table needs its own white
   ground to read as the surface the rows are on. */
.tp-cands .table-wrap {
  max-height: 22rem; overflow: auto;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
}
/* A floor, so the panel scrolls sideways rather than squeezing a heading under
   itself -- the Area folder's answer, for the same reason, and measured the
   same way. Below it the last column, which is unsized so the leftover lands
   there, is the one that runs out: at 1,020px it gets 62px and clips "Who to
   ask for". 72.5rem is the width at which every heading still fits, so the
   panel reads whole at 1440 and 1920 and scrolls rather than clips below.

   `table.pr-list.is-area` is the shape to copy and the reason: `table.pr-list`
   sets the 1020px floor and wins on specificity over a bare class, so a
   `.tp-cand-list` floor is kept only for what that rule does not set and the
   width silently stays 1020. Measured, not read off the selector. */
/* The floor grows with the figure columns the rep asked for, so past three
   the wrap scrolls rather than squeezing a heading. The template sets
   `--cand-floor` because only it knows how many columns there are; the
   fallback is the floor this table had before criteria existed.

   Read through a property rather than set inline, because an inline
   `min-width` beats a media query too -- and that silently took the phone
   layout away, which was found by measuring 390px rather than by reading
   the rule. */
table.pr-list.tp-cand-list {
  font-size: 12px; min-width: var(--cand-floor, 1160px);
}
/* The practice's specialty under its kind in the candidate panel: the one
   thing on the line a rep reads to tell a cardiology practice from a GP, so a
   touch stronger than the muted size lines around it. */
.tp-cand-spec { font-weight: 600; color: var(--dignity); }
@media (max-width: 560px) {
  /* **After the floor, not before it.** The phone block that clears every
     list's width floor sits 230 lines above this rule and names this table
     among them -- at equal specificity source order decides, so its
     `min-width: 0` lost and the candidate panel went on dragging 860px at
     390 while every other list stacked. It has done since the panel was
     written, because the panel was added after that block; found by
     measuring rather than by reading the rule, which is the third time this
     file records the same fault. */
  table.pr-list.tp-cand-list { min-width: 0; }
  /* **One value per stacked line.** A stacked cell is a flex row of its
     label and its content, so a cell holding three blocks -- the kind, its
     count, the busiest panel; a name, its address, its signals -- laid them
     side by side and squeezed each to a sliver. Each such cell wraps its
     content in one `.tp-cell`, which is the one flex item beside the label
     and may shrink to the width left. */
  table.pr-list.tp-cand-list td .tp-cell { flex: 1 1 auto; min-width: 0; }
  /* **The label goes above its value here, not beside it.** The panel sits
     inside the day, beside the road rail, and at 390 it is 220px wide -- the
     list's 136px label column left 76px for a value, so an address, a
     telephone and "busiest 640 Medicare pts" ran off the right edge. The
     pipeline's own list has the whole width and keeps its side-by-side
     labels; this one stacks them. */
  table.pr-list.tp-cand-list td { display: block; }
  table.pr-list.tp-cand-list td::before {
    display: block; margin-bottom: 1px; font-size: 10px;
  }
  table.pr-list.tp-cand-list td .muted,
  table.pr-list.tp-cand-list td a { overflow-wrap: anywhere; white-space: normal; }
  /* A figure is short -- "$111k", "24.6%" -- so it keeps its label beside it
     on a narrow one, rather than every figure costing two lines and ten
     criteria making a row a screen tall. */
  table.pr-list.tp-cand-list td.pr-num { display: flex; align-items: baseline; gap: 8px; }
  table.pr-list.tp-cand-list td.pr-num::before {
    display: block; flex: 0 0 5.5rem; margin: 0;
  }
  /* The Add button sits in the row's corner, where the pipeline's status dot
     sits, rather than on a line of its own above the name it adds. */
  table.pr-list.tp-cand-list td.tp-cand-add {
    position: absolute; right: 13px; top: 11px; padding: 0;
  }
  table.pr-list.tp-cand-list td.tp-cand-name { padding-right: 64px; }
  table.pr-list.tp-cand-list td.tp-cand-name .pr-nm { white-space: normal; }
}
.tp-cand-list thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface); box-shadow: inset 0 -1px 0 var(--line);
}
.tp-cand-list td { vertical-align: top; }
/* **A figure column is its heading plus 12px.** The pipeline list pads every
   cell 10px a side, which is what a word column wants; here the colgroup sizes
   each figure to its own heading, and at 10px a side HYPERTEN clipped in the
   76px it was given. Needs `table.pr-list` in the selector to outrank the
   component's own padding -- a modifier of a component you did not write
   needs at least the specificity of the rule it is modifying. */
table.pr-list.tp-cand-list th.pr-num,
table.pr-list.tp-cand-list td.pr-num { padding-left: 6px; padding-right: 6px; }
/* The kind and its sizes wrap rather than clip: "2 clinicians listed (1-2)"
   and the busiest panel under it are the facts a rep chooses a practice by,
   and an ellipsis would cut them where the number is. Every other cell in
   the component is one line with a title, which is right for a name. */
@media (min-width: 561px) {
  /* Desktop only: below 560 the row is a stack of heading-and-value lines,
     and a cell allowed to wrap there is squeezed into a flex item and
     broken a character at a time. */
  table.pr-list.tp-cand-list td.tp-cand-kind { white-space: normal; overflow: visible; }
  table.pr-list.tp-cand-list td.tp-cand-kind .muted { white-space: normal; }
  .tp-cand-kind .tp-nowrap { white-space: nowrap; }
}
/* Name over address, not beside it. `td.pr-name` is the pipeline's cell and is
   a flex row, which is right there -- it carries the name and a duplicate mark
   on one line. Here the second thing is the street, and sharing the line left
   24% of the table to hold both, so a rep read "D&S ..." and could not tell
   one pharmacy from another. `.pr-nm` needs `display: block` to clip with an
   ellipsis: it is an anchor, and `overflow` does nothing to an inline box --
   in the pipeline it works because it is a flex item there. */
.tp-cand-name { display: block; }
.tp-cand-name .pr-nm { display: block; }
.tp-cand-list td .muted { font-size: 11px; line-height: 1.35; }
/* A row already on the day keeps its place rather than disappearing, so the
   panel does not reshuffle under a rep who has just pressed Add. */
.tp-cand-list tr.is-system td { background: var(--tp-sky-wash); }
.tp-cand-list form { display: inline; }
.tp-cands .pr-key { margin: 8px 2px 0; }

/* ---------- A record's own page: a Market Planner place, a prospect ----------

   Named pr- because both pages wear it, the same reason .mp-bench became
   .pr-bench; mp- was also already My Projects' prefix (.mp-row, .mp-dots).

   The place page was four cards of one weight: the record, the area, the action and
   the clinicians, each a white slab with the same rule under the same title.
   So the only thing on the page a rep can *do* -- promote it -- read as a
   reference table, third of four, while the twelve area figures repeated their
   provenance eleven times between them. Measured at 1,703px for about
   twenty-five facts.

   The place is a header now rather than a card, carrying its own action; the
   record it came from is secondary and dense; and the area figures group under
   the source they came from, which says the provenance once. */

.pr-hero {
  display: flex; align-items: flex-start; gap: 18px; flex-wrap: wrap;
  padding: 16px 20px; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r);
}
.pr-hero-main { flex: 1 1 340px; min-width: 0; }
.pr-hero-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pr-hero-top h2 { margin: 0; font-size: 17px; }
.pr-hero-addr { margin-top: 7px; font-size: 14px; color: var(--ink-2); }
.pr-hero-facts { margin-top: 5px; font-size: 12.5px; color: var(--ink-3); }
.pr-hero-act { flex: 0 0 auto; display: flex; flex-direction: column;
               align-items: flex-end; gap: 6px; }
.pr-hero-act .pr-basis { margin-top: 0; text-align: right; max-width: 260px; }
/* A refusal keeps its own sentence, in full: which of the three it is, and
   whether it can ever change, is the whole content of the answer. */
.pr-why { margin-top: 10px; font-size: 12.5px; color: var(--ink-3);
          line-height: 1.55; max-width: 62ch; }

/* The record CMS published: denser than .pr-kv and quieter, because it is what
   the page rests on rather than what it is about. */
.pr-rec { display: grid; gap: 12px 24px;
          grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.pr-rec > div { min-width: 0; font-size: 13.5px; }
.pr-rec .muted { display: block; font-size: 11px; text-transform: uppercase;
                 letter-spacing: .04em; margin-bottom: 2px; }

/* Area figures, grouped by the source they came from. The heading carries the
   provenance for the whole group -- derived from the figures that actually
   have a value, because on a ZIP-area place the tract-only measures are absent
   and claiming one geography for all five would be false. */
.pr-group + .pr-group { margin-top: 18px; }
.pr-group-hd {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding-bottom: 6px; margin-bottom: 12px;
  border-bottom: 1px solid var(--line-2);
}
.pr-group-hd h3 {
  margin: 0; font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-3);
}
.pr-group-hd .pr-basis { display: inline; margin: 0; }
.pr-group-hd .spacer { flex: 1; }

/* A fixed five wide rather than auto-fit, so the figures line up vertically
   between groups: auto-fit stretched People's four across the full width while
   Health's five sat tighter, and nothing in one group aligned with anything in
   the next. Five is the widest group. */
.pr-stats { display: grid; gap: 16px 20px;
            grid-template-columns: repeat(5, minmax(0, 1fr)); }
@media (max-width: 1100px) { .pr-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 720px)  { .pr-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.pr-stat { min-width: 0; }
/* The figure first and large: it is the content, and the label above it in
   caps was reading louder than the number it described. */
.pr-stat-v { font-size: 21px; line-height: 1.2; color: var(--ink);
             font-variant-numeric: tabular-nums; }
.pr-stat-v .pr-none { font-size: 21px; }
.pr-stat-l { margin-top: 2px; font-size: 12.5px; color: var(--ink-3); }
.pr-stat .pr-basis { margin-top: 3px; }

/* A card whose head is its own body's first line rather than a second box. */
.card.is-flush > .card-hd { border-bottom: 0; padding-bottom: 0; }

/* The comparison under a figure: what the median tract in this state reads, so
   a percentage becomes a judgement rather than a number. Neutral by design --
   the direction is marked and never coloured, because for this pipeline more
   chronic disease is a larger opportunity rather than a worse place, and a red
   number would be the portal making a judgement it has no business making. The
   status colours stay for what a rep can *do* about a place. */
.pr-bench { margin-top: 3px; font-size: 11.5px; color: var(--ink-3); }
.pr-bench-dir { color: var(--ink-4); font-size: 9px; margin-right: 3px;
                vertical-align: 1px; }

/* ---------- Market Planner: Market research ----------

   Gregg Smith's market plan, drawn from his own screen: filters and his four
   figures across the top, a map of his centres with his market buttons under
   it on the left, and a chosen market on the right. His patterns at a lower
   volume -- a status is a sentence with its numbers in bold, a figure carries a
   grey line saying what it is not, secondary material sits behind a disclosure
   with its count in the summary, and there is one tinted panel on the page, the
   market's character.

   His figures and ours never share a provenance line: .mk-credit sits under
   each, and each says whose. */

.mk-top { margin-bottom: 14px; }
/* The one line of credit for the markets themselves, under the page heading. */
.mk-plan-credit { margin: -14px 0 14px; font-size: 12.5px; color: var(--ink-3); }
.mk-attrib { margin: 12px 0 0; }
.mk-top .pr-filters { margin-bottom: 14px; }

.mk-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.mk-tiles.is-two { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 14px; }
@media (max-width: 720px) { .mk-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.mk-tile {
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--canvas);
}
.mk-tile .v { font-size: 21px; line-height: 1.2; color: var(--ink); font-variant-numeric: tabular-nums; }
.mk-tile .l { margin-top: 2px; font-size: 12.5px; color: var(--ink-3); }

/* Whose figure this is, directly under it; then what it is not, quieter. */
.mk-credit { margin: 8px 0 0; font-size: 12px; color: var(--ink-3); }
.mk-not { margin: 2px 0 0; font-size: 12px; color: var(--ink-4); }
.mk-credit.is-tight { margin-top: 1px; }

.mk-split { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 14px; align-items: start; }
@media (max-width: 1000px) { .mk-split { grid-template-columns: minmax(0, 1fr); } }
.mk-left, .mk-right { margin: 0; }
/* Two classes, to outrank .mk-plain's margin without an !important. */
.mk-plain.mk-left-hd { margin-bottom: 12px; }

/* The map: Census state outlines and his centres, nothing street-level. The
   five states we collect are washed in Sky Blue so the ground we hold data for
   reads at a glance; the rest are the page ground. */
.mk-map {
  display: block; width: 100%; aspect-ratio: 1.25; background: var(--blue-50);
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
.mk-state { fill: var(--surface); stroke: var(--ink-4); stroke-linejoin: round; }
.mk-state.is-collected { fill: color-mix(in srgb, var(--sky) 28%, white); }
.mk-pin { fill: var(--dignity); stroke: var(--surface); cursor: pointer; }
.mk-pin.is-plan-only { fill: var(--surface); stroke: var(--dignity); }
.mk-pin.is-chosen { fill: var(--sandstone); stroke: var(--dignity); }
.mk-map a:hover .mk-pin { fill: var(--dignity-hover); }
.mk-map a:hover .mk-pin.is-plan-only { fill: var(--blue-100); }
.mk-pin-label {
  fill: var(--ink); font-weight: 600; paint-order: stroke;
  stroke: var(--surface); stroke-width: .08; stroke-linejoin: round;
}

/* His market buttons, grouped by state, with what we hold in each. */
.mk-buttons { margin-top: 14px; display: grid; gap: 10px; }
.mk-group h3 {
  margin: 0 0 5px; font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-3);
}
.mk-btns { display: flex; flex-wrap: wrap; gap: 6px; }
.mk-btn {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 5px 10px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--canvas); color: var(--ink); font-size: 13px; line-height: 1.3;
}
.mk-btn:hover { border-color: var(--dignity); text-decoration: none; }
.mk-btn .n { font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.mk-btn.is-plan-only { background: var(--surface); border-style: dashed; }
.mk-btn[aria-current="true"] { background: var(--dignity); border-color: var(--dignity); color: var(--on-accent); }
.mk-btn[aria-current="true"] .n { color: var(--on-accent); opacity: .8; }

/* The chosen market. */
.mk-market-hd { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }
.mk-market-hd h2, .mk-plain { margin: 0 8px 0 0; font-size: 20px; letter-spacing: -.01em; }
.mk-pill {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  background: var(--blue-50); border: 1px solid var(--blue-100);
  color: var(--dignity); font-size: 12px; font-weight: 600;
}
/* The one tinted panel: his character of the ground and what to verify. */
.mk-character {
  margin-top: 12px; padding: 10px 14px;
  background: color-mix(in srgb, var(--sky) 16%, white);
  border-left: 3px solid var(--dignity); border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.mk-character strong { display: block; font-size: 14.5px; color: var(--ink); }
.mk-character p { margin: 3px 0 0; font-size: 13.5px; color: var(--ink-2); }
/* Unset, not empty and not zero: a judgement nobody has made yet reads as a
   sentence in the muted ink rather than as a value in the strong one. */
.mk-pill.is-unset {
  background: transparent; border-style: dashed; border-color: var(--line);
  color: var(--ink-3); font-weight: 500;
}
.mk-character strong.is-unset { font-weight: 500; color: var(--ink-2); }

.mk-ours { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line-2); }
.mk-status { margin: 0 0 6px; font-size: 14px; line-height: 1.55; color: var(--ink-2); }
.mk-status b { color: var(--ink); font-weight: 650; font-variant-numeric: tabular-nums; }
.mk-status a { color: inherit; text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 3px; }
.mk-status a:hover { text-decoration-color: var(--dignity); }
.mk-sub { margin: 18px 0 2px; font-size: 14px; }
.mk-note { margin: 4px 0 8px; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; }
.mk-hint { margin-top: 16px; }

/* Secondary material, with its count in the summary line. */
.mk-more { margin-top: 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.mk-more > summary {
  cursor: pointer; padding: 8px 12px; font-size: 13.5px; font-weight: 600; color: var(--ink);
  list-style: revert;
}
.mk-more > summary .n {
  margin-left: 6px; font-weight: 500; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.mk-more[open] > summary { border-bottom: 1px solid var(--line-2); }
.mk-more > .mk-note, .mk-more > ul { margin-left: 12px; margin-right: 12px; }
.mk-reach { list-style: none; padding: 0 0 8px; margin: 0; font-size: 13.5px; display: grid; gap: 3px; }
.mk-reach b { font-variant-numeric: tabular-nums; margin-left: 4px; }

/* A market's places as cards, the way he shows candidates. */
.mk-places-hd { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-top: 20px; }
.mk-places-hd h3 { margin: 0; font-size: 15px; }
.mk-places-hd .mk-note { margin: 0; }
/* Two columns: fifty candidates in one column was a page seven thousand
   pixels long, which is a list nobody reaches the end of. */
.mk-cards {
  list-style: none; margin: 8px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 20px;
}
@media (max-width: 720px) { .mk-cards { grid-template-columns: minmax(0, 1fr); } }
.mk-card { padding: 10px 0 12px; border-bottom: 1px solid var(--line-2); min-width: 0; }
.mk-card-nm { overflow-wrap: anywhere; }
.mk-card-nm { display: block; font-weight: 650; color: var(--ink); font-size: 14.5px; }
.mk-card-meta { margin-top: 1px; font-size: 12.5px; color: var(--ink-3); }
.mk-card-addr { font-size: 12.5px; color: var(--ink-3); }
.mk-card .btn { margin-top: 6px; }
.mk-cards.is-compact { padding-bottom: 6px; grid-template-columns: minmax(0, 1fr); }
.mk-cards.is-compact .mk-card { padding: 7px 0; }
.mk-cards.is-compact .mk-card .btn { display: none; }

/* A group's locations: every source name, each with its own page. */
.mk-locs { margin-top: 5px; font-size: 12.5px; }
.mk-locs > summary { cursor: pointer; color: var(--dignity); font-weight: 600; }
.mk-locs ul { list-style: none; margin: 4px 0 0; padding: 0 0 0 12px; border-left: 2px solid var(--line-2); display: grid; gap: 2px; }
.mk-locs li { overflow-wrap: anywhere; }
.mk-locs .muted { margin-left: 4px; }

/* The plan's markets on ground we have not collected, behind one disclosure. */
.mk-plan-only { margin-top: 2px; }
.mk-plan-only-body { padding: 10px 12px 12px; display: grid; gap: 10px; }


/* ---------- Market Planner: Territory ----------

   Who works each market, and a market's worklist in the plan's own form:
   numbered prose, a bold name, the kind and the street, then a grey line of
   the inputs that ranked it. Same split as Market research -- people and
   markets on the left, a chosen market on the right -- so the two tabs read
   as one tool. */

.tr-sub-hd { margin-top: 22px; margin-bottom: 4px; }

.tr-people { list-style: none; margin: 8px 0 0; padding: 0; }
.tr-people > li { padding: 8px 0; border-bottom: 1px solid var(--line-2); }
.tr-people > li:last-child { border-bottom: 0; }
.tr-person { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; }
.tr-name { font-weight: 650; color: var(--ink); font-size: 14px; }
.tr-email { font-size: 12px; color: var(--ink-4); overflow-wrap: anywhere; }
.tr-email.is-inline { margin-left: 4px; }
.tr-holds { margin-top: 2px; font-size: 13px; color: var(--ink-2); }
.tr-holds.is-none { color: var(--ink-3); font-style: italic; }

/* A fact about an owner the roster positively confirms. Amber, because it is
   something to act on in Workspace and not a refusal. */
.tr-flag {
  display: inline-block; padding: 0 7px; border-radius: 999px;
  background: var(--amber-100); color: #92400e; font-size: 11.5px; font-weight: 600;
}

.tr-markets { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.tr-markets > li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 11em);
  align-items: baseline; gap: 10px; padding: 3px 8px; border-radius: var(--r-sm);
  font-size: 13.5px;
}
.tr-markets > li[aria-current="true"] { background: var(--blue-50); }
.tr-markets .n { font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tr-own { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tr-own.is-unowned { color: var(--ink-3); font-style: italic; }

.tr-owner { margin-top: 12px; padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--canvas); }
.tr-owner .mk-status { margin: 0; }
.tr-label {
  margin-right: 6px; font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-3);
}
.tr-owner-form { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
/* The base form reset makes every select 100% wide. */
.tr-owner-form select { width: auto; min-width: 18em; max-width: 100%; }

/* The worklist. The number is the list's own, as his is. */
.tr-work { margin: 10px 0 0; padding-left: 2.1em; }
.tr-entry { padding: 5px 0 7px; }
.tr-entry::marker { color: var(--ink-3); font-variant-numeric: tabular-nums; font-size: 14px; }
.tr-line { font-size: 14px; color: var(--ink-2); overflow-wrap: anywhere; }
.tr-nm { font-weight: 650; color: var(--ink); }
a.tr-nm:hover { color: var(--dignity); }
.tr-why { margin-top: 1px; font-size: 12.5px; color: var(--ink-3); }
.tr-why .pr-bub { width: 8px; height: 8px; margin-right: 3px; vertical-align: 0; cursor: default; }
.tr-rule { margin: 10px 0 6px; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; }

/* The worklist's sections: one per kind, both open, each with its count and
   the rule under it. The picker sits in the worklist's own heading, because it
   reorders the sections below it and nothing else. */
.tr-work-hd { justify-content: space-between; }
.tr-order { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-3); }
/* The base form reset makes every select 100% wide. */
.tr-order select { width: auto; padding: 3px 8px; font-size: 12.5px; }
.tr-section { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--line-2); }
.tr-section-hd { margin: 0; font-size: 14px; font-weight: 600; color: var(--ink-2); }
.tr-section-hd b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* On a phone the name row cannot hold the name, Selection criteria and the
   move controls at once: the button takes a line of its own under the name,
   and the name keeps the width beside the controls. At the end of the file
   because a media query outranks nothing that comes after it. */
@media (max-width: 560px) {
  .tp-node.is-stop .tp-stop-hd { flex-wrap: wrap; row-gap: 6px; }
  .tp-node.is-stop .tp-stop-name { flex: 1 1 0; }
  .tp-node.is-stop .tp-stop-crit { order: 3; margin-left: 0; }
  .tp-node.is-stop .tp-stop-tools { order: 2; }
  .tp-node.is-stop .tp-stop-hd::after { content: ""; order: 2; flex-basis: 100%; }
}

/* ---------------------------------------------------------------- trip views
   The three sub-tabs of one day: the road, the choosing, the settings. Drawn
   like the portal's `.tabs` -- separate destinations, so separate buttons --
   under the folder row, which says which list the day is in. */
.tp-views {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 0 0 14px;
}
.tp-views a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: 13px; font-weight: 700; color: var(--ink-2); text-decoration: none;
}
.tp-views a .ico { width: 15px; height: 15px; }
.tp-views a:hover { border-color: var(--dignity); color: var(--dignity); }
.tp-views a[aria-current="page"] {
  background: var(--dignity); border-color: var(--dignity); color: var(--on-accent);
}

/* Add destinations, as its own pane: the same card the road is, so switching
   between them changes what is on the page rather than how the page looks. */
.tp-addview { padding: 0 0 18px; }
.tp-addview .tp-add-panel { margin: 0 20px; }
.tp-addview .tp-run-hd { margin-bottom: 4px; }

/* The way to it from the road, at the place the next stop will go. */
.tp-add-link {
  display: block; padding: 10px 14px; border-radius: 12px;
  border: 1.5px dashed color-mix(in srgb, var(--dignity) 45%, var(--line));
  background: var(--surface); text-decoration: none;
}
.tp-add-link:hover { border-color: var(--dignity); box-shadow: var(--shadow-sm); }
.tp-add-link strong { display: block; font-size: 14px; color: var(--dignity); }
.tp-add-link span { display: block; font-size: 12px; color: var(--ink-3); }
.tp-copyday { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; }
.tp-copyday .tp-field { margin: 0; }

/* The day's destination, on the planning form: a state, a name to search by,
   the matches, and the typed address for a place we have never been. */
.tp-target {
  /* The whole row of the planning grid: it is a question with a list under
     it, and half a row put a search box beside "Time at each stop". */
  grid-column: 1 / -1;
  border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; background: var(--surface);
}
.tp-target > label { font-weight: 700; }
.tp-target-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.tp-target-row select { width: auto; min-width: 8rem; flex: none; }
.tp-target-row input[type=search] { flex: 1 1 18rem; min-width: 0; }
.tp-target-found:empty { display: none; }
.tp-target-hint { margin: 8px 0 0; font-size: 12.5px; color: var(--ink-3); }
.tp-target-list { list-style: none; margin: 8px 0 0; padding: 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.tp-target-list li + li { border-top: 1px solid var(--line-2); }
.tp-target-list label {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  align-items: baseline; padding: 8px 12px; cursor: pointer; font-size: 13px;
}
.tp-target-list label:hover { background: var(--tp-sky-wash); }
.tp-target-list input { grid-row: span 2; align-self: center; }
.tp-target-name { font-weight: 700; }
.tp-target-where { grid-column: 2; font-size: 12px; color: var(--ink-3); }
.tp-target-tag {
  margin-left: 8px; padding: 1px 8px; border-radius: 999px;
  font-style: normal; font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
}
.tp-target-tag.is-pipeline { background: color-mix(in srgb, var(--dignity) 12%, var(--surface)); color: var(--dignity); }
.tp-target-tag.is-contact { background: color-mix(in srgb, var(--green-600) 12%, var(--surface)); color: var(--green-600); }
.tp-target-none label { color: var(--ink-3); font-weight: 600; }
.tp-target-typed { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.tp-target-typed input[name=target_address] { flex: 1 1 20rem; min-width: 0; }
.tp-target-typed input[name=target_name] { flex: 1 1 12rem; min-width: 0; }
/* **The time sits inside the card, not over its edge.** The label is a flex
   item that shrank with the row while the input inside it did not -- a flex
   item does not shrink below its content, and `width: auto` on a time input is
   whatever the browser's own clock control wants. It ran 31px past the card's
   border at every desktop width. Sized explicitly, and neither box allowed to
   shrink under it. */
.tp-target-at {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font-size: 12.5px; font-weight: 700; color: var(--ink-2); white-space: nowrap;
}
/* Two classes and the attribute, because `.tp-grid input[type=time]` is two
   and sets `width: 100%` -- which resolved against the label and left the
   clock control hanging over the card's edge. The recorded specificity trap:
   a modifier of a rule you did not write needs at least its weight. */
.tp-grid .tp-target-at input[type=time] { width: 8.5rem; flex: none; min-width: 0; }

/* What we learned at a stop: a disclosure under the day's own notes, because
   it is written after a visit rather than while a day is planned. */
.tp-learn { margin: 0 14px 12px; border-top: 1px solid var(--line-2); }
.tp-learn > summary {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  padding: 8px 2px; font-size: 12.5px; font-weight: 700; color: var(--a, var(--dignity));
}
.tp-learn > summary .ico { width: 15px; height: 15px; }
.tp-learn > summary .muted { font-weight: 500; font-size: 11.5px; }
.tp-learn-body { padding: 2px 2px 10px; }
.tp-learn-where { margin: 0 0 8px; font-size: 12.5px; }
.tp-learn-where a { display: inline-flex; align-items: center; gap: 5px; font-weight: 700; }
.tp-learn-where .ico { width: 14px; height: 14px; }
.tp-learn-where em { color: var(--ink-3); font-style: normal; }
.tp-learn-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; }
.tp-learn-form .tp-field { flex: 1 1 9rem; min-width: 0; margin: 0; }
.tp-learn-form .tp-learn-note { flex: 1 1 18rem; }
.tp-learn-form .tp-learn-note textarea { min-height: 34px; }
.tp-learn-form .tp-learn-decide { flex: 0 1 8rem; }
.tp-learn-form .tp-learn-decide select { width: auto; }
.tp-learn-hint { margin: 8px 0 0; font-size: 11.5px; color: var(--ink-3); }

/* **The planning form is tightened, because it is a form somebody fills in
   once a day and reads never.** It stood 692px tall at 1440 with the button
   below the fold on a laptop; the space went on gaps between fields, a hint
   under every second one and a destination card padded like a page. Nothing
   is hidden -- the hints that say what a field does are still there, smaller
   and on one line. */
.tp-plan .tp-grid { gap: 0 10px; }
.tp-plan .field { margin-bottom: 8px; }
.tp-plan .field label { margin-bottom: 2px; }
.tp-plan .tp-grid input,
.tp-plan .tp-grid select { padding: 6px 10px; }
.tp-plan .th-hint { font-size: 11px; }
.tp-plan .tp-target { padding: 8px 10px 6px; margin-bottom: 8px; }
.tp-plan .tp-target > label { margin-bottom: 4px; }
/* The paragraph under the card, not the inline "optional" beside its label:
   `.th-hint` is both, and a block rule on the span put one word on a line. */
.tp-plan .tp-target > p.th-hint { display: block; margin: 6px 0 0; line-height: 1.35; }
/* **Two classes, because `.tp-grid .tp-wide` is two.** The whole-row rule on
   `.tp-target` lost to it and the card came out half width with the clock
   fields beside it -- the recorded specificity trap, in a grid this time. */
.tp-grid .tp-target { grid-column: 1 / -1; }
.tp-plan .tp-target-row,
.tp-plan .tp-target-typed { margin-top: 6px; gap: 6px; }
.tp-plan .tp-target-list label { padding: 6px 10px; }

/* How far past "back home by" the day now runs, on the confirmation an add
   answers with: the road says it too, and a rep adding stops is not on the
   road. Amber inside a green toast, because it is a caveat on a success. */
.tp-toast-late {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  padding: 2px 9px; border-radius: 999px; font-weight: 700; white-space: nowrap;
  background: color-mix(in srgb, var(--amber-600, #b45309) 85%, black); color: #fff;
}
.tp-toast-late .ico { width: 14px; height: 14px; }

/* ------------------------------------------------- the picker's control bars
   **Three tight rows rather than three blocks.** The panel's controls stood
   as a labelled field, a corridor form and a fold, each with its own heading
   and its own whitespace -- about 210px before a single candidate, and no
   line of it said which button belonged to which fields. Each is one row now,
   reading left to right: what it does, the fields it does it with, and the
   button that applies it. */
.tp-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin: 0 0 6px; font-size: 12.5px; color: var(--ink-2);
}
.tp-bar input[type=search], .tp-bar select {
  height: 30px; padding: 0 9px; width: auto; flex: 0 1 auto;
  border-radius: var(--r-sm);
  font: inherit; font-size: 12.5px; color: var(--ink);
}
.tp-bar input[type=search] { min-width: 6rem; }
.tp-bar .tp-bar-lead { font-weight: 700; color: var(--ink-2); white-space: nowrap; }
.tp-bar .btn.sm { flex: none; }
.tp-bar-where input[name=near_city] { flex: 1 1 8rem; }
.tp-bar-where input[name=near_q] { flex: 1 1 10rem; }
.tp-bar.tp-along input[type=search] { flex: 1 1 11rem; }
.tp-bar .pr-kinds, .tp-bar .tp-crit-set { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.tp-bar .pr-kinds label, .tp-bar .tp-crit-set label {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
}
.tp-crit-bar { padding: 6px 8px; border: 1px solid var(--line-2); border-radius: 8px; background: var(--tp-sky-wash); }
.tp-crit-bar .tp-crit-set { flex: 1 1 auto; }
.tp-crit-set em { font-style: normal; font-size: 10px; letter-spacing: .04em; color: var(--ink-4); text-transform: uppercase; }

/* What the list is, said in italics immediately above it. */
.tp-showing { margin: 10px 0 4px; font-size: 12.5px; color: var(--ink-3); }
/* How to find prospects: a radio for the way, then only that way's boxes.
   Drawn as radio buttons -- a circle beside each word -- because the row above
   is already pills, and two rows of pills would read as two sets of tabs. The
   real inputs are visually hidden and come before the panels as siblings, so
   :checked shows the chosen panel with no script. */
/* The find tool is one pipe-bordered frame: "How do you want to find prospects?"
   is the header, and the way form, Just ask and the filters are its subordinate
   body, indented, so the progression reads (Andrew, 6 October 2026). */
.tp-find {
  display: flex; flex-direction: column; gap: 10px;
  margin: 4px 0 8px; padding: 12px 14px; border: 1px solid var(--frame);
  border-radius: 10px; background: var(--surface);
}
/* The header: the question and its four ways, set off from the body by a rule
   so the rest reads as "under" it rather than beside it. */
.tp-find-modes { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px;
  padding-bottom: 10px; border-bottom: 1px solid var(--frame); }
.tp-find-modes .tp-bar-lead { font-weight: 700; color: var(--ink-2); font-size: 13.5px; }
/* The body: everything under the question, indented behind a soft rail. */
.tp-find-body { display: flex; flex-direction: column; gap: 10px;
  padding-left: 14px; border-left: 2px solid color-mix(in srgb, var(--frame) 55%, white); }
/* The second step's label, framing the filters as the narrowing that follows. */
/* The filters as one card: "Filters / Refine your search" over stacked fold-out
   rows (Andrew, 6 October 2026) -- Facilities, Program, Demographics. Each row
   shows its chosen values as chips and folds open to its options, indented
   beneath so every row's options line up. A Just ask search leaves them empty
   (the template's `manual` gate), because Just ask is the "or" below. */
.tp-ff { border: 1px solid var(--frame); border-radius: 10px; overflow: hidden; background: var(--surface); }
.tp-ff-head { text-align: center; padding: 8px 12px 7px;
  background: color-mix(in srgb, var(--frame) 12%, white); border-bottom: 1px solid var(--frame); }
.tp-ff-head b { display: block; font-size: 14px; color: var(--ink-2); }
.tp-ff-head span { font-size: 11.5px; font-style: italic; color: var(--ink-3); }
.tp-ff-row + .tp-ff-row { border-top: 1px solid var(--line); }
.tp-ff-row > summary { list-style: none; cursor: pointer; display: grid;
  grid-template-columns: 116px 1fr auto; align-items: center; gap: 10px; padding: 9px 14px; }
.tp-ff-row > summary::-webkit-details-marker { display: none; }
.tp-ff-row > summary:focus-visible { outline: 2px solid var(--dignity); outline-offset: -2px; }
.tp-ff-row > summary > b { font-size: 13px; color: var(--ink-2); }
.tp-ff-row.has-sel > summary > b { color: var(--dignity); }
.tp-ff-sum { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0;
  font-size: 12.5px; font-style: italic; color: var(--ink-3); }
.tp-ff-tag { font-style: normal; font-size: 12px; font-weight: 600; color: var(--dignity);
  padding: 1px 8px; border-radius: 999px; white-space: nowrap;
  background: color-mix(in srgb, var(--dignity) 10%, white); }
.tp-ff-chev { width: 16px; height: 16px; color: var(--ink-3); transition: transform .15s ease; }
.tp-ff-row[open] .tp-ff-chev { transform: rotate(90deg); }
.tp-ff-opts { padding: 0 14px 12px 130px; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(165px, 1fr)); gap: 7px 14px; }
.tp-ff-opts.is-ctl { display: block; }
.tp-ff-opt { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-2); cursor: pointer; }
.tp-ff-opt em { font-style: normal; font-size: 10px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .03em; }
/* Program is checkboxes in the same grid; several may be chosen and the panel
   ranks by the union. Six to a row on a full screen (Andrew, 6 October 2026),
   dropping to four, three and two as it narrows. The chosen lenses' "Ranked by"
   line spans the grid. */
.tp-ff-opts.tp-ff-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
@media (max-width: 1100px) { .tp-ff-opts.tp-ff-6 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .tp-ff-opts.tp-ff-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* "All Access Programs" / "All Programs": select-all options, set off from the
   named ones by a hairline above them so they read as the roll-ups they are. */
.tp-ff-opt.is-meta { font-weight: 600; color: var(--ink-1); }
.tp-ff-opts .tp-program-means { grid-column: 1 / -1; margin: 4px 0 0; }
@media (max-width: 560px) {
  .tp-ff-row > summary { grid-template-columns: 1fr auto; }
  .tp-ff-sum { grid-column: 1 / -1; grid-row: 2; }
  .tp-ff-opts { padding-left: 14px; }
  .tp-ff-opts.tp-ff-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) { .tp-ff-chev { transition: none; } }
/* The real "or": the filters (Show prospects) are one search, Just ask below is
   another; neither reads the other. The divider says so. */
.tp-or { display: flex; align-items: center; gap: 10px; margin: 2px 0;
  font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }
.tp-or::before, .tp-or::after { content: ""; flex: 1; border-top: 1px solid var(--frame); }
.tp-find-modes label {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  font-size: 13.5px; font-weight: 600; color: var(--ink-2);
}
.tp-find-modes label::before {
  content: ""; width: 16px; height: 16px; border-radius: 50%; flex: none;
  border: 2px solid var(--frame); background: var(--surface); box-sizing: border-box;
}
#tp-find-drive:checked ~ .tp-find-modes label[for="tp-find-drive"],
#tp-find-area:checked ~ .tp-find-modes label[for="tp-find-area"],
#tp-find-list:checked ~ .tp-find-modes label[for="tp-find-list"],
#tp-find-name:checked ~ .tp-find-modes label[for="tp-find-name"] { color: var(--dignity); }
#tp-find-drive:checked ~ .tp-find-modes label[for="tp-find-drive"]::before,
#tp-find-area:checked ~ .tp-find-modes label[for="tp-find-area"]::before,
#tp-find-list:checked ~ .tp-find-modes label[for="tp-find-list"]::before,
#tp-find-name:checked ~ .tp-find-modes label[for="tp-find-name"]::before {
  border-color: var(--dignity); background: radial-gradient(var(--dignity) 0 3.5px, var(--surface) 4px);
}
#tp-find-drive:focus-visible ~ .tp-find-modes label[for="tp-find-drive"],
#tp-find-area:focus-visible ~ .tp-find-modes label[for="tp-find-area"],
#tp-find-list:focus-visible ~ .tp-find-modes label[for="tp-find-list"],
#tp-find-name:focus-visible ~ .tp-find-modes label[for="tp-find-name"] {
  outline: 2px solid var(--dignity); outline-offset: 3px; border-radius: 4px;
}
.tp-find-panel { display: none; }
/* Folded until a way is chosen: the narrow-step label, the filters and the
   button appear with the first radio ticked, and the list below moves down to
   make room. They live in .tp-find-body now, so the radios' sibling reveal
   reaches in through it. */
.tp-find-body > .tp-ff, .tp-find-body > .tp-find-go,
.tp-find-body > .tp-or { display: none; }
.tp-find-radio:checked ~ .tp-find-body .tp-ff { display: block; }
.tp-find-radio:checked ~ .tp-find-body .tp-find-go { display: flex; }
.tp-find-radio:checked ~ .tp-find-body .tp-or { display: flex; }
#tp-find-drive:checked ~ .tp-find-body .tp-find-p-drive,
#tp-find-area:checked ~ .tp-find-body .tp-find-p-area,
#tp-find-list:checked ~ .tp-find-body .tp-find-p-list,
#tp-find-name:checked ~ .tp-find-body .tp-find-p-name {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 12px;
  padding: 10px 12px; border-radius: 8px;
  background: color-mix(in srgb, var(--sky) 12%, var(--surface));
}
.tp-find-field { display: flex; flex-direction: column; gap: 3px; font-size: 12px;
  font-weight: 600; color: var(--ink-3); flex: 1 1 200px; min-width: 0; }
.tp-find-field.is-wide { flex: 3 1 280px; }
.tp-find-field select { width: auto; }
.tp-find-field input, .tp-find-field select { font-weight: 400; font-size: 13.5px; color: var(--ink); }
.tp-find-p-drive .tp-find-field:last-of-type { flex: 0 0 auto; }
.tp-find-p-area .tp-find-field:last-of-type { flex: 0 0 auto; }
/* The legs case shows the active part's ends read-only, filled from the plan
   (Andrew, 6 October 2026). They are wide, so re-assert that after the
   last-of-type rule above, which exists for the editable case's Within
   select; and an <output> keeps its paper because it is display, not entry. */
.tp-find-p-drive .tp-find-field.is-wide { flex: 3 1 280px; }
.tp-ro { font-weight: 400; font-size: 13.5px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: 6px;
  padding: 7px 9px; min-height: 19px; }
.tp-unset { color: var(--ink-3); font-style: italic; }
.tp-find-hint { flex-basis: 100%; margin: 0; font-size: 12px; color: var(--ink-3); }
.tp-find-p-drive .tp-legs { margin: 0; }
/* The three filter rows are one table: a label column of one width, so each
   row's first control starts at the same x, and the facility types and the
   area figures in the same even columns (Andrew, 29 September 2026). */
.tp-find-common { display: grid; grid-template-columns: 12.5rem minmax(0, 1fr);
  align-items: center; gap: 6px 14px; font-size: 13px; }
.tp-find-common > .tp-bar-lead { white-space: nowrap; font-weight: 700; color: var(--ink-2); }
.tp-find-ctl { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; min-width: 0; }
.tp-find-common .tp-find-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px 14px; align-items: center; }
.tp-find-grid label { display: block; min-width: 0; line-height: 1.35; }
.tp-find-grid label input { margin: 0 5px 0 0; vertical-align: -2px; }
.tp-find-grid label em { margin-left: 3px; }
.tp-find-common.tp-crit-bar { align-items: start; }
@media (max-width: 560px) {
  .tp-find-common { grid-template-columns: minmax(0, 1fr); }
  .tp-find-common .tp-find-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.tp-find-common.tp-crit-bar { padding: 0; border: 0; background: none; }
.tp-find-go { display: flex; justify-content: flex-start; }
.tp-program { width: auto; font-size: 13px; }
.tp-program-means { flex-basis: auto; }
.tp-find-error {
  display: flex; align-items: flex-start; gap: 6px; margin: 0; padding: 8px 10px;
  border-radius: 8px; background: var(--red-50); color: var(--red-600); font-size: 13px;
}
.tp-find-error .ico { width: 15px; height: 15px; flex: none; margin-top: 1px; }

/* "Just ask": a sentence instead of the form, above it. The Assistant fills
   the form; what it understood is said back in a tinted panel above the list. */
.tp-ask { margin: 0 0 10px; }
.tp-ask-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tp-ask-row .tp-bar-lead { display: inline-flex; align-items: center; gap: 5px; }
.tp-ask-row .tp-bar-lead .ico { width: 15px; height: 15px; color: var(--dignity, #174775); }
.tp-ask-row input[type=text] { flex: 1 1 18rem; min-width: 0; }
.tp-ask-note { margin: 4px 0 0; font-size: 11px; color: var(--muted); text-align: right; }
.tp-ask-said { margin: 2px 0 12px; padding: 10px 14px 10px;
  border-radius: 10px; text-align: center; font-size: 14px;
  background: color-mix(in srgb, var(--sky) 22%, white);
  border: 1px solid color-mix(in srgb, var(--dignity) 30%, white);
  box-shadow: 0 1px 3px rgba(23, 71, 117, .10); }
/* The heading and the answer share a row: the heading at the left, the answer
   centred in the rest, a wrapped line centred under the one above it. */
.tp-ask-said-hd { display: flex; align-items: baseline; gap: 6px 12px;
  font-size: 12.5px; color: var(--dignity); }
.tp-ask-said-hd > b { flex: none; white-space: nowrap; }
@media (max-width: 560px) { .tp-ask-said-hd { flex-wrap: wrap; } }
.tp-ask-mark { display: inline-flex; flex: none; align-self: flex-start; margin-top: 1px; color: var(--dignity); cursor: help; }
.tp-ask-mark .ico { width: 18px; height: 18px; }
.tp-ask-said-body { flex: 1 1 auto; min-width: 0; margin: 0; text-align: center;
  font-size: 14px; color: var(--ink); }
/* "Back from where?" -- a return leg was asked for but the day has no finish to
   turn around at. Said plainly, not as an error: the list below still stands. */
.tp-ask-back-note { display: flex; align-items: flex-start; gap: 6px; margin: 8px 0 0;
  font-size: 12.5px; color: var(--ink-2); }
.tp-ask-back-note .ico { flex: none; width: 15px; height: 15px; margin-top: 1px; color: var(--ink-3); }
/* The legs: shaded to draw the eye, not the bright blue of an action. */
.tp-ask-legs { display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 8px 10px; margin-top: 10px; }
.tp-ask-leg { display: inline-flex; align-items: center; padding: 6px 16px; border-radius: 999px;
  border: 1px solid var(--frame); color: var(--ink-2); background: var(--surface);
  font-weight: 700; font-size: 13.5px; text-decoration: none;
  box-shadow: 0 1px 2px rgba(10, 31, 68, .08); }
.tp-ask-leg:hover { background: color-mix(in srgb, var(--dignity) 7%, white); }
.tp-ask-leg.is-on { background: color-mix(in srgb, var(--dignity) 16%, white);
  border-color: color-mix(in srgb, var(--dignity) 55%, white); color: var(--dignity);
  box-shadow: inset 0 1px 2px rgba(23, 71, 117, .18); }
.tp-add-end { display: flex; justify-content: flex-end; align-items: center; gap: 10px;
  padding: 12px 20px 16px; border-top: 1px solid var(--line); }
.tp-add-end-count { font-size: 12px; font-style: italic; color: var(--ink-3); }
/* "Need help?" -- the trip planner's help video: small, italic, underlined so
   it reads as a link, and the hover says what it opens. */
.tp-help-link { font-size: 12px; font-style: italic; font-weight: 400;
  color: var(--ink-3); text-decoration: underline; text-underline-offset: 2px; }
.card-hd .tp-help-link { margin-left: 10px; align-self: center; }
.tp-help-link:hover { color: var(--dignity); }
/* The chaptered help page: the video beside a clickable chapter list, so a rep
   jumps to the one task they came for instead of scrubbing twelve minutes. Two
   columns on a wide screen, stacked on a phone; the chapter playing now is lit. */
.tp-help { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 24px;
  align-items: start; margin-top: 16px; }
.tp-help-player { min-width: 0; }
.tp-help-video { width: 100%; max-height: 72vh; display: block; background: #000;
  border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 6px 24px rgba(10, 31, 68, .14); }
.tp-help-chapters h2 { margin: 2px 0 10px; font-size: 13px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; color: var(--ink-3); }
.tp-help-list { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: 6px; }
.tp-help-chap { display: flex; align-items: baseline; gap: 10px; width: 100%;
  text-align: left; padding: 9px 12px; font: inherit; color: var(--ink-1);
  background: #fff; border: 1px solid var(--line); border-radius: 9px;
  cursor: pointer; transition: background .12s, border-color .12s; }
.tp-help-chap:hover { border-color: var(--dignity); }
.tp-help-chap[aria-current="true"] { color: #fff; background: var(--dignity);
  border-color: var(--dignity); }
.tp-help-time { flex: none; min-width: 34px; font-size: 12.5px; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--ink-3); }
.tp-help-chap[aria-current="true"] .tp-help-time { color: #cfe3f3; }
.tp-help-label { font-size: 14px; }
.tp-help-dl { margin: 14px 0 0; font-size: 12.5px; color: var(--ink-3); }
@media (max-width: 860px) { .tp-help { grid-template-columns: 1fr; gap: 16px; } }
.tp-fresh { display: flex; align-items: center; gap: 6px; margin: 0 0 6px; font-size: 12.5px; color: var(--ink-3); }
.tp-fresh .ico { width: 14px; height: 14px; flex: none; }
.tp-ask-legs-hint { flex-basis: 100%; font-size: 12px; color: var(--ink-3); }
/* Slim variant: the answer sits inline with the question below the Just ask box,
   left-aligned, one strip rather than the centred panel, so it costs a line or
   two and does not push the way boxes and the list down (Andrew, 6 Oct 2026). */
.tp-ask-said.is-slim { margin: 2px 0 10px; padding: 6px 12px; text-align: left;
  border-radius: 8px; }
.tp-ask-said.is-slim .tp-ask-said-hd { gap: 4px 8px; font-size: 12.5px; }
.tp-ask-said.is-slim .tp-ask-mark { align-self: baseline; margin-top: 0; }
.tp-ask-said.is-slim .tp-ask-mark .ico { width: 15px; height: 15px; }
.tp-ask-said.is-slim .tp-ask-said-body { text-align: left; font-size: 13px; }
.tp-ask-said.is-slim .tp-ask-legs { justify-content: flex-start; gap: 6px 8px; margin-top: 6px; }
.tp-ask-said.is-slim .tp-ask-leg { padding: 3px 12px; font-size: 12.5px; box-shadow: none; }

/* The offer to save a planned stop to Contacts: one line, easy to ignore. */
.tp-save {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  margin: 0 20px 12px; padding: 10px 14px; border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--dignity) 25%, var(--line));
  background: color-mix(in srgb, var(--sky) 14%, var(--surface)); font-size: 13px;
}
.tp-save .ico { width: 16px; height: 16px; color: var(--dignity); flex: none; }
.tp-save select { width: auto; font-size: 13px; }
.tp-planned-find { display: block; margin-bottom: 10px; }
.tp-planned-find > span { display: block; margin-bottom: 4px; }

/* A day with nothing placed: one sentence and the way out, not a list. */
.tp-noground {
  margin: 12px 0 4px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--surface); font-size: 13px; color: var(--ink-2);
}
.tp-noground p { margin: 0 0 6px; }
.tp-noground p:last-child { margin: 0; color: var(--ink-3); }
.tp-noground .ico { width: 15px; height: 15px; vertical-align: -3px; margin-right: 4px; color: var(--ink-4); }

/* The contacts list's own views, wearing the folder component: All, the ones
   a trip added, and one per type. The count rides on the tab, because it is
   the size of the view behind it -- the same rule the app's tab row follows.
   The type's own accent shows on the icon, so the row keeps the colour that
   tells a pharmacy from a vendor without eleven coloured tabs. */
.ct-folders { flex-wrap: wrap; row-gap: 0; }
.ct-folders a { display: inline-flex; align-items: center; gap: 6px; }
.ct-folders a .ico { width: 15px; height: 15px; color: var(--a, var(--ink-4)); }
.ct-folders a[aria-current="page"] .ico { color: var(--a, var(--dignity)); }
.ct-folders .ct-n {
  padding: 0 6px; border-radius: 999px; font-size: 11px; font-weight: 700;
  background: var(--line-2); color: var(--ink-3);
}
.ct-folders a[aria-current="page"] .ct-n { background: var(--line); color: var(--ink-2); }
.pr-pane .ct-bar { margin-bottom: 10px; }
/* The pane is the card here too: the rows' own border inside it would be a
   second frame round the same thing, which is the fault the single-card rule
   above exists for -- this list simply has a search row above the card. */
.pr-pane > .ct-bar ~ .card { border: none; box-shadow: none; }

/* The day as a link, for getting it onto a phone. Closed, because a rep only
   needs it once a day and the buttons above are what they press in the car. */
.tp-phone-body { padding: 10px 2px 2px; }
.tp-phone-why, .tp-phone-foot { margin: 0 0 8px; font-size: 12px; color: var(--ink-3); line-height: 1.45; }
.tp-phone-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 8px; }
.tp-phone-row label { flex: none; font-size: 12px; font-weight: 700; color: var(--ink-2); }
.tp-phone-row label em { font-style: normal; font-weight: 500; color: var(--ink-4); }
.tp-phone-url {
  flex: 1 1 18rem; min-width: 0; height: 30px; padding: 0 9px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: 12px; font-family: var(--mono, monospace); color: var(--ink-2);
  background: var(--canvas);
}
.tp-phone-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
.tp-phone-foot form { margin: 0; }
.tp-phone-foot.is-quiet { margin-top: 6px; }
.tp-phone-foot.is-quiet .muted { font-size: 11.5px; line-height: 1.45; }
/* One group per maps app. The heading is the choice, so it carries the app's
   name and the platforms it runs on and nothing else does. */
.tp-phone-group { margin: 0 0 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: #fbfcfd; }
.tp-phone-group h4 {
  display: flex; align-items: center; gap: 6px; margin: 0 0 2px;
  font-size: 13px; font-weight: 800; color: var(--ink-2);
}
.tp-phone-group h4 .ico { width: 15px; height: 15px; color: var(--dignity); }
.tp-phone-group h4 em { font-style: normal; font-size: 11px; font-weight: 600; color: var(--ink-4); }
.tp-phone-group > p { margin: 0 0 8px; font-size: 12px; color: var(--ink-3); line-height: 1.45; }
.tp-phone-dlg { width: min(94vw, 40rem); }
.tp-phone-dlg .tp-phone-body { padding: 14px 18px 18px; }
/* Rendered, and off the edge of the page: the clipboard fallback selects this
   node and lets the browser supply both flavours, and a browser cannot select
   what it has not laid out. `display: none` would take the feature away. */
.tp-offscreen {
  position: absolute; left: -9999px; top: 0; width: 40rem; height: 1px;
  overflow: hidden; opacity: 0; pointer-events: none;
}
.tp-phone-row.is-block { align-items: flex-start; }
.tp-phone-row.is-block label { flex: 1 1 100%; }
textarea.tp-phone-url.is-list { flex: 1 1 260px; min-width: 0; height: auto; padding: 6px 9px; resize: vertical; line-height: 1.5; white-space: pre; }
@media (max-width: 560px) {
  .tp-phone-row label { flex: 1 1 100%; }
  .tp-phone-url { flex: 1 1 100%; }
}

/* Two links, one per maps app, named after the app rather than the platform:
   nothing here reads the user agent, because the phone the link is bound for
   is not the one the planner is holding. */
.tp-stop-nav {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; color: var(--ink-4); white-space: nowrap;
}
.tp-stop-nav .ico { width: 14px; height: 14px; color: var(--a, var(--dignity)); }
.tp-stop-nav a { color: var(--a, var(--dignity)); text-decoration: none; }
.tp-stop-nav a + a { padding-left: 6px; border-left: 1px solid var(--line); }
.tp-stop-nav a:hover { text-decoration: underline; }
@media (max-width: 420px) { .tp-stop-nav .tp-nav-os { display: none; } }


/* ---- Help marks -------------------------------------------------------- */
/* **An explanation somebody asks for.** A paragraph of muted grey beside a
   control is read once, by whoever wrote it -- Andrew's own reading of the
   upload bar's line. This is the size of a copyright mark, sits against the
   thing it explains, and opens a window with the whole of it.
   `portal/templates/_help.html` is the macro; these are its rules. */
.help-dot {
  display: inline-grid; place-items: center; vertical-align: middle;
  width: 15px; height: 15px; margin-left: 6px; padding: 0;
  border: 1px solid var(--ink-3); border-radius: 50%;
  background: transparent; color: var(--ink-2);
  font-size: 10px; font-weight: 800; line-height: 1; cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.help-dot:hover, .help-dot:focus-visible {
  background: var(--dignity); border-color: var(--dignity); color: #fff;
}
/* A column heading is uppercase and letter-spaced; the mark should not be. */
th .help-dot { letter-spacing: 0; text-transform: none; }

/* **Set on the last word, like a copyright sign.** Where the mark belongs to a
   sentence rather than to a control beside it, it rides above the line at the
   end of the final word -- which is where the eye already is when the sentence
   runs out. Smaller than the standing one, because it is inside running text. */
.help-dot.is-sup {
  width: 13px; height: 13px; margin-left: 1px;
  font-size: 9px; vertical-align: super;
}

.help-pop {
  width: min(94vw, 30rem); padding: 0; border: 0;
  border-radius: var(--r-md); background: var(--surface); color: var(--ink);
  box-shadow: 0 24px 60px rgba(10, 31, 68, .3);
}
.help-pop::backdrop { background: rgba(10, 31, 68, .34); }
.help-pop-hd {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 16px; border-bottom: 1px solid var(--line);
}
.help-pop-hd h3 {
  margin: 0; font-size: 15px; display: flex; align-items: center; gap: 7px;
}
.help-pop-hd .ico { width: 17px; height: 17px; color: var(--dignity); }
.help-pop-x {
  margin-left: auto; border: 0; background: transparent; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--ink-2); padding: 0 2px;
}
.help-pop-x:hover { color: var(--ink); }
.help-pop-bd { padding: 14px 16px 16px; font-size: 13.5px; line-height: 1.55; }
.help-pop-bd p { margin: 0 0 10px; }
.help-pop-bd p:last-child { margin-bottom: 0; }
.help-pop-note {
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line);
  color: var(--ink-2); font-size: 12.5px;
}


/* ---- The library's tool bar ------------------------------------------------
   **Five tools drawn alike, as icons.** Andrew: standardise the bar so every
   management tool looks the same -- Upload files, Upload a folder, Download,
   Move, Trash -- one size and one shape, with the word in the hover rather
   than on the button.

   At the end of the file on purpose, and four classes deep: the portal's own
   `.btn:not(.ghost):not(.sm)` and `.btn.is-danger` are both declared at the
   same weight elsewhere, and a component that loses to either comes out in a
   colour nobody chose. That trap is recorded three times already. */
.lb-foot .btn.sm.lb-tool {
  display: inline-flex; align-items: center; justify-content: center; gap: 0;
  width: 38px; min-width: 38px; height: 34px; padding: 0;
  border-radius: 8px; white-space: nowrap;
  transition: color .12s, border-color .12s, background .12s, opacity .12s,
              filter .12s;
}
.lb-foot .btn.sm.lb-tool .ico { width: 19px; height: 19px; }
/* **One cluster, at the right.** The uploads sat on the left and the
   selection tools on the right while which of them was on offer changed with
   the ticks; now every tool is always drawn and colour says which is live,
   Andrew asked for them together. Same gap between every pair, so it reads
   as one toolbar rather than two groups that happen to be close. */
.lb-foot { justify-content: flex-end; gap: 8px; }
.lb-foot > .lb-up-side { flex: none; }
.lb-up-side { display: flex; align-items: center; gap: 8px; }
.lb-upload { gap: 8px; }
.lb-acts { margin-left: 0; flex: none; display: flex; gap: 8px; }

/* **Colour is the state.** Andrew: the flat white icons looked the same live
   and not, so a live tool is a filled, tinted button with a filled icon --
   the folder tools a manila folder, Download a solid arrow, Trash a filled
   bin -- and an inactive one is a grey outline with a grey outline icon.
   Two looks that differ in fill, colour and weight at once, rather than one
   look at two opacities.

   Each tool names its own colours once; the live rule applies them. Lucide
   draws with `stroke` and `fill` presentation attributes, which any
   stylesheet rule outranks, so filling an icon is a declaration and not a
   second icon set. The tints are outside the brand like the status colours,
   because they say what a thing *is* -- a folder, a bin -- rather than whose
   it is. */
.lb-foot .lb-tool.t-upfile   { --tool-bg: #e6eff9; --tool-br: #8fb0d6; --tool-fill: #ffffff; --tool-ink: var(--dignity); }
.lb-foot .lb-tool.t-upfolder { --tool-bg: #fdf1d8; --tool-br: #dcb466; --tool-fill: #f5c969; --tool-ink: #8a5a12; }
.lb-foot .lb-tool.t-download { --tool-bg: #e6eff9; --tool-br: #8fb0d6; --tool-fill: var(--dignity); --tool-ink: #ffffff; }
.lb-foot .lb-tool.t-move     { --tool-bg: #fdf1d8; --tool-br: #dcb466; --tool-fill: #f5c969; --tool-ink: #8a5a12; }
.lb-foot .lb-tool.t-trash    { --tool-bg: #fdecec; --tool-br: #f0a3a3; --tool-fill: #fecaca; --tool-ink: #b91c1c; }

/* Inactive, which is every tool until the rule below says otherwise. */
.lb-foot .btn.sm.lb-tool {
  background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-4); cursor: default; opacity: .7;
}
.lb-foot .btn.sm.lb-tool .ico { fill: none; stroke: var(--ink-4); }

/* Live: the uploads while nothing is ticked, the selection tools once
   something is. With no script
   there is no ticking state at all, and the uploads read as live, which they
   are. */
.lb-foot:not(.is-armed) .btn.sm.lb-tool.lb-up-tool,
.lb-foot.is-armed .btn.sm.lb-tool.lb-act {
  background: var(--tool-bg); border-color: var(--tool-br);
  color: var(--tool-ink); cursor: pointer; opacity: 1;
}
.lb-foot:not(.is-armed) .btn.sm.lb-tool.lb-up-tool .ico,
.lb-foot.is-armed .btn.sm.lb-tool.lb-act .ico {
  fill: var(--tool-fill); stroke: var(--tool-ink);
}
.lb-foot:not(.is-armed) .btn.sm.lb-tool.lb-up-tool:hover,
.lb-foot.is-armed .btn.sm.lb-tool.lb-act:hover {
  filter: brightness(.95) saturate(1.1);
}

/* Five icons fit a phone's row, so the bar stays one row there too. */

/* ---- The Move window: the department's folder tree, to choose from. */
.lb-move {
  width: min(94vw, 32rem); padding: 0; border: 0;
  border-radius: var(--r-md); background: var(--surface); color: var(--ink);
  box-shadow: 0 24px 60px rgba(10, 31, 68, .3);
}
.lb-move::backdrop { background: rgba(10, 31, 68, .34); }
.lb-move-hd {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 16px; border-bottom: 1px solid var(--line);
}
.lb-move-hd h3 { margin: 0; font-size: 15px; display: flex; align-items: center; gap: 7px; flex: 1; }
.lb-move-say { margin: 10px 16px 6px; font-size: 12.5px; color: var(--ink-3); }
.lb-move-tree {
  max-height: min(55vh, 26rem); overflow: auto;
  margin: 0 10px; padding: 4px 6px 8px;
  border: 1px solid var(--line); border-radius: 8px;
}
.lb-pick-list { list-style: none; margin: 0; padding: 0; }
.lb-pick-list .lb-pick-list { padding-left: 18px; }
.lb-pick-list li:not(.is-open) > .lb-pick-list { display: none; }
.lb-pick-row { display: flex; align-items: center; gap: 2px; min-height: 30px; }
.lb-pick-row label {
  display: flex; align-items: center; gap: 7px; flex: 1; min-width: 0;
  padding: 4px 8px; border-radius: 6px; cursor: pointer; font-size: 13px;
}
.lb-pick-row label span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-pick-row label:hover { background: var(--canvas); }
.lb-pick-row input[type=radio] { margin: 0; flex: none; }
/* The chosen row, marked by the script rather than by `:has(input:checked)`
   -- the contract check reads a selector naming an input as a field's colour,
   and this is a label's. */
.lb-pick-row.is-chosen label { background: #e8eef6; color: var(--dignity); font-weight: 600; }
.lb-pick-row.is-here label { cursor: default; color: var(--ink-4); }
.lb-pick-row.is-here label:hover { background: none; }
.lb-pick-row em { font-style: normal; font-size: 11px; color: var(--ink-4); margin-left: auto; }
.lb-pick-caret, .lb-pick-caret-gap { flex: none; width: 22px; height: 22px; }
.lb-pick-caret {
  display: inline-grid; place-items: center; padding: 0; border: 0;
  background: none; color: var(--ink-3); cursor: pointer; border-radius: 5px;
}
.lb-pick-caret:hover { background: var(--canvas); color: var(--ink); }
.lb-pick-caret .ico { width: 14px; height: 14px; transition: transform .12s; }
.lb-pick-list li.is-open > .lb-pick-row .lb-pick-caret .ico { transform: rotate(90deg); }
.lb-move-ft {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 12px 16px; border-top: 1px solid var(--line); margin-top: 10px;
}
.lb-move-go[disabled] { opacity: .5; cursor: default; }

/* ---- A tool's hover card: its name in bold, then one sentence. */
.help-tip {
  position: fixed; z-index: 95; width: min(90vw, 22rem);
  padding: 12px 14px; border-radius: 10px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--frame); box-shadow: 0 14px 34px rgba(10, 31, 68, .22);
  font-size: 12.5px; line-height: 1.5; pointer-events: none;
}
.help-tip p { margin: 0 0 6px; }
.help-tip p:last-child { margin-bottom: 0; }
.help-tip strong.help-tip-hd { display: block; margin-bottom: 3px; font-size: 13px; }
.help-tip.is-tool { width: min(90vw, 17rem); }
.help-tip .help-tip-then { display: block; margin-top: 5px; color: var(--ink-3); font-size: 12px; }

/* A line at the foot of the window for an act whose result is somewhere else
   -- a zip being built is the browser's to show once it starts. */
.lb-toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 96; max-width: min(92vw, 34rem); padding: 10px 16px;
  border-radius: 999px; background: var(--navy-900, #0a1f44); color: #fff;
  font-size: 13px; box-shadow: 0 10px 28px rgba(10, 31, 68, .3);
}

/* ---- A list that is on its way ------------------------------------------
   The Recover page opens before Drive has answered and says what it is
   doing; three dots rise in turn so the wait reads as work, not a hang.
   Still, for anybody who asks for reduced motion. */
.lb-loading {
  padding: 40px 16px; text-align: center;
  color: var(--ink-3); font-size: 14px;
}
.lb-dots i {
  display: inline-block; font-style: normal; font-weight: 700;
  animation: lb-dot 1.2s infinite ease-in-out;
}
.lb-dots i:nth-child(2) { animation-delay: .2s; }
.lb-dots i:nth-child(3) { animation-delay: .4s; }
@keyframes lb-dot {
  0%, 60%, 100% { opacity: .25; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .lb-dots i { animation: none; opacity: 1; }
}

/* ---- Are you sure ----------------------------------------------------------
   The one question a folder's Delete asks: the sentence, then Cancel and a
   red Delete. Its own classes rather than .btn.is-danger, which is declared
   far earlier and loses to the portal's primary button rule. */
dialog.lb-confirm {
  border: 1px solid var(--frame); border-radius: 12px;
  padding: 20px 22px 16px; width: min(420px, calc(100vw - 32px));
  box-shadow: 0 18px 48px rgba(10, 31, 68, .22);
}
dialog.lb-confirm::backdrop { background: rgba(10, 31, 68, .35); }
dialog.lb-confirm p { margin: 0 0 18px; font-size: 15px; line-height: 1.45; overflow-wrap: anywhere; }
.lb-confirm-foot { display: flex; justify-content: flex-end; gap: 8px; }
dialog.lb-confirm .lb-confirm-foot .btn.sm.lb-confirm-go {
  background: #c62828; border-color: #c62828; color: #fff;
}
dialog.lb-confirm .lb-confirm-foot .btn.sm.lb-confirm-go:hover {
  background: #a51f1f; border-color: #a51f1f;
}

/* The portal's own notice and question share the Delete window's frame; a
   notice may run to several paragraphs, so they sit closer together. */
dialog.lb-confirm #portal-say-q p { margin: 0 0 10px; }
dialog.lb-confirm #portal-say-q p:last-child { margin-bottom: 18px; }

/* The tick and the name share one line. The name was allowed 100% of the
   cell, so with the tick in front a long name was 22px too wide and wrapped
   under it, leaving the box on a line of its own. The name now takes what the
   tick leaves, and the cell does not wrap; the ellipsis still ends the name. */
table.lb tbody td:first-child { white-space: nowrap; }
table.lb tbody td:first-child .lb-tick + .lb-name { max-width: calc(100% - 24px); }

/* ---- The file list on a phone ---------------------------------------------
   Below 560px a row is a card, the way Drive, OneDrive and Dropbox draw a
   file list on a phone: the tick, the icon and the name on the first line --
   wrapping as far as it needs rather than cut to nothing -- with the row's
   menu at its right; then one small line of type . size . modified, one of
   who changed it last, and the status tags. The table was 237px of sideways drag
   at 390 with the name column squeezed to zero, so no file could be read.
   Every rule here is `.lb-main table.lb ...` and sits at the end of the file,
   because the rules it overrides are that weight and earlier. */
.lb-sortby { display: none; }
@media (max-width: 560px) {
  .lb-sortby { display: block; margin: 10px 12px 4px; font-size: 13px; }
  .lb-sortby > summary { cursor: pointer; color: var(--ink-3); list-style: none;
    display: inline-flex; align-items: center; gap: 6px; }
  .lb-sortby > summary::-webkit-details-marker { display: none; }
  .lb-sortby > summary b { color: var(--ink); }
  .lb-sortby .ico { width: 14px; height: 14px; }
  .lb-sortby-opts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
  .lb-sortby-opts .chip.is-on { border-color: var(--blue-600); color: var(--blue-600); }

  .lb-main .table-wrap { overflow-x: visible; }
  .lb-main table.lb, .lb-main table.lb tbody { display: block; width: 100%; min-width: 0; }
  .lb-main table.lb thead { display: none; }

  .lb-main table.lb tbody tr {
    display: flex; flex-wrap: wrap; align-items: center;
    padding: 10px 12px; column-gap: 8px; row-gap: 2px;
    border-bottom: 1px solid var(--line);
  }
  .lb-main table.lb tbody tr > td {
    display: block; height: auto; padding: 0; border: 0; max-width: none; width: auto;
  }
  .lb-main table.lb tbody tr > td:not(:last-child) { border-right: 0; }

  /* the name, and the menu beside it; the name takes the line so the
     columns that follow have to wrap under it */
  .lb-main table.lb tbody tr > td:first-child {
    order: 1; flex: 1 1 calc(100% - 48px); min-width: 0; white-space: normal;
    display: flex; align-items: flex-start;
  }
  .lb-main table.lb tbody tr > td:first-child .lb-tick { margin-top: 3px; }
  .lb-main table.lb tbody tr > td:first-child .lb-name,
  .lb-main table.lb tbody tr > td:first-child .lb-tick + .lb-name {
    display: block; max-width: none; white-space: normal; overflow: visible;
    overflow-wrap: anywhere; line-height: 1.35; font-size: 14px;
  }
  /* The icon floats so a long name runs beside it: inline, a name with no
     break in it wrapped whole onto the next line and left the icon alone. */
  .lb-main table.lb tbody tr > td:first-child .lb-name .lb-ico {
    float: left; margin: 1px 6px 0 0;
  }
  .lb-main table.lb tbody tr > td:first-child .lb-name .lb-ext { display: none; }
  .lb-main table.lb tbody tr > td:last-child { order: 2; flex: none; margin-left: auto; }

  /* type . size . modified . by, on one small line under the name */
  .lb-main table.lb tbody tr > td:nth-child(2),
  .lb-main table.lb tbody tr > td:nth-child(3),
  .lb-main table.lb tbody tr > td:nth-child(4),
  .lb-main table.lb tbody tr > td:nth-child(5) {
    order: 3; flex: none; font-size: 12px; color: var(--ink-3); white-space: nowrap;
  }
  .lb-main table.lb tbody tr > td:nth-child(2) { padding-left: 21px; }
  .lb-main table.lb tbody tr > td:nth-child(5) { flex: 1 1 100%; padding-left: 21px; }
  .lb-main table.lb tbody tr > td:nth-child(5):not(:empty)::before { content: "by "; }
  .lb-main table.lb tbody tr > td:nth-child(n+3):nth-child(-n+4):not(:empty)::before {
    content: "\00b7"; margin-right: 8px; color: var(--ink-4);
  }
  .lb-main table.lb tbody tr > td:nth-child(n+3):nth-child(-n+5):empty { display: none; }
  .lb-main table.lb tbody tr > td.lb-when { font-family: inherit; letter-spacing: 0; }

  /* the status tags on a line of their own, and nothing where there are none */
  .lb-main table.lb tbody tr > td:nth-child(6) { order: 4; flex: 1 1 100%; padding-left: 21px; }
  .lb-main table.lb tbody tr > td:nth-child(6):not(:has(.pb-pill, .badge)) { display: none; }

  /* the whole-width rows -- up one folder, nothing here, folders -- stay rows */
  .lb-main table.lb tbody tr > td[colspan] { flex: 1 1 100%; order: 1; }
}

/* Choosing a folder to upload needs a file manager that picks folders, which
   no phone or tablet has; there the control would open a picker that cannot
   do what it says. */
@media (hover: none) and (pointer: coarse) {
  .lb-foot .btn.sm.lb-tool.lb-up-tool.lb-up-folder { display: none; }
}

/* A file row that can be dragged says so under the pointer. */
@media (hover: hover) and (pointer: fine) {
  .lb-main table.lb tbody tr[data-drag-file] { cursor: grab; }
  .lb-main table.lb tbody tr[data-drag-file].is-lifting { opacity: .45; }
}

/* ---- Undo, in the corner of the file table ---------------------------------
   A tool like the ones on the bar: grey and quiet when there is nothing to
   undo, tinted and filled when the last move or delete can be undone. It sits
   in the heading row's last cell, which was empty, so lighting it moves
   nothing on the page. */
.lb-main table.lb thead th.lb-undo-h { width: 1%; text-align: center; padding: 0 8px; }
.lb-main table.lb thead th.lb-undo-h form { display: inline; }
.lb-undo {
  display: inline-grid; place-items: center; width: 30px; height: 28px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
  color: var(--ink-4); cursor: default; opacity: .7;
  transition: background .15s, color .15s, border-color .15s, opacity .15s;
}
.lb-undo .ico { width: 16px; height: 16px; stroke-width: 2.25; }
/* Lit, it carries a stronger tint, a heavier edge and a soft ring, so it
   reads as live from across the table; the grey state is unchanged. */
.lb-undo.is-live {
  opacity: 1; cursor: pointer; color: #1e40af;
  background: var(--blue-100); border: 1.5px solid var(--blue-600);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .18);
}
.lb-undo.is-live:hover { background: var(--blue-600); color: #fff; }

/* The notice floats at the foot of the window and fades, rather than sitting
   above the files and pushing the page down a row. */
.lb-notice {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 96; margin: 0; max-width: min(92vw, 34rem);
  box-shadow: 0 10px 28px rgba(10, 31, 68, .22);
  animation: lb-notice-out .4s ease 7s forwards;
}
@keyframes lb-notice-out { to { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) { .lb-notice { animation-duration: .01s; } }

/* ---- The national-chain list, on the Market Planner's Collection tab ------ */
.mk-chains .mk-brand-edit > summary { list-style: none; cursor: pointer; }
.mk-chains .mk-brand-edit > summary::-webkit-details-marker { display: none; }
.mk-chains .mk-brand-edit[open] form,
.mk-chains .mk-brand-add { display: grid; gap: 8px; margin-top: 8px; max-width: 28rem; }
.mk-chains .mk-brand-edit label,
.mk-chains .mk-brand-add label { display: grid; gap: 4px; font-size: 12.5px; color: var(--ink-3); }
.mk-chains .mk-suggest { list-style: none; padding: 0; margin: 8px 0 0; display: grid; gap: 10px; }
.mk-chains .mk-suggest li { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.mk-chains .mk-suggest form { display: inline-flex; gap: 6px; margin-left: auto; }

/* ---------------------------------------------------------------------------
   Market research, the drill-down (apps/marketplanner/templates/_research.html).

   The map is 240px high at every level and only its viewBox moves, so a click
   never changes the height of anything above the list. Census outlines and
   our own points: served states tinted, the rest faint and inert.
   ------------------------------------------------------------------------- */
.mk-work { min-height: 480px; }
/* The trail and the Export report button share a line; the button keeps right. */
/* The level heading and its Export control on one line: heading left, export
   right, so "N matching" and the way to export those N read together. */
.mk-res-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 12px; margin: 6px 0 8px; }
.mk-res-head .mk-h { margin: 0; }
.mk-res-hd .mk-export { margin-left: auto; }
.mk-res-note { margin: 0 0 6px; }
.mk-export { flex: none; position: relative; }
.mk-export > summary { list-style: none; cursor: pointer; }
.mk-export > summary::-webkit-details-marker { display: none; }
.mk-export-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 30; min-width: 220px;
  display: grid; padding: 4px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm); box-shadow: 0 8px 24px rgba(10, 31, 68, .12); }
.mk-export-menu a { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 6px;
  color: var(--ink); text-decoration: none; font-size: 13.5px; white-space: nowrap; }
.mk-export-menu a:hover, .mk-export-menu a:focus-visible { background: var(--canvas, #f1f5f9); }
.mk-export-menu svg { width: 16px; height: 16px; color: var(--dignity); }
/* On a phone the button wraps under the trail at the left, so the menu opens
   from its left edge rather than off the screen. After the rule it overrides. */
@media (max-width: 560px) { .mk-export-menu { left: 0; right: auto; } }
.mk-trail { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; margin: 0 0 8px; font-size: 13.5px; }
.mk-trail .sep { color: var(--ink-4); }
.mk-trail [aria-current] { font-weight: 650; color: var(--ink); }
.mk-mapbox { margin: 0 0 12px; }
svg.mk-map2 { display: block; width: 100%; height: 240px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--sky) 12%, white); }
.mk-st { fill: var(--surface); stroke: var(--line); stroke-linejoin: round; opacity: .55; }
.mk-st.is-served { fill: color-mix(in srgb, var(--sky) 30%, white); stroke: var(--ink-4); opacity: 1; }
.mk-st.is-here { fill: color-mix(in srgb, var(--sky) 45%, white); stroke: var(--dignity); }
.mk-map2 a { cursor: pointer; }
.mk-map2 a:hover .mk-st.is-served { fill: color-mix(in srgb, var(--sky) 55%, white); }
.mk-reach { fill: none; stroke: var(--dignity); stroke-dasharray: 0.02 0.015; opacity: .55; }
.mk-pin2 { fill: var(--dignity); stroke: var(--surface); fill-opacity: .85; }
.mk-pin2.is-away { fill-opacity: .35; }
.mk-pin2.is-chosen { fill: none; stroke: var(--dignity); }
.mk-pin2.is-plan-only { fill: var(--ink-4); fill-opacity: .35; stroke: none; }
.mk-map2 a:hover .mk-pin2 { fill: var(--dignity-hover); fill-opacity: 1; }
.mk-dot { fill-opacity: .75; }
.mk-dot.k-pharmacy { fill: #16a34a; }
.mk-dot.k-practice_location { fill: #2563eb; }
.mk-dot.k-nursing_facility { fill: #7c3aed; }
.mk-mapbox .mk-credit { margin-top: 4px; }

.mk-ask { margin: 0 0 14px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.mk-ask-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.mk-ask-q { flex: 1 1 260px; margin: 0; }
.mk-ask-q input { width: 100%; }
.mk-ask select { width: auto; }
.mk-ask-kinds { display: flex; flex-wrap: wrap; gap: 4px 12px; margin: 0; padding: 0; border: 0; font-size: 13px; }
.mk-ask-kinds label, .mk-crit-boxes label { display: inline-flex; align-items: center; gap: 4px; margin: 0; font-weight: 400; }
.mk-crit { margin-top: 8px; font-size: 13px; }
.mk-crit > summary { cursor: pointer; color: var(--dignity); font-weight: 600; }
.mk-crit-boxes { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; margin-top: 6px; }

.mk-h { margin: 6px 0 8px; font-size: 16px; }
.mk-levels .num, .mk-results .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.mk-go { font-weight: 650; }
.mk-sub2 { font-size: 12px; color: var(--ink-3); line-height: 1.4; }
.mk-strip { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; margin: 4px 0 4px; }
.mk-strip h2 { margin: 0; font-size: 19px; }
.mk-fig { font-size: 13px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.mk-fig b { color: var(--ink); }
.mk-fig.is-kind { font-size: 12px; }
.mk-char { margin: 0 0 10px; font-size: 13px; color: var(--ink-2); }
.mk-res-hd { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 12px 0 6px; }
.mk-res-hd h3 { margin: 0; font-size: 15px; }
.mk-res-hd .mk-note { margin: 0; }
.mk-results { font-size: 13px; }
.mk-results td { vertical-align: top; }
.mk-results td.is-fired { background: color-mix(in srgb, var(--sandstone) 30%, white); font-weight: 650; }
.mk-results th a { color: inherit; }
.mk-results th a[aria-sort] { color: var(--dignity); text-decoration: underline; }
/* Read out, not drawn: a label a control needs and a sighted reader does not. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.mk-inline { display: inline; margin: 0; }
.mk-tick { width: 32px; }
.mk-newlist { margin-top: 14px; }
.mk-listbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 6px 0; font-size: 13px; }
.mk-listbar select, .mk-listbar input[type=text] { width: auto; }
.pr-chip.is-listed { background: color-mix(in srgb, var(--sandstone) 35%, white); }
.pr-lists { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line-2); font-size: 13px; }
.pr-lists-add { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 6px 0 0; }
.pr-lists-add select, .pr-lists-add input[type=text] { width: auto; max-width: 14rem; }
.tp-list-pick { width: auto; max-width: 16rem; }
.mk-zips { margin: 10px 0 4px; }
.mk-zips > summary { cursor: pointer; font-weight: 650; font-size: 14px; }
.mk-ziptable { max-width: 640px; font-size: 13px; }
.mk-ziptable tr[aria-current] td { background: color-mix(in srgb, var(--sky) 22%, white); }
.mk-ziptable td, .mk-ziptable th { padding-top: 5px; padding-bottom: 5px; }
.pr-chip.is-bills { background: color-mix(in srgb, #7c3aed 14%, white); color: #5b21b6; }
/* Clinic type (FQHC/RHC): a steel tint, a label on the practice beside its name. */
.pr-chip.is-clinic { background: color-mix(in srgb, var(--dignity) 12%, white); color: var(--dignity); font-weight: 650; }
/* Possible ACO: a name match, not confirmed -- a quiet amber so it reads as a
   hint rather than a status, and never green or red, which mean what a rep can do. */
.pr-chip.is-aco { background: color-mix(in srgb, var(--amber, #d97706) 16%, white); color: #92600a; }
/* Clinic-type / ACO chips under the kind on a trip candidate row. */
.tp-cand-flags { display: flex; flex-wrap: wrap; gap: 3px 4px; margin-top: 3px; }
/* The ACO intelligence line on a flagged prospect's page. */
.pr-aco { margin: 8px 0 2px; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: color-mix(in srgb, var(--amber, #d97706) 7%, white);
  font-size: 13px; }
.pr-aco-lead { font-weight: 650; color: #92600a; }
.pr-aco-facts { margin-top: 3px; color: var(--ink-2); font-size: 12.5px; }
/* A chosen program's signal a row meets: the fired-figure mark's own look, never a status colour. */
.pr-signals { display: flex; flex-wrap: wrap; gap: 3px 4px; margin-top: 3px; white-space: normal; }
.pr-chip.is-signal { background: color-mix(in srgb, var(--dignity) 8%, white); color: var(--dignity); font-weight: 650; }
.mp-access { font-size: 12px; }
.mp-access-top { margin: 6px 0 10px; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: color-mix(in srgb, var(--sky) 10%, white); font-size: 13px; }
.mp-access-row { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 4px; color: var(--ink-2); }
.mp-access-row b { color: var(--ink); font-variant-numeric: tabular-nums; }


/* ---- The file list on a phone, one line a file ----------------------------
   Andrew, 29 September 2026: the card was four lines a file -- the name, type
   and size and date, who changed it, the tags -- so a folder showed four or
   five files a screen. Now one line: the tick, the icon, the name cut with an
   ellipsis, then owner and size, then the menu; the rest is in File
   properties, which the menu offers on a phone only. Appended after the card
   rules above, which are the same weight, so source order lets these win. */
.lb-mini, .lb-phone-only { display: none; }
@media (max-width: 560px) {
  .lb-phone-only { display: flex; }
  .lb-main table.lb tbody tr { flex-wrap: nowrap; padding: 8px 10px; }
  .lb-main table.lb tbody tr > td:nth-child(2),
  .lb-main table.lb tbody tr > td:nth-child(3),
  .lb-main table.lb tbody tr > td:nth-child(4),
  .lb-main table.lb tbody tr > td:nth-child(5),
  .lb-main table.lb tbody tr > td:nth-child(6) { display: none; }
  .lb-main table.lb tbody tr > td:first-child {
    flex: 1 1 auto; align-items: center; white-space: nowrap; gap: 0;
  }
  .lb-main table.lb tbody tr > td:first-child .lb-tick { margin-top: 0; }
  .lb-main table.lb tbody tr > td:first-child .lb-name,
  .lb-main table.lb tbody tr > td:first-child .lb-tick + .lb-name {
    flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; overflow-wrap: normal; font-size: 13.5px;
  }
  .lb-main table.lb tbody tr > td:first-child .lb-name .lb-ico {
    float: none; display: inline-block; vertical-align: -2px; margin: 0 6px 0 0;
  }
  .lb-mini {
    display: flex; flex: none; gap: 6px; margin-left: 8px;
    font-size: 11.5px; color: var(--ink-3); white-space: nowrap;
  }
  .lb-mini-when + .lb-mini-size::before { content: "\00b7"; margin-right: 6px; color: var(--ink-4); }
  .lb-main table.lb tbody tr > td[colspan] { white-space: normal; }
}
dialog.lb-props h3 { margin: 0 0 10px; font-size: 15px; overflow-wrap: anywhere; }
.lb-props-list { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px;
  margin: 0 0 16px; font-size: 13.5px; }
.lb-props-list dt { color: var(--ink-3); }
.lb-props-list dd { margin: 0; overflow-wrap: anywhere; }
dialog.lb-props .lb-confirm-foot { flex-wrap: wrap; }

/* **A place on the way: a quiet line under Finishing at, a field when
   opened.** Inside the finish's own field, so the plan form gains no row. */
/* A place on the way: a disclosure whose summary is a caret (not a plus --
   the plus read as "add a row" and the toggle hid the field), opening onto up
   to four rows, each its own input with a Remove, and one Add below them. */
.tp-via { margin-top: .3rem; }
.tp-via > .tp-via-sum { list-style: none; cursor: pointer; display: inline-flex; align-items: center;
  gap: .25rem; font-size: 12.5px; color: var(--dignity); }
.tp-via > .tp-via-sum::-webkit-details-marker { display: none; }
.tp-via > .tp-via-sum:hover { text-decoration: underline; }
.tp-via-caret { width: 13px; height: 13px; transition: transform .15s ease; }
.tp-via[open] > .tp-via-sum .tp-via-caret { transform: rotate(90deg); }
.tp-via[open] > .tp-via-sum { margin-bottom: .35rem; }
.tp-via-rows { display: flex; flex-direction: column; gap: .3rem; }
.tp-via-row { display: flex; align-items: center; gap: .3rem; }
.tp-via-row > input { flex: 1 1 auto; min-width: 0; }
.tp-via-del { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border: 1px solid var(--field-line); border-radius: 6px;
  background: var(--field); color: var(--ink-3); cursor: pointer; }
.tp-via-del:hover { color: var(--danger); border-color: var(--danger); }
.tp-via-del .ico { width: 14px; height: 14px; }
.tp-via-more { margin-top: .35rem; display: inline-flex; align-items: center; gap: .25rem;
  background: none; border: 0; padding: 0; cursor: pointer; font-size: 12.5px; color: var(--dignity); }
.tp-via-more:hover { text-decoration: underline; }
.tp-via-more .ico { width: 14px; height: 14px; }
.tp-via-more[hidden], .tp-via-del[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .tp-via-caret { transition: none; } }

/* Just ask on Plan a trip: the same box, with what it could not fill listed
   and the next step said. */
.tp-plan-ask { margin-bottom: 12px; }
.tp-ask-unclear { margin: 6px 0 0; padding: 0; list-style: none; text-align: center;
  font-size: 12.5px; color: var(--ink-3); }
.tp-ask-next { margin: 6px 0 0; font-size: 12.5px; text-align: center; }

/* **A stop is a heading row, a line of where, and one fold.** Andrew, 1
   October 2026: with the choosing done, the day is managed by its order and
   its clock. The times sit on the name row in one small group, left of
   Selection criteria; the notes, the time per visit, how it went and what we
   learned sit behind "Visit Details and Notes"; the appointment time stays in
   view at that row's right. Measured on trip 49: 258px a stop to 140. */
/* 3px above and below the stop's heading row (Andrew), and the name centred
   in it, so the space either side of the heading is even. */
.tp-node.is-stop .tp-stop-hd { padding-top: 3px; padding-bottom: 3px; align-items: center; }
.tp-stop-hd .tp-stop-times {
  flex: none; align-self: center; margin: 0 0 0 auto; padding: 0;
  display: flex; flex-wrap: nowrap; gap: 0;
  background: color-mix(in srgb, var(--surface) 75%, transparent);
  border: 1px solid color-mix(in srgb, var(--a, var(--dignity)) 22%, var(--line-2));
  border-radius: 8px;
}
.tp-stop-hd .tp-stop-times div { flex-direction: column; align-items: center; gap: 0; padding: 3px 10px; }
.tp-stop-hd .tp-stop-times div + div { border-left: 1px solid var(--line-2); }
.tp-stop-hd .tp-stop-times dt { font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  white-space: nowrap; }
.tp-stop-hd .tp-stop-times dt .tp-src { text-transform: none; letter-spacing: 0; }
.tp-stop-hd .tp-stop-times dd { font-size: 14px; white-space: nowrap; }
.tp-stop-hd .tp-stop-times + .tp-stop-crit { margin-left: 0; }
/* Shrunk to sit inside the 3px row: thin cells, tight lines, and the "yours"
   tag beside "Time here" at the label's own height rather than adding to it. */
.tp-stop-hd .tp-stop-times div { padding: 1px 9px; }
.tp-stop-hd .tp-stop-times dt { font-size: 9.5px; line-height: 1.2; display: flex; align-items: center; gap: 4px; }
.tp-stop-hd .tp-stop-times dt .tp-src { font-size: 8.5px; line-height: 1.1; padding: 0 4px; }
.tp-stop-hd .tp-stop-times dd { font-size: 13.5px; line-height: 1.2; }

/* The appointment time holds its place at the right of the fold line, out of
   the flow, so an opened fold has the stop's whole width for its notes. */
.tp-fold { position: relative; padding: 1px 0; border-top: 1px solid var(--line-2); }
.tp-visit { flex: 1 1 auto; min-width: 0; }
.tp-visit > summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; gap: 8px;
  padding: 6px 400px 6px 14px; min-height: 40px; align-content: center;
  font-size: 13px; font-weight: 650; color: var(--dignity); border-radius: 6px; }
.tp-visit > summary::-webkit-details-marker { display: none; }
.tp-visit > summary::before { content: "\25B8"; font-size: 12px; width: 10px; flex: none; }
.tp-visit[open] > summary::before { content: "\25BE"; }
.tp-visit > summary:hover { background: color-mix(in srgb, var(--dignity) 5%, transparent); }
.tp-visit-hint { font-weight: 400; font-size: 12px; color: var(--ink-3); }
.tp-visit > .tp-stop-forms { border-radius: 0 0 0 12px; }
.tp-fold .tp-book { position: absolute; top: 4px; right: 10px; flex-wrap: nowrap; align-items: center; margin: 0; }
.tp-fold .tp-field-book { display: flex; flex-direction: row; align-items: center; gap: 6px; flex: none; }
.tp-fold .tp-field-book > span:first-child { display: flex; flex-direction: column; align-items: flex-end;
  margin: 0; text-align: right; line-height: 1.15; font-size: 12px; font-weight: 650; }
.tp-fold .tp-field-book small { font-size: 10.5px; font-weight: 400; color: var(--ink-3); }
.tp-fold .tp-field-book input { width: 104px; height: 26px; min-height: 0; padding: 0 6px;
  font-size: 12.5px; line-height: 1; }
.tp-fold .tp-book .tp-pill { height: 26px; min-height: 0; padding: 0 11px; font-size: 12px; }
.tp-fold .tp-field-book > span:first-child { font-size: 11.5px; }
.tp-fold .tp-field-book small { font-size: 10px; }
/* Kept inside the fold row: the row is as tall as its summary, and the
   control is centred in it rather than hung from its top. */
.tp-fold .tp-book { top: 50%; transform: translateY(-50%); }
.tp-visit[open] ~ .tp-book { top: 19px; }

@media (max-width: 560px) {
  .tp-node.is-stop .tp-stop-hd .tp-stop-times { order: 4; margin-left: 0; flex: 1 1 100%; min-width: 0; }
  .tp-stop-hd .tp-stop-times div { flex: 1 1 0; min-width: 0; padding: 3px 4px; }
  .tp-stop-hd .tp-stop-times dt { font-size: 9px; white-space: normal; text-align: center; }
  .tp-stop-hd .tp-stop-times dt .tp-src { display: block; width: max-content; margin: 1px auto 0; }
  .tp-stop-hd .tp-stop-times dd { font-size: 12.5px; white-space: normal; text-align: center; }
  .tp-visit > summary { flex-wrap: wrap; row-gap: 0; padding-right: 8px; min-height: 0; }
  .tp-visit-hint { flex-basis: 100%; padding-left: 18px; }
  .tp-fold .tp-book { position: static; flex-wrap: wrap; margin: 0 10px 8px 14px; }
  .tp-fold .tp-field-book { flex-wrap: wrap; flex: 1 1 100%; min-width: 0; }
  .tp-fold .tp-field-book small { white-space: normal; }
  .tp-fold .tp-field-book > span:first-child { flex-basis: 100%; align-items: flex-start; text-align: left; }
}

/* Several appointments: Sort my day, the whole day's order with its count of
   calls, and one part at a time behind a small fold. */
.tp-pill-note { font-weight: 500; opacity: .75; margin-left: 2px; }
.tp-order-parts { position: relative; }
.tp-order-parts > summary { list-style: none; cursor: pointer; font-size: 12.5px; font-weight: 650;
  color: var(--dignity); padding: 6px 8px; border-radius: 999px; }
.tp-order-parts > summary::-webkit-details-marker { display: none; }
.tp-order-parts > summary::after { content: " \25BE"; font-size: 11px; }
.tp-order-parts > summary:hover { background: color-mix(in srgb, var(--dignity) 6%, transparent); }
.tp-order-parts-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 30;
  display: flex; flex-direction: column; gap: 6px; padding: 8px; min-width: 14rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 8px 24px rgba(10, 31, 68, .14); }
.tp-order-parts-menu .tp-pill { width: 100%; justify-content: flex-start; }
.pr-sort-dir { font-size: 9px; margin-left: 3px; }

/* ---------- Tables: columns you can follow (21 October 2026) ----------

   Andrew: rows had faint lines but column data seemed "loosely associated with
   the column". Measured on the demo practice: 49 tables, 220 columns, none with
   a line between columns; 46 wide columns whose values filled under 45% of the
   width; two number columns left-aligned. So, for every data table:

   * the same faint line between columns as between rows (`--grid`);
   * numbers right-aligned with their heading, in tabular figures, unwrapped,
     and their column only as wide as its widest value -- the free-text
     column takes the slack, instead of every value floating mid-column;
   * `.fit` does the same for a date, status or action column;
   * `.compact` stops a two- or three-column table stretching across a card;
   * `.zebra` shades alternate rows of a long list;
   * badges and dates never wrap.

   Written with :where() so each rule weighs no more than the base `tbody td`
   rule -- a table with its own styling (the library, the prospect list) still
   wins wherever it says something. `.plain` opts a table out, and the phone
   layouts that turn rows into cards (pr-list, pr-stack) are left alone. */
:root { --grid: #e6ebf1; }

:where(table:not(.plain, .pr-list, .pr-stack)) tbody td {
  border-bottom-color: var(--grid);
}
:where(table:not(.plain, .pr-list, .pr-stack)) :is(tbody td, thead th, tbody th) + :is(td, th) {
  border-left: 1px solid var(--grid);
}
:where(table:not(.plain, .pr-list, .pr-stack)) thead th { border-bottom-color: var(--line); }

:where(td, th):is(.num, .right) {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; width: 1%;
}
:where(td, th).fit { white-space: nowrap; width: 1%; }

:where(table).compact { width: auto; min-width: 280px; max-width: 100%; }
:where(table).compact :is(td, th):first-child { padding-right: 28px; }

:where(table).zebra > tbody > tr:nth-child(even) { background: #fafbfd; }
:where(table).zebra > tbody > tr:hover { background: var(--blue-50); }

/* A size-to-content table must not have a 1% column: the browser grows the
   table until 1% of it holds the value, i.e. to the full card. */
table.compact :is(td, th):is(.num, .right, .fit) { width: auto; }

.badge, .qc-day { white-space: nowrap; }

/* A metric card's footnote borrowed the page footer's `.foot` -- a flex row
   padded 32px -- so it sat 14px right of the label above it, and any element
   in it (a date) split the line into columns. A plain block on the label's
   edge, keeping the rule above it. */
.metric .foot { display: block; padding: 8px 0 0; margin-top: 8px; background: none; }

/* A card heading inside an already padded card sat 20px in from the card's
   content, and its rule stopped 20px short of each edge (20 cards). Pull it
   out to the card's edges, so heading, rule and body share one left edge. */
.card-pad > .card-hd:first-child { margin: -18px -20px 14px; padding-left: 20px; padding-right: 20px; }
/* A card whose body is a table starts its first column 16px in (the cell
   padding), so its heading does too -- it was 4px further in than the
   column it heads. */
.card-hd { padding-left: 16px; padding-right: 16px; }

/* ---------- Wide tables: show that there is more (21 October 2026) ----------

   Seven tables scrolled sideways inside their card at a 1100px laptop width
   with nothing to say so. base.html marks a wrap that scrolls (`scrolls`) and
   one hiding columns past its right edge (`more-right`):

   * the right edge fades while there is more to scroll to;
   * the first column -- what each row is -- stays put as the rest scroll, on
     an opaque background (rows get the card's colour so the stuck cell can
     inherit its row's, zebra and hover included), with a rule beside it. */
.table-wrap.more-right {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 56px), rgba(0, 0, 0, .15));
          mask-image: linear-gradient(to right, #000 calc(100% - 56px), rgba(0, 0, 0, .15));
}
:where(.table-wrap.scrolls) tbody tr { background: var(--surface); }
.table-wrap.scrolls > table > :is(thead, tbody) > tr > :first-child {
  position: sticky; left: 0; z-index: 1;
  box-shadow: 1px 0 0 var(--line);
}
.table-wrap.scrolls > table > tbody > tr > :first-child { background: inherit; }
.table-wrap.scrolls > table > thead > tr > :first-child { background: var(--canvas); }
/* A first column of tick boxes is not what a row is: the second one sticks
   with it (care gaps, send evidence). */
.table-wrap.scrolls > table.stick-2 > :is(thead, tbody) > tr > :nth-child(2) {
  position: sticky; left: var(--stick-1, 44px); z-index: 1; box-shadow: 1px 0 0 var(--line);
}
.table-wrap.scrolls > table.stick-2 > :is(thead, tbody) > tr > :first-child { box-shadow: none; }
.table-wrap.scrolls > table.stick-2 > tbody > tr > :nth-child(2) { background: inherit; }
.table-wrap.scrolls > table.stick-2 > thead > tr > :nth-child(2) { background: var(--canvas); }

/* Dense: a many-column table on a laptop. Tighter cells, same lines. */
:where(table).dense :is(tbody td, thead th) { padding: 8px 10px; }

/* ---------- Secondary buttons you can see ---------- */
/* Andrew, 22 October 2026: the white "ghost" buttons -- Open the board,
   Print, Facilities and letters, Show -- "slip by without even looking",
   while the coral ones draw the eye. A secondary action keeps its rank
   (lighter than the solid coral primary) but now carries a blue tint:
   blue already means "go somewhere" here, it stays distinct from coral
   Save, and it does not read as a green or amber status. (A coral tint
   was tried first; it blurred into the primary.) */
.btn.ghost {
  background: #eff6ff;
  border-color: #93b4f5;
  color: #1d4ed8;
}
.btn.ghost:hover {
  background: #dbeafe;
  border-color: #6b97ef;
  color: #1e40af;
}
.btn.ghost:disabled, .btn.ghost[aria-disabled="true"] {
  background: var(--line-2); border-color: var(--line); color: var(--ink-4); cursor: default;
}
