← Cosmo · Hub
Sett · Cosmo

Design System

Components and patterns for the Cosmo pipeline orchestration tool. Built for power users: dense, warm, purposeful. Brand identity and token foundations are in the reference pages below.

Archive →
Reference
Components · 01

Buttons

Primary action element. Three styles (primary / secondary / subtle) for different visual emphasis levels.

Primary
Secondary
Subtle
Small (24px — pair these with .fbtn--sm)
Success (green fill — Approve primary)
Subtle + icon-only (toolbar)
ClassPurpose
.fbtnBase, combine with a type and optionally a layout
.fbtn--primaryAccent fill, white text (Figma Primary)
.fbtn--secondaryTransparent fill, line border, ink text (Figma Secondary)
.fbtn--subtlebg-panel fill, ink text (Figma Subtle)
.fbtn--successGreen-500 fill, white text — Approve / positive completion actions
.fbtn--icon-onlySquare 32x32, no horizontal padding
.fbtn--sm24px height variant for history events and inline toolbars
.fbtn-chevTrailing 12x12 chevron icon for dropdown buttons
State: hoverPseudo-class, automatic
State: disableddisabled attribute or .is-disabled
HTML
<button class="fbtn fbtn--primary">
  <i data-lucide="play"></i>Preview
</button>

<!-- Icon-only -->
<button class="fbtn fbtn--primary fbtn--icon-only">
  <i data-lucide="play"></i>
</button>

<!-- With dropdown chevron -->
<button class="fbtn fbtn--secondary">
  <i data-lucide="play"></i>Preview
  <i data-lucide="chevron-down" class="fbtn-chev"></i>
</button>
Figma node: 661:16938 Source: Figma Cosmo V2
DimensionValues
Type--primary / --secondary / --subtle / --success
Stateregular / hover / disabled
Layouticon-only / icon+text / icon+text+chevron / text-only
Sizedefault 32px / --sm 24px
Components · 02

Toggle

Two-state segmented switch for binary or short-list choices. Sits on a sunken pill; the selected tab lifts to panel-fill.

Adaptive (click to switch — hover to preview hover state)
Stretched (full-width, interactive)
All four states side-by-side (Regular / Hover / Selected / Disabled)
ClassPurpose
.ftoggleContainer pill (bg-sunken), holds .ftoggle-tab children
.ftoggle--stretchedModifier, tabs share width via flex:1
.ftoggle-tabIndividual tab, 28px high, 8px radius, 12px medium text
.ftoggle-tab.is-selectedActive tab, bg-panel fill
.ftoggle-tab[disabled]Disabled tab, cream-400 text
State: hoverPseudo-class on non-selected, non-disabled tabs, bg-line fill
HTML
<!-- Adaptive -->
<div class="ftoggle">
  <button class="ftoggle-tab is-selected">
    <i data-lucide="history"></i>History
  </button>
  <button class="ftoggle-tab">
    <i data-lucide="messages-square"></i>Feedback
  </button>
</div>

<!-- Stretched -->
<div class="ftoggle ftoggle--stretched">
  <button class="ftoggle-tab is-selected">History</button>
  <button class="ftoggle-tab">Feedback</button>
</div>
Figma node: 670:18003 Source: Figma Cosmo V2
ModifierEffect
ftoggle (default)Adaptive — each tab sizes to its content
ftoggle--stretchedStretched — tabs share available width equally via flex:1
Components · 03

Data grid

Dense tabular layout for lists with consistent row structure. Header and rows share CSS subgrid columns so cells align across all rows.

Interactive: hover a row + click to select. Cells use ellipsis at 220px max.
Name
Age
Tier
Partner
SLA
Status
Coin Rain
15 Days
VIP
SuperPlay
14 Days ago
Ready to send
Lucky Strike
9 Days
T1
Scopely
2 Days ago
Building
Treasure Hunt
4 Days
T2
Moon Active
Tomorrow
PG
City Builder
2 Days
FDE
Playtika
3 Days
Approved
Overflow: many columns — grid floors at max-content and container scrolls horizontally.
Name
Age
Built
Tier
PG owner
Auditor
Partner
Cosmo
Apollo
Coin Rain
15 Days
2 Days
VIP
Anna L.
Marija T.
SuperPlay
#2600
APL-1000
Lucky Strike
9 Days
3 Days
T1
Tamir Z.
Tal H.
Scopely
#2601
APL-1001
Behaviors (consumer-wired, not styled here):
  • Column reorder via drag. Add draggable="true" to .fgrid-th. Add .is-fixed on the identity column to opt out. While dragging, peers get .drop-target-left or .drop-target-right depending on the cursor side, painting an inset border.
  • Column visibility menu. Open .fgrid-col-menu from a toolbar control. Render a checkbox per column in your registry; toggling re-renders the grid with the new column array.
  • Row selection. Add .is-selected to the row. Clicking again toggles off (your handler decides). Hover state lifts to --bg-panel; selected to --accent-wash.
  • 5-row max per group. Consumer-side: slice the data to 5 before rendering. No inner scroll on the lane — the page or outer container scrolls if multiple groups exceed viewport.
  • Row separators. Drawn as border-top on each row (header excluded), so the last row in a lane has no trailing line.
