Skip to content

canon extract polaris

Polaris dashboard.html — Design canon extraction (verbatim)

Section titled “Polaris dashboard.html — Design canon extraction (verbatim)”

Source of truth: /Users/Ridwan/Pictures/Claude/Rechaj 2.0/rechaj-design-system/products/polaris/screens/dashboard.html (4197 lines, read in full).

File structure: two <style> blocks — an inherited Caesar base layer (lines 8–737, header comment says “CAESAR — Dashboard… Prefix: cz-*” though no cz- classes actually appear) and a Polaris layer (lines 742–1453, comment: “Polaris component styles (layered on the inherited Rechaj DS)”). Everything below is static shell markup + one giant <script> that renders every screen as HTML strings.

Font: General Sans via Fontshare (400,500,600,700). Root font-size 14px. html { overflow-y:scroll; scrollbar-gutter:stable; }.


Verbatim :root block:

:root {
--brand:#01E46F; --brand-dim:rgba(1,228,111,.10); --brand-dim-h:rgba(1,228,111,.16); --g-dark:#05853E;
--blue:#0090FF; --blue-dim:rgba(0,144,255,.12);
--amber:#FFC53D; --amber-text:#9A5B00; --amber-dim:rgba(255,197,61,.18);
--red:#E32627; --red-dim:rgba(227,38,39,.10);
--purple:#7C3AED; --purple-dim:rgba(124,58,237,.12);
--ink:#0F1D13;
--bg:#F5F6FA; --surface:#fff; --hover:#F0F1F4;
--grey1:#FAFAFA; --grey2:#F4F4F5;
--border:#E8E8EC; --border-soft:#EFEFF2;
--text-1:#111; --text-2:#555; --text-3:#888;
--sh-card:2px 3px 16px 0 rgba(193,197,210,.18);
--r-sm:6px; --r-md:8px; --r-lg:12px; --r-xl:16px; --r-f:999px;
--side-w:248px; --side-w-collapsed:68px; --topbar-h:60px;
--input-bg:#fff;
}

Dark mode is a full token override on body.dark (every component adapts automatically because everything uses var(--*)):

body.dark {
color-scheme:dark;
--ink:#EEF1F5;
--bg:#0F1116; --surface:#181B21; --hover:#262B34;
--grey1:#1F232B; --grey2:#262B34;
--border:#2D323C; --border-soft:#252932;
--text-1:#EAECF0; --text-2:#A6AEBA; --text-3:#7E8591;
--sh-card:0 2px 14px 0 rgba(0,0,0,.45);
--g-dark:#35D982; --brand-dim:rgba(1,228,111,.15); --brand-dim-h:rgba(1,228,111,.24);
--blue:#3BA5FF; --blue-dim:rgba(0,144,255,.20);
--amber:#FFD166; --amber-text:#F0B94A; --amber-dim:rgba(255,197,61,.16);
--red:#FF5B5D; --red-dim:rgba(255,91,93,.16);
--purple:#A78BFA; --purple-dim:rgba(167,139,250,.18);
--input-bg:#20242C;
}

Extra dark-mode patches (verbatim, they follow the block above): inputs/selects/textareas get background:var(--input-bg); .dlg, .sb-tooltip, .chart-tip, and the five .alert-toast--* variants get explicit dark recolors; theme-toggle icon swap is CSS-only:

body:not(.dark) #theme-toggle .ico-sun { display:none; }
body.dark #theme-toggle .ico-moon { display:none; }

Base typography / resets (verbatim):

*,*::before,*::after { box-sizing:border-box; margin:0; padding:0; }
html { font-size:14px; -webkit-font-smoothing:antialiased; overflow-y:scroll; scrollbar-gutter:stable; }
body { font-family:'General Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
font-size:14px; color:var(--text-1); background:var(--bg); line-height:1.5; }
a { text-decoration:none; color:inherit; }
b,strong { font-weight:600; }
button { cursor:pointer; border:none; background:none; font-family:inherit; }

Note: b,strong { font-weight:600 } — bold text renders at 600, never 700, by default. Mono stack: .mono, code { font-family:"SF Mono",ui-monospace,"Roboto Mono",Menlo,monospace; }.


body
├── aside.sidebar ← fixed, left, 248px (68px collapsed)
│ ├── .sb-logo (60px tall = --topbar-h, brand SVG + "Polaris")
│ ├── nav.sb-body#sb-nav ← scrolls independently (overflow-y:auto)
│ │ ├── .sb-group "OVERVIEW" (uppercase group label)
│ │ ├── .sb-item (× n, .active on current)
│ │ └── …
│ └── .sb-foot (Settings .sb-item, pinned bottom)
├── div.main ← margin-left:248px, min-height:100vh, flex column
│ ├── header.topbar ← sticky top:0, 60px, z-40
│ │ ├── .crumb-toggle (sidebar collapse button)
│ │ ├── nav.crumbs#crumbs (breadcrumb, "A / B / current")
│ │ ├── .tb-spacer (flex:1)
│ │ ├── .q-pill (quarter context pill "Q2 2026")
│ │ ├── button.pg-mode-switch ("Admin view" / "General view")
│ │ ├── button.icon-action#theme-toggle
│ │ ├── .dd > .icon-action (bell + .dot) > .dd-menu (notifications)
│ │ └── .dd > .user-pill (avatar + name + role + chevron) > .dd-menu
│ └── div.page.app-screen#scr-* (× 13, one per section; only one has .show)
│ └── div.pg-wrap ← every screen's content wrapper (JS-rendered)
├── div#modal-root ← all .dlg overlays injected here
├── div#toast-container ← created lazily by toast()
├── .sb-tooltip / .av-tip / .chart-tip ← fixed, appended to body by JS
  • The document scrolls (html { overflow-y:scroll; scrollbar-gutter:stable }). There is no inner page scroller.
  • Fixed: .sidebar (position:fixed; top:0; left:0; bottom:0). Its .sb-body scrolls internally with a 5px custom scrollbar.
  • Sticky: .topbar (position:sticky; top:0; z-index:40), .settings-nav (sticky; top:88px), .pf-tabs (sticky; top:var(--topbar-h)), .pf-foot (sticky; bottom:0 with a bg gradient), .cmt-composer (sticky; bottom:0), .rpt-nav (sticky; top:8px).
  • Modals lock body scroll: openModal sets document.body.style.overflow='hidden'.
  • Screen switching scrolls to top: showScreen() calls window.scrollTo(0,0).
/* ── SIDEBAR ── */
.sidebar { position:fixed; top:0; left:0; bottom:0; width:var(--side-w); z-index:50;
background:var(--surface); border-right:1px solid var(--border); display:flex; flex-direction:column;
transition:width .18s ease; }
.sb-logo { display:flex; align-items:center; gap:10px; height:var(--topbar-h); padding:0 20px; border-bottom:1px solid var(--border-soft); flex-shrink:0; }
.sb-logo-name { font-size:18px; font-weight:700; letter-spacing:-.02em; color:var(--ink); white-space:nowrap; }
.sb-body { flex:1; overflow-y:auto; overflow-x:hidden; padding:10px 12px; }
.sb-body::-webkit-scrollbar { width:5px; } .sb-body::-webkit-scrollbar-thumb { background:var(--border); border-radius:4px; }
/* ── MAIN ── */
.main { margin-left:var(--side-w); transition:margin-left .18s ease; min-height:100vh; display:flex; flex-direction:column; }
body.sb-collapsed .main { margin-left:var(--side-w-collapsed); }
.topbar { position:sticky; top:0; z-index:40; height:var(--topbar-h); background:var(--surface);
border-bottom:1px solid var(--border); display:flex; align-items:center; gap:16px; padding:0 24px; }
/* ── PAGE ── */
.page { max-width:1320px; width:100%; margin:0 auto; padding:24px 32px 48px; }
/* Polaris layer overrides the content wrapper: */
.pg-wrap { padding:28px 32px 64px; max-width:1280px; }
/* ── App screens ── */
.app-screen { display:none; } .app-screen.show { display:block; }

Note the double wrapper: each screen is <div class="page app-screen" id="scr-x"> and JS renders '<div class="pg-wrap">…</div>' inside it, so effective content max-width is 1280px. Admin detail pages narrow further: admRender() wraps in <div class="pg-wrap" style="max-width:920px;margin:0 auto">.

Verbatim shell markup (static, from the file):

<aside class="sidebar">
<div class="sb-logo">
<svg width="28" height="28" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Rechaj" style="flex-shrink:0">
<path d="M39.6964 8.40009H33.2341C32.1322 8.40009 31.2388 9.29346 31.2388 10.3955V26.0808H40.8856L19.1794 52.4274H35.6029C36.8217 52.4274 37.9736 51.8704 38.7307 50.9152L52.8618 33.0847C53.3368 32.4853 53.4275 31.6671 53.0951 30.9783L43.2908 10.6568C42.6251 9.277 41.2284 8.40009 39.6964 8.40009Z" fill="#0F1D0F"/>
<path d="M17.597 48.0272H24.0593C25.1612 48.0272 26.0546 47.1339 26.0546 46.0318V30.3465H16.4077L38.1139 4L21.6905 4C20.4717 4 19.3198 4.55689 18.5627 5.51204L4.43159 23.3426C3.95655 23.9419 3.86591 24.7602 4.19825 25.4491L14.0026 45.7705C14.6683 47.1502 16.065 48.0272 17.597 48.0272Z" fill="#01E46F"/>
</svg>
<span class="sb-logo-name">Polaris</span>
</div>
<nav class="sb-body" id="sb-nav"></nav>
<div class="sb-foot">
<div class="sb-item" data-tip="Settings" data-screen onclick="openSettingsHub()"><svg class="lead" …>…</svg><span class="sb-label">Settings</span></div>
</div>
</aside>
<div class="main">
<header class="topbar">…</header>
<div class="page app-screen show" id="scr-dashboard"></div>
<div class="page app-screen" id="scr-orgchart"></div>
<!-- scr-interviews, scr-performance, scr-tasks, scr-initiatives, scr-summaries,
scr-notes, scr-boards, scr-knowledge, scr-requisitions, scr-profile, scr-admin -->
</div>
<div id="modal-root"></div>

Canonical selectors: .sidebar, .sb-logo, .sb-body, .sb-group, .sb-item, .sb-label, .sb-chev, .sb-sub, .sb-subitem, .sb-badge, .sb-foot, .sb-tooltip; collapse via body.sb-collapsed.

