/* P3 Nurture admin console */
:root {
	--bg: #f6f7fb;
	--surface: #ffffff;
	--surface-2: #f9fafc;
	--border: #e8eaf1;
	--border-strong: #d7dae4;
	--text: #0f172a;
	--text-2: #475569;
	--muted: #8a93a6;
	/* --text-muted was used in seven places - the calendar day headings and
	   dates among them - and never defined anywhere, so those colours were
	   falling back to inherited text and the headings read as body copy. Defined
	   as the same grey rather than hunted down and renamed, because the name is
	   a reasonable one and renaming seven call sites is seven chances to miss
	   one. */
	--text-muted: #8a93a6;
	--accent: #5b5bf6;
	--accent-600: #4a48e0;
	--accent-50: #eef0ff;
	--accent-100: #e0e3ff;
	--green: #0f9f6e; --green-50: #e7f7f0;
	--red: #e5484d; --red-50: #fdeeee;
	--amber: #c77c02; --amber-50: #fdf5e4;
	--blue: #2f7de1; --blue-50: #e9f2fd;
	--violet: #8b5cf6; --violet-50: #f2edff;
	--radius: 14px;
	--radius-sm: 10px;
	--shadow-sm: 0 1px 2px rgba(15, 23, 42, .04);
	--shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 4px 16px rgba(15, 23, 42, .04);
	--shadow-lg: 0 12px 40px rgba(15, 23, 42, .12);
	--sidebar: 256px;

	/* ----------------------------------------------------------------
	   213: FIVE NAMES THAT WERE USED AND NEVER DEFINED.

	   28 uses across ten files, every one of them doing nothing. An
	   undefined custom property makes the whole declaration invalid at
	   computed-value time, so the property falls back to inherited or
	   initial - which for a background means transparent and for a
	   border means none. Nothing errors, nothing logs, and the element
	   simply has no background.

	   --surface-3 was the worst of them: it is the hover tint, so the
	   pin button, the chips, the nav search and the panel buttons all
	   had hover states that did not highlight.

	   DEFINED AS ALIASES RATHER THAN EDITED OUT of 28 call sites. The
	   names are reasonable and in use; aliasing makes every existing
	   one correct in one place and means the next person who reaches
	   for the familiar name gets the right colour instead of nothing.

	   csscheck did not catch this because it reads class names and
	   never looked at var(). It does now.
	   ---------------------------------------------------------------- */
	--surface-3: #f1f3f8;      /* hover tint: between surface-2 and border */
	--panel: #f9fafc;          /* = surface-2; a card inset inside a card */
	--line: #e8eaf1;           /* = border; the hairline rule */
	--soft: #f9fafc;           /* = surface-2 */
	--bg-2: #f6f7fb;           /* = bg */
	--font: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body { font-family: var(--font); font-size: 14px; line-height: 1.5; color: var(--text); background: var(--bg); -webkit-font-smoothing: antialiased; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-600); }
h1, h2, h3, h4 { margin: 0; letter-spacing: -0.015em; }
code, .mono { font-family: var(--mono); font-size: 12.5px; }
.i { flex-shrink: 0; vertical-align: middle; }
.muted { color: var(--muted); }
.small { font-size: 12px; }
.nowrap { white-space: nowrap; }
.right { text-align: right; }
.hidden { display: none !important; }