ClassPurpose
.fgridContainer CSS Grid. Set grid-template-columns inline; one slot per active column. Recommended floor + fill: minmax(max-content, 1fr). Container has min-width: max-content so it grows past parent for horizontal scroll when natural sum exceeds container.
.fgrid-head / .fgrid-rowSubgrid wrappers inheriting parent's column tracks via grid-template-columns: subgrid; grid-column: 1 / -1. Background + row separator live on the row, not per cell.
.fgrid-row:hoverRow hover, bg-panel fill across all cells.
.fgrid-row.is-selectedSelected row, accent-wash fill (matches active nav item).
.fgrid-thHeader cell. Add draggable="true" for column reorder. Add .is-fixed to opt out (identity column).
.fgrid-th.draggingDrag-source state (set by handler, opacity 0.4).
.fgrid-th.drop-target-left / -rightDrop-target affordance painted as an inset accent border on the dragged-over peer.
.fgrid-cellData cell. Single-line ellipsis at max-width: 220px.
.fgrid-cell--nameIdentity cell modifier. Opts out of ellipsis; hosts avatar + multi-line text + trailing action cluster.
.fgrid-col-menuColumn-control popover (toggle visibility from registry).
.fgrid-col-menu-itemOne checkbox row inside the menu.
HTML
<div class="fgrid" style="grid-template-columns: 220px minmax(max-content,1fr) minmax(max-content,1fr);">
  <div class="fgrid-head">
    <div class="fgrid-th is-fixed" data-col="name">Name</div>
    <div class="fgrid-th" draggable="true" data-col="tier">Tier</div>
    <div class="fgrid-th" draggable="true" data-col="status">Status</div>
  </div>
  <div class="fgrid-row">
    <div class="fgrid-cell fgrid-cell--name">Coin Rain</div>
    <div class="fgrid-cell"><span class="ftag ftag--tier-vip">VIP</span></div>
    <div class="fgrid-cell"><span class="fstatus fstatus--approved">Approved</span></div>
  </div>
</div>
Components · 04

Navigation rail

Vertical navigation rail with expanded and collapsed states. Expanded at 224px with labels; collapsed at 68px icon-only with a two-phase animate.

Expanded (224px)
Collapsed (68px)
ClassPurpose
.fnavRail container. 224px expanded, flex column, bg-panel. Add .fnav--collapsed to switch to 68px icon-only mode.
.fnav--collapsedModifier on .fnav. Narrows to 68px; collapses labels, section headers (OBSERVE), and the separator becomes visible.
.fnav-brand83px header row for the logo mark. Houses .fnav-logo-link, .fnav-logo-full, and .fnav-logo-icon (icon-only shown when collapsed).
.fnav-mainFlex column that holds all .fnav-section blocks. Grows to fill vertical space.
.fnav-sectionA named section group (e.g. Work, Observe). Use .fnav-section--work and .fnav-section--observe modifier classes for collapse-specific rules.
.fnav-separator1px horizontal rule between WORK and OBSERVE. Hidden expanded; visible collapsed.
.fnav-section-headerRow with the section label and (for WORK only) the collapse toggle button.
.fnav-section-labelSection name text. Slides and fades out when collapsed.
.fnav-rail-toggle24x24 icon button. Shown in WORK section header only. Triggers expand/collapse. Swap icon between panel-left-close and panel-left-open.
.fnav-itemNav link or button. 40px tall, 8px radius, icon + label. Works as <a>, <button>, or <div>.
.fnav-item--activeActive state. accent/18% bg via color-mix, accent text.
.fnav-item-labelText label inside a nav item. Slides and fades out when collapsed.
.fnav-footerBottom-anchored flex column (padding 25px vertical). Holds theme toggle, settings link, and user card.
.fnav-user-cardAvatar + user info row at the bottom of the footer.
.fnav-avatar32x32 circle, accent-soft bg, accent text, initials string.
.fnav-user-infoColumn holding .fnav-user-name (12.5px/600) and .fnav-user-title (10.5px/muted). Fades/collapses when rail is collapsed.
.fnav-no-animAnti-flicker guard. Add to body or .fnav before first paint (from localStorage sync); remove after two rAF ticks to restore transitions.
body.fnav-pre-collapseTwo-phase collapse step 1: labels fade out (140ms). JS then removes this and adds .fnav--collapsed.
body.fnav-expandingTwo-phase expand step 1: layout opens; labels held invisible. JS removes after ~220ms to trigger fade-in.
HTML
<nav class="fnav">
  <div class="fnav-brand">
    <a class="fnav-logo-link" href="/" aria-label="Home">Cosmo</a>
  </div>
  <div class="fnav-main">
    <div class="fnav-section fnav-section--work">
      <div class="fnav-section-header">
        <span class="fnav-section-label">Work</span>
        <button class="fnav-rail-toggle" aria-label="Collapse navigation">
          <i data-lucide="panel-left-close"></i>
        </button>
      </div>
      <a class="fnav-item fnav-item--active" href="/weekly">
        <i data-lucide="calendar-range"></i>
        <span class="fnav-item-label">Weekly</span>
      </a>
    </div>
  </div>
  <div class="fnav-footer">
    <div class="fnav-user-card">
      <div class="fnav-avatar">IR</div>
      <div class="fnav-user-info">
        <span class="fnav-user-name">Ishai Revach</span>
        <span class="fnav-user-title">Product design</span>
      </div>
    </div>
  </div>
</nav>

<!-- Collapsed state -->
<nav class="fnav fnav--collapsed">...</nav>
Source: cosmo-lab/lab-shell.html Source: screens/components/nav-panel.css
Components · 05

Status

Lifecycle status of a playable. Closed enum — each status has a dedicated modifier so callers cannot mix mismatched colors.

Not Started In Progress TL TL PG PG Approved Ready to send Building apollo: in_progress Build Failed Quota Backlog
ClassPurpose
.fstatusBase, combine with status modifier
.fstatus--not-startedgrey
.fstatus--in-progressblue
.fstatus--in-progress-softamber — Apollo orchestration in_progress state
.fstatus--pending-tlpurple, paired with hourglass icon
.fstatus--polish-tlpurple, paired with brush-cleaning icon
.fstatus--pending-pgindigo, paired with hourglass icon
.fstatus--polish-pgindigo, paired with brush-cleaning icon
.fstatus--approvedgreen
.fstatus--ready-to-sendgreen (alias of approved palette)
.fstatus--buildingamber
.fstatus--build-failedred
.fstatus--quota-backloggrey (alias of not-started)
HTML
<span class="fstatus fstatus--approved">Approved</span>

