Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/design-tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ Application rules:
- 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 `.ops-preview-fact-card` for import preview facts so backup metadata, row counts, and impact summaries keep one inset chip rhythm.
- 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.
Expand Down Expand Up @@ -228,6 +229,7 @@ History selection chrome:
- 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.
- Mobile selected day buttons use the same selection tokens as desktop selected nodes. Do not map mobile selection to nominal readiness color.
- 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.

Expand Down Expand Up @@ -280,10 +282,16 @@ They are available for future rollouts even where core Tailwind spacing utilitie
- `--ops-chip-min-h-sm`: `36px`
- `--ops-chip-min-h`: `44px`
- `--ops-chip-min-h-lg`: `52px`
- `--ops-chip-pad-x`: `0.875rem`
- `--ops-chip-pad-y`: `0.75rem`
- `--ops-chip-pad-y-tight`: `0.625rem`
- `--ops-chip-gap`: `0.625rem`

Application rules:

- Use the shared chip height tokens through `.ops-action-button`, `.ops-action-button-sm`, `.ops-action-button-lg`, telemetry chips, radio chips, and compact controls.
- Use `.ops-chip-rhythm`, `.ops-chip-rhythm-tight`, and `.ops-chip-rhythm-large` when a clipped chip needs shared density without a bespoke padding stack.
- Radio chips, telemetry chips, preview fact cards, and recovery guidance chips should stay on the shared chip rhythm unless a fixed-format layout needs an explicit exception.
- Avoid new ad hoc `min-h-[...]` values unless the control has a fixed-format layout requirement that cannot use the shared scale.

