---
version: "1.0"
name: "Shiftline"
---

# Shiftline design

Shiftline is a local weekly scheduling workspace for small teams of 8 to 20 people. The included sample workspace has 12 fictional people in Service, Operations, and Support. Both pages identify the data as sample data. The primary action is **Add shift**.

## Pages and information

- `index.html`: Dashboard, with coverage, open shifts, scheduled people, and planned hours. A seven-day assigned/planned bar chart sits beside team availability. A compact table shows up to six planned shifts for the selected week, day, and team.
- `schedule.html`: a separate built HTML document, linked from desktop and mobile navigation. Shows each selected day's shifts with person, team, and 24-hour start/end times. Open shifts have a dashed amber border and an assignment action. Each day has Add shift.
- Both documents share a source shell in `index.html`, application logic in `src/app.js`, and the sample roster, date, validation, and summary functions in `src/model.js`. `build.mjs` emits both documents and their shared assets.

Week controls move by seven days; This week returns to the current local calendar week. Day and team filters compose. Clear resets both. The empty state explains how to find or add shifts. Saving moves the view to the shift's week/day/team so the result is visible.

## Layout, density, and spacing

Preserves the captured dashboard's proportions: 232px desktop sidebar; a header at least 66px tall; a main rail capped at 1280px with 24px side padding. Header and main use the same width and padding. Main sections are separated by 16px, summary cards by 12px. Cards have 16px padding; panels have 18px. The chart and availability panel use a 1.55fr / 0.7fr split with a 280px minimum for the latter.

Four summary cards occupy one desktop row, two columns below 900px. The bar chart is 212px tall. Table rows retain 12px vertical and 10px horizontal padding, thin top rules, and nonwrapping values. At viewport widths of 520px and below, table header and data cells use 6px horizontal padding while retaining 12px vertical padding (`th,td{padding:12px 6px}`). Long table content scrolls inside a focusable labeled table region, rather than expanding the page.

## Typography and shape

Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif. No remote font request: Inter is used only if installed. Body is 14px with 1.45 line height. Desktop page heading is 19px, section headings 15px, metrics 23px with -0.03em tracking. Supporting text is 11 to 13px. Metric and heading weight is 700 to 760.

Panels use 14px radii and a subtle `0 1px 2px rgba(0,0,0,.03)` shadow. Navigation radius is 9px, buttons 10px, fields 8px, shift cards 7px. Status badges and progress bars have pill radii. The dialog uses a 14px radius and `0 8px 24px #0003` shadow.

## Colors

| Role | Light | Dark |
| --- | --- | --- |
| Canvas | #f7f7f8 | #111318 |
| Surface | #ffffff | #191c22 |
| Soft surface | #f1f2f4 | #242831 |
| Border | #e3e4e8 | #343943 |
| Main text | #17181b | #f4f6f8 |
| Secondary text | #646872 | #a4acb9 |
| Accent / Service | #087cf0 | #55a7ff |
| Success / Operations | #16885c | #55c995 |
| Warning / open shift | #9b5a0e | #efb566 |
| Error | #c43045 | #ff7d8c |
| Support | #7859b7 | #b9a0f0 |
| Service tint | #eaf3fe | #1b2d45 |
| Operations tint | #e6f6ef | #19372c |
| Open shift tint | #fff2dd | #392e1e |
| Support tint | #f1edfa | #2b253c |

Primary buttons use white on #0872dc in both themes. Team names and status words accompany colors. The Shiftline mark is an inline SVG with three staggered white lines on #17181b. The favicon uses a matching embedded SVG; there are no external image, font, or icon dependencies.

## Responsive behavior

At 1100px and below, controls can wrap and the calendar uses four day columns. At 900px and below, the sidebar is replaced by a visible Shiftline header and two-link mobile navigation, the chart and availability stack, side padding becomes 16px, and the calendar uses three columns. At 520px and below, calendar days stack vertically with two shift cards per row, metrics become 19px, card/panel padding is 13/14px, and table text becomes 12px. The separate table Time column hides, with times shown below the day instead. The Add shift action and brand remain visible. Form width is limited to the viewport minus 32px and height to `100dvh - 32px` with internal scrolling.

These are implemented CSS behaviors. Real rendered geometry and overflow at 390px, 768px, and 1440px remain unverified because the environment blocks browser access and local server binding.

## Forms, storage, and keyboard design

The native modal dialog has associated title/description, visible field labels, required date and times, an alert for validation errors, Cancel, Close, and submission buttons. Native dialog behavior provides Escape and focus containment. Closing returns focus to its trigger, or to the main Add shift button when the trigger was replaced during rendering. Focus-visible outlines are 3px accent with a 3px offset; the page has a skip link.

Shifts must end after they start on the same day, use a valid date between 2000 and 2100, and have a person from the chosen team. Unavailable people are disabled in the person select and rejected by validation. Overlapping assignments are rejected; adjacent shifts are allowed. Open-shift assignment retains the original team, date, and time. All times use local calendar dates and a 24-hour clock; there is no timezone conversion.

The sample availability repeats by weekday and is explicitly labeled. With All days selected, availability shows Monday's date; choosing a day updates it. Coverage is assigned shifts / total planned shifts. Hours include open shifts. Empty coverage is N/A. Metrics and calendar derive from the same records.

The app stores the versioned workspace under `shiftline-workspace-v1` in localStorage. Added and assigned shifts persist across the two pages. Invalid stored data falls back to sample data with a warning. Storage write failures keep the current page usable and warn that changes will be lost. No backend, account connection, publishing, or remote synchronization exists.

## Themes

The original `src/theme-runtime.js` is preserved unchanged. Its `assets/ca-theme.js` script and `data-ca-theme-action="toggle"` / `data-ca-theme-toggle` attributes remain. The control now sits in the shared header. Initial theme follows the OS unless `ca-theme` contains a saved light/dark preference. Both values persist via the original runtime. Theme CSS uses `data-ca-theme` semantic variables rather than brittle captured DOM selectors.

Node VM tests verify light/dark toggling, saved preference after fresh runtime initialization, OS default, and blocked storage behavior. Actual browser reload, visual theme rendering, and keyboard interaction remain unverified.

## Content and metadata

Titles are Dashboard | Shiftline and Schedule | Shiftline. Description explains scheduling; robots are noindex, nofollow for this local workspace. No production URL, canonical, sitemap, structured data, contact details, legal claims, or analytics IDs were invented. No source business copy or links remain in runtime files. The initial capture is preserved byte-for-byte in `REFERENCE_DESIGN.md` with SHA-256 `00df1b79c14c9b7ff476f20b812638bb8d40897e493e6cc6197ede3d606861a0`.

The interface copy passed two Humanizer reviews: first replacing vague scheduling promises with specific tasks, then removing redundant guidance and checking action labels against their destinations. Dates and time ranges use ordinary hyphens.