<!-- With icon (pending states) -->
<span class="fstatus fstatus--pending-tl">
  <i data-lucide="hourglass"></i>TL
</span>
Figma node: 555:202 Source: Figma Cosmo V2
ModifierColorIcon
--not-startedgreynone
--in-progressbluenone
--pending-tlpurplehourglass
--polish-tlpurplebrush-cleaning
--pending-pgindigohourglass
--polish-pgindigobrush-cleaning
--approvedgreennone
--ready-to-sendgreennone
--buildingambernone
--in-progress-softambernone (Apollo only)
--build-failedrednone
--quota-backloggreynone
Components · 06

Tag

Compact pill for tags, badges, and categorical labels. Three shape families: symbol square, text pill, and two-segment revision label.

Symbol tags (square)
V Tag
Tier
VIP FDE T1 T2 T3
Effort
Easy Medium Hard
Revision (two-segment: label + age)
R33h R33d R33w
Square modifier (uniform 20x20 — row leading tags)
V R1 R2 R3
ClassPurpose
.ftagBase, combine with a named modifier
.ftag--symbolSquare 20x20 shape modifier (icon-only or single letter)
.ftag--squareUniform 20x20 square regardless of variant — for row leading tags (V / R1 / R2 / R3)
.ftag--versionSymbol — green, single "V" or check
.ftag--rolled-overSymbol — orange, corner-down-right icon
.ftag--high-prioritySymbol — indigo, crown icon
.ftag--client-requestSymbol — purple, megaphone icon
.ftag--generalText tag, sunken bg, muted text
.ftag--tier-t1 / -t2 / -t3Tier square 20x20
.ftag--tier-vip / -fdeTier pill (text)
.ftag--effort-easy / -medium / -hardEffort pill, icon + label
.ftag--revision .ftag--revision-(regular|warning1|warning2)Two-segment: .ftag-rev-label + .ftag-rev-age
HTML
<!-- Text pill -->
<span class="ftag ftag--tier-vip">VIP</span>

<!-- Effort pill with icon -->
<span class="ftag ftag--effort-easy">
  <i data-lucide="leaf"></i>Easy
</span>

<!-- Revision two-segment -->
<span class="ftag ftag--revision ftag--revision-regular">
  <span class="ftag-rev-label">R3</span>
  <span class="ftag-rev-age">3h</span>
</span>
Figma node: 662:17527 Source: Figma Cosmo V2
FamilyVariants
Symbol square--version / --rolled-over / --high-priority / --client-request
Text pill--general / --tier-vip / --tier-fde / --tier-t1/t2/t3 / --effort-easy/medium/hard
Two-segment revision--revision-regular / --revision-warning1 / --revision-warning2
Shape override--square — forces 20x20 uniform square for row-leading tags
Components · 07

Inputs

All form controls share the same border token and focus ring. Text inputs, selects, checkboxes, radio buttons, and switches — one consistent system for every user interaction that collects a value.

Text input

Name or email
Invalid playable ID format

Select & checkboxes

Checkbox

Native <input type="checkbox"> styled with accent-color: var(--accent). Always paired with a label via .checkbox-row.

Radio

Native <input type="radio"> styled with accent-color: var(--accent). Group via shared name attribute.

Checkbox

Bordered checkbox with accent fill on checked state. Use as a <button role="checkbox"> with .checkbox--on modifier.

off
on
Include revisions
High priority only

Check

Borderless checkmark toggle. No background or border in either state. The checkmark appears in accent on checked. Use in dense table row contexts where a bordered box would be visually noisy.

off
on

Switch

40x24 pill toggle. Track transitions cream-200 to accent. Knob is 18x18, cream-50, transitions from left:3 to left:19. Use .switch--on modifier.

off
on
Notifications
Sound effects
ClassDescription
.fieldFlex-column wrapper for label + input + hint
.field-label / .field-hintAbove-field label (550 weight) and optional clarifying hint
.inputText input — bg-raised, accent focus ring
.input.input-errorError state — red border and focus shadow
.selectDropdown — same sizing as .input, custom chevron via background-image
.checkbox-rowFlex-row wrapper for checkbox / radio / switch + label
button.checkbox16x16 bordered checkbox. Off: transparent + cream border. On: add .checkbox--on (accent fill, embed check SVG).
.checkbox--onChecked state modifier. Accent background + cream-50 icon color. Embed check SVG as child.
.check16x16 borderless checkmark toggle. No border or fill in either state. On: add .check--on (accent icon color).
.check--onChecked state modifier. Sets color to accent so the inline SVG resolves via currentColor.
.switch40x24 pill toggle. Off: cream-200 track. On: add .switch--on (accent track). Always contains <span class="switch-knob">.
.switch--onChecked state modifier. Track turns accent, knob slides from left:3 to left:19.
.switch-knob18x18 circle knob inside .switch. Positioned absolute, transitions on left.

Text input

HTML
<div class="field">
  <label class="field-label">Search</label>
  <input class="input" type="text" placeholder="Search playables…">
</div>

<!-- Error state -->
<div class="field">
  <label class="field-label">Playable ID</label>
  <input class="input input-error" type="text" value="PLY-abc">
  <span style="font-size:var(--text-xs);color:var(--red-600)">Invalid format</span>
</div>

Select

HTML
<div class="field">
  <label class="field-label">Status filter</label>
  <select class="select">
    <option>All statuses</option>
    <option>On track</option>
    <option>At risk</option>
  </select>
</div>

Checkbox

HTML
<!-- Native checkbox (accent-color styled) -->
<label class="checkbox-row">
  <input type="checkbox" class="checkbox" checked>
  <span class="checkbox-label">Include revisions</span>