.sb-item { display:flex; align-items:center; gap:12px; height:38px; padding:0 12px; border-radius:var(--r-md);
font-size:13.5px; color:var(--text-2); cursor:pointer; user-select:none; transition:background .12s,color .12s; white-space:nowrap; position:relative; }
.sb-item:hover { background:var(--hover); color:var(--text-1); }
.sb-item.active { background:var(--brand-dim); color:var(--g-dark); font-weight:500; }
.sb-item svg.lead { flex-shrink:0; }
.sb-label { flex:1; }
.sb-chev { transition:transform .18s; color:var(--text-3); }
.sb-item.open .sb-chev { transform:rotate(90deg); }
.sb-sub { display:none; margin:2px 0 4px; }
.sb-sub.show { display:block; }
.sb-subitem { display:flex; align-items:center; height:34px; padding:0 12px 0 46px; border-radius:var(--r-md);
font-size:13px; color:var(--text-2); cursor:pointer; white-space:nowrap; }
.sb-subitem:hover { background:var(--hover); color:var(--text-1); }
.sb-subitem.active { color:var(--g-dark); font-weight:500; }
.sb-subitem .sb-badge { margin-left:auto; }
.sb-foot { border-top:1px solid var(--border-soft); padding:10px 12px; flex-shrink:0; }
.sb-badge { font-size:11px; font-weight:600; color:var(--amber-text); background:var(--amber-dim); border-radius:var(--r-f); padding:2px 8px; }
.sb-item .sb-badge { margin-left:auto; }
/* collapsed rail */
body.sb-collapsed .sidebar { width:var(--side-w-collapsed); }
body.sb-collapsed .sb-logo-name,
body.sb-collapsed .sb-label,
body.sb-collapsed .sb-chev,
body.sb-collapsed .sb-item .sb-badge { display:none; }
body.sb-collapsed .sb-logo { justify-content:center; padding:0; }
body.sb-collapsed .sb-item { justify-content:center; padding:0; }
body.sb-collapsed .sb-sub { display:none !important; }
/* collapsed hover tooltip — Atlas .sb-tooltip (fixed pill, escapes sidebar overflow) */
.sb-tooltip { position:fixed; display:none; background:var(--ink); color:#fff; padding:6px 10px; border-radius:6px;
font-size:12.5px; font-weight:500; white-space:nowrap; transform:translateY(-50%); z-index:9999; pointer-events:none;
box-shadow:0 4px 12px rgba(0,0,0,.15); }
/* collapse/expand toggle icon swaps with state */
body.sb-collapsed .ico-expanded, body:not(.sb-collapsed) .ico-collapsed { display:none; }

Group label (Polaris layer):

.sb-group { font-size:10.5px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--text-3); padding:14px 12px 6px; }

Markup (as generated by renderNav() — verbatim template):

<div class="sb-group">Overview</div>
<div class="sb-item active" data-tip="Dashboard" data-screen onclick="navTo('dashboard')">
<svg class="lead" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><!-- PIC glyph --></svg>
<span class="sb-label">Dashboard</span>
</div>

Usage: item icons are 18×18 stroke-1.9 line icons. Active = brand-dim wash + --g-dark text at weight 500 (not 600). Groups in Polaris nav: Overview / Performance / Collaboration / Spend (general) and Overview / Directory / Spend / Performance (admin). Collapse toggles body.sb-collapsed only; collapsed items show a fixed dark tooltip fed from data-tip. .sb-sub sub-menus and .sb-badge counts exist in the base layer but are unused by Polaris nav (flat items only).

Canonical selectors: .topbar, .crumb-toggle, .crumbs, .crumb-item, .crumb-current, .crumb-sep, .tb-spacer, .tb-search-wrap/.tb-search (global search, present in CSS but not rendered by Polaris), .icon-action (+.dot), .user-pill, .avatar, .user-name, .user-role, .q-pill, .pg-mode-switch.

.crumb-toggle { width:34px; height:34px; border-radius:var(--r-md); display:flex; align-items:center; justify-content:center; color:var(--text-2); }
.crumb-toggle:hover { background:var(--hover); color:var(--text-1); }
.crumb { font-size:15px; font-weight:600; color:var(--text-1); }
.crumbs { display:flex; align-items:center; gap:8px; font-size:15px; min-width:0; }
.crumb-item { font-weight:500; color:var(--text-3); white-space:nowrap; }
.crumb-item.crumb-current { font-weight:600; color:var(--text-1); }
.crumb-item.link { color:var(--text-3); font-weight:500; cursor:pointer; }
.crumb-item.link:hover { color:var(--g-dark); }
.crumb-sep { color:#C9CED6; flex-shrink:0; }
.tb-search-wrap { flex:1; max-width:420px; position:relative; }
.tb-search { height:38px; display:flex; align-items:center; gap:8px; padding:0 12px; background:var(--bg); border-radius:var(--r-md); color:var(--text-3); font-size:13px; }
.tb-search input { flex:1; border:none; background:none; outline:none; font-family:inherit; font-size:13px; color:var(--text-1); }
.tb-spacer { flex:1; }
.icon-action { width:38px; height:38px; border-radius:var(--r-md); border:1px solid var(--border); background:var(--surface);
display:flex; align-items:center; justify-content:center; color:var(--text-2); cursor:pointer; position:relative; }
.icon-action:hover { background:var(--hover); color:var(--text-1); }
.icon-action.danger { border-color:var(--red); color:var(--red); }
.icon-action.danger:hover { background:var(--red-dim); color:var(--red); }
.icon-action .dot { position:absolute; top:7px; right:8px; width:7px; height:7px; border-radius:50%; background:var(--red); border:1.5px solid #fff; }
.user-pill { display:flex; align-items:center; gap:8px; height:42px; padding:4px 12px 4px 4px; border-radius:var(--r-f); background:var(--bg); cursor:pointer; }
.avatar { width:32px; height:32px; border-radius:50%; background:var(--brand-dim); color:var(--g-dark); display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:600; flex-shrink:0; }
.user-name { font-size:13px; font-weight:600; color:var(--text-1); line-height:1.1; }
.user-role { font-size:11px; color:var(--text-3); }

Polaris-only topbar pills:

.q-pill { display:inline-flex; align-items:center; gap:7px; height:32px; padding:0 12px; border-radius:var(--r-f); background:var(--hover); font-size:12.5px; font-weight:600; color:var(--text-1); cursor:default; }
.pg-mode-switch { display:inline-flex; align-items:center; gap:7px; height:32px; padding:0 13px; border-radius:var(--r-f); border:1px solid var(--border); background:var(--surface); font-size:12.5px; font-weight:600; color:var(--text-1); cursor:pointer; white-space:nowrap; }
.pg-mode-switch:hover { border-color:var(--brand); color:var(--g-dark); }
.pg-mode-switch svg { color:var(--g-dark); }

Markup (verbatim from file, abridged icons):

<header class="topbar">
<div class="crumb-toggle" onclick="toggleSidebar()" title="Toggle sidebar">
<svg class="ico-expanded" …></svg><svg class="ico-collapsed" …></svg>
</div>
<nav class="crumbs" id="crumbs"><span class="crumb-item crumb-current">Dashboard</span></nav>
<div class="tb-spacer"></div>
<div class="q-pill" title="Fiscal quarter"><svg …></svg><span id="q-label">Q2 2026</span></div>
<button class="pg-mode-switch" id="mode-switch" title="Switch view" onclick="toggleMode()"><svg …></svg><span id="mode-switch-text">Admin view</span></button>
<button class="icon-action" id="theme-toggle" title="Toggle dark mode" aria-label="Toggle dark mode" onclick="toggleTheme()"><svg class="ico-moon" …></svg><svg class="ico-sun" …></svg></button>
<div class="dd" data-dd="notif"><div class="icon-action dd-trigger"><svg …></svg><span class="dot"></span></div><div class="dd-menu" style="min-width:300px;right:0">…</div></div>
<div class="dd" data-dd="user"><div class="user-pill dd-trigger"><div class="avatar">RO</div><div><div class="user-name">Ridwan Odebiyi</div><div class="user-role">Product Design Lead</div></div><svg …chevron…></svg></div><div class="dd-menu" style="min-width:200px;right:0">…</div></div>
</header>

Usage: breadcrumb is a plain A / B / current string (crumb-current 600, ancestors 500 grey, / separators). Right cluster order: quarter pill → mode switch → theme toggle → notifications (icon-action with red .dot) → user pill. Breadcrumb content per screen comes from the CRUMB map. No global search rendered in Polaris (the .tb-search/.gsearch-panel CSS is inherited, unused).

Selectors: .pg-head, .pg-title, .pg-sub, .pg-actions; helper pgHead(title, sub, actions).

.pg-head { display:flex; align-items:flex-end; justify-content:space-between; gap:20px; margin-bottom:24px; }
.pg-title { font-size:23px; font-weight:700; letter-spacing:-.02em; color:var(--ink); }
.pg-sub { font-size:13px; color:var(--text-3); margin-top:4px; }
.pg-actions { display:flex; align-items:center; gap:10px; }
/* also (base layer, same name redefined): .pg-actions { display:flex; gap:10px; flex-wrap:wrap; justify-content:flex-end; } */
.pg-sec-t { font-size:13px; font-weight:600; color:var(--ink); margin:4px 0 12px; }
.greet { font-size:24px; font-weight:700; letter-spacing:-.02em; color:var(--ink); }

Markup (as produced by pgHead() — verbatim template):

<div class="pg-head">
<div>
<div class="pg-title">Tasks</div>
<div class="pg-sub">Product Design Lead · Q2 2026</div>
</div>
<div class="pg-actions">
<div class="pseg">…</div>
<button class="btn-sec" onclick="…">Recurring</button>
<button class="btn-pri" onclick="openTaskForm()"><svg …>+</svg> New task</button>
</div>
</div>

Usage: every screen opens with pgHead(title, sub, actions); sub is typically "{role} · {quarter}" or a one-line description. Actions live top-right (primary button last). Detail pages replace the title block with breadcrumb-above-title (.crumb-back or .kc-crumbs + .pg-title with margin-top). The dashboard uses .greet (“Hi, Ridwan”) instead of .pg-title. Admin detail pages use .adm-dh / .adm-back / .adm-dh-title (22px/600) instead.

3.4 Tabs & segmented controls — every variant

Section titled “3.4 Tabs & segmented controls — every variant”

(a) .pseg — canonical pill segmented control (Polaris default). Used for all page-level tab switches (My tasks/Assigned by me, Table/Kanban, Upcoming/Completed, Board/List/Backlog, all admin filter bars via pseg() helper). Sits inside .filt-bar.

.pseg { display:inline-flex; background:var(--hover); border-radius:var(--r-md); padding:3px; gap:2px; }
.pseg button { height:30px; padding:0 14px; border-radius:6px; font-size:12.5px; font-weight:500; color:var(--text-2); background:none; white-space:nowrap; }
.pseg button.on { background:var(--surface); color:var(--g-dark); font-weight:600; box-shadow:var(--sh-card); }
<div class="filt-bar">
<div class="pseg">
<button class="on" onclick="setTaskTab('mine')">My tasks</button>
<button onclick="setTaskTab('by')">Assigned by me</button>
</div>
</div>

(b) .prof-tabs / .prof-tab — in-card pill tabs with count chips. Used inside detail modals and the issue page (Description/Activity/Comments; Sub-tasks/Attachments/Links/Comments; Details/Activity). Same visual recipe as .pseg but a button.prof-tab with optional .tc count.

.prof-tabs { display:inline-flex; background:var(--hover); border-radius:var(--r-md); padding:3px; gap:2px; margin:16px 0 12px; }
.prof-tab { height:30px; padding:0 14px; border-radius:6px; font-size:12.5px; font-weight:500; color:var(--text-2); background:none; cursor:pointer; white-space:nowrap; }
.prof-tab:hover { color:var(--text-1); }
.prof-tab.on { background:var(--surface); color:var(--g-dark); font-weight:600; box-shadow:var(--sh-card); }
.prof-tab .tc { margin-left:6px; font-size:11px; font-weight:600; color:var(--text-3); background:var(--grey2); border-radius:var(--r-f); padding:0 6px; }
.prof-tab.on .tc { background:var(--brand-dim); color:var(--g-dark); }
<div class="prof-tabs">
<button class="prof-tab on" onclick="profTab(this,'desc')">Description</button>
<button class="prof-tab" onclick="profTab(this,'activity')">Activity</button>
<button class="prof-tab" onclick="profTab(this,'comments')">Comments<span class="tc">2</span></button>
</div>
<div class="prof-panel" data-tab="desc">…</div>
<div class="prof-panel" data-tab="activity" hidden>…</div>

(c) .pf-tabs / .pf-tab — sticky scroll-spy chips (My profile page). Round pills (--r-f), sticky under the topbar, drive pfJump()/pfSpy() section scrolling rather than panel swapping.

.pf-tabs { position:sticky; top:var(--topbar-h); z-index:20; display:flex; gap:6px; flex-wrap:wrap; padding:12px 0; margin-bottom:6px; background:var(--bg); }
.pf-tab { height:30px; padding:0 13px; border-radius:var(--r-f); background:var(--hover); border:none; font-size:12.5px; font-weight:600; color:var(--text-2); cursor:pointer; white-space:nowrap; }
.pf-tab:hover { color:var(--text-1); }
.pf-tab.on { background:var(--brand-dim); color:var(--g-dark); }

(d) .txn-tabs / .txn-tab — brand-underline line tabs (inherited Caesar base; not invoked by Polaris JS but canonical for line tabs). 38px tall, 2px brand underline via ::after, count chip .ct.

.txn-tab { font-size:13px; font-weight:500; color:var(--text-2); height:38px; padding:0 14px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; position:relative; white-space:nowrap; transition:color .13s; }
.txn-tab::after { content:''; position:absolute; left:0; right:0; bottom:-1px; height:2px; background:var(--brand); border-radius:2px 2px 0 0; opacity:0; transition:opacity .13s; }
.txn-tab:hover { color:var(--text-1); }
.txn-tab.on { color:var(--g-dark); font-weight:600; }
.txn-tab.on::after { opacity:1; }
.txn-tab .ct { font-size:11px; font-weight:600; background:var(--grey2); color:var(--text-3); border-radius:var(--r-f); padding:1px 7px; }
.txn-tab.on .ct { background:var(--brand-dim); color:var(--g-dark); }

(e) .form-tabs / .form-tab — border-bottom form tabs (inherited, unused in Polaris).

.form-tabs { display:flex; gap:2px; border-bottom:1px solid var(--border-soft); margin:8px 0 20px; flex-wrap:wrap; }
.form-tab { font-size:13px; font-weight:500; color:var(--text-2); padding:8px 16px; cursor:pointer; border-bottom:2px solid transparent; margin-bottom:-1px; }
.form-tab.on { color:var(--g-dark); border-bottom-color:var(--brand); font-weight:600; }

(f) .seg — mini card-header segmented (inherited Caesar, unused in Polaris JS).

.seg { display:flex; gap:2px; background:var(--bg); border-radius:var(--r-md); padding:4px; }
.seg button { font-size:12.5px; font-weight:500; color:var(--text-2); padding:4px 12px; border-radius:6px; }
.seg button.on { background:var(--surface); color:var(--g-dark); box-shadow:var(--sh-card); }

Rule of thumb from this file: page-level tab switching and filters = .pseg (via pseg()), in-modal/in-card panel tabs = .prof-tabs, long-form scrollspy = .pf-tabs. Line tabs (.txn-tab) exist in the token layer but Polaris never uses them.

Filter bars that host these:

.filt-bar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:16px; }
.filt-bar2 { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:-4px 0 16px; }
.filt-search { display:flex; align-items:center; gap:7px; height:34px; padding:0 11px; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface); color:var(--text-3); min-width:200px; }
.filt-search input { border:none; outline:none; background:none; font:inherit; font-size:13px; color:var(--text-1); width:100%; }
.filt-pill { display:inline-flex; align-items:center; gap:6px; height:34px; padding:0 12px; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface); font-size:13px; color:var(--text-2); cursor:pointer; white-space:nowrap; }
.filt-pill:hover { color:var(--text-1); } .filt-pill.on { border-color:var(--brand); background:var(--brand-dim); color:var(--g-dark); font-weight:600; }
.filt-clear { height:34px; padding:0 12px; background:none; color:var(--text-3); font-size:13px; font-weight:500; cursor:pointer; border-radius:var(--r-md); } .filt-clear:hover { color:var(--g-dark); background:var(--hover); }