/* ---------- Shell ---------- */
.app { display: flex; min-height: 100vh; }
.sidebar {
	width: var(--sidebar); position: fixed; inset: 0 auto 0 0; z-index: 30;
	background: #0d1024; color: #c5c9d9; display: flex; flex-direction: column;
	padding: 18px 14px; overflow-y: auto;
}
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 10px 22px; color: #fff; }
.brand-mark {
	width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; font-weight: 800; font-size: 14px; color: #fff;
	background: linear-gradient(135deg, #7c7cff 0%, #5b5bf6 45%, #c35bf6 100%); box-shadow: 0 6px 18px rgba(91, 91, 246, .45);
}
.brand-name { font-weight: 700; font-size: 15px; letter-spacing: -0.01em; }
.brand-sub { font-size: 11px; color: #7d839c; margin-top: -2px; }
.nav-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .09em; color: #5f6580; padding: 16px 12px 6px; font-weight: 600; }
.nav a {
	display: flex; align-items: center; gap: 11px; padding: 9px 12px; border-radius: 10px; color: #b3b8cc; font-weight: 500;
	transition: background .15s, color .15s; margin-bottom: 2px;
}
.nav a:hover { background: rgba(255,255,255,.05); color: #fff; }
.nav a.active { background: rgba(124,124,255,.16); color: #fff; box-shadow: inset 0 0 0 1px rgba(124,124,255,.25); }
.nav a.active .i { color: #a5a6ff; }
.nav .count { margin-left: auto; font-size: 11px; background: rgba(255,255,255,.08); padding: 1px 7px; border-radius: 99px; color: #cfd3e3; }
.sidebar-foot { margin-top: auto; padding-top: 10px; border-top: 1px solid rgba(255,255,255,.06); position: sticky; bottom: -18px; background: #0d1024; padding-bottom: 18px; margin-bottom: -18px; }
/* drop 113: one-item scroll buttons for the menu */
.nav-steppers { display: flex; gap: 6px; justify-content: flex-end; padding: 0 6px 8px; }
.nav-steppers button { background: rgba(255,255,255,.06); border: 0; color: #cfd3e3; cursor: pointer; width: 34px; height: 30px; border-radius: 8px; display: grid; place-items: center; }
.nav-steppers button:hover { background: rgba(255,255,255,.12); color: #fff; }
.nav-steppers button:disabled { opacity: .35; cursor: default; }
.me { display: flex; align-items: center; gap: 10px; padding: 8px 10px; }
.me .avatar { background: #262a45; color: #d9dcf0; }
.me-email { font-size: 12px; color: #d9dcf0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 150px; }
.me a { margin-left: auto; color: #7d839c; }
.me a:hover { color: #fff; }

.main { flex: 1; margin-left: var(--sidebar); min-width: 0; }
.topbar {
	position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 16px; height: 64px; padding: 0 32px;
	background: rgba(246,247,251,.82); backdrop-filter: saturate(180%) blur(12px); -webkit-backdrop-filter: saturate(180%) blur(12px);
	border-bottom: 1px solid var(--border);
}
.crumbs { display: flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; }
.crumbs a { color: var(--text-2); }
.crumbs .i { opacity: .5; }
.topsearch { margin-left: auto; position: relative; width: 300px; }
.topsearch input { width: 100%; padding: 9px 12px 9px 36px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface); font: inherit; }
.topsearch .i { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--muted); }
.menu-toggle { display: none; background: none; border: 0; padding: 6px; cursor: pointer; color: var(--text); }
.content { padding: 28px 32px 64px; width: 100%; max-width: none; }

.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; }
.page-head h1 { font-size: 26px; font-weight: 700; }
.page-head p { margin: 4px 0 0; color: var(--text-2); }
.actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* ---------- Cards / grid ---------- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.card + .card { margin-top: 20px; }
.grid > .card, .grid > * > .card:first-child { margin-top: 0; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.card-head h2, .card-head h3 { font-size: 15px; font-weight: 650; }
.card-head p { margin: 2px 0 0; color: var(--muted); font-size: 12.5px; }
.card-body { padding: 20px; }
.card-foot { padding: 14px 20px; border-top: 1px solid var(--border); background: var(--surface-2); border-radius: 0 0 var(--radius) var(--radius); display: flex; gap: 8px; justify-content: flex-end; }
.grid { display: grid; gap: 20px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.grid-main { grid-template-columns: minmax(0, 1fr) 360px; align-items: start; }
.stack > * + * { margin-top: 20px; }

.stat { padding: 18px 20px; position: relative; overflow: hidden; }
.stat-label { display: flex; align-items: center; gap: 8px; color: var(--text-2); font-size: 12.5px; font-weight: 550; }
.stat-icon { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; background: var(--accent-50); color: var(--accent); }
.stat-value { font-size: 28px; font-weight: 700; letter-spacing: -0.03em; margin-top: 12px; line-height: 1.1; }
.stat-sub { font-size: 12px; color: var(--muted); margin-top: 4px; }
.stat.green .stat-icon { background: var(--green-50); color: var(--green); }
.stat.amber .stat-icon { background: var(--amber-50); color: var(--amber); }
.stat.violet .stat-icon { background: var(--violet-50); color: var(--violet); }
.stat.blue .stat-icon { background: var(--blue-50); color: var(--blue); }
.stat.red .stat-icon { background: var(--red-50); color: var(--red); }

/* ---------- Buttons ---------- */
.btn {
	display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 9px 14px; border-radius: 10px;
	font: inherit; font-weight: 600; font-size: 13.5px; line-height: 1; cursor: pointer; white-space: nowrap;
	border: 1px solid transparent; transition: background .15s, border-color .15s, box-shadow .15s, color .15s;
}
.btn-primary { background: var(--accent); color: #fff; box-shadow: 0 1px 2px rgba(91,91,246,.3), inset 0 1px 0 rgba(255,255,255,.15); }
.btn-primary:hover { background: var(--accent-600); color: #fff; }
.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); border-color: #c5c9d6; }
.btn-danger { background: var(--surface); color: var(--red); border-color: #f3c9ca; }
.btn-danger:hover { background: var(--red-50); color: var(--red); }
.btn-soft { background: var(--accent-50); color: var(--accent-600); }
.btn-soft:hover { background: var(--accent-100); color: var(--accent-600); }
.btn-sm { padding: 6px 10px; font-size: 12.5px; border-radius: 8px; }
.btn-icon { padding: 7px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.linkbtn { background: none; border: 0; padding: 0; color: var(--accent); font: inherit; cursor: pointer; }
.linkbtn.danger { color: var(--red); }

/* ---------- Forms ---------- */
.field { margin-bottom: 18px; }
.field:last-child { margin-bottom: 0; }
label, .label { display: block; font-weight: 600; font-size: 13px; margin-bottom: 6px; color: var(--text); }
.hint { font-size: 12px; color: var(--muted); margin-top: 5px; }
input[type=text], input[type=email], input[type=tel], input[type=password], input[type=number], input[type=url], input[type=datetime-local], input[type=search], input[type=color], select, textarea {
	width: 100%; padding: 10px 12px; font: inherit; color: var(--text); background: var(--surface);
	border: 1px solid var(--border-strong); border-radius: var(--radius-sm); transition: border-color .15s, box-shadow .15s;
}
/* drop 142: date and time boxes were left as the browser drew them - the same border and padding, no forced width */
input[type=date], input[type=time] { padding: 9px 12px; font: inherit; color: var(--text); background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); max-width: 100%; }
.field > input[type=date], .field > input[type=time] { width: 100%; }
input[type=color] { padding: 4px; height: 42px; cursor: pointer; }
/* The search box in the header has the magnifying glass inside it, so it needs
   the room back that the rule above takes away. This has to come after that
   rule, not before it, or the glass sits on top of the placeholder. */
.topsearch input[type=search] { padding: 9px 12px 9px 36px; }
textarea { min-height: 90px; resize: vertical; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px rgba(91,91,246,.14); }
.row { display: grid; gap: 16px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.row-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* the Diagrams screen's folders down the left (drop 123); stacked on a phone */
.dg-folders-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 16px; align-items: start; }
.dg-folders { position: sticky; top: 12px; }
.dg-folder { display: flex; align-items: center; gap: 8px; padding: 7px 14px; color: var(--text); text-decoration: none; font-size: 14px; border-left: 3px solid transparent; }
.dg-folder span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dg-folder em { font-style: normal; font-size: 12px; color: var(--muted); }
.dg-folder:hover { background: var(--panel); }
.dg-folder.active { background: var(--panel); border-left-color: var(--accent); font-weight: 600; }
.dg-drop-here { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--accent-50, #eef0ff) !important; }
tr.dg-dragging { opacity: .45; }
.dg-tick { display: inline-flex; padding: 4px; cursor: pointer; }
.dg-tick input { width: 16px; height: 16px; margin: 0; }
.dg-subfolder td { background: var(--panel); }
@media (max-width: 860px) {
	.dg-folders-layout { grid-template-columns: 1fr; }
	.dg-folders { position: static; }
}
/* a radio or checkbox with a sentence beside it (drop 120): the control keeps its
   place at the left and the sentence wraps under itself, never under the control */
.choice { display: flex; gap: 10px; align-items: flex-start; margin: 6px 0; cursor: pointer; font-size: 14px; line-height: 1.4; }
.choice input { flex: 0 0 auto; margin: 3px 0 0; width: 16px; height: 16px; }
.choice span { flex: 1 1 auto; }
.inline > input, .inline > select { width: auto; flex: 1; min-width: 140px; }
.check { display: flex; align-items: flex-start; gap: 10px; font-weight: 500; margin: 0; cursor: pointer; }
.check input { margin-top: 3px; accent-color: var(--accent); width: 16px; height: 16px; }
.check + .check { margin-top: 7px; }
.check + .field, .check + .row, .field + .check, .row + .check { margin-top: 14px; }
.checks { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.checkcard { display: flex; gap: 10px; align-items: center; padding: 11px 12px; border: 1px solid var(--border-strong); border-radius: 10px; cursor: pointer; font-weight: 550; margin: 0; }
.checkcard:has(input:checked) { border-color: var(--accent); background: var(--accent-50); }
.checkcard input { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; }
.switch { position: relative; display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-weight: 550; margin: 0; }
.switch input { appearance: none; -webkit-appearance: none; width: 38px; height: 22px; border-radius: 99px; background: #d5d8e2; position: relative; cursor: pointer; transition: background .2s; margin: 0; flex-shrink: 0; }
.switch input::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.2); transition: transform .2s; }
.switch input:checked { background: var(--accent); }
.switch input:checked::after { transform: translateX(16px); }

/* ---------- Segmented choice ---------- */
/* The follow-up panel's "Reach out" row: four radios that should read as one
   control rather than four loose circles. The markup was written using .seg
   and .seg-item and NEITHER EXISTED, so the row rendered as a vertical stack
   of unstyled radio buttons - which is the state it shipped in this morning.
   Found by inverting csscheck's gate so it covers every file rather than five
   filenames from an old release.
   The radio itself is kept visible rather than hidden-and-faked: a hidden
   input styled by its label is a keyboard-focus problem waiting to happen,
   and this console has no other control that does it. */
.seg { display: flex; flex-wrap: wrap; gap: 8px; }
.seg-item {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 7px 12px;
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-sm);
	background: var(--surface);
	cursor: pointer;
	font-size: 13px;
	font-weight: 550;
	color: var(--text-2);
	line-height: 1.2;
}
.seg-item:hover { border-color: var(--accent); color: var(--accent); }
.seg-item input { margin: 0; cursor: pointer; flex-shrink: 0; }
/* :has is what lets the whole chip light up from the radio inside it. Where a
   browser does not support it the chip simply stays plain and the radio still
   shows which one is chosen, so nothing is lost - the selected state is in the
   input either way. */
.seg-item:has(input:checked) {
	border-color: var(--accent);
	background: var(--accent-50);
	color: var(--accent);
}
.seg-item svg { flex-shrink: 0; }

/* Rich text editor (ColdFusion cftextarea richtext / CKEditor) */
.editor-wrap { border-radius: var(--radius-sm); overflow: hidden; }
.editor-wrap .cke { width: 100% !important; border-color: var(--border-strong) !important; border-radius: var(--radius-sm) !important; box-shadow: none !important; }
.editor-wrap .cke_top { background: var(--surface-2) !important; border-bottom-color: var(--border) !important; }
.editor-wrap .cke_bottom { background: var(--surface-2) !important; border-top-color: var(--border) !important; }
.editor-wrap .cke_chrome { border: 1px solid var(--border-strong) !important; }
.merge-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.merge-tags button { font-family: var(--mono); font-size: 11.5px; padding: 4px 8px; background: var(--surface-2); border: 1px dashed var(--border-strong); border-radius: 7px; cursor: pointer; color: var(--text-2); }
.merge-tags button:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-50); }

/* ---------- Tables ---------- */
.table-wrap { overflow-x: auto; }
table.t { width: 100%; border-collapse: collapse; }
table.t th { text-align: left; font-size: 11.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; padding: 11px 16px; background: var(--surface-2); border-bottom: 1px solid var(--border); white-space: nowrap; }
table.t td { padding: 13px 16px; border-bottom: 1px solid var(--border); vertical-align: middle; }
table.t tr:last-child td { border-bottom: 0; }
table.t tbody tr { transition: background .12s; }
table.t tbody tr:hover { background: #fafbff; }
table.t .num { text-align: right; font-variant-numeric: tabular-nums; }

/* A ticket nobody has opened yet, read the way an unread email reads */
table.t tbody tr.row-unseen td { font-weight: 600; }
table.t tbody tr.row-unseen td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
table.t tbody tr.row-unseen .cell-sub { font-weight: 400; }

/* "Wrong ticket?" under an attached email - out of the way until wanted */
details.comms-move > summary { cursor: pointer; list-style: none; display: inline-block; margin-top: 6px; }
details.comms-move > summary::-webkit-details-marker { display: none; }
details.comms-move > summary:hover { color: var(--accent); }
.cell-main { font-weight: 600; color: var(--text); }
.cell-main:hover { color: var(--accent); }
.cell-sub { font-size: 12px; color: var(--muted); }
.person { display: flex; align-items: center; gap: 11px; }
.avatar { width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: 12px; background: var(--accent-50); color: var(--accent-600); flex-shrink: 0; }
.avatar.lg { width: 56px; height: 56px; font-size: 18px; }
.empty { padding: 48px 20px; text-align: center; color: var(--muted); }
.empty .i { color: var(--border-strong); margin-bottom: 10px; }
.empty h3 { color: var(--text); font-size: 15px; margin-bottom: 4px; }

/* ---------- Pills / chips ---------- */
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px 3px 8px; border-radius: 99px; font-size: 12px; font-weight: 600; white-space: nowrap; }
.pill::first-letter { text-transform: uppercase; }
.pill i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill-green { background: var(--green-50); color: var(--green); }
.pill-red { background: var(--red-50); color: var(--red); }
.pill-amber { background: var(--amber-50); color: var(--amber); }
.pill-blue { background: var(--blue-50); color: var(--blue); }
.pill-violet { background: var(--violet-50); color: var(--violet); }
.pill-gray { background: #f0f1f5; color: #5c6479; }
/* drop 149: how long an open ticket has waited - yellow from 3 days, orange from 7, red from 14 (ticketAge) */
.age-chip { display: inline-block; padding: 1px 7px; border-radius: 999px; font-size: 11.5px; font-weight: 600; line-height: 1.5; white-space: nowrap; background: var(--surface-3); color: var(--text-2); }
.age-chip.age-yellow { background: #fff4be; color: #806200; }
.age-chip.age-orange { background: #ffe9d4; color: #b85400; }
.age-chip.age-red { background: #fde8e8; color: #c4282e; }
/* drop 149: a form that saves as each field changes (data-live-form) */
.live-status { font-size: 12px; color: var(--muted); }
/* .btn is display:inline-flex, which beats the hidden attribute */
[data-live-hide][hidden] { display: none !important; }
.live-status.is-ok { color: var(--green); }
.live-status.is-bad { color: var(--red); font-weight: 600; }
.chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 7px; font-size: 12px; font-weight: 550; background: #f1f2f7; color: var(--text-2); border: 1px solid var(--border); white-space: nowrap; margin: 2px 4px 2px 0; }
.chip .dot { width: 7px; height: 7px; border-radius: 50%; }
.chip form { display: inline; margin: 0; }
.chip button { background: none; border: 0; padding: 0; margin-left: 2px; cursor: pointer; color: var(--muted); display: inline-flex; }
.chip button:hover { color: var(--red); }
.chip.tag { background: var(--accent-50); border-color: var(--accent-100); color: var(--accent-600); }

/* ---------- Tabs / filters ---------- */
.tabs { display: flex; gap: 4px; padding: 4px; background: #eceef4; border-radius: 11px; width: fit-content; margin-bottom: 20px; flex-wrap: wrap; }
.tabs a { padding: 7px 14px; border-radius: 8px; color: var(--text-2); font-weight: 600; font-size: 13px; }
.tabs a.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

/* ---------------------------------------------------------------------------
   A NOTE BESIDE A TAB STRIP, NOT INSIDE IT

   Justin, on the Checklists screen: "the tabs are odd, they read
   [All][services][solutions]Wording is also editable on the Collections tab".

   Three screens had put a trailing <span style="margin-left:auto"> inside
   .tabs - Checklists, Events and Shipping & tax - and on all three it did
   nothing, because .tabs is width: fit-content. With no spare width there is
   no free space for auto margins to eat, so the note sat flush against the
   last tab, inside the grey pill, reading as one run-on string.

   .tabs-line is the row: the pill keeps its own width, the note sits outside
   it and takes the slack. The fix is here rather than three times in markup
   because the mistake was a shared one.
--------------------------------------------------------------------------- */
.tabs-line { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 20px; }
.tabs-line > .tabs { margin-bottom: 0; }
.tabs-note { font-size: 13px; color: var(--text-2); }
/* on a phone the note goes under the tabs rather than squeezing them */
@media (max-width: 640px) { .tabs-line { gap: 8px; } .tabs-note { flex-basis: 100%; } }
.filters { display: flex; gap: 10px; flex-wrap: wrap; padding: 14px 16px; border-bottom: 1px solid var(--border); align-items: center; }
.filters input, .filters select { width: auto; min-width: 160px; padding: 8px 11px; }
.filters .grow { flex: 1; min-width: 220px; }
.bulkbar { display: none; gap: 10px; align-items: center; padding: 10px 16px; background: var(--accent-50); border-bottom: 1px solid var(--accent-100); flex-wrap: wrap; }
.bulkbar.show { display: flex; }
.bulkbar select { width: auto; padding: 6px 10px; }

/* ---------- Alerts / flash ---------- */
.flash { display: flex; gap: 10px; align-items: flex-start; padding: 12px 16px; border-radius: 12px; margin-bottom: 20px; font-weight: 550; border: 1px solid; }
.flash-success { background: var(--green-50); color: #0b6e4d; border-color: #bfe8d6; }
.flash-error { background: var(--red-50); color: #b42318; border-color: #f6caca; }
.flash-info { background: var(--blue-50); color: #1d5fb0; border-color: #c7dcf6; }
.flash-warn { background: var(--amber-50); color: #8a5500; border-color: #f1dcae; }
.callout { padding: 14px 16px; border-radius: 12px; background: var(--surface-2); border: 1px dashed var(--border-strong); color: var(--text-2); font-size: 13px; }

/* ---------- Timeline ---------- */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { display: flex; gap: 12px; padding: 0 0 18px; position: relative; }
.timeline li:not(:last-child)::before { content: ""; position: absolute; left: 13px; top: 30px; bottom: 2px; width: 2px; background: var(--border); }
.tl-dot { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: #f0f1f5; color: #6b7389; flex-shrink: 0; }
.tl-dot.opt_in, .tl-dot.resubscribed, .tl-dot.created { background: var(--green-50); color: var(--green); }
.tl-dot.opt_out, .tl-dot.email_failed, .tl-dot.sequence_stopped { background: var(--red-50); color: var(--red); }
.tl-dot.email_sent { background: var(--accent-50); color: var(--accent); }
.tl-dot.email_opened { background: var(--blue-50); color: var(--blue); }
.tl-dot.link_clicked { background: var(--violet-50); color: var(--violet); }
.tl-dot.tag_added, .tl-dot.sequence_enrolled, .tl-dot.sequence_completed { background: var(--amber-50); color: var(--amber); }
.tl-dot.note { background: var(--blue-50); color: var(--blue); }
.tl-dot.task_created { background: var(--amber-50); color: var(--amber); }
.tl-dot.task_completed, .tl-dot.group_added { background: var(--green-50); color: var(--green); }
a.tl-text { text-decoration: none; border-radius: 7px; margin: -3px -7px; padding: 3px 7px; transition: background .12s ease; }
a.tl-text:hover { background: var(--surface-2); }
.tl-row { display: flex; gap: 12px; align-items: flex-start; justify-content: space-between; flex-wrap: nowrap; }
.tl-row > :first-child { min-width: 0; flex: 1; }
.tl-row > :last-child { flex-shrink: 0; }
.tl-dot.action, .tl-dot.ticket_created { background: var(--amber-50); color: var(--amber); }
.file-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 260px; padding: 5px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface-2); color: var(--text-2); font-size: 12px; font-weight: 600; text-decoration: none; }
.file-chip:hover { border-color: var(--accent); color: var(--accent); }
.file-chip span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-chip-size { color: var(--muted); font-weight: 500; flex-shrink: 0; }
.private-flag { display: inline-flex; align-items: center; gap: 4px; color: var(--muted); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
@media (max-width: 560px) { .tl-row { flex-wrap: wrap; } }
.tl-body { min-width: 0; padding-top: 3px; }
.tl-text { font-weight: 550; color: var(--text); word-break: break-word; }
.tl-meta { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* ---------- Misc components ---------- */
.kv { display: grid; grid-template-columns: 120px 1fr; gap: 10px 14px; font-size: 13.5px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; word-break: break-word; }
.bars { display: flex; align-items: flex-end; gap: 6px; height: 150px; padding-top: 10px; }
.bar { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }
.bar span { display: block; width: 100%; max-width: 30px; border-radius: 6px 6px 3px 3px; background: linear-gradient(180deg, #8b8bff, var(--accent)); min-height: 3px; }
.bar small { font-size: 10.5px; color: var(--muted); }
/* The bar chart with both axes (includes/bar_chart.cfm, drop 114): a
   three-cell grid - tick labels down the left, the plot with gridlines,
   the day or hour labels along the bottom. The plot is a fixed height
   so a bar's percentage is a true fraction of the axis top. */
.chart { display: grid; grid-template-columns: auto 1fr; grid-template-rows: 150px auto; column-gap: 8px; row-gap: 6px; padding-top: 10px; }
.chart-y { position: relative; grid-column: 1; grid-row: 1; min-width: 22px; font-size: 10.5px; color: var(--muted); }
.chart-y span { position: absolute; right: 0; transform: translateY(50%); line-height: 1; white-space: nowrap; }
.chart-plot { position: relative; grid-column: 2; grid-row: 1; }
.chart-grid { position: absolute; left: 0; right: 0; height: 0; border-top: 1px dashed #e3e5ee; pointer-events: none; }
.chart-plot .bars { position: relative; height: 100%; padding-top: 0; }
.chart-plot .bar { gap: 0; }
.chart-x { grid-column: 2; grid-row: 2; display: flex; }
.chart-x small { flex: 1; text-align: center; font-size: 10.5px; color: var(--muted); }
.progress { height: 6px; background: #eceef4; border-radius: 99px; overflow: hidden; }
.progress span { display: block; height: 100%; background: var(--accent); border-radius: 99px; }
.step-card { display: flex; gap: 16px; align-items: stretch; }
.step-rail { display: flex; flex-direction: column; align-items: center; width: 40px; flex-shrink: 0; }
.step-num { width: 34px; height: 34px; border-radius: 11px; background: var(--accent); color: #fff; display: grid; place-items: center; font-weight: 700; }
.step-num.off { background: #cfd3de; }
.step-line { flex: 1; width: 2px; background: var(--border); margin-top: 6px; }
.step-delay { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--text-2); background: #f0f1f5; padding: 4px 10px; border-radius: 99px; margin: 0 0 10px; }
.step-body { flex: 1; min-width: 0; padding-bottom: 22px; }
.step-body .card { margin: 0; }
.metric-inline { display: flex; gap: 18px; font-size: 12.5px; color: var(--text-2); flex-wrap: wrap; }
.metric-inline b { color: var(--text); }
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 16px; }
.media-item { border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--surface); display: flex; flex-direction: column; }
.media-thumb { aspect-ratio: 4/3; background: repeating-conic-gradient(#f2f3f7 0% 25%, #fff 0% 50%) 50% / 16px 16px; display: grid; place-items: center; overflow: hidden; }
.media-thumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.media-meta { padding: 10px 12px; font-size: 12px; }
.media-meta .name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.media-actions { display: flex; gap: 6px; padding: 0 12px 12px; }
.dropzone { border: 2px dashed var(--border-strong); border-radius: 14px; padding: 28px; text-align: center; background: var(--surface-2); }
.codebox { background: #0d1024; color: #d6d9f0; border-radius: 12px; padding: 16px; font-family: var(--mono); font-size: 12px; overflow-x: auto; white-space: pre; line-height: 1.6; }
.preview-frame { width: 100%; height: 720px; border: 0; border-radius: 0 0 var(--radius) var(--radius); background: #f3f4f8; display: block; }
.device-toggle { display: flex; gap: 4px; }
.sep { height: 1px; background: var(--border); margin: 18px 0; }

/* ---------- Modal ---------- */
.modal-backdrop { position: fixed; inset: 0; background: rgba(13,16,36,.45); backdrop-filter: blur(3px); display: none; align-items: center; justify-content: center; z-index: 100; padding: 16px; }
.modal-backdrop.show { display: flex; }
.modal { background: var(--surface); border-radius: 16px; box-shadow: var(--shadow-lg); width: 100%; max-width: 860px; max-height: 88vh; display: flex; flex-direction: column; }
.modal .card-body { overflow-y: auto; }

/* ---------- Login ---------- */
.auth { min-height: 100vh; display: grid; grid-template-columns: 1.1fr 1fr; }
.auth-art {
	background: radial-gradient(1200px 600px at 10% 10%, rgba(124,124,255,.35), transparent 60%), radial-gradient(900px 500px at 90% 90%, rgba(195,91,246,.28), transparent 60%), #0d1024;
	color: #fff; padding: 48px; display: flex; flex-direction: column; justify-content: space-between;
}
.auth-art h2 { font-size: 38px; line-height: 1.12; font-weight: 700; letter-spacing: -0.03em; max-width: 460px; }
.auth-art p { color: #aab0c8; max-width: 420px; font-size: 15px; }
.auth-form { display: grid; place-items: center; padding: 32px 16px; }
.auth-card { width: 100%; max-width: 380px; }
.auth-card h1 { font-size: 24px; margin-bottom: 6px; }

@media (max-width: 1100px) {
	.grid-4, .grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.grid-main { grid-template-columns: 1fr; }
	.grid-3 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 860px) {
	.sidebar { transform: translateX(-100%); transition: transform .2s; }
	.sidebar.open { transform: translateX(0); box-shadow: var(--shadow-lg); }
	.main { margin-left: 0; }
	.menu-toggle { display: inline-flex; }
	.topbar { padding: 0 16px; }
	.topsearch { width: auto; flex: 1; }
	.content { padding: 20px 16px 48px; }
	.grid-2, .grid-3, .row, .row-3 { grid-template-columns: 1fr; }
	.auth { grid-template-columns: 1fr; }
	.auth-art { display: none; }
	.crumbs { display: none; }
}
@media (max-width: 520px) {
	.grid-4, .grid-5 { grid-template-columns: 1fr; }
	.page-head h1 { font-size: 22px; }
}

/* ---------------------------------------------------------------------------
   Clickable rows: the whole row opens the record, not just the name.
   Real links, buttons and form controls inside the row still do their own
   thing, and selecting text never navigates.
--------------------------------------------------------------------------- */
tr.row-link { cursor: pointer; }
tr.row-link:hover { background: var(--surface-2); }
tr.row-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
tr.row-link a.cell-main { text-decoration: none; }

/* A row that opens its own detail rather than going somewhere. The cursor says
   "this expands", not "this navigates". */
tr.row-payload { cursor: zoom-in; }
tr.row-payload:hover { background: var(--surface-2); }
tr.row-payload:has(details[open]) { cursor: zoom-out; background: var(--surface-2); }
tr.row-payload summary { cursor: pointer; }

/* A submission on the contact record: the form name and when, and the fields
   they actually typed when you open it. */
.sub-entry { border-bottom: 1px solid var(--border); padding: 10px 0; }
.sub-entry:last-child { border-bottom: 0; }
.sub-entry > summary { cursor: pointer; list-style: none; display: flex;
	flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.sub-entry > summary::-webkit-details-marker { display: none; }
.sub-entry > summary::before { content: "\25B8"; color: var(--muted); margin-right: 4px;
	transition: transform .15s ease; display: inline-block; }
.sub-entry[open] > summary::before { transform: rotate(90deg); }
.sub-entry > summary:hover .cell-main { color: var(--accent); }

/* ---------------------------------------------------------------------------
   Drop zone: drag files in, or click to choose. Handles several at once.
--------------------------------------------------------------------------- */
.dropzone { position: relative; border: 1.5px dashed var(--border-strong); border-radius: 12px; background: var(--surface-2);
  padding: 18px 16px; text-align: center; color: var(--text-2); cursor: pointer; transition: border-color .15s ease, background .15s ease; }
.dropzone:hover { border-color: var(--accent); background: var(--accent-50); }
.dropzone.is-over { border-color: var(--accent); background: var(--accent-50); border-style: solid; }
.dropzone input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.dropzone-label { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 13px; font-weight: 600; }
.dropzone-hint { font-size: 12px; color: var(--muted); margin-top: 3px; }
.dropzone-files { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; text-align: left; }
.dropzone-file { display: flex; align-items: center; gap: 8px; padding: 7px 10px; background: var(--surface); border: 1px solid var(--border);
  border-radius: 9px; font-size: 12px; font-weight: 600; color: var(--text-2); }
.dropzone-file span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dropzone-file .size { color: var(--muted); font-weight: 500; margin-left: auto; flex-shrink: 0; }
.dropzone-file .over { color: var(--red); }

/* A composer modal is taller than a normal one */
.modal.modal-lg { max-width: 680px; }
.modal-scroll { max-height: 62vh; overflow-y: auto; }
/* A lightbox is mostly one tall column - the facts, then the picture as big as
   the room allows - so it gets more of the screen than a form does. 62vh on a
   phone left the picture as a letterbox strip, which defeats the point of it. */
.modal-tall .modal-scroll { max-height: 80vh; max-height: 80dvh; }

/* ---------------------------------------------------------------------------
   Confirmation modal: replaces the browser's confirm() box, which cannot be
   styled and is barely readable on a phone. Driven by data-confirm in app.js.
--------------------------------------------------------------------------- */
.modal.modal-sm { max-width: 420px; }
.confirm-text { color: var(--text-2); font-size: 14px; margin: 0; }

/* ---------------------------------------------------------------------------
   Lists on a phone: a table wide enough for a desktop turns into one card per
   row instead of a sideways scroll. Add class "t-stack" to the table and give
   every cell a data-label, which becomes the little heading beside its value.
--------------------------------------------------------------------------- */
@media (max-width: 640px) {
	table.t.t-stack thead { display: none; }
	table.t.t-stack, table.t.t-stack tbody, table.t.t-stack tr, table.t.t-stack td { display: block; width: 100%; }
	table.t.t-stack tr { border-bottom: 1px solid var(--border); padding: 6px 0; }
	table.t.t-stack tr:last-child { border-bottom: 0; }
	table.t.t-stack td { border-bottom: 0; padding: 5px 16px; text-align: left; }
	table.t.t-stack td.num { text-align: left; }
	table.t.t-stack td[data-label]::before {
		content: attr(data-label); display: block; font-size: 11px; font-weight: 600; letter-spacing: .05em;
		text-transform: uppercase; color: var(--muted); margin-bottom: 2px;
	}
	table.t.t-stack td[data-label="."]::before { content: none; }
	table.t.t-stack td:first-child { padding-top: 12px; }
	table.t.t-stack td:last-child { padding-bottom: 12px; }
	table.t.t-stack .cell-main { font-size: 15px; }
}

/* ---------------------------------------------------------------------------
   Touch: a finger is not a mouse pointer. On anything without hover - iPhone,
   iPad - controls get a 44px target, and a modal uses the full width and the
   real viewport height, so the keyboard cannot push its buttons off screen.
--------------------------------------------------------------------------- */
@media (hover: none) {
	.btn { min-height: 44px; }
	.btn-sm { min-height: 38px; }
	.btn-icon { min-width: 44px; }
	table.t td a.cell-main { display: inline-block; padding: 2px 0; }
	input[type="text"], input[type="email"], input[type="tel"], input[type="password"], input[type="search"],
	input[type="number"], input[type="date"], select, textarea { font-size: 16px; min-height: 44px; }
	textarea { min-height: 88px; }
}
@media (max-width: 640px) {
	.modal-backdrop { padding: 0; align-items: flex-end; }
	.modal { max-width: 100%; max-height: 92dvh; border-radius: 16px 16px 0 0; }
	.modal-scroll { max-height: 60dvh; }
	.modal-tall .modal-scroll { max-height: 82dvh; }
	.modal .card-foot { position: sticky; bottom: 0; background: var(--surface-2); }
	.page-head { flex-wrap: wrap; gap: 12px; }
	.page-head .actions { width: 100%; }
	.page-head .actions .btn { flex: 1; justify-content: center; }
	.card-head { flex-wrap: wrap; gap: 10px; }
	.filters { flex-wrap: wrap; }
}

/* An archived row reads as set aside, not as live data */
tr.is-archived td { opacity: .62; }
tr.is-archived .cell-main { font-style: italic; }

/* A field group that belongs to another channel or provider is hidden, not
   removed - it still posts the value it already had. */
[data-channel-fields][hidden], [data-provider-fields][hidden] { display: none !important; }
[data-ticket-mode-fields][hidden], #messageTicketLinkThread[hidden] { display: none !important; }

/* Reply sits with the message it answers, not in the page header */
.bubble-reply { margin-top: 6px; }
.bubble-row.in .bubble-reply { text-align: left; }
.bubble-reply .btn { opacity: .75; }
.bubble-row:hover .bubble-reply .btn, .bubble-reply .btn:focus-visible { opacity: 1; }
.reply-bar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; border-top: 1px solid var(--border); background: var(--surface-2); }
.reply-bar .small { color: var(--muted); margin: 0; }
@media (max-width: 640px) {
	.reply-bar .btn { width: 100%; justify-content: center; }
}

/* Contact picker: a search that becomes a chosen contact */
.contact-picker { position: relative; }
.contact-picker-chosen { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface-2); }
.contact-picker-chosen[hidden], .contact-picker-input[hidden], .contact-picker-results[hidden] { display: none !important; }
.contact-picker-who { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.contact-picker-who .cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* In the flow, not floating: a floating list is clipped by a modal's scroll box,
   and on a phone there is nowhere for it to float to. */
.contact-picker-results { margin-top: 4px; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 12px; box-shadow: var(--shadow-sm); max-height: 260px; overflow-y: auto; padding: 4px; }
.contact-picker-option { display: flex; flex-direction: column; align-items: flex-start; width: 100%; text-align: left; background: none; border: 0; border-radius: 8px; padding: 8px 10px; cursor: pointer; font: inherit; }
.contact-picker-option:hover, .contact-picker-option:focus { background: var(--accent-50); outline: none; }
.contact-picker-option .cell-sub { font-size: 12px; }
.contact-picker-empty { padding: 10px 12px; color: var(--muted); font-size: 13px; }
@media (hover: none) { .contact-picker-option { min-height: 44px; } }

/* A ticket's communications: theirs plain, ours marked with the accent */
.comms-row { padding: 12px 0; border-bottom: 1px solid var(--border); }
.comms-row:last-child { border-bottom: 0; }
.comms-out { border-left: 3px solid var(--accent); padding-left: 12px; }
.comms-meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: 12.5px; color: var(--muted); }
.comms-meta b { color: var(--text); }
.comms-subject { font-weight: 600; margin: 4px 0 2px; }
.comms-body { white-space: pre-wrap; font-size: 14px; color: var(--text-2); overflow-wrap: anywhere; }

/* A tag that is also a link to everything else carrying it */
a.chip.chip-link { text-decoration: none; }
a.chip.chip-link:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-50); }
.contact-picker-heading { padding: 6px 10px 4px; font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }

/* "Who is this?" - a text from a number that is not on any contact yet */
.assign-banner { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 16px 20px; margin-bottom: 20px; border-left: 4px solid var(--accent, #6d5efc); }
.assign-banner-text { display: flex; flex-direction: column; gap: 4px; flex: 1 1 320px; min-width: 0; }
.assign-banner-actions { display: flex; gap: 8px; flex-wrap: wrap; }
@media (max-width: 640px) {
	.assign-banner-actions { width: 100%; }
	.assign-banner-actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* Tag picker: chips and a search box that browses every tag */
.tag-picker { position: relative; min-width: 0; }
.tag-picker-box { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 42px; padding: 5px 8px; border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface); cursor: text; }
.tag-picker-box:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-50); }
.tag-picker-chips { display: contents; }
.tag-picker-chips .chip { margin: 0; }
.tag-picker-chips .chip button { font-size: 15px; line-height: 1; padding: 0 2px; }
.tag-picker .tag-picker-input { flex: 1 1 120px; min-width: 100px; border: 0 !important; box-shadow: none !important; outline: none; padding: 4px 2px !important; background: transparent; min-height: 0; }
.tag-picker-results { margin-top: 4px; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 12px; box-shadow: var(--shadow-sm); max-height: 260px; overflow-y: auto; padding: 4px; }
.tag-picker-results[hidden] { display: none !important; }
.tag-picker-option { display: flex; flex-direction: column; align-items: flex-start; width: 100%; text-align: left; background: none; border: 0; border-radius: 8px; padding: 8px 10px; cursor: pointer; font: inherit; color: inherit; }
.tag-picker-option:hover, .tag-picker-option:focus { background: var(--accent-50); outline: none; }
.tag-picker-option .cell-sub { font-size: 12px; }
.tag-picker-create { border-top: 1px solid var(--border); border-radius: 0 0 8px 8px; }
.tag-picker-create .cell-main { color: var(--accent-600); }
@media (hover: none) { .tag-picker-option { min-height: 44px; } }
.inline .tag-picker { flex: 1 1 200px; }
@media (hover: none) { .tag-picker-chips .chip button { min-width: 28px; min-height: 28px; } }
.bulkbar .tag-picker { flex: 0 1 300px; }

/* People picker: the composer's To box. Deliberately the same measurements as
   .tag-picker above - it is the same gesture on the same kind of box, and two
   almost-alike boxes on one screen read as a mistake. */
.people-picker { position: relative; min-width: 0; }
.people-picker-box { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 42px; padding: 5px 8px; border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface); cursor: text; }
.people-picker-box:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-50); }
.people-picker-chips { display: contents; }
.people-picker-chips .chip { margin: 0; }
.people-picker-chips .chip button { font-size: 15px; line-height: 1; padding: 0 2px; }
.people-picker .people-picker-input { flex: 1 1 140px; min-width: 120px; border: 0 !important; box-shadow: none !important; outline: none; padding: 4px 2px !important; background: transparent; min-height: 0; }
.people-picker-results { margin-top: 4px; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 12px; box-shadow: var(--shadow-sm); max-height: 260px; overflow-y: auto; padding: 4px; }
.people-picker-results[hidden] { display: none !important; }
.people-picker-option { display: flex; flex-direction: column; align-items: flex-start; width: 100%; text-align: left; background: none; border: 0; border-radius: 8px; padding: 8px 10px; cursor: pointer; font: inherit; color: inherit; }
.people-picker-option:hover, .people-picker-option:focus { background: var(--accent-50); outline: none; }
.people-picker-option .cell-sub { font-size: 12px; }
.people-picker-empty { padding: 8px 10px; color: var(--muted); font-size: 13px; }
.people-picker-add { border-top: 1px solid var(--border); border-radius: 0 0 8px 8px; }
.people-picker-add .cell-main { color: var(--accent-600); }
@media (hover: none) { .people-picker-option { min-height: 44px; } .people-picker-chips .chip button { min-width: 28px; min-height: 28px; } }

/* ---------------------------------------------------------------------------
   Portal dashboard tiles. Deliberately plain: they are signposts, not
   content, and a row of eight loud cards competes with the thing the person
   actually came to do. One line of label, one line of answer.
   --------------------------------------------------------------------------- */
.p3tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
.p3tile { display: flex; flex-direction: column; gap: 4px; padding: 14px 15px; background: var(--surface);
	border: 1px solid var(--border); border-radius: 10px; text-decoration: none; color: inherit;
	transition: border-color .15s ease, transform .15s ease; }
.p3tile:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.p3tile-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.p3tile-top b { font-size: 15px; }
.p3tile-top .pill { margin: 0; }
.p3tile-sub { font-size: 13px; color: var(--muted); }
@media (hover: none) { .p3tile { min-height: 72px; } }

/* Relationship chips: lead, customer, past customer, partner, vendor, team */
.rel-chip .rel-via { color: var(--muted); font-weight: 500; }
.rel-chip.rel-customer { background: #e8f7f1; border-color: #c4ead9; color: #0b7a55; }
.rel-chip.rel-team { background: #e8f1fa; border-color: #c7dcf0; color: #004a85; }
.nav a.nav-sub { padding-left: 34px; font-size: 13px; }
.nav a.nav-sub svg { width: 15px; height: 15px; }

/* ---------------------------------------------------------------------------
   THE SECOND LEVEL OF THE MENU FOLDS AWAY

   Justin: "I'd like to be able to expand and collapse the 'Message Templates'
   level, not just the 'Email' level."

   The chevron is a button BESIDE the parent link rather than inside it - an
   anchor may not contain a button, and more to the point the parent is still
   a link to its own screen. Pressing the words goes to Message Templates;
   pressing the chevron folds the two entries underneath it away.

   It sits over the right-hand end of the row, and the link gets padding so
   its text can never run under it. */
.nav-parent { position: relative; }
.nav-parent > a { padding-right: 30px; }

.nav-subtoggle {
	position: absolute;
	top: 0;
	right: 2px;
	height: 100%;
	width: 26px;
	display: flex;
	align-items: center;
	justify-content: center;
	appearance: none;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
	color: var(--text-2);
	opacity: .55;
	border-radius: 8px;
}
.nav-subtoggle:hover { opacity: 1; background: var(--surface-2); }
.nav-subtoggle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; opacity: 1; }

/* A chevron drawn from borders: this one is built in the browser, where the
   icon() function that draws every other chevron in the console is not
   available. Down when open, right when closed - the same direction the group
   level above it uses. */
.nav-subchev {
	width: 0;
	height: 0;
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 5px solid currentColor;
	transition: transform .12s ease;
}
.nav-parent.is-closed .nav-subchev { transform: rotate(-90deg); }

.nav-kids.is-closed { display: none; }

/* Archive: the strip over an archived list or record */
.archive-notice { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 12px 16px; margin-bottom: 16px; border-radius: 12px; background: #fff7e6; border: 1px solid #f3dfb5; color: #7a5200; font-size: 13px; }
.archive-notice-text { flex: 1 1 240px; min-width: 0; }
.archive-notice svg { flex: none; }
tr.is-archived td { color: var(--muted); }

/* Sidebar groups: a heading that opens and closes its links */
.nav-group { margin-top: 2px; }
.nav .nav-toggle { display: flex; align-items: center; gap: 8px; width: 100%; background: none; border: 0; cursor: pointer; text-align: left; font-family: inherit; border-radius: 8px; }
.nav .nav-toggle:hover { color: #cfd3e3; }
.nav .nav-toggle:focus-visible { outline: 2px solid rgba(124,124,255,.5); outline-offset: -2px; }
.nav .nav-toggle > span:first-child { flex: 1; }
.nav .nav-toggle svg { width: 14px; height: 14px; transition: transform .15s ease; opacity: .7; }
.nav-group.is-open > .nav-toggle svg { transform: rotate(90deg); }
.nav-group > .nav-items { display: none; }
.nav-group.is-open > .nav-items { display: block; }
.nav .nav-group-count { margin-left: 0; font-size: 10px; letter-spacing: 0; text-transform: none; }
.nav-group.is-open .nav-group-count { display: none; }

/* ======================================================================
   Tall modals scroll inside themselves. The form between the heading and
   the buttons has to share the modal's height too, or the body grows past
   the bottom of the window and the Save button can't be reached. The
   heading and the buttons stay put; the fields between them scroll. Any
   modal laid out differently still scrolls as a whole.
   ====================================================================== */
.modal { max-height: calc(100vh - 32px); max-height: calc(100dvh - 32px); overflow-y: auto; overscroll-behavior: contain; }
.modal > form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.modal > .card-head, .modal > form > .card-foot, .modal > .card-foot { flex: none; }
.modal > .card-body, .modal > form > .card-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.modal > form > .card-body.modal-scroll { max-height: none; }
@media (max-width: 640px) {
	.modal { max-height: 92dvh; }
}

/* Contact details: every email, number and address, each with a label */
.methods { padding-top: 6px; }
.methods-kind { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); margin: 12px 0 4px; }
.methods-kind:first-child { margin-top: 0; }
.method-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--border); min-width: 0; }
.method-row:last-of-type { border-bottom: 0; }
.method-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); font-size: 13.5px; }
.method-label { flex: none; border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2); border-radius: 7px; font: inherit; font-size: 11.5px; font-weight: 550; padding: 2px 8px; cursor: pointer; }
.method-label.is-empty { border-style: dashed; color: var(--muted); background: none; }
.method-label:hover { border-color: var(--accent); color: var(--accent); }
.method-actions { display: inline-flex; align-items: center; gap: 2px; flex: none; }
.method-actions form { margin: 0; display: inline; }
.method-actions button { background: none; border: 0; cursor: pointer; color: var(--muted); padding: 2px 4px; font-size: 15px; line-height: 1; display: inline-flex; }
.method-actions button:hover { color: var(--accent); }
.method-actions .method-remove:hover { color: var(--red); }
.method-primary { color: var(--violet, #7c3aed); font-size: 15px; padding: 2px 4px; }
.method-none { padding: 2px 0 4px; }
@media (hover: none) { .method-actions button { min-width: 36px; min-height: 36px; justify-content: center; } }

/* ======================================================================
   Phone fixes
   ====================================================================== */
/* Grid and form columns shrink to the screen instead of growing to their widest content */
.card, .stack > *, .grid > *, .row > *, .field { min-width: 0; }
input, select, textarea { max-width: 100%; }
.card-body { overflow-wrap: anywhere; }
@media (max-width: 1100px) {
	.grid-main { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 860px) {
	.grid-2, .grid-3, .row, .row-3 { grid-template-columns: minmax(0, 1fr); }
	.page-head .actions { flex-wrap: wrap; }
	.filters { flex-wrap: wrap; }
	.filters > * { min-width: 0; }
	.filters select { flex: 1 1 140px; }
	.bulkbar > * { min-width: 0; }
	.card-head { flex-wrap: wrap; }
}

/* The menu on a phone: a close button, and the page dims behind it */
.sidebar-close { display: none; margin-left: auto; background: none; border: 0; color: #cfd3e3; cursor: pointer; padding: 8px; border-radius: 8px; }
.sidebar-close:hover { background: rgba(255,255,255,.08); color: #fff; }
.sidebar-scrim { display: none; }
@media (max-width: 860px) {
	.sidebar-close { display: inline-flex; }
	.sidebar-head { display: flex; align-items: center; }
	.sidebar-scrim { display: block; position: fixed; inset: 0; background: rgba(13,16,36,.45); z-index: 29; opacity: 0; pointer-events: none; transition: opacity .2s; }
	body.sidebar-open .sidebar-scrim { opacity: 1; pointer-events: auto; }
	body.sidebar-open { overflow: hidden; }
	.sidebar { overflow-y: auto; }
}

/* Lists as cards on a phone: tidy up what the desktop table needed */
@media (max-width: 640px) {
	table.t.t-stack td, table.t.t-stack td .nowrap { white-space: normal; }
	table.t.t-stack td:empty { display: none; }
	table.t.t-stack td.right { text-align: left; }
	table.t.t-stack tr.row-link { cursor: pointer; }
	.table-wrap { overflow-x: visible; }
	table.t.t-stack .person { min-width: 0; }
}

/* Sign-in on a phone: the brand goes above the form */
.auth-mobile-brand { display: none; }
@media (max-width: 860px) {
	.auth-form { place-items: start center; padding-top: 40px; }
	.auth-mobile-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 28px; }
	.auth-mobile-brand .brand-mark { width: 40px; height: 40px; }
	.auth-mobile-brand .brand-name { font-weight: 700; font-size: 17px; color: var(--text); }
	.auth-mobile-brand .brand-sub { font-size: 12.5px; color: var(--muted); }
}

/* Back, where the breadcrumbs were, on a phone */
.topbar-back { display: none; align-items: center; gap: 2px; color: var(--text); font-weight: 600; font-size: 14px; padding: 6px 8px 6px 2px; border-radius: 8px; min-width: 0; white-space: nowrap; }
.topbar-back svg { transform: rotate(180deg); flex: none; }
.topbar-back span { overflow: hidden; text-overflow: ellipsis; max-width: 34vw; }
@media (max-width: 860px) {
	.topbar-back { display: inline-flex; }
}

/* Card rows, compact: the name across the top, the rest two to a line */
@media (max-width: 640px) {
	table.t.t-stack tbody tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 14px; row-gap: 2px; padding: 12px 16px; position: relative; }
	table.t.t-stack tbody td { padding: 4px 0 !important; min-width: 0; }
	table.t.t-stack tbody td.stack-main { grid-column: 1 / -1; order: -1; padding-bottom: 6px !important; }
	table.t.t-stack tbody td.stack-main::before { content: none; }
	table.t.t-stack tbody tr:has(td.stack-check) td.stack-main { padding-right: 36px !important; }
	table.t.t-stack tbody td.stack-check { position: absolute; top: 12px; right: 12px; width: auto; padding: 0 !important; }
	table.t.t-stack tbody td.stack-check::before { content: none; }
	table.t.t-stack tbody td[data-label]::before { font-size: 10.5px; margin-bottom: 1px; }
}
.sidebar-head .sidebar-close { align-self: flex-start; margin-top: 4px; }

/* Metric cards that open the list behind the number */
a.card.stat-link { display: block; color: inherit; text-decoration: none; cursor: pointer; transition: border-color .15s, box-shadow .15s, transform .15s; }
a.card.stat-link:hover { border-color: var(--accent-100); box-shadow: var(--shadow-sm); transform: translateY(-1px); }
a.card.stat-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
a.card.stat-link .stat-label::after { content: "\203A"; margin-left: auto; font-size: 18px; line-height: 1; color: var(--muted); opacity: .6; }
a.card.stat-link .stat-label { display: flex; align-items: center; gap: 8px; }
a.card.stat-link.is-active { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-50); }
.filter-notice { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: -6px 0 16px; padding: 10px 14px; border-radius: 10px; background: var(--accent-50); border: 1px solid var(--accent-100); color: var(--accent-600); font-size: 13px; }
.filter-notice a { margin-left: auto; font-weight: 600; }
.sort-select { width: auto; }

/* Columns button on list pages */
details.col-picker { position: relative; display: inline-block; }
details.col-picker > summary { list-style: none; cursor: pointer; }
details.col-picker > summary::-webkit-details-marker { display: none; }
details.col-picker[open] > summary { background: var(--surface-2); }
.col-picker-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 60; width: 240px; max-height: 70vh; overflow-y: auto; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-lg); padding: 12px; text-align: left; }
.col-picker-title { font-size: 12px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px; }
.col-picker-item { display: flex; align-items: center; gap: 8px; padding: 6px 4px; font-size: 14px; font-weight: 500; cursor: pointer; border-radius: 6px; }
.col-picker-item:hover { background: var(--surface-2); }
.col-picker-item input { width: auto; margin: 0; }
.col-picker-note { font-size: 12px; color: var(--muted); margin: 8px 4px 10px; }
.col-picker-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Columns menu, part two: a name box beside each tick, and a default sort */
.col-picker-menu { width: 300px; }
.col-picker-hint { font-size: 12px; color: var(--muted); margin: 0 4px 8px; }
.col-picker-row { display: grid; grid-template-columns: 1fr 108px; align-items: center; gap: 8px; }
.col-picker-row .col-picker-item { min-width: 0; }
.col-picker-row .col-picker-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-picker-name { width: 100%; font-size: 13px; padding: 4px 7px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); }
.col-picker-name::placeholder { color: var(--muted); opacity: .7; }
.col-picker-name:focus { outline: none; border-color: var(--accent); }
.col-picker-sort { width: 100%; font-size: 13px; padding: 5px 7px; margin-bottom: 4px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); }
.col-picker-actions { flex-wrap: wrap; }

/* The grip you drag to resize a column. Desktop only - the script adds it. */
table.t th { position: relative; }
.col-grip { position: absolute; top: 0; right: 0; width: 9px; height: 100%; cursor: col-resize; user-select: none; touch-action: none; }
.col-grip::after { content: ""; position: absolute; top: 20%; bottom: 20%; right: 4px; width: 1px; background: var(--border); opacity: 0; transition: opacity .12s ease; }
table.t th:hover .col-grip::after, .col-resizing .col-grip::after { opacity: 1; }
.col-grip:hover::after { background: var(--accent); opacity: 1; width: 2px; }
/* while dragging, nothing else on the page should highlight or select */
body.col-resizing { cursor: col-resize; user-select: none; }
body.col-resizing a, body.col-resizing .col-grip { pointer-events: none; }

/*
	A table nobody has resized is left exactly as it was - automatic layout,
	sized to its content. The moment one is resized it switches to fixed
	layout, because under the automatic algorithm a width on a cell is only a
	suggestion and the browser had been quietly overruling every drag.
*/
table.t.cols-sized { table-layout: fixed; }
table.t.cols-sized th { overflow: hidden; text-overflow: ellipsis; }
table.t.cols-sized td { overflow: hidden; }
table.t.cols-sized td .cell-main,
table.t.cols-sized td .cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }

/* Source cell: the website as a chip, the form beside it, one line */
.src-cell { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; }
.src-site { flex: none; font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); color: var(--text); white-space: nowrap; }
.src-form { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 13px; }

@media (max-width: 640px) {
	.col-picker-menu { position: fixed; left: 16px; right: 16px; top: auto; bottom: 16px; width: auto; }
}

/* Clickable column headings.

   THE WHOLE CELL IS THE TARGET, not just the letters.

   This link used to be inline-flex, so it was exactly as wide as its own
   text while the cell around it kept 11px of padding on top and bottom and
   16px each side. Clicking a heading therefore worked or did nothing
   depending on whether you hit the word or the space beside it - which reads
   as "sorting is broken on this screen", and did.

   So the anchor now spreads out over that padding with negative margins:
   identical appearance, and a click anywhere in the heading counts.

   The resize grip still works - it is absolutely positioned, so it paints
   above this and wins the click on its own nine pixels.

   The faint arrow is always there for the same reason: a column that can be
   sorted should say so before you go looking. */
/* Negative margins rather than th:has() on purpose: :has() is only in
   recent browsers, and where it is missing the heading would keep its own
   padding AND gain the link's, so every table would grow a taller header
   row. This works the same everywhere and degrades to nothing. */
table.t th a.th-sort { color: inherit; text-decoration: none; display: flex; align-items: center; gap: 4px; white-space: nowrap; margin: -11px -16px; padding: 11px 16px; }
table.t th a.th-sort:hover { color: var(--accent); }
table.t th a.th-sort .th-arrow { font-size: 11px; min-width: 8px; }
table.t th a.th-sort.is-sorted { color: var(--text); }
table.t th a.th-sort.is-sorted .th-arrow { color: var(--accent); }
/* not sorted: a dim double arrow, brighter on hover, so it is visibly clickable */
table.t th a.th-sort:not(.is-sorted) .th-arrow::after { content: "\2195"; opacity: .28; }
table.t th a.th-sort:not(.is-sorted):hover .th-arrow::after { opacity: .75; }
/* a heading in a right-aligned column keeps its label against the edge */
table.t th.right a.th-sort { justify-content: flex-end; }

/* "From this device" buttons beside the composer */
.device-send { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 14px; }
.device-send-label { font-size: 12px; font-weight: 600; color: var(--muted); display: inline-flex; align-items: center; gap: 5px; }
.modal .device-send { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--border); }

/* Page browser under lists */
.pager { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; width: 100%; }
.pager-btns { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.pager-link { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; height: 34px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text-2); font-size: 13px; font-weight: 600; text-decoration: none; }
a.pager-link:hover { border-color: var(--accent); color: var(--accent); }
.pager-link.is-current { background: var(--accent); border-color: var(--accent); color: #fff; }
.pager-link.is-off { opacity: .4; cursor: default; }
.pager-gap { padding: 0 4px; color: var(--muted); }
.pager-jump { width: auto; height: 34px; padding: 0 8px; border-radius: 8px; font-size: 13px; margin-left: 4px; }
@media (max-width: 640px) {
	.pager { justify-content: center; }
	.pager-num { display: none; }
	.pager-link.is-current { display: inline-flex; }
}

/* ---------------- Projects: timeline (Gantt) ---------------- */
.gantt { min-width: 720px; font-size: 13px; position: relative; }
.g-head, .g-row { display: flex; align-items: stretch; }
.g-label { width: 260px; flex-shrink: 0; padding: 6px 10px 6px 0; display: flex; align-items: center; gap: 6px; min-width: 0; }
.g-head .g-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.g-num { color: var(--muted); font-size: 11px; width: 20px; flex-shrink: 0; text-align: right; }
.g-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.g-who { color: var(--muted); font-size: 11px; white-space: nowrap; max-width: 90px; overflow: hidden; text-overflow: ellipsis; }
.g-track { position: relative; flex: 1; min-height: 32px; border-left: 1px solid var(--border); }
.g-row { border-top: 1px solid var(--border); }
.g-row:hover { background: var(--surface-2); }
.g-scale { height: 40px; }
.g-month { position: absolute; top: 2px; font-size: 11px; font-weight: 700; color: var(--text); white-space: nowrap; padding-left: 3px; border-left: 1px solid var(--border); }
.g-day { position: absolute; top: 22px; font-size: 10px; color: var(--muted); padding-left: 2px; }
.g-week { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--border); opacity: .6; }
.g-today { position: absolute; top: 0; bottom: 0; width: 2px; background: #2563eb; opacity: .7; z-index: 2; }
.g-deadline { position: absolute; top: 0; bottom: 0; width: 2px; background: #dc2626; z-index: 2; }
.g-bar { position: absolute; top: 8px; height: 16px; border-radius: 6px; background: #c7c9fb; overflow: hidden; z-index: 1; min-width: 4px; }
.g-bar .g-fill { display: block; height: 100%; background: var(--accent); }
.g-bar.is-critical { background: #fca5a5; }
.g-bar.is-critical .g-fill { background: #dc2626; }
.g-bar.is-done { background: #86efac; }
.g-bar.is-done .g-fill { background: #16a34a; }
.g-bar.is-late { box-shadow: 0 0 0 2px #dc2626; }
.g-milestone { position: absolute; top: 9px; width: 14px; height: 14px; background: var(--text); transform: rotate(45deg); border-radius: 2px; z-index: 1; }
.g-milestone.is-critical { background: #dc2626; }
.g-legend { display: flex; flex-wrap: wrap; gap: 16px; padding: 12px 0 0; font-size: 12px; color: var(--muted); border-top: 1px solid var(--border); }
.g-legend span { display: inline-flex; align-items: center; gap: 6px; }
.g-key { display: inline-block; width: 22px; height: 10px; border-radius: 4px; background: var(--accent); }
.g-key.is-critical { background: #dc2626; }
.g-key.is-done { background: #16a34a; }
.g-key-ms { display: inline-block; width: 10px; height: 10px; background: var(--text); transform: rotate(45deg); }
.g-key-line { display: inline-block; width: 2px; height: 14px; }
.g-key-line.today { background: #2563eb; }
.g-key-line.deadline { background: #dc2626; }
/* drop 151: the lines from a task to the ones waiting for it (drawn by app.js), and a bar that opens its task */
.g-links { position: absolute; left: 0; top: 0; z-index: 0; pointer-events: none; overflow: visible; }
.g-links path { fill: none; stroke: #94a3b8; stroke-width: 1.5; }
.g-links polygon { fill: #94a3b8; }
.g-links .is-critical path { stroke: #dc2626; }
.g-links .is-critical polygon { fill: #dc2626; }
.g-links .is-lit path { stroke: var(--accent); stroke-width: 2.5; }
.g-links .is-lit polygon { fill: var(--accent); }
.g-key-link { display: inline-block; width: 22px; height: 10px; border-left: 2px solid #94a3b8; border-bottom: 2px solid #94a3b8; border-radius: 0 0 0 3px; }
.gantt [data-modal] { cursor: pointer; }
.gantt .g-title[data-modal]:hover { color: var(--accent); text-decoration: underline; }
.gantt .g-bar[data-modal]:hover, .gantt .g-milestone[data-modal]:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (max-width: 640px) { .g-label { width: 170px; } .g-who { display: none; } }

/* the "waits for" checklist in the task window */
.pred-list { max-height: 220px; overflow-y: auto; border: 1px solid var(--border); border-radius: 10px; padding: 6px 10px; background: var(--surface-2); }
.pred-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.pred-row:last-child { border-bottom: 0; }

/* ---------------- Client portal ---------------- */
.portal-body { background: var(--bg, #f5f6fa); min-height: 100vh; display: flex; flex-direction: column; }
.portal-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 24px; background: var(--surface); border-bottom: 1px solid var(--border); }
.portal-brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--text); }
.portal-brand b { display: block; font-size: 15px; }
.portal-brand small { display: block; font-size: 12px; color: var(--muted); }
.portal-nav { display: flex; gap: 16px; font-size: 14px; font-weight: 600; }
.portal-nav a { color: var(--text-2); text-decoration: none; }
.portal-nav a:hover { color: var(--accent); }

/* ---------------------------------------------------------------------------
   THEIR OWN MENU IN THE PORTAL HEADER

   Justin: "the user should also have a profile with a dropdown for editing
   their profile/settings/password or logging out."

   A <details> rather than a scripted menu. It opens on a click with no
   JavaScript at all, which matters more here than anywhere else in the
   console: the thing behind it is the way OUT, and a menu that traps somebody
   signed in on an old phone is worse than no menu. app.js only adds the
   close-on-click-outside nicety on top.

   Sign out is tinted and separated, because it was previously the last item
   in the row of tabs - one along from Support - and a misclick there ends the
   session.
--------------------------------------------------------------------------- */
.portal-me { position: relative; flex-shrink: 0; }
.portal-me > summary {
	display: flex; align-items: center; gap: 8px;
	padding: 5px 9px 5px 5px; border-radius: 999px; cursor: pointer;
	border: 1px solid var(--border); background: var(--surface);
	font-size: 14px; font-weight: 600; color: var(--text-2);
	list-style: none;
}
.portal-me > summary::-webkit-details-marker { display: none; }
.portal-me > summary::marker { content: ""; }
.portal-me > summary:hover { border-color: #c5c9d6; color: var(--text); }
.portal-me[open] > summary { border-color: var(--accent); color: var(--text); }
.portal-me-face {
	width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
	display: inline-flex; align-items: center; justify-content: center;
	background: var(--accent-50); color: var(--accent-600);
	font-size: 12px; font-weight: 700;
}
/* the name is the first thing to go on a narrow screen; the circle stays,
   because the circle is what says "this is you" */
.portal-me-name { max-width: 16ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.portal-me-menu {
	position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
	min-width: 208px; padding: 6px;
	background: var(--surface); border: 1px solid var(--border);
	border-radius: var(--radius); box-shadow: 0 10px 30px rgba(15, 23, 42, .14);
	display: flex; flex-direction: column;
}
.portal-me-menu a {
	padding: 8px 10px; border-radius: 7px;
	font-size: 14px; font-weight: 600; color: var(--text-2); text-decoration: none;
	white-space: nowrap;
}
.portal-me-menu a:hover { background: var(--surface-2); color: var(--text); }
.portal-me-out { margin-top: 4px; border-top: 1px solid var(--border); padding-top: 10px !important; color: var(--red) !important; }
.portal-me-out:hover { background: var(--red-50) !important; color: var(--red) !important; }
@media (max-width: 640px) { .portal-me-name { display: none; } }
.portal-main { width: 100%; max-width: 1040px; margin: 0 auto; padding: 24px 16px 48px; flex: 1; }
.portal-h1 { font-size: 26px; font-weight: 700; margin: 0 0 18px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.portal-auth { max-width: 420px; margin: 40px auto; }
.portal-auth h1 { font-size: 24px; margin: 0 0 6px; }
.portal-foot { text-align: center; font-size: 12px; color: var(--muted); padding: 18px; }
.portal-step, .portal-project { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); text-decoration: none; color: var(--text); }
.portal-step:last-child, .portal-project:last-child { border-bottom: 0; }
.portal-step .cell-sub, .portal-project .cell-sub { display: block; }
.portal-step-num { width: 28px; height: 28px; border-radius: 50%; background: var(--accent-50); color: var(--accent-600); font-weight: 700; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.portal-step.is-done .portal-step-num { background: #dcfce7; color: #16a34a; }
.portal-step-dot { width: 10px; height: 10px; border-radius: 50%; background: #f59e0b; flex-shrink: 0; }
.portal-step-dot.is-task { background: var(--accent); }
.portal-task { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.portal-task:last-child { border-bottom: 0; }
.portal-task .cell-sub { display: block; }
@media (max-width: 640px) { .portal-top { padding: 12px 16px; } .portal-task, .portal-project { flex-wrap: wrap; } }

/* ---------------- Client onboarding checklist (portal) - phone first ---------------- */
.onb-hero { display: flex; align-items: center; gap: 18px; margin: 4px 0 16px; }
.onb-hero h1 { font-size: 26px; margin: 0 0 4px; line-height: 1.2; }
.onb-hero p { margin: 0; color: var(--text-2); font-size: 15px; }
.onb-ring { --pct: 0; width: 92px; height: 92px; flex-shrink: 0; border-radius: 50%; display: grid; place-items: center;
	background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--border) 0); }
.onb-ring > span { width: 74%; height: 74%; border-radius: 50%; background: var(--surface); display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.1; }
.onb-ring b { font-size: 20px; }
.onb-ring small { font-size: 11px; color: var(--muted); }
.onb-ring-sm { width: 54px; height: 54px; }
.onb-ring-sm b { font-size: 13px; }
.onb-helper { display: flex; align-items: center; gap: 12px; padding: 14px 16px; margin-bottom: 16px; }
.onb-avatar { width: 44px; height: 44px; border-radius: 50%; background: var(--accent-50); color: var(--accent-600); font-weight: 800; font-size: 18px; display: grid; place-items: center; flex-shrink: 0; }
.onb-helper-text { flex: 1; min-width: 0; }
.onb-helper-text b { display: block; }
.onb-helper-text span { display: block; font-size: 13px; color: var(--muted); }
.onb-steps { list-style: none; margin: 0 0 18px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.onb-step { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; overflow: hidden; scroll-margin-top: 16px; }
.onb-step summary { list-style: none; display: flex; align-items: center; gap: 12px; padding: 16px; cursor: pointer; min-height: 64px; }
.onb-step summary::-webkit-details-marker { display: none; }
.onb-num { width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center; font-weight: 800; background: var(--accent-50); color: var(--accent-600); }
.onb-step.is-done .onb-num { background: #dcfce7; color: #16a34a; }
.onb-step.is-sent .onb-num { background: #fef3c7; color: #b45309; }
.onb-title { flex: 1; min-width: 0; }
.onb-title b { display: block; font-size: 15.5px; line-height: 1.3; }
.onb-step.is-done .onb-title b { color: var(--muted); }
.onb-title small { display: block; font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.onb-chev { color: var(--muted); transition: transform .15s ease; flex-shrink: 0; }
.onb-step details[open] .onb-chev { transform: rotate(180deg); }
.onb-body { padding: 0 16px 18px 62px; display: flex; flex-direction: column; gap: 12px; }
.onb-instructions { margin: 0; font-size: 15px; line-height: 1.55; color: var(--text-2); white-space: pre-wrap; }
.onb-note { margin: 0; font-size: 14px; color: var(--text-2); display: flex; gap: 8px; align-items: flex-start; }
.onb-small { margin: 0; font-size: 12.5px; color: var(--muted); }
.onb-btn { min-height: 46px; justify-content: center; font-size: 15px; width: 100%; }
.onb-form { display: flex; flex-direction: column; gap: 10px; margin: 0; }
.onb-form textarea { width: 100%; font-size: 16px; }
.onb-invite { background: var(--bg, #f5f6fa); border: 1px dashed var(--border-strong, #cfd3de); border-radius: 12px; padding: 10px 12px; }
.onb-invite small { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.onb-invite-row { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.onb-invite code { font-size: 15px; font-weight: 700; word-break: break-all; background: none; padding: 0; }
.onb-file { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 64px; border: 2px dashed var(--border-strong, #cfd3de); border-radius: 12px; cursor: pointer; font-weight: 600; color: var(--text-2); position: relative; padding: 10px; text-align: center; }
.onb-file input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; }
.onb-support .onb-channel { display: block; padding: 12px 0; border-bottom: 1px solid var(--border); text-decoration: none; color: var(--text); }
.onb-support .onb-channel:last-of-type { border-bottom: 0; }
.onb-channel b { display: block; font-size: 14.5px; }
.onb-channel span { display: block; font-size: 13.5px; color: var(--accent-600); word-break: break-word; }
.onb-banner { display: flex; align-items: center; gap: 14px; padding: 14px 16px; margin-bottom: 20px; text-decoration: none; color: var(--text); border: 1px solid var(--accent-50); }
.onb-banner-text { flex: 1; min-width: 0; }
.onb-banner-text b { display: block; }
.onb-banner-text small { display: block; color: var(--muted); font-size: 13px; }
@media (min-width: 720px) {
	.onb-btn { width: auto; align-self: flex-start; padding-left: 22px; padding-right: 22px; }
	.onb-steps { gap: 12px; }
}
@media (max-width: 420px) {
	.portal-brand > span:last-child { display: none; }
}
@media (max-width: 640px) {
	.portal-main { padding: 16px 12px 40px; }
	.onb-hero { gap: 14px; }
	.onb-hero h1 { font-size: 22px; }
	.onb-ring { width: 76px; height: 76px; }
	.onb-body { padding: 0 14px 16px 14px; }
	.onb-helper { flex-wrap: wrap; }
	.onb-helper .onb-btn { width: 100%; }
	.portal-nav { gap: 12px; font-size: 13px; }
	.portal-nav a { white-space: nowrap; }
	.portal-brand b { white-space: nowrap; }
	.portal-brand small { display: none; }
	.onb-ring b { font-size: 17px; }
}

/* ---------------------------------------------------------------------------
   The picker: a category, an item, an Add button, and what has been picked
   listed underneath with an X on each row. Used where a long list of
   checkboxes would otherwise take over the page (Website > Social proof).
   --------------------------------------------------------------------------- */
.picker-pick { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.picker-pick select { flex: 1 1 160px; min-width: 0; }
.picker-pick .btn { flex: 0 0 auto; }
.picker-chosen { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.picker-row {
	display: flex; align-items: center; gap: 10px;
	background: var(--surface-2); border: 1px solid var(--border);
	border-radius: 9px; padding: 7px 8px 7px 12px; font-size: 14px;
}
.picker-row > span { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.picker-row .btn { flex: 0 0 auto; }
.picker-empty { margin: 2px 0 0; }
@media (max-width: 560px) {
	.picker-pick select { flex: 1 1 100%; }
	.picker-pick .btn { width: 100%; justify-content: center; }
}

/* ---------------------------------------------------------------------------
   The dashboard grid: four columns, each card taking one to four of them.
   A card's width is a class (span-1 .. span-4) so the page arrives already
   laid out, and app.js only changes the class when you press + or −.
   --------------------------------------------------------------------------- */
.dash { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; align-items: start; }
/* A three-column board. The Today page uses it: each card there is a short list
   rather than a single number, and four across makes every line wrap. The two
   narrower breakpoints below already collapse this to 2 and then 1. */
.dash.dash-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.dash-w.span-5 { grid-column: span 5; }
.dash-w.span-6 { grid-column: span 6; }
.dash-w { position: relative; min-width: 0; grid-column: span 1; }
.dash-w.span-1 { grid-column: span 1; }
.dash-w.span-2 { grid-column: span 2; }
.dash-w.span-3 { grid-column: span 3; }
.dash-w.span-4 { grid-column: span 4; }
.dash-w > .card { margin: 0; height: 100%; }

/* the handle and the width buttons: out of the way until the card is used */
.dash-tools {
	/* straddling the top edge, so it never lands on a View all button or a
	   heading inside the card */
	position: absolute; top: -13px; right: 10px; z-index: 3;
	display: flex; gap: 2px; padding: 2px;
	background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
	box-shadow: 0 2px 8px rgba(15, 23, 42, .10);
	opacity: 0; transition: opacity .15s;
}
.dash-w:hover .dash-tools, .dash-w:focus-within .dash-tools { opacity: 1; }
.dash-btn {
	border: 0; background: none; color: var(--muted); cursor: pointer;
	width: 24px; height: 24px; border-radius: 6px; padding: 0;
	font-size: 15px; line-height: 1; font-family: inherit;
	display: inline-flex; align-items: center; justify-content: center;
}
.dash-btn:hover { background: var(--surface-2); color: var(--text); }
.dash-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; opacity: 1; }
.dash-grip { cursor: grab; }
.dash-grip:active { cursor: grabbing; }

.dash-w.is-dragging { opacity: .45; }
.dash-w.is-dragging > .card { outline: 2px dashed var(--accent); outline-offset: 2px; }
body.dash-dragging { user-select: none; -webkit-user-select: none; }
body.dash-dragging .dash-tools { opacity: 1; }

/* narrower screens: the four columns become two, then one, and a card that
   was set wider than the grid simply fills it */
@media (max-width: 1100px) {
	.dash, .dash.dash-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.dash-w.span-3, .dash-w.span-4, .dash-w.span-5, .dash-w.span-6 { grid-column: span 2; }
}
@media (max-width: 700px) {
	.dash, .dash.dash-3 { grid-template-columns: minmax(0, 1fr); gap: 22px; }
	.dash-w, .dash-w.span-1, .dash-w.span-2, .dash-w.span-3, .dash-w.span-4, .dash-w.span-5, .dash-w.span-6 { grid-column: span 1; }
}
/* Rearranging is a desktop job, here as everywhere else. Below this the grid
   is one or two columns, where there is little to arrange and a drag is more
   likely to be a scroll that went wrong - so the tools are simply not there.
   Whatever was arranged on a desktop is still saved and comes back on one. */
@media (max-width: 1023px) {
	.dash-tools { display: none; }
}

/* ---------------------------------------------------------------------------
   The lesson list on a course

   One row per lesson, grouped into sections. The row is a link to the
   lesson's own page; only the grip starts a drag, so a stray swipe while
   reading never reorders a course.

   .is-dropping is put on the section a row is hovering over, so it is always
   obvious which one it would land in.
   --------------------------------------------------------------------------- */
.lesson-board { padding: 0; }
.lesson-group + .lesson-group { border-top: 1px solid var(--border); }
.lesson-group.is-dropping { background: var(--surface-2); }

.lesson-group-head {
	display: flex; align-items: center; gap: 10px;
	padding: 10px 16px; background: var(--surface-2);
	border-bottom: 1px solid var(--border);
}
.lesson-group-head.lesson-group-plain { background: transparent; }
.lesson-group-title { flex: 1; min-width: 0; line-height: 1.3; }
.lesson-group-title .chip { margin-left: 6px; }

.lesson-drop { min-height: 10px; }
.lesson-empty {
	margin: 10px 16px; padding: 14px; text-align: center;
	color: var(--text-muted); font-size: 13px;
	border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
}

.lesson-row {
	display: flex; align-items: center; gap: 10px;
	padding: 9px 12px 9px 8px;
	border-bottom: 1px solid var(--border);
	background: var(--surface);
}
.lesson-row:last-child { border-bottom: 0; }
.lesson-row:hover { background: var(--surface-2); }
.lesson-row.is-off { opacity: .55; }
.lesson-row.is-dragging {
	opacity: .9; border-radius: var(--radius-sm);
	box-shadow: 0 10px 24px rgba(0,0,0,.18); border-bottom-color: transparent;
}

.lesson-grip {
	flex: none; display: inline-flex; align-items: center; justify-content: center;
	width: 26px; height: 30px; padding: 0;
	background: none; border: 0; border-radius: var(--radius-sm);
	color: var(--text-muted); cursor: grab; touch-action: none;
}
.lesson-grip:hover { background: var(--surface-3); color: var(--text); }
.lesson-grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lesson-grip.is-idle { cursor: default; opacity: .35; }
body.lesson-dragging { cursor: grabbing; user-select: none; }
body.lesson-dragging .lesson-grip { cursor: grabbing; }

.lesson-main {
	flex: 1; min-width: 0; display: block;
	color: inherit; text-decoration: none; line-height: 1.35;
}
.lesson-main:hover .lesson-title { text-decoration: underline; }
.lesson-title { display: block; font-weight: 500; }
.lesson-main .cell-sub { display: block; }
.lesson-meta { flex: none; display: flex; align-items: center; gap: 8px; }

@media (max-width: 680px) {
	.lesson-row { flex-wrap: wrap; }
	.lesson-main { flex-basis: 100%; order: 2; padding-left: 34px; }
	.lesson-meta { order: 3; padding-left: 34px; }
}

/* ---------------------------------------------------------------------------
   Rearranging a card row on a module page

   Desktop only. Below 1024px none of this exists: no grips, no widths, and
   the row is in the order the page was written in. That is on purpose - a
   row on a phone is one column, where there is nothing to arrange, and a
   drag there is usually a scroll that went wrong.

   The saved order arrives as CSS in the page, so nothing jumps after paint.
   --------------------------------------------------------------------------- */
.panel-tools { display: none; }

@media (min-width: 1024px) {
	[data-panel] > .panel-w { position: relative; min-width: 0; grid-column: span 1; }
	.panel-w > .card { margin: 0; height: 100%; }

	.panel-tools {
		position: absolute; top: -11px; right: 8px; z-index: 3;
		display: flex; gap: 2px; padding: 2px;
		background: var(--surface); border: 1px solid var(--border);
		border-radius: 999px; box-shadow: var(--shadow-sm);
		opacity: 0; transition: opacity .12s ease;
	}
	.panel-w:hover .panel-tools,
	.panel-w:focus-within .panel-tools { opacity: 1; }
	body.panel-dragging .panel-tools { opacity: 1; }

	.panel-btn {
		display: inline-flex; align-items: center; justify-content: center;
		width: 20px; height: 20px; padding: 0; font-size: 13px; line-height: 1;
		background: none; border: 0; border-radius: 999px;
		color: var(--text-muted); cursor: pointer;
	}
	.panel-btn:hover { background: var(--surface-3); color: var(--text); }
	.panel-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
	.panel-grip { cursor: grab; touch-action: none; }

	body.panel-dragging { cursor: grabbing; user-select: none; }
	body.panel-dragging .panel-grip { cursor: grabbing; }
	.panel-w.is-dragging { opacity: .45; }
	.panel-w.is-dragging > .card { outline: 2px dashed var(--accent); outline-offset: 2px; }
}

/* A chip used as a filter: clickable, and obvious when it is the one on. */
a.chip { text-decoration: none; cursor: pointer; }
a.chip:hover { background: var(--surface-3); border-color: var(--border-strong); }
a.chip.is-active {
	background: var(--accent); border-color: var(--accent); color: #fff;
}
a.chip.is-active .muted, a.chip.is-active svg { color: rgba(255,255,255,.75); }

/* A submission's whole payload, folded away until you want it. A scenario
   review posts about thirty-five figures: a truncated line of them tells you
   nothing, and a wall of them on every row tells you less. */
.payload-peek > summary {
	cursor: pointer; max-width: 420px;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.payload-peek > summary::marker { color: var(--text-muted); }
.payload-peek[open] > summary { white-space: normal; margin-bottom: 8px; color: var(--text); }
.payload-table { margin: 0; font-size: 12px; }
.payload-table th {
	text-align: left; font-weight: 500; color: var(--text-muted);
	white-space: nowrap; padding: 3px 12px 3px 0; vertical-align: top;
}
.payload-table td { padding: 3px 0; word-break: break-word; }

/* ---------------------------------------------------------------------
   A SECTION AS A CLOSED DRAWER.

   The page editor drew every field of every section at once, which on a
   funnel page is two hundred lines of form to scroll past to reach the
   one heading you came to change. Collapsed, the page is a list of
   sections again.

   <details> rather than a script, so it still opens and closes with
   JavaScript off, and the browser handles the keyboard for us.
   --------------------------------------------------------------------- */
.p3-section-body > summary { list-style: none; }
.p3-section-body > summary::-webkit-details-marker { display: none; }
.p3-section-body > summary::marker { content: ""; }
.p3-section-body > summary:hover { text-decoration: underline; }
.p3-section-body > summary::after { content: " \25BE"; }
.p3-section-body[open] > summary::after { content: " \25B4"; }

/* the drag grip: grabbing, not grabbed, while the mouse is down */
[data-sort-handle]:active { cursor: grabbing; }
[data-sort-id][draggable="true"], tr[data-sort-id][draggable="true"] > td { background: var(--accent-50); }

/* ---------------------------------------------------------------------
   A CARD THAT SHOWS THE FIRST FEW.

   Rows past the limit are drawn and hidden, not left out, so the button
   reveals them in place with no second request. See listCardLimit() in
   functions_core.cfm - how many is a setting, and zero means all.

   PRINTING SHOWS EVERYTHING. A printed page has no button to press, so
   a clipped list on paper would silently lose rows - which is the kind
   of wrong that only turns up in somebody's meeting.
   --------------------------------------------------------------------- */
/* THE HIDE RULE LIVES INSIDE @media screen AND USES :not(.clip-open).

   It used to be a pair - hide with display:none, then show again with
   display:block when the card is opened - and that pair had two faults that
   only showed up together.

   display:block on reopening CLOBBERS A FLEX ROW. Any clipped row that lays
   its own contents out sideways came back from "show more" stacked.

   And a rule that sets display can always be beaten by an inline style, which
   is exactly what the Follow-ups and tasks card on Today had: display:flex
   written on the row itself. An inline style beats any stylesheet, so those
   rows never hid at all - the card showed every task it had, with a Show more
   button underneath offering to reveal the rows that were already there.

   Written this way there is no second rule to clobber anything: opening the
   card stops the hide rule matching, and each row goes back to whatever
   display it actually wanted. And print simply never sees the rule, which is
   tidier than undoing it. The inline styles are gone too - see the sweep -
   because :not() raises the specificity but still loses to an attribute. */
@media screen {
	.clip:not(.clip-open) .clip-hide { display: none; }
}
.clip-more { margin-top: 10px; width: 100%; justify-content: center; }
@media print {
	.clip-more { display: none; }
}

/* a clipped row that lays its contents out sideways. As a CLASS, never an
   inline style, so the hide rule above can still win. */
.clip-row-flex { display: flex; align-items: flex-start; gap: 8px; }

/* ---------------------------------------------------------------------
   A WHOLE ROW THAT OPENS THE THING - the non-table shape, for a line
   inside a card. tr.row-link is the table shape and is above; both run
   through the one set of handlers in app.js.

   The link inside the row is still the real link; this only widens the
   target to the rest of the line, which on Today is most of the card.
   Keyboard and screen readers follow that anchor, so the row itself is
   not made focusable - that would announce every line twice.
   --------------------------------------------------------------------- */
[data-rowlink] { cursor: pointer; border-radius: 6px; }
[data-rowlink]:hover { background: var(--surface-2); }

/* ---------------------------------------------------------------------
   TODAY AS TWO WEEKS.

   Seven columns, two rows. A fixed column count rather than auto-fit:
   a calendar whose columns reflow is no longer a calendar, because the
   same weekday has to stay in the same place for the shape of the
   fortnight to be readable at a glance.

   Below 760px it becomes one column per day, which is a list - the
   right answer on a phone, where seven columns are 50px wide and
   nothing in them can be read.
   --------------------------------------------------------------------- */
.cal-grid {
	display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
	gap: 1px; background: var(--border); border-radius: var(--radius); overflow: hidden;
}
.cal-head {
	background: var(--surface-2); padding: 7px 8px; font-size: 11px; font-weight: 600;
	text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); text-align: center;
}
.cal-day { background: var(--surface); padding: 7px; min-height: 104px; }
.cal-day.cal-past { background: var(--surface-2); }
.cal-day.cal-today { box-shadow: inset 0 0 0 2px var(--accent); }
.cal-date { font-size: 11px; font-weight: 600; color: var(--text-muted); margin-bottom: 5px; }
.cal-item {
	display: block; font-size: 11.5px; line-height: 1.25; padding: 3px 5px; margin-bottom: 3px;
	border-radius: 5px; text-decoration: none; color: var(--text);
	background: var(--accent-50); border-left: 3px solid var(--accent);
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cal-item:hover { text-decoration: underline; white-space: normal; }
/* one colour per kind, so a glance tells you what sort of day it is */
.cal-item.cal-tickets { background: #fff4e5; border-left-color: #d98324; }
.cal-item.cal-projectwork { background: #eaf7ee; border-left-color: #2f9e55; }
.cal-item.cal-unread { background: #f3eafe; border-left-color: #7c4dcc; }
.cal-item.cal-waiting { background: #ffeaea; border-left-color: #cc3b3b; }
/* opportunities to chase: teal, because the four hues already in use are taken
   and a deal needs to be findable in a day that also holds a ticket and a task */
.cal-item.cal-oppchase { background: #e4f2f2; border-left-color: #197e7e; font-weight: 600; }

/* DUE TODAY, and IN FLIGHT. The two states are deliberately opposites: due
   today keeps its kind's own hue and gains weight and a solid left edge, while
   in flight loses weight and goes dashed. Neither invents a new colour, so a
   day holding a ticket, a task and a chase still reads as three kinds - the
   urgency is carried by weight and the edge rather than by a sixth hue nobody
   could name. These come after the kind rules so they win on the edge. */
.cal-item.cal-duetoday {
	font-weight: 700;
	border-left-width: 5px;
	border-left-color: var(--red);
	box-shadow: inset 0 0 0 1px rgba(229, 72, 77, .22);
}
.cal-item.cal-inflight {
	font-weight: 400;
	font-style: italic;
	border-left-style: dashed;
	opacity: .82;
}
/* OVERDUE, added 5 October when the alarm clock split off from the flame. It is
   due-today turned up rather than a new idea: same solid red edge, same weight,
   plus a filled red tint so a late item is the first thing the eye lands on in a
   cell. Still no new hue - the kind's own colour is untouched - because the
   moment overdue gets a colour of its own, a day holding a late ticket and a
   late task stops reading as two kinds. */
.cal-item.cal-overdue {
	font-weight: 700;
	border-left-width: 5px;
	border-left-color: var(--red);
	background: var(--red-50);
	box-shadow: inset 0 0 0 1px rgba(229, 72, 77, .38);
}

/* The same two states on the Today cards. The divider labels the second group
   rather than being a bare line, because a line on its own at the bottom of a
   card reads as the end of the card. */
.group-divider {
	margin: 10px -8px 2px;
	padding: 7px 8px 5px;
	border-top: 1px solid var(--border);
	color: var(--muted);
	text-transform: uppercase;
	letter-spacing: .05em;
	font-weight: 600;
}
/* A FORM WITH UNSAVED CHANGES SAYS SO ON ITS OWN SAVE BUTTON.

   The ticket screen is several cards, each its own form with its own Save. Type
   a close date into the Details card, press the Save on the card above it, and
   the date is gone without a word - the browser only ever sends the form you
   submitted. The dot is what makes the right button findable; app.js adds the
   class on the first edit and takes it off on save. */
/* THE DOT GOES ON ONE BUTTON, CHOSEN BY app.js, not on every submit in the
   form. This rule used to match them all, and the roster's "Set" / "Send now"
   pair therefore got a dot each the moment a step number was typed - which
   reads as a rendering fault, and answers nothing, because the dot exists to
   say WHICH button saves. app.js marks it only when there is exactly one it
   could be. */
.is-dirty-mark::after {
	content: "\00a0\2022";
	font-size: 15px;
	line-height: 1;
	opacity: .85;
}
form.is-dirty .card-foot {
	box-shadow: inset 2px 0 0 var(--amber);
}

.clip-row.row-duetoday { background: var(--red-50); }
/* Due inside the flame window but NOT today. Amber, because red here was
   the same red as overdue - which made the two markers read alike and
   undid the point of telling them apart. */
.clip-row.row-duesoon { background: var(--amber-50); }
.clip-row.row-inflight { opacity: .88; }
/* A late row keeps the tint it already had and gains a left edge, so late and
   due-soon are told apart by shape at a glance and not only by the emoji. */
.clip-row.row-overdue { background: var(--red-50); box-shadow: inset 3px 0 0 var(--red); }

@media (max-width: 760px) {
	.cal-grid { grid-template-columns: 1fr; }
	.cal-head { display: none; }
	.cal-day { min-height: 0; }
	.cal-item { white-space: normal; }
}

/* ---------- The scope picker, at the top of the navigation rail ----------
   Sits on the dark sidebar, so it cannot inherit the form styling used in the
   content area - a white control here reads as a mistake. Hidden entirely
   when there is only one brand and no customer consoles, which is the state a
   customer's own install runs in. */
.scope-pick {
	padding: 0 10px 14px;
	margin-bottom: 4px;
	border-bottom: 1px solid rgba(255,255,255,.06);
}
.scope-pick form { margin: 0; }
.scope-pick label {
	display: block;
	font-size: 10.5px;
	text-transform: uppercase;
	letter-spacing: .09em;
	color: #5f6580;
	font-weight: 600;
	margin-bottom: 5px;
}
.scope-pick select {
	width: 100%;
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	color: #e8eaf4;
	background: rgba(255,255,255,.06);
	border: 1px solid rgba(255,255,255,.10);
	border-radius: 9px;
	padding: 7px 9px;
	cursor: pointer;
}
.scope-pick select:hover { background: rgba(255,255,255,.10); }
.scope-pick select:focus {
	outline: none;
	border-color: rgba(124,124,255,.55);
	box-shadow: 0 0 0 2px rgba(124,124,255,.18);
}
/* the options themselves render in the OS palette on most browsers, so they
   are given an explicit dark pair rather than inheriting white-on-white */
.scope-pick select option { background: #1b1f33; color: #e8eaf4; }

/* Customer consoles: links out to separate installs, deliberately not styled
   like the scope control above them, because they are not scopes. */
.scope-customers { margin-top: 12px; }
.scope-customers-label {
	font-size: 10.5px;
	text-transform: uppercase;
	letter-spacing: .09em;
	color: #5f6580;
	font-weight: 600;
	margin-bottom: 4px;
}
.scope-customers a {
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 6px 8px;
	border-radius: 8px;
	color: #cfd3e3;
	font-size: 12.5px;
	font-weight: 550;
	text-decoration: none;
}
.scope-customers a:hover { background: rgba(255,255,255,.06); color: #fff; }
.scope-customers a > span:first-child {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.scope-customers a .i { margin-left: auto; opacity: .55; flex: 0 0 auto; }
.scope-customers a .pill { font-size: 10.5px; padding: 1px 6px; flex: 0 0 auto; }

/* ---------- Top right: the alert inbox and the profile menu ----------
   Order left to right: search, bell, photo. Both of the last two are links
   first and menus second, so Sign out is reachable with no JavaScript. */
.topright { display: flex; align-items: center; gap: 6px; margin-left: 4px; flex: 0 0 auto; }
.topmenu { position: relative; }

.topicon {
	position: relative;
	display: grid;
	place-items: center;
	width: 38px; height: 38px;
	border-radius: 10px;
	color: var(--text-2);
	text-decoration: none;
}
.topicon:hover { background: var(--surface-2); color: var(--text); }
.topicon.has-unread { color: var(--red); }
.topdot {
	position: absolute; top: 3px; right: 2px;
	min-width: 16px; height: 16px; padding: 0 4px;
	border-radius: 99px;
	background: var(--red); color: #fff;
	font-size: 10px; font-weight: 700; line-height: 16px;
	text-align: center;
	box-shadow: 0 0 0 2px var(--surface);
}

.topavatar {
	display: grid; place-items: center;
	width: 38px; height: 38px;
	border-radius: 50%;
	text-decoration: none;
	overflow: hidden;
}
.topavatar img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; display: block; }
.topavatar:hover { box-shadow: 0 0 0 2px var(--accent-50); }

/* The panels. Hidden until the toggle adds is-open, so no-JS leaves them shut
   and the anchor underneath simply navigates instead. */
.topdrop {
	position: absolute; top: calc(100% + 8px); right: 0;
	width: 320px; max-width: calc(100vw - 32px);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: 12px;
	box-shadow: 0 12px 32px rgba(16,18,36,.14);
	padding: 6px;
	z-index: 60;
	display: none;
}
.topmenu.is-open .topdrop { display: block; }
.topdrop-right { width: 260px; }
.topdrop-head {
	display: flex; align-items: center; justify-content: space-between;
	gap: 8px; padding: 8px 10px 10px;
	border-bottom: 1px solid var(--border);
	margin-bottom: 4px;
}
.topdrop-who {
	display: flex; flex-direction: column; gap: 2px;
	padding: 8px 10px 10px;
	border-bottom: 1px solid var(--border);
	margin-bottom: 4px;
}
.topdrop-item {
	display: flex; align-items: flex-start; gap: 9px;
	padding: 9px 10px;
	border-radius: 8px;
	color: var(--text);
	text-decoration: none;
	font-size: 13px;
}
.topdrop-item:hover { background: var(--surface-2); }
.topdrop-item.is-unread { background: var(--accent-50); }
.topdrop-item.is-unread:hover { background: var(--accent-50); filter: brightness(.97); }
.topdrop-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.topdrop-text strong { font-weight: 600; }
/* a severity pip, so alarm and warn are told apart by shape not only by words */
.topdrop-sev { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex: 0 0 auto; background: var(--muted); }
.topdrop-sev.sev-alarm { background: var(--red); }
.topdrop-sev.sev-warn { background: var(--amber); }
.topdrop-sev.sev-info { background: var(--blue); }
.topdrop-empty { padding: 18px 10px; text-align: center; color: var(--muted); font-size: 13px; }
.topdrop-foot {
	display: block; text-align: center;
	padding: 9px 10px; margin-top: 4px;
	border-top: 1px solid var(--border);
	color: var(--accent); font-size: 12.5px; font-weight: 600; text-decoration: none;
}
.topdrop-foot:hover { text-decoration: underline; }

@media (max-width: 760px) {
	/* the search box gives up its width first - the bell and the photo are the
	   two things that must stay reachable on a phone */
	.topright { margin-left: auto; }
	.topdrop { width: 290px; }
}

/* The build stamp, bottom of every console screen. Quiet on purpose - it is
   there to be compared between two installs, not read every day. */
.buildstamp {
	padding: 10px 32px 28px;
	color: var(--muted);
	font-size: 11px;
	text-align: right;
}
@media (max-width: 760px) { .buildstamp { padding: 10px 16px 24px; text-align: left; } }

/* -------------------------------------------------------------------
   LIGHTBOX - looking at an image or a PDF without leaving the page.

   Wider than an ordinary modal because the content is the point, and
   the body has no padding so a photo reaches the edges. The iframe is
   given a real height rather than a percentage: a percentage of a
   flex child with no fixed basis collapses to nothing, which is a PDF
   viewer one pixel tall.
   ------------------------------------------------------------------- */
.modal.modal-lightbox { max-width: 1100px; }
.lightbox-body { padding: 0; background: var(--surface-2); display: flex; align-items: center; justify-content: center; overflow: auto; }
.lightbox-body img { display: block; max-width: 100%; max-height: 72vh; max-height: 72dvh; }
.lightbox-body iframe { display: block; width: 100%; height: 72vh; height: 72dvh; border: 0; background: #fff; }
.lightbox-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 720px) {
	.lightbox-body img { max-height: 62dvh; }
	.lightbox-body iframe { height: 62dvh; }
}

/* ===========================================================================
   THE NEW LOOK FOR DETAIL PAGES: a navigation rail, and one section at a time.

   Everything here is under [data-look="panes"] on <body>, so none of it can
   reach the classic view. Turning the new look off is not a code path - it is
   the absence of one.

   The markup is built by the pane script in app.js out of the cards the page
   already rendered. Nothing in contact.cfm or ticket.cfm knows this exists.
   =========================================================================== */

/* the two-column frame: rail, then the pane. The rail is fixed-width because a
   list of section names has no reason to grow with the window, and a pane that
   gets the rest is the point of the exercise. */
body[data-look="panes"] .pane-frame {
	display: grid;
	grid-template-columns: 228px minmax(0, 1fr);
	gap: 22px;
	align-items: start;
}

/* STICKY, so the rail is still there after scrolling a long Communications
   list. 18px matches the page gutter; the max-height and scroll are for the
   contact rail, which is forty-odd items and taller than a laptop screen. */
body[data-look="panes"] .pane-rail {
	position: sticky;
	top: 18px;
	max-height: calc(100vh - 36px);
	overflow-y: auto;
	padding: 10px;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: 14px;
	box-shadow: var(--shadow-sm);
}

/* THE GROUP HEADING IS A BUTTON NOW, because the groups collapse.

   Justin: "I'd like to be able to collapse and expand the sub navigations on
   the right side, master navigation rail."

   It keeps the look of the label it used to be - small, uppercase, quiet - and
   gains a chevron and a pointer. A heading that announced itself as a control
   would compete with the section links beside it, which are the things you
   actually came to press. */
body[data-look="panes"] .pane-rail-group {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	width: 100%;
	appearance: none;
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	text-align: left;
	cursor: pointer;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--muted);
	margin: 14px 0 4px 8px;
}
body[data-look="panes"] .pane-rail-section:first-child .pane-rail-group { margin-top: 2px; }
body[data-look="panes"] .pane-rail-group:hover { color: var(--text); }
body[data-look="panes"] .pane-rail-group:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: 6px;
}

/* A CHEVRON DRAWN FROM BORDERS, not an SVG: the rail is built in the browser
   and has no access to the icon() function every other chevron in this console
   comes from. Pointing down when open, right when closed, which is the same
   direction the left-hand menu uses. */
body[data-look="panes"] .pane-rail-chev {
	flex: 0 0 auto;
	width: 0;
	height: 0;
	margin-right: 8px;
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 5px solid currentColor;
	opacity: .8;
	transition: transform .12s ease;
}
body[data-look="panes"] .pane-rail-section.is-closed .pane-rail-chev {
	transform: rotate(-90deg);
}

/* And the collapse itself. display:none rather than a height animation: the
   rail is a list of links and a half-open group that can still be tabbed into
   is worse than no animation at all. */
body[data-look="panes"] .pane-rail-section.is-closed .pane-rail-items { display: none; }

body[data-look="panes"] .pane-rail a {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	padding: 7px 9px;
	border-radius: 8px;
	font-size: 13.5px;
	font-weight: 550;
	color: var(--text-2);
	text-decoration: none;
	line-height: 1.25;
}
body[data-look="panes"] .pane-rail a:hover { background: var(--surface-2); color: var(--text); }
body[data-look="panes"] .pane-rail a.is-current {
	background: var(--accent-50);
	color: var(--accent);
	font-weight: 650;
}

/* the count on the right of a rail item: how many rows that section holds, so
   you can see there are three tickets without opening it */
body[data-look="panes"] .pane-rail .pane-count {
	flex: none;
	min-width: 20px;
	text-align: center;
	padding: 1px 6px;
	border-radius: 99px;
	background: #eceef4;
	color: var(--muted);
	font-size: 11px;
	font-weight: 700;
}
body[data-look="panes"] .pane-rail a.is-current .pane-count {
	background: var(--accent);
	color: #fff;
}

/* ONE PANE SHOWS. The others are display:none rather than moved off-screen,
   because an off-screen pane still costs layout on every reflow and these
   pages carry a lot of markup. The script fires a resize event when a pane
   appears, which is what anything that measured itself at zero height while
   hidden - a chart, the rich text editor - listens for. */
body[data-look="panes"] .pane-item { display: none; }
body[data-look="panes"] .pane-item.is-current { display: block; }

/* the cards inside a pane lose their own stacking margin: there is one card */
body[data-look="panes"] .pane-item > .card { margin: 0; }

/* NARROW SCREENS GET THE RAIL ABOVE THE PANE, not a 228px column squeezed
   against a 90px one. Below this width the rail stops being sticky too -
   a sticky block that is taller than the viewport cannot be scrolled past. */
@media (max-width: 900px) {
	body[data-look="panes"] .pane-frame { grid-template-columns: minmax(0, 1fr); }
	body[data-look="panes"] .pane-rail {
		position: static;
		max-height: none;
	}
}

/* PRINTING SHOWS EVERYTHING AND HIDES THE RAIL. A printed contact with one
   section on it is not a printed contact. */
@media print {
	body[data-look="panes"] .pane-rail { display: none; }
	body[data-look="panes"] .pane-item { display: block; }
	body[data-look="panes"] .pane-frame { grid-template-columns: minmax(0, 1fr); }
}

/* The look toggle, in the topbar beside the profile menu. It is a console
   preference rather than an action on the record, which is why it lives in
   the chrome and not in each page's actions row - and why it is quiet. */
.topbar .pane-look {
	margin-right: 10px;
	white-space: nowrap;
}
/* on a phone the topbar is already crowded with the menu button, the back
   link and the avatar; two words of button is the first thing to go */
@media (max-width: 700px) {
	.topbar .pane-look { display: none; }
}

/* ---------------------------------------------------------------------------
   THE FOLDER PANE ON THE FILES SCREEN

   Justin: "I'd like the files/storage module to have a navigation pane to the
   right with the names of the modules (like folders)".

   Rows rather than a list of links, so the count sits hard against the right
   edge and the eye can run down the numbers. The current folder is filled
   rather than outlined: an outline reads as a focus ring on a list of links
   and people try to click it again.

   AN EMPTY FOLDER IS DIMMED, NOT HIDDEN. Hiding it would mean the pane
   changes shape as you filter, and Sales would be absent on the very day you
   went looking for somewhere to put a proposal. It stays clickable, because
   clicking it is how you see that it is genuinely empty rather than
   mis-filtered.
   --------------------------------------------------------------------------- */
.folder-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	padding: 8px 10px;
	border-radius: 8px;
	color: var(--text);
	font-size: 14px;
	font-weight: 550;
	text-decoration: none;
	border: 1px solid transparent;
}
.folder-row:hover { background: var(--surface-2); }
.folder-row > span:first-child {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.folder-row .count {
	flex-shrink: 0;
	font-size: 12px;
	font-weight: 650;
	color: var(--text-2);
	background: var(--surface-2);
	border-radius: 20px;
	padding: 1px 8px;
	min-width: 26px;
	text-align: center;
}
.folder-row.is-current {
	background: var(--accent);
	color: #fff;
	border-color: var(--accent);
}
.folder-row.is-current .count { background: rgba(255, 255, 255, 0.22); color: #fff; }
.folder-row.is-current:hover { background: var(--accent-600); }
.folder-row.is-empty { color: var(--text-2); }
.folder-row.is-empty .count { opacity: 0.55; }
.folder-row.is-empty.is-current { color: #fff; }

/* PRINTING A FILE LIST DOES NOT NEED THE NAVIGATION. */
@media print {
	.folder-row { display: none; }
}

/* ---------------------------------------------------------------------------
   THE ON/OFF DOT ON A MAILBOX ROW

   The button IS the state, so it needs to read as a state at a glance and not
   only when you get to the word. Green filled for on, hollow grey for off -
   the same two colours the pills next to it already use, so the row does not
   suddenly have a third vocabulary.

   A HOLLOW DOT RATHER THAN A RED ONE for off: off is a choice, not a fault,
   and red here would sit beside a genuinely red "refused" in the next column
   and make a working mailbox look broken.
   --------------------------------------------------------------------------- */
.mailbox-dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	margin-right: 5px;
	vertical-align: baseline;
	border: 1.5px solid var(--text-2);
	background: transparent;
}
.mailbox-dot.is-on,
.mailbox-dot.is-green {
	border-color: var(--green, #067647);
	background: var(--green, #067647);
}
/* Four states, from mailboxHealthState: on, degraded, needs attention, and
   switched off on purpose. Grey for the last one is the point - a mailbox off
   because somebody decided it should be is not a fault, and colouring it red
   teaches people to ignore red. */
.mailbox-dot.is-amber {
	border-color: var(--amber, #b54708);
	background: var(--amber, #b54708);
}
.mailbox-dot.is-red {
	border-color: var(--red, #b42318);
	background: var(--red, #b42318);
}
.mailbox-dot.is-gray {
	border-color: var(--text-2);
	background: transparent;
}
.mailbox-switch { border: 1px solid var(--border-strong); background: var(--surface); }
.mailbox-switch.is-green { border-color: var(--green, #067647); }
.mailbox-switch.is-amber { border-color: var(--amber, #b54708); }
.mailbox-switch.is-red { border-color: var(--red, #b42318); }

/* The state cell wraps. It used to be .nowrap for the sake of the On/Off
   button, which forbade wrapping for every note underneath it too - so the
   notes ran flat across the Test and Settings buttons and off the screen.
   The button keeps its own nowrap; the notes get a width that stops short. */
.mailbox-state { white-space: normal; }
.mailbox-state form { white-space: nowrap; }
.mailbox-state .small { max-width: 34ch; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------------
   SOMEBODY WHO USED TO BE THERE

   A former employee of a client, or a former member of a chapter: still a
   contact, still has their tickets, no longer somebody to ring about this
   company. Quiet rather than alarming - they have not done anything wrong,
   they have just left - and said in a word as well as a shade, because a
   colour alone does not survive a printout or a screen share.

   The row itself reuses tr.is-archived, which already greys and italicises.
--------------------------------------------------------------------------- */
.chip-former {
	color: var(--text-2);
	background: var(--surface-2);
	border-style: dashed;
}

/* ---------------------------------------------------------------------------
   WHAT A FILE LOOKS LIKE IN A LIST

   Justin: "is there any chance we could show a thumbnail of images, and
   icon/symbol for files like txt, zip, word, excel, pdf, ppt, mp4, etc.?"

   THE TWO ARE THE SAME SIZE, 36 by 36, and that is the only rule that really
   matters here. A list whose rows change height depending on whether the file
   happened to be a picture is harder to scan than one with no pictures at all.

   LETTERS RATHER THAN GLYPHS for the non-images: this icon set has no pdf,
   word, excel or zip symbol, and two similar document glyphs side by side are
   hard to tell apart anyway - which is why Drive, Dropbox and Slack all print
   the letters. The colour carries the family, the letters carry the specifics,
   and an extension nobody mapped still gets a tile of its own.
   --------------------------------------------------------------------------- */
.file-thumb,
.file-tile {
	width: 36px;
	height: 36px;
	border-radius: 7px;
	display: block;
	flex-shrink: 0;
}
.file-thumb {
	object-fit: cover;
	border: 1px solid var(--border);
	background: var(--surface-2);
}
.file-tile {
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 9.5px;
	font-weight: 750;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	border: 1px solid transparent;
	/* the words are tiny and sit on a tinted ground, so they get the darker of
	   each pair rather than the brand colour at full strength */
	color: var(--text-2);
	background: var(--surface-2);
	border-color: var(--border);
}
.file-thumb-link { display: inline-block; line-height: 0; }

.file-tile-pdf     { background: #fdecec; color: #b42318; border-color: #f7cfcf; }
.file-tile-doc     { background: #eaf1fd; color: #1d4ed8; border-color: #cfdef9; }
.file-tile-sheet   { background: #e7f7f0; color: #067647; border-color: #c6ecdb; }
.file-tile-slide   { background: #fff3e6; color: #b54708; border-color: #fadcbd; }
.file-tile-archive { background: #fdf4e3; color: #92600a; border-color: #f5e2b8; }
.file-tile-video   { background: #f1ecfd; color: #5b21b6; border-color: #ddd2f8; }
.file-tile-audio   { background: #fdeefa; color: #9d174d; border-color: #f7d4ec; }
.file-tile-text    { background: #f2f4f8; color: #475569; border-color: #e2e6ee; }
.file-tile-code    { background: #e9f4f8; color: #0e6e8c; border-color: #cbe6ef; }
.file-tile-mail    { background: #eef0ff; color: #4a48e0; border-color: #dadcfb; }
/* image and other keep the neutral ground above: an image tile only appears
   when the picture itself could not be shown, and "other" is by definition
   nothing in particular */

@media print {
	.file-thumb, .file-tile { border-color: #ccc; }
}

/* ---------------------------------------------------------------------------
   THE SEQUENCE DIAGRAM

   Justin: "I anticipate this looking similar to a diagram where I can also
   drag and drop steps... some basic analytics of how many people have seen it
   and are currently in that step."

   A COLUMN WITH THE JUMPS ARCHED DOWN ITS SIDE. The boxes are laid out by the
   ordinary flow - no absolute positioning, no stored coordinates - and the
   only drawn thing is the arcs, which the browser puts in after it knows how
   tall each box is. A diagram that cannot be dragged out of agreement with
   the engine is worth more than one that can be arranged prettily.

   DESKTOP ONLY, as asked. Below the diagram's width the list view is better
   anyway, and dragging boxes with a thumb into a live sequence is a mis-drop
   waiting to happen. */
/* ---------------------------------------------------------------------------
   THE TRUNK DOWN THE MIDDLE, AND THE BRANCHES EITHER SIDE OF IT

   Justin: "when we have a branch, I'd like the trunk of the spine to be
   centered in the middle, and the branchs to split off to the left and right,
   and then if there's a third, you'll have left, center, and right, etc."

   Centring the trunk is what makes the rest fall out for free: a fork is a
   grid of equal columns, so two lanes land either side of the centre line and
   three put one on it. Nothing counts the lanes - the browser does.

   THE SPINE MOVES WITH IT. It used to be a line at left:26px, which is where
   the step number sits; on a centred card that reads as off to one side. It is
   at the card's centre now, which is also where the fork connectors meet it.

   padding-right is still there and still 92px: the jump arcs are drawn out to
   the right of everything, and without the room they would be clipped. */
.seqmap { position: relative; padding-right: 92px; }
.seqmap-flow { position: relative; z-index: 1; max-width: 1000px; margin: 0 auto; }

.seqmap-cap {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 10px 14px;
	border: 1px dashed var(--border);
	border-radius: 12px;
	background: var(--surface-2);
	font-size: 13px;
	max-width: 520px;
}
.seqmap-cap .muted { margin-left: auto; font-size: 12px; }
.seqmap-cap { margin-left: auto; margin-right: auto; }
.seqmap-end { border-style: solid; border-color: var(--green-50); }

/* the spine between the boxes */
.seqmap-flow > * + * { margin-top: 0; }
.seqmap-node, .seqmap-cap { position: relative; }
.seqmap-node::before, .seqmap-end::before {
	content: "";
	position: absolute;
	left: 50%;
	margin-left: -1px;
	top: -18px;
	width: 2px;
	height: 18px;
	background: var(--border);
}
.seqmap-flow > .seqmap-node, .seqmap-flow > .seqmap-end { margin-top: 18px; }
/* every direct child of the flow is centred on the same line, which is what
   makes it a trunk rather than a left-hand column */
.seqmap-flow > .seqmap-node, .seqmap-flow > .seqmap-cap, .seqmap-flow > .seqmap-add { margin-left: auto; margin-right: auto; }

.seqmap-node {
	border: 1px solid var(--border);
	border-radius: 14px;
	background: var(--surface);
	box-shadow: var(--shadow-sm);
	padding: 12px 14px;
	max-width: 520px;
	cursor: pointer;
	transition: border-color .12s ease, box-shadow .12s ease;
}
.seqmap-node:hover { border-color: var(--accent); }
.seqmap-node:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.seqmap-node.is-current { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-50, rgba(91, 91, 246, .12)); }
.seqmap-node.is-off { opacity: .62; border-style: dashed; }
.seqmap-node.has-people { border-left: 3px solid var(--accent); }
.seqmap-node.is-dragging { opacity: .45; }
.seqmap-node.is-over { border-color: var(--accent); border-top-width: 3px; }

.seqmap-node-head { display: flex; align-items: center; gap: 10px; }
.seqmap-num {
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	border-radius: 8px;
	background: var(--surface-2);
	color: var(--text-2);
	font-size: 12px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
}
.seqmap-title { font-weight: 650; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seqmap-grip { margin-left: auto; color: var(--text-2); opacity: .45; cursor: grab; }
.seqmap-grip:active { cursor: grabbing; }
.seqmap-node:hover .seqmap-grip { opacity: .9; }

.seqmap-when { font-size: 12px; color: var(--text-2); margin-top: 6px; }
.seqmap-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
/* these three are used on the step list as well as on the diagram, so they are
   not scoped to .seqmap-chips - a chip that is only coloured inside the
   diagram is a chip that looks broken on the other view */
.chip-cond { color: var(--accent); }
.chip-jump { color: var(--accent); }
.chip-stop { color: var(--red); }

.seqmap-stats {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-top: 10px;
	padding-top: 8px;
	border-top: 1px solid var(--border);
	font-size: 12px;
	color: var(--text-2);
}
/* the number this view exists for: where people actually are */
.seqmap-here { color: var(--accent); font-weight: 700; }

.seqmap-edges {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
	overflow: visible;
	z-index: 0;
}
.seqmap-edge { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: .75; }
.seqmap-edge-stop { stroke: var(--red); }
/* the lines into and out of a fork: part of the spine rather than a jump, so
   they are the spine's colour and weight and carry no arrowhead - an arrow on
   every one of five connectors reads as five separate claims */
.seqmap-edge-lane { stroke: var(--border); stroke-width: 2; opacity: 1; }

/* the properties panel: a drawer, so opening it does not reflow the diagram
   out from under the box you just pressed */
.seqmap-panel {
	position: fixed;
	top: 0;
	right: 0;
	width: 400px;
	max-width: 92vw;
	height: 100%;
	background: var(--surface);
	border-left: 1px solid var(--border);
	box-shadow: -8px 0 24px rgba(15, 23, 42, .08);
	padding: 18px;
	overflow-y: auto;
	z-index: 60;
}
.seqmap-panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.seqmap-panel-stats {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 8px;
	margin: 14px 0;
}
.seqmap-panel-stats div {
	background: var(--surface-2);
	border-radius: 10px;
	padding: 8px 6px;
	text-align: center;
}
.seqmap-panel-stats b { display: block; font-size: 16px; }
.seqmap-panel-stats span { font-size: 11px; color: var(--text-2); }

@media (max-width: 900px) {
	.seqmap { padding-right: 0; }
	.seqmap-edges { display: none; }
	.seqmap-grip { display: none; }
	.seqmap-panel { width: 100%; max-width: 100%; }
}

/* ---------------------------------------------------------------------------
   LANES: a branch drawn as columns side by side, meeting again below

   Justin: "I was envisioning the possibility of multiple columns side-by-side
   based on the branch, and some might rejoin."

   The columns come from the jumps, so nothing here positions anything - a
   grid with one track per lane, and the browser does the rest. Which means
   the picture cannot be dragged out of agreement with the engine: there is no
   arrangement to drag. */
/* THE FORK. Equal columns, centred, so two lanes sit either side of the trunk
   and three put one on it - "left, center, and right, etc." without anything
   counting them.

   THE 34px OF TOP PADDING IS WHERE THE CONNECTORS GO. app.js draws them into
   the same SVG as the jump arcs, because only the browser knows where the lane
   heads ended up once the text has wrapped. Drawing them in CSS would mean
   knowing the lane count and the gap in advance, which CSS does not. */
.seqmap-fork {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
	gap: 18px;
	margin: 18px auto 0;
	padding: 34px 14px 14px;
	border: 1px dashed var(--border);
	border-radius: 16px;
	background: linear-gradient(var(--surface-2), transparent 60%);
	width: 100%;
	max-width: 1000px;
}
.seqmap-lane { display: flex; flex-direction: column; gap: 14px; min-width: 0; border-radius: 12px; transition: background .12s ease, box-shadow .12s ease; }
/* dragging a card over a lane says so, because dropping into the wrong column
   is a change to who gets what rather than a cosmetic mistake */
.seqmap-lane.is-lane-over { background: var(--accent-50, rgba(91, 91, 246, .10)); box-shadow: inset 0 0 0 2px var(--accent); }
.seqmap-lane-label {
	text-align: center;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--accent);
}
/* inside a lane the boxes fill their column and lose the trunk's spine: the
   lane itself is the line */
.seqmap-lane .seqmap-node { max-width: none; margin-top: 0; }
.seqmap-lane .seqmap-node::before { display: none; }

.seqmap-merge {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	margin: 14px auto 0;
	padding: 8px 14px;
	font-size: 12px;
	color: var(--text-2);
	max-width: 520px;
}

@media (max-width: 900px) {
	/* stacked, so there is no left and right to speak of - and the connectors
	   are not drawn either, because the SVG is hidden at this width */
	.seqmap-fork { grid-template-columns: minmax(0, 1fr); padding-top: 14px; }
	.seqmap-flow { max-width: none; }
}

/* ---------------------------------------------------------------------------
   THE GAP BETWEEN TWO CARDS

   Justin, on the diagram: "I don't see how to add a conditional evaluation to
   create a branch between two cards."

   So the gap is now a control, and it is part of the spine rather than a thing
   sitting beside it: it carries the same 18px top margin and the same 2px line
   as a card, so the trunk stays one continuous line whether the gap is open or
   shut. A details element, so it needs no JavaScript to open.

   AT REST IT IS NEARLY INVISIBLE - a short line and a plus. A row of four
   buttons in every gap would make a five-step sequence look like a toolbar
   catalogue; the control has to be findable without being the loudest thing on
   the screen. */
.seqmap-add { position: relative; margin-top: 18px; max-width: 520px; text-align: center; }
.seqmap-add::before {
	content: "";
	position: absolute;
	left: 50%;
	margin-left: -1px;
	top: -18px;
	width: 2px;
	height: 18px;
	background: var(--border);
}
.seqmap-add > summary {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 2px 8px 2px 4px;
	border-radius: 999px;
	font-size: 12px;
	color: var(--text-2);
	cursor: pointer;
	list-style: none;
	opacity: .5;
	transition: opacity .12s ease, color .12s ease, background .12s ease;
}
.seqmap-add > summary::-webkit-details-marker { display: none; }
.seqmap-add > summary:hover,
.seqmap-add[open] > summary { opacity: 1; color: var(--accent); background: var(--surface-2); }
.seqmap-add > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; opacity: 1; }
.seqmap-add-plus {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 20px;
	height: 20px;
	border-radius: 999px;
	border: 1px dashed var(--border);
	background: var(--surface);
}
.seqmap-add[open] .seqmap-add-plus { border-style: solid; border-color: var(--accent); }
/* the word is for the first time; after that the plus is enough, and a row of
   words in every gap would read as a list of steps that are not there */
.seqmap-add-word { opacity: 0; transition: opacity .12s ease; }
.seqmap-add > summary:hover .seqmap-add-word,
.seqmap-add > summary:focus-visible .seqmap-add-word,
.seqmap-add[open] .seqmap-add-word { opacity: 1; }
.seqmap-add-menu {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 2px;
	margin: 6px auto 0;
	text-align: left;
	padding: 8px;
	border: 1px solid var(--border);
	border-radius: 12px;
	background: var(--surface);
	box-shadow: var(--shadow-sm);
	max-width: 340px;
}
.seqmap-add-menu .btn { width: 100%; justify-content: flex-start; }

/* ---------------------------------------------------------------------------
   A CARD THAT IS NOT AN EMAIL

   A branch, an end point and a list step sent nothing and were drawn with
   sent/opened/clicked anyway - four zeroes that read as a broken step. They
   are their own shapes now. */
.chip-kind {
	color: var(--accent);
	border-color: var(--accent-50, rgba(91, 91, 246, .25));
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .03em;
	font-size: 10px;
}
.seqmap-node.is-branch { border-left: 3px solid var(--accent); background: linear-gradient(135deg, var(--surface-2), var(--surface) 55%); }
.seqmap-node.is-stop { border-left: 3px solid var(--red); }
.seqmap-node.is-list { border-left: 3px solid var(--green, #16a34a); }
.seqmap-note {
	margin-top: 8px;
	padding: 6px 8px;
	border-radius: 8px;
	background: var(--surface-2);
	font-size: 11.5px;
	line-height: 1.45;
	color: var(--text-2);
}

/* ---------------------------------------------------------------------------
   THE PANEL, EDITING RATHER THAN ONLY REPORTING

   Justin: "I do like how the properties panel works." So the condition and the
   branch paths are set here now, not on a separate screen. */
.seqmap-panel-form {
	margin: 0 0 14px;
	padding: 12px;
	border: 1px solid var(--border);
	border-radius: 12px;
	background: var(--surface-2);
}
.seqmap-panel-form .field { margin-bottom: 10px; }
.seqmap-panel-form select { width: 100%; }
.seqmap-rules { display: flex; flex-direction: column; gap: 8px; }
.seqmap-rule {
	display: grid;
	grid-template-columns: 20px minmax(0, 1fr);
	gap: 6px 8px;
	align-items: center;
}
.seqmap-rule select { grid-column: 2; }
.seqmap-rule-reads {
	grid-column: 2;
	font-size: 11.5px;
	line-height: 1.4;
	color: var(--text-2);
	padding: 5px 7px;
	border-radius: 7px;
	background: var(--surface);
	border: 1px solid var(--border);
}
.seqmap-rule-reads a { display: inline-block; margin-top: 2px; white-space: nowrap; }
.seqmap-rule-no {
	grid-row: span 2;
	align-self: start;
	margin-top: 7px;
	width: 20px;
	height: 20px;
	border-radius: 999px;
	background: var(--surface);
	border: 1px solid var(--border);
	color: var(--text-2);
	font-size: 11px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
}

@media (max-width: 900px) {
	/* the gap control stays: adding a step is the one thing on this view that
	   is as useful on a phone as it is on a desk */
	.seqmap-add-word { opacity: 1; }
}

/* =====================================================================
   THE PIPELINE BOARD'S DRAG GRIP  -  drop 60

   Dragging is armed only from this handle, because a pipe-card's main
   element is a link and a browser dragging a link drags the URL. The Move
   dropdown underneath is what a keyboard uses and it has not moved.

   cursor: grab rather than move, because the card does not go where the
   pointer goes - it goes into whichever column it is dropped on.
   ===================================================================== */
.pipe-grip {
	flex: 0 0 auto;
	align-self: flex-start;
	padding: 2px 4px 2px 0;
	margin-right: 2px;
	color: var(--text-muted);
	font-size: 11px;
	line-height: 1.1;
	letter-spacing: -2px;
	cursor: grab;
	user-select: none;
}
.pipe-grip:active { cursor: grabbing; }
.pipe-card.is-lifting { opacity: .4; }
/* the column being hovered over says so, because a drop with no target
   feedback is a drop somebody makes twice */
.board-col-body.is-drop-target {
	outline: 2px dashed var(--accent);
	outline-offset: -4px;
	border-radius: var(--radius-sm);
}

/* ==========================================================================
   FINDING A MODULE  -  the magnifying glass and the clock above the rail
   --------------------------------------------------------------------------
   Two small buttons and two panels that take the same shape. The panels are
   in the page and hidden rather than built on demand, so pressing the icon
   shows something in the same frame - a search box that is empty for one
   frame reads as broken.
   ========================================================================== */
.nav-find { padding: 0 12px 6px; }
.nav-find-bar { display: flex; gap: 6px; }
.nav-find-btn {
	display: inline-flex; align-items: center; justify-content: center;
	width: 30px; height: 30px; padding: 0;
	border: 1px solid var(--border); border-radius: var(--radius-sm);
	background: var(--surface-2); color: var(--text-2); cursor: pointer;
}
.nav-find-btn:hover { background: var(--surface-3); color: var(--text); border-color: var(--border-strong); }
.nav-find.is-open .nav-find-btn { border-color: var(--border-strong); }

.nav-find-panel {
	margin-top: 8px; padding: 8px;
	border: 1px solid var(--border-strong); border-radius: var(--radius);
	background: var(--surface-2);
}
.nav-find-label {
	font-size: 11px; font-weight: 700; letter-spacing: .04em;
	text-transform: uppercase; color: var(--muted); padding: 2px 4px 6px;
}
.nav-find-input {
	width: 100%; padding: 6px 8px;
	border: 1px solid var(--border); border-radius: var(--radius-sm);
	background: var(--surface); color: var(--text); font-size: 13px;
}
.nav-find-input:focus { outline: none; border-color: var(--accent); }
.nav-find-hits { display: flex; flex-direction: column; margin-top: 6px; }
.nav-find-hit {
	display: block; padding: 6px 8px; border-radius: var(--radius-sm);
	color: var(--text-2); font-size: 13px; text-decoration: none;
}
.nav-find-hit:hover, .nav-find-hit:focus {
	background: var(--surface-3); color: var(--text); outline: none;
}
.nav-find-none { padding: 6px 8px; font-size: 12px; color: var(--muted); }


/* =====================================================================
   PINNED ROWS

   Justin: "pin and unpin a project, task, to-do, opportunity, messages,
   leads, contacts, etc. to the top of a list... Sorting columns won't
   change the pinned items."

   The pinned block is not a separate table - it is the same rows, first,
   because the ordering is done in the ORDER BY. So all this does is make
   it obvious where the block ends: a tinted row and one firmer line under
   the last of them.

   THE LINE IS ON :last-of-type OF THE PINNED ROWS, not a border on every
   one, so a block of five reads as one group rather than five stripes.

   STYLED OFF data-sort-id RATHER THAN A CLASS, and that is not cosmetic.
   Every list row in this console already carries a class - row-link, or
   whatever its own row-attribute helper emits - and a pin helper that
   returned class="..." of its own would put a SECOND class attribute on
   the tag. Browsers keep the first and drop the second, so the row would
   stop being clickable or stop looking pinned depending on the order.
   Tasks made this concrete: its rows get their attributes from a function
   and there is nowhere safe to add a class at all.

   The attribute is already there for the drag, so this costs nothing and
   there is no second thing to remember per screen.
   ===================================================================== */
.pin-cell { display: flex; align-items: center; gap: 2px; }
.pin-btn {
	background: none; border: 0; padding: 3px; cursor: pointer; line-height: 0;
	color: var(--text-muted); border-radius: var(--radius-sm);
}
.pin-btn:hover { color: var(--text); background: var(--surface-3); }
.pin-btn.is-pinned { color: var(--accent); }
.pin-btn.is-pinned:hover { color: var(--red); }
.pin-grip { color: var(--text-muted); cursor: grab; line-height: 0; padding: 2px; }
.pin-grip:active { cursor: grabbing; }
.pin-steps { display: inline-flex; flex-direction: column; }
.pin-step {
	background: none; border: 0; padding: 0; cursor: pointer; line-height: 0;
	color: var(--text-muted);
}
.pin-step:hover { color: var(--text); }
/* one icon, turned - a chevron and a chevron upside down are the same
   twelve bytes and two sprite entries is two things to keep in step */
.pin-step-up { transform: rotate(180deg); }
/* drop 152: keyed on data-pinned (pinRowAttrs), not data-sort-id - project tasks and the CMS collections are draggable without being pinned */
tr[data-pinned] > td { background: var(--surface-2); }

/* =====================================================================
   THE HOT LIST TICK BOX

   A <button> drawn as a check box, which is a deliberate trade and the
   same one the pin buttons make. A real <input type="checkbox"> saves
   nothing on its own - it needs a submit button beside it on every row,
   or a script to post on change - and the rule this console works to is
   that the no-script route is the feature and script is decoration. So
   it is a button that looks and is announced like a check box.

   The tick only exists when it is on, so the empty box is the unticked
   state and there is nothing to grey out.
   ===================================================================== */
.hot-btn {
	background: none; border: 0; padding: 3px; cursor: pointer;
	display: inline-flex; align-items: center; gap: 7px;
	color: var(--text-muted); border-radius: var(--radius-sm);
	font: inherit; font-weight: 550; line-height: 1;
}
.hot-box {
	width: 16px; height: 16px; flex: 0 0 auto; border-radius: 4px;
	border: 1.5px solid var(--border-strong); background: var(--surface);
	display: inline-flex; align-items: center; justify-content: center;
	line-height: 0; transition: background .12s, border-color .12s;
}
.hot-btn:hover { color: var(--text); }
.hot-btn:hover .hot-box { border-color: var(--accent); }
.hot-btn.is-hot { color: var(--accent); }
.hot-btn.is-hot .hot-box { background: var(--accent); border-color: var(--accent); color: #fff; }
/* the words beside the box, which only the contact's own page passes - on
   a list row the column heading does that job and forty repeats of the
   word would be noise */
.hot-label { white-space: nowrap; }

tr[data-pinned]:last-of-type > td { box-shadow: inset 0 -2px 0 var(--border-strong); }

/* drop 125: Phone > Add a line, three numbered steps */
.ph-step { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; }
.ph-step + .ph-step { border-top: 1px solid var(--border); }
.ph-step-no { flex: 0 0 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 700; background: var(--blue-50); color: var(--blue); }
.ph-step.muted .ph-step-no { background: #f0f1f5; color: #8a90a6; }
.ph-step select, .ph-step input[type=text] { width: 100%; }
.ph-step label { display: block; margin-bottom: 4px; }
/* drop 126: the numbers on the Twilio account, each with what it is already doing */
.ph-numbers { border: 1px solid var(--border); border-radius: 10px; max-height: 260px; overflow-y: auto; }
.ph-number { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; padding: 8px 10px; margin: 0; cursor: pointer; }
.ph-number + .ph-number { border-top: 1px solid var(--border); }
.ph-number:hover { background: rgba(124,124,255,.05); }
.ph-number.is-taken { cursor: default; opacity: .7; }
.ph-number.is-taken:hover { background: none; }
.ph-number input { margin: 0; }
.ph-number-main { flex: 1 1 auto; }
.ph-number-roles { display: flex; flex-wrap: wrap; gap: 4px; width: 100%; padding-left: 22px; }
.ph-number-roles:empty { display: none; }
.ph-number-roles .pill::first-letter { text-transform: none; }
.ph-step label.ph-number { display: flex; margin-bottom: 0; }
/* drop 127: the hidden attribute must win over .choice / .hint / input display rules */
[data-twilio-point][hidden], [data-twilio-warn][hidden], [data-twilio-typed][hidden] { display: none !important; }
/* drop 128: the extension box shows the boxes for what the extension does */
[data-kind-show][hidden], [data-kind-label][hidden] { display: none !important; }
/* drop 132: the typed greeting or number, put away while one from the library is picked */
[data-lib-inline][hidden] { display: none !important; }
[data-lib-pick] { margin-bottom: 6px; }
/* drop 134: an assistant conversation, read back */
.ph-talk { padding: 4px 6px 8px; display: grid; gap: 6px; max-width: 820px; }
.ph-talk-line b { display: inline-block; min-width: 76px; color: var(--text-2); font-weight: 600; }
/* drop 128: a number's recent use, under it in Add a line */
.ph-use-btn { padding: 2px 8px; font-size: 12px; }
.ph-use { width: 100%; padding: 6px 0 2px 22px; color: var(--muted); }
.ph-use[hidden] { display: none !important; }
.ph-use div + div { margin-top: 2px; }
/* drop 130: the setup checklist */
.setup-step { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border-top: 1px solid var(--border); }
.setup-area .card-body > .setup-step:first-child { border-top: 0; }
.setup-no { flex: 0 0 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 700; background: #f0f1f5; color: #5c6479; }
.setup-done .setup-no { background: var(--green-50); color: var(--green); }
.setup-next .setup-no { background: var(--accent); color: #fff; }
.setup-waiting .setup-no { background: var(--amber-50); color: var(--amber); }
.setup-main { flex: 1 1 auto; min-width: 0; }
.setup-main > div + div { margin-top: 3px; }
.setup-title { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.setup-ask { background: var(--amber-50); border-radius: 8px; padding: 6px 8px; margin-top: 6px !important; }
.setup-actions { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; flex: 0 0 auto; }
.setup-done .setup-title b, .setup-skipped .setup-title b { color: var(--muted); }
.setup-next { background: rgba(124,124,255,.05); }
@media (max-width: 640px) { .setup-step { flex-wrap: wrap; } .setup-actions { width: 100%; justify-content: flex-start; padding-left: 40px; } }
/* drop 142: the phone screens - a "Clear it" tick inside a hint, the day chips, the hidden hours */
.ph-clear { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; font-size: inherit; color: var(--text); margin: 0 0 0 4px; cursor: pointer; }
.ph-clear input { width: 14px; height: 14px; margin: 0; accent-color: var(--accent); }
.ph-days { display: flex; flex-wrap: wrap; gap: 6px; }
.ph-day { position: relative; margin: 0; cursor: pointer; }
.ph-day input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.ph-day span { display: inline-block; min-width: 44px; text-align: center; padding: 7px 8px; border: 1px solid var(--border); border-radius: 8px; font-weight: 600; font-size: 13px; color: var(--muted); background: var(--surface); }
.ph-day input:checked + span { background: var(--accent-50); border-color: var(--accent); color: var(--accent-600); }
.ph-day input:focus-visible + span { box-shadow: 0 0 0 3px rgba(91,91,246,.2); }
[data-hours-days][hidden] { display: none !important; }
/* drop 142: the call flow - three steps down the middle, then the options as a tree */
.pf-wrap { overflow-x: auto; padding: 18px 12px 24px; }
.pf-legend { display: inline-flex; gap: 6px; flex-wrap: wrap; margin-right: 6px; }
.pf-chip { display: inline-block; padding: 3px 8px; border-radius: 99px; font-weight: 600; font-size: 11.5px; border: 1px solid var(--border); }
.pf-chip.pf-ring { border-color: #b9d8f5; background: #eef6fe; color: #1f5f99; }
.pf-chip.pf-mailbox { border-color: #e2e4ea; background: #f6f7f9; color: #565b6b; }
.pf-chip.pf-menu { border-color: #f1d9a8; background: #fff7e8; color: #8a5a00; }
.pf-chip.pf-ai { border-color: #d8c8f7; background: #f5f0ff; color: #5b37b5; }
.pf-spine { display: flex; flex-direction: column; align-items: center; }
.pf-step { display: flex; gap: 12px; align-items: flex-start; width: 100%; max-width: 560px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; box-shadow: var(--shadow-sm); }
.pf-step[data-rowlink] { cursor: pointer; }
.pf-step[data-rowlink]:hover, .pf-node:hover { border-color: var(--accent-100); }
.pf-step-no { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; background: var(--accent-50); color: var(--accent-600); font-weight: 700; font-size: 13px; display: grid; place-items: center; }
.pf-empty { border-style: dashed; align-items: center; }
.pf-arrow { width: 2px; height: 24px; background: var(--border); position: relative; }
.pf-arrow::after { content: ""; position: absolute; bottom: -1px; left: -4px; border: 5px solid transparent; border-top-color: var(--border); border-bottom: 0; }
.pf-quote { font-size: 13px; color: var(--text-2); margin-top: 4px; font-style: italic; }
.pf-keys { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px; color: var(--muted); }
.pf-keys b { color: var(--text); }
.pf-tree, .pf-sub { display: flex; justify-content: center; list-style: none; margin: 0; padding: 24px 0 0; position: relative; }
.pf-li { position: relative; padding: 24px 8px 0; display: flex; flex-direction: column; align-items: center; }
.pf-tree::before, .pf-sub::before { content: ""; position: absolute; top: 0; left: 50%; height: 24px; border-left: 2px solid var(--border); }
.pf-li::before, .pf-li::after { content: ""; position: absolute; top: 0; right: 50%; width: 50%; height: 24px; border-top: 2px solid var(--border); }
.pf-li::after { right: auto; left: 50%; border-left: 2px solid var(--border); }
.pf-li:first-child::before, .pf-li:last-child::after { border-top: 0; }
.pf-li:last-child::before { border-right: 2px solid var(--border); border-radius: 0 8px 0 0; }
.pf-li:first-child::after { border-radius: 8px 0 0 0; }
.pf-li:only-child::before { display: none; }
.pf-li:only-child::after { border-top: 0; border-radius: 0; }
.pf-node { width: 236px; text-align: left; background: var(--surface); border: 1px solid var(--border); border-top: 4px solid #cfd3dc; border-radius: 12px; padding: 10px 12px; box-shadow: var(--shadow-sm); cursor: pointer; font-size: 13px; }
.pf-node.pf-ring { border-top-color: #4a9be0; }
.pf-node.pf-mailbox { border-top-color: #9aa0ad; }
.pf-node.pf-menu { border-top-color: #e5a52a; }
.pf-node.pf-ai { border-top-color: #7c4dde; background: #fbf9ff; }
.pf-node.pf-off { opacity: .6; }
.pf-node-head { display: flex; align-items: center; gap: 8px; }
.pf-key { flex: 0 0 auto; min-width: 26px; height: 26px; padding: 0 6px; border-radius: 7px; background: #262a45; color: #fff; font-weight: 700; display: grid; place-items: center; font-variant-numeric: tabular-nums; }
.pf-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; }
.pf-kind { margin-top: 6px; font-weight: 600; font-size: 12px; color: var(--text-2); display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.pf-ai .pf-kind { color: #5b37b5; }
.pf-line { margin-top: 5px; color: var(--text-2); }
.pf-role { margin-top: 6px; font-size: 12.5px; line-height: 1.4; }
.pf-role-full { margin-top: 4px; font-size: 12.5px; white-space: pre-wrap; background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; }
.pf-more { border: 0; background: none; padding: 0; color: var(--accent-600); font: inherit; cursor: pointer; text-decoration: underline; }
.pf-can { margin: 6px 0 0; padding-left: 16px; color: var(--text-2); }
.pf-can li { margin: 1px 0; }
.pf-ends { margin-top: 8px; padding-top: 6px; border-top: 1px dashed var(--border); font-size: 12px; color: var(--muted); }
/* drop 143: a voicemail's player under its row in Messages */
.bubble-voicemail { display: flex; align-items: center; gap: 10px; margin-top: 6px; flex-wrap: wrap; }
.bubble-voicemail audio { height: 32px; max-width: 280px; }
/* drop 145: the timeline across projects - a person's row, their load, the weekends */
.g-group { background: var(--surface-2); }
.g-group .g-title { font-size: 13.5px; }
.g-load { position: absolute; top: 4px; bottom: 4px; border-radius: 3px; z-index: 1; }
.g-load-2 { background: #fcd34d; }
.g-load-3 { background: #f87171; }
.g-key.g-load-2 { background: #fcd34d; }
.g-key.g-load-3 { background: #f87171; }
.g-weekend { position: absolute; top: 0; bottom: 0; background: rgba(15, 23, 42, .035); }

