Skip to content

canon extract prod mgr

Design Canon Extraction — Kit Production / Production Manager (tablet reference)

Section titled “Design Canon Extraction — Kit Production / Production Manager (tablet reference)”

Source of truth: /Users/Ridwan/Pictures/Claude/Rechaj 2.0/rechaj-design-system/products/rechaj-kit-production-app/flows/production-manager/index.html 3,787 lines. CSS block: lines 11–819 (read 100%). Markup: 821–2685. JS: 2687–3785. File self-describes as: “Kit Production — Production Manager (iPad Pro 11” landscape, 1194×834)” in the CSS header comment, but the actual shell built below it is portrait 834×1194 (“Tablet shell — iPad Pro 11” portrait”). Trust the code: portrait 834×1194. It “mirrors the retrofit-app shell vocabulary (.sb / .rsm-page-head / .rsm-body / .home-ind / .rsm-nav) but at tablet dimensions. Internal classes are reused 1:1 wherever possible so cross-product visual consistency stays cheap.”


Verbatim :root block (lines 21–31):

:root {
--brand: #01E46F; --brand-dark: #013F1F; --g-primary: #01E46F; --g-dark: #05853E;
--g-2: #DCFBE2; --g-3: #B5F1C2;
--grey1: #FAFAFA; --grey2: #F9F9F9; --grey3: #E4E4E4; --grey4: #E8E8E8;
--grey5: #E0E0E0; --grey6: #D9D9D9; --grey7: #B0B0B0; --grey9: #A0A0A0;
--grey10: #888888; --grey11: #555555; --grey12: #202020;
--red9: #E32627; --amber9: #B45309;
--white: #FFFFFF; --text-main: #202020;
--sh-card: 2.08px 2.78px 16px 0px rgba(193,197,210,0.03);
--sh-sheet: 0 -8px 28px rgba(0, 0, 0, 0.18);
}

Global reset + body (verbatim, lines 32–42):

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
font-family: 'General Sans', system-ui, -apple-system, sans-serif;
background: #0E0F12;
color: var(--grey12);
letter-spacing: -0.01em;
-webkit-font-smoothing: antialiased;
display: flex; align-items: center; justify-content: center;
min-height: 100vh;
}

Font load (head):

<link href="https://api.fontshare.com/v2/css?f[]=general-sans@400,500,600,700&display=swap" rel="stylesheet">

<meta name="theme-color" content="#01E46F">. Global utility at end of CSS: [hidden] { display: none !important; }