Selectors: .tbl-card (wrapper), .tscroll (h-scroll), .tbl, .tbl-card-head, .tbl-foot, .sec-head; builder admTable(cols, rows).

.tbl { width:100%; border-collapse:separate; border-spacing:0; font-size:13.5px; }
.tbl th { height:48px; padding:0 16px; font-size:12px; font-weight:500; text-transform:uppercase; letter-spacing:.06em; color:var(--text-2); text-align:left; white-space:nowrap; background:var(--grey2); }
.tbl th:first-child { border-radius:8px 0 0 8px; } .tbl th:last-child { border-radius:0 8px 8px 0; }
.tbl th.r, .tbl td.r { text-align:right; }
.tbl tbody tr { transition:background .1s; } .tbl tbody tr:hover td { background:var(--hover); }
.tbl tbody tr:has([onclick*="open"]) { cursor:pointer; }
.tbl td { padding:12px 16px; font-size:13.5px; color:var(--text-1); border-bottom:1px solid var(--border-soft); vertical-align:middle; }
.tbl tbody tr:last-child td { border-bottom:none; }
.tbl-foot { display:flex; align-items:center; justify-content:space-between; padding:16px; border-top:1.5px solid var(--border); }
.tbl-foot .lbl { font-size:12.5px; color:var(--text-3); } .tbl-foot .val { font-size:16px; font-weight:700; color:var(--ink); }
.tbl-card { background:var(--surface); border-radius:var(--r-xl); padding:16px; }
.tbl-card-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
.tscroll { overflow-x:auto; }
.amt { font-weight:600; color:var(--ink); } .muted { color:var(--text-3); }
.row-arrow { color:var(--text-3); } .tbl tbody tr:hover .row-arrow { color:var(--g-dark); }
.row-menu-btn { width:30px; height:30px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; color:var(--text-3); cursor:pointer; }
.row-menu-btn:hover { background:rgba(15,29,19,.09); color:var(--text-1); }
.st-dot { width:7px; height:7px; border-radius:50%; background:#30A46C; display:inline-block; margin-right:8px; vertical-align:middle; }
.tbl tbody tr.inactive { opacity:.5; }

Sortable header affordances (inherited): .tbl thead th.sortable { cursor:pointer }, .sort-ic chevron, .sort-ic.on { color:var(--g-dark) }.

Markup (representative, verbatim shape from renderTasks()):

<div class="tbl-card"><div class="tscroll"><table class="tbl">
<thead><tr><th>Task</th><th>Assignee</th><th>Complexity</th><th>Deadline</th><th>Status</th></tr></thead>
<tbody>
<tr onclick="openTaskDetail('t1')" style="cursor:pointer">
<td>
<div style="font-weight:600;color:var(--text-1)">Ship the swap-station map redesign</div>
<div style="font-size:12px;color:var(--text-3);max-width:340px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">Rework the station finder map…</div>
</td>
<td><span class="av-xs" title="Ridwan Odebiyi">RO</span> Ridwan</td>
<td><span class="cx" title="Complexity 4/5"><i class="on"></i>…</span></td>
<td>30 Jun 2026</td>
<td><span class="badge b-blue">In progress</span></td>
</tr>
</tbody>
</table></div></div>

Row recipe: first cell = 600-weight title + 12px grey ellipsized sub-line; trailing cell often <span class="link-add">View <chev></span>; whole <tr> gets onclick + style="cursor:pointer". Search/filters live ABOVE the table in .filt-bar (pseg + statusDD dropdown), never inside the card head — except tbl-card-head which is used for a title+action row inside the card (e.g. “My metric key requests” + “+ Request a key” link). No pagination anywhere in this file; footer .tbl-foot is a totals row (inherited pattern). Empty tables use admEmptyRow(colspan,msg) → a centered .prof-empty in a full-width cell.

Grouped-list alternative (Boards backlog): .bl-group (white --r-xl card, --sh-card), .bl-group-h header row, .bl-row 13px rows with grip/typeicon/key/title/meta, .bl-past for closed sprints. Row lists inside cards use .pkv key-value rows (see 3.9) or .prof-row.

All text buttons are 38px tall, radius --r-md (8px), 13.5px text; icon buttons are 38×38.

.btn-pri { display:inline-flex; align-items:center; gap:8px; height:38px; padding:0 16px; border-radius:var(--r-md); background:var(--brand); color:#111; font-size:13.5px; font-weight:600; }
.btn-pri:hover { background:#00c45b; }
.btn-sec { display:inline-flex; align-items:center; gap:8px; height:38px; padding:0 16px; border-radius:var(--r-md); background:transparent; border:1px solid var(--border); color:var(--text-1); font-size:13.5px; font-weight:500; }
.btn-sec:hover { background:var(--hover); border-color:var(--text-3); }
.btn-danger { display:inline-flex; align-items:center; gap:8px; height:38px; padding:0 16px; border-radius:var(--r-md); background:var(--red-dim); color:var(--red); font-size:13.5px; font-weight:600; }
.btn-danger:hover { background:var(--red); color:#fff; }
.btn-danger-out { display:inline-flex; align-items:center; gap:8px; height:38px; padding:0 16px; border-radius:var(--r-md); background:transparent; border:1px solid var(--red); color:var(--red); font-size:13.5px; font-weight:500; }
.btn-danger-out:hover { background:var(--red-dim); }

Icon buttons:

.ds-btn-primary { display:inline-flex; align-items:center; justify-content:center; width:38px; height:38px; border-radius:var(--r-md);
background:var(--brand); color:#111; }
.ds-btn-primary:hover { background:#00c45b; }
.icon-action { width:38px; height:38px; border-radius:var(--r-md); border:1px solid var(--border); background:var(--surface); … } /* see 3.2 */
.gear-btn { width:38px; height:38px; border-radius:var(--r-md); display:inline-flex; align-items:center; justify-content:center; color:var(--text-2); background:transparent; border:1px solid var(--border); cursor:pointer; }

Text-link buttons:

.link-add { display:inline-flex; align-items:center; gap:4px; font-size:12.5px; font-weight:600; color:var(--g-dark); cursor:pointer; margin-top:4px; }
.link-add.danger { color:var(--red); }
.link-add.muted { color:var(--text-3); }
.card-link { display:inline-flex; align-items:center; gap:4px; font-size:12.5px; font-weight:600; color:var(--g-dark);
padding:6px 12px; border-radius:var(--r-f); background:var(--brand-dim); cursor:pointer; transition:background .12s; }
.card-link:hover { background:var(--brand-dim-h); }

Markup (from btnNew() and dialog footers):

<button class="btn-pri" onclick="openTaskForm()"><svg width="16" height="16" …><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg> New task</button>
<button class="btn-sec" onclick="closeModal()">Cancel</button>
<button class="btn-danger-out" onclick="reqDecide('r2','Rejected')">Decline</button>

Usage: primary = brand green #01E46F with dark #111 text (never white-on-green), hover darkens to #00c45b. Secondary = transparent + 1px border. Destructive confirm in modals uses btn-danger-out; standalone destructive action uses btn-danger (tinted fill). Compact contexts shrink inline: style="height:32px" / height:34px; padding:0 13px; font-size:13px (.adm-dh-actions override). Ghost/text action = .link-add (in table cells: “Edit” / “Archive”).

Canonical badge (12px / 500 / 6px radius / no uppercase):

.badge { display:inline-flex; align-items:center; gap:4px; height:20px; padding:0 8px; border-radius:var(--r-sm); font-size:12px; font-weight:500; letter-spacing:-.01em; }
.b-red { background:var(--red-dim); color:var(--red); } .b-amber { background:var(--amber-dim); color:var(--amber-text); }
.b-green { background:var(--brand-dim); color:var(--g-dark); } .b-blue { background:var(--blue-dim); color:var(--blue); }
.b-grey { background:var(--grey2); color:var(--text-3); }
.b-purple { background:var(--purple-dim,#efe9fe); color:var(--purple,#7c5cff); }
.up { color:var(--g-dark); font-weight:600; } .down { color:var(--red); font-weight:600; }
<span class="badge b-blue">In progress</span>
<span class="badge b-amber">Awaiting</span>

Status→tone mapping is centralized in pBadge(s) (general) and admStatePill(s) (admin). Green: Approved/Done/Reviewed/Hire/Achieved/Active/Saved/Granted/Executed/Filled. Blue: Upcoming/Submitted/In progress/On track/Offer sent/Offer signed/Scheduled. Amber: Awaiting/Needs revision/At risk/Open/Pending/Flagged/Hiring. Red: Blocked/Rejected/Missed/Declined. Grey: Assigned/Draft/Filed/Completed/Not started/Acknowledged/Cancelled/Expired/Archived/Closed.

Status pill with dot + dropdown (interactive status):

.status-pill { display:inline-flex; align-items:center; gap:6px; height:26px; padding:0 9px; border-radius:var(--r-f); font-size:12px; font-weight:600; cursor:pointer; }
.status-pill svg { opacity:.55; margin-left:1px; }
.status-pill.st-grey { background:var(--grey2); color:var(--text-2); }
.status-pill.st-blue { background:var(--blue-dim); color:var(--blue); }
.status-pill.st-red { background:var(--red-dim); color:var(--red); }
.status-pill.st-green { background:var(--brand-dim); color:var(--g-dark); }
.st-dot { width:7px; height:7px; border-radius:50%; flex-shrink:0; }
.dot-grey { background:var(--text-3); } .dot-blue { background:var(--blue); } .dot-red { background:var(--red); } .dot-green { background:var(--g-dark); }
<div class="dd" data-dd="tdst">
<div class="status-pill st-blue dd-trigger"><span class="st-dot dot-blue"></span>In progress<svg …chev…></svg></div>
<div class="dd-menu stmenu" style="right:0">
<div class="dd-opt"><span class="st-dot dot-grey"></span><span>Assigned</span></div>
<div class="dd-opt sel"><span class="st-dot dot-blue"></span><span>In progress</span><svg class="ck" …></svg></div>
…
</div>
</div>

Other pill species in the file: .st-pill (11px/600, Caesar bank txn states), .feed-tag, .sb-badge (amber count), .pts story-points pill (grey2, 18px tall, 11px/600), .epic-chip (purple, 10px uppercase 600), .lbl-chip, .bc-tag (9px/700 uppercase micro-tag), .org-hiring (9px/700 amber “HIRING”), .iv-lead (9px/700 “LEAD”), .tl-role (11px/600 uppercase grey role chip), .acc-cnt count pill, .q-pill. Person chip:

.person-chip { display:inline-flex; align-items:center; gap:6px; font-size:12.5px; font-weight:500; color:var(--text-1); background:var(--grey1); border-radius:var(--r-f); padding:3px 10px 3px 4px; cursor:pointer; }
.person-chip:hover { background:var(--grey2); }

Avatars: .avatar 32px, .av-sm 30px, .av-xs 22px, .cust-avatar 42/56px, .prof-av 52px, .phero-av 60px, .pf-avatar 72px — all circular, --brand-dim bg + --g-dark initials, weight 600. Stacks:

.av-stack { display:inline-flex; align-items:center; padding-right:7px; }
.av-stack .av-xs { margin-right:-6px; box-shadow:0 0 0 2px var(--surface); background-color:var(--surface); background-image:linear-gradient(var(--brand-dim),var(--brand-dim)); position:relative; }
.av-more { background-image:none; background-color:var(--grey2); color:var(--text-2); }
.av-xs { width:22px; height:22px; border-radius:50%; background:var(--brand-dim); color:var(--g-dark); display:inline-flex; align-items:center; justify-content:center; font-size:10px; font-weight:600; }

Complexity pips: .cx { display:inline-flex; gap:3px } .cx i { width:6px; height:6px; border-radius:50%; background:var(--border) } .cx i.on { background:var(--g-dark) } via cxPips(n).

.pstat — Polaris dashboard stat (canonical here). Clickable, hover-lift.

.pstat-row { display:grid; grid-template-columns:repeat(4,1fr); gap:16px; margin-bottom:20px; }
.pstat { background:var(--surface); border-radius:var(--r-lg); padding:18px; box-shadow:var(--sh-card); cursor:pointer; transition:transform .12s; }
.pstat:hover { transform:translateY(-2px); }
.pstat-top { display:flex; align-items:center; justify-content:space-between; }
.pstat-lbl { font-size:12.5px; color:var(--text-2); font-weight:500; }
.pstat-ic { width:34px; height:34px; border-radius:50%; display:flex; align-items:center; justify-content:center; }
.pstat-val { font-size:26px; font-weight:700; color:var(--ink); margin-top:8px; letter-spacing:-.01em; }
.pstat-sub { font-size:12px; color:var(--text-3); margin-top:4px; }
<div class="pstat" onclick="navTo('tasks')">
<div class="pstat-top"><span class="pstat-lbl">Open tasks</span><span class="pstat-ic ic-green"><svg …17px…></svg></span></div>
<div class="pstat-val">4</div>
<div class="pstat-sub">1 in progress · 1 blocked</div>
</div>

.adm-kpi — admin KPI (uppercase micro-label variant):

.adm-kpis { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:14px; }
.adm-kpi { background:var(--surface); box-shadow:var(--sh-card); border-radius:var(--r-lg); padding:16px 18px; }
.adm-kpi-top { display:flex; align-items:flex-start; justify-content:space-between; gap:10px; }
.adm-kpi-ic { width:34px; height:34px; border-radius:50%; flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; }
.adm-kpi-ic.t-green { background:var(--brand-dim); color:var(--g-dark); }
.adm-kpi-ic.t-amber { background:var(--amber-dim); color:var(--amber); }
.adm-kpi-ic.t-blue { background:var(--blue-dim); color:var(--blue); }
.adm-kpi-ic.t-grey { background:var(--grey1); color:var(--text-3); }
.adm-kpi-l { font-size:11.5px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--text-3); }
.adm-kpi-v { font-size:28px; font-weight:700; color:var(--ink); margin-top:8px; letter-spacing:-.02em; }
.adm-kpi-s { font-size:12px; color:var(--text-3); margin-top:4px; }

Inherited Caesar variants (in the CSS, available): .kpi (.kpi-lbl/.kpi-ic 38px/.kpi-val 25px/700/.kpi-bar 7px split bar/.kpi-foot), .bk-stat (30px icon, 23px value), .bk-s (grey1 tile w/ 38px icon + 20px value), .txn-s (19px value), .sum-stat (18px value), .prof-stat (grey1 tile, 19px b + 10.5px label).

Structure rule: label top-left + tonal circular icon top-right → big 700 number → grey sub/delta line. Icon container is always a circle with tinted bg + colored glyph (ic-* / t-* tone classes), never a solid fill.

No card has a border. Cards are white surface + radius + (usually) --sh-card shadow. Confirmed exceptions in this file: .org-node (org-chart tree nodes use border:1px solid var(--border) — interactive canvas nodes, not cards), the org-chart canvas wrapper (<div class="pcard" style="padding:0;box-shadow:none;border:1px solid var(--border);…"> — an inline exception), .bank-add/.drop-zone/.att-zone/.be-up dashed upload/add affordances, and inline one-offs style="box-shadow:none;border:1px solid var(--border-soft)" on nested tables inside modals (payments table in requisition detail). Everything else is shadow-only.

/* generic Polaris card */
.pcard { background:var(--surface); border-radius:var(--r-lg); box-shadow:var(--sh-card); padding:20px; }
.pcard-h { display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; }
.pcard-t { font-size:15px; font-weight:600; color:var(--ink); }
/* inherited base card (no shadow — sits on grey bg) */
.card { background:var(--surface); border-radius:var(--r-lg); padding:20px 24px; }
.card-h { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
.card-title { font-size:15px; font-weight:600; color:var(--text-1); }
/* admin card */
.adm-card { background:var(--surface); border-radius:var(--r-lg); box-shadow:var(--sh-card); padding:18px 20px; margin-bottom:14px; }
.adm-card-t { font-size:14px; font-weight:600; color:var(--ink); }
.adm-card-sub { font-size:12px; color:var(--text-3); margin-top:2px; }
.adm-card-h { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin-bottom:14px; }

Grey inner sections (the “section inside a white modal/card” pattern):

.prof-sect { background:var(--grey1); border-radius:12px; padding:12px 16px; margin-bottom:8px; }
.prof-sect:last-child { margin-bottom:0; }
.prof-sect-t { font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:.05em; color:var(--text-3); margin-bottom:4px; }
.td-details { background:var(--grey1); border-radius:12px; padding:2px 14px; margin-bottom:8px; }
.td-row { display:flex; align-items:center; justify-content:space-between; gap:16px; padding:6px 0; border-bottom:1px solid var(--border-soft); }
.td-row:last-child { border-bottom:none; }
.td-k { display:inline-flex; align-items:center; gap:10px; font-size:12.5px; color:var(--text-3); flex-shrink:0; }
.td-ic { width:26px; height:26px; border-radius:50%; background:var(--surface); border:1px solid var(--border); display:inline-flex; align-items:center; justify-content:center; color:var(--text-2); flex-shrink:0; }
.td-v { font-size:12.5px; color:var(--text-1); font-weight:500; display:flex; align-items:center; gap:8px; flex-wrap:wrap; justify-content:flex-end; text-align:right; }

On the full-page issue view those grey sections invert to white cards: .issue-page .td-details, .issue-page .prof-sect { background:var(--surface); box-shadow:var(--sh-card); }.

Key-value row (used everywhere in cards/modals):

.pkv { display:flex; justify-content:space-between; gap:16px; padding:9px 0; border-bottom:1px solid var(--border-soft); font-size:13px; }
.pkv:last-child { border-bottom:none; } .pkv .k { color:var(--text-3); } .pkv .v { color:var(--text-1); font-weight:500; text-align:right; }

Hover-lift interactive cards: .pstat, .set-tile, .kc-card, .goal-card, .note-card all use transition:transform .12s + :hover { transform:translateY(-2px) }.

Card header pattern markup (from dashTasksCard):

<div class="pcard">
<div class="pcard-h"><div class="pcard-t">My tasks</div><span class="link-add" onclick="navTo('tasks')">View all <svg …chev…></svg></span></div>
<div class="pkv" style="cursor:pointer" onclick="openTaskDetail('t1')">…</div>
</div>

Grid helpers: .row-2 { display:grid; grid-template-columns:2fr 1fr; gap:16px; align-items:start; } (Polaris redefinition), .row-3 { grid-template-columns:repeat(3,1fr); gap:16px }, .kc-grid { grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:14px }, .goal-list { repeat(auto-fill,minmax(300px,1fr)); gap:14px }, .set-grid { repeat(2,minmax(0,1fr)); gap:14px }.

3.10 Overlays: modal / drawer / full-page / (no bottom sheets on web)

Section titled “3.10 Overlays: modal / drawer / full-page / (no bottom sheets on web)”

One system: .dlg-overlay + .dlg, injected into #modal-root. All confirmations and detail views on web are centered modals — there are no bottom sheets in this file. Variants: default (540px), .dlg-md 560px, .dlg-lg 760px, .dlg.lg 780px, .dlg-side right drawer 480px (CSS present; Polaris JS never passes it), .dlg-full full-viewport takeover (used by task detail “expand to full page” toggle).

.dlg-overlay { position:fixed; inset:0; background:rgba(15,29,19,.34); z-index:400; display:flex; align-items:flex-start; justify-content:center; padding:46px 20px; overflow-y:auto; opacity:0; pointer-events:none; transition:opacity .15s; }
.dlg-overlay.show { opacity:1; pointer-events:auto; }
.dlg { width:100%; max-width:540px; background:var(--surface); border-radius:var(--r-lg); box-shadow:0 24px 64px rgba(0,0,0,.24); overflow:hidden; transform:translateY(10px); transition:transform .15s; margin:auto 0; }
.dlg-overlay.show .dlg { transform:none; }
.dlg.dlg-md { max-width:560px; } .dlg.dlg-lg { max-width:760px; }
.dlg-head-act { display:flex; align-items:center; gap:4px; flex-shrink:0; }
.dlg-icon { width:30px; height:30px; border-radius:8px; display:flex; align-items:center; justify-content:center; color:var(--text-3); cursor:pointer; }
.dlg-icon:hover { background:var(--hover); color:var(--text-1); }
.dlg-overlay:has(.dlg-side) { padding:0; align-items:stretch; justify-content:flex-end; }
.dlg.dlg-side { max-width:480px; width:480px; height:100vh; max-height:100vh; border-radius:0; margin:0; transform:translateX(24px); display:flex; flex-direction:column; }
.dlg-overlay.show .dlg.dlg-side { transform:none; }
.dlg.dlg-side .dlg-head, .dlg.dlg-side .dlg-foot { flex-shrink:0; }
.dlg.dlg-side .dlg-body { flex:1 1 auto; max-height:none; }
.dlg-overlay:has(.dlg-full) { padding:0; align-items:stretch; justify-content:center; background:var(--bg); }
.dlg.dlg-full { max-width:100vw; width:100vw; height:100vh; max-height:100vh; border-radius:0; margin:0; box-shadow:none; transform:none; display:flex; flex-direction:column; background:var(--bg); }
.dlg.dlg-full .dlg-head { flex-shrink:0; background:var(--surface); padding:16px 24px; position:relative; }
.dlg.dlg-full .dlg-head > div:first-child { max-width:760px; width:100%; margin:0 auto; }
.dlg.dlg-full .dlg-head-act { position:absolute; right:24px; top:16px; }
.dlg.dlg-full .dlg-body { flex:1 1 auto; max-height:none; width:100%; max-width:760px; margin:0 auto; padding:28px 24px 64px; }
.dlg.lg { max-width:780px; }
.dlg-head { display:flex; align-items:flex-start; justify-content:space-between; padding:16px 24px; border-bottom:1px solid var(--border-soft); }
.dlg-title { font-size:16px; font-weight:600; color:var(--ink); }
.dlg-sub { font-size:12.5px; color:var(--text-3); margin-top:4px; }
.dlg-close { width:32px; height:32px; border-radius:50%; display:flex; align-items:center; justify-content:center; color:var(--text-2); cursor:pointer; flex-shrink:0; }
.dlg-close:hover { background:var(--grey2); color:var(--text-1); }
.dlg-body { padding:20px 24px; max-height:62vh; overflow-y:auto; scrollbar-width:none; }
.dlg-body::-webkit-scrollbar { width:0; height:0; }
.dlg-foot { display:flex; align-items:center; justify-content:flex-end; gap:10px; padding:16px 24px; border-top:1px solid var(--border-soft); background:var(--grey1); }
.dlg-foot.between { justify-content:space-between; }

Markup (as produced by openModal(dlgHead(...) + body + foot, 'dlg-md')):

<div class="dlg-overlay show" onclick="if(event.target===this)closeModal()">
<div class="dlg dlg-md">
<div class="dlg-head">
<div><div class="dlg-title">New requisition</div><div class="dlg-sub">File a spend request for approval</div></div>
<div class="dlg-head-act"><div class="dlg-close" onclick="closeModal()"><svg …x…></svg></div></div>
</div>
<div class="dlg-body">…fields / .td-details / .prof-sect …</div>
<div class="dlg-foot">
<button class="btn-sec" onclick="closeModal()">Cancel</button>
<button class="btn-pri" onclick="saveReq()">File requisition</button>
</div>
</div>
</div>

Footer button placement: right-aligned; order is Cancel/Close (btn-sec) first, then destructive (btn-danger-out / btn-danger), then primary (btn-pri) last. Examples: Close | Decline | Approve (requisition), Cancel | Delete (confirm, danger=true swaps primary for btn-danger-out), Back | Submit scorecard (multi-step modals use a Back secondary that reopens the parent modal). Confirmations = confirmModal(title, body, label, cb, danger) → dlg-md with a plain 13.5px grey paragraph body. Overlay click (backdrop only) closes. dlg-full is toggled from a .dlg-icon expand button in dlg-head-act.

Canonical DS .alert-toast pill, top-center, badge + text + close. Container is created lazily.

#toast-container { position:fixed; top:24px; left:50%; transform:translateX(-50%); display:flex; flex-direction:column; align-items:center; gap:10px; z-index:9999; pointer-events:none; }
.toast-live { display:inline-flex; align-items:center; gap:10px; border-radius:16px; padding:6px 16px 6px 6px; pointer-events:all; opacity:0; transform:translateY(-16px); transition:opacity .25s ease, transform .25s ease; box-shadow:0 4px 24px rgba(0,0,0,.13); max-width:90vw; }
.toast-live.toast-in { opacity:1; transform:translateY(0); }
.toast-live.toast-out { opacity:0; transform:translateY(-10px); }
.toast-live .alert-toast-badge { display:flex; align-items:center; justify-content:center; background:rgba(255,255,255,.85); border-radius:12px; padding:4px 10px; font-size:13px; font-weight:500; line-height:20px; white-space:nowrap; flex-shrink:0; }
.toast-live .alert-toast-text { font-size:13px; font-weight:500; line-height:20px; }
.toast-live .toast-close { background:none; border:none; cursor:pointer; padding:0 2px; opacity:.55; display:flex; align-items:center; color:currentColor; margin-left:4px; flex-shrink:0; }
.toast-live .toast-close:hover { opacity:1; }
.alert-toast--default { background:#e6f4fe; } .alert-toast--default .alert-toast-badge, .alert-toast--default .alert-toast-text { color:#0d74ce; }
.alert-toast--gray { background:#f0f0f0; } .alert-toast--gray .alert-toast-badge, .alert-toast--gray .alert-toast-text { color:#646464; }
.alert-toast--error { background:#ffebe8; } .alert-toast--error .alert-toast-badge, .alert-toast--error .alert-toast-text { color:#d8121c; }
.alert-toast--warning { background:var(--input-bg)7c2; } /* ⚠ corrupted value in source — should be #fff7c2 */
.alert-toast--warning .alert-toast-badge, .alert-toast--warning .alert-toast-text { color:#9e6c00; }
.alert-toast--success { background:#e6f6eb; } .alert-toast--success .alert-toast-badge, .alert-toast--success .alert-toast-text { color:#05853e; }

JS helper (verbatim signature + behavior):

var TOAST_BADGE = { success:'Done', default:'Info', gray:'Note', warning:'Heads up', error:'Error' };
function toast(msg, type){
if(!type){ if(/prototype|not in this|copied/i.test(msg)) type='default';
else if(/must|cannot|unable|failed|error|invalid|required|window/i.test(msg)) type='warning';
else if(/deleted|removed|discarded|withdrawn/i.test(msg)) type='gray';
else type='success'; }
// builds: <div class="toast-live alert-toast alert-toast--{type}">
// <div class="alert-toast-badge">{Done|Info|Note|Heads up|Error}</div>
// <span class="alert-toast-text">{msg}</span>
// <button class="toast-close" aria-label="Dismiss" onclick="this.closest('.toast-live').remove()">…x svg…</button>
// auto-dismiss after 3600ms (adds .toast-in, then .toast-out, removes after 300ms)
}

Usage: every action gives a toast; unbuilt destinations toast 'That section is not in this prototype' (type auto-resolves to default). Type is usually omitted and inferred from the message.

Field wrapper + label:

.fld { margin-bottom:16px; } .fld:last-child { margin-bottom:0; }
.fld > label { display:block; font-size:12px; font-weight:500; color:var(--text-2); margin-bottom:6px; }
.fld .req { color:var(--red); margin-left:1px; }
.fld-row { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
.fld-hint { font-size:11.5px; color:var(--text-3); margin-top:4px; }
.fld-help { font-size:11.5px; color:var(--text-3); line-height:1.45; margin:-2px 0 7px; }

Text inputs / selects / textarea — 42px tall in dialogs/forms, 40px in .set-ctl/row grids, focus ring = brand border + 3px --brand-dim glow:

.fld input[type=text],…,.fld select,.fld textarea,
.dlg input[type=text],… { width:100%; height:42px; padding:0 12px; border:1px solid var(--border); border-radius:var(--r-md); font:inherit; font-size:13.5px; color:var(--text-1); background:var(--input-bg); outline:none; transition:border-color .12s, box-shadow .12s; }
.fld textarea { height:auto; min-height:62px; padding:8px 12px; resize:vertical; }
.fld input:focus,.fld select:focus,.fld textarea:focus { border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-dim); }
/* native selects: custom data-uri chevron, right-padded */
.fld select, .dlg select { …appearance:none; padding:0 36px 0 12px; background-color:var(--input-bg); background-repeat:no-repeat; background-position:right 12px center;
background-image:url("data:image/svg+xml;utf8,<svg …stroke='%23888888' stroke-width='2.2'…><polyline points='6 9 12 15 18 9'/></svg>"); }
<div class="fld"><label>Title <span class="req">*</span></label><input id="tk-title" type="text" placeholder="A short, specific handle"></div>
<div class="fld-row">
<div class="fld"><label>Amount <span class="req">*</span></label><input id="rq-amt" type="number" placeholder="0"></div>
<div class="fld"><label>Currency</label><select id="rq-cur"><option>NGN</option>…</select></div>
</div>

Checkbox: .chk { width:16px; height:16px; accent-color:var(--brand); cursor:pointer; vertical-align:middle; } (17px in the earlier base declaration). Radio pills: .radio-pill + .radio-pill.on { border-color:var(--brand); background:var(--brand-dim); color:var(--g-dark); font-weight:600 }. Rich radio option card: .adm-opt (grey1 → .on = brand-dim + box-shadow:inset 0 0 0 1.5px var(--brand)).

Toggle switch:

.tgl-row { display:flex; align-items:center; justify-content:space-between; gap:16px; padding-top:4px; }
.tgl-label { font-size:13.5px; font-weight:500; color:var(--text-1); }
.tgl { position:relative; flex-shrink:0; cursor:pointer; display:inline-flex; }
.tgl input { position:absolute; opacity:0; width:0; height:0; }
.tgl-track { display:block; width:40px; height:24px; border-radius:var(--r-f); background:var(--grey2); transition:background .15s; position:relative; }
.tgl-track::after { content:''; position:absolute; top:3px; left:3px; width:18px; height:18px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.25); transition:transform .15s; }
.tgl input:checked + .tgl-track { background:var(--brand); }
.tgl input:checked + .tgl-track::after { transform:translateX(16px); }
.tgl input:focus-visible + .tgl-track { box-shadow:0 0 0 3px var(--brand-dim); }
<div class="tgl-row"><div><div class="tgl-label">Repeat every quarter</div><div class="fld-help" style="margin-top:2px">Recreate this goal automatically…</div></div><label class="tgl"><input type="checkbox" id="gl-repeat"><span class="tgl-track"></span></label></div>

Search inputs: page-level .filt-search (34px, bordered) and .org-search (36px); the topbar .tb-search (38px, --bg fill, borderless) is inherited but unused. Read-only inputs: .pf-ro { background:var(--grey1); color:var(--text-2); cursor:not-allowed; }.

Special editors (all fully specced in CSS): rich-text toolbar editor .rte-wrap/.rte-bar/.rte-btn/.rte-area (contenteditable, richEditor(id, html, ph)), Notion-style block editor .be-* (slash menu .be-slash, checkboxes, callout, toggle, image, file — used by Knowledge docs + Notes), multi-select chips input .ms/.ms-box/.ms-chip (.t-dept blue, .t-unit purple)/.ms-menu/.ms-opt (msField() for task assignees), comment composer .cmt-composer/.cmt-cbox/.cmt-cbar/.cmt-tool, scorecard pips .sc-pip (30px squares, .on = solid brand w/ #111 text) and .sc-rec recommendation buttons, stepper .stepper/.step/.step-line (22px numbered circles: on = solid brand, done = brand-dim), timeline .tl-step (see below), drop zones .drop-zone/.att-zone (1.5px dashed border → brand on hover).

Approval timeline (canonical DS .tl-step, used for requisition chains, metric requests, initiative flow):

.tl-step { display:flex; gap:12px; position:relative; padding:4px 0 14px; }
.tl-step:last-child { padding-bottom:0; }
.tl-rail { position:absolute; left:15px; top:36px; bottom:-4px; width:2px; background:var(--border); }
.tl-step:last-child .tl-rail { display:none; }
.tl-step[data-state="done"] .tl-rail { background:var(--brand); }
.tl-ic { width:32px; height:32px; border-radius:50%; background:var(--hover); color:var(--text-3); display:flex; align-items:center; justify-content:center; flex-shrink:0; position:relative; z-index:1; }
.tl-step[data-state="done"] .tl-ic { background:var(--brand-dim); color:var(--g-dark); }
.tl-step[data-state="active"] .tl-ic { background:var(--amber-dim); color:var(--amber-text); }
.tl-step[data-state="upcoming"] .tl-ic { background:var(--hover); color:var(--text-3); }
.tl-step[data-state="rejected"] .tl-ic { background:var(--red-dim); color:var(--red); }
.tl-name { font-size:13.5px; font-weight:600; color:var(--text-1); }
.tl-role { font-size:11px; font-weight:600; letter-spacing:.02em; text-transform:uppercase; color:var(--text-3); background:var(--grey1); border-radius:var(--r-f); padding:2px 8px; margin-left:6px; white-space:nowrap; }
.tl-meta { font-size:11.5px; color:var(--text-3); margin-top:2px; line-height:1.4; }
<div class="tl-step" data-state="done"><span class="tl-rail"></span><span class="tl-ic"><svg …check…></svg></span>
<div class="tl-body"><div class="tl-name">Approved by Tunde Bakare <span class="tl-role">Line manager</span></div><div class="tl-meta">Signed off</div></div>
</div>

Selectors: .dd (positioning wrapper), .dd-trigger (any child), .dd-menu, .dd-opt (+.sel, .danger), .dd-divider, .dd-head, .dd-note (notification rows), .stmenu (status menu variant), .dd-flt group label.

.dd { position:relative; }
.dd-menu { position:absolute; top:calc(100% + 8px); right:0; min-width:208px; background:var(--surface);
border-radius:12px; box-shadow:0 14px 40px rgba(15,29,19,.16), 0 4px 10px rgba(0,0,0,.05); padding:6px; z-index:120;
display:none; animation:ddIn .14s ease; }
.dd.open > .dd-menu { display:block; }
@keyframes ddIn { from { opacity:0; transform:translateY(-5px); } to { opacity:1; transform:none; } }
.dd-opt { display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:var(--r-md); font-size:13px; color:var(--text-1); cursor:pointer; white-space:nowrap; }
.dd-opt:hover { background:var(--grey1); }
.dd-opt.sel { color:var(--g-dark); font-weight:500; }
.stmenu { text-align:left; min-width:190px; }
.stmenu .dd-opt.sel { background:var(--brand-dim); }
.dd-opt .ck { margin-left:auto; color:var(--g-dark); }
.dd-opt.danger { color:var(--red); } .dd-opt.danger svg.oi { color:var(--red); }
.dd-divider { height:1px; background:var(--border-soft); margin:6px 4px; }

Open/close is a single global delegated click handler: clicking a .dd-trigger toggles its .dd, clicking a .dd-opt closes, clicking outside closes all (closeAllDD()). Selected option shows the CK checkmark svg on the right. Trigger styles are ad hoc: statusDD() builds a 34px bordered pill trigger inline; filtDD() uses .filt-pill; the status-pill trigger is .status-pill. Menu markup:

<div class="dd" data-dd="TASK_STATUS">
<div class="dd-trigger" style="display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 12px;border:1px solid var(--border);border-radius:var(--r-md);font-size:13px;color:var(--text-1);cursor:pointer;background:var(--surface)">All statuses <svg …chev…></svg></div>
<div class="dd-menu" style="min-width:170px">
<div class="dd-opt sel" onclick="setTaskStatus('all')"><span>All statuses</span><svg class="ck" …></svg></div>
<div class="dd-opt" onclick="setTaskStatus('Blocked')"><span>Blocked</span></div>
</div>
</div>
.empty-wrap { text-align:center; padding:48px 24px; } .empty-ic { width:52px; height:52px; border-radius:50%; background:var(--grey2); color:var(--text-3); display:flex; align-items:center; justify-content:center; margin:0 auto 14px; }
.empty-t { font-size:15px; font-weight:600; color:var(--text-1); } .empty-m { font-size:13px; color:var(--text-3); max-width:420px; margin:6px auto 16px; line-height:1.55; }
.prof-empty { font-size:12.5px; color:var(--text-3); }

Helper + markup:

function emptyState(icon,title,msg,action){ return '<div class="pcard"><div class="empty-wrap"><div class="empty-ic">'+svg(icon,24)+'</div><div class="empty-t">'+title+'</div><div class="empty-m">'+msg+'</div>'+(action||'')+'</div></div>'; }
<div class="pcard"><div class="empty-wrap">
<div class="empty-ic"><svg width="24" height="24" …task glyph…></svg></div>
<div class="empty-t">No tasks here</div>
<div class="empty-m">Tasks your manager (or a BU lead) assigns to you show up here, scoped to the selected quarter.</div>
<button class="btn-pri" onclick="openTaskForm()"><svg …>+</svg> New task</button>
</div></div>

Usage: full-page empties = emptyState() (grey circle icon 52px, 600 title, grey message, optional primary CTA). In-table empties = admEmptyRow(colspan,msg) (centered .prof-empty). Inline section empties = bare <div class="prof-empty">No linked issues.</div>. Inherited .txn-empty (54px icon) exists for the Caesar layer.

Circular, tonal-tinted. Every icon container in this canon is border-radius:50% with a -dim tinted background + colored stroke glyph (never solid fills, never white-on-color):

.ic-green { background:var(--brand-dim); color:var(--g-dark); } .ic-blue { background:var(--blue-dim); color:var(--blue); }
.ic-amber { background:var(--amber-dim); color:var(--amber-text); } .ic-purple { background:var(--purple-dim); color:var(--purple); }
.ic-grey { background:var(--grey2); color:var(--text-2); } .ic-red { background:var(--red-dim); color:var(--red); }

(Note: the base layer also defines .ic-amber { color:var(--amber-text) } and .ic-ink { background:rgba(15,29,19,.07); color:var(--ink) }; the Polaris layer redefines the set above and it wins in cascade order.)

Sizes seen: 46px (.txn-acct .i), 40px (.bank-ic, .sum-window .sw-ic, .org-av), 38px (.kpi-ic, .bk-s .i, .acct-ic), 36px (.set-tile-ic, .qprog-ic), 34px (.pstat-ic, .adm-kpi-ic), 32px (.tl-ic, .meet-card-ic), 30px (.qc-ic, .bk-stat .l .i), 28px (.gs-ic), 26px (.td-ic, .sw-ic), 22px (.kb-add — 6px square, toolbar button). Empty-state circles 52–54px.

Documented exception: small file/folder row icons use a 6px rounded square — .kc-row-ic { width:26px; height:26px; border-radius:6px; background:var(--grey1); color:var(--text-3); } .kc-row-ic.folder { background:var(--brand-dim); color:var(--g-dark); } (and .be-mi 30px/6px in the slash menu). Everything avatar-like is a circle.


All screens render into a pre-existing #scr-* div via OPENERS[name](), then showScreen() swaps .show. Composition orders observed:

4.1 Dashboard (openDashboard → #scr-dashboard)

Section titled “4.1 Dashboard (openDashboard → #scr-dashboard)”
  1. .pg-wrap
  2. .greet “Hi, Ridwan” + .pg-sub “{role} · {dept} · {quarter}”
  3. .pstat-row — 4 clickable .pstat KPIs (each onclick="navTo(...)")
  4. .row-2 (2fr/1fr): left column (flex col, gap 16) = “My tasks” .pcard (rows = .pkv clickable → openTaskDetail) + “My initiatives” .pcard; right column = profile .pcard (.phero + .pkv rows) + “This week’s summary” .pcard with full-width btn-sec CTA.

4.2 List pages (Tasks / Interviews / Requisitions / Summaries / Performance)

Section titled “4.2 List pages (Tasks / Interviews / Requisitions / Summaries / Performance)”

Canonical order:

  1. pgHead(title, "{role} · {quarter}" or descriptor, actions) — actions = optional .pseg view switch + .btn-sec extras + btnNew() primary.
  2. .filt-bar — .pseg scope tabs (e.g. My tasks / Assigned by me; My summaries / Team; Upcoming / Completed; My requisitions / Awaiting my approval / Approved by me) + optional statusDD() dropdown.
  3. Optional banner card (.sum-window state banner on Summaries; .qprog quarter-progress card on Performance).
  4. Body div (#tasks-body etc.) → .tbl-card > .tscroll > table.tbl OR .kb kanban OR card grid (.goal-list, .row-3 for notes) OR emptyState().

Interaction rules:

  • Row click opens a centered modal (openTaskDetail, openSummaryDetail, openReqDetail, openInterviewDetail, openGoalDetail, openMetricDetail, openGraceDetail) — always dlg-md, body = .td-details meta rows → .prof-sect content sections → (timeline) → footer actions.
  • Detail modal footers carry the decisions: Close only (read), Close | Decline | Approve (approver), Flag for discussion | Approve (summary review), Back | Submit (nested forms reopen parent via Back).
  • Task detail modal has .prof-tabs (Description / Activity / Comments) and a .dlg-icon expand toggle → reopens as dlg-full.
  • Create = btnNew() → form modal (dlg-md) with .fld stack; validation = toast('… is required') (warning tone); save = mutate array, closeModal(), re-render list, success toast.
  • Default selected tab is always the “mine” scope; quarter switch (setQuarter) re-runs the current opener.
  • Kanban view (Tasks): .kb > .kb-col.t-{tone} columns with HTML5 drag-drop (kbDragStart/kbDrop/kbMove), toast on move.

4.3 Boards (three-level: hub → board → issue)

Section titled “4.3 Boards (three-level: hub → board → issue)”
  • Hub (openBoards): pgHead + .kc-grid of .kc-card.board-card (icon + name + .board-key mono + desc + .av-stack + issue count). Card click → openBoardDetail.
  • Board detail (openBoardDetail, same #scr-boards): .pg-head with .crumb-back (“‹ Boards”), .board-key-lg mono chip + title + desc, actions = New ticket (btn-pri) / Members (btn-sec) / share + settings .icon-action; then .filt-bar pseg Board / List / Backlog; then .filt-bar2 (My-issues pill, .filt-search, filtDD type/assignee/epic/priority/grouping, Clear); body = .kb kanban (boardCard = .kb-card.iss-card with epic chip, title, labels, type icon + SWAP-9 ref + priority icon, subtask/comment counts, points, av-stack), or .tbl list, or .bl-wrap backlog (epics group + sprint groups + Backlog + .bl-past), with sprint drag-drop between groups.
  • Issue detail (openIssue): a full in-shell page, not a modal — .issue-page (max 1100px): .pg-head with issue breadcrumb (.bcrumbs mono) + title + Share; .issue-cols = main col (Description .prof-sect + tabs card: Sub-tasks / Attachments / Links / Comments) + 340px side col (.prof-tabs Details / Activity over .td-details meta with inline-editable rows via issEdit dropdowns).
  • Modals here: new-ticket form, sprint form, complete-sprint, members, board settings.

4.4 Knowledge Center (hub → folder → doc)

Section titled “4.4 Knowledge Center (hub → folder → doc)”
  • Hub: pgHead + .kc-grid of section cards.
  • Folder: .pg-head with .kc-crumbs breadcrumb above .pg-title, lead person chip, actions = New folder / New document / Share (all btn-sec); body = .tbl-card table (Name w/ .kc-row-ic, Type, Updated, hover-reveal .kc-act delete). Row click drills in.
  • Doc: breadcrumb + contenteditable .kc-title-edit + Published/Draft badge; actions = .note-save “Saved” indicator, Publish/Move-to-draft btn-sec, Share btn-sec, delete .icon-action.danger; meta line; .pcard.kc-doc hosting the .be-* block editor with 650ms debounced autosave. Delete = confirmModal(..., danger).

pgHead → .org-toolbar (.org-search, as-of date .org-asof, Reset btn-sec) + .org-cap caption → bordered canvas card (inline exception) containing .org-wrap pan/zoom stage, .org-node tree cards (.vac amber vacancy w/ HIRING tag, .me brand tint, collapse .org-toggle count pills), .org-zoom +/−/fit controls. Node click → openPersonProfile(id) modal (hero + .prof-stats + Reporting/Contact/Organization .prof-sects; footer: Close | Add note | Assign task). Search dims non-hits (.dim/.hit).

4.6 My profile (openProfile → form page)

Section titled “4.6 My profile (openProfile → form page)”

pgHead → sticky .pf-tabs scrollspy chips → stacked .pcard.pf-card sections (.pf-grid 2-col .flds, read-only .pf-ro inputs with “Request change” .pf-req links) → sticky .pf-foot (Cancel / Save) at the bottom.

toggleMode() swaps NAV → ADMIN_NAV; all admin screens render into #scr-admin. List modules follow: pgHead → admFilterBar (pseg of statuses) → admTable(cols, rows); row click → detail page (not modal) rendered via admRender() at max-width 920px: admDetailHead (.adm-back “‹ eyebrow”, 22px title, status pill, actions) → .adm-cards (admDl definition lists, doc rows, permission rows) → history. Entity create/edit = modals (admEntityForm). Settings hub (openSettingsHub) = pgHead + .set-grid of .set-tiles → per-module pages via openSetPage(key) with stHead (back link + title + actions), stFilterBar psegs, admTable. Confirmations always confirmModal.

pgHead + .row-3 of .note-card pcards (hover-reveal .note-del); click → full-page editor (back bar, autosave .note-save, title input .note-title-input 24px/600, block editor). Empty untitled notes are discarded on back.

Cross-cutting interaction rules: search lives in the page body (filter bars), never the topbar. Detail = modal for records (tasks/summaries/requisitions/interviews/goals/people), full page for composable objects (issues, docs, notes, admin entities). Confirmations = confirmModal centered dialog, destructive label + btn-danger-out. Every mutation ends in a toast. Dead ends are impossible: navTo toasts for unknown screens.


Navigation / shell:

  • navTo(name) — looks up OPENERS[name]; unknown → toast('That section is not in this prototype'). Renders nav, breadcrumbs from CRUMB[name] (array of strings), calls opener, showScreen(SCREENS[name]), closeAllDD().
  • SCREENS = {dashboard:'scr-dashboard', …}, CRUMB = {tasks:['Performance','Tasks'], …}, OPENERS = {dashboard:openDashboard, …} — the routing triple. Admin keys are auto-registered from ADMIN_NAV.
  • renderNav(active), showScreen(id), toggleSidebar(), toggleTheme() (persists localStorage['caesar-theme']), toggleMode() (general ↔ admin), setQuarter(q) / renderQMenu(), stCrumbs(sub), ensureAdminMode().
  • Openers: openDashboard() openOrgChart() openInterviews() openPerformance() openTasks() openInitiatives() openSummaries() openNotes() openBoards() openKnowledge() openRequisitions() openProfile() openAdmin(key,label) openSettingsHub() openSetPage(key).

Modal system:

  • openModal(html, cls) — injects .dlg-overlay > .dlg.{cls} into #modal-root, animates .show, locks body scroll. cls ∈ '' | 'dlg-md' | 'dlg-lg' | 'dlg-side' | 'dlg-full' | 'lg'.
  • closeModal() — fades out, clears #modal-root after 160ms, unlocks scroll.
  • dlgHead(title, sub, actions) — returns the .dlg-head block (actions = extra .dlg-icon buttons before the close X).
  • confirmModal(title, body, label, cb, danger) — Cancel + (danger ? btn-danger-out : btn-pri) confirm; _confirmRun() executes stored _confirmCb.

Toast: toast(msg, type?) — type ∈ success|default|gray|warning|error, auto-inferred if omitted (see 3.11). copyLink(url, what) → clipboard + '{what} copied to clipboard' toast.

Tab switching: pseg(opts) builds [{label,on,fn}] → segmented control; per-page setters re-render (setTaskTab/setTaskView/setTaskStatus, setSumTab/setTeamSub, setIvTab, setReqTab, setBoardView, admSetFilter(key,val), stSetFilter, setFilt(key,val)); in-modal panels use profTab(btn, t) (toggles .prof-tab.on + .prof-panel[data-tab] hidden); issue page uses issTab(t)/issSide(s); profile scrollspy pfJump(id)/pfSpy().

Shared render helpers (the canon for building screens):

  • pgHead(title, sub, actions), pBadge(status), admStatePill(status), cxPips(n), avG(personId, sizeClass='av-xs'), avStack(ids, max=4), ngn(n) (₦ format), money(r), btnNew(label, fn), emptyState(icon, title, msg, action?), admTable(cols, rowsHtml) (cols: string or {t,r} for right-align), admEmptyRow(colspan, msg), admFilterBar(key, items), statusDD(varName, fn, opts), filtDD(key, cur, opts), detRow(iconSvg, label, valueHtml) + DET_IC icon map, admCard(title, sub, body, headRight), admDl(pairs, two), admDetailHead(eyebrow, title, statusPill, actions, backFn), admRender(html), stHead(key, sub, actions), tlStep({name,when,state}), reqTimeline(r), pfField(lbl, inner, opt), pfInput(val, ro).
  • Icons: svg(pathData, size=16) wraps 24-viewBox stroke paths from the PIC map (plus chev x arrow check task flag summary note board book spend org people grid search interview clock repeat goal folder doc share trash pencil members gear back move userminus ban upload download teamgoal); DOTS_H kebab, CK checkmark.
  • Editors: richEditor(id, html, placeholder) / rteCmd(e, cmd); block editor beInit(hostId, html) / beHTML(hostId); attachments attZone() / attCard(a, i, removable); multi-select msField().
  • Utilities: initials(name), fv(id) (trimmed value), esc(s), stripHtml(h), isoToDisp(iso) ↔ dispToIso(disp) (“DD Mon YYYY”), APP_TODAY='2026-06-25', pById(id), kcNowTime(), fmtSize(bytes).
  • Drag-drop engines: kanban kbDragStart/kbDragEnd/kbDragOver/kbDragLeave/kbDrop/kbMove(id,kind,status); board cards bcDragStart/bcDrop; backlog blDragStart/blDrop; board columns .kb-col[data-status] + .drag-over inset ring.
  • Dropdown engine: global click delegate on .dd-trigger / .dd-opt; closeAllDD().
  • Confirm-style pickers: scPick(i,n,btn) / scRec(r,btn) / doPick(o,btn).
  • Init sequence (bottom of file): bindOrgPan(); normalizeBoards(); avatar-tooltip binder, document.execCommand('defaultParagraphSeparator', false, 'p'), then navTo('dashboard').

Class prefixes (namespace → domain):

  • sb- sidebar · tb- topbar · crumb- breadcrumbs · pg- page chrome (pg-wrap/pg-head/pg-title/pg-sub/pg-actions/pg-sec-t/pg-mode-switch) · dd- dropdowns · dlg- dialogs · fld form fields · filt- filter bars · tbl tables · btn- buttons · ic-/t- icon tones · b- badge tones · st- status (dots/pills) and settings modules (stWft, st-doctypes — overloaded prefix)
  • Polaris “p” family: pcard pstat pkv pseg phero prof-* pf-* (pf = profile form)
  • Feature namespaces: adm- admin · kb- kanban · iss-/bl-/bc-/il-/sp- boards/issues/backlog · kc- knowledge center · iv-/sc- interviews/scorecards · sum-/qprog/goal-/mk- performance · cmt- comments · rte- rich text · be- block editor · ms- multi-select · td- task detail rows · tl- timeline · att- attachments · org- org chart · doa- delegation of authority · aud- audit log · note- notes · av- avatars · cx complexity pips · qc- quick-create (inherited) · bk-/txn-/cf-/est-/stmt-/rpt-/li- inherited Caesar banking/sales modules.
  • Element IDs: screens scr-{section}; form fields {module}-{field} (tk-title, rq-amt, gl-metric, mk-name, sc-notes, dt-slug); bodies {module}-body (tasks-body, sum-body, iv-body, req-body).

Personas / seed data: current user ME = Ridwan Odebiyi, Product Design Lead, id 'ridwan', initials RO, dept Product Management, BU Swap Operations, email ridwan.odebiyi@mocx.co. Org = MocX Group; people ids are first names (osita, emeka, funmi, tunde, kunle, sade, grace, aisha, chidi). Manager chain drives approvals (reqApprovers).

ID formats visible: positions P-00011…; employee no MX-00102 / moc-x-E-00102; records t1 tasks, i1 initiatives, s1 summaries, g1 goals, gr1 grace, n1 notes, r1 requisitions, b1 boards, iv1 interviews, wft1 templates, i101 issues; issue refs {BOARDKEY}-{ref} (SWAP-9, DS-21, RES-28); requisition refs REQ-26-1000-R1; quarters Q2 2026; dates displayed 25 Jun 2026 (isoToDisp), datetimes 24 Jun 2026 · 09:12 or 29/06/2026, 08:57 (admin runs); metric keys snake_case 3–64 chars (station_activation_rate); doc-type slugs UPPER_SNAKE (NG_NIN_SLIP); share URLs polaris.rechaj.com/app/{area}/{id}.

Theme key: localStorage['caesar-theme'] (shared across the suite).


Legit display numbers / display titles (conforms to canon): .kpi-val 25px · .pstat-val 26px · .adm-kpi-v 28px · .bank-bal 22px · .bk-stat .v 23px · .bk-s .v 20px · .txn-s .v 19px · .cf-v 19px · .sum-stat .n 18px · .prof-stat b 19px · .qprog-pct-val 18px · .unc-n 18px · .rec-b .v 17px · .tbl-foot .val 16px · .greet 24px · .sb-logo-name 18px (brand wordmark) · .pg-title 23px (page display title) · .est-doc-title 20px · avatar-initial displays .set-avatar 22px / .pf-avatar 26px / .phero-av 20px · .chart-tip .v · .rpt-net 15px · .est-tot-rows .tr.grand 15px · .sum-side-tile .n 16px.

Violations inside the file (700 on small/label text — do NOT copy):

  • .bc-tag { font-size:9px; font-weight:700; … text-transform:uppercase } — micro tag at 700.
  • .org-hiring { font-size:9px; font-weight:700; … } — HIRING chip (also has a border:1px solid on a chip).
  • .iv-lead { font-size:9px; font-weight:700; … } — LEAD chip.
  • .board-key-lg { font-size:11px; font-weight:700; … } — mono board-key chip.
  • .tbl-foot .val and .rpt-net are borderline (bold totals, tolerated as numeric display). Everything else (names, section titles, buttons, card titles, dlg titles, tab labels) is correctly 600 or lower. Table th are 500. Badges are 500.
  • Page: .pg-wrap padding 28px 32px 64px, max 1280px; base .page 24px 32px 48px, max 1320px; admin detail max 920px; forms max 660px; issue page max 1100px; note editor 760px.
  • Card grid gaps: 16px dominant (.kpi-row .row .pstat-row .fld-row), 14px for dense grids (.adm-kpis .kc-grid .goal-list .set-grid .kb gap), 10px button gaps, 20px .pg-head gap, 24px pg-head margin-bottom.
  • Card padding: 20px (.pcard), 18px (.pstat, .adm-card 18/20), 16px (.tbl-card, .kpi 16/20), 24px dlg gutters (.dlg-head/.dlg-body/.dlg-foot all x=24px).
  • Control heights: 42px inputs (dialogs) / 40px (.set-ctl, row-grids) / 38px buttons + icon-actions / 36px org toolbar / 34px filter pills + statusDD / 32px topbar pills / 30px pseg buttons / 26px status pills / 20px badges.
  • Radii scale strictly from tokens: 6/8/12/16/999 (+ 10px one-offs: .doa-step, .org-zoom button, .prof-stat, .adm-opt, .be-slash; 14px .org-node; 11px .org-toggle).
  • Off-grid values that exist in the file (inherited quirks; do not propagate): 13px paddings (.pf-tab, .pg-mode-switch, .adm-dh-actions btns), 7px gaps (.q-pill, .doa-step inner, .filt-search), 9px paddings (.pkv, .sn-item, .stmenu .dd-opt, .status-pill), 11px (.kb-card padding, .st-task, .cmt gaps), 14px card gaps, 18px paddings, 46px .sb-subitem indent. Fonts use half-pixels liberally: 13.5 / 12.5 / 11.5 / 10.5 / 9px.
  • Motion: .12s–.18s ease across the board (sidebar .18s, hover .12s, dd .14s/.16s, dlg .15s, toast .25s); hover-lift translateY(-2px).

Other in-file anomalies worth knowing (found while extracting)

Section titled “Other in-file anomalies worth knowing (found while extracting)”
  1. .alert-toast--warning { background:var(--input-bg)7c2; } — corrupted CSS value (was #fff7c2); warning toasts silently fall back to transparent bg in light mode (dark mode has a valid override).
  2. Duplicate/conflicting declarations left in cascade: .chk (17px then 16px), .fld textarea (min-height 66px then 62px), .row-2/.row-3 redefined by the Polaris layer (2fr/1fr wins), .st-dot defined twice (table status dot vs status-pill dot), .ic-amber color (amber-text wins), .cmt defined in both layers (Polaris wins), .pg-actions twice.
  3. The header comment block still says “CAESAR … Prefix: cz-*” — stale; Polaris uses the prefixes in §6.
  4. Org-chart canvas card takes an inline border:1px solid var(--border) — the one deliberate bordered “card” (it’s a tool canvas).
  5. .tbl tbody tr:has([onclick*="open"]) relies on :has() — row cursor is also set inline as a fallback everywhere.