</label>

<!-- Button checkbox (Figma-spec bordered variant) -->
<button class="checkbox checkbox--on" type="button" role="checkbox" aria-checked="true">
  <svg width="10.5" height="8" viewBox="0 0 10.5 8" fill="none" aria-hidden="true">
    <path d="M9.5 1L3.5 7L1 4.5" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round"/>
  </svg>
</button>
Figma node: 843:66792

Radio

HTML
<label class="checkbox-row">
  <input type="radio" name="filter" class="checkbox" checked>
  All playables
</label>
<label class="checkbox-row">
  <input type="radio" name="filter" class="checkbox">
  Only ready to send
</label>

Switch

HTML
<!-- Off -->
<button class="switch" type="button" role="switch" aria-checked="false">
  <span class="switch-knob"></span>
</button>

<!-- On -->
<button class="switch switch--on" type="button" role="switch" aria-checked="true">
  <span class="switch-knob"></span>
</button>
Figma node: 843:66792
Components · 08

Icons

Icons come from Lucide, a MIT-licensed stroke icon library embedded locally. Use <i data-lucide="icon-name"></i> — Lucide replaces the element with an inline SVG at runtime.

Navigation icons

layout-dashboard Dashboard
calendar-days Weekly
send Delivery
chevron-left Collapse toggle
chevron-right Expand toggle

Usage

14×14 nav icon with 1.8 stroke
16×16 inline icon with 1.5 stroke
UsageDescription
<i data-lucide="icon-name"></i>Replaced at runtime by lucide.createIcons(). Add CSS width/height and stroke properties to size and color.
.nav-icon14×14 with stroke-width 1.8. Inherits opacity from parent nav-item state.
npm run update-iconsRun from data/ to pull latest Lucide and copy the UMD bundle to lib/lucide.min.js.
HTML
<!-- Standard usage -->
<i data-lucide="calendar-days" style="width:20px;height:20px;stroke:var(--ink-soft);stroke-width:1.8"></i>

<!-- Nav icon (14x14, 1.8 stroke) -->
<i data-lucide="send" class="nav-icon"></i>
Source: design-system/lib/lucide.min.js
Patterns · 01

Data visualization

One home for every quantitative surface: KPI tiles for headline metrics, the distribution bar for live pipeline filtering, load bars for auditor capacity, and Recharts for trend, proportion, and gauge views. All use Cosmo tokens.

KPI tile — states

Three meaningful states: positive delta, negative delta (uses .kpi-delta.down), and zero-value (uses .kpi-delta.flat). The .accent modifier tints the value to orange for primary-metric emphasis.

Populated · up delta
Delivered this week
38 / wk
↑ +6 vs last week
Populated · down delta
Revision rate
12 %
↑ +3pp this week
Zero value
Delivered this week
0
— no data yet

Compact variant (.kpi.sm)

Tighter padding, smaller font, smaller min-width. Used in dense sub-header strips (Pulse, Delivery) where full KPI tiles would dominate.

In-flight
84
Stalled
6
↑ +2
Build failed
3
— same
Delivered
38
↑ +6

Status distribution bar (.sdb)

Horizontal pipeline bar — each segment is one stage_status, width proportional to count. Click a segment to filter (others dim); click again or the × clear button to reset. Labels collapse to icon-only when there isn't room. Canonical JS pattern lives in screens/prototypes/air.html.

Pipeline

Load bars — auditor capacity (.load-bar-wrap)

Compact, named bars for "auditor X is at Y/N capacity". Severity-colored fill: .low (green) / .high (amber, ≥75%) / .over (red, ≥100%). Use these for compact summary surfaces; for the in-lane capacity row inside .kanban-lane use .cap-bar instead (Patterns · 05 · Kanban lane).

Tatiana Iudina
6 / 11
Daria Yakusheva
9 / 11
Amir Cohen
13 / 11

Charts — Recharts

All charts use Recharts (React) styled with Cosmo tokens — green = on-track, amber = at-risk, red = behind, accent = highlight. No default Recharts tooltip/legend styling; everything is overridden in the React mount script at the bottom of this file. For HTML prototypes outside React, use the same approach via the Recharts UMD build.

Delivery Trend · Weekly
Status by Game
Status Distribution
Team Capacity
Auditor Workload
Class / ElementDescription
KPI tiles
.kpi / .kpi.smKPI tile — flex column with label, value, delta. .sm is the compact variant.
.kpi.accentTints .kpi-value to the accent color for primary-metric emphasis.
.kpi-label / .kpi-value / .kpi-deltaMono uppercase label / display numeral / mono trend indicator.
.kpi-delta.down / .flatRed (down) or muted (flat) delta. Default is green.
Status distribution bar
.sdbBar container — flex row, 22px height, radius-full, overflow hidden.
.sdb-header / .sdb-label / .sdb-filter-hint / .sdb-clear-btnHeader row above the bar — label left, filter hint + clear button right.
.sdb-segSegment. Width inline as %, background inline from STATUS_CFG.
.sdb-seg.is-active / .is-dimmed / .is-wide / .is-lightFilter active / others dimmed / wide enough to show label / dark-bg variant (cream text).
.sdb-seg-icon / .sdb-seg-label10×10 Lucide wrapper / mono label hidden until .is-wide.
.sdb-tooltipBody-attached fixed tooltip, JS-positioned. Add .is-visible to show.
.dist-bar / .dist-segLegacy aliases — same visual output. Prefer .sdb / .sdb-seg.
Load bars
.load-bar-wrap / .load-bar-track / .load-bar-fillCompact severity-colored capacity bar. .low (green) / .high (amber, ≥75%) / .over (red, ≥100%).
.load-countMono "X / N" count next to the bar.
Charts
Delivery TrendAreaChart + Area (fill gradient) + Line (target dashed) + axes + Tooltip + CartesianGrid
Status by GameBarChart + Bar × 3 (stacked) + axes + Tooltip + Legend
Status DonutPieChart + Pie (innerRadius 60, outerRadius 90) + Cell per segment + Legend
Team CapacityPieChart + Pie (semicircle, startAngle=180, endAngle=0) + center label via foreignObject
Auditor WorkloadBarChart (layout=vertical) + Bar × 2 (active + remaining) + axes + Tooltip
Color palettegreen-500 (on-track), amber-600 (at-risk), red-500 (behind), orange-500 (accent / delivered), ink-300 (grid), ink-400 (axis text)

