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.”
1. Tokens
Section titled “1. Tokens”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(alsovar(--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%), stagelinear-gradient(160deg, #1f1f23 0%, #0a0a0c 70%, #050505 100%) - Onboarding hero card gradient:
linear-gradient(160deg, #06311B 0%, #013F1F 60%, #021F11 100%)
2. Shell
Section titled “2. Shell”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. Atoms
Section titled “3. Atoms”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.
3.2 Topbar / header
Section titled “3.2 Topbar / header”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).
3.3 Page head
Section titled “3.3 Page head”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>3.4 Tabs & segmented controls
Section titled “3.4 Tabs & segmented controls”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; }3.6 Buttons
Section titled “3.6 Buttons”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.
3.7 Badges & status pills
Section titled “3.7 Badges & status pills”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-primarytext, 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,--grey11text..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-mark44px r12,.km-wo-hero-mark52px r14,.km-kit-row-mark44px r12,.km-push-kit-mark32px r8) — tonal rounded squares with STD/KaaG/1/8text, green by default,--kaagmodifier 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; }.
3.8 KPI / stat cards
Section titled “3.8 KPI / stat cards”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; }3.9 Cards / panels
Section titled “3.9 Cards / panels”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".
3.11 Toast
Section titled “3.11 Toast”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.
3.12 Inputs & forms
Section titled “3.12 Inputs & forms”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).
3.13 Dropdown menus
Section titled “3.13 Dropdown menus”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.
3.14 Empty states
Section titled “3.14 Empty states”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>3.15 Icon-container convention
Section titled “3.15 Icon-container convention”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>3.18 Activity timelines (two variants)
Section titled “3.18 Activity timelines (two variants)”(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>3.19 Photo evidence (viewer + thumbs)
Section titled “3.19 Photo evidence (viewer + thumbs)”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; }3.20 Profile rows (settings list)
Section titled “3.20 Profile rows (settings list)”.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.
4. Page anatomy
Section titled “4. Page anatomy”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.
4.1 Auth flow
Section titled “4.1 Auth flow”- Splash — brand-dark, centered 96px mark, light home-ind. Tap anywhere OR 2.5s auto-advance → Onboarding.
- Onboarding — dark sb → brand row → square gradient hero card w/ 200px mark + uppercase caption → 36px/700 display title with green
.accentword → tag → singlebtn-primary--lg“Get started” → Welcome. - 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.
4.2 Dashboard (s-dashboard)
Section titled “4.2 Dashboard (s-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 linksgoTo(...).
4.3 List page (s-work-orders)
Section titled “4.3 List page (s-work-orders)”.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:
.km-wo-hero-cardfull-width (mark, id, sub, status pill, progress bar w/ tone flips, 3-cell meta grid whose labels flip by status)- nested
.rsm-body--split: LEFT.km-panel“BOM components” (.km-bom-listhydrated fromBOM_TEMPLATES[kitType]), RIGHT.km-panel“Assembly records” (.km-asm-list— one.km-asm-rowper 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 throughopenWoDetail(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 understyle="display:none;"for diffing.
4.6 Library page (s-bom)
Section titled “4.6 Library page (s-bom)”.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).
4.7 Queue with multi-select (s-handoff)
Section titled “4.7 Queue with multi-select (s-handoff)”.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.
4.8 Profile (s-profile)
Section titled “4.8 Profile (s-profile)”.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).
4.9 Cross-cutting interaction rules
Section titled “4.9 Cross-cutting interaction rules”- 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' });goToresets.rsm-body.scrollTop.
5. JS contracts
Section titled “5. JS contracts”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-bodyscrollTop.- IIFE
init()—?screen=deep-link; else splash auto-advance after 2500ms; callsonWelcomeInput(). - Fit IIFE — scales
.tabletto viewport (834/1194).
Auth:
onWelcomeInput()— enables/disables#welcome-login-btn(+.is-disabledclass).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 fromWO_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)— usesbtn.dataset.woTab, syncsaria-pressed+[data-wo-pane].hidden, scrolls top.setHandoffTab(btn)— same withdata-handoff-tab/[data-handoff-pane]; clears selection when leaving Ready.
New WO sheet:
openNewWoSheet()/closeNewWoSheet()— toggle.is-openon#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-listfrom[aria-pressed="true"]rows usingdata-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(); dataQA_PHOTOS = { g2: { title, sub, gateLabel, by, photos: [{label, time}] }, g3: {…} }, stateqaPhotoState = { 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).
6. Naming
Section titled “6. Naming”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-pressedfor toggles/tabs/selection;data-statefor pill/dot colors;data-tonefor tints (blue/amber/red/grey/neutral);data-*-tab/data-*-panepairs +hiddenfor 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-); lowercasekit-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)
7. Weight & spacing discipline
Section titled “7. Weight & spacing discipline”Where 700 appears (complete list):
Sanctioned (display numbers / display titles / iOS clock):
.sb-time15px/700 (iOS clock — allowed).ob-brand-name,.ob-title36px,.welcome-left-mark span,.welcome-left-headline32px,.welcome-title28px (onboarding/welcome display titles — allowed).km-kpi-num28px,.km-handoff-count22px,.km-handoff-summary-val24px,.km-wo-hero-progress-val17px,.km-qty-stepper-val18px (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:600at 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):
- 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.
.alert-toast-closestyled nowhere (JS injects it unstyled).- 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. - 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·. .km-tabsis hard-codedrepeat(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)..km-wo-pill[data-state="in-progress"]has no explicit rule — it falls through to the default green; the JS relies on this..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-selectdisabled variants exist in CSS but are unused in markup — reserved vocabulary..km-bom-panel-meta-rowdeclarespadding-top: 2pxthen overrides it with the shorthandpadding: 14px 0 4px— the shorthand wins.