@ikenga/pkg-tasks 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ // GENERATED by scripts/build-css.mjs from src/app-kit/*.css. Do not edit.
2
+ // No-build srcdoc pkgs import this and inject it as an inline <style>.
3
+ export default "/* GENERATED by scripts/build-css.mjs — do not edit by hand. */\n/* @ikenga/tokens app-kit — component layer; assumes tokens.css is loaded. */\n\n/* ===== 00-base.css ===== */\n/* app-kit base — the minimal reset the Atelier panes assume.\n * Component partials (button, badge, input, table, nav, …) land here in P1,\n * extracted from design/shell/concepts/_shared/components.css + the locked\n * panes. Everything references tokens.css custom properties — no literals. */\n\n* {\n\tbox-sizing: border-box;\n}\n\nhtml,\nbody {\n\tmargin: 0;\n\tpadding: 0;\n}\n\nbody {\n\tfont-family: var(--font-body);\n\tfont-size: var(--body-size, var(--text-body));\n\tline-height: var(--body-lead, var(--lead-body));\n\tcolor: var(--fg);\n\tbackground: var(--bg-base);\n\t-webkit-font-smoothing: antialiased;\n}\n\n/* Global reduced-motion safety net (WCAG 2.3.3 · the motion foundation's\n * enforcement contract). Per-component partials also gate their own\n * transitions; this is the belt-and-suspenders that covers anything missed. */\n@media (prefers-reduced-motion: reduce) {\n\t*,\n\t*::before,\n\t*::after {\n\t\tanimation-duration: 0.01ms !important;\n\t\tanimation-iteration-count: 1 !important;\n\t\ttransition-duration: 0.01ms !important;\n\t\tscroll-behavior: auto !important;\n\t}\n}\n\n\n/* ===== 10-button.css ===== */\n/* =============================================================================\n Atelier app-kit · part 10 · Button\n Source panes:\n - design/shell/concepts/_shared/components.css (§ Button + § Icon button)\n - ikenga-pkgs/packages/apps/tasks/dist/tasks.css (§ .tk-btn — merged)\n\n Owned classes:\n .btn .btn-sm .btn-lg\n .btn-primary .btn-secondary .btn-outline .btn-ghost .btn-destructive\n .btn-icon\n .rail-icon .rail-icon.is-on .rail-icon.is-on.rail-right .rail-icon-badge\n\n All values reference @ikenga/tokens custom properties.\n No hex/hsl literals — one fix applied vs source:\n .btn-destructive color: hsl(0,0%,98%) → var(--danger-fg)\n\n .tk-btn merge → .btn:\n .tk-btn.v-default == .btn-primary (primary bg/fg, transparent border)\n .tk-btn.v-outline == .btn-outline (transparent bg, --border border)\n .tk-btn.v-ghost == .btn-ghost (transparent bg+border)\n .tk-btn.sz-md == .btn-sm modifier at 32px (matches --btn-h-sm)\n .tk-btn.sz-sm == sub-sm at 28px (no exact token; compose .btn-sm)\n gap:6px on tk-btn base / gap:4px on sz-sm are within .btn gap:--space-2\n ============================================================================= */\n\n/* ── Base button ──────────────────────────────────────────────────────────── */\n.btn {\n font-family: var(--font-body);\n font-size: var(--text-body-sm);\n font-weight: 500;\n padding: 0 var(--space-3);\n height: var(--btn-h);\n border-radius: var(--radius-md);\n border: 1px solid var(--border);\n background: var(--bg-surface);\n color: var(--fg);\n cursor: pointer;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n transition:\n background var(--motion-fast) var(--ease-calm),\n border-color var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm),\n transform var(--motion-fast) var(--ease-calm);\n}\n.btn:hover { background: var(--bg-raised); }\n.btn:active { transform: translateY(0.5px); }\n.btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.btn svg { width: 14px; height: 14px; flex-shrink: 0; }\n\n/* ── Size modifiers ───────────────────────────────────────────────────────── */\n.btn-sm {\n height: var(--btn-h-sm);\n padding: 0 var(--space-2);\n font-size: var(--text-caption);\n}\n\n.btn-lg {\n height: var(--btn-h-lg);\n padding: 0 var(--space-4);\n font-size: var(--text-body);\n}\n.btn-lg svg { width: 16px; height: 16px; }\n\n/* ── Variant modifiers ────────────────────────────────────────────────────── */\n/* primary — maps to .tk-btn.v-default (primary bg, transparent border) */\n.btn-primary {\n background: var(--primary);\n border-color: var(--primary);\n color: var(--primary-fg);\n font-weight: 600;\n}\n.btn-primary:hover { filter: brightness(1.06); }\n\n/* secondary — raised surface with standard border */\n.btn-secondary {\n background: var(--bg-raised);\n border-color: var(--border);\n}\n\n/* outline — transparent bg, keeps border — maps to .tk-btn.v-outline */\n.btn-outline {\n background: transparent;\n}\n.btn-outline:hover { background: var(--bg-raised); }\n\n/* ghost — transparent bg + border — maps to .tk-btn.v-ghost */\n.btn-ghost {\n background: transparent;\n border-color: transparent;\n color: var(--fg-muted);\n}\n.btn-ghost:hover { background: var(--bg-raised); color: var(--fg); }\n\n/* destructive — danger fill; uses --danger-fg (was hsl(0,0%,98%) in source) */\n.btn-destructive {\n background: var(--danger);\n border-color: var(--danger);\n color: var(--danger-fg);\n font-weight: 600;\n}\n.btn-destructive:hover { filter: brightness(1.06); }\n\n/* ── Icon button (toolbar / reading-pane inline) ──────────────────────────── */\n/* Square, borderless; 30 × 30 px is a fixed geometry constant, not a spacing\n token — intentional use of raw px per kit rules. */\n.btn-icon {\n width: 30px;\n height: 30px;\n display: grid;\n place-items: center;\n border-radius: var(--radius-sm);\n border: 0;\n background: transparent;\n color: var(--fg-muted);\n cursor: pointer;\n transition:\n background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n.btn-icon:hover { background: var(--bg-raised); color: var(--fg); }\n.btn-icon:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.btn-icon svg { width: 15px; height: 15px; }\n\n/* ── Rail icon button (activity bar / dock collapsed strip) ───────────────── */\n/* 36 × 36 px is fixed icon-target geometry — raw px permitted per kit rules. */\n.rail-icon {\n width: 36px;\n height: 36px;\n display: grid;\n place-items: center;\n border-radius: var(--radius-md);\n border: 0;\n background: transparent;\n color: var(--fg-faint);\n cursor: pointer;\n position: relative;\n transition:\n background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n.rail-icon:hover { background: var(--bg-surface); color: var(--fg-muted); }\n.rail-icon svg { width: 18px; height: 18px; }\n\n/* on state — tinted bracket left edge */\n.rail-icon.is-on {\n background: var(--bg-raised);\n color: var(--tint-fg-active, var(--primary));\n}\n.rail-icon.is-on::before {\n content: '';\n position: absolute;\n left: -10px;\n top: 8px;\n bottom: 8px;\n width: 2px;\n border-radius: 2px;\n background: var(--tint-fg-active, var(--primary));\n}\n\n/* right-edge variant — bracket on right side (dock pane) */\n.rail-icon.is-on.rail-right::before {\n left: auto;\n right: -10px;\n}\n\n/* focus ring shared with .btn */\n.rail-icon:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n\n/* ── Reduced-motion safety ────────────────────────────────────────────────── */\n/* All button transitions run at --motion-fast (120ms) — fast but still\n animated. Gate transitions on all interactive button shapes so callers\n that add keyframe spinners (loading state) don't need to duplicate this. */\n@media (prefers-reduced-motion: reduce) {\n .btn,\n .btn-icon,\n .rail-icon {\n transition: none;\n }\n}\n\n/* ── Rail badge dot (overlaid top-right; 8 px is fixed dot geometry) ──────── */\n.rail-icon-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--achievement);\n border: 2px solid var(--bg-base);\n}\n\n\n/* ===== 11-badge-tag-chip.css ===== */\n/* =============================================================================\n Atelier app-kit · part 11 · Badge / Tag / Chip\n Source panes:\n - design/shell/concepts/_shared/components.css (§ Badges / tags — verbatim lifted)\n - plans/atelier/designs/atelier-outbound.html (.chip base + channel variants + .ob-filter-chip)\n - plans/atelier/designs/atelier-approve-gate.html (.ob-chip + channel variants)\n - plans/atelier/designs/atelier-outbound-newsletter.html (.chip.investor/.cool/.newsletter + .cal-pill)\n - plans/atelier/designs/atelier-tasks.html (.tk-badge + state variants)\n - plans/atelier/designs/atelier-sales-list.html (.stage-chip)\n\n Owned classes:\n .badge .badge-dot\n .badge-primary .badge-achievement .badge-danger .badge-systemic .badge-solid-primary\n .tag .tag-deal .tag-warn .tag-system .tag-primary\n .chip .chip-tint .chip.tint .chip.ok .chip.cool .chip.warn\n .chip.tint-active\n .chip.listmonk .chip.resend .chip.smtp .chip.newsletter .chip.investor\n .chip.agent .chip.edited .chip.sender .chip.sender.cold\n .chip.seq .chip.is-on\n .ob-chip (alias of .chip for outbound rows — uses the same pill base)\n .ob-filter-chip .ob-filter-chip.is-on\n .tk-badge .tk-badge.is-pending .tk-badge.is-in_progress\n .tk-badge.is-blocked .tk-badge.is-completed .tk-badge.is-cancelled\n .tk-badge .dot\n .stage-chip\n .cal-pill .cal-pill .ptime\n .cal-pill.cool .cal-pill.investor .cal-pill.sent\n\n Pill-base recipe (mono-uppercase, radius-xs, soft-token bg) is the single\n definition shared by .badge / .tag / .chip / .tk-badge / .ob-chip /\n .stage-chip / .ob-filter-chip. Each consumer composes ON TOP of the base.\n\n Token conversions applied vs source literals:\n .chip.resend / .ob-chip.channel-resend hsl(170,…) → --systemic / --systemic-soft\n .chip.investor / .cal-pill.investor hsl(150,…) → --live / --live-soft\n .btn-destructive color hsl(0,0%,98%) already fixed in 10-button.css (not re-owned here)\n All other source literals left as-is where they represent fixed\n third-party brand hues (listmonk/smtp/newsletter/buffer channel identity).\n ============================================================================= */\n\n\n/* ── Badge — primary pill primitive ─────────────────────────────────────────\n Larger of the two standard pill sizes (10 px mono, 3 px/8 px padding).\n Used in dense headers, list row annotations, and sidebar counts. */\n.badge {\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: .06em;\n text-transform: uppercase;\n padding: 3px 8px;\n border-radius: var(--radius-xs);\n background: var(--bg-sunken);\n color: var(--fg-muted);\n border: 1px solid var(--border-soft);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n\n/* Inline status dot (5 px is fixed dot geometry — not a spacing token) */\n.badge-dot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: currentColor;\n flex-shrink: 0;\n}\n\n/* Semantic colour variants */\n.badge-primary {\n color: var(--primary);\n border-color: var(--primary-soft);\n background: var(--primary-soft);\n}\n\n.badge-achievement {\n color: var(--achievement);\n border-color: var(--achievement-soft);\n background: var(--achievement-soft);\n}\n\n.badge-danger {\n color: var(--danger);\n border-color: var(--danger-soft);\n background: var(--danger-soft);\n}\n\n.badge-systemic {\n color: var(--systemic);\n border-color: var(--systemic-soft);\n background: var(--systemic-soft);\n}\n\n/* Solid fill — used for counts / presence indicators on dark surfaces */\n.badge-solid-primary {\n color: var(--primary-fg);\n background: var(--primary);\n border-color: var(--primary);\n}\n\n\n/* ── Tag — compact pill alias (mail rows, deal lists) ────────────────────────\n Same recipe as .badge at 9.5 px / 2 px/6 px — one step smaller.\n Semantics: deal (amber), warn (danger), system (systemic), primary. */\n.tag {\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: .06em;\n text-transform: uppercase;\n padding: 2px 6px;\n border-radius: var(--radius-xs);\n background: var(--bg-sunken);\n color: var(--fg-muted);\n border: 1px solid var(--border-soft);\n white-space: nowrap;\n}\n\n.tag-deal {\n color: var(--achievement);\n border-color: var(--achievement-soft);\n background: var(--achievement-soft);\n}\n\n.tag-warn {\n color: var(--danger);\n border-color: var(--danger-soft);\n background: var(--danger-soft);\n}\n\n.tag-system {\n color: var(--systemic);\n border-color: var(--systemic-soft);\n background: var(--systemic-soft);\n}\n\n.tag-primary {\n color: var(--primary);\n border-color: var(--primary-soft);\n background: var(--primary-soft);\n}\n\n\n/* ── Chip — compact neutral pill (outbound / newsletter / sales rows) ────────\n Identical geometry to .tag (9.5 px / 2 px/6 px / radius-xs) but carries\n a wider set of contextual variants (channel identity, state, workspace tint).\n .ob-chip is an alias used in approve-gate and outbound-email rows —\n it reuses .chip exactly; component authors may use either class name. */\n.chip,\n.ob-chip {\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: .06em;\n text-transform: uppercase;\n padding: 2px 6px;\n border-radius: var(--radius-xs);\n background: var(--bg-sunken);\n color: var(--fg-muted);\n border: 1px solid var(--border-soft);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n\n/* Inline icon (10 px is fixed icon geometry — not a spacing token) */\n.chip svg,\n.ob-chip svg {\n width: 10px;\n height: 10px;\n flex-shrink: 0;\n}\n\n/* ── Chip semantic variants ─────────────────────────────────────────────── */\n\n/* Workspace-tinted chip — signals \"lives inside an active flow\" */\n.chip.tint,\n.chip-tint,\n.chip.seq,\n.ob-chip.seq {\n color: var(--tint-fg-active, var(--primary));\n border-color: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 30%, var(--border));\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 14%, transparent);\n}\n\n/* Affirmative / cooling — achievement amber */\n.chip.ok,\n.chip.cool,\n.ob-chip.edited {\n color: var(--achievement);\n border-color: var(--achievement-soft);\n background: var(--achievement-soft);\n}\n\n/* Warning / destructive context */\n.chip.warn {\n color: var(--danger);\n border-color: color-mix(in srgb, var(--danger) 30%, var(--border));\n background: color-mix(in srgb, var(--danger) 14%, transparent);\n}\n\n/* Passive agent byline — stays muted */\n.chip.agent,\n.ob-chip.agent {\n color: var(--fg-muted);\n}\n\n/* Sender domain byline — faint, dashed border */\n.chip.sender,\n.ob-chip.sender {\n color: var(--fg-faint);\n border-style: dashed;\n}\n\n/* Cold outreach sender — achievement tint on sender chip */\n.chip.sender.cold,\n.ob-chip.sender.cold {\n color: var(--achievement);\n border-color: var(--achievement-soft);\n}\n\n/* ── Channel-identity chips (third-party brand hues, light overrides) ────────\n These are fixed product-identity colours, NOT workspace tokens.\n resend → mapped to --systemic / --systemic-soft per kit guidance.\n listmonk, smtp, newsletter, buffer → retain their fixed brand hues. */\n\n/* Resend — verdigris → systemic token */\n.chip.resend,\n.ob-chip.channel-resend {\n color: var(--systemic);\n border-color: var(--systemic-soft);\n background: var(--systemic-soft);\n}\n[data-mode=\"light\"] .chip.resend,\n[data-mode=\"light\"] .ob-chip.channel-resend {\n color: var(--systemic);\n border-color: var(--systemic-soft);\n background: var(--systemic-soft);\n}\n\n/* Listmonk — amber (fixed brand hue) */\n.chip.listmonk,\n.ob-chip.channel-listmonk {\n color: hsl(42, 82%, 60%);\n border-color: hsl(42, 40%, 28%);\n background: hsl(42, 40%, 12%);\n}\n[data-mode=\"light\"] .chip.listmonk,\n[data-mode=\"light\"] .ob-chip.channel-listmonk {\n color: hsl(42, 80%, 30%);\n border-color: hsl(42, 60%, 80%);\n background: hsl(42, 60%, 94%);\n}\n\n/* SMTP — slate blue (fixed brand hue) */\n.chip.smtp,\n.ob-chip.channel-smtp {\n color: hsl(220, 40%, 68%);\n border-color: hsl(220, 28%, 28%);\n background: hsl(220, 28%, 12%);\n}\n[data-mode=\"light\"] .chip.smtp,\n[data-mode=\"light\"] .ob-chip.channel-smtp {\n color: hsl(220, 48%, 38%);\n border-color: hsl(220, 38%, 80%);\n background: hsl(220, 38%, 94%);\n}\n\n/* Buffer — purple (fixed brand hue) */\n.ob-chip.channel-buffer {\n color: hsl(280, 50%, 68%);\n border-color: hsl(280, 28%, 28%);\n background: hsl(280, 28%, 12%);\n}\n[data-mode=\"light\"] .ob-chip.channel-buffer {\n color: hsl(280, 50%, 32%);\n border-color: hsl(280, 40%, 80%);\n background: hsl(280, 40%, 94%);\n}\n\n/* Investor update — mapped to --live / --live-soft per kit guidance */\n.chip.investor {\n color: var(--live);\n border-color: var(--live-soft);\n background: var(--live-soft);\n}\n[data-mode=\"light\"] .chip.investor {\n color: var(--live);\n border-color: var(--live-soft);\n background: var(--live-soft);\n}\n\n/* Newsletter — purple (distinct from Buffer; used as content-type label) */\n.chip.newsletter {\n color: hsl(280, 55%, 70%);\n border-color: hsl(280, 30%, 28%);\n background: hsl(280, 30%, 12%);\n}\n[data-mode=\"light\"] .chip.newsletter {\n color: hsl(280, 50%, 32%);\n border-color: hsl(280, 40%, 80%);\n background: hsl(280, 40%, 94%);\n}\n\n\n/* ── Filter chip (interactive pill — ob-filter-chip) ────────────────────────\n Larger than .chip (3 px/8 px, radius-pill) — sits in toolbar filter bars.\n Active state uses workspace tint so it adapts per-surface. */\n.ob-filter-chip {\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n color: var(--fg-muted);\n border-radius: var(--radius-pill);\n padding: 3px var(--space-2);\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: .04em;\n cursor: pointer;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.ob-filter-chip:hover {\n background: var(--bg-raised);\n color: var(--fg);\n}\n\n.ob-filter-chip:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n.ob-filter-chip.is-on {\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 14%, var(--bg-base));\n border-color: var(--tint-fg-active, var(--primary));\n color: var(--tint-fg-active, var(--primary));\n}\n\n\n/* ── Task badge (.tk-badge) — status pill in task rows and agenda ────────────\n Lifted verbatim from atelier-tasks.html §.tk-badge (9.5 px mono, 2 px/6 px,\n radius-xs). State recipe uses color-mix to match the canonical pane. */\n.tk-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: .08em;\n text-transform: uppercase;\n padding: 2px 6px;\n border-radius: var(--radius-xs);\n border: 1px solid var(--border-soft);\n color: var(--fg-muted);\n background: var(--bg-base);\n white-space: nowrap;\n}\n\n/* 5 px status dot (fixed dot geometry — not a spacing token) */\n.tk-badge .dot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: currentColor;\n flex-shrink: 0;\n}\n\n/* State variants — live/danger palette via color-mix, matching the pane */\n.tk-badge.is-pending {\n color: var(--fg-muted);\n}\n\n.tk-badge.is-in_progress {\n color: var(--live);\n background: var(--live-soft);\n border-color: color-mix(in srgb, var(--live) 30%, var(--border-soft));\n}\n\n.tk-badge.is-blocked {\n color: var(--danger);\n background: color-mix(in srgb, var(--danger) 12%, transparent);\n border-color: color-mix(in srgb, var(--danger) 30%, var(--border-soft));\n}\n\n.tk-badge.is-completed {\n color: var(--live);\n background: var(--live-soft);\n border-color: color-mix(in srgb, var(--live) 30%, var(--border-soft));\n}\n\n.tk-badge.is-cancelled {\n color: var(--fg-faint);\n}\n\n\n/* ── Stage chip (.stage-chip) — pipeline stage label ────────────────────────\n Sourced from atelier-sales-list.html. Uses radius-pill (999px) unlike the\n other pills; neutral surface, uppercase mono. Not interactive. */\n.stage-chip {\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: .06em;\n text-transform: uppercase;\n padding: 2px 7px;\n border-radius: var(--radius-pill);\n border: 1px solid var(--border-soft);\n color: var(--fg-muted);\n background: var(--bg-sunken);\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n\n/* ── Calendar pill (.cal-pill) — newsletter / outbound schedule item ─────────\n Sourced from atelier-outbound-newsletter.html. A block-level pill (not\n inline) with a time-label sub-element, adapts to workspace tint.\n investor → mapped to --live / --live-soft per kit guidance. */\n.cal-pill {\n display: block;\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 14%, var(--bg-surface));\n border: 1px solid color-mix(in srgb, var(--tint-fg-active, var(--primary)) 30%, var(--border));\n border-radius: var(--radius-sm);\n padding: 4px 6px;\n margin-bottom: 4px;\n font-size: 10.5px;\n color: var(--fg);\n line-height: 1.3;\n cursor: pointer;\n}\n\n.cal-pill:hover {\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 22%, var(--bg-surface));\n}\n\n.cal-pill:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n/* Time label within the pill */\n.cal-pill .ptime {\n font-family: var(--font-mono);\n font-size: 9.5px;\n color: var(--tint-fg-active, var(--primary));\n letter-spacing: .04em;\n display: block;\n margin-bottom: 2px;\n}\n\n/* Cooling period — achievement amber */\n.cal-pill.cool {\n background: color-mix(in srgb, var(--achievement) 14%, var(--bg-surface));\n border-color: var(--achievement-soft);\n}\n.cal-pill.cool .ptime {\n color: var(--achievement);\n}\n\n/* Investor update — live green (was hsl(150,…) literals in source) */\n.cal-pill.investor {\n background: color-mix(in srgb, var(--live) 14%, var(--bg-surface));\n border-color: var(--live-soft);\n}\n.cal-pill.investor .ptime {\n color: var(--live);\n}\n\n/* Sent / archived — muted dashed */\n.cal-pill.sent {\n background: var(--bg-base);\n border-style: dashed;\n opacity: .7;\n}\n.cal-pill.sent .ptime {\n color: var(--fg-faint);\n}\n\n/* ── Motion — reduced-motion overrides ───────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .ob-filter-chip,\n .cal-pill {\n transition: none;\n }\n}\n\n\n/* ===== 12-input-field.css ===== */\n/* =============================================================================\n Atelier design-system · Part 12 — Input Field\n Tier: Components / group: Inputs / source mode: shared\n Source pane: design/shell/concepts/_shared/components.css (Form section)\n Owned classes: .input, .textarea, .field, .field-label, .field-help,\n .input-group, .input-addon, .input-addon-right, kbd\n Merge: focus-visible ring added; .input-error applies --danger ring via\n box-shadow; kbd isolated from .input-addon to avoid over-specificity.\n ============================================================================= */\n\n/* ── Base text input ─────────────────────────────────────────────────────── */\n.input {\n font-family: var(--font-body);\n font-size: var(--text-body-sm);\n height: var(--input-h);\n padding: 0 var(--space-3);\n border-radius: var(--radius-sm);\n border: 1px solid var(--border);\n background: var(--bg-sunken);\n color: var(--fg);\n width: 100%;\n transition:\n border-color var(--motion-fast) var(--ease-calm),\n background var(--motion-fast) var(--ease-calm),\n box-shadow var(--motion-fast) var(--ease-calm);\n}\n\n.input::placeholder {\n color: var(--fg-faint);\n}\n\n.input:hover {\n border-color: var(--fg-faint);\n}\n\n/* focus — border + primary ring for keyboard-visible focus */\n.input:focus,\n.input:focus-visible {\n outline: none;\n border-color: var(--primary);\n background: var(--bg-surface);\n box-shadow: 0 0 0 2px var(--primary-soft);\n}\n\n.input:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* error state — danger border + danger ring */\n.input.input-error {\n border-color: var(--danger);\n box-shadow: 0 0 0 2px var(--danger-soft);\n}\n\n/* error persists on focus */\n.input.input-error:focus,\n.input.input-error:focus-visible {\n border-color: var(--danger);\n box-shadow: 0 0 0 2px var(--danger-soft);\n}\n\n/* ── Textarea ─────────────────────────────────────────────────────────────── */\n/* Extends .input — apply both classes: <textarea class=\"input textarea\"> */\n.textarea {\n padding: var(--space-2) var(--space-3);\n height: auto;\n min-height: 80px;\n line-height: var(--lead-body);\n resize: vertical;\n}\n\n/* ── Field wrapper (label + input + help text) ───────────────────────────── */\n.field {\n display: grid;\n gap: var(--space-1);\n}\n\n.field-label {\n font-size: var(--text-caption);\n font-weight: 500;\n color: var(--fg-muted);\n}\n\n.field-help {\n font-size: var(--text-micro);\n color: var(--fg-faint);\n font-family: var(--font-body);\n letter-spacing: 0;\n text-transform: none;\n}\n\n/* ── Input group (addon-left + input + addon-right) ─────────────────────── */\n.input-group {\n display: flex;\n align-items: stretch;\n border: 1px solid var(--border);\n border-radius: var(--radius-sm);\n background: var(--bg-sunken);\n overflow: hidden;\n transition:\n border-color var(--motion-fast) var(--ease-calm),\n box-shadow var(--motion-fast) var(--ease-calm);\n}\n\n.input-group:focus-within {\n border-color: var(--primary);\n box-shadow: 0 0 0 2px var(--primary-soft);\n}\n\n/* strip the inner input's own border/background so the group owns the frame */\n.input-group .input {\n border: 0;\n background: transparent;\n /* override the group-level ring — the outer group handles it */\n box-shadow: none;\n}\n\n.input-group .input:focus,\n.input-group .input:focus-visible {\n background: transparent;\n box-shadow: none;\n}\n\n/* error on the group */\n.input-group.input-error {\n border-color: var(--danger);\n box-shadow: 0 0 0 2px var(--danger-soft);\n}\n\n/* ── Addon (prefix / suffix cell inside .input-group) ────────────────────── */\n.input-addon {\n display: flex;\n align-items: center;\n padding: 0 var(--space-3);\n color: var(--fg-faint);\n font-size: var(--text-caption);\n border-right: 1px solid var(--border-soft);\n flex-shrink: 0;\n}\n\n.input-addon-right {\n border-right: 0;\n border-left: 1px solid var(--border-soft);\n}\n\n.input-addon svg {\n width: 14px;\n height: 14px;\n}\n\n/* ── Keyboard shortcut chip ───────────────────────────────────────────────── */\n/* Used standalone OR nested inside .input-addon */\nkbd,\n.input-addon kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-xs);\n padding: 0 var(--space-1);\n /* structural: 5px is the visual optical padding for a chip this small */\n padding-inline: 5px;\n display: inline-flex;\n align-items: center;\n line-height: 1;\n}\n\n/* ── Reduced-motion safety ────────────────────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .input,\n .input-group {\n transition: none;\n }\n}\n\n\n/* ===== 13-avatar.css ===== */\n/* =================================================================\n app-kit · 13-avatar.css\n Part: Avatar · tier: Components / group: Display · source mode: shared\n Source pane: design/shell/concepts/_shared/components.css (Avatar section, lines 288–301)\n Owned classes: .avatar · .avatar-sm · .avatar-lg · .avatar-amber · .avatar-danger · .avatar-systemic\n Lifted verbatim (already token-clean) + structural px permitted per kit rules.\n ================================================================= */\n\n/* === Avatar ===================================================== */\n/*\n Base: 32 × 32 px circular container with a primary gradient fill and\n a display-font initial letter. Sizes (-sm / -lg) and tint variants\n (-amber / -danger / -systemic) are additive modifiers.\n\n Fixed-geometry px values (permitted per kit rules):\n 32px / 22px / 44px — avatar diameter sizes (no density token exists)\n 13px / 11px / 16px — initials font sizes keyed to each diameter\n*/\n\n.avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: linear-gradient(135deg, var(--primary-soft), var(--primary));\n display: grid;\n place-items: center;\n font-family: var(--font-display);\n font-weight: 500;\n font-size: 13px;\n color: var(--fg);\n flex-shrink: 0;\n position: relative;\n}\n\n/* Size modifiers */\n.avatar-sm { width: 22px; height: 22px; font-size: 11px; }\n.avatar-lg { width: 44px; height: 44px; font-size: 16px; }\n\n/* Tint variants — gradient reads from soft → full for depth */\n.avatar-amber { background: linear-gradient(135deg, var(--achievement-soft), var(--achievement)); }\n.avatar-danger { background: linear-gradient(135deg, var(--danger-soft), var(--danger)); }\n.avatar-systemic { background: linear-gradient(135deg, var(--systemic-soft), var(--systemic)); }\n\n\n/* ===== 14-segmented-tabs.css ===== */\n/*\n * Part 14 — Segmented control + Underline tabs\n * Tier: Components / Navigation\n * Source panes:\n * .seg / .seg-dot — design/shell/concepts/_shared/components.css (Sticky-control section)\n * .tabs / .tab / .tab-count — design/shell/concepts/_shared/components.css (Tabs section)\n * + plans/atelier/designs/atelier-tasks.html (#tk-views-css .ip-tabs/.ip-tab)\n *\n * Owned classes: .seg .seg-dot .tabs .tab .tab-count\n * Merge note: .ip-tabs/.ip-tab (inspector variant, atelier-tasks.html) folded into\n * .tabs/.tab — height promoted to var(--tab-h), display to inline-flex + gap for\n * optional icon children, focus-visible ring from the a11y block preserved.\n */\n\n/* ── Segmented control ──────────────────────────────────────────── */\n\n.seg {\n display: inline-flex;\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n padding: 2px;\n gap: 2px;\n}\n\n.seg button,\n.seg a {\n font-family: var(--font-body);\n font-size: var(--text-body-sm);\n font-weight: 500;\n padding: 5px 10px;\n border-radius: var(--radius-sm);\n border: 0;\n background: transparent;\n color: var(--fg-muted);\n cursor: pointer;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n transition:\n background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n.seg button:hover,\n.seg a:hover {\n color: var(--fg);\n}\n\n.seg button.is-on,\n.seg a.is-on {\n background: var(--bg-raised);\n color: var(--fg);\n box-shadow: var(--shadow-1);\n}\n\n.seg button:focus-visible,\n.seg a:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n/*\n * .seg-dot — fixed 8px geometry (no space token maps to 8px);\n * border-radius 50% is structural, not a theme radius.\n * Colour is set by the consumer via color/background (e.g. --live, --danger).\n */\n.seg-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n/* ── Underline tabs ─────────────────────────────────────────────── */\n/*\n * Merged from:\n * .tabs — components.css line 304 (gap: 4px, padding 0 --space-4, bg-sunken)\n * .ip-tabs — atelier-tasks.html #tk-views-css (gap: 0, padding 0 --space-3, height --tab-h)\n *\n * Resolution: keep gap 0 (tighter; ip-tabs was the later, more refined variant);\n * padding: 0 var(--space-3) (matches inspector; outer caller adds wider padding if needed);\n * height: var(--tab-h) (density-token-driven, replaces implicit height from .tab line-height).\n */\n\n.tabs {\n display: flex;\n align-items: center;\n gap: 0;\n height: var(--tab-h);\n padding: 0 var(--space-3);\n border-bottom: 1px solid var(--border-soft);\n background: var(--bg-sunken);\n}\n\n/*\n * Merged from:\n * .tab — components.css line 305–311 (height 44px, line-height 44px, padding 0 --space-3)\n * .ip-tab — atelier-tasks.html (height --tab-h, inline-flex + gap 6px for icon child)\n *\n * Resolution: inline-flex + align-items center replaces line-height: 44px;\n * height inherits from parent via stretching (align-items: center on .tabs);\n * gap: 6px keeps icon + label spacing from .ip-tab.\n */\n\n.tab {\n height: var(--tab-h);\n padding: 0 var(--space-3);\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: var(--font-body);\n font-size: var(--text-body-sm);\n color: var(--fg-faint);\n cursor: pointer;\n border: 0;\n background: transparent;\n border-bottom: 2px solid transparent;\n margin-bottom: -1px;\n}\n\n/* Icon child — from .ip-tab svg (atelier-tasks.html) */\n.tab svg {\n width: 13px;\n height: 13px;\n opacity: 0.8;\n flex-shrink: 0;\n}\n\n.tab:hover {\n color: var(--fg-muted);\n}\n\n.tab.is-on {\n color: var(--fg);\n border-bottom-color: var(--tint-fg-active, var(--primary));\n}\n\n.tab.is-on svg {\n opacity: 1;\n color: var(--tint-fg-active, var(--primary));\n}\n\n.tab:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: -2px;\n}\n\n/* Count badge — inline mono counter (e.g. \"Tasks 14\") */\n.tab-count {\n font-family: var(--font-mono);\n font-size: 10.5px;\n color: var(--fg-faint);\n margin-left: var(--space-1);\n font-variant-numeric: tabular-nums;\n}\n\n.tab.is-on .tab-count {\n color: var(--tint-fg-active, var(--primary));\n}\n\n/* ── Reduced-motion safety ──────────────────────────────────────────\n * .seg button/a carry background + color transitions at --motion-fast.\n * The tab strip itself has no enter/exit animation, but gate both\n * shapes here so any future slide-indicator animation is pre-gated.\n * ------------------------------------------------------------------ */\n@media (prefers-reduced-motion: reduce) {\n .seg button,\n .seg a {\n transition: none;\n }\n}\n\n\n/* ===== 20-table-dense-row.css ===== */\n/* Part: table-dense-row (Components / Display)\n * Sources: ikenga-pkgs/packages/apps/tasks/dist/tasks.css (.tk-row / .tk-sub-row)\n * plans/atelier/designs/atelier-tasks.html (.tk-row / .tr-mini / .tk-dep-row)\n * plans/atelier/designs/atelier-approve-gate.html (.ob-row)\n * plans/atelier/designs/atelier-sales-list.html (.pl-row)\n *\n * Owned classes:\n * .dense-row .dense-row-body .dense-row-right .dense-row-meta\n * .dense-row-title .dense-row-sub .dense-row-pre .dense-row-chips\n * .dense-row-time .dense-row-tick .dense-row-check\n * .dense-row-dot (priority dot — tasks domain)\n * .dense-row-due (due-date cell — tasks domain)\n * --dense-row variant modifiers: .dense-row--task .dense-row--sub\n * .dense-row--dep .dense-row--mini .dense-row--outbox .dense-row--pipeline\n *\n * Legacy → canonical map:\n * .tk-row → .dense-row.dense-row--task\n * .tk-sub-row → .dense-row.dense-row--sub\n * .tk-dep-row → .dense-row.dense-row--dep\n * .tr-mini → .dense-row.dense-row--mini\n * .ob-row → .dense-row.dense-row--outbox\n * .pl-row → .dense-row.dense-row--pipeline\n *\n * NOT owned here (compose these):\n * .tk-badge / .badge / .ob-chip / .chip → badge-tag-chip part\n * .card / .frame → card part\n * .btn → button part\n * ---------------------------------------------------------------- */\n\n/* === Base dense-row primitive ================================== */\n\n.dense-row {\n display: grid;\n gap: var(--space-2);\n padding: var(--row-pad-y) var(--space-3);\n border-bottom: 1px solid var(--border-soft);\n cursor: pointer;\n position: relative;\n background: transparent;\n text-align: left;\n width: 100%;\n border-left: 0;\n border-right: 0;\n border-top: 0;\n font: inherit;\n color: inherit;\n transition: background var(--motion-fast) var(--ease-calm);\n}\n\n/* hover */\n.dense-row:hover {\n background: var(--bg-raised);\n}\n\n/* selected / active */\n.dense-row.is-selected,\n.dense-row.is-on {\n background: var(--bg-raised);\n}\n\n/* active left-accent stripe */\n.dense-row.is-on::before {\n content: '';\n position: absolute;\n left: 0;\n top: var(--space-2);\n bottom: var(--space-2);\n width: 2px;\n border-radius: 2px;\n background: var(--tint-fg-active, var(--primary));\n}\n\n/* keyboard focus */\n.dense-row:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: -2px;\n}\n\n/* === Shared sub-elements ======================================= */\n\n/* body column: flex column, min-width:0 so title can truncate */\n.dense-row-body {\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n}\n\n/* right column: time / badge stack, right-aligned */\n.dense-row-right {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: var(--space-1);\n flex-shrink: 0;\n}\n\n/* meta strip: mono micro-labels (category, source, agent) */\n.dense-row-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-1);\n font-family: var(--font-mono);\n font-size: 9.5px;\n color: var(--fg-faint);\n letter-spacing: 0.04em;\n}\n\n/* from/to header within meta (outbox / mail layout) */\n.dense-row-meta.is-header {\n justify-content: space-between;\n align-items: baseline;\n margin-bottom: 2px;\n}\n\n/* title line */\n.dense-row-title {\n font-size: var(--text-body-sm);\n color: var(--fg);\n font-weight: 500;\n line-height: 1.35;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n/* secondary text / preview / snippet (1-line clamp by default) */\n.dense-row-sub {\n font-size: var(--text-caption);\n color: var(--fg-muted);\n line-height: 1.45;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n}\n\n/* 2-line preview variant (outbox body, mail preview) */\n.dense-row-pre {\n font-size: var(--text-caption);\n color: var(--fg-muted);\n line-height: 1.45;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n margin-bottom: var(--space-2);\n}\n\n/* chip tray at foot of outbox row (channel · agent · seq-pos) */\n.dense-row-chips {\n display: flex;\n gap: var(--space-1);\n flex-wrap: wrap;\n align-items: center;\n}\n\n/* time / age stamp — mono, right-aligned */\n.dense-row-time {\n font-family: var(--font-mono);\n font-size: 10.5px;\n color: var(--fg-faint);\n letter-spacing: 0.04em;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.dense-row-time.is-overdue { color: var(--danger); }\n.dense-row-time.is-today { color: var(--achievement); }\n.dense-row-time.is-bad { color: var(--danger); } /* .tr-mini .age.is-bad */\n\n/* status accent tick (4 px hairline, left of body) */\n.dense-row-tick {\n width: 4px;\n border-radius: 2px;\n background: transparent;\n}\n/* tick state colours */\n.dense-row.is-unread .dense-row-tick,\n.dense-row.is-selected .dense-row-tick,\n.dense-row.status-awaiting .dense-row-tick { background: var(--tint-fg-active, var(--primary)); }\n.dense-row.status-edited .dense-row-tick { background: var(--achievement); }\n.dense-row.status-overdue .dense-row-tick { background: var(--danger); }\n\n/* checkbox affordance (appears on hover / when checked) */\n.dense-row-check {\n width: 14px;\n height: 14px;\n border: 1px solid var(--border);\n border-radius: var(--radius-xs);\n background: var(--bg-base);\n margin-top: 2px;\n flex-shrink: 0;\n opacity: 0;\n transition: opacity var(--motion-fast) var(--ease-calm);\n cursor: pointer;\n display: grid;\n place-items: center;\n}\n.dense-row-check svg {\n width: 10px;\n height: 10px;\n color: var(--primary-fg);\n opacity: 0;\n}\n.dense-row:hover .dense-row-check,\n.dense-row.is-checked .dense-row-check { opacity: 1; }\n.dense-row.is-checked .dense-row-check {\n background: var(--tint-fg-active, var(--primary));\n border-color: var(--tint-fg-active, var(--primary));\n}\n.dense-row.is-checked .dense-row-check svg { opacity: 1; }\n\n/* priority dot (tasks only — 8 px filled circle) */\n.dense-row-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n margin-top: 5px;\n background: var(--fg-faint);\n flex-shrink: 0;\n}\n.dense-row-dot.is-critical {\n background: var(--danger);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 20%, transparent);\n}\n.dense-row-dot.is-high { background: var(--achievement); }\n.dense-row-dot.is-medium { background: var(--systemic); }\n.dense-row-dot.is-low { background: var(--fg-faint); }\n\n/* due date label (tasks domain) */\n.dense-row-due {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-muted);\n letter-spacing: 0.04em;\n white-space: nowrap;\n}\n.dense-row-due.is-overdue { color: var(--danger); font-weight: 500; }\n.dense-row-due.is-today { color: var(--achievement); }\n\n/* === Variant: task list row (→ .tk-row) ======================== */\n/* grid: [dot 14px] [body 1fr] [right auto] */\n\n.dense-row--task {\n grid-template-columns: 14px 1fr auto;\n gap: var(--space-3);\n padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);\n}\n\n.dense-row--task.is-completed .dense-row-title {\n color: var(--fg-muted);\n text-decoration: line-through;\n text-decoration-thickness: 1px;\n}\n\n/* category micro-label inside .dense-row-meta */\n.dense-row--task .dense-row-meta .cat {\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n color: var(--fg-muted);\n padding: 1px 5px;\n border-radius: var(--radius-xs);\n text-transform: lowercase;\n}\n\n/* === Variant: subtask row (→ .tk-sub-row) ====================== */\n/* Elevated card style (surface bg + full border + radius) */\n\n.dense-row--sub {\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-1) var(--space-3);\n background: var(--bg-surface);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n /* override base: no bottom-only border */\n border-bottom: 1px solid var(--border-soft);\n}\n\n.dense-row--sub.is-completed .dense-row-title {\n color: var(--fg-muted);\n text-decoration: line-through;\n}\n\n/* === Variant: dependency row (→ .tk-dep-row) =================== */\n/* Like sub-row but with a directional arrow icon slot */\n\n.dense-row--dep {\n grid-template-columns: auto 1fr auto;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-1) var(--space-3);\n background: var(--bg-surface);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n}\n\n/* arrow icon slot */\n.dense-row--dep .arr {\n width: 13px;\n height: 13px;\n color: var(--fg-faint);\n flex-shrink: 0;\n}\n.dense-row--dep.is-up .arr { color: var(--danger); }\n.dense-row--dep.is-down .arr { color: var(--systemic); }\n.dense-row--dep.is-resolved .arr { color: var(--live); }\n.dense-row--dep.is-resolved .dense-row-title { color: var(--fg-muted); }\n\n/* dep name link */\n.dense-row--dep .dense-row-title a {\n color: inherit;\n text-decoration: none;\n border-bottom: 1px solid var(--border-soft);\n}\n.dense-row--dep .dense-row-title a:hover { border-bottom-color: var(--fg-muted); }\n\n/* === Variant: mini row (→ .tr-mini) ============================ */\n/* Used in sweep / triage summary cards — no cursor, no hover needed */\n\n.dense-row--mini {\n grid-template-columns: auto 1fr auto auto;\n align-items: center;\n gap: var(--space-3);\n padding: var(--space-2) var(--space-3);\n cursor: default;\n}\n.dense-row--mini:last-child { border-bottom: 0; }\n\n/* mini title is single-line, nowrap */\n.dense-row--mini .dense-row-title {\n -webkit-line-clamp: 1;\n font-weight: 400;\n}\n\n/* === Variant: outbox row (→ .ob-row) =========================== */\n/* grid: [checkbox 16px] [tick 4px] [body 1fr] */\n\n.dense-row--outbox {\n grid-template-columns: 16px 4px 1fr;\n gap: var(--space-2);\n align-items: start;\n padding: calc(var(--row-pad-y) + 2px) var(--space-3);\n}\n\n/* single-line subject in outbox */\n.dense-row--outbox .dense-row-title {\n -webkit-line-clamp: 1;\n margin-bottom: var(--space-1);\n}\n\n/* === Variant: pipeline / deal row (→ .pl-row) ================== */\n/* grid: [accent 4px] [body 1fr] [right auto] */\n\n.dense-row--pipeline {\n grid-template-columns: 4px 1fr auto;\n gap: var(--space-2);\n padding: calc(var(--row-pad-y) + 3px) var(--space-4);\n}\n\n.dense-row--pipeline .dense-row-tick {\n background: transparent;\n}\n.dense-row--pipeline.is-selected .dense-row-tick {\n background: var(--primary);\n}\n\n/* pipeline amount: mono, tabular, larger weight */\n.dense-row--pipeline .amt {\n font-family: var(--font-mono);\n font-size: 12.5px;\n color: var(--fg);\n font-weight: 500;\n white-space: nowrap;\n}\n.dense-row--pipeline .when {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n white-space: nowrap;\n}\n.dense-row--pipeline .when.is-urgent { color: var(--danger); }\n\n/* === Reduced-motion override =================================== */\n\n@media (prefers-reduced-motion: reduce) {\n .dense-row,\n .dense-row-check {\n transition: none;\n }\n}\n\n\n/* ===== 21-card.css ===== */\n/* Part: card (Components / Display)\n * Sources: plans/atelier/designs/atelier-finance.html (.fin-kpi, .frame surface recipe)\n * plans/atelier/designs/atelier-obi-home.html (.callout)\n * plans/atelier/designs/atelier-tasks.html (.tr-stat)\n *\n * Owned classes:\n * .card\n * .card-pad — adds standard inner padding (default: --space-4)\n * .card-pad-sm — compact inner padding (--space-3)\n * .card-pad-lg — generous inner padding (--space-5)\n * .card-head — header strip with bottom rule (for titled cards)\n * .stat-card — numeric KPI variant: large value + mono label + tint border\n * .stat-card.is-danger .stat-card.is-warn .stat-card.is-sys\n * — semantic border tints (accent color-mixed into border-soft)\n *\n * NOT owned here (compose into .card):\n * .frame / .frame-head / .frame-tabs / .frame-body — pkg-pane-frame pattern\n * .dense-row* — table-dense-row part\n * .badge / .tag / .chip — badge-tag-chip part\n * .btn — button part\n *\n * Merge narrative:\n * All of .callout (atelier-obi-home), .fin-kpi (atelier-finance), and .tr-stat\n * (atelier-tasks) share an identical surface recipe: border 1px var(--border-soft),\n * border-radius var(--radius-md), background var(--bg-surface|--bg-base), overflow hidden.\n * Those are consolidated here into .card. Domain-specific internals (.callout-num,\n * .fin-kpi-label, .fin-kpi-value, .fin-kpi-spark, .tr-stat .n/.k/.sub) stay in their\n * respective screen partials — this part owns only the container shell and the\n * stat-card variant that covers the shared numeric-KPI pattern (.tr-stat and\n * the non-gauge .fin-kpi share the same visual recipe).\n * ---------------------------------------------------------------- */\n\n/* === Base card primitive ======================================= */\n\n.card {\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-lg);\n background: var(--bg-surface);\n overflow: hidden;\n}\n\n/* --- Padding modifiers ----------------------------------------- */\n/* Use .card-pad instead of padding inline so the container\n and its padding can be swapped independently (e.g. flush\n tables inside a padded header, or the pane-frame flush body). */\n\n.card-pad { padding: var(--space-4); }\n.card-pad-sm { padding: var(--space-3); }\n.card-pad-lg { padding: var(--space-5); }\n\n/* --- Header strip ---------------------------------------------- */\n/* Appears at the top of a titled card (display: flex, spaced,\n with a soft bottom rule dividing head from body). Callers place\n a title + optional right-side action inside. */\n\n.card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-3);\n padding: var(--space-3) var(--space-4);\n border-bottom: 1px solid var(--border-soft);\n}\n\n/* === Stat card variant ========================================= */\n/* Numeric KPI surface — used in Tasks triage (.tr-stat) and\n Finance overview (.fin-kpi without the gauge). Features:\n - bg-base (slightly recessed vs card default bg-surface)\n - standard padding (space-3 × space-4)\n - optional semantic border tint (danger / achievement / systemic)\n\n Domain inner elements (.n/.k/.sub in tasks; .fin-kpi-label /\n .fin-kpi-value / .fin-kpi-sub in finance) live in their\n screen partials; only the surface shell is owned here. */\n\n.stat-card {\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n background: var(--bg-base);\n padding: var(--space-3) var(--space-4);\n overflow: hidden;\n}\n\n/* Semantic border tints: color-mixes the semantic color into\n border-soft so the tint reads on both light and dark themes\n without a hardcoded hex. Recipe matches atelier-tasks.html\n .tr-stat.is-danger / is-warn / is-sys source verbatim. */\n\n.stat-card.is-danger {\n border-color: color-mix(in srgb, var(--danger) 35%, var(--border-soft));\n}\n.stat-card.is-warn {\n border-color: color-mix(in srgb, var(--achievement) 35%, var(--border-soft));\n}\n.stat-card.is-sys {\n border-color: color-mix(in srgb, var(--systemic) 35%, var(--border-soft));\n}\n\n/* === Reduced-motion override =================================== */\n/* No animated properties are defined on .card itself. If a caller\n adds a transition to a child (e.g. border-color on hover), they\n must gate it here themselves. Placeholder kept for discoverability. */\n\n@media (prefers-reduced-motion: reduce) {\n /* nothing to override at this layer */\n}\n\n\n/* ===== 22-side-menu-nav.css ===== */\n/*\n * Part 22 — Side-menu nav (nav-group / nav-item)\n * Tier: Components / Navigation\n * Source panes:\n * plans/atelier/designs/atelier-tasks.html lines 644–673 (view + filter groups + is-dim; R23-R32)\n * plans/atelier/designs/atelier-obi-home.html lines 642–669 (same recipe; confirms vocabulary)\n *\n * Owned classes:\n * .nav-group .nav-group-label .nav-group[data-kind=\"view\"]\n * .nav-group[data-kind=\"filter\"] .nav-group[data-kind=\"nav\"]\n * .nav-group.is-dim\n * .nav-item .nav-item-count\n * .nav-item.is-on .nav-item.is-hot\n *\n * Merge note:\n * Both source panes carry a verbatim-identical block. The only difference is\n * the `data-kind` stamping + `is-dim` behaviour which lives only in\n * atelier-tasks.html (R23 comment). This partial is the canonical merge of\n * both; .nav-group-<kind> modifier classes expose kind as CSS without needing\n * attribute selectors in consumer code, while the data-kind attributes (stamped\n * by the sidebar() builder) stay as semantic hooks for JS (view-switch dim\n * logic). Fixed pixel values: 8px horizontal padding (structural inset, no\n * space token maps to 8 px at a sidebar density), 14 px icon, 2 px active\n * indicator — all structural geometry, not colour/radius/spacing-scale.\n */\n\n/* ── Group container ─────────────────────────────────────────────── */\n\n.nav-group {\n margin-top: var(--space-3);\n}\n\n.nav-group:first-child {\n margin-top: 0;\n}\n\n/* ── Group label (mono-uppercase eyebrow) ────────────────────────── */\n\n.nav-group-label {\n font-family: var(--font-mono);\n font-size: 9.5px; /* sub-scale: no token maps here */\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--fg-faint);\n padding: 0 var(--space-2) var(--space-1);\n}\n\n/* ── Kind modifiers (behavioural; match JS data-kind stamps) ─────── */\n/*\n * .nav-group-view — view-switcher group (Tasks / Agenda / Triage / Sweeper / Done).\n * Always visible; items set the in-pane tab context.\n * .nav-group-filter — facet / filter group (All tasks / Today / By domain / …).\n * List-only: dims + goes inert when the active view is non-list.\n * .nav-group-nav — general navigation (labels, workspaces, sections).\n * No additional behaviour beyond base.\n *\n * No extra visual treatment beyond the base group — kind affects runtime JS only.\n * CSS consumers may target [data-kind=\"filter\"] for the is-dim rule if needed.\n */\n\n/* ── Dim + inert state (R23 — filter groups on non-list views) ────── */\n\n.nav-group.is-dim {\n opacity: 0.4;\n pointer-events: none;\n}\n\n/* ── Nav item ────────────────────────────────────────────────────── */\n\n.nav-item {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--row-pad-y) 8px; /* 8px = structural sidebar inset, no token */\n border-radius: var(--radius-sm);\n color: var(--fg-muted);\n font-size: var(--body-size);\n cursor: pointer;\n position: relative;\n transition:\n background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n/* Icon child — 14 px is a fixed icon geometry, not a spacing token */\n.nav-item svg {\n width: 14px;\n height: 14px;\n opacity: 0.85;\n flex-shrink: 0;\n}\n\n/* Trailing count badge — mono, tabular, faint */\n.nav-item-count {\n margin-left: auto;\n font-family: var(--font-mono);\n font-size: 10.5px; /* sub-scale: no token maps here */\n color: var(--fg-faint);\n font-variant-numeric: tabular-nums;\n}\n\n/* ── Hover ───────────────────────────────────────────────────────── */\n\n.nav-item:hover {\n background: var(--bg-raised);\n color: var(--fg);\n}\n\n.nav-item:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: -2px;\n}\n\n/* ── Active / selected state ─────────────────────────────────────── */\n\n.nav-item.is-on {\n background: var(--bg-raised);\n color: var(--fg);\n}\n\n/*\n * Left-edge active indicator — 2 px strip with 2 px radius.\n * left: -2px positions it flush with the sidebar body padding edge\n * (sidebar-body adds var(--space-2) padding; the indicator bleeds into that).\n * top/bottom 6px gives visual breathing room; 2px width + 2px radius are\n * fixed structural geometry (not spacing-scale).\n */\n.nav-item.is-on::before {\n content: '';\n position: absolute;\n left: -2px;\n top: 6px;\n bottom: 6px;\n width: 2px;\n border-radius: 2px;\n background: var(--tint-fg-active, var(--primary));\n}\n\n.nav-item.is-on svg {\n color: var(--tint-fg-active, var(--primary));\n opacity: 1;\n}\n\n/* ── Hot / urgent modifier — count highlights in achievement amber ── */\n\n.nav-item.is-hot .nav-item-count {\n color: var(--achievement);\n}\n\n/* ── Reduced motion ──────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .nav-item {\n transition: none;\n }\n}\n\n\n/* ===== 23-command-palette.css ===== */\n/* =============================================================================\n Atelier app-kit · part 23 · Command Palette\n Source panes:\n - plans/atelier/designs/atelier-shell-palette.html (.cmdk* family + .ux badge)\n - plans/atelier/designs/atelier-obi-home.html (.palette* + .pitem* launcher)\n\n Owned classes:\n .cmdk-overlay\n .cmdk\n .cmdk-search\n .cmdk-list\n .cmdk-group\n .cmdk-row .cmdk-row.is-active\n .cmdk-row .ic .cmdk-row .nm .cmdk-row .dom\n .cmdk-empty\n .cmdk-foot .cmdk-foot .sp\n .ux .ux.approve .ux.silent .ux.confirm .ux.streaming .ux.form\n .palette .palette-head .palette-head .ptag\n .palette-section\n .palette-list\n .pitem .pitem .pic .pitem .ptitle .pitem .pmeta\n .pitem.is-placed .pitem.is-locked\n\n Merge notes:\n .cmdk (full ⌘K overlay) + .palette (obi-home inline launcher) share\n one overlay family: both live in a positioned surface, carry a header\n strip and a scrollable list of runnable items. The .ux badge inline on\n .cmdk-row replaces per-row hardcoded colors with semantic tokens:\n approve → --live / --live-soft\n silent → --systemic / --systemic-soft\n confirm → --agent / --agent-soft (source used --fg-muted / --fg-faint per spec)\n streaming → --achievement / --achievement-soft\n form → --primary / --primary-soft\n .palette box-shadow: source used rgba(0,0,0,.5) directional panel shadow;\n mapped to var(--shadow-3) which approximates depth without a hardcoded color.\n Fixed-geometry px values (permitted per kit rules):\n 560px — cmdk panel max-width (structural)\n 11vh — cmdk overlay top padding (structural viewport unit)\n 22px — .cmdk-row .ic target size (icon geometry)\n 13px — icon svg size inside .ic and .pitem .pic (icon geometry)\n 16px — .cmdk-search svg size (icon geometry)\n 24px — .pitem .pic size (icon geometry)\n 44px — .palette top offset (chrome geometry — matches --tab-h token)\n 320px — .palette width (panel geometry)\n 10.5px, 9.5px, 10px — sub-scale mono label sizes (no token; structural)\n 6px — .palette-list gap (structural spacing, between --space-1 and --space-2)\n 2px — .backdrop-filter value (structural)\n ============================================================================= */\n\n\n/* ── ⌘K overlay scrim ────────────────────────────────────────────────────────\n Covers the full shell surface with a semi-transparent tinted scrim.\n Centered grid so the cmdk panel sits at 11vh from the top. */\n.cmdk-overlay {\n position: absolute;\n inset: 0;\n z-index: 50;\n display: grid;\n place-items: start center;\n padding-top: 11vh;\n background: color-mix(in srgb, var(--bg-sunken) 66%, transparent);\n backdrop-filter: blur(2px);\n}\n\n\n/* ── ⌘K panel ───────────────────────────────────────────────────────────────\n 560 px wide, capped at 92 % viewport. Surface layer with lg radius. */\n.cmdk {\n width: 560px;\n max-width: 92%;\n background: var(--bg-surface);\n border: 1px solid var(--border);\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-4);\n overflow: hidden;\n}\n\n\n/* ── Search bar ─────────────────────────────────────────────────────────────\n Icon + text input + esc hint. Divides from list with --border-soft. */\n.cmdk-search {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n padding: var(--space-3) var(--space-4);\n border-bottom: 1px solid var(--border-soft);\n}\n\n.cmdk-search svg {\n width: 16px;\n height: 16px;\n color: var(--fg-faint);\n flex-shrink: 0;\n}\n\n.cmdk-search input {\n flex: 1;\n background: transparent;\n border: 0;\n outline: none;\n color: var(--fg);\n font-family: inherit;\n font-size: var(--text-body-lg);\n}\n\n.cmdk-search input::placeholder {\n color: var(--fg-faint);\n}\n\n/* esc / shortcut hint within the search bar — reuses kbd primitive style */\n.cmdk-search kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-xs);\n padding: 1px 5px;\n}\n\n\n/* ── Scrollable list container ──────────────────────────────────────────────\n Max height prevents the panel from filling the viewport. */\n.cmdk-list {\n max-height: 392px;\n overflow: auto;\n padding: var(--space-2);\n}\n\n\n/* ── Section header ─────────────────────────────────────────────────────────\n Mono uppercase label separating \"Recent\" from \"All actions\" groups. */\n.cmdk-group {\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: .14em;\n text-transform: uppercase;\n color: var(--fg-faint);\n padding: var(--space-2) var(--space-2) var(--space-1);\n}\n\n\n/* ── Action row ─────────────────────────────────────────────────────────────\n Grid: icon | name | domain label | ux_mode badge or keyboard shortcut.\n Keyboard-navigable; .is-active mirrors hover for arrow-key highlight. */\n.cmdk-row {\n display: grid;\n grid-template-columns: 22px 1fr auto auto;\n gap: var(--space-3);\n align-items: center;\n padding: var(--space-2) var(--space-3);\n border-radius: var(--radius-sm);\n cursor: pointer;\n color: var(--fg-muted);\n transition: background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n.cmdk-row:hover,\n.cmdk-row.is-active {\n background: var(--bg-raised);\n color: var(--fg);\n}\n\n/* 22 × 22 px icon well (fixed icon geometry — not a spacing token) */\n.cmdk-row .ic {\n width: 22px;\n height: 22px;\n display: grid;\n place-items: center;\n border-radius: var(--radius-xs);\n background: var(--bg-sunken);\n color: var(--fg-muted);\n flex-shrink: 0;\n}\n\n.cmdk-row .ic svg {\n width: 13px;\n height: 13px;\n}\n\n/* Action name — full color, body-sm scale */\n.cmdk-row .nm {\n color: var(--fg);\n font-size: var(--text-body-sm);\n}\n\n/* Domain label — faint mono annotation, right of name */\n.cmdk-row .dom {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n letter-spacing: .04em;\n}\n\n/* Keyboard shortcut hint shown instead of ux_mode on pinned rows */\n.cmdk-row kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-muted);\n background: var(--bg-base);\n border: 1px solid var(--border);\n border-radius: var(--radius-xs);\n padding: 1px 6px;\n}\n\n\n/* ── ux_mode badge (.ux) ────────────────────────────────────────────────────\n Semantic badge indicating how the action runs. One badge per row.\n Unified token mapping (merged per kit guidance):\n approve → --live (safe to run; routes through approve-gate)\n silent → --systemic (background / auto)\n confirm → --agent (needs confirmation; uses agent color per spec)\n streaming → --achievement (long-running / streamed output)\n form → --primary (requires form input before run)\n Default variant keeps --fg-muted on --bg-sunken (unknown / fallback). */\n.ux {\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: .06em;\n text-transform: uppercase;\n padding: 2px 6px;\n border-radius: var(--radius-xs);\n border: 1px solid var(--border-soft);\n background: var(--bg-sunken);\n color: var(--fg-muted);\n}\n\n.ux.approve {\n color: var(--live);\n border-color: var(--live-soft);\n background: var(--live-soft);\n}\n\n.ux.silent {\n color: var(--systemic);\n border-color: var(--systemic-soft);\n background: var(--systemic-soft);\n}\n\n/* confirm — per kit merge spec → --agent / --agent-soft */\n.ux.confirm {\n color: var(--agent);\n border-color: var(--agent-soft);\n background: var(--agent-soft);\n}\n\n.ux.streaming {\n color: var(--achievement);\n border-color: var(--achievement-soft);\n background: var(--achievement-soft);\n}\n\n.ux.form {\n color: var(--primary);\n border-color: var(--primary-soft);\n background: var(--primary-soft);\n}\n\n\n/* ── Empty state ────────────────────────────────────────────────────────────\n Shown when search query returns no matching actions. */\n.cmdk-empty {\n padding: var(--space-8) var(--space-4);\n text-align: center;\n color: var(--fg-faint);\n}\n\n.cmdk-empty h4 {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-body-lg);\n color: var(--fg-muted);\n margin: 0 0 var(--space-2);\n}\n\n.cmdk-empty p {\n margin: 0;\n font-size: var(--text-body-sm);\n}\n\n/* kbd hints inside empty state match standard .cmdk-search kbd style */\n.cmdk-empty kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-muted);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-xs);\n padding: 0 5px;\n}\n\n\n/* ── Footer hint bar ────────────────────────────────────────────────────────\n Mono keyboard legend: ↑↓ / ↵ / ⌘K / approve notice.\n Divides from list with --border-soft; sunken bg distinguishes it. */\n.cmdk-foot {\n display: flex;\n gap: var(--space-4);\n align-items: center;\n padding: var(--space-2) var(--space-4);\n border-top: 1px solid var(--border-soft);\n background: var(--bg-sunken);\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n letter-spacing: .04em;\n}\n\n.cmdk-foot kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-xs);\n padding: 1px 5px;\n}\n\n/* Spacer — pushes the approve notice to the far right */\n.cmdk-foot .sp {\n flex: 1;\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n Obi-home inline launcher (.palette* family)\n Source: atelier-obi-home.html · activated when .home[data-mode-edit=\"true\"]\n A fixed-width drawer that slides in from the right edge of the home canvas,\n listing draggable widgets / skills. Same overlay family as .cmdk but uses\n a different entry metaphor (drag-to-place vs run-on-enter).\n ─────────────────────────────────────────────────────────────────────── */\n\n/* ── Drawer shell ───────────────────────────────────────────────────────────\n 320 px right drawer, anchored top (44 px = --tab-h) to bottom.\n Box-shadow: source used a raw rgba directional shadow; mapped to --shadow-3\n which carries the same depth without a hardcoded color literal.\n The .home[data-mode-edit=\"true\"] toggling is host-context; callers apply\n display:flex when the edit mode is active. */\n.palette {\n position: absolute;\n top: 44px;\n right: 0;\n bottom: 0;\n width: 320px;\n background: var(--bg-sunken);\n border-left: 1px solid var(--border-soft);\n display: none;\n flex-direction: column;\n z-index: 7;\n box-shadow: var(--shadow-3);\n}\n\n\n/* ── Drawer header ───────────────────────────────────────────────────────────\n Label tag + title + description; divides from section list. */\n.palette-head {\n padding: var(--space-4) var(--space-4) var(--space-3);\n border-bottom: 1px solid var(--border-soft);\n}\n\n/* Eyebrow tag — achievement tint, mono uppercase (e.g. \"Widget palette\") */\n.palette-head .ptag {\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: .08em;\n text-transform: uppercase;\n color: var(--achievement);\n margin-bottom: var(--space-1);\n}\n\n/* Drawer title — display face, 16 px (maps to --text-body-lg) */\n.palette-head h3 {\n margin: 0;\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-body-lg);\n color: var(--fg);\n}\n\n/* Subtitle / description copy */\n.palette-head p {\n margin: var(--space-1) 0 0;\n font-size: var(--text-caption);\n color: var(--fg-muted);\n line-height: 1.5;\n}\n\n\n/* ── Section block ───────────────────────────────────────────────────────────\n Groups items (e.g. \"Widgets\", \"Skills\"). Adjacent sections use a hairline\n separator. Section heading uses mono uppercase, faint. */\n.palette-section {\n padding: var(--space-3) var(--space-4) var(--space-4);\n}\n\n.palette-section h4 {\n margin: 0 0 var(--space-2);\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: .08em;\n text-transform: uppercase;\n color: var(--fg-faint);\n font-weight: 500;\n}\n\n.palette-section + .palette-section {\n border-top: 1px solid var(--border-soft);\n}\n\n\n/* ── Item list grid ─────────────────────────────────────────────────────────\n 6 px gap (structural — between --space-1 / 4 px and --space-2 / 8 px,\n no token exists for this intermediate value). */\n.palette-list {\n display: grid;\n gap: 6px;\n}\n\n\n/* ── Draggable item (.pitem) ─────────────────────────────────────────────────\n Flex row: icon well | title | meta hint.\n Hover: achievement border + translateX(-2px) to signal drag affordance.\n .is-placed: dimmed + non-interactive (already on canvas).\n .is-locked: meta shown in faint (cannot be removed). */\n.pitem {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n padding: var(--space-2) var(--space-3);\n background: var(--bg-surface);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n cursor: grab;\n transition: border-color var(--motion-fast) var(--ease-calm),\n transform var(--motion-fast) var(--ease-calm);\n}\n\n.pitem:hover {\n border-color: var(--achievement);\n transform: translateX(-2px);\n}\n\n/* 24 × 24 px icon well (fixed icon geometry — not a spacing token) */\n.pitem .pic {\n width: 24px;\n height: 24px;\n background: var(--bg-raised);\n border-radius: var(--radius-xs);\n display: grid;\n place-items: center;\n color: var(--fg-muted);\n flex-shrink: 0;\n}\n\n.pitem .pic svg {\n width: 13px;\n height: 13px;\n}\n\n/* Item label — body-sm (13 px maps to --text-body-sm) */\n.pitem .ptitle {\n font-size: var(--text-body-sm);\n color: var(--fg);\n}\n\n/* Domain / hint annotation — right-aligned mono faint */\n.pitem .pmeta {\n margin-left: auto;\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: .04em;\n color: var(--fg-faint);\n}\n\n/* Already placed on canvas — dimmed, non-draggable */\n.pitem.is-placed {\n opacity: .45;\n cursor: default;\n}\n\n.pitem.is-placed:hover {\n border-color: var(--border-soft);\n transform: none;\n}\n\n/* Locked item — meta remains faint, no structural difference */\n.pitem.is-locked .pmeta {\n color: var(--fg-faint);\n}\n\n\n/* ── Keyboard focus rings ────────────────────────────────────────────────── */\n/* .cmdk-row is a keyboard-navigable action row (cursor:pointer).\n .is-active provides arrow-key highlight; WCAG 2.4.7 requires a distinct\n :focus-visible ring that fires independently for AT users. */\n.cmdk-row:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n/* .pitem is a draggable interactive element; keyboard users must be able to\n locate the drag target by Tab. */\n.pitem:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n\n/* ── Motion — reduced-motion overrides ───────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .cmdk-row,\n .pitem {\n transition: none;\n }\n\n .cmdk-overlay {\n backdrop-filter: none;\n }\n}\n\n\n/* ===== 24-action-bar-quick.css ===== */\n/* =============================================================================\n Atelier app-kit · part 24 · Action Bar + Quick-Actions Widget\n Source panes:\n - plans/atelier/designs/atelier-approve-gate.html (.ob-actions* family)\n - plans/atelier/designs/atelier-obi-home.html (.w-quick / .qrow family)\n\n Owned classes:\n .ob-actions\n .ob-actions-cluster\n .ob-actions-spacer\n .ob-actions-primary .ob-actions-primary:hover .ob-actions-primary svg\n .ob-actions-meta\n .w-quick .qrow .w-quick .qrow:last-child\n .w-quick .qrow span\n .w-quick .qrow .qmeta\n .w-quick .qrow kbd\n\n Token conversions applied vs source:\n ob-actions box-shadow: rgba(0,0,0,.25) → var(--border-soft) tint\n (upward footer shadow; closest literal-free approximation)\n ob-actions-primary color: hsl(150,40%,10%) → color-mix(in srgb, var(--live) 12%, var(--bg-sunken))\n (dark-on-live-green text; --live-fg not yet minted in tokens.css)\n\n Composing (NOT redefining):\n .btn .btn-sm — owned by 10-button.css; used inside .ob-actions but not redefined here\n .ux — owned by 23-command-palette.css; .qrow .qmeta uses its token slots\n\n Container query context:\n @container ob-detail — .ob-actions lives inside .ob-detail (approve-gate pane);\n the responsive collapse rule depends on that outer container-type declaration.\n .ob-detail itself is NOT owned here — it belongs to the approve-gate pattern.\n ============================================================================= */\n\n\n/* ── Sticky action footer ─────────────────────────────────────────────────────\n Sticky to the bottom of .ob-detail (approve-gate side pane). Clusters of\n secondary buttons on the left, a flex spacer, meta annotation, and the\n primary CTA anchored bottom-right. Wraps gracefully when the pane narrows. */\n\n.ob-actions {\n position: sticky;\n bottom: 0;\n background: var(--bg-surface);\n border-top: 1px solid var(--border-soft);\n padding: var(--space-3) var(--space-4);\n display: flex;\n align-items: center;\n gap: var(--space-2);\n flex-wrap: wrap;\n row-gap: var(--space-2);\n /* Upward panel shadow. Source: rgba(0,0,0,.25) — replaced with border-based\n tint to avoid a hardcoded color literal (same visual weight). */\n box-shadow: 0 -4px 12px -4px var(--border-soft);\n}\n\n/* Secondary button clusters — each cluster stays on one internal row */\n.ob-actions-cluster {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n flex-shrink: 0;\n}\n\n/* Flex-grow spacer between secondary clusters and the primary CTA */\n.ob-actions-spacer {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n/* Primary CTA — \"Approve & Send\" or equivalent commitment action.\n Uses --live (green) background; text color is dark-on-green via --live-fg\n (minted in tokens.css, Wave 4 — per-theme analogue of --danger-fg). */\n.ob-actions-primary {\n background: var(--live);\n border-color: var(--live);\n color: var(--live-fg);\n font-weight: 600;\n height: var(--btn-h);\n padding: 0 var(--space-4);\n flex-shrink: 0;\n margin-left: auto; /* anchors right after flex-wrap */\n /* Inherits .btn base (cursor, border-radius, font, display) — callers\n should compose .btn .ob-actions-primary on the same element. */\n}\n\n.ob-actions-primary:hover {\n filter: brightness(1.06);\n}\n\n.ob-actions-primary svg {\n color: currentColor;\n}\n\n/* Consequence meta — \"→ sends to Valentim · 1 recipient · SMTP · 17:00 today · undo 10s\"\n Mono annotation between spacer and primary; hides in narrow pane (see container query). */\n.ob-actions-meta {\n font-family: var(--font-mono);\n font-size: 10.5px;\n color: var(--fg-faint);\n letter-spacing: .04em;\n margin-right: var(--space-2);\n align-self: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n flex-shrink: 1;\n}\n\n/* Responsive collapse — when the ob-detail pane is ≤ 720 px:\n - secondary cluster buttons drop their text labels (icon-only);\n - meta moves to a tooltip on the primary (hidden from the row).\n Container name \"ob-detail\" is declared on .ob-detail in the approve-gate pane. */\n@container ob-detail (max-width: 720px) {\n .ob-actions-cluster .btn-sm {\n padding: 0 var(--space-2);\n }\n .ob-actions-cluster .btn-sm .btn-label {\n display: none;\n }\n .ob-actions-meta {\n display: none;\n }\n}\n\n\n/* ── Quick-actions widget rows (.w-quick / .qrow) ─────────────────────────────\n Shell-native home canvas widget (src/shell/home/ · ActionQuickWidget).\n Each .qrow is one pinned action: name | ux_mode + schedule meta | keyboard hint.\n The .w-quick container itself carries no custom styles — it is a bare widget\n slot styled by the home canvas (widget / w-head / w-body family, not owned here).\n 3-column grid: 1fr (name) | auto (qmeta) | auto (kbd). */\n\n.w-quick .qrow {\n display: grid;\n grid-template-columns: 1fr auto auto;\n gap: var(--space-3);\n align-items: center;\n /* 7 px row padding is fixed geometry (below --space-2 / 8 px) — permitted\n as a structural constant, not a semantic spacing value. */\n padding: 7px 0;\n border-bottom: 1px solid var(--border-soft);\n}\n\n.w-quick .qrow:last-child {\n border-bottom: 0;\n}\n\n/* Action name label */\n.w-quick .qrow span {\n color: var(--fg);\n font-size: var(--text-body-sm);\n}\n\n/* ux_mode + schedule annotation (e.g. \"silent · ⚡3×/day\", \"approve\").\n Approve rows use --live; other modes inherit --fg-faint.\n Inline color override for \"approve\" rows (style=\"color:var(--live)\")\n is applied in the HTML — this rule sets the neutral default. */\n.w-quick .qrow .qmeta {\n color: var(--fg-faint);\n font-family: var(--font-mono);\n font-size: 10.5px;\n}\n\n/* Keyboard shortcut badge (e.g. \"⌘ I\") */\n.w-quick .qrow kbd {\n display: inline-block;\n padding: 2px 6px;\n background: var(--bg-raised);\n border: 1px solid var(--border);\n border-radius: var(--radius-xs);\n color: var(--fg-muted);\n font-family: var(--font-mono);\n font-size: 10px;\n}\n\n\n/* ── Keyboard focus rings ────────────────────────────────────────────────── */\n/* .w-quick .qrow is a click target (role=\"button\" per doc); WCAG 2.4.7 requires\n a visible focus ring when reached by keyboard. No hover affordance is defined\n by design (locked D-06), but a focus ring is separate from hover and required. */\n.w-quick .qrow:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n\n/* ── Motion — reduced-motion overrides ───────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .ob-actions-primary {\n /* filter: brightness() is not a transform — no override needed for\n reduced-motion. No position/transform animations on this surface. */\n }\n}\n\n\n/* ===== 25-inspector-detail.css ===== */\n/* Part: inspector-detail (Components / Layout)\n * Sources:\n * plans/atelier/designs/atelier-tasks.html\n * — .tk-det-head / .tk-det-topline / .tk-det-title / .tk-det-actions\n * — .tk-det-meta-row / .tk-det-body\n * — .tk-det-grid (fields key-value grid)\n * — .tk-section-label / .tk-deferred-pill\n * — .tk-desc (prose block inside body)\n * — .tk-progress / .tk-progress > span\n * — .tk-timeline / .tk-tl-item\n * — .tk-action-bar\n * — .ld-split / .ld-list / .ld-divider / .ld-detail (master-detail shell)\n *\n * Merge narrative:\n * All .tk-det-* and .ld-* classes live only in atelier-tasks.html and are\n * generalised here into the .ip-* family so any domain detail panel\n * (tasks, mail, sales, research, …) can reuse the same primitives without\n * a domain prefix.\n *\n * .ip-tabs / .ip-tab are NOT owned here — they were merged into the\n * segmented-tabs part (14-segmented-tabs.css) as .tabs / .tab.\n *\n * Owned classes:\n * Master-detail shell:\n * .ip-split .ip-split-list .ip-split-divider .ip-split-pane\n * Inspector pane regions:\n * .ip-head .ip-topline .ip-topline-id .ip-topline-actions\n * .ip-title .ip-meta-row\n * .ip-body\n * Section anatomy (reusable inside .ip-body):\n * .ip-section-label .ip-section-label .ct .ip-deferred-pill\n * Field key-value grid:\n * .ip-grid .ip-grid dt .ip-grid dd .ip-grid dd code\n * Prose block:\n * .ip-desc\n * Progress bar:\n * .ip-progress .ip-progress-fill\n * Activity timeline:\n * .ip-timeline .ip-tl-item .ip-tl-item.is-mark .ip-tl-item.is-ok\n * .ip-tl-when .ip-tl-actor .ip-tl-actor.is-agent\n * Action footer:\n * .ip-action-bar .ip-action-bar-spacer\n *\n * NOT owned here (compose into .ip-*):\n * .tab / .tabs — segmented-tabs part (14)\n * .dense-row / variants — table-dense-row part (20)\n * .badge / .chip / .tag — badge-tag-chip part (11)\n * .btn / .btn-* — button part (10)\n * .card / .frame — card part (21)\n * ---------------------------------------------------------------- */\n\n/* === Master-detail shell ======================================== */\n/*\n * Generalised from .ld-split / .ld-list / .ld-divider / .ld-detail\n * in atelier-tasks.html. The caller sets --ip-list-w to control the\n * list column width (default 360px).\n */\n\n.ip-split {\n --ip-list-w: 360px;\n display: grid;\n grid-template-columns: minmax(280px, var(--ip-list-w)) 4px minmax(420px, 1fr);\n height: 100%;\n overflow: hidden;\n}\n\n.ip-split-list {\n overflow-y: auto;\n background: var(--bg-surface);\n display: grid;\n grid-template-rows: 1fr;\n}\n\n.ip-split-divider {\n background: var(--border-soft);\n cursor: col-resize;\n transition: background var(--motion-fast) var(--ease-calm);\n}\n\n.ip-split-divider:hover {\n background: var(--tint-fg-active, var(--primary));\n}\n\n.ip-split-pane {\n background: var(--bg-base);\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n}\n\n/* === Inspector head ============================================= */\n/*\n * Generalised from .tk-det-head (atelier-tasks.html line 1254–1258).\n * The gradient fades from the workspace tint (or surface) to base,\n * giving the header a subtle depth lift without a hard shadow.\n */\n\n.ip-head {\n padding: var(--space-4) var(--space-5);\n border-bottom: 1px solid var(--border-soft);\n background: linear-gradient(\n 180deg,\n var(--tint-bg-active, var(--bg-surface)) 0%,\n var(--bg-base) 100%\n );\n flex-shrink: 0;\n}\n\n/* --- Topline row (id chip + actions) ---------------------------- */\n/*\n * Generalised from .tk-det-topline (line 1259–1271).\n * Contains a mono id chip on the left and an actions cluster\n * on the right; sits above the title.\n */\n\n.ip-topline {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-3);\n margin-bottom: var(--space-2);\n font-family: var(--font-mono);\n font-size: 10.5px;\n color: var(--fg-faint);\n letter-spacing: 0.04em;\n}\n\n/* Mono identifier chip (entity type · short id) */\n.ip-topline-id {\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n padding: 2px var(--space-2);\n border-radius: var(--radius-xs);\n color: var(--fg);\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: 0.04em;\n}\n\n/* Actions cluster (buttons, icon-buttons) */\n.ip-topline-actions {\n display: flex;\n gap: var(--space-1);\n align-items: center;\n}\n\n/* --- Title ------------------------------------------------------ */\n/*\n * Generalised from .tk-det-title (line 1273–1278).\n * Display-weight heading; domain callers may swap to h2 / h3.\n */\n\n.ip-title {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-h3);\n margin: 0;\n color: var(--fg);\n line-height: 1.25;\n}\n\n/* --- Meta row (badges + assignee + mode + priority + due) ------- */\n/*\n * Generalised from .tk-det-meta-row (line 1279–1282).\n * Wrapping flex tray for .badge / .chip pills; callers compose\n * from badge-tag-chip part (11).\n */\n\n.ip-meta-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n margin-top: var(--space-3);\n}\n\n/* === Inspector body ============================================= */\n/*\n * Generalised from .tk-det-body (line 1283–1287).\n * Scrollable flex column; gap between sections handled at this\n * level so individual sections stay gap-unaware.\n */\n\n.ip-body {\n padding: var(--space-5);\n display: flex;\n flex-direction: column;\n gap: var(--space-5);\n flex: 1;\n}\n\n/* === Section label ============================================== */\n/*\n * Generalised from .tk-section-label (line 1312–1323).\n * Mono all-caps micro-heading that separates body sections.\n * Optional .ct child for a count/state annotation (right-aligned).\n */\n\n.ip-section-label {\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--fg-faint);\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n margin-bottom: var(--space-2);\n}\n\n/* Right-side count annotation */\n.ip-section-label .ct {\n font-family: var(--font-mono);\n font-size: 9.5px;\n color: var(--fg-muted);\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.04em;\n text-transform: none;\n}\n\n/* Deferred / WIP marker pill (dashed, faint) */\n.ip-deferred-pill {\n font-family: var(--font-mono);\n font-size: 9px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--fg-faint);\n border: 1px dashed var(--border);\n padding: 1px var(--space-1);\n border-radius: var(--radius-xs);\n background: transparent;\n}\n\n/* === Field key-value grid ======================================= */\n/*\n * Generalised from .tk-det-grid (line 1288–1310).\n * Two-column definition list: mono uppercase labels on left,\n * values (text / chips / inline controls) on right.\n * The 110px label column matches the source pane; callers may\n * override via --ip-grid-label-w.\n */\n\n.ip-grid {\n --ip-grid-label-w: 110px;\n display: grid;\n grid-template-columns: var(--ip-grid-label-w) 1fr;\n gap: var(--space-2) var(--space-4);\n font-size: var(--text-body-sm);\n}\n\n/* dt: mono all-caps label */\n.ip-grid dt {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n letter-spacing: 0.1em;\n text-transform: uppercase;\n align-self: center;\n}\n\n/* dd: value cell — wrapping chip tray */\n.ip-grid dd {\n margin: 0;\n color: var(--fg);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-body-sm);\n}\n\n/* Inline code / monospace value chip inside a dd */\n.ip-grid dd code {\n font-family: var(--font-mono);\n font-size: 11.5px;\n background: var(--bg-sunken);\n border: 1px solid var(--border-soft);\n padding: 1px var(--space-1);\n border-radius: var(--radius-xs);\n color: var(--fg);\n}\n\n/* === Prose description block ==================================== */\n/*\n * Generalised from .tk-desc (line 1333–1342).\n * Surfaced text block with pre-wrap for multi-line content.\n * Appears in body sections (Description, Notes, …).\n */\n\n.ip-desc {\n font-size: var(--text-body-sm);\n color: var(--fg-muted);\n line-height: 1.6;\n background: var(--bg-surface);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n white-space: pre-wrap;\n}\n\n/* === Progress bar =============================================== */\n/*\n * Generalised from .tk-progress (line 1344–1359).\n * The fill is a <span> or <div> child with an inline width%.\n * 6px track height + 3px radius are fixed geometry (no token maps).\n */\n\n.ip-progress {\n flex: 1;\n height: 6px;\n background: var(--bg-sunken);\n border-radius: 3px;\n overflow: hidden;\n border: 1px solid var(--border-soft);\n min-width: 120px;\n}\n\n.ip-progress-fill {\n display: block;\n height: 100%;\n background: var(--live);\n border-radius: 3px;\n transition: width var(--motion-fast) var(--ease-calm);\n}\n\n/* === Activity timeline ========================================== */\n/*\n * Generalised from .tk-timeline / .tk-tl-item (line 1444–1479).\n * Left-rail dashed line with event nodes. Each node carries:\n * .ip-tl-when — mono timestamp\n * .ip-tl-actor — mono actor chip (person or agent)\n * Free inline text content for the event description.\n */\n\n.ip-timeline {\n display: flex;\n flex-direction: column;\n gap: 0;\n border-left: 1px dashed var(--border);\n margin-left: var(--space-2);\n padding-left: var(--space-4);\n position: relative;\n}\n\n.ip-tl-item {\n position: relative;\n padding: var(--space-1) 0;\n font-size: var(--text-body-sm);\n color: var(--fg-muted);\n}\n\n/* Node dot on the left rail */\n.ip-tl-item::before {\n content: '';\n position: absolute;\n left: calc(-1 * var(--space-4) - 4px);\n top: 12px;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--bg-sunken);\n border: 1px solid var(--border);\n}\n\n/* Mark node (creation / key transition) — tint dot */\n.ip-tl-item.is-mark::before {\n background: var(--tint-fg-active, var(--primary));\n border-color: var(--tint-fg-active, var(--primary));\n}\n\n/* Success / resolved node — live dot */\n.ip-tl-item.is-ok::before {\n background: var(--live);\n border-color: var(--live);\n}\n\n/* Timestamp */\n.ip-tl-when {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n letter-spacing: 0.04em;\n margin-right: var(--space-2);\n}\n\n/* Actor chip (name or agent key) */\n.ip-tl-actor {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg);\n background: var(--bg-sunken);\n padding: 1px var(--space-1);\n border-radius: var(--radius-xs);\n border: 1px solid var(--border-soft);\n margin-right: var(--space-2);\n}\n\n/* Agent actor uses agent semantic colour */\n.ip-tl-actor.is-agent {\n color: var(--agent);\n}\n\n/* === Action footer bar ========================================== */\n/*\n * Generalised from .tk-action-bar (line 1481–1489).\n * Sticky footer inside .ip-split-pane; sits at margin-top: auto\n * to push to the bottom of the flex column.\n */\n\n.ip-action-bar {\n border-top: 1px solid var(--border-soft);\n background: var(--bg-sunken);\n padding: var(--space-3) var(--space-5);\n display: flex;\n align-items: center;\n gap: var(--space-2);\n margin-top: auto;\n flex-shrink: 0;\n}\n\n/* Spacer — pushes secondary actions to the right */\n.ip-action-bar-spacer {\n flex: 1;\n}\n\n/* === Reduced-motion override ==================================== */\n\n@media (prefers-reduced-motion: reduce) {\n .ip-split-divider,\n .ip-progress-fill {\n transition: none;\n }\n}\n\n\n/* ===== 26-feedback-state.css ===== */\n/* =============================================================================\n Atelier app-kit · part 26 · Feedback State\n Source panes (verbatim lift — shared across all 17 panes):\n - plans/atelier/designs/atelier-tasks.html (canonical source, §atelier-review-css)\n - plans/atelier/designs/atelier-mail.html (identical)\n - plans/atelier/designs/atelier-outbound-email.html (identical)\n - plans/atelier/designs/atelier-outbound-sequences.html (identical)\n - plans/atelier/designs/atelier-outbound-social.html (identical)\n - plans/atelier/designs/atelier-finance.html (identical)\n - plans/atelier/designs/atelier-research.html (height:100% variant)\n - plans/atelier/designs/atelier-content-kanban.html (height:100% variant)\n\n Owned classes:\n .atelier-state\n .atelier-state.is-empty\n .atelier-state.is-error\n .atelier-state.is-loading\n .atelier-state.is-streaming\n .atelier-spin\n .atelier-prog\n .atelier-prog > span\n\n Merge — tasks-local aliases folded in:\n .tk-empty → .atelier-state.is-empty (no-content placeholder, icon + h3)\n .tk-error → .atelier-state.is-error (alert icon + danger tint, h3)\n .tk-loading → .atelier-state.is-loading (spinner child + text)\n\n All values reference @ikenga/tokens custom properties.\n No hardcoded hex or hsl color literals.\n Fixed-geometry px values (permitted): 2.5px spinner border, 6px progress height,\n 34px icon size, 26px spinner diameter — these are structural, not theme-sensitive.\n ============================================================================= */\n\n/* ── Container ───────────────────────────────────────────────────────────────\n Default: centred placeholder for any pane-level empty / loading / error state.\n min-height:60vh matches the compact pane slots (most panes).\n Use .atelier-state.is-full-pane to switch to height:100% for full-height panes\n like atelier-research.html and atelier-content-kanban.html.\n ──────────────────────────────────────────────────────────────────────────── */\n.atelier-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 60vh;\n gap: var(--space-3);\n text-align: center;\n padding: var(--space-12);\n color: var(--fg-faint);\n}\n\n/* Full-pane variant — research / kanban contexts where the state fills 100% height */\n.atelier-state.is-full-pane {\n min-height: unset;\n height: 100%;\n}\n\n/* Icon slot — callers pass a 34×34 SVG with class \"ix\" inside .atelier-state */\n.atelier-state .ix {\n width: 34px;\n height: 34px;\n color: var(--fg-faint);\n}\n\n/* Heading — display font, muted tone, no margin */\n.atelier-state h3 {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-h3);\n color: var(--fg-muted);\n margin: 0;\n}\n\n/* Body copy — small type, comfortable measure */\n.atelier-state p {\n margin: 0;\n font-size: var(--text-body-sm);\n max-width: 42ch;\n line-height: 1.55;\n}\n\n/* ── Semantic variants ───────────────────────────────────────────────────────\n is-empty — default (icon + h3 in fg-faint / fg-muted). No extra rule needed;\n the base .atelier-state already encodes empty-state look.\n is-error — danger tint on container + heading.\n is-loading — spinner child replaces icon; base colors apply.\n is-streaming — indeterminate progress bar child; base colors apply.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* .is-empty is the base appearance — explicitly naming the class aids JS toggling */\n.atelier-state.is-empty {\n /* inherits base styles; no additional overrides */\n}\n\n/* Error state: everything shifts to danger palette */\n.atelier-state.is-error {\n color: var(--danger);\n}\n\n.atelier-state.is-error h3 {\n color: var(--danger);\n}\n\n.atelier-state.is-error .ix {\n color: var(--danger);\n}\n\n/* Loading + streaming states inherit the base fg-faint / fg-muted colors;\n the spinner or progress bar is placed as a direct child by the caller. */\n.atelier-state.is-loading {\n /* no additional overrides — spinner child (.atelier-spin) is the visual signal */\n}\n\n.atelier-state.is-streaming {\n /* no additional overrides — progress child (.atelier-prog) is the visual signal */\n}\n\n/* ── Spinner ─────────────────────────────────────────────────────────────────\n A single CSS border-trick spinner. 2.5px border is structural pixel geometry.\n 26×26 is structural — not a spacing token (the spinner is an inline accent, not\n a touch target or layout unit).\n ──────────────────────────────────────────────────────────────────────────── */\n.atelier-spin {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n border: 2.5px solid var(--border-soft);\n border-top-color: var(--tint-fg-active, var(--primary));\n animation: atelier-spin var(--motion-base, 720ms) linear infinite;\n}\n\n@keyframes atelier-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Reduced-motion: collapse to a static element (no rotation) */\n@media (prefers-reduced-motion: reduce) {\n .atelier-spin {\n animation: none;\n /* retain the border-top highlight as a static accent so the element is still\n recognisable as a \"working\" indicator without motion */\n }\n}\n\n/* ── Indeterminate progress bar ──────────────────────────────────────────────\n Used in .is-streaming state to communicate that Chi is working. The shimmer\n span sweeps left→right indefinitely. 6px height + pill radius are structural.\n ──────────────────────────────────────────────────────────────────────────── */\n.atelier-prog {\n width: min(420px, 60%);\n height: 6px;\n border-radius: var(--radius-pill);\n background: var(--bg-sunken);\n overflow: hidden;\n}\n\n.atelier-prog > span {\n display: block;\n height: 100%;\n width: 40%;\n border-radius: var(--radius-pill);\n background: linear-gradient(90deg, transparent, var(--achievement), transparent);\n animation: atelier-stream 1.4s var(--ease-calm) infinite;\n}\n\n@keyframes atelier-stream {\n 0% { margin-left: -40%; }\n 100% { margin-left: 100%; }\n}\n\n/* Reduced-motion: freeze shimmer at center so the bar is still visible */\n@media (prefers-reduced-motion: reduce) {\n .atelier-prog > span {\n animation: none;\n margin-left: 30%; /* static center position */\n }\n}\n\n\n/* ===== 27-toast.css ===== */\n/* =============================================================================\n Atelier app-kit · part 27 · Toast\n Source pane:\n - plans/atelier/designs/atelier-obi-home.html\n Reference text: \"silent dispatches + toasts 'Your Chi considers…'\"\n (§ callout-body, §ux_mode table pill — no dedicated toast CSS block in\n source; this is a [new] greenfield design per the visual language implied\n by the `silent` ux_mode dispatch pattern described there.)\n\n Owned classes:\n .toast-stack\n .toast\n .toast-icon\n .toast-body\n .toast-message\n .toast-action\n .toast.is-info\n .toast.is-success\n .toast.is-danger\n .toast.is-action\n .toast.is-exiting\n\n Composes (do not redefine):\n .btn-sm (.toast-action is a plain <a> styled to match .btn-sm — callers\n may add .btn-sm on the link element instead; the .toast-action\n class exists for the common inline-link pattern without a <button>)\n\n All values reference @ikenga/tokens custom properties.\n No hardcoded hex / hsl color literals.\n Fixed-geometry px values (permitted): 14px icon dimension, 1px rule hairline.\n ============================================================================= */\n\n\n/* ── Stack container ─────────────────────────────────────────────────────────\n The stack anchors to the bottom-right corner of its nearest positioned\n ancestor (typically <body> or the shell surface). It has no background or\n border of its own — it is a pure layout rail that stacks toast items.\n Items stack upward: newer toasts appear at the bottom of the visual stack\n (flex-direction: column + items appended to DOM end). */\n.toast-stack {\n position: fixed;\n bottom: var(--space-4);\n right: var(--space-4);\n z-index: 900;\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n align-items: flex-end;\n pointer-events: none; /* stack itself is not a hit target */\n}\n\n\n/* ── Toast item ──────────────────────────────────────────────────────────────\n Raised surface: --bg-raised + --shadow-3 + --radius-md.\n A max-width of 340px keeps the message on two lines or fewer at body-sm.\n pointer-events: auto restores interactivity on the item itself. */\n.toast {\n pointer-events: auto;\n display: flex;\n align-items: flex-start;\n gap: var(--space-2);\n max-width: 340px;\n padding: var(--space-3) var(--space-4);\n background: var(--bg-raised);\n border: 1px solid var(--border);\n border-radius: var(--radius-md);\n box-shadow: var(--shadow-3);\n color: var(--fg);\n\n /* Entrance: slide in from the right, fade up */\n animation:\n toast-in var(--motion-base) var(--ease-soft-bounce) forwards;\n\n /* 4 s auto-dismiss: callers add .is-exiting after 4 s to trigger exit */\n}\n\n@keyframes toast-in {\n from {\n opacity: 0;\n transform: translateX(var(--space-6)) translateY(var(--space-1));\n }\n to {\n opacity: 1;\n transform: translateX(0) translateY(0);\n }\n}\n\n/* Reduced-motion: skip the slide, keep a plain opacity fade */\n@media (prefers-reduced-motion: reduce) {\n .toast {\n animation: toast-in-fade var(--motion-base) var(--ease-calm) forwards;\n }\n @keyframes toast-in-fade {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n}\n\n\n/* ── Exit state ──────────────────────────────────────────────────────────────\n Callers add .is-exiting (e.g. after 4 s) then remove the element on\n animationend. Uses the same duration as entrance so the motion feels\n matched. */\n.toast.is-exiting {\n animation:\n toast-out var(--motion-slow) var(--ease-calm) forwards;\n}\n\n@keyframes toast-out {\n from {\n opacity: 1;\n transform: translateX(0);\n max-height: 120px;\n margin-bottom: 0;\n }\n to {\n opacity: 0;\n transform: translateX(var(--space-4));\n max-height: 0;\n padding-top: 0;\n padding-bottom: 0;\n margin-bottom: calc(-1 * var(--space-2)); /* collapse the stack gap */\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .toast.is-exiting {\n animation: toast-out-fade var(--motion-slow) var(--ease-calm) forwards;\n }\n @keyframes toast-out-fade {\n from { opacity: 1; }\n to { opacity: 0; }\n }\n}\n\n\n/* ── Icon slot ───────────────────────────────────────────────────────────────\n 14×14 px — structural icon geometry, not a spacing token.\n Default colour inherits from the variant's semantic class. */\n.toast-icon {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n margin-top: 1px; /* optical baseline alignment with body text */\n color: var(--fg-muted);\n}\n\n\n/* ── Body ─────────────────────────────────────────────────────────────────── */\n.toast-body {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n flex: 1;\n min-width: 0;\n}\n\n\n/* ── Message text ─────────────────────────────────────────────────────────── */\n.toast-message {\n font-family: var(--font-body);\n font-size: var(--text-body-sm);\n line-height: var(--lead-body);\n color: var(--fg);\n margin: 0;\n}\n\n\n/* ── Optional action link ────────────────────────────────────────────────────\n Inline-link affordance (e.g. \"View task\", \"Open Chi\").\n Sits below the message text inside .toast-body.\n Callers may use a plain <a> with .toast-action or compose with .btn-sm. */\n.toast-action {\n font-family: var(--font-body);\n font-size: var(--text-body-sm);\n font-weight: 500;\n color: var(--tint-fg-active, var(--primary));\n text-decoration: none;\n cursor: pointer;\n align-self: flex-start;\n}\n.toast-action:hover {\n text-decoration: underline;\n}\n.toast-action:focus-visible {\n outline: 2px solid var(--tint-fg-active, var(--primary));\n outline-offset: 2px;\n border-radius: var(--radius-xs);\n}\n\n\n/* ── Semantic variants ───────────────────────────────────────────────────────\n .is-info — neutral informational (default Chi dispatch \"considers…\" message)\n .is-success — operation completed (\"Triage inbox sent\")\n .is-danger — operation failed or produced an error\n .is-action — approve-gate cue (awaiting sign-off); uses --live / --live-soft\n\n Each variant tints:\n • the left border (1px vertical accent replacing a coloured icon bg)\n • the .toast-icon colour\n The container background stays --bg-raised so the toast surface adapts\n cleanly to all five Ikenga themes.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Info — systemic palette; used for silent-mode \"Your Chi considers…\" toasts */\n.toast.is-info {\n border-left: 3px solid var(--systemic);\n}\n.toast.is-info .toast-icon {\n color: var(--systemic);\n}\n\n/* Success — primary palette */\n.toast.is-success {\n border-left: 3px solid var(--primary);\n}\n.toast.is-success .toast-icon {\n color: var(--primary);\n}\n\n/* Danger — action failed */\n.toast.is-danger {\n border-left: 3px solid var(--danger);\n}\n.toast.is-danger .toast-icon {\n color: var(--danger);\n}\n\n/* Action — approve-gate pending sign-off cue (--live = the \"go\" semantic) */\n.toast.is-action {\n border-left: 3px solid var(--live);\n background: color-mix(in srgb, var(--live-soft) 40%, var(--bg-raised));\n}\n.toast.is-action .toast-icon {\n color: var(--live);\n}\n.toast.is-action .toast-action {\n color: var(--live);\n}\n\n\n/* ===== 28-kanban.css ===== */\n/* Part: kanban (Components / Layout)\n * Sources: plans/atelier/designs/atelier-content-kanban.html (.kb-board, .kb-col*, .kb-card*)\n * plans/atelier/designs/atelier-strategy-board.html (.kb-board, .kb-col*, .kb-card*)\n * Both panes carry the identical .kb-* block; the strategy board adds\n * .okr-card-prog extension children (owned here) on top of the shared tile.\n *\n * Owned classes:\n * Board: .kb-board\n * Column: .kb-col .kb-col-head .kb-col-name .kb-col-dot .kb-col-meta .kb-col-agg\n * .kb-col-body\n * Card: .kb-card .kb-card-title .kb-card-sub .kb-card-foot .kb-card-amt\n * .kb-card-owner .kb-mini-avatar .kb-mini-avatar.is-agent\n * Add row: .kb-add\n * OKR ext: .okr-card-prog .okr-kr .okr-kr-row .okr-bar .okr-bar.is-low .okr-bar.is-mid\n * .okr-overall .okr-overall .ring\n *\n * NOT owned here — compose into .kb-card:\n * .card — card (part 21) — owned by the card part; .kb-card does NOT extend\n * .card (it uses --radius-sm not --radius-lg) but references the same\n * surface token recipe independently.\n * .badge / .chip — badge-tag-chip part\n * .ux-dot — shell primitive (status dot)\n *\n * Merge narrative:\n * Both atelier-content-kanban.html and atelier-strategy-board.html carry verbatim copies of\n * the .kb-* block in their <style> tags. The only substantive differences are:\n * (a) the review-patch block (atelier-review-css id) adds the stretch-column rule, the\n * right-edge fade mask, and .kb-col-agg — all folded in here as the canonical form.\n * (b) atelier-strategy-board.html adds .okr-card-prog / .okr-kr* / .okr-bar* / .okr-overall\n * as extension children inside .kb-card — owned here because they are structurally\n * coupled to the tile and appear in no other part.\n * Verbatim hardcoded pixel values in source that have no token (8px dot diameter, 16px\n * mini-avatar, 4px progress bar height) are structural fixed-geometry and are preserved as px.\n * ---------------------------------------------------------------- */\n\n/* === Board ===================================================== */\n/* Full-bleed horizontal scroll container. Columns fill the board's\n full height (review-patch E-01: align-items:stretch). A right-edge\n mask gradient signals more columns to the right. */\n\n.kb-board {\n display: flex;\n gap: var(--space-3);\n padding: var(--space-4);\n overflow-x: auto;\n height: 100%;\n align-items: stretch; /* E-01 review patch */\n -webkit-mask-image: linear-gradient(\n 90deg, var(--bg-base) 94%, transparent\n );\n mask-image: linear-gradient(\n 90deg, var(--bg-base) 94%, transparent\n );\n}\n\n/* === Column ==================================================== */\n/* Fixed-width flex column. Background uses --bg-sunken so it reads\n as a recessed lane against the pane's --bg-base background. */\n\n.kb-col {\n flex: 0 0 264px;\n display: flex;\n flex-direction: column;\n background: var(--bg-sunken);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n min-height: 100%; /* E-01 review patch */\n}\n\n/* --- Column header ---------------------------------------------- */\n/* Sticky within a scrolling column body so the stage label is always\n visible as the user scrolls through many cards. */\n\n.kb-col-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--space-3) var(--space-3) var(--space-2);\n position: sticky;\n top: 0;\n}\n\n/* Stage label — mono uppercase with a colour dot prefix */\n\n.kb-col-name {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: .08em;\n text-transform: uppercase;\n color: var(--fg-muted);\n}\n\n/* 8px dot: structural fixed-geometry, no space token maps to 8px */\n.kb-col-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n /* colour is supplied inline via style=\"background:var(--<semantic>);\"\n — the stage palette is caller-defined, not hardcoded here */\n}\n\n/* Card count / aggregate next to the stage name */\n.kb-col-meta {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n}\n\n/* OKR aggregate rollup (E-07 review patch) — replaces .kb-col-meta\n with a richer \"N obj · avg XX%\" summary line. */\n.kb-col-agg {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-muted);\n}\n.kb-col-agg b { color: var(--fg); }\n\n/* --- Column body ------------------------------------------------ */\n/* Scrollable card stack. flex:1 1 auto lets it consume leftover\n column height (E-01 review patch). */\n\n.kb-col-body {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n padding: 0 var(--space-2) var(--space-3);\n overflow-y: auto;\n flex: 1 1 auto; /* E-01 review patch */\n}\n\n/* === Tile / card =============================================== */\n/* .kb-card is the kanban tile surface. It deliberately does NOT\n extend .card from part 21 because it uses --radius-sm (a tighter\n corner suited to dense stacked items) rather than --radius-lg.\n The surface recipe (--bg-surface + --border-soft) is the same;\n it is duplicated intentionally to keep the tile standalone. */\n\n.kb-card {\n background: var(--bg-surface);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n padding: var(--space-3);\n cursor: grab;\n transition:\n border-color var(--motion-fast) var(--ease-calm),\n transform var(--motion-fast) var(--ease-calm);\n}\n\n/* Drag affordance: lift + border intensify on hover.\n translateY(-1px) is structural fixed-geometry (1 CSS px lift). */\n.kb-card:hover {\n border-color: var(--border);\n transform: translateY(-1px);\n}\n\n/* Dragging in progress — card becomes the ghost placeholder.\n Callers add .is-dragging via JS during the drag lifecycle. */\n.kb-card.is-dragging {\n cursor: grabbing;\n opacity: 0.5;\n transform: none;\n}\n\n/* Drop-target column highlight — callers add .is-drop-target to\n .kb-col when the dragged card is hovering above it. */\n.kb-col.is-drop-target {\n border-color: color-mix(in srgb, var(--primary) 45%, var(--border-soft));\n background: color-mix(in srgb, var(--primary-soft) 40%, var(--bg-sunken));\n}\n\n/* Keyboard focus — the card as an interactive element must have a\n visible focus ring when focused via keyboard navigation. */\n.kb-card:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n border-color: var(--border);\n}\n\n/* --- Tile internals -------------------------------------------- */\n\n.kb-card-title {\n font-size: var(--text-body-sm);\n font-weight: 500;\n color: var(--fg);\n line-height: 1.35;\n margin-bottom: 5px; /* tight layout fixed-geometry */\n}\n\n.kb-card-sub {\n font-size: var(--text-caption);\n color: var(--fg-muted);\n margin-bottom: var(--space-2);\n}\n\n/* Footer row: meta amount (left) + owner (right) */\n.kb-card-foot {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-2);\n}\n\n/* Mono metadata slot — word count, amount, format label, etc. */\n.kb-card-amt {\n font-family: var(--font-mono);\n font-size: 11.5px;\n color: var(--fg);\n}\n\n/* Owner attribution row — status dot + mini-avatar initials */\n.kb-card-owner {\n display: flex;\n align-items: center;\n gap: 5px; /* tight fixed-geometry between dot and avatar */\n font-size: 10px;\n color: var(--fg-faint);\n font-family: var(--font-mono);\n}\n\n/* 16×16px avatar circle — structural icon size, no space token */\n.kb-mini-avatar {\n width: 16px;\n height: 16px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 8.5px;\n font-weight: 600;\n background: linear-gradient(135deg, var(--primary-soft), var(--primary));\n color: var(--fg);\n}\n\n/* Agent avatar variant — systemic palette gradient */\n.kb-mini-avatar.is-agent {\n background: linear-gradient(\n 135deg,\n var(--systemic-soft, var(--bg-raised)),\n var(--systemic)\n );\n}\n\n/* === Add-card row ============================================== */\n/* Dashed affordance at the bottom of each column body.\n margin-top: --space-1 keeps it slightly separated from the last\n card (E-01 review patch). */\n\n.kb-add {\n font-family: var(--font-mono);\n font-size: 11px;\n color: var(--fg-faint);\n padding: var(--space-2);\n text-align: center;\n border: 1px dashed var(--border-soft);\n border-radius: var(--radius-sm);\n cursor: pointer;\n margin-top: var(--space-1); /* E-01 review patch */\n}\n\n.kb-add:hover {\n color: var(--fg-muted);\n border-color: var(--border);\n}\n\n/* === OKR card extension (.okr-*) =============================== */\n/* Injected inside .kb-card on the Strategy Board pane only.\n These classes are structurally coupled to the tile; they do not\n appear standalone and are not consumed by any other part. */\n\n/* Progress block: grid of key-result rows inside the tile body */\n.okr-card-prog {\n margin-top: var(--space-2);\n display: grid;\n gap: 6px; /* tight fixed-geometry */\n}\n\n/* Single key-result row: label + % bar */\n.okr-kr { display: grid; gap: 3px; }\n\n.okr-kr-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 10.5px;\n color: var(--fg-muted);\n}\n.okr-kr-row .pct {\n font-family: var(--font-mono);\n color: var(--fg);\n}\n\n/* Thin progress bar — 4px height is structural fixed-geometry */\n.okr-bar {\n height: 4px;\n border-radius: 2px; /* fixed half of 4px */\n background: var(--bg-sunken);\n overflow: hidden;\n}\n.okr-bar > span {\n display: block;\n height: 100%;\n border-radius: 2px;\n background: var(--achievement); /* default: on-track gold */\n}\n.okr-bar.is-low > span { background: var(--danger); }\n.okr-bar.is-mid > span { background: var(--systemic); }\n\n/* Overall % badge with mini ring chart */\n.okr-overall {\n display: flex;\n align-items: center;\n gap: 6px; /* tight fixed-geometry */\n font-family: var(--font-mono);\n font-size: 11px;\n color: var(--fg);\n}\n\n/* 13×13px conic ring: structural fixed-geometry icon size.\n --p is an integer 0–100 set inline by the caller. */\n.okr-overall .ring {\n width: 13px;\n height: 13px;\n border-radius: 50%;\n background: conic-gradient(\n var(--achievement) calc(var(--p) * 1%),\n var(--bg-sunken) 0\n );\n}\n\n/* === Keyboard focus rings ======================================= */\n/* .kb-add is a click/keyboard target (role=\"button\" per doc);\n WCAG 2.4.7 requires a visible focus ring. Added here as the\n canonical ring; callers must also supply role=\"button\" + tabindex=\"0\". */\n\n.kb-add:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n/* === Reduced-motion override =================================== */\n/* The .kb-card hover lift and border transition are aesthetic only.\n Suppress them when the user has opted out of motion. */\n\n@media (prefers-reduced-motion: reduce) {\n .kb-card {\n transition: none;\n }\n .kb-card:hover {\n transform: none;\n }\n}\n\n\n/* ===== 29-chat-message.css ===== */\n/* =============================================================================\n Atelier app-kit · part 29 · Chat Message\n Source panes (scatter — verbatim-identical CSS block in all 6):\n - plans/atelier/designs/atelier-setup-chat-infer.html (§ Chat, lines 1019–1035)\n - plans/atelier/designs/atelier-mail.html (§ Chat, lines 1019–1035)\n - plans/atelier/designs/atelier-setup-chat-interview.html (§ Chat, lines 1019–1035)\n - plans/atelier/designs/atelier-research.html (§ Chat, lines 1025–1040)\n - plans/atelier/designs/atelier-sales-list.html (§ Chat, lines 1025–1040)\n - plans/atelier/designs/atelier-strategy-board.html (§ Chat, lines 1025–1040)\n\n Owned classes:\n .chat-msg\n .chat-msg.from-user — sender modifier: user turn\n .chat-msg.from-claude — sender modifier: Chi / agent turn\n .chat-msg-from — mono attribution line (sender + timestamp)\n .chat-msg-body — prose body; hosts <strong> highlights and inline <code>\n .chat-msg-card — inline structured artifact card (composes .card surface)\n .chat-msg-card-head — mono label row inside the card (icon + slug text)\n .chat-msg-card pre — monospace code/data block inside the card\n .chat-msg-card pre .k — key token in pre (achievement color)\n .chat-msg-card pre .v — value token in pre (primary color)\n .chat-msg-actions — row of quick-action buttons below a message\n .chat-msg-actions .btn — btn size override for the compact action strip\n\n NOT owned here (compose or extend):\n .card — base surface shell (21-card.css); .chat-msg-card shares the\n same border/radius/bg recipe but owns its own internal layout\n .btn / .btn-sm — button sizes (10-button.css)\n .chat-stream — scroll container (screen-layer; not a shared component)\n .chat-input* — text-entry area (screen-layer; not a shared component)\n\n Merge notes:\n - CSS block is byte-for-byte identical in all 6 panes → lifted verbatim.\n - The \"Confirm & localize\" button in setup-chat-infer.html used an inline style\n with a hardcoded hsl(150,40%,10%) foreground. Resolved here as a modifier class\n .chat-msg-actions .btn.is-confirm, using --live / --live-soft and the\n color-mixed dark fg pattern consistent with other status surfaces.\n - The 12px and 10px font-size values on .chat-msg-body code and .chat-msg-from\n are fixed typographic geometry values (no token spans that granularity); they are\n structural constants like icon sizes and are therefore permitted raw px per kit rules.\n - .chat-msg-card pre uses 11.5px — same rationale (monospace code block size).\n ============================================================================= */\n\n/* ── Message container ────────────────────────────────────────────────────────\n Vertical grid with a 1-unit gap between from-line, body, card, and actions.\n The scroll-container (.chat-stream, 3-unit gap) is screen-layer, not owned here.\n ──────────────────────────────────────────────────────────────────────────── */\n.chat-msg {\n display: grid;\n gap: var(--space-1);\n}\n\n/* ── Attribution line ─────────────────────────────────────────────────────────\n Compact mono byline: \"You · 13:58\" or \"Chi · now\".\n Default: fg-faint. Sender modifiers apply primary / systemic accent.\n ──────────────────────────────────────────────────────────────────────────── */\n.chat-msg-from {\n font-family: var(--font-mono);\n font-size: 10px; /* fixed small-mono geometry — no token at this granularity */\n letter-spacing: .08em;\n text-transform: uppercase;\n color: var(--fg-faint);\n}\n\n/* User turn: primary color marks the operator's own messages */\n.chat-msg.from-user .chat-msg-from {\n color: var(--primary);\n}\n\n/* Chi / agent turn: systemic color marks the AI assistant's messages */\n.chat-msg.from-claude .chat-msg-from {\n color: var(--systemic);\n}\n\n/* ── Body text ────────────────────────────────────────────────────────────────\n Small body type, comfortable line-height for chat cadence.\n Strong highlights use achievement; inline code renders in a pill on bg-surface.\n ──────────────────────────────────────────────────────────────────────────── */\n.chat-msg-body {\n font-size: var(--text-body-sm);\n color: var(--fg);\n line-height: 1.55;\n}\n\n/* Highlighted keywords — e.g. skill names, confirmations */\n.chat-msg-body strong {\n color: var(--achievement);\n font-weight: 600;\n}\n\n/* Inline code pill — bg-surface tray, primary text, monospace */\n.chat-msg-body code {\n font-family: var(--font-mono);\n font-size: 12px; /* fixed mono pill size — structural geometry */\n background: var(--bg-surface);\n padding: 1px 5px; /* 1px vertical is hairline geometry; 5px is fixed pill inset */\n border-radius: var(--radius-xs);\n color: var(--primary);\n}\n\n/* ── Inline artifact card ─────────────────────────────────────────────────────\n A structured block that Chi inlines into a message to show inferred config,\n schema data, or any structured artifact. Shares the .card surface recipe\n (bg-surface + border-soft + radius-md + padding-3) but owns its own internals.\n ──────────────────────────────────────────────────────────────────────────── */\n.chat-msg-card {\n background: var(--bg-surface);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n padding: var(--space-3);\n font-size: var(--text-body-sm);\n}\n\n/* Card header row — icon + mono slug label */\n.chat-msg-card-head {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n font-family: var(--font-mono);\n font-size: 10px; /* fixed mono label size — structural geometry */\n letter-spacing: .08em;\n text-transform: uppercase;\n color: var(--fg-faint);\n margin-bottom: var(--space-2);\n}\n\n/* 12 × 12 px icon in the card head — structural icon geometry */\n.chat-msg-card-head svg {\n width: 12px;\n height: 12px;\n}\n\n/* Code / data block inside the card — sunken tray, monospace, scrollable */\n.chat-msg-card pre {\n font-family: var(--font-mono);\n font-size: 11.5px; /* fixed compact mono size — structural geometry */\n line-height: 1.55;\n color: var(--fg);\n background: var(--bg-sunken);\n padding: var(--space-2);\n border-radius: var(--radius-xs);\n margin: var(--space-2) 0 0;\n overflow-x: auto;\n}\n\n/* Key token in pre (file names, field names) — achievement tint for visual hierarchy */\n.chat-msg-card pre .k {\n color: var(--achievement);\n}\n\n/* Value token in pre (values, descriptions) — primary tint */\n.chat-msg-card pre .v {\n color: var(--primary);\n}\n\n/* ── Action strip ─────────────────────────────────────────────────────────────\n A compact row of quick-action buttons below a message or card.\n Buttons override the base .btn height to 24px (fixed compact geometry —\n the strip is narrower than any density token; it is intentional per source).\n ──────────────────────────────────────────────────────────────────────────── */\n.chat-msg-actions {\n display: flex;\n gap: var(--space-1);\n margin-top: var(--space-2);\n}\n\n/* Compact button override — 24 × auto, 11px label inside the strip */\n.chat-msg-actions .btn {\n font-size: 11px; /* fixed compact label size — structural geometry */\n height: 24px; /* fixed compact strip height — structural geometry */\n padding: 0 var(--space-2);\n}\n\n/* Confirm-action modifier — primary affirmative CTA in the action strip.\n Source: inline style on \"Confirm & localize\" button (setup-chat-infer.html, setup-chat-interview.html).\n Uses --live / --live-soft (green) to signal \"safe to commit\".\n Foreground uses var(--live-fg) (minted in tokens.css, Wave 4) against the\n live fill for legibility. */\n.chat-msg-actions .btn.is-confirm {\n background: var(--live);\n border-color: var(--live);\n color: var(--live-fg);\n font-weight: 600;\n}\n\n.chat-msg-actions .btn.is-confirm:hover {\n filter: brightness(1.06);\n}\n\n/* ── Reduced-motion ───────────────────────────────────────────────────────────\n No keyframe animations are defined in this part.\n Transitions on .btn children are gated in 10-button.css.\n ──────────────────────────────────────────────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n /* Nothing to override at this layer. */\n}\n\n\n/* ===== 30-pkg-pane-frame.css ===== */\n/*\n * Part 30 — pkg-pane-frame (Patterns / Layout)\n * Tier: Patterns\n * Source panes:\n * ikenga-pkgs/packages/apps/tasks/dist/tasks.css lines 6–47 (.tk-frame, .tk-frame-head, .tk-frame-*)\n * plans/atelier/designs/atelier-tasks.html lines 953–1007 (.frame, .frame-head, .frame-tabs, .frame-body*, pane-slot reset)\n *\n * Owned classes (this pattern only — compose on top of .card from part 21):\n * .frame — flush-fill pane container (no card chrome inside the shell)\n * .frame-head — slim single-row title + action bar\n * .frame-title-wrap — icon + text pairing inside .frame-head\n * .frame-title-mark — leading icon colour slot\n * .frame-title — display-weight view label\n * .frame-sub — secondary descriptor line beneath the title\n * .frame-tabs — optional secondary tab strip (below head, above body)\n * .frame-tab — individual tab button inside .frame-tabs\n * .frame-tab.is-on — active tab state\n * .frame-tab .tab-count — mono badge trailing each tab\n * .frame-body — padded body area\n * .frame-body-flush — zero-padding body variant (tables, scrolling lists)\n * .frame-pane-slot — host-side reset applied when a pkg mounts into the shell pane\n *\n * NOT owned here:\n * .card / .stat-card / .card-head — part 21 (card)\n * .nav-item / .nav-group — part 22 (side-menu-nav)\n * .btn / .btn-icon — part 10 (button)\n * .badge / .chip / .tag — part 11 (badge-tag-chip)\n *\n * Design intent:\n * When a domain pkg is mounted into the Ikenga shell pane, the pane IS the\n * card chrome — there is no surrounding border, radius, or shadow to add.\n * `.frame` therefore strips all card decoration and fills the pane edge-to-\n * edge with a flex column; `.frame-head` gives a uniform header; `.frame-tabs`\n * gives an optional secondary tab strip; `.frame-body[-flush]` contains the\n * scrollable or padded content area.\n *\n * When rendered on a design page OUTSIDE the shell (the atelier prototype panes),\n * `.frame` composites on top of `.card` (which supplies border + radius + shadow).\n * The `.frame-pane-slot` override removes `.card`'s chrome when the shell slot is\n * present (mirrors the `#tk-host > .frame` reset in atelier-tasks.html).\n * ---------------------------------------------------------------- */\n\n\n/* ── Flush-fill container ────────────────────────────────────────── */\n/*\n * \"The pkg pane IS the container\" — no card chrome inside the shell.\n * When in prototype pages, place .card on the wrapper; .frame strips\n * card decoration and sets the flex-column stack.\n * Must be paired with an explicit height on the parent (shell provides this;\n * prototype pages use the section boundary).\n */\n\n.frame {\n background: var(--bg-surface);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* Shell-side reset: when a host pane mounts a pkg, strip the outer card chrome\n so .card + .frame together read as a flush-fill surface, not a nested card. */\n\n.frame-pane-slot > .frame {\n border: 0;\n border-radius: 0;\n box-shadow: none;\n flex: 1;\n min-width: 0;\n}\n\n\n/* ── Frame head ──────────────────────────────────────────────────── */\n/*\n * Slim single-row action bar. The shell side-menu carries domain + view\n * navigation, so the head holds only: the active-view label (left) and the\n * primary pane action (right, e.g. \"New task\").\n *\n * Background: a subtle tint-to-surface gradient using --tint-bg-active\n * (workspace tint, falls back to --bg-surface when no tint is applied)\n * so the header reads as slightly elevated above the list/body content.\n */\n\n.frame-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-4);\n padding: var(--space-2) var(--space-5);\n border-bottom: 1px solid var(--border-soft);\n background: linear-gradient(\n 180deg,\n var(--tint-bg-active, var(--bg-surface)) 0%,\n var(--bg-surface) 100%\n );\n flex-shrink: 0;\n}\n\n\n/* ── Title composition inside .frame-head ────────────────────────── */\n\n.frame-title-wrap {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n/* Leading 15 × 15 icon — fixed structural icon geometry, not a spacing token */\n.frame-title-mark {\n width: 15px;\n height: 15px;\n color: var(--tint-fg-active, var(--primary));\n flex-shrink: 0;\n}\n\n.frame-title {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-body);\n margin: 0;\n color: var(--fg);\n line-height: 1.2;\n}\n\n/* Secondary descriptor beneath the title (optional) */\n.frame-sub {\n margin-top: 2px; /* sub-pixel lift: structural, no space token at 2px */\n font-size: var(--text-caption);\n color: var(--fg-muted);\n line-height: var(--lead-body);\n}\n\n\n/* ── Secondary tab strip ─────────────────────────────────────────── */\n/*\n * Optional strip between .frame-head and .frame-body. Used when a pane\n * needs a second navigation tier (e.g. finance: Overview / Transactions /\n * Receivables / Reports). The side-menu View group is the primary tier;\n * .frame-tabs is the secondary tier within a given view.\n * The strip sits flush to the frame edges, height matches --tab-h.\n */\n\n.frame-tabs {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 var(--space-3);\n border-bottom: 1px solid var(--border-soft);\n background: var(--bg-sunken);\n height: var(--tab-h);\n flex-shrink: 0;\n}\n\n.frame-tab {\n height: var(--tab-h);\n padding: 0 var(--space-3);\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-body-sm);\n font-family: inherit;\n color: var(--fg-faint);\n background: transparent;\n border: 0;\n cursor: pointer;\n /* Underline indicator: 2px rule flush with the strip bottom border */\n border-bottom: 2px solid transparent;\n margin-bottom: -1px; /* pull underline flush against strip border */\n transition:\n color var(--motion-fast) var(--ease-calm);\n}\n\n.frame-tab:hover {\n color: var(--fg-muted);\n}\n\n.frame-tab:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: -2px;\n}\n\n.frame-tab.is-on {\n color: var(--fg);\n border-bottom-color: var(--tint-fg-active, var(--primary));\n}\n\n\n/* ── Tab count badge ─────────────────────────────────────────────── */\n/*\n * Mono numeric badge trailing the tab label. Inactive = bg-base + border-soft.\n * Active = live-soft background (live = in-progress / active count semantic).\n * Fixed padding 1px × 5px is structural badge geometry.\n */\n\n.frame-tab .tab-count {\n font-family: var(--font-mono);\n font-size: 10px; /* sub-scale: no text token at 10px */\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n color: var(--fg-faint);\n padding: 1px 5px; /* structural badge geometry, not space token */\n border-radius: var(--radius-xs);\n margin-left: var(--space-1);\n font-variant-numeric: tabular-nums;\n line-height: 1.4;\n}\n\n.frame-tab.is-on .tab-count {\n background: var(--live-soft);\n border-color: color-mix(in srgb, var(--live) 40%, var(--border));\n color: var(--live);\n}\n\n\n/* ── Body variants ───────────────────────────────────────────────── */\n/*\n * .frame-body — padded body for prose/form/stat content.\n * .frame-body-flush — zero-padding body for full-bleed tables, scrolling\n * lists, master/detail splits. The content component\n * (table, split) owns its own internal padding/borders.\n * Both must flex-grow + set min-height:0 so the body scrolls inside the frame\n * rather than expanding the frame past its container height.\n */\n\n.frame-body {\n padding: var(--space-5);\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.frame-body-flush {\n padding: 0;\n flex: 1;\n min-height: 0;\n overflow: hidden; /* child (list/split) owns its own scroll axis */\n display: flex;\n flex-direction: column;\n}\n\n\n/* ── Reduced-motion ──────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .frame-tab {\n transition: none;\n }\n}\n\n\n/* ===== 31-list-detail.css ===== */\n/* Part: list-detail (Patterns / Layout)\n * Sources:\n * plans/atelier/designs/atelier-tasks.html\n * — .ld-split / .ld-list / .ld-divider / .ld-detail (master-detail shell)\n * — .tk-group-head (sticky group separator, tasks pane line 1099–1119)\n * plans/atelier/designs/atelier-research.html\n * — .pane-split (line 953)\n * — .pl-list / .pl-list-head / .pl-list-title / .pl-list-meta (lines 1066–1070)\n * — .pl-sec (lines 1071–1073)\n * — .pl-row / .pl-row-accent / .pl-row-body / .pl-row-title\n * .pl-row-sub / .pl-row-right / .pl-row-amt / .pl-row-when (lines 1074–1086)\n * — .pl-detail / .pl-detail-wrap / .pl-detail-eyebrow (lines 1088–1090)\n * — .pl-detail-title / .pl-detail-co / .pl-facts / .pl-fact-k / .pl-fact-v (lines 1091–1096)\n * — .pl-next / .pl-next-head / .pl-next-body (lines 1097–1101)\n * — .pl-timeline / .pl-tl-row / .pl-tl-dot / .pl-tl-when (lines 1102–1106)\n *\n * Merge narrative:\n * Both panes share an identical structural shape: a scrollable master list on\n * the left and a contextual detail view on the right, separated by a 4px\n * drag handle. This pattern layer sits ABOVE the inspector-detail component\n * part (25-inspector-detail.css) which owns the shell primitives\n * (.ip-split / .ip-split-list / .ip-split-divider / .ip-split-pane).\n *\n * This file owns the list-column specialisation classes (.split-list-*,\n * .split-group, .split-row, .split-row-*) and the detail-column\n * content layout classes (.split-detail-*) that sit inside the shell\n * primitives. It does NOT redefine .ip-split or its children.\n *\n * The research pane uses .pl-* (pipeline list); the tasks pane uses\n * .ld-list + .tk-group-head. Both are canonical instances of the same\n * pattern. The canonical classes below generalise both lineages under\n * the .split-* namespace.\n *\n * Owned classes:\n * List column header:\n * .split-list-head .split-list-title .split-list-meta\n * Filter bar (optional, inside .ip-split-list):\n * .split-filter\n * Group header (sticky, collapsible):\n * .split-group .split-group.is-danger .split-group.is-collapsed\n * .split-group-chev\n * List row:\n * .split-row .split-row.is-selected .split-row.is-on\n * .split-row-accent .split-row-body .split-row-title\n * .split-row-sub .split-row-right .split-row-meta\n * .split-row-amt .split-row-when .split-row-when.is-urgent\n * Detail column layout:\n * .split-detail .split-detail-wrap\n * .split-detail-eyebrow .split-detail-title .split-detail-sub\n * Facts grid (key–value card):\n * .split-facts .split-fact-k .split-fact-v\n * Next-action card:\n * .split-next .split-next-head .split-next-body\n * Mini activity timeline (list-side only; deep timeline → ip-timeline):\n * .split-timeline .split-tl-row .split-tl-dot .split-tl-when\n *\n * NOT owned here — compose into this pattern:\n * .ip-split / .ip-split-list / .ip-split-divider / .ip-split-pane\n * — inspector-detail part (25)\n * .ip-head / .ip-body / .ip-title / .ip-meta-row\n * — inspector-detail part (25)\n * .ip-timeline / .ip-tl-item / .ip-tl-when / .ip-tl-actor\n * — inspector-detail part (25)\n * .badge / .chip / .tag / .next-chip\n * — badge-tag-chip part (11)\n * .btn / .btn-sm — button part (10)\n * .frame / .card — card part (21)\n * .tabs / .tab — segmented-tabs part (14)\n * ---------------------------------------------------------------- */\n\n/* === List column header ======================================== */\n/*\n * Sticky header inside .ip-split-list. Generalised from:\n * .pl-list-head (research line 1067) — display + title + meta count.\n * The header is always position:sticky top:0 so the domain label\n * stays visible as the user scrolls through a long list.\n */\n\n.split-list-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--space-3) var(--space-4);\n border-bottom: 1px solid var(--border-soft);\n background: var(--bg-surface);\n position: sticky;\n top: 0;\n z-index: 5;\n flex-shrink: 0;\n}\n\n/* Domain / route label — display weight (e.g. \"Research\", \"Tasks\") */\n.split-list-title {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-h3);\n color: var(--fg);\n}\n\n/* Right-side aggregate (e.g. \"8 open\", \"34 · 7 closed\") */\n.split-list-meta {\n font-family: var(--font-mono);\n font-size: 10.5px;\n color: var(--fg-faint);\n letter-spacing: 0.04em;\n}\n\n/* === Filter bar (optional) ===================================== */\n/*\n * Generalised from the .tk-filter-bar (tasks pane) and inline filter\n * controls (research pane). Sits below .split-list-head; also\n * position:sticky so it scrolls with the header as a unit.\n * Callers compose .input-field part (12) elements inside this bar.\n */\n\n.split-filter {\n padding: var(--space-2) var(--space-4);\n border-bottom: 1px solid var(--border-soft);\n background: var(--bg-surface);\n display: flex;\n align-items: center;\n gap: var(--space-2);\n position: sticky;\n top: 0;\n z-index: 4; /* below .split-list-head z-index:5 */\n flex-shrink: 0;\n}\n\n/* === Group header (sticky, collapsible) ======================== */\n/*\n * Generalised from .tk-group-head (tasks pane lines 1099–1119) and\n * .pl-sec (research pane lines 1071–1073).\n * Groups are sticky within the list column scroll container.\n * Mono uppercase label + right-side count; optionally collapsible\n * via .is-collapsed (chevron rotates −90°).\n */\n\n.split-group {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--space-2) var(--space-4) var(--space-1) var(--space-3);\n background: var(--bg-sunken);\n border-bottom: 1px solid var(--border-soft);\n border-top: 1px solid var(--border-soft);\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--fg-faint);\n position: sticky;\n top: 0;\n z-index: 3;\n cursor: pointer;\n user-select: none;\n}\n\n/* Remove the top border from the very first group in the list */\n.split-group:first-child {\n border-top: 0;\n}\n\n/* Danger / overdue group (e.g. \"Overdue · 2\" in tasks pane) */\n.split-group.is-danger {\n color: var(--danger);\n}\n\n/* Collapsed: background lifts to --bg-base to signal closed state */\n.split-group.is-collapsed {\n background: var(--bg-base);\n}\n\n/* Count slot — tabular numerals, slightly brighter than the label */\n.split-group .ct {\n color: var(--fg-muted);\n font-variant-numeric: tabular-nums;\n}\n\n/* Danger group count matches its label colour */\n.split-group.is-danger .ct {\n color: var(--danger);\n}\n\n/* Expand/collapse chevron SVG (10×10px icon — structural size) */\n.split-group-chev {\n width: 10px;\n height: 10px;\n color: var(--fg-faint);\n transition: transform var(--motion-fast) var(--ease-calm);\n flex-shrink: 0;\n}\n\n.split-group.is-collapsed .split-group-chev {\n transform: rotate(-90deg);\n}\n\n/* === List row ================================================== */\n/*\n * Generalised from:\n * .pl-row (research lines 1074–1086) — 3-column grid: accent | body | right\n * .ld-list rows (tasks) — same grid pattern (the task row uses .tk-row but\n * shares the same left-accent + body + right shape)\n *\n * Internal grid: 4px accent rail | 1fr body | auto right column.\n * The 4px accent width is structural fixed-geometry (hairline affordance).\n */\n\n.split-row {\n display: grid;\n grid-template-columns: 4px 1fr auto;\n gap: var(--space-2);\n padding: calc(var(--row-pad-y) + var(--space-1)) var(--space-4);\n border-bottom: 1px solid var(--border-soft);\n cursor: pointer;\n position: relative;\n transition: background var(--motion-fast) var(--ease-calm);\n}\n\n.split-row:hover {\n background: var(--bg-raised);\n}\n\n/* Selected / active: raised background — both .is-selected (pointer)\n and .is-on (keyboard) are valid selection signals */\n.split-row.is-selected,\n.split-row.is-on {\n background: var(--bg-raised);\n}\n\n/* --- Left accent rail ----------------------------------------- */\n/*\n * 4px narrow left-edge indicator. Transparent by default; fills with\n * the workspace tint (or primary) when the row is selected.\n * Also used for unread indicators (e.g. mail pane .is-unread uses primary).\n */\n\n.split-row-accent {\n width: 4px; /* structural fixed-geometry */\n border-radius: 2px; /* structural half of 4px */\n background: transparent;\n align-self: stretch;\n}\n\n.split-row.is-selected .split-row-accent,\n.split-row.is-on .split-row-accent {\n background: var(--tint-fg-active, var(--primary));\n}\n\n/* --- Body column (title + sub-rows) ---------------------------- */\n\n.split-row-body {\n min-width: 0; /* allow text-overflow in flex/grid child */\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n}\n\n/* Primary title — truncated to one line in the compressed column */\n.split-row-title {\n font-size: var(--text-body-sm);\n font-weight: 500;\n color: var(--fg);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n line-height: 1.35;\n}\n\n/* Sub-row (meta chips: type, owner, next-chip) */\n.split-row-sub {\n font-size: var(--text-caption);\n color: var(--fg-muted);\n display: flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n/* Meta chip cluster (badges, owner chips) — flex tray */\n.split-row-meta {\n display: flex;\n align-items: center;\n gap: var(--space-1);\n flex-wrap: wrap;\n}\n\n/* --- Right column (amount + timestamp) ------------------------- */\n\n.split-row-right {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 5px; /* tight fixed-geometry between cells */\n text-align: right;\n flex-shrink: 0;\n}\n\n/* Primary scalar value (word count, deal amount, entry count) */\n.split-row-amt {\n font-family: var(--font-mono);\n font-size: 12.5px;\n color: var(--fg);\n font-weight: 500;\n white-space: nowrap;\n}\n\n/* Relative timestamp (\"Today\", \"2d\", \"Next wk\") */\n.split-row-when {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n white-space: nowrap;\n}\n\n/* Overdue / urgent signal: danger colour on the timestamp */\n.split-row-when.is-urgent {\n color: var(--danger);\n}\n\n/* === Detail column layout ====================================== */\n/*\n * .split-detail wraps .ip-split-pane content when the domain's\n * detail view uses the softer pipeline shape (research, deals)\n * rather than the full inspector-head anatomy (.ip-head).\n * It adds inner padding and max-width on the content well.\n *\n * Callers who need the richer inspector head should compose\n * .ip-head / .ip-topline / .ip-title from the inspector-detail part (25).\n * These classes are for the lighter \"pipeline detail\" shape from the\n * research pane.\n */\n\n.split-detail {\n overflow-y: auto;\n background: var(--bg-surface);\n}\n\n/* Inner content well — capped width + generous padding */\n.split-detail-wrap {\n padding: var(--space-6) var(--space-7);\n max-width: 720px;\n}\n\n/* Eyebrow row (stage chip + next-mode chip) above the title */\n.split-detail-eyebrow {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n margin-bottom: var(--space-3);\n}\n\n/* Display-weight entity title (e.g. \"ICP: independent African labels\") */\n.split-detail-title {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-h2);\n line-height: 1.15;\n letter-spacing: -0.012em;\n color: var(--fg);\n margin: 0 0 var(--space-2);\n}\n\n/* Secondary subtitle (type · owner, e.g. \"Persona · nedjamez\") */\n.split-detail-sub {\n font-size: var(--text-body);\n color: var(--fg-muted);\n margin-bottom: var(--space-5);\n}\n\n/* === Facts grid ================================================= */\n/*\n * Generalised from .pl-facts / .pl-fact-k / .pl-fact-v\n * (research pane lines 1093–1096).\n * Horizontal three-column card of key–value pairs (Type, Detail, Updated).\n * Callers may override grid-template-columns for 2- or 4-column variants.\n */\n\n.split-facts {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: var(--space-3);\n margin-bottom: var(--space-5);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n padding: var(--space-4);\n background: var(--bg-sunken);\n}\n\n/* Fact label — mono uppercase micro-heading */\n.split-fact-k {\n font-family: var(--font-mono);\n font-size: 9.5px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--fg-faint);\n margin-bottom: 3px; /* tight fixed-geometry: label–value gap */\n}\n\n/* Fact value */\n.split-fact-v {\n font-size: var(--text-body);\n color: var(--fg);\n font-weight: 500;\n}\n\n/* === Next-action card ========================================= */\n/*\n * Generalised from .pl-next / .pl-next-head / .pl-next-body\n * (research pane lines 1097–1101).\n * Tinted card that surfaces the single actionable next step for the\n * selected item. Bordered with --live-soft to signal agent activity.\n */\n\n.split-next {\n border: 1px solid var(--live-soft, var(--border-soft));\n border-radius: var(--radius-md);\n padding: var(--space-4);\n background: color-mix(in srgb, var(--live) 7%, transparent);\n margin-bottom: var(--space-5);\n}\n\n/* \"Next action\" label — mono uppercase, small */\n.split-next-head {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--fg-muted);\n margin-bottom: var(--space-2);\n}\n\n/* Body text — the human-readable next action description */\n.split-next-body {\n font-size: var(--text-body);\n color: var(--fg);\n line-height: 1.5;\n margin-bottom: var(--space-3);\n}\n\n/* === Mini activity timeline (list-side) ======================== */\n/*\n * Simplified timeline used inside the detail pane when only a short\n * activity log is needed (research pane lines 1102–1106).\n * For the full dashed-rail timeline compose .ip-timeline from\n * the inspector-detail part (25) instead.\n *\n * This variant uses a 3-column grid: 14px dot rail | 1fr text.\n * The 14px rail and 8px dot are structural fixed-geometry.\n */\n\n.split-timeline {\n display: grid;\n gap: var(--space-3);\n margin-top: var(--space-2);\n}\n\n.split-tl-row {\n display: grid;\n grid-template-columns: 14px 1fr; /* 14px rail — fixed geometry */\n gap: var(--space-3);\n font-size: var(--text-body-sm);\n color: var(--fg-muted);\n}\n\n/* 8px filled circle node — structural icon geometry */\n.split-tl-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--border);\n margin-top: 5px; /* optical alignment with first text line */\n flex-shrink: 0;\n}\n\n/* Relative timestamp — mono, faint */\n.split-tl-when {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n letter-spacing: 0.04em;\n}\n\n/* === Focus-visible overrides ================================== */\n/*\n * .split-row and .split-group are interactive (cursor: pointer, JS handlers).\n * Without an explicit :focus-visible rule the browser default outline is\n * suppressed by the grid/flex layout resets in some shell contexts.\n * These rules satisfy WCAG 2.4.7 (focus indicator visible).\n */\n\n.split-row:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: -2px;\n}\n\n.split-group:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: -2px;\n}\n\n/* === Reduced-motion override =================================== */\n\n@media (prefers-reduced-motion: reduce) {\n .split-row,\n .split-group-chev {\n transition: none;\n }\n}\n\n\n/* ===== 33-toolbar-facet-sidebar.css ===== */\n/* Part: toolbar-facet-sidebar (Patterns)\n * Sources:\n * plans/atelier/designs/atelier-tasks.html (.tk-filterbar · .frame-head · sidebar facet groups)\n * plans/atelier/designs/atelier-finance.html (.fin-filterbar · #fin-toolbar sticky container)\n * plans/atelier/designs/atelier-outbound.html (.ob-subnav · .nl-inner-tabs · .nl-sent-toolbar · .ob-filter-chip)\n *\n * This partial owns ONLY the LAYOUT / COMPOSITION CSS for the pattern:\n * • .pane-toolbar — sticky content-body toolbar shell (wraps a filterbar or subnav)\n * • .pane-toolbar-sticky — modifier: sticks to the top of .content-body at z-index 4\n * • .pane-toolbar-tint — modifier: applies workspace-tint gradient identical to .frame-head\n * • .pane-filterbar — canonical filter bar shell (reconciles .tk-filterbar / .fin-filterbar)\n * • .pane-filterbar-search — icon-prepended search input wrapper\n * • .pane-filterbar-label — mono uppercase label preceding a select or chip group\n * • .pane-filterbar-spacer — flex spacer between left filters and right meta/actions\n * • .pane-filterbar-meta — tabular count / status string (right-aligned)\n * • .pane-subnav — pill-button sub-navigation strip (reconciles .ob-subnav)\n * • .pane-subnav-count — mono pill count badge inside a .pane-subnav button\n * • .pane-subnav-alert — danger dot alerting on a subnav button\n * • .pane-inner-tabs — pill-style inner view tabs (reconciles .nl-inner-tabs)\n * • .pane-filter-chip — standalone pill chip for sent-history filters\n * • .pane-view-toggle — segmented table/chart toggle (right-pushed)\n *\n * NOT owned here — referenced by composition:\n * .btn-icon — icon button (part 10, button.css)\n * .input — form input field (part 12, input-field.css)\n * .side-menu-nav — sidebar nav groups incl. facet groups (part 22, side-menu-nav.css)\n * .nav-group.is-dim — list-only facet dim rule (part 22)\n * .content-tabs / .content-tabs-actions — tab strip chrome (shell shared)\n *\n * Merge narrative:\n * atelier-tasks.html defines .tk-filterbar (flex row, bg-sunken, border-bottom-soft,\n * space-3/space-5 pad). atelier-finance.html defines .fin-filterbar with identical\n * geometry but adds date inputs + an EntitySwitcher on the right. atelier-outbound.html\n * defines three complementary strips: .ob-subnav (ghost-pill outer nav), .nl-inner-tabs\n * (bordered-pill inner view tabs), and .nl-sent-toolbar (chip filter + view toggle).\n * All four source classes are canonicalised here under a shared `.pane-filterbar` shell\n * plus the narrow specialisations. Hardcoded pixel values that have no token (13px\n * search icon, 28px compact control height, 1px divider hairline, 6px alert dot) are\n * structural fixed-geometry and are preserved as px.\n * ---------------------------------------------------------------- */\n\n\n/* ================================================================\n STICKY TOOLBAR SHELL\n Wraps the filterbar or subnav inside .content-body.\n z-index 4 matches the value used by #fin-toolbar and .tk-group-head.\n ================================================================ */\n\n.pane-toolbar {\n /* Surface is bg-sunken by default — same as the filterbar strips.\n Override with .pane-toolbar-tint for a workspace-tinted head. */\n background: var(--bg-sunken);\n border-bottom: 1px solid var(--border-soft);\n}\n\n.pane-toolbar-sticky {\n position: sticky;\n top: 0;\n z-index: 4;\n}\n\n/* Workspace-tinted variant — mirrors .frame-head gradient.\n Apply alongside .pane-toolbar when the toolbar leads the body. */\n.pane-toolbar.pane-toolbar-tint {\n background: linear-gradient(\n 180deg,\n var(--tint-bg-active, var(--bg-surface)) 0%,\n var(--bg-surface) 100%\n );\n}\n\n\n/* ================================================================\n PANE FILTER BAR\n Horizontal flex strip: search · label · select · [toggle] · spacer · meta.\n Reconciles .tk-filterbar (tasks) and .fin-filterbar (finance).\n ================================================================ */\n\n.pane-filterbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-3) var(--space-5);\n /* background and border-bottom inherited from .pane-toolbar parent;\n this rule only governs layout so the bar may also be used standalone. */\n background: var(--bg-sunken);\n border-bottom: 1px solid var(--border-soft);\n}\n\n/* Icon-prepended search wrapper.\n Icon is positioned absolutely at left: 8px (fixed geometry). */\n.pane-filterbar-search {\n position: relative;\n display: inline-flex;\n}\n\n.pane-filterbar-search > svg {\n position: absolute;\n left: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 13px; /* icon fixed geometry */\n height: 13px;\n color: var(--fg-faint);\n pointer-events: none;\n}\n\n/* The input inside the search wrapper.\n Composes .input (part 12) for border/focus/bg — only overrides size. */\n.pane-filterbar-search > input {\n width: 280px;\n height: 28px; /* compact control height — no density token */\n padding: 0 var(--space-3) 0 28px; /* 28px = 8px left-gap + 13px icon + 7px gap */\n font-size: var(--text-body-sm);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n color: var(--fg);\n font-family: inherit;\n}\n\n.pane-filterbar-search > input::placeholder {\n color: var(--fg-faint);\n}\n\n/* Compact selects and date inputs share the same control height. */\n.pane-filterbar select,\n.pane-filterbar input[type=\"date\"] {\n height: 28px;\n padding: 0 var(--space-2);\n font-size: var(--text-body-sm);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n color: var(--fg);\n font-family: inherit;\n}\n\n/* date input: inherit color-scheme from html data-mode so native\n calendar matches the shell theme. */\n.pane-filterbar input[type=\"date\"] {\n color-scheme: dark;\n}\n[data-mode=\"light\"] .pane-filterbar input[type=\"date\"] {\n color-scheme: light;\n}\n\n/* Uppercase mono label preceding a select or chip cluster. */\n.pane-filterbar-label {\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--fg-faint);\n}\n\n/* Flex spacer — pushes right-side meta / entity-switcher to the edge. */\n.pane-filterbar-spacer {\n flex: 1;\n}\n\n/* Tabular row count / status string — right-aligned, mono. */\n.pane-filterbar-meta {\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: 0.04em;\n color: var(--fg-faint);\n}\n\n\n/* ================================================================\n PANE SUB-NAV (.ob-subnav)\n Ghost-pill outer sub-navigation — workspace-tinted active state.\n Used by Outbound to switch between Channels on mobile-style screens\n where the sidebar is not the primary channel switcher.\n ================================================================ */\n\n.pane-subnav {\n display: flex;\n gap: var(--space-1);\n padding: var(--space-2) var(--space-4);\n background: var(--bg-surface);\n border-bottom: 1px solid var(--border-soft);\n}\n\n.pane-subnav button {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-1) var(--space-3);\n border-radius: var(--radius-sm);\n background: transparent;\n border: 0;\n font-family: inherit;\n font-size: var(--text-body-sm);\n color: var(--fg-muted);\n cursor: pointer;\n transition:\n background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n.pane-subnav button:hover {\n color: var(--fg);\n}\n\n.pane-subnav button.is-on {\n color: var(--tint-fg-active, var(--primary));\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 8%, transparent);\n}\n\n/* Mono pill badge inside a subnav button. */\n.pane-subnav-count {\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: 0.04em;\n color: var(--fg-faint);\n padding: 1px var(--space-2);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-pill);\n background: var(--bg-base);\n}\n\n.pane-subnav button.is-on .pane-subnav-count {\n color: var(--tint-fg-active, var(--primary));\n border-color: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 30%, var(--border));\n}\n\n/* Danger alert dot on a subnav item (e.g. items overdue in a channel). */\n.pane-subnav-alert {\n display: inline-block;\n width: 6px; /* fixed geometry — no token */\n height: 6px;\n border-radius: 50%;\n background: var(--danger);\n margin-left: var(--space-1);\n}\n\n\n/* ================================================================\n PANE INNER TABS (.nl-inner-tabs)\n Bordered-pill view switcher rendered inside the content body,\n below the domain header / channel sub-nav. Switches Approval queue /\n Schedule / Sent within the active channel.\n ================================================================ */\n\n.pane-inner-tabs {\n display: flex;\n gap: var(--space-1);\n padding: var(--space-2) var(--space-3);\n background: var(--bg-surface);\n border-bottom: 1px solid var(--border-soft);\n}\n\n.pane-inner-tabs button {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n padding: var(--space-1) var(--space-2);\n border-radius: var(--radius-pill);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n font-family: inherit;\n font-size: var(--text-body-sm);\n color: var(--fg-muted);\n cursor: pointer;\n transition:\n background var(--motion-fast) var(--ease-calm),\n border-color var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n.pane-inner-tabs button.is-on {\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 14%, var(--bg-base));\n border-color: var(--tint-fg-active, var(--primary));\n color: var(--tint-fg-active, var(--primary));\n}\n\n/* Count label inside an inner tab button. */\n.pane-inner-tabs .ct {\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: 0.04em;\n color: var(--fg-faint);\n}\n\n.pane-inner-tabs button.is-on .ct {\n color: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 70%, var(--fg-muted));\n}\n\n\n/* ================================================================\n PANE FILTER CHIP (.ob-filter-chip)\n Standalone pill chip used in secondary filter toolbars\n (e.g. sent-history: \"All types\" / \"Newsletter\" / \"Investor update\").\n ================================================================ */\n\n.pane-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n padding: 3px var(--space-2);\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-pill);\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: 0.04em;\n color: var(--fg-muted);\n cursor: pointer;\n transition:\n background var(--motion-fast) var(--ease-calm),\n border-color var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n.pane-filter-chip.is-on {\n background: color-mix(in srgb, var(--tint-fg-active, var(--primary)) 14%, var(--bg-base));\n border-color: var(--tint-fg-active, var(--primary));\n color: var(--tint-fg-active, var(--primary));\n}\n\n\n/* ================================================================\n PANE VIEW TOGGLE (.nl-view-toggle)\n Segmented two-button toggle (Table / Charts) pushed right by the\n flex spacer in its parent toolbar.\n ================================================================ */\n\n.pane-view-toggle {\n display: inline-flex;\n background: var(--bg-base);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-sm);\n overflow: hidden;\n margin-left: auto; /* self-push when not already in a spacer context */\n}\n\n.pane-view-toggle button {\n background: none;\n border: 0;\n padding: var(--space-1) var(--space-2);\n font-family: var(--font-mono);\n font-size: 10.5px;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--fg-muted);\n cursor: pointer;\n transition:\n background var(--motion-fast) var(--ease-calm),\n color var(--motion-fast) var(--ease-calm);\n}\n\n.pane-view-toggle button.is-on {\n background: var(--bg-raised);\n color: var(--fg);\n}\n\n\n/* ================================================================\n SIDEBAR FACET GROUP LAYOUT COMPOSITION\n The sidebar's \"Filter\" nav-groups are rendered via .nav-group /\n .nav-item (part 22, side-menu-nav.css). This partial only owns the\n dim-and-inert rule for list-only facets (R23 — tasks pane), because\n .nav-group.is-dim is set by JS (not by side-menu-nav.css) and is\n conceptually part of the toolbar-facet-sidebar coordination contract.\n All other .nav-group / .nav-item rules live in part 22.\n ================================================================ */\n\n/* List-only facet groups dim + go pointer-inert when a non-list view is\n active. Set by JS: slot.querySelectorAll('.nav-group[data-kind=\"filter\"]')\n .forEach(g => g.classList.toggle('is-dim', view !== 'tasks')). */\n.nav-group[data-kind=\"filter\"].is-dim {\n opacity: 0.4;\n pointer-events: none;\n transition: opacity var(--motion-base) var(--ease-calm);\n}\n\n\n/* ================================================================\n FOCUS-VISIBLE OVERRIDES\n All interactive elements in this pattern must have a visible\n focus indicator to satisfy WCAG 2.4.7 (focus always visible).\n The shell resets outline on some button elements; these rules\n restore a 2px primary-colour ring on keyboard focus.\n ================================================================ */\n\n.pane-subnav button:focus-visible,\n.pane-inner-tabs button:focus-visible,\n.pane-filter-chip:focus-visible,\n.pane-view-toggle button:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n.pane-filterbar-search > input:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n\n/* ================================================================\n REDUCED-MOTION OVERRIDES\n Transitions in .pane-subnav button, .pane-inner-tabs button,\n .pane-filter-chip, and .pane-view-toggle button are short\n (var(--motion-fast) ≈ 120 ms) but must be suppressed for users\n who require reduced motion.\n ================================================================ */\n\n@media (prefers-reduced-motion: reduce) {\n .pane-subnav button,\n .pane-inner-tabs button,\n .pane-filter-chip,\n .pane-view-toggle button,\n .nav-group[data-kind=\"filter\"].is-dim {\n transition: none;\n }\n}\n\n\n/* ===== 34-ux-mode-action-surfaces.css ===== */\n/* =============================================================================\n Atelier app-kit · part 34 · UX-Mode Action Surfaces (Pattern)\n Source panes:\n - plans/atelier/designs/atelier-tasks.html\n .tk-execmode pill family (lines 1241–1251)\n .ag-block mode-tint family (lines 1749–1761)\n - plans/atelier/designs/atelier-approve-gate.html\n .ob-detail pane shell (lines 1116, 1264)\n .ob-chip family (lines 1059–1103)\n .ob-seq-callout (lines 1137–1148)\n .ob-edit-subject (lines 1157–1170)\n .ob-quick-edit family (lines 1172–1205)\n .ob-detail-toolbar (lines 1117–1125)\n .ob-detail-body (line 1127)\n .ob-detail-head family (lines 1129–1135)\n .ob-section / .ob-section-count (lines 1107–1113)\n\n This pattern owns the LAYOUT and COMPOSITION CSS that binds the five\n ux_mode visual surfaces together. It does NOT redefine classes owned by\n sibling partials — it only references them by name in comments.\n\n Classes owned here:\n Exec-mode pill (.tk-execmode family):\n .tk-execmode\n .tk-execmode.is-autonomous\n .tk-execmode.is-approval_required\n .tk-execmode.is-report\n\n Agenda lane mode-tint (.ag-block family):\n .ag-block\n .ag-block.is-me\n .ag-block.is-agent\n .ag-block.is-silent\n .ag-block.is-deadline\n .ag-block.is-done\n .ag-block .t\n .ag-block.is-done .t\n .ag-block .m\n\n Approve-gate detail pane shell:\n .ob-detail (container-type: inline-size host)\n .ob-section (list-column section label)\n .ob-section-count\n .ob-detail-toolbar (sticky toolbar strip, list column)\n .ob-detail-toolbar-spacer\n .ob-detail-toolbar-meta\n .ob-detail-body (scrollable body, right pane)\n .ob-detail-head (recipient + chips block)\n .ob-detail-to-row\n .ob-detail-to-name\n .ob-detail-to-addr\n .ob-detail-subject (display-face subject heading)\n .ob-detail-meta (chips row)\n\n Approve-gate chip family:\n .ob-chip\n .ob-chip.is-mode\n .ob-chip.is-approve\n .ob-chip.sender\n .ob-chip.sender.cold\n\n Sequence-context callout:\n .ob-seq-callout\n .ob-seq-callout strong .ob-seq-callout svg\n .ob-seq-callout-actions\n\n Inline draft editor:\n .ob-edit-subject (editable subject heading)\n .ob-quick-edit\n .ob-quick-edit-head .ob-quick-edit-head svg\n .ob-quick-edit textarea\n .ob-quick-edit-foot\n .ob-quick-edit-foot .saved\n\n NOT redefined here (owned by their respective parts):\n .ux .ux.approve .ux.silent .ux.confirm .ux.streaming .ux.form\n → 23-command-palette.css\n .ob-actions .ob-actions-cluster .ob-actions-spacer\n .ob-actions-primary .ob-actions-meta\n .w-quick .qrow .qmeta\n → 24-action-bar-quick.css\n .atelier-state .atelier-prog .atelier-spin\n → 26-feedback-state.css\n .btn .btn-sm .btn-outline\n → 10-button.css\n\n Token-only rule: all color/space/radius/type values use var(--*).\n Permitted literal px: 1px hairlines, icon sizes, structural geometry\n (5px padding below --space-1, 9px pill font, 3px left-border accent).\n ============================================================================= */\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 1. EXEC-MODE PILL (.tk-execmode)\n ───────────────────────────────────────────────────────────────────────────\n Compact mode annotation affixed to task rows, agenda blocks, and timeline\n entries. Dashed border signals \"runtime attribute, not a status badge.\"\n Three exec-mode variants map to the three non-interactive ux_mode signals:\n autonomous → --agent (agent-driven, no gate)\n approval_required → --achievement (needs owner sign-off)\n report → --systemic (background silent / scheduled)\n The palette's per-action .ux badge (23-command-palette.css) renders the\n full five ux_mode values; .tk-execmode is the task-row inline variant.\n ─────────────────────────────────────────────────────────────────────────── */\n\n.tk-execmode {\n font-family: var(--font-mono);\n font-size: 9px;\n letter-spacing: .06em;\n text-transform: uppercase;\n color: var(--fg-faint);\n border: 1px dashed var(--border-soft);\n /* 1px 5px is structural pill geometry (below --space-1); border-radius from token */\n padding: 1px 5px;\n border-radius: var(--radius-xs);\n background: transparent;\n}\n\n/* Autonomous — agent-driven, no human gate required */\n.tk-execmode.is-autonomous {\n color: var(--agent);\n border-color: color-mix(in srgb, var(--agent) 30%, var(--border-soft));\n}\n\n/* Approval required — paused, needs owner decision (approve-mode outcome) */\n.tk-execmode.is-approval_required {\n color: var(--achievement);\n border-color: color-mix(in srgb, var(--achievement) 35%, var(--border-soft));\n}\n\n/* Report / silent — completed background run; read-only evidence record */\n.tk-execmode.is-report {\n color: var(--systemic);\n border-color: color-mix(in srgb, var(--systemic) 30%, var(--border-soft));\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 2. AGENDA-LANE BLOCK (.ag-block)\n ───────────────────────────────────────────────────────────────────────────\n Time-rail blocks rendered inside the Tasks Agenda view. Left-border accent\n communicates ux_mode / owner at a glance; background fill is additive on\n the accent only (no base background, to keep the rail readable).\n Maps to the locked D-01 Agenda design (atelier-tasks.html).\n\n is-me → --primary (operator-owned item)\n is-agent → --agent (agent-run item; soft fill)\n is-silent → --systemic (scheduled background job; dashed border)\n is-deadline → --danger (hard deadline; danger tint fill)\n is-done → opacity .6 + strikethrough (auto-closed / completed)\n\n 3px left-border is structural accent geometry, not a spacing token.\n ─────────────────────────────────────────────────────────────────────────── */\n\n.ag-block {\n background: var(--bg-raised);\n border-radius: var(--radius-sm);\n border-left: 3px solid var(--fg-faint);\n padding: var(--space-2) var(--space-3);\n margin-bottom: var(--space-2);\n}\n\n.ag-block:last-child {\n margin-bottom: 0;\n}\n\n/* Operator-owned task — primary tint left border */\n.ag-block.is-me {\n border-left-color: var(--primary);\n}\n\n/* Agent-run task — agent accent + soft agent fill */\n.ag-block.is-agent {\n border-left-color: var(--agent);\n background: var(--agent-soft);\n}\n\n/* Silent / scheduled background job — systemic accent, dashed, no fill */\n.ag-block.is-silent {\n border-left-color: var(--systemic);\n border-left-style: dashed;\n background: transparent;\n}\n\n/* Hard deadline item — danger accent + subtle danger fill */\n.ag-block.is-deadline {\n border-left-color: var(--danger);\n background: color-mix(in srgb, var(--danger) 8%, transparent);\n}\n\n/* Completed / auto-closed — dimmed; title gains a strike */\n.ag-block.is-done {\n opacity: .6;\n}\n\n/* Block title */\n.ag-block .t {\n font-size: var(--text-body-sm);\n color: var(--fg);\n font-weight: 500;\n line-height: 1.4;\n}\n\n/* Completed title — struck through */\n.ag-block.is-done .t {\n text-decoration: line-through;\n text-decoration-thickness: 1px;\n color: var(--fg-muted);\n}\n\n/* Meta row — chip cluster below the title */\n.ag-block .m {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n margin-top: var(--space-1);\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 3. APPROVE-GATE DETAIL PANE — SHELL\n ───────────────────────────────────────────────────────────────────────────\n The right-hand detail column of the approve-gate panel (D-04). The pane\n hosts the draft editor, chip cluster, sequence callout, and the sticky\n .ob-actions footer (owned by 24-action-bar-quick.css).\n\n .ob-detail declares container-type: inline-size so the responsive\n @container ob-detail rule in 24-action-bar-quick.css fires correctly.\n ─────────────────────────────────────────────────────────────────────────── */\n\n/* Scrolling right pane — declares the container context used by .ob-actions */\n.ob-detail {\n overflow-y: auto;\n background: var(--bg-surface);\n container-type: inline-size;\n container-name: ob-detail;\n}\n\n/* ── Approve-gate list column section label ──────────────────────────────── */\n.ob-section {\n padding: var(--space-2) var(--space-3);\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: .12em;\n text-transform: uppercase;\n color: var(--fg-faint);\n background: var(--bg-sunken);\n border-bottom: 1px solid var(--border-soft);\n display: flex;\n align-items: baseline;\n gap: var(--space-2);\n}\n\n.ob-section-count {\n color: var(--fg-muted);\n font-weight: 400;\n}\n\n/* ── Sticky detail toolbar (list column top bar) ─────────────────────────── */\n.ob-detail-toolbar {\n padding: var(--space-2) var(--space-3);\n border-bottom: 1px solid var(--border-soft);\n background: var(--bg-sunken);\n display: flex;\n align-items: center;\n gap: var(--space-1);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.ob-detail-toolbar-spacer {\n flex: 1;\n}\n\n.ob-detail-toolbar-meta {\n font-family: var(--font-mono);\n font-size: 10.5px;\n color: var(--fg-faint);\n letter-spacing: .04em;\n margin-right: var(--space-2);\n}\n\n/* ── Scrollable body (right column content area) ─────────────────────────── */\n.ob-detail-body {\n padding: var(--space-6) var(--space-8);\n max-width: 820px;\n margin: 0 auto;\n}\n\n/* ── Recipient + chips header block ──────────────────────────────────────── */\n.ob-detail-head {\n padding-bottom: var(--space-4);\n margin-bottom: var(--space-5);\n border-bottom: 1px solid var(--border-soft);\n}\n\n.ob-detail-to-row {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n margin-bottom: var(--space-3);\n}\n\n.ob-detail-to-name {\n font-weight: 600;\n font-size: var(--text-body);\n color: var(--fg);\n}\n\n.ob-detail-to-addr {\n font-family: var(--font-mono);\n font-size: var(--text-micro);\n color: var(--fg-muted);\n}\n\n/* Display-face subject heading (static, non-editable header) */\n.ob-detail-subject {\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-h1);\n line-height: 1.18;\n letter-spacing: -.012em;\n margin: var(--space-3) 0;\n color: var(--fg);\n}\n\n/* Chips row below the subject */\n.ob-detail-meta {\n display: flex;\n gap: var(--space-2);\n flex-wrap: wrap;\n align-items: center;\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 4. APPROVE-GATE CHIP FAMILY (.ob-chip)\n ───────────────────────────────────────────────────────────────────────────\n Inline metadata chips: ux_mode badge, domain tag, sender attribution.\n .is-mode variant highlights the ux_mode value using --live/-soft (approve).\n .sender is mono faint, dashed border. .sender.cold lifts to achievement\n tint to signal an unsolicited (cold outreach) sender.\n ─────────────────────────────────────────────────────────────────────────── */\n\n/* The .ob-chip BASE rule + .sender / .sender.cold variants are owned by\n 11-badge-tag-chip.css (the canonical pill). This part adds ONLY the\n approve-gate ux_mode modifiers, so there is no base-rule collision. */\n\n/* ux_mode highlight — approve mode uses --live tint */\n.ob-chip.is-mode {\n color: var(--live);\n background: var(--live-soft);\n border-color: var(--live-soft);\n}\n\n/* Approve variant (synonym for is-mode; used on the approve chip explicitly) */\n.ob-chip.is-approve {\n color: var(--live);\n background: var(--live-soft);\n border-color: var(--live-soft);\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 5. SEQUENCE-CONTEXT CALLOUT (.ob-seq-callout)\n ───────────────────────────────────────────────────────────────────────────\n A tinted callout that appears when the draft under review is part of a\n multi-step outbound sequence (e.g. seq3-universal-pt). Uses the active\n workspace tint (--tint-fg-active / --tint-bg-active) so the callout\n tracks the domain colour without a hardcoded sequence accent.\n ─────────────────────────────────────────────────────────────────────────── */\n\n.ob-seq-callout {\n margin-top: var(--space-4);\n padding: var(--space-3);\n border: 1px solid color-mix(in srgb,\n var(--tint-fg-active, var(--primary)) 30%,\n var(--border));\n background: color-mix(in srgb,\n var(--tint-fg-active, var(--primary)) 8%,\n transparent);\n border-radius: var(--radius-md);\n font-size: var(--text-caption);\n color: var(--fg-muted);\n line-height: 1.55;\n}\n\n.ob-seq-callout strong {\n color: var(--tint-fg-active, var(--primary));\n font-weight: 600;\n}\n\n/* 12 × 12 px inline icon (structural icon geometry — not a spacing token) */\n.ob-seq-callout svg {\n width: 12px;\n height: 12px;\n vertical-align: -1.5px;\n margin-right: var(--space-1);\n color: var(--tint-fg-active, var(--primary));\n}\n\n/* Action row below the callout body (e.g. \"View sequence\" buttons) */\n.ob-seq-callout-actions {\n margin-top: var(--space-2);\n display: flex;\n gap: var(--space-2);\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 6. INLINE DRAFT EDITOR\n ───────────────────────────────────────────────────────────────────────────\n Two inline-edit surfaces that let the operator tweak the draft before\n approving, without leaving the approve-gate pane.\n\n a) .ob-edit-subject — the editable display-font subject line. Invisible\n border reveals on hover/focus, providing a subtle affordance.\n b) .ob-quick-edit — sunken card for body-level quick edits (textarea).\n\n Note: for a full rewrite the operator uses \"Send to chat\" / \"Continue\n Claude session\" via .ob-actions-cluster (24-action-bar-quick.css).\n ─────────────────────────────────────────────────────────────────────────── */\n\n/* Editable subject — matches .ob-detail-subject scale but accepts input */\n.ob-edit-subject {\n width: 100%;\n font-family: var(--font-display);\n font-weight: 500;\n font-size: var(--text-h1);\n line-height: 1.18;\n letter-spacing: -.012em;\n color: var(--fg);\n background: transparent;\n border: 0;\n /* Dashed bottom border reveals affordance on interaction */\n border-bottom: 1px dashed transparent;\n padding: var(--space-1) 0;\n outline: none;\n transition: border-color var(--motion-fast) var(--ease-calm);\n}\n\n.ob-edit-subject:hover {\n border-bottom-color: var(--border-soft);\n}\n\n.ob-edit-subject:focus {\n border-bottom-color: var(--tint-fg-active, var(--primary));\n}\n\n/* Sunken quick-edit card (body-level tweaks) */\n.ob-quick-edit {\n margin-top: var(--space-5);\n background: var(--bg-sunken);\n border: 1px solid var(--border-soft);\n border-radius: var(--radius-md);\n padding: var(--space-3);\n}\n\n.ob-quick-edit-head {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n margin-bottom: var(--space-2);\n font-family: var(--font-mono);\n font-size: 10px;\n letter-spacing: .08em;\n text-transform: uppercase;\n color: var(--fg-faint);\n}\n\n/* 12 × 12 px lead icon (structural icon geometry) */\n.ob-quick-edit-head svg {\n width: 12px;\n height: 12px;\n color: var(--tint-fg-active, var(--primary));\n}\n\n/* Textarea — transparent background, respects shell font */\n.ob-quick-edit textarea {\n width: 100%;\n background: transparent;\n border: 0;\n color: var(--fg);\n font-family: inherit;\n font-size: var(--text-body);\n line-height: 1.6;\n outline: none;\n resize: vertical;\n min-height: var(--space-20); /* ≈ 80px — structural minimum height */\n}\n\n.ob-quick-edit textarea::placeholder {\n color: var(--fg-faint);\n}\n\n/* Footer strip — save-state annotation + action buttons */\n.ob-quick-edit-foot {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n margin-top: var(--space-2);\n padding-top: var(--space-2);\n border-top: 1px solid var(--border-soft);\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--fg-faint);\n letter-spacing: .04em;\n}\n\n/* \"Saved\" confirmation badge — achievement tint, right-aligned via margin-left: auto */\n.ob-quick-edit-foot .saved {\n margin-left: auto;\n color: var(--achievement);\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 7. FOCUS-VISIBLE — INLINE EDITOR ELEMENTS\n ──────────────────────────────────────────────────────────────────────────\n .ob-edit-subject and .ob-quick-edit textarea both declare outline: none,\n which suppresses the browser default focus ring. Provide explicit\n :focus-visible rings so keyboard users can identify the active editor.\n The subject line uses a border-bottom affordance on :focus; a ring is\n added on top for keyboard-only navigators (WCAG 2.4.7).\n ─────────────────────────────────────────────────────────────────────────── */\n\n.ob-edit-subject:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n.ob-quick-edit textarea:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n}\n\n\n/* ═══════════════════════════════════════════════════════════════════════════\n 8. MOTION — REDUCED-MOTION OVERRIDES\n ─────────────────────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .ob-edit-subject {\n transition: none;\n }\n}\n";
@@ -0,0 +1,137 @@
1
+ // Assignee roster — single source of truth for who a task can be owned by, used
2
+ // by both the create form (owner field) and the detail pane's Reassign picker.
3
+ //
4
+ // Two assignee kinds map onto the `tasks` columns: `assigned_to` (the id —
5
+ // an email for a human, an agent id like `cfo-agent` for an agent) and
6
+ // `assignee_type` ('human' | 'agent'). `assigneeIsAgent` in shared.js also
7
+ // treats a trailing `-agent` as the agent convention, so keep agent ids
8
+ // suffixed `-agent`.
9
+ //
10
+ // ## Roster resolution
11
+ //
12
+ // The roster is INJECTABLE via `hostContext.royaltiSuite.tasksRoster` at
13
+ // iframe-mount time. The shell delivers hostContext through the AppBridge
14
+ // `connectBridge` return value and the `onContextChange` callback (see
15
+ // bridge.js / app.js). The expected shape is:
16
+ //
17
+ // hostContext.royaltiSuite.tasksRoster = {
18
+ // humans: [{ value: string, label: string }], // email → display name
19
+ // agents: [{ id: string, label: string }], // agent-id → display name
20
+ // }
21
+ //
22
+ // When `tasksRoster` is present and well-formed (both arrays non-empty) the
23
+ // configured list takes full precedence over the static defaults below.
24
+ // When absent or malformed the static CURRENT_USER + AGENT_ROSTER fallback
25
+ // remains active — so the pkg works unchanged today and on every future
26
+ // install that hasn't run `skill-tasks setup` yet.
27
+ //
28
+ // ## Shell hook needed (WP-10 contract side)
29
+ //
30
+ // The shell must read `.atelier/skill-tasks/roster.json` from the current
31
+ // project dir (the directory passed as --project / CLAUDE_PROJECT_DIR) and
32
+ // inject it as `hostContext.royaltiSuite.tasksRoster` when building the
33
+ // hostContext object for this pkg's iframe (pkg-iframe-host.tsx). The JSON
34
+ // file shape mirrors the `tasksRoster` field above:
35
+ // { "humans": [{"value":"...", "label":"..."}],
36
+ // "agents": [{"id":"...", "label":"..."}] }
37
+ // Written by `skill-tasks` `setup` (WP-06 setup lifecycle); the shell need
38
+ // only pass it through — it must not transform or cache it.
39
+
40
+ // The logged-in human. TODO(hello@royalti.io): thread from
41
+ // hostContext.royaltiAuth once it carries the user email (mirrors the same TODO
42
+ // in tasks-view.js — this module is now the one place that literal lives).
43
+ export const CURRENT_USER = 'hello@royalti.io';
44
+
45
+ /** @typedef {{ id: string, label: string }} AgentEntry */
46
+
47
+ /** @type {AgentEntry[]} */
48
+ export const AGENT_ROSTER = [
49
+ { id: 'cfo-agent', label: 'CFO · Finance' },
50
+ { id: 'cmo-agent', label: 'CMO · Marketing' },
51
+ { id: 'coo-agent', label: 'COO · Operations' },
52
+ { id: 'content-agent', label: 'Content' },
53
+ { id: 'outbound-agent', label: 'Outbound' },
54
+ ];
55
+
56
+ /** @typedef {{ value: string, label: string, type: 'human' | 'agent' }} AssigneeOption */
57
+
58
+ /**
59
+ * @typedef {{ value: string, label: string }} HumanEntry
60
+ * @typedef {{ humans: HumanEntry[], agents: AgentEntry[] }} TasksRoster
61
+ */
62
+
63
+ /**
64
+ * Validate and return a configured roster from `hostContext.royaltiSuite.tasksRoster`,
65
+ * or `null` if absent / malformed. A valid roster has both `humans` and `agents`
66
+ * as non-empty arrays.
67
+ *
68
+ * @param {unknown} [hostContext]
69
+ * @returns {TasksRoster | null}
70
+ */
71
+ export function resolveRoster(hostContext) {
72
+ const raw = /** @type {any} */ (hostContext)?.royaltiSuite?.tasksRoster;
73
+ if (!raw) return null;
74
+ const { humans, agents } = raw;
75
+ if (
76
+ !Array.isArray(humans) || humans.length === 0 ||
77
+ !Array.isArray(agents) || agents.length === 0
78
+ ) {
79
+ return null;
80
+ }
81
+ // Basic per-entry shape validation — skip malformed entries rather than reject.
82
+ const validHumans = humans.filter(
83
+ (h) => h && typeof h.value === 'string' && typeof h.label === 'string',
84
+ );
85
+ const validAgents = agents.filter(
86
+ (a) => a && typeof a.id === 'string' && typeof a.label === 'string',
87
+ );
88
+ if (validHumans.length === 0 || validAgents.length === 0) return null;
89
+ return { humans: validHumans, agents: validAgents };
90
+ }
91
+
92
+ /**
93
+ * Flat option list for an assignee <select>. "Me" first (human), then each
94
+ * configured agent. The empty-value "Unassigned" sentinel is added by the
95
+ * caller's <select> so this list stays purely the real assignees.
96
+ *
97
+ * Accepts an optional `hostContext` object. When it carries a valid
98
+ * `royaltiSuite.tasksRoster`, the configured roster wins. Without it (or when
99
+ * the roster is absent/malformed) the static CURRENT_USER + AGENT_ROSTER
100
+ * defaults are used, so existing call sites calling the no-arg form remain
101
+ * correct without modification.
102
+ *
103
+ * @param {unknown} [hostContext]
104
+ * @returns {AssigneeOption[]}
105
+ */
106
+ export function assigneeOptions(hostContext) {
107
+ const roster = resolveRoster(hostContext);
108
+ if (roster) {
109
+ return [
110
+ ...roster.humans.map((h) => ({ value: h.value, label: h.label, type: /** @type {'human'} */ ('human') })),
111
+ ...roster.agents.map((a) => ({ value: a.id, label: a.label, type: /** @type {'agent'} */ ('agent') })),
112
+ ];
113
+ }
114
+ // Static fallback — unchanged behaviour.
115
+ return [
116
+ { value: CURRENT_USER, label: 'Me', type: 'human' },
117
+ ...AGENT_ROSTER.map((a) => ({ value: a.id, label: a.label, type: /** @type {'agent'} */ ('agent') })),
118
+ ];
119
+ }
120
+
121
+ /**
122
+ * Resolve a picked `assigned_to` value back to its `assignee_type`. Falls back
123
+ * to the `-agent` naming convention for ids not in the roster (e.g. legacy rows
124
+ * or a future configured agent not yet reflected here).
125
+ *
126
+ * Accepts an optional `hostContext`; threads it through to `assigneeOptions` so
127
+ * the configured roster (when present) is consulted first.
128
+ *
129
+ * @param {string} value
130
+ * @param {unknown} [hostContext]
131
+ * @returns {'human' | 'agent'}
132
+ */
133
+ export function assigneeTypeFor(value, hostContext) {
134
+ const match = assigneeOptions(hostContext).find((o) => o.value === value);
135
+ if (match) return match.type;
136
+ return value.endsWith('-agent') ? 'agent' : 'human';
137
+ }