KPI tile

HTML
<div class="kpi accent">
  <div class="kpi-label">Delivered this week</div>
  <div class="kpi-value">38 <span class="unit">/ wk</span></div>
  <div class="kpi-delta">↑ +6 vs last week</div>
</div>
<!-- States: .kpi-delta.down (red), .kpi-delta.flat (muted) -->
<!-- Compact: add .sm modifier to .kpi -->

Status distribution bar

HTML
<div class="sdb-header">
  <span class="sdb-label">Pipeline</span>
  <span class="sdb-filter-hint">
    <span id="hint-text"></span>
    <button class="sdb-clear-btn">× clear</button>
  </span>
</div>
<div class="sdb" id="sdb-bar">
  <!-- Segments injected by JS. Each: -->
  <!-- <button class="sdb-seg" style="width:15%;background:var(--green-500)"
    data-tip="Build Complete">...</button> -->
</div>

Load bar

HTML
<div class="load-bar-wrap">
  <div class="load-bar-track">
    <div class="load-bar-fill high" style="width:82%"></div>
  </div>
  <div class="load-count">9 / 11</div>
</div>
<!-- Severity modifiers: .low (green), .high (amber ≥75%), .over (red ≥100%) -->

Charts (Recharts UMD)

HTML
<!-- Mount target -->
<div id="chart-delivery" style="height:220px;"></div>

<!-- React/Recharts mount (see bottom of index.html for full script) -->
<!-- Colors: green-500, amber-600, red-500, orange-500 — all via DS tokens -->
Patterns · 08

Kanban lane

Vertical column for an auditor or status bucket. Header holds the avatar, name, and an optional two-row layout for capacity. The scrollable body holds playable cards and activates a drop-zone highlight during drag.

Lanes — default & active drop-zone

TI
Tatiana I. 3
V Cascade PLY-017
Bubble Cash
R Tilt Shot PLY-018
Pool Payday
V Power Rush PLY-006
Solitaire Cash
DY
Daria Y. 1
V Wide Shot PLY-024
Spine Road

Two-row head — name + role badge + capacity bar

Used by weekly v2 to make room for a capacity bar below the avatar/name row. .kl-head-row1 is the avatar + name + days chip. .kl-head-name-group wraps the name and an adjacent role badge (e.g. "TL") so they stay together with predictable ellipsis. .kl-cap-row is the capacity bar row.

TI
Tatiana I. TL
5d
3/5

Capacity controls — day chip + popover

The .kl-days-chip in the lane header opens a .kl-days-pop popover with a stepper and a vacation toggle. The popover is position:fixed so it can escape the lane's overflow:hidden; the consumer positions it via getBoundingClientRect. Below the chip is the popover open inline so its contents are visible in this docs page.

Chip — default 5d
Chip — on vacation Vac
Popover (open · default)
5d
Vacation
Popover (vacation on)
Vacation

On-vacation lane state

Add .on-vacation to .kanban-lane to fade the body, hatch it diagonally, hide the capacity row, and surface the amber .kl-vac-banner between the head and the body.

DY
Daria Y.
Vac
0/0
On vacation
V Wide Shot PLY-024
Spine Road

Team divider — between adjacent lanes

Insert .kl-team-divider between two lanes when they belong to different teams (e.g. multi-TL view). 1px ink line, full lane height, small horizontal margins.

TI
Tatiana I.
DY
Daria Y.
SK
Sergei K.
VM
Vera M.
ClassState / VariantDescription
.kanban-lanedefaultVertical column shell — min-width 280px, panel surface, rounded corners, vertical flex
.kanban-lane.on-vacationstateFades body, applies hatched stripe overlay, hides cap row, exposes .kl-vac-banner
.kl-headstructureLane header — padded, bottom border. Flex-direction can be overridden for two-row layouts
.kl-head-row1structureFirst row of a two-row head — avatar + name-group + days chip
.kl-head-nameelementAuditor name — UI font, 600, ellipsis
.kl-head-name-groupelementWraps name + role badge so they stay together with predictable ellipsis
.kl-head-count DEPRECATEDNumeric pill for card count. Replaced by .priority-slot. Kept for back-compat only.
.kl-cap-rowelementCapacity bar + readout row inside the lane head
.kl-bodystructureScrollable container for cards — gap 8px, padding 12px
.kl-body.drop-zonestateActive drag-drop target — accent-wash background and inset accent ring
.kl-team-dividerelement1px vertical line inserted between lanes from different teams
.kl-vac-bannerelementAmber strip shown between head and body when lane .on-vacation
.kl-days-chipdefaultMono pill showing weekly day capacity — click to open .kl-days-pop
.kl-days-chip.on-vacationstateAmber "Vac" variant when the lane is on vacation
.kl-days-pop / .opendefault / stateDay-capacity popover. Add .open to display
.kl-days-stepper-btn / :disabledelement / state24×24 ± button. Disabled at boundaries (0d / 7d) and during vacation
.kl-days-switch / .ondefault / state26×14 pill toggle. .on applies accent color
HTML
<!-- Default lane -->
<div class="kanban-lane">
  <div class="kl-head">
    <div class="avatar">TI</div>
    <span class="kl-head-name">Tatiana I.</span>
  </div>
  <div class="kl-body">
    <div class="ply-card">...</div>
  </div>
