Skip to content
14 changes: 14 additions & 0 deletions docs/design-tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ Application rules:
- Use `.ops-headline-h2` and `.ops-headline-h3` for readable section and card headings.
- Do not remove mono from sigils, readiness status, telemetry, or controls.
- Prefer `.ops-mono` or `.ops-eyebrow` when a component needs explicit tactical voice.
- Use `.ops-telemetry-label`, `.ops-telemetry-value`, and `.ops-telemetry-detail` inside telemetry chips instead of one-off muted or attention text mixes.
- Telemetry attention states should use the mapped `data-tone="attention"` rail and register treatment. Do not restyle them as full warning banners.

### Tracking scale

Expand Down Expand Up @@ -175,12 +177,14 @@ Application rules:
- Reserve clipped panel notches for the app shell, first-level section cards, and key repeated controls.
- Use `ops-flat-panel` for secondary decision zones and narrative guidance inside a section.
- Use `ops-inline-alert` for non-critical banners that need tone without a full notched frame.
- Use `.ops-recovery-support-panel` for steady backup, undo, and storage guidance blocks that need cockpit structure without alert escalation.
- Use `tactical-subpanel` only when a nested control truly needs cockpit framing.
- Use `tactical-subpanel-strong` when a detail brief or selected-state summary should read one step higher than surrounding support strips.
- Use `tactical-chip-panel` for compact meta blocks, legends, and grouped facts that should feel inset rather than flat.
- Keep these utilities inside the current cockpit language. They are not a license to add decorative glow, blur, or card-rounding.
- Use tone chip panels for import, restore, recovery, and fault guidance instead of repeating inline gradient stacks.
- Use uniform calm `SignalCard` chrome for backup summary signals. Express caution with the left spine or an inline tone chip rather than recoloring the entire card amber when the state is an intended safety lock.
- Accordion status chips stay in `.ops-export-accordion-status` so badge alignment remains stable across open and collapsed recovery panels.

Frame emphasis:

Expand Down Expand Up @@ -217,6 +221,16 @@ Application rules:
- Do not recreate cockpit focus treatment with ad hoc `focus-visible:ring-*` Tailwind stacks in component markup.
- Keep `ops-focus-ring-chip` on the clipped chip surface itself. If the focusable element is a parent shell, proxy focus to the chip surface instead of inventing a new ring pattern.

History selection chrome:

- `--ops-history-selection-bg`, `--ops-history-selection-bg-strong`, and `--ops-history-selection-border` are selection-only accents for the history grid and mobile week selector.
- Use `.ops-history-selection-axis-header` on the selected desktop day header.
- Use `.ops-history-selection-axis` on cells that belong to the selected desktop day column.
- Use `.ops-history-selection-row-header` on the selected desktop sector row header.
- Use `.ops-history-selection-node` on the exact selected desktop cell or selected mobile day.
- Keep `aria-selected`, `aria-current`, and `aria-pressed` as the semantic source of truth. These classes are visual reinforcement only.
- Do not use readiness status colors for selection axes. Status colors remain reserved for the cell payload, badges, and spines.

## Notch geometry

