02 · Components
Built pieces, live.
Every specimen below is a working static recreation of a shiftops.ai component, rendered from tokens.css. The code under each one is the code on this page — copy it and it works anywhere the tokens are linked.
Buttons
One filled button per view.
Primary is ink on the page — it needs no color to win because nothing competes. Secondary is bordered, ghost is bare. The arrow nudges 2px on hover; that's the whole animation.
<a class="btn btn-primary" href="#">Request a demo <span class="arrow">→</span></a>
<a class="btn btn-secondary" href="#">Explore the platform</a>
<a class="btn btn-ghost" href="#">See gap analysis <span class="arrow">→</span></a>
/* css */
.btn { display:inline-flex; align-items:center; gap:6px;
border-radius:var(--radius-full); padding:10px 20px;
font-size:14px; font-weight:500; transition:all var(--dur-fast) ease; }
.btn-primary { background:var(--accent); color:var(--accent-fg); }
.btn-primary:hover { background:var(--accent-hover); }
.btn-secondary { background:var(--bg-elev); color:var(--fg);
border:1px solid var(--line-strong); }
.btn-ghost { background:transparent; color:var(--fg-secondary); }
.btn:hover .arrow { transform:translateX(2px); }
Pills & capability chips
Small facts wear small frames.
Pills carry sans-serif metadata; chips carry mono capabilities with a status dot. The AI chip is the one place violet enters the chrome — it marks a capability an agent performs.
<span class="pill">Workforce orchestration</span>
<span class="chip"><span class="chip-dot"></span>location-verified check-in</span>
<!-- violet only because an agent does the work -->
<span class="chip chip-ai"><span class="chip-dot"></span>confirmation sweep · agent calls</span>
/* css */
.chip { display:inline-flex; align-items:center; gap:7px;
border-radius:var(--radius-full); border:1px solid var(--line);
background:var(--bg-elev); padding:5px 13px;
font-family:var(--font-mono); font-size:11px; color:var(--fg-secondary); }
.chip .chip-dot { height:6px; width:6px; border-radius:9999px; background:var(--fg-subtle); }
.chip-ai { border-color:var(--ai-line); background:var(--ai-soft); }
.chip-ai .chip-dot { background:var(--ai); }
Status pills
Three colors, three facts.
ok / warn / danger appear only for real operational states. A pulsing dot means the number is live, not cached.
<span class="status-pill status-ok"><span class="dot"></span>Gate A · 24/24</span>
<span class="status-pill status-warn"><span class="dot"></span>Club Level · 18/20</span>
<span class="status-pill status-danger"><span class="dot"></span>Suites · 10/12</span>
<!-- pulse = live data -->
<span class="status-pill status-ok"><span class="dot animate-pulse-dot"></span>LIVE</span>
/* css */
.status-pill { display:inline-flex; align-items:center; gap:6px;
border-radius:var(--radius-full); padding:2px 9px;
font-size:10px; font-weight:500; }
.status-ok { background:var(--ok-soft); color:var(--ok); }
.status-warn { background:var(--warn-soft); color:var(--warn); }
.status-danger { background:var(--danger-soft); color:var(--danger); }
.animate-pulse-dot { animation:pulse-dot var(--dur-pulse) ease-in-out infinite; }
Cards
A border, a radius, a fact.
Three card species: the bordered default, the sunken stat card for numbers, and the update card whose only color is an 8px editorial-gradient bar on top.
The cascade
True gaps go to every partner at once
Open shifts become structured orders across agencies and marketplaces — tracked from placed to filled.
Live Gap Analysis in the Deploy command center
<!-- default card -->
<div class="card">…</div>
<!-- sunken stat card -->
<div class="stat-card">
<div class="stat-n">96%</div>
<div class="stat-l">fill rate</div>
<div class="stat-s">shifts covered before day-of</div>
</div>
<!-- update card: color arrives as an 8px gradient bar, nowhere else -->
<a class="update-card" href="#">
<div class="bar" style="background:linear-gradient(135deg,#8a7bd8 0%,#c77f9e 45%,#e8944a 100%);"></div>
<div class="body">
<h4>Live Gap Analysis in the Deploy command center</h4>
<div class="meta"><span class="cat">Product</span><span class="date">Jul 8, 2026</span></div>
</div>
</a>
MockFrame
Every mockup wears the same window.
Three neutral dots, a mono label in
section · view form, and an optional LIVE
pill with a pulsing dot. The frame carries
--shadow-cmd so product screens read as
windows floating over the page.
<div class="mock">
<div class="mock-bar">
<div class="mock-dots"><span></span><span></span><span></span></div>
<span class="mock-label">deploy · live gap analysis</span>
<span class="mock-live status-pill status-ok">
<span class="dot animate-pulse-dot"></span>LIVE</span>
</div>
<div class="mock-body">
<div class="mock-row"><span>Gate A</span>
<span class="status-pill status-ok"><span class="dot"></span>24/24</span></div>
<div class="mock-row"><span>Club Level</span>
<span class="status-pill status-warn"><span class="dot"></span>18/20</span></div>
<div class="mock-row"><span>Suites</span>
<span class="status-pill status-danger"><span class="dot"></span>10/12</span></div>
</div>
</div>
/* labels are always mono, lowercase, "section · view" */
Lifecycle scrubber
One event, scrubbed end to end.
Mono time-pills switch a caption below — the pattern the marketing site uses to walk one event from brief to closeout. Selected state is the ink accent; this demo is wired, click through it.
<div class="scrub-pills" role="tablist">
<button class="scrub-pill" aria-selected="true">T-30 days</button>
<button class="scrub-pill" aria-selected="false">T-7 days</button>
…
</div>
<div class="scrub-caption">
<span class="time">T-30 days</span>
<div class="t">Build the event</div>
<div class="d">Zones, service locations, shifts & budget…</div>
</div>
/* css */
.scrub-pill { border:1px solid var(--line); background:var(--bg-elev);
border-radius:var(--radius-full); padding:6px 14px;
font-family:var(--font-mono); font-size:11px; cursor:pointer; }
.scrub-pill[aria-selected="true"] { background:var(--accent);
border-color:var(--accent); color:var(--accent-fg); }
FAQ accordion
Hairlines and a rotating plus.
Divided by 1px lines, opened one at a time, the plus
rotating 45° into a close. The reveal is a
grid-template-rows: 0fr → 1fr transition —
no measured heights, no JS animation. This one works.
Ranked shift offers go to your own people first — by certification, prior performance at the venue, and cost against budget. Only what remains becomes the gap that goes external.
Agencies, marketplaces, and regional staffing partners — one order fanned to three, four, or more at once, each commitment tracked from placed to filled.
A timestamped, location-verified clock-in at the gate and clock-out at the end of shift. Hours stop being a my-word-against-yours argument.
<div class="faq">
<div class="faq-item">
<button class="faq-q" aria-expanded="false">
<span>What counts as a verified hour?</span>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<path d="M7 1v12M1 7h12" stroke="currentColor"
stroke-width="1.4" stroke-linecap="round"/></svg>
</button>
<div class="faq-a"><div><p>A timestamped, location-verified clock-in…</p></div></div>
</div>
</div>
/* open state: .faq-item.open — grid-rows 0fr→1fr, plus rotates 45° */
.faq-a { display:grid; grid-template-rows:0fr; opacity:0;
transition:grid-template-rows var(--dur-med) var(--ease-out-expo),
opacity var(--dur-med) ease; }
.faq-item.open .faq-a { grid-template-rows:1fr; opacity:1; }
.faq-a > div { overflow:hidden; }
Photo cutout
The world, framed at 28px.
Photography never runs full-bleed. It sits in a
--radius-3xl cutout with a
bottom-up black scrim carrying a white caption. The gradient below
stands in for a photo — swap in real labor, shot dark and cinematic.
Live at championship golf, motorsport & enterprise venues
Gate A, 5:40 a.m. — load-in crew, verified in
<div class="cutout">
<img class="cutout-media" src="…" alt=""> <!-- or a .grain gradient -->
<div class="cutout-scrim">
<p>Live at championship golf, motorsport & enterprise venues</p>
<p class="sub">Gate A, 5:40 a.m. — load-in crew, verified in</p>
</div>
</div>
/* css */
.cutout { position:relative; overflow:hidden;
border-radius:var(--radius-3xl); border:1px solid var(--line);
min-height:260px; }
.cutout-media { position:absolute; inset:0; object-fit:cover; }
.cutout-scrim { position:absolute; left:0; right:0; bottom:0; padding:24px;
background:linear-gradient(to top, rgba(0,0,0,0.72), transparent); }
.cutout-scrim p { color:#fff; font-size:14px; font-weight:500; }
Mega panel
Navigation that names the work.
Dropdown panels float on --shadow-pop,
group items under eyebrows, and give each item a mono-glyph tile.
The violet tile marks the one item where an agent does the work.
<div class="mega">
<div>
<h5 class="eyebrow">Platform</h5>
<a class="mega-item" href="#">
<span class="mi-icon">SC</span>
<span><span class="mi-t">Schedule</span><br>
<span class="mi-d">Internal-first fill, ranked by skill, cost & history</span></span>
</a>
</div>
<div>
<h5 class="eyebrow">Automation</h5>
<!-- .mi-ai: violet tile, only because an agent acts -->
<a class="mega-item mi-ai" href="#">
<span class="mi-icon">AI</span>
<span><span class="mi-t">Outbound agents</span><br>
<span class="mi-d">Calls, texts & emails that confirm every worker</span></span>
</a>
</div>
</div>
Dark theme
Same tokens, lights off.
Dark is the same tokens flipped by
[data-theme="dark"] — nothing is
redesigned. The panel below is forced dark regardless of the page
toggle; every specimen inside is byte-identical to the ones above.
One rule of thumb: photography and gradients are shared across
themes; hairlines get slightly stronger in dark so edges keep
reading.
forced [data-theme="dark"] · ignores the page toggle
<!-- whole page: set the attribute on <html> and every token flips -->
<html data-theme="dark">
<!-- one region: nest the attribute; tokens re-resolve inside the wrapper -->
<div class="theme-panel" data-theme="dark">
…any component, unchanged…
</div>
/* css — the wrapper just paints its own tokens */
.theme-panel { background: var(--bg); color: var(--fg);
border: 1px solid var(--line); border-radius: var(--radius-2xl);
padding: 28px 24px; }