</div>

<!-- On-vacation state -->
<div class="kanban-lane on-vacation">
  <div class="kl-head">...</div>
  <div class="kl-vac-banner"><i data-lucide="palmtree"></i> On vacation</div>
  <div class="kl-body">...</div>
</div>

<!-- Two-row head with capacity bar -->
<div class="kl-head">
  <div class="kl-head-row1">
    <div class="avatar">TI</div>
    <div class="kl-head-name-group">
      <span class="kl-head-name">Tatiana I.</span>
    </div>
    <div class="kl-days-wrap"><span class="kl-days-chip">5d</span></div>
  </div>
  <div class="kl-cap-row">
    <div class="cap-bar"><div class="cap-bar-track"><div class="cap-bar-fill" style="width:60%"></div></div></div>
    <span class="cap-bar-nums">3/5</span>
  </div>
</div>
VariantModifier
Default.kanban-lane
On vacation.kanban-lane.on-vacation + .kl-vac-banner
Two-row head.kl-head-row1 + .kl-cap-row inside .kl-head
Patterns · 13

Drag-and-drop states

Three utility classes applied via JS during the drag lifecycle: the card being dragged, the hovered drop target, and a passive container that signals it can receive the active drag.

Source — .dragging

Applied to the card being dragged — half opacity, grabbing cursor.

V Cascade PLY-017
Bubble Cash

Hovered target — .drop-target

Applied to the element the dragged card is currently over.

R Tilt Shot PLY-018
Pool Payday

Active container — .drop-zone-active

Applied to a wider container (e.g. an empty area of a kanban lane body) so the user can see where a drop is allowed.

DY
Daria Y. 0
ClassDescription
.draggingApply to source card during drag — opacity 0.5, cursor: grabbing.
.drop-targetApply to hovered target — accent border, accent-wash background. Uses !important to win over any baseline border colors.
.drop-zone-activeApply to a container that can receive the active drag — dashed accent outline, accent-wash fill.
HTML
<!-- Source card being dragged -->
<div class="ply-card dragging">...</div>

<!-- Hovered drop target -->
<div class="ply-card drop-target">...</div>

<!-- Container that can receive the drag -->
<div class="kl-body drop-zone-active">...</div>
VariantClass
Dragging (source).dragging
Drop target (hovered).drop-target
Drop zone (active container).drop-zone-active
Patterns · 15

Popover menu

Generic dropdown framework for any tethered overflow menu. Items support an optional check icon for toggle or radio choices, and an optional right-aligned mono meta value for counts or keyboard shortcuts.

Toggle list with check marks

Show

Action list

ClassDescription
.popover-anchorWrapper around the trigger — gives the absolutely-positioned menu a relative parent
.popover-menuMenu panel — bg-raised, line-strong border, radius-md, shadow-sm, z-index 200, padded space-1. Default position: top 100%, right 0
.popover-section-headUppercase mono 10px section label — ink-muted
.popover-itemFlex row item — space-2 / space-3 padding, hover bg-sunken, radius-sm. Combine with .active for selected state
.popover-item-check14px check icon slot — accent color, opacity 0 by default, opacity 1 inside .popover-item.active
.popover-item-labelFlex-1 label text
.popover-item-metaOptional right-aligned mono 10px meta (count, kbd shortcut, etc.) — ink-muted
.popover-divider1px line separator between item groups
HTML
<!-- Toggle list (check marks) -->
<div class="popover-anchor">
  <button class="btn btn-secondary btn-sm" aria-expanded="true">Filter</button>
  <div class="popover-menu">
    <div class="popover-section-head">Show</div>
    <button class="popover-item active">
      <span class="popover-item-check"><i data-lucide="check"></i></span>
      <span class="popover-item-label">Pending TL</span>
      <span class="popover-item-meta">12</span>
    </button>
    <div class="popover-divider"></div>
    <button class="popover-item">
      <span class="popover-item-label">Reset filters</span>
    </button>
  </div>
</div>

<!-- Action list -->
<div class="popover-anchor">
  <button class="kebab-trigger"><i data-lucide="more-vertical"></i></button>
  <div class="popover-menu">
    <button class="popover-item"><span class="popover-item-label">Edit</span></button>
    <button class="popover-item"><span class="popover-item-label">Duplicate</span></button>
    <div class="popover-divider"></div>
    <button class="popover-item"><span class="popover-item-label">Archive</span></button>
  </div>
</div>
VariantPattern
Toggle listItems with .popover-item-check + .active modifier
Action listItems with label only, no check slot
Patterns · 16

Team picker

Workspace-scope selector used in the Weekly app topbar to switch between auditor teams. Small bordered trigger with a users icon, current label, and a chevron that rotates 180° on open. Pairs with .popover-menu.

Closed and open

Switch team
ClassDescription
.team-pickerWrapper — relative positioning for the menu
.team-picker-triggerBordered button — 6px / 10px padding, line border, hover sunken. Drive open state with aria-expanded="true"
.team-picker-icon14px leading icon — ink-muted, stroke-width 1.8
.team-picker-chevron12px trailing chevron — rotates 180° when [aria-expanded="true"]
.team-picker .popover-menuMenu inside the picker — widened to 220px so team names don't truncate
HTML
<div class="team-picker">
  <button class="team-picker-trigger" aria-expanded="false">
    <i data-lucide="users" class="team-picker-icon"></i>
    <span>Tatiana I.'s team</span>
    <i data-lucide="chevron-down" class="team-picker-chevron"></i>
  </button>
  <!-- Add .popover-menu here when open (aria-expanded="true") -->
</div>
Patterns · 17

Kebab menu

Three-dot overflow trigger for row-level and card-level actions. 28px hit area so it fits inside dense card headers without dominating them. Pairs with .popover-menu. For full-size 32px topbar chrome buttons, use .icon-btn instead.