Hard-coded colors used OUTSIDE the token set (canonical tonal pairs, used consistently):

  • Blue tone: bg #DBEAFE / fg #1E40AF (awaiting-qa, KaaG mark, blue KPI, active gate)
  • Amber tone: bg #FEF3C7 / fg #B45309 (also var(--amber9) = #B45309; toast warning fg #92400e)
  • Red tone: bg #FEE2E2 / fg #B91C1C (defect/fail/danger)
  • Amber progress fill: #F59E0B
  • Button hover green: #00C45B
  • Page bg for tab screens: #F5F5F7; device backdrop #0E0F12
  • Selected-row tint / KaaG-add row tint: rgba(1,228,111,0.08)
  • Toast pairs: success #dcfbe2/#05853e, info #e6f4fe/#0d74ce, warning #fef3c7/#92400e, error #fee2e2/#b91c1c
  • Photo/dark-thumb gradients: linear-gradient(135deg, #1f2230 0%, #2c3140 100%), linear-gradient(160deg, #1f1f23 0%, #0e0e10 100%), stage linear-gradient(160deg, #1f1f23 0%, #0a0a0c 70%, #050505 100%)
  • Onboarding hero card gradient: linear-gradient(160deg, #06311B 0%, #013F1F 60%, #021F11 100%)

Dimensions: tablet device frame 834 × 1194 (iPad Pro 11” portrait), border-radius: 28px, white, centered on dark #0E0F12 body. Tab screens use light grey #F5F5F7 page background. One .screen.active visible at a time (absolute inset:0 stack).

ASCII skeleton (tab screen):

body (#0E0F12, flex center)
└── .tablet (834×1194, white, radius 28, overflow hidden, flex column)
├── .screen.tab-screen.active (absolute inset 0, bg #F5F5F7, flex column)
│ ├── .km-scroll (flex:1; overflow-y:auto — EVERYTHING below scrolls together)
│ │ ├── .sb (status bar, 52px, scrolls away)
│ │ ├── header (either .rsm-hero [dashboard] or .rsm-page-head [other pages])
│ │ ├── (.km-kpi-strip) (dashboard only, overlaps hero by -64px)
│ │ └── .rsm-body (padding 0 24px 24px; column gap 18px)
│ │ └── (.rsm-body--split for 2-col grid 1.2fr/1fr)
│ ├── (.km-fab) (absolute right 24 / bottom 120 — pinned, outside .km-scroll)
│ ├── (.km-selection-bar) (absolute left/right 24, bottom 100 — pinned)
│ ├── .rsm-nav (bottom nav — OUTSIDE .km-scroll, pinned, z-index 4)
│ └── .home-ind (absolute bottom 8, z-index 3)
├── .rsm-sheet-overlay ×4 (absolute inset 0, z-index 50 — sheets live at .tablet level)
└── .alert-toast#toast (absolute top 64, centered, z-index 80)

Scroll model: the page-level scroll container is .km-scroll inside each .screen. The status bar, hero, KPI strip and body all live inside it, so the hero scrolls away. Only the bottom nav (.rsm-nav), home indicator, FAB and selection bar are pinned (they sit outside .km-scroll). Sheets overlay everything. Scrollbars are hidden (.km-scroll::-webkit-scrollbar { display: none; }).

Verbatim shell CSS (lines 46–73):

/* Tablet shell — iPad Pro 11" portrait. Same internal scaffolding as
the retrofit .phone shell, just bigger and in portrait orientation. */
.tablet {
position: relative;
width: 834px; height: 1194px;
background: var(--white);
overflow: hidden;
border-radius: 28px;
display: flex; flex-direction: column;
}
.screen {
display: none; flex-direction: column;
position: absolute; inset: 0;
background: var(--white);
}
.screen.active { display: flex; }
.tab-screen { background: #F5F5F7; overflow: hidden; }
/* Inner scroll wrapper for tab-screens. Holds everything that should
scroll together (status bar + hero + KPI strip + body) so the hero
scrolls AWAY when the user pulls the page up, instead of staying
pinned. .rsm-nav lives outside this wrapper so it remains visible
at the bottom of the .screen at all times. */
.km-scroll { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; }
.km-scroll::-webkit-scrollbar { display: none; }
/* Home indicator — same proportions as retrofit, scaled for tablet. */
.home-ind { position: absolute; bottom: 8px; left: 50%; width: 158px; height: 5px; border-radius: 100px; transform: translateX(-50%); background: var(--text-main); z-index: 3; }
.home-ind--light { background: rgba(255,255,255,0.5); }

Body / body-split (verbatim, lines 91–106):

/* Body — 24px horiz padding on tablet vs 16px on mobile. No own
scroll container; the parent .tab-screen scrolls the whole page so
the hero + KPI strip scroll away with the rest of the content. */
.rsm-body { padding: 0 24px 24px; display: flex; flex-direction: column; gap: 18px; }
.rsm-body > * { flex-shrink: 0; }
/* Two-column body modifier — for Dashboard / WO Detail / BOM library.
In portrait, 1.2fr / 1fr gives the primary list column enough room
while keeping the side rail readable. */
.rsm-body--split {
display: grid;
grid-template-columns: 1.2fr 1fr;
gap: 18px;
align-content: start;
}
.rsm-body--split > * { min-width: 0; }

Dashboard-only override: #s-dashboard .rsm-body { padding-top: 24px; }

Responsive fit script (2nd <script>, verbatim behavior): scales .tablet down with transform: scale(min(vw/834, vh/1194, 1)), transform-origin: top center, and re-centers via body padding. Never scales above 1.


3.1 Bottom nav (.rsm-nav) — the “sidebar” equivalent on tablet

Section titled “3.1 Bottom nav (.rsm-nav) — the “sidebar” equivalent on tablet”

Canonical selectors: .rsm-nav, .rsm-nav-tab, .rsm-nav-tab.is-active, .rsm-nav-badge

/* Bottom nav — 5-col grid for PM. Lives outside the .km-scroll wrapper
so it stays fixed at the bottom of the .screen while the rest of
the page scrolls. */
.rsm-nav { display: grid; grid-template-columns: repeat(5, 1fr); background: var(--white); border-top: 1px solid var(--grey4); padding: 10px 32px 12px; flex-shrink: 0; position: relative; z-index: 4; }
.rsm-nav-tab { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 6px 4px 4px; background: transparent; border: 0; cursor: pointer; font-family: inherit; font-size: 11.5px; font-weight: 500; color: var(--grey10); -webkit-appearance: none; appearance: none; transition: color 0.18s ease; position: relative; }
.rsm-nav-tab svg { width: 24px; height: 24px; }
.rsm-nav-tab.is-active { color: var(--g-dark); font-weight: 600; }
.rsm-nav-tab.is-active svg { color: var(--g-dark); }
.rsm-nav-badge { position: absolute; top: 4px; right: calc(50% - 22px); min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--red9); color: var(--white); font-size: 10.5px; font-weight: 700; display: flex; align-items: center; justify-content: center; line-height: 1; }

Markup (from #s-dashboard, trimmed to 2 of 5 tabs — full set is Home / Work orders / BOM / Handoff / Profile):

<nav class="rsm-nav" role="tablist">
<button class="rsm-nav-tab is-active" type="button" onclick="goTo('s-dashboard')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12 12 3l9 9"/><path d="M5 10v10a1 1 0 0 0 1 1h4v-6h4v6h4a1 1 0 0 0 1-1V10"/></svg>
<span>Home</span>
</button>
<button class="rsm-nav-tab" type="button" onclick="goTo('s-work-orders')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
<span>Work orders</span>
</button>
...
</nav>

Usage: repeated verbatim at the bottom of every tab screen with is-active moved to the current tab (nav is duplicated per screen, not shared). Icons are 24px feather-style strokes; active state is --g-dark green + weight bump 500→600. .rsm-nav-badge exists in CSS but is unused in this file’s markup (red count dot, weight 700). No group labels, no collapse behavior — tablet nav is a fixed 5-column grid.

There are TWO header types, plus the status bar which tops every screen.

(a) Status bar .sb — 52px iOS-style bar, dark (.sb--dark) on brand-dark/hero screens, default dark-glyphs-on-light elsewhere:

/* Status bar — taller on tablet (52px) for landscape proportion. */
.sb { height: 52px; padding: 18px 32px 0; display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; position: relative; z-index: 2; }
.sb-time { font-size: 15px; font-weight: 700; letter-spacing: -0.4px; color: var(--grey12); }
.sb-icons { display: flex; align-items: center; gap: 6px; }
.sb-icons svg { display: block; }
.sb--dark .sb-time { color: var(--white); }
.sb--dark .sb-icons svg path, .sb--dark .sb-icons svg rect, .sb--dark .sb-icons svg line { color: var(--white); fill: var(--white); }
<div class="sb">
<span class="sb-time">9:41</span>
<div class="sb-icons">
<svg width="17" height="11" viewBox="0 0 17 11" fill="none"><rect x="0" y="5" width="3" height="6" rx="1" fill="#202020"></rect><rect x="4.5" y="3" width="3" height="8" rx="1" fill="#202020"></rect><rect x="9" y="1" width="3" height="10" rx="1" fill="#202020"></rect><rect x="13.5" y="0" width="3" height="11" rx="1" fill="#202020" opacity="0.35"></rect></svg>
<svg width="16" height="12" viewBox="0 0 16 12" fill="none"><path d="M8 9.5a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3z" fill="#202020"></path><path d="M4.6 6.9a4.8 4.8 0 0 1 6.8 0" stroke="#202020" stroke-width="1.5" fill="none" stroke-linecap="round"></path><path d="M1.5 3.8a8.5 8.5 0 0 1 13 0" stroke="#202020" stroke-width="1.5" fill="none" stroke-linecap="round"></path></svg>
<svg width="25" height="12" viewBox="0 0 25 12" fill="none"><rect x="0.5" y="0.5" width="21" height="11" rx="3.5" stroke="#202020" stroke-opacity="0.35"></rect><rect x="2" y="2" width="17" height="8" rx="2" fill="#202020"></rect><path d="M23 4v4a2 2 0 0 0 0-4z" fill="#202020" opacity="0.4"></path></svg>
</div>
</div>

Time is always literal 9:41. Dark variant uses fill #FFFFFF in the SVGs plus the .sb--dark class. On splash/welcome it’s absolutely positioned over the content (style="position:absolute;top:0;left:0;right:0;").

(b) Dashboard hero .rsm-hero — brand-dark header with avatar / name / role pill / meta / circular search button, and a faint brand-mark background:

.rsm-hero { position: relative; background: var(--brand-dark); padding: 0 32px 80px; flex-shrink: 0; }
.rsm-hero-bg { position: absolute; top: 0; right: 0; width: 360px; height: 100%; pointer-events: none; opacity: 0.18; display: flex; align-items: center; justify-content: flex-end; }
.rsm-hero-bg svg { width: 100%; height: auto; }
.rsm-hero-row { position: relative; display: flex; align-items: center; justify-content: space-between; padding: 12px 0 20px; }
.rsm-hero-id { display: flex; align-items: center; gap: 14px; min-width: 0; }
.rsm-hero-avatar { width: 52px; height: 52px; border-radius: 50%; background: var(--brand); display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 600; color: var(--text-main); letter-spacing: -0.4px; flex-shrink: 0; }
.rsm-hero-text { min-width: 0; }
.rsm-hero-name { font-size: 20px; font-weight: 600; color: var(--white); letter-spacing: -0.3px; line-height: 26px; }
.rsm-hero-meta { font-size: 13px; font-weight: 400; color: rgba(255,255,255,0.6); line-height: 18px; margin-top: 2px; }
.rsm-hero-role { display: inline-block; font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: 100px; background: rgba(1,228,111,0.16); color: var(--g-primary); letter-spacing: 0.02em; margin: 4px 0 2px; }
.rsm-hero-right { display: flex; align-items: center; gap: 12px; }
.rsm-hero-search { width: 44px; height: 44px; border-radius: 50%; background: rgba(255,255,255,0.1); border: 0; color: var(--white); display: flex; align-items: center; justify-content: center; cursor: pointer; -webkit-appearance: none; appearance: none; }
.rsm-hero-search:hover { background: rgba(255,255,255,0.15); }
.rsm-hero-search svg { width: 18px; height: 18px; }
<header class="rsm-hero">
<div class="sb sb--dark">…</div>
<span class="rsm-hero-bg" aria-hidden="true">
<svg viewBox="0 0 100 100" fill="none">
<path d="M70 15h-10c-1 0-2 .8-2 2v22h14L40 95h22c1 0 2-.4 3-1.2L82 65c.5-.6.5-1.4 0-2L72 17c-.3-.7-1-2-2-2Z" fill="#01E46F"/>
</svg>
</span>
<div class="rsm-hero-row">
<div class="rsm-hero-id">
<span class="rsm-hero-avatar">EM</span>
<div class="rsm-hero-text">
<p class="rsm-hero-name">Erioluwa Morenikeji</p>
<span class="rsm-hero-role">Production Manager</span>
<p class="rsm-hero-meta">Tricycle Hardware · Wed, 14 May 2026</p>
</div>
</div>
<div class="rsm-hero-right">
<button class="rsm-hero-search" type="button" aria-label="Search">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="20" y1="20" x2="16.65" y2="16.65"/></svg>
</button>
</div>
</div>
</header>

Usage: hero only on the Dashboard. The 80px bottom padding + -64px KPI-strip margin creates the overlap. The avatar is a brand-green circle with dark initials (user pill). Search here is a translucent white 44px circle (dark surface variant of the icon button).

Two variants, both inside <header class="rsm-page-head">:

/* Page head — same anatomy as retrofit, taller bar (64px) for tablet. */
.rsm-page-head { background: transparent; padding: 0 24px 16px; flex-shrink: 0; }
.rsm-page-head-row { position: relative; height: 64px; display: flex; align-items: center; justify-content: center; padding: 0 28px; margin: 0 -24px; }
.rsm-page-title { font-size: 22px; font-weight: 600; color: var(--grey12); letter-spacing: -0.3px; flex: 1; text-align: center; }
.rsm-page-back { position: absolute; left: 28px; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--grey6); background: var(--white); display: flex; align-items: center; justify-content: center; color: var(--grey12); cursor: pointer; -webkit-appearance: none; appearance: none; transition: background 0.15s ease; }
.rsm-page-back:hover { background: var(--grey2); }
.rsm-page-back svg { width: 20px; height: 20px; }
/* Page-head row for screens that own a left-aligned title (no back btn). */
.km-page-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0; height: 64px; margin: 0; }
.km-page-title { font-size: 24px; font-weight: 600; color: var(--grey12); letter-spacing: -0.3px; }
/* Circular icon button for the page-head right slot (search, filter,
etc.). 44px circle with subtle border on the light page bg. */
.km-page-icon-btn { width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--grey6); background: var(--white); display: flex; align-items: center; justify-content: center; color: var(--grey12); cursor: pointer; -webkit-appearance: none; appearance: none; transition: background 0.15s ease; flex-shrink: 0; }
.km-page-icon-btn:hover { background: var(--grey2); }
.km-page-icon-btn svg { width: 18px; height: 18px; }

Detail-page right-action slot: .km-page-head-action { position: absolute; right: 28px; } (combined as class="km-page-icon-btn km-page-head-action").

Markup — root page variant (left title, right icon button):

<header class="rsm-page-head">
<div class="km-page-head-row">
<h1 class="km-page-title">Work orders</h1>
<button class="km-page-icon-btn" type="button" aria-label="Search work orders">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="20" y1="20" x2="16.65" y2="16.65"/></svg>
</button>
</div>
</header>

Markup — detail page variant (back button + centered title + right action):

<header class="rsm-page-head">
<div class="rsm-page-head-row">
<button class="rsm-page-back" type="button" aria-label="Back" onclick="goTo('s-work-orders')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg></button>
<h1 class="rsm-page-title" id="wo-title">WO-K-2407-0188</h1>
<button class="km-page-icon-btn km-page-head-action" type="button" aria-label="More actions" onclick="toggleWoHaltedDemo(this)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="12" cy="19" r="1.5"/></svg>
</button>
</div>
</header>

Rule: root/tab pages get a left-aligned 24px title with one 44px circular icon button on the right; drill-in pages get a centered 22px title with a circular back button at left and (optionally) one circular action at right. There is no separate sub/actions row and no breadcrumb — subtitles live inside the hero card of the body instead.

Section heads inside the body:

/* Section heads — same as retrofit. */
.rsm-section-head { display: flex; align-items: center; justify-content: space-between; padding: 4px 0; }
.rsm-section-title { font-size: 16px; font-weight: 600; letter-spacing: -0.2px; }
.rsm-section-meta { font-size: 12.5px; font-weight: 500; color: var(--grey11); }
.rsm-section-link { font-size: 12.5px; font-weight: 600; color: var(--g-dark); text-decoration: none; cursor: pointer; background: none; border: 0; padding: 0; font-family: inherit; }
<div class="rsm-section-head">
<h2 class="rsm-section-title">Today's work orders</h2>
<button class="rsm-section-link" type="button" onclick="goTo('s-work-orders')">View all</button>
</div>

Three variants exist. No line/underline tabs exist in this file — everything is pill-in-track.

Variant A — .km-tabs filter tabs (pill segmented with counts). Used at the top of list pages (Work Orders: 6 columns; Handoff: 3 columns — the grid column count is set per instance in the class rule, 6 by default, and the Handoff instance simply has 3 children in a 6-col rule? No — one shared rule repeat(6, 1fr); the Handoff screen reuses .km-tabs with 3 buttons which stretch into the first 3 tracks. Verbatim:

/* Filter tabs — 6 columns, with count inline. */
.km-tabs { display: grid; grid-template-columns: repeat(6, 1fr); gap: 4px; padding: 4px; background: var(--grey2); border-radius: 12px; }
.km-tab { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 6px; background: transparent; border: 0; border-radius: 8px; cursor: pointer; font-family: inherit; font-size: 12.5px; font-weight: 500; color: var(--grey11); -webkit-appearance: none; appearance: none; transition: background 0.15s ease, color 0.15s ease; }
.km-tab:hover { color: var(--grey12); }
.km-tab[aria-pressed="true"] { background: var(--white); color: var(--g-dark); font-weight: 600; box-shadow: 0 1px 2px rgba(0,0,0,0.06); }
.km-tab-count { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--grey3); color: var(--grey11); font-size: 11px; font-weight: 600; line-height: 1; }
.km-tab[aria-pressed="true"] .km-tab-count { background: var(--g-3); color: var(--g-dark); }
<div class="km-tabs" role="tablist">
<button class="km-tab" type="button" aria-pressed="false" data-wo-tab="open" onclick="setWoTab(this)">Open <span class="km-tab-count">2</span></button>
<button class="km-tab" type="button" aria-pressed="true" data-wo-tab="in-progress" onclick="setWoTab(this)">In progress <span class="km-tab-count">2</span></button>
<button class="km-tab" type="button" aria-pressed="false" data-wo-tab="awaiting-qa" onclick="setWoTab(this)">Awaiting QA <span class="km-tab-count">2</span></button>
...
</div>

Active state = white pill + green text + soft shadow; count chip flips grey→green tint. Selection via aria-pressed, panes via data-*-pane + hidden.

Variant B — .km-segmented form segmented control. Used inside sheets for a binary choice (kit type). Bigger touch target than km-tab, with an inline type-mark chip:

/* Segmented control for kit type. */
.km-segmented { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 4px; background: var(--grey2); border-radius: 12px; }
.km-segmented-opt { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px 14px; background: transparent; border: 0; border-radius: 9px; cursor: pointer; font-family: inherit; font-size: 14px; font-weight: 500; color: var(--grey11); -webkit-appearance: none; appearance: none; transition: background 0.15s ease, color 0.15s ease; }
.km-segmented-opt[aria-pressed="true"] { background: var(--white); color: var(--grey12); font-weight: 600; box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
.km-segmented-opt-mark { display: inline-flex; align-items: center; justify-content: center; height: 22px; padding: 0 9px; border-radius: 6px; background: var(--g-3); color: var(--g-dark); font-size: 11px; font-weight: 600; letter-spacing: 0.02em; }
.km-segmented-opt[data-kit="kaag"] .km-segmented-opt-mark { background: #DBEAFE; color: #1E40AF; }
<div class="km-segmented" role="group">
<button type="button" class="km-segmented-opt" aria-pressed="true" data-kit="standard" onclick="setNewWoKit(this)">
<span class="km-segmented-opt-mark">STD</span>
<span>Standard</span>
</button>
<button type="button" class="km-segmented-opt" aria-pressed="false" data-kit="kaag" onclick="setNewWoKit(this)">
<span class="km-segmented-opt-mark">KaaG</span>
<span>KaaG</span>
</button>
</div>

Variant C — bottom nav .rsm-nav-tab (see 3.1) — screen-level tab switching.

3.5 Table / list system (tablet list-card equivalents)

Section titled “3.5 Table / list system (tablet list-card equivalents)”

No <table> exists. The list system has three row types plus panes.

(a) .km-wo-card — dashboard summary card (rich, 3-block: head / progress / meta):

/* WO summary cards — list rows on the left column. */
.km-wo-card { background: var(--white); border-radius: 16px; box-shadow: var(--sh-card); padding: 16px 18px; display: flex; flex-direction: column; gap: 14px; border: 0; text-align: left; font-family: inherit; width: 100%; cursor: pointer; -webkit-appearance: none; appearance: none; transition: transform 0.1s; }
.km-wo-card:active { transform: scale(0.998); }
.km-wo-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.km-wo-id-block { display: flex; align-items: center; gap: 12px; min-width: 0; }
.km-wo-id-mark { width: 44px; height: 44px; border-radius: 12px; background: var(--g-3); color: var(--g-dark); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 14px; letter-spacing: -0.1px; flex-shrink: 0; }
.km-wo-id-mark--kaag { background: #DBEAFE; color: #1E40AF; }
.km-wo-id-text { min-width: 0; }
.km-wo-id { font-size: 15px; font-weight: 600; color: var(--grey12); letter-spacing: -0.1px; font-variant-numeric: tabular-nums; }
.km-wo-sub { font-size: 12.5px; font-weight: 500; color: var(--grey10); margin-top: 2px; }

Meta row inside the card:

.km-wo-meta-row { display: flex; align-items: center; gap: 16px; font-size: 12px; color: var(--grey11); }
.km-wo-meta-cell { display: flex; align-items: center; gap: 6px; }
.km-wo-meta-cell svg { width: 14px; height: 14px; color: var(--grey10); }
.km-wo-meta-val { font-weight: 600; color: var(--grey12); }
<button class="km-wo-card" type="button" onclick="openWoDetail('WO-K-2407-0188')">
<div class="km-wo-head">
<div class="km-wo-id-block">
<span class="km-wo-id-mark">STD</span>
<div class="km-wo-id-text">
<p class="km-wo-id">WO-K-2407-0188</p>
<p class="km-wo-sub">Standard kit · Target 8 · Due today 5 PM</p>
</div>
</div>
<span class="km-wo-pill" data-state="in-progress">In progress</span>
</div>
<div class="km-wo-progress">
<div class="km-wo-progress-row">
<span class="km-wo-progress-label">Kits closed</span>
<span class="km-wo-progress-val">5 of 8</span>
</div>
<div class="km-wo-progress-bar"><span class="km-wo-progress-fill" style="width: 62%;"></span></div>
</div>
<div class="km-wo-meta-row">
<span class="km-wo-meta-cell">
<svg …>…</svg>
<span class="km-wo-meta-val">3</span> assemblers
</span>
<span class="km-wo-meta-cell"><svg …>…</svg> BOM v4</span>
</div>
</button>

(b) .km-wo-row — compact list row for the list page (grid: mark / meta / right progress+chevron):

/* WO list rows — 2-line card with progress + meta. Slightly more
compact than the dashboard variant so more rows fit per page. */
.km-wo-list { display: flex; flex-direction: column; gap: 10px; }
.km-wo-row { background: var(--white); border-radius: 14px; box-shadow: var(--sh-card); padding: 14px 16px; display: grid; grid-template-columns: 44px 1fr auto; gap: 14px; align-items: center; border: 0; text-align: left; font-family: inherit; width: 100%; cursor: pointer; -webkit-appearance: none; appearance: none; transition: transform 0.1s; }
.km-wo-row:active { transform: scale(0.998); }
.km-wo-row-meta { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.km-wo-row-line1 { display: flex; align-items: center; gap: 10px; min-width: 0; }
.km-wo-row-id { font-size: 14.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.1px; font-variant-numeric: tabular-nums; }
.km-wo-row-sub { font-size: 12px; font-weight: 500; color: var(--grey10); }
.km-wo-row-line2 { display: flex; align-items: center; gap: 14px; font-size: 12px; color: var(--grey11); flex-wrap: wrap; }
.km-wo-row-cell { display: flex; align-items: center; gap: 6px; }
.km-wo-row-cell svg { width: 14px; height: 14px; color: var(--grey10); flex-shrink: 0; }
.km-wo-row-cell strong { font-weight: 600; color: var(--grey12); }
.km-wo-row-right { display: flex; align-items: center; gap: 14px; }
.km-wo-row-progress { display: flex; flex-direction: column; gap: 4px; min-width: 110px; align-items: flex-end; }
.km-wo-row-progress-val { font-size: 12px; font-weight: 600; color: var(--grey12); font-variant-numeric: tabular-nums; }
.km-wo-row-progress-bar { display: block; width: 110px; height: 5px; border-radius: 100px; background: var(--grey2); overflow: hidden; }
.km-wo-row-progress-fill { display: block; height: 100%; background: var(--g-primary); border-radius: 100px; transition: width 0.3s ease; }
.km-wo-row-progress-fill[data-tone="amber"] { background: #F59E0B; }
.km-wo-row-progress-fill[data-tone="grey"] { background: var(--grey6); }
.km-wo-row-chev { width: 22px; height: 22px; color: var(--grey9); flex-shrink: 0; }
<button class="km-wo-row" type="button" onclick="openWoDetail('WO-K-2407-0188')">
<span class="km-wo-id-mark">STD</span>
<div class="km-wo-row-meta">
<div class="km-wo-row-line1">
<span class="km-wo-row-id">WO-K-2407-0188</span>
<span class="km-wo-pill" data-state="in-progress">In progress</span>
</div>
<div class="km-wo-row-line2">
<span class="km-wo-row-cell">Standard kit · <strong>BOM v4</strong></span>
<span class="km-wo-row-cell"><svg …>…</svg><strong>3</strong> assemblers</span>
<span class="km-wo-row-cell"><svg …>…</svg>Due today 5 PM</span>
</div>
</div>
<div class="km-wo-row-right">
<div class="km-wo-row-progress">
<span class="km-wo-row-progress-val">5 of 8</span>
<span class="km-wo-row-progress-bar"><span class="km-wo-row-progress-fill" style="width: 62%;"></span></span>
</div>
<svg class="km-wo-row-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</button>

(c) .km-kit-row — selectable list row (Handoff queue), grid: check / mark / meta / right pill:

/* Kit row — selectable list row. Tap anywhere on the row to toggle. */
.km-kit-list { display: flex; flex-direction: column; gap: 8px; }
.km-kit-row { display: grid; grid-template-columns: 28px 44px 1fr auto; gap: 12px; align-items: center; padding: 12px 14px; background: var(--white); border-radius: 14px; box-shadow: var(--sh-card); border: 0; text-align: left; font-family: inherit; width: 100%; cursor: pointer; -webkit-appearance: none; appearance: none; transition: transform 0.1s; }
.km-kit-row:active { transform: scale(0.998); }
.km-kit-row[aria-pressed="true"] { background: rgba(1,228,111,0.08); }
.km-kit-select { width: 22px; height: 22px; border-radius: 50%; background: var(--white); box-shadow: inset 0 0 0 1.5px var(--grey5); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.km-kit-row[aria-pressed="true"] .km-kit-select { background: var(--g-primary); box-shadow: none; }
.km-kit-select svg { width: 12px; height: 12px; color: var(--white); opacity: 0; }
.km-kit-row[aria-pressed="true"] .km-kit-select svg { opacity: 1; }
.km-kit-row-mark { width: 44px; height: 44px; border-radius: 12px; background: var(--g-3); color: var(--g-dark); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 12px; letter-spacing: -0.05em; flex-shrink: 0; }
.km-kit-row-mark--kaag { background: #DBEAFE; color: #1E40AF; }
.km-kit-row-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.km-kit-row-id { font-size: 13.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; font-variant-numeric: tabular-nums; }
.km-kit-row-sub { font-size: 11.5px; font-weight: 500; color: var(--grey10); }
.km-kit-row-right { display: flex; align-items: center; gap: 10px; }
<button class="km-kit-row" type="button" aria-pressed="false" data-kit-id="kit-K-88301-WS-0011" data-kit-wo="WO-K-2407-0188" onclick="toggleKitSelect(this)">
<span class="km-kit-select"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg></span>
<span class="km-kit-row-mark">STD</span>
<div class="km-kit-row-meta">
<p class="km-kit-row-id">kit-K-88301-WS-0011</p>
<p class="km-kit-row-sub">WO-K-2407-0188 · Closed 8:42 AM · Adewale</p>
</div>
<div class="km-kit-row-right">
<span class="km-wo-pill" data-state="ready">Ready</span>
</div>
</button>

Panes: each tab’s rows sit in a sibling container .km-wo-list[data-wo-pane="…"] / .km-kit-list[data-handoff-pane="…"]; all except the active one carry hidden. [data-wo-pane][hidden] { display: none; } + global [hidden] { display:none !important; }.

There is no head-row-with-search inside the list card (search is the circular page-head button) and no pagination/footer — lists are short and fully rendered. Row hover is not styled on white rows; feedback is :active { transform: scale(0.998) }. Grey sub-rows inside panels use :hover { background: var(--grey3) } when tappable.

In-panel sub-rows (grey --grey2 rounded rows inside white panels — the “table body” of detail pages):

/* BOM component rows — compact list per component (name + qty + status). */
.km-bom-list { display: flex; flex-direction: column; gap: 8px; }
.km-bom-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--grey2); border-radius: 10px; }
.km-bom-row-text { flex: 1; min-width: 0; }
.km-bom-row-name { font-size: 13px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-bom-row-sub { font-size: 11.5px; font-weight: 500; color: var(--grey10); margin-top: 2px; }
.km-bom-row-qty { display: inline-flex; align-items: center; font-size: 12px; font-weight: 600; color: var(--grey11); font-variant-numeric: tabular-nums; padding: 3px 9px; border-radius: 100px; background: var(--white); }
/* Assembly record rows — per-kit row with G1/G2/G3 dots and assembler. */
.km-asm-list { display: flex; flex-direction: column; gap: 8px; }
.km-asm-row { display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: center; padding: 12px 14px; background: var(--grey2); border-radius: 12px; border: 0; text-align: left; font-family: inherit; width: 100%; cursor: pointer; -webkit-appearance: none; appearance: none; transition: transform 0.1s; }
.km-asm-row:active { transform: scale(0.998); }
.km-asm-row-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.km-asm-row-line1 { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.km-asm-row-id { font-size: 13px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; font-variant-numeric: tabular-nums; }
.km-asm-row-sub { font-size: 11.5px; font-weight: 500; color: var(--grey10); }
.km-asm-row-chev { width: 18px; height: 18px; color: var(--grey9); }
/* Serial rows — show component + serial number + source PO. */
.km-serial-list { display: flex; flex-direction: column; gap: 6px; }
.km-serial-row { display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: center; padding: 10px 12px; background: var(--grey2); border-radius: 10px; }
.km-serial-row-text { min-width: 0; }
.km-serial-row-name { font-size: 12.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-serial-row-val { font-size: 11.5px; font-weight: 500; color: var(--grey10); margin-top: 2px; font-variant-numeric: tabular-nums; letter-spacing: 0; }
/* SOP step list. */
.km-sop-list { display: flex; flex-direction: column; gap: 6px; }
.km-sop-row { display: grid; grid-template-columns: 28px 1fr auto; gap: 10px; align-items: center; padding: 10px 12px; background: var(--grey2); border-radius: 10px; }
.km-sop-check { width: 22px; height: 22px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--g-3); color: var(--g-dark); }
.km-sop-check svg { width: 12px; height: 12px; }
.km-sop-name { font-size: 13px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-sop-sub { font-size: 11.5px; font-weight: 500; color: var(--grey10); margin-top: 2px; }
.km-sop-time { font-size: 11.5px; font-weight: 500; color: var(--grey10); font-variant-numeric: tabular-nums; }
.km-sop-row--tappable { border: 0; font-family: inherit; width: 100%; text-align: left; -webkit-appearance: none; appearance: none; cursor: pointer; transition: background 0.15s ease, transform 0.1s ease; }
.km-sop-row--tappable:hover { background: var(--grey3); }
.km-sop-row--tappable:active { transform: scale(0.997); }
/* QA gate result card — G2 / G3 row with verdict + photo evidence chip. */
.km-qa-list { display: flex; flex-direction: column; gap: 10px; }
.km-qa-row { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--grey2); border-radius: 12px; }
.km-qa-ic { width: 40px; height: 40px; border-radius: 50%; background: var(--white); color: var(--g-dark); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.km-qa-ic svg { width: 18px; height: 18px; }
.km-qa-text { flex: 1; min-width: 0; }
.km-qa-name { font-size: 13px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-qa-sub { font-size: 11.5px; font-weight: 500; color: var(--grey10); margin-top: 2px; }

Primary (brand-green bg, DARK text — never white-on-green):

.btn-primary {
display: flex; align-items: center; justify-content: center;
width: 100%; height: 52px;
background: var(--brand); border: 1.5px solid var(--brand);
border-radius: 10px; font-family: inherit;
font-size: 16px; font-weight: 600; color: var(--text-main); letter-spacing: -0.2px;
cursor: pointer; transition: background 0.18s ease, border-color 0.18s ease, transform 0.1s;
-webkit-appearance: none; appearance: none;
}
.btn-primary:hover { background: #00C45B; border-color: #00C45B; }
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled, .btn-primary.is-disabled { background: var(--g-3); border-color: var(--g-3); color: rgba(17,17,17,0.45); cursor: not-allowed; pointer-events: none; }
.btn-primary--lg { height: 56px; font-size: 17px; }

Secondary (transparent, 1.5px grey border):

.btn-secondary {
display: flex; align-items: center; justify-content: center;
width: 100%; height: 52px;
background: transparent; border: 1.5px solid var(--grey5);
border-radius: 10px; font-family: inherit;
font-size: 16px; font-weight: 600; color: var(--grey12); letter-spacing: -0.2px;
cursor: pointer; transition: background 0.18s ease, border-color 0.18s ease, transform 0.1s;
-webkit-appearance: none; appearance: none;
}
.btn-secondary:hover { background: var(--grey2); border-color: var(--grey9); }
.btn-secondary:active { transform: scale(0.98); }
.btn-secondary--lg { height: 56px; font-size: 17px; }
<button class="btn-primary btn-primary--lg" type="button" onclick="submitNewWo()">Issue work order</button>
<button class="btn-secondary btn-secondary--lg" type="button" onclick="closeNewWoSheet()">Cancel</button>

Specs: 52px default / 56px --lg; radius 10px; weight 600; full width (buttons are always block-level in sheets/CTAs). No destructive button variant exists — danger is expressed via the profile-row danger modifier and red pills, not a red button. No small/inline solid button — inline actions are text links (.rsm-section-link, .km-side-link, .text-link).

Circular icon buttons (44px, radius 50%): .km-page-icon-btn and .rsm-page-back (white bg, 1px solid var(--grey6) border, 18–20px icon, hover --grey2); .rsm-hero-search (dark-surface variant: rgba(255,255,255,0.1) bg, no border); .km-photo-nav-btn (same as page-icon-btn + :disabled { opacity: 0.4; cursor: not-allowed; }).

Extended FAB:

/* Extended FAB — pill with icon + label, floats at bottom-right above
the bottom nav. Sits outside .km-scroll so it stays pinned while
the page scrolls. z-index keeps it above content but under sheets. */
.km-fab {
position: absolute; right: 24px; bottom: 120px; z-index: 30;
display: inline-flex; align-items: center; gap: 8px;
padding: 0 22px 0 18px; height: 56px;
border-radius: 100px;
background: var(--brand); border: 0;
color: var(--text-main);
font-family: inherit; font-size: 15px; font-weight: 600; letter-spacing: -0.1px;
cursor: pointer;
box-shadow: 0 12px 28px rgba(1,228,111,0.32), 0 2px 6px rgba(0,0,0,0.12);
-webkit-appearance: none; appearance: none;
transition: background 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
}
.km-fab:hover { background: #00C45B; box-shadow: 0 14px 32px rgba(1,228,111,0.36), 0 2px 6px rgba(0,0,0,0.14); }
.km-fab:active { transform: scale(0.97); }
.km-fab svg { width: 18px; height: 18px; }
<button class="km-fab" type="button" onclick="openNewWoSheet()" aria-label="New work order">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
New work order
</button>

Selection-bar buttons (on the dark pill bar): .km-selection-bar-clear (ghost, 36px, white 0.8 text) and .km-selection-bar-send (brand pill, 40px, dark text) — see 3.17.

Text links: .text-link { font-size: 14px; font-weight: 600; color: var(--g-dark); text-decoration: none; cursor: pointer; }; .km-side-link { font-size: 12px; font-weight: 600; color: var(--g-dark); background: none; border: 0; cursor: pointer; font-family: inherit; padding: 0; }; .rsm-section-link (12.5px, see 3.3). All green --g-dark, weight 600, no underline.

The canonical status pill — .km-wo-pill (matches retrofit .rsm-wo-summary-pill / .rsm-q-pill: 10.5px / 600 / 3px 9px / radius 100px). State is a data-state attribute, label is free text:

/* Status pill — matches the retrofit RSM/Team-Lead spec exactly
(.rsm-wo-summary-pill / .rsm-q-pill). Compact pill: 10.5px text,
3px 9px padding, 100px radius. Color tokens shared across products. */
.km-wo-pill { display: inline-flex; align-items: center; font-size: 10.5px; font-weight: 600; padding: 3px 9px; border-radius: 100px; letter-spacing: 0.02em; background: var(--g-3); color: var(--g-dark); white-space: nowrap; flex-shrink: 0; }
.km-wo-pill[data-state="awaiting-qa"] { background: #DBEAFE; color: #1E40AF; }
.km-wo-pill[data-state="ready"] { background: var(--g-3); color: var(--g-dark); }
.km-wo-pill[data-state="parked"] { background: #FEF3C7; color: #B45309; }
.km-wo-pill[data-state="open"] { background: var(--grey3); color: var(--grey11); }
.km-wo-pill[data-state="completed"] { background: var(--grey3); color: var(--grey11); }
.km-wo-pill[data-state="defect"] { background: #FEE2E2; color: #B91C1C; }
<span class="km-wo-pill" data-state="awaiting-qa">Awaiting QA</span>

Color map (default/in-progress = green --g-3/--g-dark):

data-state bg fg labels seen
(default / in-progress) var(--g-3) #B5F1C2 var(--g-dark) #05853E In progress, Active
awaiting-qa #DBEAFE #1E40AF Awaiting QA, Awaiting scan-in, Pending
ready var(--g-3) var(--g-dark) Ready
parked #FEF3C7 #B45309 Parked
open var(--grey3) var(--grey11) Queued
completed var(--grey3) var(--grey11) Completed, Closed, Accepted
defect #FEE2E2 #B91C1C (reserved)

Note the completed-state-subtle discipline: Completed/Closed/Accepted pills are neutral grey, never green.

Other pill/badge species:

  • .km-tab-count — count chip in tabs (11px/600, radius 9px, min 18×18) — see 3.4.
  • .rsm-nav-badge — red notification count on nav (10.5px/700) — see 3.1.
  • .rsm-hero-role — role pill on dark hero: 11px/600, rgba(1,228,111,0.16) bg, --g-primary text, radius 100px, padding 3px 10px.
  • .rsm-profile-role-pill — same shape on white: background: var(--g-2); color: var(--g-dark);.
  • .km-serial-row-pill — icon+text pass chip: display:inline-flex; gap:4px; padding:3px 9px; radius 100px; bg var(--g-3); color var(--g-dark); 10.5px/600; letter-spacing .02em; with 11px check svg. Used as panel-head verdict (“G1 pass”, “G2 + G3 pass”).
  • .ka-evi-result — evidence verdict pill: 11px/600, padding 4px 11px, radius 100px; [data-state="done"|"pass"] green --g-3/--g-dark; [data-state="fail"] #FEE2E2/#B91C1C.
  • .km-bom-snap-pill — neutral “Active” chip on grey card: 11px/600, 3px 9px, radius 100px, white bg, --grey11 text.
  • .km-segmented-opt-mark — kit-type mark chip (22px tall, radius 6px) — see 3.4.
  • Inline “KaaG add” chip (in BOM rows, inline style): font-size:10px;font-weight:600;color:var(--g-dark);padding:1px 6px;border-radius:6px;background:var(--g-3);letter-spacing:0.02em;.
  • ID/type marks (.km-wo-id-mark 44px r12, .km-wo-hero-mark 52px r14, .km-kit-row-mark 44px r12, .km-push-kit-mark 32px r8) — tonal rounded squares with STD/KaaG/1/8 text, green by default, --kaag modifier flips to blue.

Status-dot pattern — gate dots (G1/G2/G3):

/* Gate dots — G1 / G2 / G3 visual status indicator inside an asm row. */
.km-gate-dots { display: inline-flex; align-items: center; gap: 4px; }
.km-gate-dot { width: 20px; height: 20px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 700; letter-spacing: 0; background: var(--grey3); color: var(--grey11); position: relative; }
.km-gate-dot[data-state="pass"] { background: var(--g-3); color: var(--g-dark); }
.km-gate-dot[data-state="active"] { background: #DBEAFE; color: #1E40AF; }
.km-gate-dot[data-state="fail"] { background: #FEE2E2; color: #B91C1C; }
.km-gate-dot svg { width: 11px; height: 11px; }

JS-rendered markup: pass = check svg, fail = X svg, active/pending = the literal text G1/G2/G3:

<div class="km-gate-dots">
<span class="km-gate-dot" data-state="pass" title="G1 pass"><svg …><polyline points="20 6 9 17 4 12"/></svg></span>
<span class="km-gate-dot" data-state="active">G2</span>
<span class="km-gate-dot">G3</span>
</div>

Plain activity dots: .km-activity-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--g-primary); } with [data-tone="amber"] { background: var(--amber9); } / [data-tone="blue"] { background: #1E40AF; }.

Dashboard KPI tiles (3-col grid, overlaps hero by 64px):

/* KPI strip — 3-column grid that wraps to a second row (3 + 2) in
portrait. Overlaps the hero by 64px. */
.km-kpi-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin: -64px 24px 0; position: relative; z-index: 2; }
.km-kpi { background: var(--white); border-radius: 18px; box-shadow: var(--sh-card); padding: 18px 18px 16px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.km-kpi-head { display: flex; align-items: center; gap: 10px; }
.km-kpi-ic { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; background: var(--g-2); color: var(--g-dark); }
.km-kpi-ic svg { width: 18px; height: 18px; }
.km-kpi[data-tone="blue"] .km-kpi-ic { background: #DBEAFE; color: #1E40AF; }
.km-kpi[data-tone="amber"] .km-kpi-ic { background: #FEF3C7; color: var(--amber9); }
.km-kpi[data-tone="red"] .km-kpi-ic { background: #FEE2E2; color: #B91C1C; }
.km-kpi[data-tone="neutral"] .km-kpi-ic { background: var(--grey2); color: var(--grey11); }
.km-kpi-label { font-size: 13px; font-weight: 500; color: var(--grey11); letter-spacing: -0.05em; }
.km-kpi-num { font-size: 28px; font-weight: 700; letter-spacing: -0.4px; line-height: 32px; color: var(--grey12); font-variant-numeric: tabular-nums; }
.km-kpi-num-unit { font-size: 16px; font-weight: 600; color: var(--grey10); margin-left: 2px; letter-spacing: -0.2px; }
.km-kpi-foot { font-size: 11.5px; font-weight: 500; color: var(--grey10); margin-top: -2px; }
<div class="km-kpi" data-tone="blue">
<div class="km-kpi-head">
<span class="km-kpi-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></span>
<span class="km-kpi-label">Awaiting QA</span>
</div>
<p class="km-kpi-num">6</p>
<p class="km-kpi-foot">G2 + G3 pending</p>
</div>

Structure: icon+label head row → 28px/700 number (unit rendered as <span class="km-kpi-num-unit">%</span> inside) → 11.5px foot. Icon treatment = circular tonal container: tinted bg + colored glyph, never solid. Dashboard uses 6 tiles in the 3-col grid (wraps 3+3).

Stat-summary cards (Handoff header, BOM library header — 3-cell row with hairline dividers):

/* Summary card sits above the tabs — quick at-a-glance counters. */
.km-handoff-summary-card { background: var(--white); border-radius: 18px; box-shadow: var(--sh-card); padding: 18px 20px; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }
.km-handoff-summary-cell { display: flex; flex-direction: column; gap: 4px; }
.km-handoff-summary-cell + .km-handoff-summary-cell { border-left: 1px solid var(--grey3); padding-left: 16px; }
.km-handoff-summary-label { font-size: 11px; font-weight: 500; color: var(--grey10); letter-spacing: 0.04em; text-transform: uppercase; }
.km-handoff-summary-val { font-size: 24px; font-weight: 700; color: var(--grey12); letter-spacing: -0.4px; line-height: 28px; font-variant-numeric: tabular-nums; }
.km-handoff-summary-sub { font-size: 11.5px; font-weight: 500; color: var(--grey10); }
/* BOM summary card at top of the library — quick at-a-glance. */
.km-bom-library-summary { background: var(--white); border-radius: 18px; box-shadow: var(--sh-card); padding: 18px 20px; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }
.km-bom-library-summary > * { display: flex; flex-direction: column; gap: 4px; }
.km-bom-library-summary > * + * { border-left: 1px solid var(--grey3); padding-left: 16px; }
<div class="km-handoff-summary-card">
<div class="km-handoff-summary-cell">
<span class="km-handoff-summary-label">Ready</span>
<span class="km-handoff-summary-val">12</span>
<span class="km-handoff-summary-sub">across 3 WOs</span>
</div>
…
</div>

Mini stat block inside side cards (tinted):

/* Handoff queue summary block. */
.km-handoff-summary { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--g-2); border-radius: 12px; }
.km-handoff-ic { width: 40px; height: 40px; border-radius: 50%; background: var(--white); color: var(--g-dark); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.km-handoff-ic svg { width: 18px; height: 18px; }
.km-handoff-text { flex: 1; min-width: 0; }
.km-handoff-count { font-size: 22px; font-weight: 700; color: var(--g-dark); letter-spacing: -0.4px; line-height: 26px; font-variant-numeric: tabular-nums; }
.km-handoff-label { font-size: 12px; font-weight: 500; color: var(--g-dark); margin-top: 2px; }

NO CARD HAS A BORDER. Every card container is white var(--white) + box-shadow: var(--sh-card) only. The only 1px borders in the file are: (a) circular icon-button strokes, (b) .btn-secondary/.input strokes, (c) the nav’s border-top divider, and (d) hairline internal dividers (.km-handoff-summary-cell + … border-left; .km-bom-panel-meta-row border-top; .rsm-profile-row + .rsm-profile-row::before border-top). No accent stripes anywhere.

Card taxonomy (all white + --sh-card, differing only in radius/padding):

class radius padding role
.km-kpi 18px 18px 18px 16px KPI tile
.km-wo-hero-card 18px 22px 24px detail hero summary
.km-bom-panel 18px 22px 24px BOM library panel
.km-handoff-summary-card / .km-bom-library-summary 18px 18px 20px stat summary
.rsm-profile-user 18px 20px profile user card
.km-wo-card 16px 16px 18px dashboard list card
.km-panel 16px 18px generic titled panel
.km-side-card 16px 18px dashboard right-rail card
.rsm-profile-section 16px 4px 0 grouped rows card
.km-wo-row / .km-kit-row 14px 14px 16px / 12px 14px list rows
.km-push-tracker 14px 14px 16px in-transit tracker

Panel + header pattern (verbatim):

/* Section head variant for inside cards / panels. */
.km-panel { background: var(--white); border-radius: 16px; box-shadow: var(--sh-card); padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.km-panel-head { display: flex; align-items: center; justify-content: space-between; }
.km-panel-title { font-size: 14px; font-weight: 600; color: var(--grey12); letter-spacing: -0.1px; }
.km-panel-meta { font-size: 12px; font-weight: 500; color: var(--grey11); }
/* Right column — handoff queue & parked alerts. */
.km-side-card { background: var(--white); border-radius: 16px; box-shadow: var(--sh-card); padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.km-side-head { display: flex; align-items: center; justify-content: space-between; }
.km-side-title { font-size: 14px; font-weight: 600; color: var(--grey12); letter-spacing: -0.1px; }
.km-side-link { font-size: 12px; font-weight: 600; color: var(--g-dark); background: none; border: 0; cursor: pointer; font-family: inherit; padding: 0; }
.km-side-body { display: flex; flex-direction: column; gap: 12px; }
<section class="km-panel">
<div class="km-panel-head">
<h2 class="km-panel-title">BOM components</h2>
<span class="km-panel-meta" id="wo-bom-meta">12 required · BOM v4</span>
</div>
<div class="km-bom-list" id="wo-bom-list"></div>
</section>

Detail hero card (.km-wo-hero-card) — the full-width summary card at the top of every detail screen: head (mark + id + sub + status pill), optional progress, then a meta grid with uppercase micro-labels:

.km-wo-hero-card { background: var(--white); border-radius: 18px; box-shadow: var(--sh-card); padding: 22px 24px; display: flex; flex-direction: column; gap: 18px; }
.km-wo-hero-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.km-wo-hero-id { display: flex; align-items: center; gap: 14px; min-width: 0; flex: 1; }
.km-wo-hero-mark { width: 52px; height: 52px; border-radius: 14px; background: var(--g-3); color: var(--g-dark); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 15px; letter-spacing: -0.1px; flex-shrink: 0; }
.km-wo-hero-mark--kaag { background: #DBEAFE; color: #1E40AF; }
.km-wo-hero-id-text { min-width: 0; }
.km-wo-hero-id-val { font-size: 17px; font-weight: 600; color: var(--grey12); letter-spacing: -0.2px; font-variant-numeric: tabular-nums; }
.km-wo-hero-id-sub { font-size: 13px; font-weight: 500; color: var(--grey10); margin-top: 2px; }
.km-wo-hero-progress { display: flex; flex-direction: column; gap: 6px; }
.km-wo-hero-progress-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.km-wo-hero-progress-label { font-size: 12.5px; color: var(--grey11); }
.km-wo-hero-progress-val { font-size: 17px; font-weight: 700; color: var(--grey12); letter-spacing: -0.2px; font-variant-numeric: tabular-nums; }
.km-wo-hero-progress-bar { display: block; height: 8px; border-radius: 100px; background: var(--grey2); overflow: hidden; }
.km-wo-hero-progress-fill { display: block; height: 100%; background: var(--g-primary); border-radius: 100px; transition: width 0.3s ease; }
.km-wo-hero-meta { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; padding-top: 4px; }
.km-wo-hero-meta-cell { display: flex; flex-direction: column; gap: 2px; }
.km-wo-hero-meta-label { font-size: 11px; font-weight: 500; color: var(--grey10); letter-spacing: 0.04em; text-transform: uppercase; }
.km-wo-hero-meta-val { font-size: 14px; font-weight: 600; color: var(--grey12); letter-spacing: -0.1px; }
<div class="km-wo-hero-card">
<div class="km-wo-hero-head">
<div class="km-wo-hero-id">
<span class="km-wo-hero-mark" id="wo-hero-mark">STD</span>
<div class="km-wo-hero-id-text">
<p class="km-wo-hero-id-val" id="wo-hero-id">WO-K-2407-0188</p>
<p class="km-wo-hero-id-sub" id="wo-hero-sub">Standard kit · BOM v4 · Due today 5 PM</p>
</div>
</div>
<span class="km-wo-pill" id="wo-hero-pill" data-state="in-progress">In progress</span>
</div>
<div class="km-wo-hero-progress">
<div class="km-wo-hero-progress-row">
<span class="km-wo-hero-progress-label" id="wo-progress-label">Kits closed</span>
<span class="km-wo-hero-progress-val"><span id="wo-progress-done">5</span> <span style="font-size:13px;font-weight:500;color:var(--grey10);">of <span id="wo-progress-total">8</span></span></span>
</div>
<span class="km-wo-hero-progress-bar"><span class="km-wo-hero-progress-fill" id="wo-progress-fill" style="width: 62%;"></span></span>
</div>
<div class="km-wo-hero-meta">
<div class="km-wo-hero-meta-cell">
<span class="km-wo-hero-meta-label" id="wo-meta-1-label">Assemblers</span>
<span class="km-wo-hero-meta-val" id="wo-meta-1-val">3 active</span>
</div>
…×3
</div>
</div>

Tinted inner blocks (the only tinted surfaces, always INSIDE a white card, radius 10–12px): .km-handoff-summary (green --g-2), .km-alert-row (amber #FEF3C7 — warning affordance), .km-bom-snap / .km-date-row / all grey sub-rows (--grey2), selected .km-kit-row (rgba(1,228,111,0.08)).

/* Parked alert row. */
.km-alert-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px; background: #FEF3C7; border-radius: 12px; border: 0; width: 100%; text-align: left; font-family: inherit; cursor: pointer; -webkit-appearance: none; appearance: none; transition: filter 0.15s ease; }
.km-alert-row:hover { filter: brightness(0.97); }
.km-alert-ic { width: 32px; height: 32px; border-radius: 50%; background: var(--white); color: var(--amber9); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.km-alert-ic svg { width: 16px; height: 16px; }
.km-alert-text { flex: 1; min-width: 0; }
.km-alert-title { font-size: 13px; font-weight: 600; color: var(--amber9); letter-spacing: -0.05em; }
.km-alert-sub { font-size: 11.5px; font-weight: 500; color: var(--amber9); opacity: 0.85; margin-top: 2px; }

BOM library panel extras:

.km-bom-panel { background: var(--white); border-radius: 18px; box-shadow: var(--sh-card); padding: 22px 24px; display: flex; flex-direction: column; gap: 18px; }
.km-bom-panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.km-bom-panel-id { display: flex; align-items: center; gap: 14px; min-width: 0; flex: 1; }
.km-bom-panel-meta-row { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 12px; padding-top: 2px; border-top: 1px solid var(--grey3); padding: 14px 0 4px; margin-top: -4px; }
/* Components grid — 2 cols inside each BOM panel. */
.km-bom-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.km-bom-grid .km-bom-row { padding: 10px 12px; }
/* Spec tiles — Tooling / Acceptance / Revision history. */
.km-bom-specs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.km-bom-spec-tile {
display: flex; align-items: center; gap: 10px;
padding: 12px 14px;
background: var(--grey2); border-radius: 12px;
border: 0; cursor: pointer; text-align: left; font-family: inherit;
-webkit-appearance: none; appearance: none;
transition: background 0.15s ease;
}
.km-bom-spec-tile:hover { background: var(--grey3); }
.km-bom-spec-tile-ic { width: 32px; height: 32px; border-radius: 10px; background: var(--white); color: var(--g-dark); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.km-bom-spec-tile-ic svg { width: 16px; height: 16px; }
.km-bom-spec-tile-text { flex: 1; min-width: 0; }
.km-bom-spec-tile-name { font-size: 12.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-bom-spec-tile-sub { font-size: 11px; color: var(--grey10); margin-top: 2px; }

Push tracker card (In-transit pane):

/* Compact "in transit" card showing live status of a push request. */
.km-push-tracker { background: var(--white); border-radius: 14px; box-shadow: var(--sh-card); padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.km-push-tracker-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.km-push-tracker-id { font-size: 13.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; font-variant-numeric: tabular-nums; }
.km-push-tracker-sub { font-size: 11.5px; color: var(--grey10); margin-top: 2px; }
.km-push-tracker-progress-row { display: flex; align-items: center; justify-content: space-between; font-size: 12.5px; }
.km-push-tracker-progress-label { color: var(--grey11); }
.km-push-tracker-progress-val { font-weight: 600; color: var(--grey12); font-variant-numeric: tabular-nums; }
.km-push-tracker-progress-bar { display: block; height: 5px; border-radius: 100px; background: var(--grey2); overflow: hidden; }
.km-push-tracker-progress-fill { display: block; height: 100%; background: var(--g-primary); border-radius: 100px; transition: width 0.3s ease; }

3.10 Overlays: bottom sheet (the ONLY overlay type)

Section titled “3.10 Overlays: bottom sheet (the ONLY overlay type)”

There are no centered modals, no drawers in this file. All confirmations, forms and viewers are bottom sheets (.rsm-sheet-*, reused from the retrofit auto-mech kit-request pattern). Four instances: #sheet-new-wo (form), #sheet-push-request (confirmation form), #sheet-qa-photos (photo viewer), #sheet-evidence (read-only evidence). Sheets live at .tablet level, absolute inset 0, z-index 50 (above FAB z-30 and selection bar z-25, below toast z-80).

.rsm-sheet-overlay { position: absolute; inset: 0; z-index: 50; display: flex; flex-direction: column; justify-content: flex-end; pointer-events: none; overflow: hidden; }
.rsm-sheet-overlay.is-open { pointer-events: auto; }
.rsm-sheet-backdrop { position: absolute; inset: 0; background: rgba(14,15,18,0.45); opacity: 0; transition: opacity 0.22s ease; }
.rsm-sheet-overlay.is-open .rsm-sheet-backdrop { opacity: 1; }
.rsm-sheet { position: relative; background: var(--white); border-radius: 24px 24px 0 0; padding: 0 32px; transform: translateY(100%); transition: transform 0.28s cubic-bezier(0.32,0.72,0,1); box-shadow: var(--sh-sheet); max-height: 80%; display: flex; flex-direction: column; }
.rsm-sheet-overlay.is-open .rsm-sheet { transform: translateY(0); }
.rsm-sheet-handle-row { display: flex; align-items: center; justify-content: center; padding: 10px 0 6px; flex-shrink: 0; }
.rsm-sheet-handle { width: 40px; height: 4px; border-radius: 100px; background: var(--grey5); }
.rsm-sheet-head { padding: 8px 0 16px; flex-shrink: 0; }
.rsm-sheet-title { font-size: 20px; font-weight: 600; color: var(--grey12); letter-spacing: -0.3px; margin: 0; }
.rsm-sheet-sub { font-size: 13px; color: var(--grey11); line-height: 19px; margin: 4px 0 0; }
.rsm-sheet-body { display: flex; flex-direction: column; gap: 18px; padding: 0 0 8px; overflow-y: auto; }
.rsm-sheet-body::-webkit-scrollbar { display: none; }
.rsm-sheet-cta { display: flex; flex-direction: column; gap: 10px; padding: 16px 0 28px; flex-shrink: 0; }

Skeleton markup (New WO sheet, abbreviated body):

<div class="rsm-sheet-overlay" id="sheet-new-wo">
<div class="rsm-sheet-backdrop" onclick="closeNewWoSheet()"></div>
<div class="rsm-sheet">
<div class="rsm-sheet-handle-row"><span class="rsm-sheet-handle"></span></div>
<div class="rsm-sheet-head">
<p class="rsm-sheet-title">New work order</p>
<p class="rsm-sheet-sub">Issue a WO against the active BOM. The system spawns one assembly record per kit.</p>
</div>
<div class="rsm-sheet-body">
<div class="km-field">…</div>
…
</div>
<div class="rsm-sheet-cta">
<button class="btn-primary btn-primary--lg" type="button" onclick="submitNewWo()">Issue work order</button>
<button class="btn-secondary btn-secondary--lg" type="button" onclick="closeNewWoSheet()">Cancel</button>
</div>
</div>
</div>

Footer button placement rule: vertically stacked full-width buttons in .rsm-sheet-cta, primary on top, secondary (Cancel/Close) below, both --lg (56px). View-only sheets get a single btn-secondary--lg Close. Backdrop click closes. Open/close = toggling .is-open on the overlay. Dialog a11y attrs appear on the evidence sheet: role="dialog" aria-modal="true" aria-labelledby="evidence-title".

Canonical DS .alert-toast pill, top-center, badge + text + close:

/* Toast */
.alert-toast { position: absolute; top: 64px; left: 50%; transform: translate(-50%, -16px); z-index: 80; display: inline-flex; align-items: center; gap: 8px; border-radius: 999px; padding: 4px 14px 4px 4px; white-space: nowrap; box-shadow: 0 4px 20px rgba(0,0,0,0.12); opacity: 0; pointer-events: none; transition: opacity 0.25s ease, transform 0.25s ease; }
.alert-toast.is-visible { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.alert-toast-badge { display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,0.85); border-radius: 12px; padding: 3px 10px; font-size: 13px; font-weight: 500; line-height: 20px; }
.alert-toast-text { font-size: 13px; font-weight: 500; line-height: 20px; }
.alert-toast--success { background: #dcfbe2; color: #05853e; }
.alert-toast--info { background: #e6f4fe; color: #0d74ce; }
.alert-toast--warning { background: #fef3c7; color: #92400e; }
.alert-toast--error { background: #fee2e2; color: #b91c1c; }

Host element: <div class="alert-toast" id="toast"></div> (last child of .tablet).

JS helper (verbatim):

let toastT;
function showToast(msg, badge, variant = 'success') {
const el = document.getElementById('toast');
if (!el) return;
el.className = 'alert-toast is-visible alert-toast--' + variant;
el.innerHTML = (badge ? `<span class="alert-toast-badge">${badge}</span>` : '') +
`<span class="alert-toast-text">${msg}</span>` +
`<button class="alert-toast-close" type="button" aria-label="Dismiss" onclick="hideToast()">` +
`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>` +
`</button>`;
clearTimeout(toastT);
toastT = setTimeout(hideToast, 3200);
}
function hideToast() {
const el = document.getElementById('toast');
if (el) el.classList.remove('is-visible');
}

Signature: showToast(msg, badge, variant = 'success') — variant ∈ success | info | warning | error. Auto-hides after 3200ms. Call convention seen in file: showToast('Label sent to printer', 'Printed', 'success'), showToast('${label} kit · … ', 'WO issued', 'success'), showToast('Kit detail unavailable', kitId, 'info'). NOTE: .alert-toast-close is generated by JS but has no CSS rule in this file (inherits the global reset; svg has no size constraint) — a latent gap, do not copy that omission; give the close button explicit sizing when reusing.

Auth text input (white, bordered, focus ring):

.field-group { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
.field-label { font-size: 14px; font-weight: 500; color: var(--grey12); line-height: 20px; }
.input { display: flex; align-items: center; gap: 8px; height: 52px; padding: 0 16px; background: var(--white); border: 1px solid var(--grey6); border-radius: 10px; box-shadow: 0 1px 2px rgba(16,24,40,0.05); transition: border-color 0.18s ease, box-shadow 0.18s ease; }
.input:focus-within { border-color: var(--brand); box-shadow: 0 0 0 4px rgba(1,228,111,0.12); }
.input.is-error { border-color: var(--red9); box-shadow: 0 0 0 4px rgba(227,38,39,0.12); }
.input input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; font-family: inherit; font-size: 16px; line-height: 24px; color: var(--grey12); }
.input input::placeholder { color: var(--grey9); }
.input-icon { width: 20px; height: 20px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: transparent; border: 0; padding: 0; outline: 0; -webkit-appearance: none; appearance: none; color: var(--grey10); cursor: pointer; }
.input-icon svg { width: 100%; height: 100%; display: block; }
.field-aside { text-align: right; margin-top: 6px; }
.text-link { font-size: 14px; font-weight: 600; color: var(--g-dark); text-decoration: none; cursor: pointer; }
<div class="field-group">
<label class="field-label" for="welcome-email">Email</label>
<div class="input">
<input id="welcome-email" type="email" placeholder="you@rechaj.com" value="erioluwa.morenikeji@rechaj.com" oninput="onWelcomeInput()">
</div>
</div>

Focus ring = brand border + 0 0 0 4px rgba(1,228,111,0.12) halo. Error = red border + red halo.

In-sheet field rhythm (grey fills, no borders):

/* Field label + control rhythm inside the sheet. */
.km-field { display: flex; flex-direction: column; gap: 8px; }
.km-field-label { font-size: 13px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }

Textarea:

/* Notes textarea reused styling. */
.km-textarea { width: 100%; box-sizing: border-box; resize: none; border: 0; border-radius: 12px; padding: 12px 14px; background: var(--grey2); font-family: inherit; font-size: 14px; line-height: 20px; color: var(--grey12); -webkit-appearance: none; appearance: none; }
.km-textarea::placeholder { color: var(--grey9); }

Date/select-style row (grey pseudo-select, tap to change — no native select exists in the file):

/* Due-date row uses the same input style. */
.km-date-row { display: flex; align-items: center; gap: 8px; height: 52px; padding: 0 16px; background: var(--grey2); border-radius: 10px; cursor: pointer; }
.km-date-row svg { width: 18px; height: 18px; color: var(--grey10); flex-shrink: 0; }
.km-date-row-val { font-size: 14px; font-weight: 500; color: var(--grey12); flex: 1; }
.km-date-row-chev { color: var(--grey9); }

Quantity stepper (pill track + circular white buttons):

/* Big stepper — reuses .rsm-stepper / .ak-stepper shape, sized for tablet. */
.km-qty-stepper { display: inline-flex; align-items: center; gap: 0; background: var(--grey2); border-radius: 100px; padding: 4px; align-self: flex-start; }
.km-qty-stepper button { width: 36px; height: 36px; border: 0; background: var(--white); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: var(--grey12); cursor: pointer; -webkit-appearance: none; appearance: none; box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
.km-qty-stepper button:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
.km-qty-stepper button svg { width: 16px; height: 16px; }
.km-qty-stepper-val { min-width: 56px; text-align: center; font-size: 18px; font-weight: 700; color: var(--grey12); letter-spacing: -0.3px; padding: 0 12px; font-variant-numeric: tabular-nums; }
<div class="km-qty-stepper" role="group" aria-label="Target quantity">
<button type="button" aria-label="Decrease" onclick="adjNewWoQty(-1)"><svg …><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
<span class="km-qty-stepper-val" id="new-wo-qty">8</span>
<button type="button" aria-label="Increase" onclick="adjNewWoQty(1)"><svg …><line x1="5" y1="12" x2="19" y2="12"/><line x1="12" y1="5" x2="12" y2="19"/></svg></button>
</div>

Toggle switch:

/* Toggle inside profile row — same shape as retrofit .rsm-toggle. */
.rsm-toggle { position: relative; width: 40px; height: 24px; background: var(--grey5); border-radius: 100px; cursor: pointer; transition: background 0.2s ease; border: 0; -webkit-appearance: none; appearance: none; flex-shrink: 0; }
.rsm-toggle::after { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: var(--white); border-radius: 50%; transition: transform 0.2s ease; box-shadow: 0 1px 2px rgba(0,0,0,0.1); }
.rsm-toggle[aria-pressed="true"] { background: var(--g-primary); }
.rsm-toggle[aria-pressed="true"]::after { transform: translateX(16px); }
<button class="rsm-toggle" type="button" aria-pressed="true" aria-label="Push notifications" onclick="this.setAttribute('aria-pressed', this.getAttribute('aria-pressed') === 'true' ? 'false' : 'true')"></button>

Search: there is no inline search input anywhere — search is always the circular icon button in the page head / hero (non-functional stub in this file).

None present. No dropdown/popover/menu component exists in this file. The “More actions” ⋯ button on WO detail stubs to showToast('Action menu', 'Coming soon', 'info') — a real action menu would presumably be a bottom sheet. The date field cycles preset values instead of opening a picker.

List-pane empty state (CSS present; not exercised in the markup since every pane has rows):

.km-wo-empty { padding: 48px 24px; text-align: center; color: var(--grey10); }
.km-wo-empty h3 { font-size: 14px; font-weight: 600; color: var(--grey11); margin-bottom: 4px; }
.km-wo-empty p { font-size: 12.5px; }

Screen placeholder (for unbuilt screens):

/* ── Placeholders for screens we haven't built yet ── */
.km-placeholder { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 24px; text-align: center; gap: 10px; color: var(--grey11); }
.km-placeholder h2 { font-size: 20px; font-weight: 600; color: var(--grey12); }
.km-placeholder p { font-size: 14px; color: var(--grey11); max-width: 340px; line-height: 1.5; }

JS-rendered “Not started” empty panel (kit detail for queued kits) — centered 56px grey circular icon + panel title + explainer (from renderKitSplit):

<div class="km-panel" style="text-align:center; padding: 40px 24px;">
<div style="width:56px;height:56px;border-radius:50%;background:var(--grey2);color:var(--grey10);display:flex;align-items:center;justify-content:center;align-self:center;margin-bottom:14px;">
<svg …style="width:22px;height:22px;"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/></svg>
</div>
<h2 class="km-panel-title">Not started</h2>
<p style="font-size:13px;color:var(--grey11);line-height:18px;margin-top:6px;max-width:360px;margin-left:auto;margin-right:auto;">This kit is queued under <strong>WO-…</strong>. An assembly record will open when an assembler picks it up.</p>
</div>

Circular is the default for every icon container, with tonal tinting (tinted bg + colored glyph), never solid fills:

container size shape fill
.km-kpi-ic 36px circle tinted tone bg + tone glyph (--g-2/--g-dark default)
.km-handoff-ic, .km-qa-ic 40px circle white circle + green glyph (on tinted/grey rows — inverted tonal)
.km-alert-ic 32px circle white circle + amber glyph (on amber row)
.km-sop-check 22px circle --g-3 + --g-dark check
.km-gate-dot 20px circle tonal per state
.km-asm-activity-dot 22px circle --g-3/--g-dark, tones grey/blue
.km-activity-dot 8px circle solid tone dot (plain bullet)
.rsm-hero-avatar 52 / .rsm-profile-avatar 64 / .km-push-recipient-avatar 40 circle solid --brand (avatars) or --g-3
.rsm-page-back, .km-page-icon-btn, .km-photo-nav-btn, .rsm-hero-search 44px circle buttons
.rsm-profile-chev 32px circle --grey2 + grey chevron
.km-kit-select 22px circle radio-style check
.km-photo-stage-ic 56px circle rgba(255,255,255,0.08) on dark

Rounded-square exceptions (identity marks & media, NOT icons): .km-wo-id-mark/.km-kit-row-mark 44px r12, .km-wo-hero-mark 52px r14, .km-push-kit-mark 32px r8 (these hold TEXT: STD/KaaG/1-of-8); .rsm-profile-row-ic 36px r10 (the documented Kit-Assembler-precedent exception — grey2 square + dark glyph, red-tinted for danger); .km-bom-spec-tile-ic 32px r10 and .km-bom-snap-ic 36px r10 (white squares on grey tiles); photo/media thumbs .km-qa-photo 44px r10, .ka-evi-thumb 84px r12 (dark gradient media placeholders).

3.16 Progress bars (three sizes, one grammar)

Section titled “3.16 Progress bars (three sizes, one grammar)”

Track = --grey2, fill = --g-primary, radius 100px, transition: width 0.3s ease; tones: [data-tone="amber"] #F59E0B (parked), [data-tone="grey"] --grey6 (queued/0%).

  • Hero: 8px (.km-wo-hero-progress-bar)
  • Card: 6px (.km-wo-progress-bar)
  • Row / tracker: 5px, row fixed 110px wide (.km-wo-row-progress-bar, .km-push-tracker-progress-bar)
/* Progress row inside WO card. */
.km-wo-progress { display: flex; flex-direction: column; gap: 6px; }
.km-wo-progress-row { display: flex; align-items: center; justify-content: space-between; font-size: 12.5px; }
.km-wo-progress-label { color: var(--grey11); }
.km-wo-progress-val { font-weight: 600; color: var(--grey12); font-variant-numeric: tabular-nums; }
.km-wo-progress-bar { height: 6px; border-radius: 100px; background: var(--grey2); overflow: hidden; }
.km-wo-progress-fill { height: 100%; background: var(--g-primary); border-radius: 100px; transition: width 0.3s ease; }
.km-wo-progress-fill[data-tone="amber"] { background: #F59E0B; }

3.17 Selection action bar (multi-select pattern)

Section titled “3.17 Selection action bar (multi-select pattern)”

Dark pill bar, pinned above the nav, slides up when selection > 0:

/* Selection action bar — sticky to the bottom of the .km-scroll area
just above the nav. Slides up via transform when selection > 0. */
.km-selection-bar {
position: absolute; left: 24px; right: 24px; bottom: 100px;
z-index: 25;
display: flex; align-items: center; justify-content: space-between;
padding: 10px 14px 10px 18px;
background: var(--grey12); color: var(--white);
border-radius: 100px;
box-shadow: 0 12px 28px rgba(0,0,0,0.24);
transform: translateY(20px); opacity: 0; pointer-events: none;
transition: transform 0.22s ease, opacity 0.22s ease;
}
.km-selection-bar.is-visible { transform: translateY(0); opacity: 1; pointer-events: auto; }
.km-selection-bar-count { font-size: 14px; font-weight: 600; letter-spacing: -0.1px; }
.km-selection-bar-actions { display: flex; align-items: center; gap: 8px; }
.km-selection-bar-clear { padding: 6px 12px; height: 36px; border-radius: 100px; background: transparent; border: 0; color: rgba(255,255,255,0.8); font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.km-selection-bar-clear:hover { color: var(--white); }
.km-selection-bar-send { display: inline-flex; align-items: center; gap: 8px; padding: 0 18px; height: 40px; border-radius: 100px; background: var(--brand); border: 0; color: var(--text-main); font-family: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer; -webkit-appearance: none; appearance: none; }
.km-selection-bar-send:hover { background: #00C45B; }
.km-selection-bar-send svg { width: 14px; height: 14px; }
<div class="km-selection-bar" id="kit-selection-bar">
<span class="km-selection-bar-count" id="kit-selection-count">0 kits selected</span>
<div class="km-selection-bar-actions">
<button class="km-selection-bar-clear" type="button" onclick="clearKitSelection()">Clear</button>
<button class="km-selection-bar-send" type="button" onclick="openPushRequestSheet()">
<svg …>…</svg>
Build push request
</button>
</div>
</div>

(a) Compact feed (dashboard) — dot / text / time, no connectors:

/* Activity feed row — compact, mirrors the timeline pattern. */
.km-activity-row { display: flex; align-items: flex-start; gap: 10px; padding: 6px 0; }
.km-activity-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--g-primary); flex-shrink: 0; margin-top: 7px; }
.km-activity-dot[data-tone="amber"] { background: var(--amber9); }
.km-activity-dot[data-tone="blue"] { background: #1E40AF; }
.km-activity-text { flex: 1; min-width: 0; font-size: 12.5px; line-height: 18px; color: var(--grey12); }
.km-activity-text strong { font-weight: 600; }
.km-activity-time { font-size: 11px; color: var(--grey10); flex-shrink: 0; margin-top: 3px; }
<div class="km-activity-row">
<span class="km-activity-dot" data-tone="amber"></span>
<p class="km-activity-text"><strong>WO-K-2407-0190</strong> parked · wiring harness short</p>
<span class="km-activity-time">42 min</span>
</div>

(b) Connected audit timeline (assembly detail) — 22px check-dots joined by a 2px grey rail:

/* Activity timeline inside assembly detail. */
.km-asm-activity { display: flex; flex-direction: column; }
.km-asm-activity-row { position: relative; display: grid; grid-template-columns: 22px 1fr auto; gap: 10px; align-items: flex-start; padding: 8px 0; }
.km-asm-activity-row::before {
content: ''; position: absolute; left: 10px; top: 24px; bottom: -8px;
width: 2px; background: var(--grey3);
}
.km-asm-activity-row:last-child::before { display: none; }
.km-asm-activity-dot { width: 22px; height: 22px; border-radius: 50%; background: var(--g-3); color: var(--g-dark); display: inline-flex; align-items: center; justify-content: center; position: relative; z-index: 1; flex-shrink: 0; }
.km-asm-activity-dot[data-tone="grey"] { background: var(--grey3); color: var(--grey11); }
.km-asm-activity-dot[data-tone="blue"] { background: #DBEAFE; color: #1E40AF; }
.km-asm-activity-dot svg { width: 11px; height: 11px; }
.km-asm-activity-text { font-size: 12.5px; line-height: 17px; color: var(--grey12); padding-top: 2px; }
.km-asm-activity-text strong { font-weight: 600; }
.km-asm-activity-text .km-asm-activity-sub { display: block; font-size: 11.5px; color: var(--grey10); margin-top: 2px; }
.km-asm-activity-time { font-size: 11px; color: var(--grey10); padding-top: 4px; font-variant-numeric: tabular-nums; }
<div class="km-asm-activity-row">
<span class="km-asm-activity-dot"><svg …><polyline points="20 6 9 17 4 12"/></svg></span>
<p class="km-asm-activity-text"><strong>G2 Visual passed</strong><span class="km-asm-activity-sub">Adaeze · 2 photos captured</span></p>
<span class="km-asm-activity-time">8:38 AM</span>
</div>

Camera tile with count badge (opens viewer sheet):

.km-qa-photo { width: 44px; height: 44px; border-radius: 10px; background: linear-gradient(160deg, #1f1f23 0%, #0e0e10 100%); flex-shrink: 0; display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.4); position: relative; overflow: hidden; border: 0; padding: 0; cursor: pointer; -webkit-appearance: none; appearance: none; transition: transform 0.1s ease, box-shadow 0.15s ease; }
.km-qa-photo:hover { box-shadow: 0 4px 14px rgba(0,0,0,0.2); }
.km-qa-photo:active { transform: scale(0.96); }
.km-qa-photo svg { width: 18px; height: 18px; }
.km-qa-photo-count { position: absolute; right: 4px; bottom: 4px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: var(--white); color: var(--grey12); font-size: 10px; font-weight: 700; display: flex; align-items: center; justify-content: center; line-height: 1; font-variant-numeric: tabular-nums; }

Viewer stage + meta + nav (inside #sheet-qa-photos):

/* QA photo viewer sheet — opens when a camera tile is tapped. */
.km-photo-stage {
width: 100%; aspect-ratio: 4 / 3; border-radius: 16px;
background: linear-gradient(160deg, #1f1f23 0%, #0a0a0c 70%, #050505 100%);
position: relative; overflow: hidden;
display: flex; align-items: center; justify-content: center;
color: rgba(255,255,255,0.5);
}
.km-photo-stage::before {
content: ''; position: absolute; inset: 0;
background:
radial-gradient(circle at 30% 25%, rgba(255,255,255,0.06), transparent 50%),
radial-gradient(circle at 75% 70%, rgba(1,228,111,0.05), transparent 55%);
pointer-events: none;
}
.km-photo-stage-ic { position: relative; z-index: 1; width: 56px; height: 56px; border-radius: 50%; background: rgba(255,255,255,0.08); display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.5); }
.km-photo-stage-ic svg { width: 24px; height: 24px; }
.km-photo-stage-label { position: absolute; left: 20px; bottom: 18px; right: 20px; display: flex; align-items: center; gap: 10px; }
.km-photo-stage-label-text { font-size: 13px; font-weight: 500; color: rgba(255,255,255,0.85); letter-spacing: -0.05em; flex: 1; min-width: 0; }
.km-photo-stage-counter { font-size: 12px; font-weight: 600; color: rgba(255,255,255,0.7); padding: 4px 9px; border-radius: 100px; background: rgba(255,255,255,0.12); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.km-photo-meta { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; padding: 4px 0; }
.km-photo-meta-cell { display: flex; flex-direction: column; gap: 2px; }
.km-photo-meta-label { font-size: 11px; font-weight: 500; color: var(--grey10); letter-spacing: 0.04em; text-transform: uppercase; }
.km-photo-meta-val { font-size: 13.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-photo-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 4px; }
.km-photo-nav-btn { width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--grey6); background: var(--white); display: flex; align-items: center; justify-content: center; color: var(--grey12); cursor: pointer; -webkit-appearance: none; appearance: none; transition: background 0.15s ease; }
.km-photo-nav-btn:hover { background: var(--grey2); }
.km-photo-nav-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.km-photo-nav-btn svg { width: 18px; height: 18px; }
.km-photo-nav-dots { display: inline-flex; align-items: center; gap: 6px; }
.km-photo-nav-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--grey4); }
.km-photo-nav-dot.is-active { background: var(--g-primary); width: 24px; border-radius: 100px; }

Evidence sheet atoms (ka- prefix, shared with Kit Assembler flow):

/* Read-only evidence sheet — view what the assembler submitted per SOP step */
.ka-evi-result { display: inline-flex; align-items: center; align-self: flex-start; font-size: 11px; font-weight: 600; padding: 4px 11px; border-radius: 100px; letter-spacing: 0.02em; }
.ka-evi-result[data-state="done"], .ka-evi-result[data-state="pass"] { background: var(--g-3); color: var(--g-dark); }
.ka-evi-result[data-state="fail"] { background: #FEE2E2; color: #B91C1C; }
.ka-evi-thumbs { display: flex; gap: 8px; flex-wrap: wrap; }
.ka-evi-thumb { width: 84px; height: 84px; border-radius: 12px; background: linear-gradient(135deg, #1f2230 0%, #2c3140 100%); display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.45); flex-shrink: 0; }
.ka-evi-thumb svg { width: 24px; height: 24px; }
.ka-evi-meta { font-size: 11.5px; color: var(--grey10); line-height: 16px; }
.ka-evi-note { font-size: 12.5px; color: var(--grey11); line-height: 17px; padding: 10px 12px; background: var(--grey2); border-radius: 10px; }
.ka-evi-note--defect { background: rgba(227,38,39,0.06); color: #B91C1C; }
.rsm-profile-user { background: var(--white); border-radius: 18px; box-shadow: var(--sh-card); padding: 20px; display: flex; align-items: center; gap: 14px; cursor: pointer; border: 0; text-align: left; font-family: inherit; width: 100%; -webkit-appearance: none; appearance: none; transition: background 0.15s ease; }
.rsm-profile-user:hover { background: var(--grey1); }
.rsm-profile-avatar { width: 64px; height: 64px; border-radius: 50%; background: var(--brand); display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 600; color: var(--text-main); letter-spacing: -0.4px; flex-shrink: 0; }
.rsm-profile-text { flex: 1; min-width: 0; }
.rsm-profile-name { font-size: 17px; font-weight: 600; color: var(--grey12); letter-spacing: -0.2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rsm-profile-role-pill { display: inline-block; font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: 100px; background: var(--g-2); color: var(--g-dark); letter-spacing: 0.02em; margin: 6px 0 2px; }
.rsm-profile-meta { font-size: 12.5px; color: var(--grey11); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rsm-profile-chev { width: 32px; height: 32px; border-radius: 50%; background: var(--grey2); display: flex; align-items: center; justify-content: center; color: var(--grey10); flex-shrink: 0; }
.rsm-profile-chev svg { width: 16px; height: 16px; }
.rsm-profile-section-title { font-size: 12px; font-weight: 600; color: var(--grey10); letter-spacing: 0.06em; text-transform: uppercase; padding: 0 4px 6px; }
.rsm-profile-section { background: var(--white); border-radius: 16px; box-shadow: var(--sh-card); padding: 4px 0; }
.rsm-profile-row { display: flex; align-items: center; gap: 14px; width: 100%; padding: 14px 18px; background: transparent; border: 0; text-align: left; cursor: pointer; font-family: inherit; -webkit-appearance: none; appearance: none; position: relative; transition: background 0.15s ease; }
.rsm-profile-row:hover { background: var(--grey1); }
.rsm-profile-row + .rsm-profile-row::before { content: ''; position: absolute; left: 64px; right: 18px; top: 0; border-top: 1px solid var(--grey3); }
.rsm-profile-row-ic { width: 36px; height: 36px; border-radius: 10px; background: var(--grey2); display: flex; align-items: center; justify-content: center; color: var(--grey12); flex-shrink: 0; }
.rsm-profile-row-ic svg { width: 18px; height: 18px; }
.rsm-profile-row-label { flex: 1; font-size: 14.5px; font-weight: 500; color: var(--grey12); letter-spacing: -0.1px; }
.rsm-profile-row-sub { display: block; font-size: 12px; font-weight: 500; color: var(--grey10); margin-top: 2px; letter-spacing: 0; }
.rsm-profile-row-tail { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--grey10); flex-shrink: 0; }
.rsm-profile-row-tail svg { width: 16px; height: 16px; color: var(--grey10); }
.rsm-profile-row--danger .rsm-profile-row-ic { background: #FEE2E2; color: #B91C1C; }
.rsm-profile-row--danger .rsm-profile-row-label { color: #B91C1C; }
.rsm-profile-row--danger .rsm-profile-row-tail svg { color: #B91C1C; opacity: 0.7; }
<div>
<p class="rsm-profile-section-title">Support</p>
<div class="rsm-profile-section">
<button class="rsm-profile-row" type="button">
<span class="rsm-profile-row-ic"><svg …>…</svg></span>
<span class="rsm-profile-row-label">About
<span class="rsm-profile-row-sub">Kit Production v2.0 · Build 14.05</span>
</span>
<span class="rsm-profile-row-tail"><svg …><polyline points="9 18 15 12 9 6"/></svg></span>
</button>
<button class="rsm-profile-row rsm-profile-row--danger" type="button" onclick="goTo('s-welcome')">
<span class="rsm-profile-row-ic"><svg …>…</svg></span>
<span class="rsm-profile-row-label">Sign out</span>
<span class="rsm-profile-row-tail"><svg …><polyline points="9 18 15 12 9 6"/></svg></span>
</button>
</div>
</div>

Danger = tinted red icon square + red label; Sign out routes to s-welcome. Row tails can carry value text (“On”, “English”) before the chevron.

3.21 Push-request sheet atoms (recipient + removable kit list)

Section titled “3.21 Push-request sheet atoms (recipient + removable kit list)”
/* Push request sheet — kit-id list, recipient row, notes, send CTA. */
.km-push-recipient { display: flex; align-items: center; gap: 12px; padding: 14px; background: var(--grey2); border-radius: 12px; }
.km-push-recipient-avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--g-3); color: var(--g-dark); display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 600; flex-shrink: 0; letter-spacing: -0.1px; }
.km-push-recipient-text { flex: 1; min-width: 0; }
.km-push-recipient-name { font-size: 13.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; }
.km-push-recipient-role { font-size: 12px; color: var(--grey10); margin-top: 2px; }
.km-push-kit-list { display: flex; flex-direction: column; gap: 6px; max-height: 220px; overflow-y: auto; padding-right: 4px; }
.km-push-kit-list::-webkit-scrollbar { width: 4px; }
.km-push-kit-list::-webkit-scrollbar-thumb { background: var(--grey4); border-radius: 100px; }
.km-push-kit-row { display: grid; grid-template-columns: 32px 1fr auto; gap: 10px; align-items: center; padding: 10px 12px; background: var(--grey2); border-radius: 10px; }
.km-push-kit-mark { width: 32px; height: 32px; border-radius: 8px; background: var(--white); color: var(--g-dark); display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 600; flex-shrink: 0; }
.km-push-kit-mark--kaag { color: #1E40AF; }
.km-push-kit-id { font-size: 12.5px; font-weight: 600; color: var(--grey12); letter-spacing: -0.05em; font-variant-numeric: tabular-nums; }
.km-push-kit-sub { font-size: 11px; color: var(--grey10); margin-top: 2px; }
.km-push-kit-remove { width: 24px; height: 24px; border-radius: 50%; background: transparent; border: 0; color: var(--grey9); cursor: pointer; display: flex; align-items: center; justify-content: center; -webkit-appearance: none; appearance: none; }
.km-push-kit-remove:hover { color: var(--grey12); background: var(--white); }
.km-push-kit-remove svg { width: 12px; height: 12px; }

3.22 BOM snapshot read-out (read-only info card in forms)

Section titled “3.22 BOM snapshot read-out (read-only info card in forms)”
/* BOM snapshot read-out — read-only card showing what's being snapped. */
.km-bom-snap { background: var(--grey2); border-radius: 12px; padding: 14px 16px; display: flex; align-items: center; gap: 12px; }
.km-bom-snap-ic { width: 36px; height: 36px; border-radius: 10px; background: var(--white); color: var(--g-dark); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.km-bom-snap-ic svg { width: 18px; height: 18px; }
.km-bom-snap-text { flex: 1; min-width: 0; }
.km-bom-snap-title { font-size: 13.5px; font-weight: 600; color: var(--grey12); }
.km-bom-snap-sub { font-size: 12px; color: var(--grey11); margin-top: 2px; }
.km-bom-snap-pill { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 100px; background: var(--white); color: var(--grey11); letter-spacing: 0.02em; flex-shrink: 0; }

3.23 Auth screens (splash / onboarding / welcome) — verbatim CSS

Section titled “3.23 Auth screens (splash / onboarding / welcome) — verbatim CSS”
/* Splash */
#s-splash { background: var(--brand-dark); align-items: center; justify-content: center; cursor: pointer; }
.splash-logo { display: flex; align-items: center; justify-content: center; flex: 1; }
.splash-logo svg { width: 96px; height: 96px; }
#s-splash .home-ind { background: rgba(255,255,255,0.5); }
/* Onboarding — vertical (portrait) layout: brand mark at top, hero
illustration card centered, title + tag below, CTA at the bottom. */
#s-onboarding { background: var(--brand-dark); padding: 0; }
.ob-col { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 32px 48px 56px; gap: 28px; }
.ob-brand { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.ob-brand-mark { width: 36px; height: 36px; }
.ob-brand-name { font-size: 22px; font-weight: 700; color: var(--white); letter-spacing: -0.5px; }
.ob-hero { flex: 1; display: flex; align-items: center; justify-content: center; width: 100%; min-height: 0; }
.ob-hero-card {
width: 100%; max-width: 440px; aspect-ratio: 1; border-radius: 32px;
background: linear-gradient(160deg, #06311B 0%, #013F1F 60%, #021F11 100%);
box-shadow: 0 30px 80px rgba(0,0,0,0.4);
position: relative; overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
.ob-hero-card::before {
content: ''; position: absolute; top: -40px; right: -40px;
width: 260px; height: 260px;
background: radial-gradient(circle at center, rgba(1,228,111,0.16), rgba(1,228,111,0));
}
.ob-hero-mark svg { width: 200px; height: 200px; position: relative; z-index: 2; }
.ob-hero-caption {
position: absolute; bottom: 24px; left: 24px; right: 24px;
font-size: 12.5px; font-weight: 500; color: rgba(255,255,255,0.55); letter-spacing: 0.04em;
text-transform: uppercase; text-align: center;
}
.ob-text { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.ob-title { font-size: 36px; font-weight: 700; color: var(--white); line-height: 44px; letter-spacing: -0.6px; max-width: 560px; }
.ob-title .accent { color: var(--brand); }
.ob-tag { font-size: 15px; font-weight: 400; color: rgba(255,255,255,0.7); line-height: 24px; max-width: 520px; }
.ob-cta-row { width: 100%; max-width: 360px; display: flex; flex-direction: column; flex-shrink: 0; }
.ob-cta-row .btn-primary--lg { width: 100%; }
/* Welcome / Login — vertical (portrait) stack:
Top = brand-dark section with logo + headline + tag.
Bottom = white sheet (rounded top corners) with login form. */
#s-welcome { background: var(--brand-dark); padding: 0; flex-direction: column; }
.welcome-left {
flex-shrink: 0;
min-height: 560px;
padding: 80px 56px 64px;
display: flex; flex-direction: column; align-items: center; gap: 18px;
color: var(--white);
position: relative; overflow: hidden;
text-align: center;
}
.welcome-left::before {
content: ''; position: absolute; top: -160px; left: 50%; transform: translateX(-50%);
width: 520px; height: 520px;
background: radial-gradient(circle at center, rgba(1,228,111,0.18), rgba(1,228,111,0));
pointer-events: none;
}
.welcome-left-mark { display: flex; align-items: center; gap: 12px; position: relative; z-index: 1; }
.welcome-left-mark svg { width: 36px; height: 36px; }
.welcome-left-mark span { font-size: 22px; font-weight: 700; color: var(--white); letter-spacing: -0.5px; }
.welcome-left-headline { font-size: 32px; font-weight: 700; color: var(--white); line-height: 40px; letter-spacing: -0.6px; max-width: 560px; margin-top: 8px; position: relative; z-index: 1; }
.welcome-left-headline .accent { color: var(--brand); }
.welcome-left-tag { font-size: 14px; color: rgba(255,255,255,0.7); line-height: 22px; max-width: 520px; position: relative; z-index: 1; }
.welcome-left-foot { display: none; }
.welcome-right {
width: 100%; flex: 1; min-height: 0;
background: var(--white);
border-radius: 28px 28px 0 0;
padding: 40px 56px 56px;
display: flex; flex-direction: column; align-items: center;
box-shadow: 0 -8px 28px rgba(0,0,0,0.16);
}
.welcome-right-head { width: 100%; max-width: 440px; margin-bottom: 28px; text-align: center; }
.welcome-right-eyebrow { font-size: 12.5px; font-weight: 600; color: var(--g-dark); letter-spacing: 0.06em; text-transform: uppercase; margin-bottom: 10px; }
.welcome-title { font-size: 28px; font-weight: 700; color: var(--grey12); letter-spacing: -0.5px; line-height: 34px; margin-bottom: 6px; }
.welcome-sub { font-size: 14px; font-weight: 400; color: var(--grey11); line-height: 22px; }
/* Constrain form to a centered column inside the wider .welcome-right. */
.welcome-right .field-group { width: 100%; max-width: 440px; }
.welcome-right .welcome-cta-wrap { width: 100%; max-width: 440px; margin-top: auto; }
…
.welcome-cta-wrap { margin-top: auto; padding-top: 24px; display: flex; flex-direction: column; gap: 16px; align-items: center; }

The brand mark is the exact two-tone Rechaj SVG (paths M39.6964 8.4H33.2341… + M17.597 48.0272h6.4623…); on dark surfaces the tone order flips (white primary + green secondary vs green primary + white secondary on splash). Never redrawn.


Screens (in DOM order): s-splash, s-onboarding, s-welcome, s-dashboard, s-work-orders, s-work-order-detail, s-assembly-detail, s-bom, s-handoff, s-profile. Sheets: sheet-new-wo, sheet-push-request, sheet-qa-photos, sheet-evidence.

  1. Splash — brand-dark, centered 96px mark, light home-ind. Tap anywhere OR 2.5s auto-advance → Onboarding.
  2. Onboarding — dark sb → brand row → square gradient hero card w/ 200px mark + uppercase caption → 36px/700 display title with green .accent word → tag → single btn-primary--lg “Get started” → Welcome.
  3. Welcome/Login — dark top block (mark, 32px/700 headline w/ accent, tag, radial green glow) + white bottom sheet (radius 28 top) containing uppercase green eyebrow (persona name), 28px/700 “Welcome back”, sub, Email field (pre-filled), Password field w/ eye toggle, right-aligned “Forgot password?” link, CTA pinned to bottom via margin-top:auto. Sign in disabled until both fields non-empty (onWelcomeInput), then → Dashboard.

Top-to-bottom inside .km-scroll: dark .sb → .rsm-hero (avatar EM, name, role pill, meta line, circular search) → .km-kpi-strip (6 KPI tiles, 3-col, -64px overlap) → .rsm-body.rsm-body--split (also rsm-body on the same element with padding-top 24):

  • LEFT (1.2fr): .rsm-section-head “Today’s work orders” + “View all” link → column of 4 .km-wo-card (gap 12, wrapped in inline-styled div)
  • RIGHT (1fr): three .km-side-cards stacked (inline-styled section, gap 16): Handoff queue (tinted .km-handoff-summary, “Open queue” link → s-handoff), Parked alerts (amber .km-alert-row → opens the parked WO), Recent activity (4 .km-activity-row) Pinned: .rsm-nav (Home active) + .home-ind. Interactions: WO card click → openWoDetail(id); section links goTo(...).

.sb (light) → .rsm-page-head w/ .km-page-head-row (left title “Work orders”, right circular search) → .rsm-body: .km-tabs (6 filter tabs w/ counts: Open / In progress [default active] / Awaiting QA / Ready / Parked / Completed) → six sibling .km-wo-list[data-wo-pane] panes (only the active one visible, rest hidden). Pinned: .km-fab “New work order” (right 24, bottom 120) → opens sheet-new-wo; nav (Work orders active). Interactions: tab click → setWoTab(this) (aria-pressed swap, pane hidden swap, scroll-to-top); row click → openWoDetail(id).

4.4 Detail page (s-work-order-detail) — single template hydrated per WO

Section titled “4.4 Detail page (s-work-order-detail) — single template hydrated per WO”

.sb → .rsm-page-head w/ .rsm-page-head-row (back → s-work-orders, centered WO id title, right ⋯ action → toast stub) → .rsm-body:

  1. .km-wo-hero-card full-width (mark, id, sub, status pill, progress bar w/ tone flips, 3-cell meta grid whose labels flip by status)
  2. nested .rsm-body--split: LEFT .km-panel “BOM components” (.km-bom-list hydrated from BOM_TEMPLATES[kitType]), RIGHT .km-panel “Assembly records” (.km-asm-list — one .km-asm-row per kit: Kit N of M, pill, sub, G1/G2/G3 gate dots, chevron). Detail views live on their own screens (never modal/inline). Every WO row anywhere routes through openWoDetail(woId) so the detail always matches the clicked row’s data. Nav keeps “Work orders” active.

4.5 Drill-in detail (s-assembly-detail) — kit audit trail

Section titled “4.5 Drill-in detail (s-assembly-detail) — kit audit trail”

.sb → page-head (back → dynamic kitDetailReturnScreen, title “Kit N of M”, right print action — visible only for completed kits, toasts “Label sent to printer”) → #kit-detail-body fully rendered by renderKitDetail():

  • hero card (mark = N/M, kit-id or “Pending kit-id”, status pill, 3 status-dependent meta cells)
  • status-dependent split: completed/awaiting-qa/in-progress → 2-col: LEFT Component serials panel (G1 pass chip or “x of y scanned”) + SOP steps panel (done steps are tappable → openSopEvidence(i)); RIGHT Production QA panel (photo tiles → openQaPhotos(gate); awaiting = blue queued rows w/ Pending pills) + Activity timeline. open → single centered “Not started” empty panel. parked → single amber halt banner panel. A legacy static copy of this body is kept in the DOM under style="display:none;" for diffing.

.sb → page-head (“BOM library” + search) → .rsm-body: .km-bom-library-summary (3 stats) → two stacked .km-bom-panels (Standard, KaaG). Each panel: head (52px mark, “Standard kit · BOM v4” + “Active since … · BOM ID …”, Active pill w/ data-state=“in-progress”) → 4-col meta row (border-top divider) → .km-bom-grid 2-col component rows (KaaG’s Inverter row tinted green + inline “KaaG add” chip) → .km-bom-specs 3 tappable spec tiles (Tooling refs / Acceptance specs / Revision history → openBomSpecSheet toast stub).

.sb → page-head (“Handoff queue” + search) → .rsm-body: .km-handoff-summary-card (Ready 12 / In transit 4 / Accepted today 22) → .km-tabs (Ready [default] / In transit / Accepted) → panes: Ready = selectable .km-kit-rows (toggleKitSelect); In transit = .km-push-tracker card (PUSH id, “Awaiting scan-in” pill, scan-in progress, per-kit status line); Accepted = kit rows with pre-checked green selects (inline styles) + grey Accepted pills, clicking opens kit detail via openKitById. Pinned .km-selection-bar appears when selection > 0 → “Build push request” opens sheet-push-request (recipient seeded to the linked Inventory Manager, removable kit list, notes) → submitPushRequest() hides pushed rows, toasts N kits sent to Inventory · PUSH-2407-0045, auto-switches to the In-transit tab after 300ms. Tab switching away from Ready clears selection.

.sb → page-head (“Profile” + settings gear) → .rsm-body: .rsm-profile-user card → grouped sections each = .rsm-profile-section-title (uppercase) + .rsm-profile-section card of .rsm-profile-rows: Workspace (3 rows w/ subs), Account (3 rows), Preferences (2 toggle rows + Language), Support (Help, About, danger Sign out → s-welcome).

  • Row click = navigate to a dedicated screen (openWoDetail / openKitDetail / openKitById), never expand-inline, never modal.
  • Forms & confirmations = bottom sheets with stacked primary-over-secondary CTAs; backdrop tap cancels.
  • Default selections: Work Orders opens on “In progress”; Handoff opens on “Ready”; dashboard is the post-login landing.
  • Search lives in the page head as a circular icon button (stub — no inline search field pattern).
  • Confirmed actions toast via top-center .alert-toast (success w/ badge, e.g. “WO issued”), and where relevant the app auto-switches to the tab where the result now lives.
  • Unbuilt destinations toast info (“Coming soon” / “Opening”) — never a dead click.
  • Deep-linking: ?screen=s-… query param jumps straight to a screen on load.
  • Tab switches reset the pane scroll: .km-scroll.scrollTo({ top: 0, behavior: 'instant' }); goTo resets .rsm-body.scrollTop.

Navigation & shell:

  • const SCREENS = ['s-splash','s-onboarding','s-welcome','s-dashboard','s-work-orders','s-work-order-detail','s-assembly-detail','s-bom','s-handoff','s-profile']
  • goTo(id) — validates against SCREENS, swaps .screen.active, resets .rsm-body scrollTop.
  • IIFE init() — ?screen= deep-link; else splash auto-advance after 2500ms; calls onWelcomeInput().
  • Fit IIFE — scales .tablet to viewport (834/1194).

Auth:

  • onWelcomeInput() — enables/disables #welcome-login-btn (+.is-disabled class).
  • togglePw(inputId, btn) — flips input type password/text.
  • attemptLogin() — guards disabled, goTo('s-dashboard').

Data:

  • const WO_DATA = { 'WO-K-2407-0188': { id, kitType: 'standard'|'kaag', bomVersion, target, closed, inQa, open, assemblers, issuedAt, dueLabel, status, statusLabel, progressLabel, assemblyRecords: [{ kitNum, kitId|null, status, statusLabel, sub, gates: ['pass'|'fail'|'active-g*'|'pending-g*'] ×3 }] }, … } (10 WOs).
  • const BOM_TEMPLATES = { standard: { meta, items: [[name, sub, qty]…] }, kaag: {…} }
  • let currentWoId; let currentKitContext = { woId, kitNum, kit, wo }; let kitDetailReturnScreen.
  • const KIT_SOP_STEPS = [[name, sub, time] ×4]; kitSerialsFor(wo); kitAssembler(kit); kitQaTech(kit).

WO detail:

  • openWoDetail(woId) — sets context, renderWoDetail(), goTo('s-work-order-detail').
  • renderWoDetail() — hydrates title/hero/pill/progress(+data-tone)/meta cells/BOM list/asm list from WO_DATA[currentWoId].
  • toggleWoHaltedDemo(btn) — stub, toasts “Action menu / Coming soon”.

Kit detail:

  • openKitDetail(woId, kitNum, returnScreen) / openKitById(kitId, returnScreen) (resolves owning WO; default returns 's-work-order-detail' / 's-handoff').
  • renderKitDetail(); renderKitSplit(kit, wo) — returns status-dependent HTML.

Tabs:

  • setWoTab(btn) — uses btn.dataset.woTab, syncs aria-pressed + [data-wo-pane].hidden, scrolls top.
  • setHandoffTab(btn) — same with data-handoff-tab/[data-handoff-pane]; clears selection when leaving Ready.

New WO sheet:

  • openNewWoSheet() / closeNewWoSheet() — toggle .is-open on #sheet-new-wo.
  • setNewWoKit(btn), adjNewWoQty(delta) (clamped 1–99), cycleNewWoDate(), submitNewWo() (close → success toast → setWoTab(in-progress) after 300ms).
  • State: newWoState {kit, qty, date}, NEW_WO_DATES[], BOM_BY_KIT{}.

Handoff / selection:

  • toggleKitSelect(row), clearKitSelection(), refreshKitSelectionBar() (count label + .is-visible).
  • openPushRequestSheet() / closePushRequestSheet() — hydrates #push-kit-list from [aria-pressed="true"] rows using data-kit-id/data-kit-wo.
  • removePushKit(kitId); submitPushRequest() (hide rows → toast … · PUSH-2407-0045 → jump to In-transit tab).

Sheets/viewers:

  • openQaPhotos(gate) / closeQaPhotos() / cycleQaPhoto(delta) / renderQaPhoto(); data QA_PHOTOS = { g2: { title, sub, gateLabel, by, photos: [{label, time}] }, g3: {…} }, state qaPhotoState = { gate, idx }.
  • openEvidence(opts) — opts = { title, sub, result, resultState, photos, note, noteDefect }; closeEvidence(); openSopEvidence(idx).
  • openBomSpecSheet(kit, kind) — kind ∈ ‘tooling’|‘acceptance’|‘history’; toast stub.

Toast: showToast(msg, badge, variant = 'success') / hideToast() (see 3.11).


Class prefixes:

  • km- — Kit-production Manager-specific components (the bulk of this flow).
  • rsm- — shared retrofit-shell vocabulary reused 1:1 (rsm-nav, rsm-page-head, rsm-body, rsm-hero, rsm-sheet-*, rsm-profile-*, rsm-section-*, rsm-toggle).
  • ka- — Kit Assembler evidence components reused (ka-evi-*).
  • sb/sb-* — status bar; ob-* — onboarding; welcome-*/splash-* — auth; home-ind; alert-toast*; btn-primary/btn-secondary; field-*/input/text-link.
  • State conventions: .is-active, .is-open, .is-visible, .is-disabled, .is-error; aria-pressed for toggles/tabs/selection; data-state for pill/dot colors; data-tone for tints (blue/amber/red/grey/neutral); data-*-tab / data-*-pane pairs + hidden for panes; modifier suffix --kaag, --lg, --danger, --dark, --light, --tappable, --defect.
  • Screen ids: s-<kebab>; sheet ids: sheet-<kebab>; hydration ids: wo-*, kit-*, qa-photo-*, new-wo-*, push-*, evidence-*.

Personas: Production Manager = Erioluwa Morenikeji (avatar “EM”, erioluwa.morenikeji@rechaj.com, Tricycle Hardware). Linked Inventory Manager = Olufunke Adesina (“OA”, Receiving bay). Assemblers: Adewale John, Muiz, Yusuf. Production QA: Adaeze Nwosu.

ID formats:

  • Work order: WO-K-2407-0188 (WO-K-YYMM?-serial)
  • Kit id: kit-K-88301-WS-0011 (standard -WS-) / kit-K-88412-KG-0007 (KaaG -KG-); lowercase kit- prefix
  • Push request: PUSH-2407-0044
  • Purchase order: PO-118
  • BOM: BOM-STD-2026-04, BOM-KAA-2026-02; versions “BOM v4”, “BOM v2 KaaG”
  • Component serials: MTR-A4-22914-7K9, MCU-V3-88102-031, RBN-88301-WH-014, etc.
  • Gates: G1 (serial scan) / G2 (visual) / G3 (electrical pre-check); kit types STD / KaaG
  • Copy separator is the middot · throughout (no em dashes in UI copy — one violation noted in §7)

Where 700 appears (complete list):

Sanctioned (display numbers / display titles / iOS clock):

  • .sb-time 15px/700 (iOS clock — allowed)
  • .ob-brand-name, .ob-title 36px, .welcome-left-mark span, .welcome-left-headline 32px, .welcome-title 28px (onboarding/welcome display titles — allowed)
  • .km-kpi-num 28px, .km-handoff-count 22px, .km-handoff-summary-val 24px, .km-wo-hero-progress-val 17px, .km-qty-stepper-val 18px (KPI/display digits — allowed)

Questionable / violations within the file (700 on non-display, tiny text):

  • .rsm-nav-badge — 10.5px/700 badge count
  • .km-gate-dot — 9px/700 G1/G2/G3 letters
  • .km-qa-photo-count — 10px/700 photo count
  • JS-rendered SOP step number fallback font-weight:600 at 10px (fine), but the check svg uses stroke-width 3 (visual weight, acceptable)
  • No 800 anywhere. Everything else (names, WO ids, titles, buttons, pills, section titles) is 600; labels/meta 500; body 400.

Type scale observed: 9 / 10 / 10.5 / 11 / 11.5 / 12 / 12.5 / 13 / 13.5 / 14 / 14.5 / 15 / 16 / 17 / 18 / 20 / 22 / 24 / 28 / 32 / 36. Half-point sizes (11.5/12.5/13.5/14.5) are canonical for meta/sub text. Numbers always get font-variant-numeric: tabular-nums. Letter-spacing: global -0.01em; small semibold rows -0.05em; larger titles px-based (-0.2 to -0.6px); uppercase micro-labels +0.04em/0.06em; pills +0.02em. Uppercase appears ONLY on micro-labels (.km-wo-hero-meta-label, .km-handoff-summary-label, .km-photo-meta-label, .rsm-profile-section-title, .welcome-right-eyebrow, .ob-hero-caption) — never on badges/pills.

Spacing rhythm: even-number rhythm, mostly 4px-grid: gaps 2/4/6/8/10/12/14/16/18/28; body padding 24 h / 18 gap; card padding 18 or 22×24; row padding 10×12 / 12×14 / 14×16; sheet padding 0 32; hero padding 0 32 80. Note the file uses 10/14/18/22 freely (even but off the strict 4-multiple grid — 14 and 18 are the two dominant “in-between” values, and they are consistent, so treat 14/18 as canonical for this shell rather than snapping to 16/20). No 7/11/15px values anywhere. Radii ladder: 6 (mini chips) / 8 / 9 / 10 (buttons, inputs, sub-rows) / 12 (tinted blocks, marks) / 14 (rows, hero mark) / 16 (panels, cards) / 18 (hero cards, KPI, summary) / 24 (sheet top) / 28 (device, welcome sheet) / 32 (ob hero card) / 100px or 999px (pills/bars).

Other violations / quirks noticed in the file itself (do NOT propagate):

  1. Header comment says “landscape 1194×834” and onboarding/welcome comments say “landscape 2-col”/“split-panel ~58%/42%” but the built shell and layouts are portrait — stale comments.
  2. .alert-toast-close styled nowhere (JS injects it unstyled).
  3. Inline styles used for: dashboard column wrappers (style="display:flex;flex-direction:column;gap:12px;margin-top:8px"), accepted-pane pre-checked selects (style="background:var(--g-primary);box-shadow:none;"), BOM library “9 May” val downsizing (style="font-size:18px;line-height:22px;"), KaaG-add row tint, kit-detail JS templates — a real componentization would promote these.
  4. Em dash used in JS-rendered copy 'Halted — wiring harness short' (renderKitSplit parked panel) — violates the no-em-dash rule; the static markup consistently uses ·.
  5. .km-tabs is hard-coded repeat(6, 1fr) — the Handoff screen’s 3 tabs rely on the same class (3 buttons in 6 tracks would break; visually it works because grid auto-places 3 items in the first 3 columns of 6, leaving the right half of the track empty — check in build; if reusing with ≠6 tabs, override the column count).
  6. .km-wo-pill[data-state="in-progress"] has no explicit rule — it falls through to the default green; the JS relies on this.
  7. .rsm-nav-badge, .km-wo-empty, .km-placeholder, .rsm-section-meta, .km-wo-pill[data-state="defect"], .ka-evi-result[data-state="fail"], .ka-evi-note--defect, .home-ind--light (outside auth), .km-kit-select disabled variants exist in CSS but are unused in markup — reserved vocabulary.
  8. .km-bom-panel-meta-row declares padding-top: 2px then overrides it with the shorthand padding: 14px 0 4px — the shorthand wins.