Shared notch sizes live in `src/styles/index.css`.
Expand Down
4 changes: 2 additions & 2 deletions src/components/HeaderTelemetry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ function TelemetryChip({
].join(' ')}
>
<span className="ops-telemetry-label-row">
<span className="ops-eyebrow text-[10px] font-semibold text-ops-text-muted">
<span className="ops-telemetry-label ops-eyebrow text-[10px] font-semibold text-ops-text-muted">
{isAttention ? (
<span className="ops-telemetry-attention-pip" aria-hidden="true">
!
Expand Down Expand Up @@ -211,7 +211,7 @@ function TelemetryChip({
<TelemetryRail />
)}
{detail ? (
<span className="ops-tracking-grid text-[10px] leading-4 text-ops-text-muted uppercase">
<span className="ops-telemetry-detail ops-tracking-grid text-[10px] leading-4 text-ops-text-muted uppercase">
{detail}
</span>
) : null}
Expand Down
2 changes: 1 addition & 1 deletion src/features/export/StorageHealthSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function StorageHealthSection({
onRequestStorageProtection={onRequestStorageProtection}
isRequestingStorageProtection={isRequestingStorageProtection}
/>
<div className="ops-flat-panel p-4 text-sm leading-6 text-ops-text-secondary sm:p-5">
<div className="ops-recovery-support-panel ops-flat-panel p-4 text-sm leading-6 text-ops-text-secondary sm:p-5">
The browser automatically manages local storage. You can manually
request exemption from automatic deletion, though browsers may deny
this silently. Always rely on routine exports to secure your critical
Expand Down
2 changes: 1 addition & 1 deletion src/features/export/UndoRecoverySection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function UndoRecoverySection({
<div className="space-y-4">
<NotchedFrame
emphasis="quiet"
innerClassName="tactical-chip-panel tactical-chip-panel-neutral p-4 text-sm leading-6 sm:p-5"
innerClassName="ops-recovery-support-panel tactical-chip-panel tactical-chip-panel-neutral p-4 text-sm leading-6 sm:p-5"
>
Undo restores the pre-import snapshot for the current session only.
Reload the app and that rope is gone. Keep external backups current.
Expand Down
4 changes: 3 additions & 1 deletion src/features/export/exportPanelShared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ export function AccordionSection({
</span>
</span>
{statusChip ? (
<span className="flex shrink-0 justify-end">{statusChip}</span>
<span className="ops-export-accordion-status flex shrink-0 justify-end">
{statusChip}
</span>
) : null}
</span>
</button>
Expand Down
8 changes: 4 additions & 4 deletions src/features/history/DesktopHistoryGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export function DesktopHistoryGrid({ model }: DesktopHistoryGridProps) {
isToday
? 'ops-history-today-header bg-[var(--ops-tint-1)] text-ops-accent-muted'
: isSelectedColumn
? 'ops-history-selected-column-header bg-[var(--ops-tint-2)] text-ops-text-primary'
? 'ops-history-selected-column-header ops-history-selection-axis-header bg-[var(--ops-tint-2)] text-ops-text-primary'
: 'bg-ops-surface-1 text-ops-text-secondary',
].join(' ')}
scope="col"
Expand Down Expand Up @@ -211,7 +211,7 @@ export function DesktopHistoryGrid({ model }: DesktopHistoryGridProps) {
'ops-history-sector-row-header ops-history-sector-divider ops-tracking-table sticky left-0 z-20 border-r border-ops-border-struct bg-ops-surface-2 px-4 py-3 text-left text-xs font-semibold uppercase',
getSectorTintClassName(sector.id),
isSelectedRow && hasInteractedWithHistory
? 'ops-history-selected-row-header'
? 'ops-history-selected-row-header ops-history-selection-row-header'
: '',
isSelectedRow
? 'text-ops-accent-muted'
Expand Down Expand Up @@ -277,12 +277,12 @@ export function DesktopHistoryGrid({ model }: DesktopHistoryGridProps) {
? 'ops-history-week-boundary'
: '',
isSelected && hasInteractedWithHistory
? 'ops-history-selected-cell bg-[var(--ops-tint-3)]'
? 'ops-history-selected-cell ops-history-selection-node bg-[var(--ops-tint-3)]'
: isToday
? 'ops-history-today-cell'
: dateKey === selectedCell.dateKey &&
hasInteractedWithHistory
? 'ops-history-selected-column bg-[var(--ops-tint-1)]'
? 'ops-history-selected-column ops-history-selection-axis bg-[var(--ops-tint-1)]'
: isOddWeek
? 'ops-history-week-band'
: '',
Expand Down
10 changes: 6 additions & 4 deletions src/features/history/HistoryDetailBrief.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ export function HistoryDetailBrief({
}));

return (
<div className="grid gap-4">
<div className="ops-history-detail-brief grid gap-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="ops-eyebrow text-ops-text-muted">{title}</p>
<p className="ops-history-detail-label ops-eyebrow text-ops-text-muted">
{title}
</p>
<div className="mt-2 flex flex-wrap items-center gap-2">
{hasInteractedWithHistory ? (
<span
Expand All @@ -69,7 +71,7 @@ export function HistoryDetailBrief({
) : null}
<p className="ops-headline-h3">{selectedSector.label}</p>
</div>
<h3 className="ops-numeric ops-tracking-caption mt-4 text-2xl leading-none font-semibold text-ops-text-primary uppercase">
<h3 className="ops-history-detail-date ops-numeric ops-tracking-caption mt-4 text-2xl leading-none font-semibold text-ops-text-primary uppercase">
{selectedDateLabel}
</h3>
</div>
Expand All @@ -82,7 +84,7 @@ export function HistoryDetailBrief({
{selectedStatusSummary}
</p>

<div className="ops-flat-panel px-3 py-3">
<div className="ops-history-momentum-panel ops-flat-panel px-3 py-3">
<div className="flex flex-wrap items-center justify-between gap-2">
<p className="ops-eyebrow text-[10px] text-ops-text-muted">
Sector momentum
Expand Down
2 changes: 1 addition & 1 deletion src/features/history/MobileHistoryGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ export function MobileHistoryGrid({ model }: MobileHistoryGridProps) {
className={[
'ops-focus-ring-chip ops-mobile-day-button ops-notch-chip clip-notched min-h-14 min-w-10 border px-2 py-2.5 text-center font-semibold transition hover:border-ops-border-struct hover:bg-[var(--ops-tint-2)] hover:text-ops-text-primary',
isSelectedDay && hasInteractedWithHistory
? 'ops-mobile-day-button-selected ops-history-selected-cell text-ops-accent-muted'
? 'ops-mobile-day-button-selected ops-history-selected-cell ops-history-selection-node text-ops-accent-muted'
: 'border-ops-border-soft bg-ops-surface-2 text-ops-text-secondary',
isToday && !isSelectedDay
? 'ops-history-today-cell'
Expand Down
Loading
Loading