Trigger states

In a card header

Quota backlog
ClassDescription
.kebab-trigger28×28 transparent icon button — ink-muted glyph, sunken bg on hover or [aria-expanded="true"]
.kebab-trigger + .popover-menuWrap both in a .popover-anchor and toggle the menu's display via aria/JS state
HTML
<div class="popover-anchor">
  <button class="kebab-trigger" aria-expanded="false">
    <i data-lucide="more-vertical"></i>
  </button>
  <div class="popover-menu">
    <button class="popover-item">
      <span class="popover-item-label">Edit auditor</span>
    </button>
    <div class="popover-divider"></div>
    <button class="popover-item">
      <span class="popover-item-label">Archive</span>
    </button>
  </div>
</div>
Patterns · 18

Context menu

Position-fixed variant of the popover menu for right-click and on-card context actions. Heavier shadow because it floats over arbitrary content. Toggle visibility with .open; top and left coords are set inline at JS-runtime.

Open over a card

ClassDescription
.context-menuPosition-fixed menu panel — bg-raised, line-strong border, radius-md, shadow-lg, z-index 200. Hidden by default
.context-menu.openToggles display:block
.context-menu-itemFlex row item — space-2 / space-3 padding, hover bg-sunken, radius-sm. Includes 13px leading icon slot
.context-menu-item.dangerRed-600 text + icon for destructive actions
.popover-divider1px line separator (shared with .popover-menu)
HTML
<!-- Rendered in body, positioned by JS -->
<div class="context-menu open" style="position:fixed;top:120px;left:240px;">
  <button class="context-menu-item">
    <i data-lucide="edit-3"></i>
    <span>Edit playable</span>
  </button>
  <button class="context-menu-item">
    <i data-lucide="copy"></i>
    <span>Duplicate</span>
  </button>
  <div class="popover-divider"></div>
  <button class="context-menu-item danger">
    <i data-lucide="trash-2"></i>
    <span>Delete</span>
  </button>
</div>
Patterns · 20

Priority slot

Wrapper that prepends a CSS counter number to a card. The number sits in an 18px left gutter; the card itself stays untouched. Used to show ranked priority order in lanes, where top position equals priority 1.

Numbered lane body

Set counter-reset: priority-rank; on the parent — here, an inline style on the wrapper.

V Coin Rain PLY-014
Bubble Cash
R Tilt Shot PLY-018
Pool Payday
V Cascade PLY-017
Solitaire Cash

Drop indicator

A 2px accent line shown between two cards to signal the exact insertion slot during drag-and-drop. Render as a sibling element inside the drop container.

V Coin Rain
Bubble Cash
R Tilt Shot
Pool Payday
ClassDescription
parent: counter-resetSet counter-reset: priority-rank; on the parent list (e.g. the .kl-body inside a kanban-lane)
.priority-slotWrapper — counter-increment + 22px left padding. The card sits inside, untouched
.priority-slot::beforeThe number itself — mono 10px, ink-muted, in an 18px-wide centered gutter on the left
.drop-indicator2px accent line rendered as a sibling element inside the drop container while a drag is hovering
HTML
<div style="counter-reset: priority-rank;">
  <div class="priority-slot">
    <div class="ply-card">...</div>
  </div>
  <div class="priority-slot">
    <div class="ply-card">...</div>
  </div>
  <!-- Drop indicator between slots: -->
  <div class="drop-indicator"></div>
  <div class="priority-slot">
    <div class="ply-card">...</div>
  </div>
</div>
Patterns · 21

Scrollbar — thin

Utility class that swaps the chunky default scrollbar for a minimal 4px track and thumb matching DS surface tokens. Apply to any scrollable container. Webkit-only; Firefox falls back to its native thin styling.

Thin scrollbar in a panel

Resize-friendly preview with overflowing content so the scrollbar is visible.

VCoin Rain
Bubble Cash
RTilt Shot
Pool Payday
VCascade
Solitaire Cash
VPower Rush
Solitaire Cash
RFree Spin
Bubble Cash
VBooster
Pool Payday
ClassDescription
.scrollbar-thinApply to a scrollable container — 4px webkit scrollbar with a transparent track and a line-strong thumb (ink-300 on hover)
HTML
<div class="scrollbar-thin" style="height:200px;overflow-y:auto;">
  <!-- scrollable content -->
</div>
Patterns · 22

Floating panel

Elevated side-panel shell at 280px fixed width. The canonical use is the Quota Backlog panel in the Weekly dispatch screen. Add .hidden to animate the panel to zero width with no content jump.

Default (with generic content skeleton)

280px wide, shadow-md. Consumers add any header + scrollable body inside — the panel enforces only the outer shell.

Panel title
VCoin Rain
Bubble Cash
RTilt Shot
Pool Payday
VFree Spin
Bubble Cash

States

Default
.floating-panel
.hidden (width → 0)
ClassState / VariantDescription
.floating-paneldefault280px flex column — bg-panel surface, 1px line border, 14px radius, shadow-md. Width fixed; add overflow:hidden on the element.
.floating-panel.hiddenstateCollapses to width:0 / min-width:0 — animate with transition on width. Content hidden by overflow:hidden.
.qb-panelaliasIdentical to .floating-panel. Kept live for weekly.html back-compat. New code uses .floating-panel.
.qb-panel.hiddenalias stateSame collapse behavior as .floating-panel.hidden.
HTML
<!-- Default -->
<div class="floating-panel">
  <div style="padding:var(--space-4);border-bottom:1px solid var(--line);
    display:flex;align-items:center;justify-content:space-between;">
    <span style="font-family:var(--font-display);font-weight:700;">Panel title</span>
    <button class="icon-btn"><i data-lucide="x"></i></button>
  </div>
  <div class="scrollbar-thin" style="flex:1;overflow-y:auto;padding:var(--space-4);">
    <!-- scrollable body -->
  </div>