## Action button chrome
Expand Down
4 changes: 2 additions & 2 deletions src/components/DomainCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ export function DomainCard({
}}
onKeyDown={(event) => handleRadioKeyDown(event, optionIndex)}
className={[
'ops-focus-ring-chip ops-radio-chip tactical-chip-panel ops-tracking-grid min-h-[var(--ops-chip-min-h)] border px-2 py-2 text-center text-[11px] font-semibold uppercase',
'ops-focus-ring-chip ops-radio-chip ops-chip-rhythm tactical-chip-panel ops-tracking-grid border text-center text-[11px] font-semibold uppercase',
busy ? 'cursor-wait opacity-70' : '',
isSelected
? `${content.classes} shadow-[inset_0_1px_0_rgba(255,255,255,0.08)]`
? content.classes
: 'ops-radio-chip-ghost text-ops-text-secondary hover:text-ops-text-primary',
].join(' ')}
>
Expand Down
2 changes: 1 addition & 1 deletion src/components/HeaderTelemetry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ function TelemetryChip({
<div
data-tone={tone}
className={[
'ops-telemetry-chip min-h-[var(--ops-chip-min-h-lg)] px-3.5 py-4 text-left lg:px-4',
'ops-telemetry-chip ops-chip-rhythm-large text-left',
isShimmering ? 'ops-telemetry-chip-shimmer' : '',
isAttention ? 'ops-telemetry-chip-attention' : '',
isPrimary ? 'ops-telemetry-chip-primary' : '',
Expand Down
4 changes: 2 additions & 2 deletions src/features/checkin/TodayPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function DayCompletionRollup({
isComplete ? 'ops-day-rollup-complete ops-complete-badge' : '',
].join(' ')}
>
<div className="ops-rollup-count-plate min-w-[8rem]">
<div className="ops-rollup-count-plate clip-notched ops-notch-chip min-w-[8rem]">
<p className="ops-numeric flex items-baseline gap-1.5 text-2xl leading-none font-semibold text-ops-text-primary">
<span>{markedCount}</span>
<span className="text-base text-ops-text-muted">/ {totalCount}</span>
Expand All @@ -85,7 +85,7 @@ function DayCompletionRollup({
</div>
<div className="flex flex-wrap items-center gap-3 lg:justify-end">
<div
className="ops-day-rollup-meter grid min-w-[13.5rem] grid-cols-5 gap-px bg-ops-panel-border-strong p-px"
className="ops-day-rollup-meter clip-notched ops-notch-chip grid min-w-[13.5rem] grid-cols-5 gap-[2px] p-1"
aria-label={rollupLabel}
>
{SECTORS.map((sector, index) => {
Expand Down
14 changes: 7 additions & 7 deletions src/features/export/ImportRestoreSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export function ImportRestoreSection({

{pendingImportRequiresAcknowledgment ? (
<div className="panel-shadow mt-4">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber p-3">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber p-3">
<div>
<p className="text-sm leading-6">
Review the staged file risk before merge or
Expand All @@ -316,7 +316,7 @@ export function ImportRestoreSection({
</>
) : (
<div className="panel-shadow mt-4">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-rose p-3 text-sm leading-6">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-rose p-3 text-sm leading-6">
Local data unchanged. Select a different JSON backup or
clear this preview.
</div>
Expand Down Expand Up @@ -386,7 +386,7 @@ export function ImportRestoreSection({
</fieldset>

<div className="panel-shadow mt-4">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-neutral px-3 py-3 text-sm leading-6 text-ops-text-secondary">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-neutral px-3 py-3 text-sm leading-6 text-ops-text-secondary">
{importMode === 'replace'
? 'Destructive restore path selected. '
: 'Merge path selected. '}
Expand All @@ -396,7 +396,7 @@ export function ImportRestoreSection({

{!pendingImportCanCommit ? (
<div className="panel-shadow mt-4">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber px-3 py-3 text-sm leading-6">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber px-3 py-3 text-sm leading-6">
Acknowledge the staged file risk before the write path
unlocks.
</div>
Expand All @@ -413,7 +413,7 @@ export function ImportRestoreSection({
>
<div ref={replaceActionRef}>
<div className="panel-shadow">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber p-3 text-sm leading-6">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber p-3 text-sm leading-6">
Step 1 - secure a pre-replace backup.{' '}
{replaceCheckpointStepTwoText} Step 3 - arm the
destructive path. Step 4 - execute the replace
Expand All @@ -425,7 +425,7 @@ export function ImportRestoreSection({
{replaceBackupState.phase ===
'manual-awaiting-ack' ? (
<div className="panel-shadow">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber p-3">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-amber p-3">
<div>
<p className="mb-3 text-sm leading-6">
{manualBackupInstructionText}
Expand Down Expand Up @@ -481,7 +481,7 @@ export function ImportRestoreSection({

{replaceBackupState.phase === 'ready' ? (
<div className="panel-shadow">
<div className="clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-neutral px-3 py-3 text-sm leading-6 text-ops-text-primary">
<div className="ops-chip-rhythm clip-notched ops-notch-chip tactical-chip-panel tactical-chip-panel-neutral px-3 py-3 text-sm leading-6 text-ops-text-primary">
<p>
Backup ready - {replaceBackupState.fileName}
.{' '}
Expand Down
35 changes: 17 additions & 18 deletions src/features/export/exportPanelShared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export function SignalCard({
className="ops-signal-frame"
data-tone={tone}
outerClassName={chromeClasses.outer}
innerClassName={`min-h-[7.5rem] p-4 sm:p-5 ${chromeClasses.inner}`}
innerClassName={`p-4 sm:p-5 ${chromeClasses.inner}`}
>
<p
className={`ops-eyebrow text-xs font-semibold ${chromeClasses.label}`}
Expand Down Expand Up @@ -187,22 +187,21 @@ export function PreviewFactCard({
detail,
}: PreviewFactCardProps) {
return (
<div role="listitem" className="panel-shadow">
<div className="clip-notched ops-notch-chip bg-ops-border-soft p-px">
<div className="clip-notched ops-notch-chip ops-surface-overlay-card p-3">
<p className="ops-eyebrow text-xs font-semibold text-ops-text-muted">
{label}
</p>
<p className="mt-1 text-sm font-semibold text-ops-text-primary">
{value}
</p>
{detail ? (
<p className="mt-2 text-xs leading-5 text-ops-text-muted">
{detail}
</p>
) : null}
</div>
</div>
</div>
<NotchedFrame
role="listitem"
notch="chip"
emphasis="inset"
innerClassName="ops-preview-fact-card tactical-chip-panel tactical-chip-panel-neutral p-3"
>
<p className="ops-eyebrow text-xs font-semibold text-ops-text-muted">
{label}
</p>
<p className="mt-1 text-sm font-semibold text-ops-text-primary">
{value}
</p>
{detail ? (
<p className="mt-2 text-xs leading-5 text-ops-text-muted">{detail}</p>
) : null}
</NotchedFrame>
);
}
7 changes: 5 additions & 2 deletions src/features/history/HistoryDetailBrief.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function HistoryDetailBrief({

return (
<div className="ops-history-detail-brief grid gap-4">
<div className="flex items-start justify-between gap-3">
<div className="ops-history-detail-header flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="ops-history-detail-label ops-eyebrow text-ops-text-muted">
{title}
Expand Down Expand Up @@ -80,7 +80,10 @@ export function HistoryDetailBrief({

<span className="ops-rule-hairline" aria-hidden="true" />

<p id={summaryId} className="text-sm leading-6 text-ops-text-secondary">
<p
id={summaryId}
className="ops-history-summary-copy text-sm leading-6 text-ops-text-secondary"
>
{selectedStatusSummary}
</p>

Expand Down
Loading
Loading