</div>

<!-- Collapsed -->
<div class="floating-panel hidden"></div>
VariantModifier
Default (visible).floating-panel
Hidden (collapsed to 0).floating-panel.hidden
Patterns · 25

Data table

Generic table chrome for Settings-style data tables. Covers person cell, avatar, role tags, status toggle, kebab menu, subsection grouping, orphan row, inline-editable input, and allocations matrix wrapper.

Basic table with person cell, role tags, switch, kebab

User Role Active Capacity
AK
Avi Katz avi@sett.ai
TL 8
NR
Noa Reiner noa@sett.ai
PG 6
MS
Maya Schwartz maya@sett.ai
Auditor 4

Subsection grouping (.dt-row--group)

UserRoleCap
Studio A
AK
Avi Katz
TL 8
Studio B
NR
Noa Reiner
PG 6

Orphan row (.dt-row--orphan)

UserRoleCap
AK
Avi Katz
TL 8
??
UnassignedNo studio
-- 3

Inline-editable input (.dt-input-cell)

UserW16W17W18
AK
Avi Katz
NR
Noa Reiner

Empty state (.dt-empty)

UserRole
No users in this section.
ClassElement / StateDescription
.dt-tableblockFull-width table with border, radius, bg-raised background.
.dt-table thead thelementMono 10px uppercase header, bg-panel, border-bottom.
.dt-table tbody trelementRow with border-bottom; hover state switches to bg-sunken.
.dt-cell--center / --right / --nummodifierCenters / right-aligns / mono-centered cell. Use --num for numeric columns.
.dt-personelementFlex row: avatar + .dt-person-info. min-width 180px.
.dt-avatarelement24x24 round mono-initials chip.
.dt-name / .dt-subelementfont-ui 13px 500 primary label / mono 10px muted sub-label.
.dt-tagelementPill badge base (neutral). Role tags use canonical .tag family: TL = .tag.tag--orange, PG = .tag.tag--blue, Auditor = .tag.tag--green.
.dt-tag--tl / --pg / --auditordeprecatedRemoved from showcase 2026-05-10. Use .tag.tag--orange / .tag.tag--blue / .tag.tag--green.
.switch / .switch--onblock40x24 pill toggle. See Inputs section (Components · 07).
.dt-toggle / .dt-toggle-track / .dt-toggle-thumbdeprecatedKept for existing screens. Use .switch for new work.
.dt-kebab-btn / .dt-kebab-menu / .openelement / stateTable-inline kebab. Absolute menu; add .open to show.
.dt-kebab-item / .dangerelementFull-width button row in menu. .danger sets red color.
.dt-row--group / .dt-group-labelmodifierGroup header row with bg-panel + mono uppercase label.
.dt-row--orphanmodifierRow with red left border bar (inset box-shadow on first td).
.dt-emptyelementCentered muted placeholder cell spanning full colspan.
.dt-input-cellelement52px mono number input. Transparent border default; line on hover, accent on focus.
.dt-matrixmodifierOuter frame for 2D allocation grids. Pairs with .alc-matrix-wrap.
HTML
<table class="dt-table">
  <thead>
    <tr><th>User</th><th>Role</th><th class="dt-cell--center">Active</th><th></th></tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <div class="dt-person">
          <div class="dt-avatar">AK</div>
          <div class="dt-person-info">
            <span class="dt-name">Avi Katz</span>
            <span class="dt-sub">avi@sett.ai</span>
          </div>
        </div>
      </td>
      <td><span class="tag tag--orange">TL</span></td>
      <td class="dt-cell--center">
        <button class="switch switch--on" role="switch" aria-checked="true">
          <span class="switch-knob"></span>
        </button>
      </td>
      <td style="width:32px;">
        <div style="position:relative;">
          <button class="dt-kebab-btn"><i data-lucide="more-vertical"></i></button>
          <div class="dt-kebab-menu">
            <button class="dt-kebab-item"><i data-lucide="edit-2"></i> Edit</button>
            <button class="dt-kebab-item danger"><i data-lucide="trash-2"></i> Remove</button>
          </div>
        </div>
      </td>
    </tr>
  </tbody>
</table>
Source: screens/explorations/settings-v1.html
VariantModifier
Person cell.dt-person + .dt-avatar + .dt-person-info
Subsection group.dt-row--group + .dt-group-label
Orphan row.dt-row--orphan
Empty state.dt-empty on a colspan td
Patterns · Component

Applied Filters Chip

Topbar chip that surfaces active filter state. Shows a count badge, opens a removable-items dropdown, and exposes a clear-all button. Mounts via mountAppliedFiltersChip(containerSel, options). Hides automatically when count reaches zero.

0 filters (hidden)
1 filter
3 filters
Class / functionRole
mountAppliedFiltersChip(sel, opts)Factory. Renders chip into container, mounts dropdown via mountMenu. Returns { update, destroy }.
opts.getCount()Called on every update(). Returns total active filter count; chip hides when 0.
opts.getRemovables()Returns [{section, label, onRemove}] flat list. Component groups by section for the dropdown.
opts.onClearAll()Fired when the X button is clicked.
.applied-filters-chipOuter wrapper. Orange-tinted bg, 32px height, radius 8.
.applied-filters-chip-revertLeft button. Hosts lucide x icon. Calls onClearAll.
.applied-filters-chip-bodyRight button. Dropdown trigger wired by mountMenu.
.applied-filters-chip-countOrange pill badge showing filter count.
.applied-filters-chip-label"Applied Filters" text label.
.applied-filters-chip-chevChevron icon. Rotates via .is-open on the outer wrapper.
.applied-filters-chip.is-openAdded/removed by the controller when dropdown opens/closes.