Work in progress, known quantities, arriving type, notes to counsel, confirmations, empty desks and error pages. Words carry the meaning; oxblood marks it; nothing spins.
The turn in progress is one line of chrome type with an oxblood point — what is happening, in counsel’s terms, and how long it has taken. There is no spinner anywhere.
Anatomy
.preceda-working-line
Sans at the small role (12/1.45), ink-tertiary, one line. role="status" so the phrase is announced politely.
__point
A 5px oxblood square. It breathes (opacity only) while live; still under reduced motion.
__text
The phrase. Truncates with an ellipsis; `--wrap` lets it wrap.
__elapsed
Tabular “41 s” after a middot. Hidden from assistive technology so it is not read every second.
--ruled / --waiting / --stalled
On a hairline; hollow point while waiting on counsel; ink-secondary with a grey point when stopped short.
Variants
Working
The default: the point breathes, the time counts.
Paper
Reading authorities on s. 482 BNSS41 s
Lamp
Reading authorities on s. 482 BNSS41 s
Ruled, beneath the last letter
In desktop correspondence the line sits on a hairline and may wrap.
Paper
Reading authorities on 482 BNSS for accused abroad at the time of the alleged offence2 min 08 s
Lamp
Reading authorities on 482 BNSS for accused abroad at the time of the alleged offence2 min 08 s
Waiting on counsel
Nothing is running; a question waits. The point is hollow and the words say so.
Paper
Waiting for your answer to 2 questions
Lamp
Waiting for your answer to 2 questions
Stalled
The turn stopped short. Pair with a Note that says what is on the desk.
Paper
Stopped at the time limit — the draft so far is on the desk4 min 00 s
Lamp
Stopped at the time limit — the draft so far is on the desk4 min 00 s
Live, counting
Interactive: `since` makes the line count once a second on the client.
Paper
Idle. Start a turn to see the line count.
Lamp
Idle. Start a turn to see the line count.
State matrix
StatePaperLamp
working
Drafting paragraph 49 s
Drafting paragraph 49 s
working, long
Checking Satender Kumar Antil v. CBI, (2022) 10 SCC 511 h 02 min
Checking Satender Kumar Antil v. CBI, (2022) 10 SCC 511 h 02 min
waiting
Waiting for your answer
Waiting for your answer
stalled
Stopped short4 min 00 s
Stopped short4 min 00 s
reduced motion
Reading the FIR12 s
Reading the FIR12 s
At 390 px
On the phone the working line sits at the foot of the dock, beneath the composer, so a turn never blocks reading. It truncates to one line.
390 px
Reading authorities on 482 BNSS for accused abroad at the time of the alleged offence41 s
Accessibility
role="status" (polite): the phrase is announced when it changes, never interrupting.
The ticking time is aria-hidden; screen-reader users hear the phrase, not a clock.
Colour is never alone: waiting is a hollow point and different words; stalled changes the ink and the words.
The breathing point is opacity only and stops under prefers-reduced-motion.
Do
Name the work in counsel’s terms: “Reading authorities on s. 482 BNSS”.
Use the safe fallback “Working on the matter” when the phase is not a closed, typed value.
Keep one working line per turn.
Don’t
Add a spinner, a progress ring, or cycling “Thinking…” labels.
Render raw tool names, model names, token counts or costs.
Put the working line in a card or a bubble.
Usage
HTML
<p class="preceda-working-line preceda-working-line--live" role="status" aria-live="polite">
<span class="preceda-working-line__point" aria-hidden="true"></span>
<span class="preceda-working-line__text">Reading authorities on s. 482 BNSS</span>
<span class="preceda-working-line__elapsed" aria-hidden="true">41 s</span>
</p>
React
import { WorkingLine } from '@luvkapur/preceda-design-system/react';
<WorkingLine label="Reading authorities on s. 482 BNSS" since={turn.startedAt} />
<WorkingLine state="waiting" label="Waiting for your answer to 2 questions" />
02
Progress
When the amount is known, draw it as a printed rule to length and print the figure. Unknown durations use the working line instead.
Anatomy
.preceda-progress
Grid: label and figure on one line, the rule beneath. role="progressbar" with value min/max/now/text.
__track / __fill
A 2px rule in `rule`, filled in binding to `--preceda-progress-value` (0–1).
__value
The printed figure, tabular, ink-tertiary; binding when complete.
--neutral / --inline
Ink-tertiary fill for measures with no call to act; a short inline rule for table cells.
Variants
Labelled
Paper
Authorities verified6 of 9 verified
Lamp
Authorities verified6 of 9 verified
Neutral measure
Relevance, treatment share — information, not an obligation.
Paper
Relevance to the proposition72%
Lamp
Relevance to the proposition72%
Inline
In a register row or table cell, beside the figure.
Paper
Followed in 41 of 52 citing decisions
79%
Lamp
Followed in 41 of 52 citing decisions
79%
Interactive
Paper
Authorities verified4 of 9 verified
Lamp
Authorities verified4 of 9 verified
State matrix
StatePaperLamp
empty
Facts confirmedNone of 5 confirmed
Facts confirmedNone of 5 confirmed
partial
Facts confirmed3 of 5 confirmed
Facts confirmed3 of 5 confirmed
complete
Facts confirmedAll 5 confirmed
Facts confirmedAll 5 confirmed
At 390 px
The rule takes the full measure; the label may wrap, the figure never does.
Accessibility
role="progressbar" with aria-valuemin/max/now and a spoken aria-valuetext (“6 of 9 verified”).
The figure is printed, so length is never the only signal.
Label with a visible label; use aria-label only for inline rules beside visible text.
Do
Phrase the figure in words counsel uses: “6 of 9 verified”.
Use neutral for scores and shares.
Don’t
Animate an indeterminate bar — use the working line.
<Skeleton lines={3} label="Loading the headnote" />
<Skeleton variant="sheet" label="Loading the draft" />
04
Note
The clerk’s note to counsel: a hairline, a small-caps word naming the kind of note, and a plain sentence in ink-secondary. It says what happened, what is on the desk, and what counsel can do next.
Anatomy
.preceda-note
A hairline above; body in the serif at the body role. role="note" by default.
__label
Run-in small caps: “Note”, “Caution”, “Error” — or a precise word (“Limitation”, “Partial draft”).
__title
Optional run-in lead sentence in ink.
__actions
Next acts as a middot-separated line of binding links.
__dismiss
Optional 40px close control.
--caution / --error / --compact
Umber or binding label and hairline; sans at ui size inside forms and dialogs.
Variants
Info — a bounded partial
Paper
Lamp
Caution
Paper
Lamp
Error
Paper
Lamp
Compact, inside a form
Paper
Lamp
Dismissible
Paper
Lamp
State matrix
StatePaperLamp
default
action hover
action focus-visible
action disabled
announced
At 390 px
At 390 px the note keeps the full measure; actions wrap onto a second line. Notes live in the correspondence sheet or under the document, never floating.
390 px
Accessibility
The label word differs by tone, so colour never carries the meaning alone.
Static notes are role="note"; pass live="polite" for an outcome that just happened, live="assertive" only for an error that stops counsel’s act.
Actions are real buttons or links with 40px targets on mobile via their line height and padding in context.
Do
Say what is on the desk and what counsel can do next.
Quote the bounded-partial sentence from the runtime verbatim.
Name the kind precisely: “Limitation”, “Partial draft”, “Verify”.
Don’t
Use a red box, an icon standing in for the word, or an emoji.
Put a note in a toast — a toast disappears.
Apologise or blame: “Oops!”, “Something went wrong on our end :(”.
Usage
HTML
<aside class="preceda-note preceda-note--error" role="note">
<p class="preceda-note__body">
<span class="preceda-note__label">Error</span>
<span class="preceda-note__title">The FIR could not be read.</span>
The file appears to be a scanned image without a text layer.
</p>
<ul class="preceda-note__actions">
<li><button class="preceda-note__action" type="button">Attach a text PDF</button></li>
</ul>
</aside>
React
<Note tone="error" title="The FIR could not be read." actions={[<button className="preceda-note__action" onClick={attach}>Attach a text PDF</button>]}>
The file appears to be a scanned image without a text layer.
</Note>
05
Banner
A page-level note printed between two rules — the daily limit, a shared read-only view, a deadline that has passed. One per page, never floating.
Anatomy
.preceda-banner
Full width, a rule above and below; tone wash only for caution and error. role="region" named by its label.
__label
Small caps naming the kind: “Limit reached”, “Shared view”, “Deadline passed”.
__message / __detail
One line of consequence in ink; an optional second sentence in ink-secondary.
__actions / __action / __dismiss
One act at the end of the line, and an optional dismiss.
--centered
A standalone gate: centred, the act beneath.
Variants
Limit reached — gate
Replaces the rate-limit card on search.
Paper
Limit reached
You have used your 10 free searches for today. Pro members search without a daily limit.
<Banner centered label="Limit reached" detail="Pro members search without a daily limit."
actions={<Link className="preceda-banner__action" to="/account">Upgrade to Pro</Link>}>
You have used your {limit} free searches for today.
</Banner>
06
Toast
A short confirmation of something counsel just did — “Copied”, “Download started” — on a raised slip at the foot of the screen. It is announced, it can be dismissed, and it waits while it is being read.
Anatomy
ToastProvider
Owns the stack (max 3) and two live regions (polite, assertive) that stay in the document.
.preceda-toast-region
A manual popover at the viewport foot, so it rises above open dialogs; bottom-right at desk, full width on phones.
.preceda-toast
Raised paper, hairline, sheet shadow; message in ui sans; optional action and dismiss (40px).
--error
A binding hairline and the word “Error”; announced assertively.
Variants
Live demo
Hover or focus the stack to pause it; Esc on a focused toast dismisses it.
Paper
Lamp
Confirmation
Paper
Link copied
Lamp
Link copied
With an act
Paper
Authority removed from the matter
Lamp
Authority removed from the matter
Error
Paper
ErrorCould not revoke this link.
Lamp
ErrorCould not revoke this link.
State matrix
StatePaperLamp
default
Download started
Download started
dismiss hover
Authority removed from the matter
Authority removed from the matter
action hover
Authority removed from the matter
Authority removed from the matter
action focus-visible
Authority removed from the matter
Authority removed from the matter
error
ErrorCould not copy — select the link instead.
ErrorCould not copy — select the link instead.
At 390 px
At 390 px the stack spans the width above the safe-area inset, newest nearest the thumb. It sits above the dock but never covers the composer for longer than its duration.
390 px
Link copied
Accessibility
Announcements go through polite and assertive live regions that are always rendered; errors are prefixed “Error:”.
Auto-dismiss pauses on hover and on focus inside the stack (WCAG 2.2.1); a toast with an act stays at least 8 s.
Esc dismisses the focused toast. Dismiss buttons are named.
While a package Dialog or Sheet is open the stack renders inside it, so it is not inert.
Do
Confirm an act counsel just took, in two or three words.
Offer Undo for a reversible removal.
Don’t
Carry the only copy of an error counsel must act on — use a Note.
Toast on page load, or for background agent progress.
Use a dark pill or an emoji.
Usage
HTML
<!-- Rendered by ToastProvider; the classes for a product that manages its own stack. -->
<section class="preceda-toast-region" popover="manual" aria-label="Notifications">
<ol class="preceda-toast-region__list">
<li><div class="preceda-toast"><p class="preceda-toast__message">Link copied</p>
<span class="preceda-toast__actions"><button class="preceda-toast__dismiss" aria-label="Dismiss">…</button></span></div></li>
</ol>
</section>
<div class="preceda-toast-region__announcer" role="status" aria-live="polite">Link copied</div>
Where the work will be, say so honestly and quietly: one sentence, one line of guidance, at most one next act. No icon, no illustration, no welcome card.
Anatomy
.preceda-empty
Serif subheading title in ink, guidance in the body role in ink-secondary.
__actions
At most one act, usually a binding link.
--desk
The empty sheet on the desk, centred on raised paper.
--inline
Inside a tab panel or list, on a hairline, at body size.
Variants
The desk
Paper
Nothing on the desk yet.
Instruct the associate in correspondence; the draft will be prepared here.
Lamp
Nothing on the desk yet.
Instruct the associate in correspondence; the draft will be prepared here.
Inside a tab
Paper
No authorities on this matter yet.
Authorities the associate relies on are listed here with their treatment and verification.
Lamp
No authorities on this matter yet.
Authorities the associate relies on are listed here with their treatment and verification.
No results
Paper
No judgments match “anticipatory bail brother-in-law abroad”.
Try a case name, a citation such as (2014) 8 SCC 273, or a provision such as s. 482 BNSS.
On the phone the desk sheet shrinks its padding and height; the sentence stays on one or two lines.
390 px
Nothing on the desk yet.
Instruct the associate below.
Accessibility
The title is a real heading at the level the page needs (`headingLevel`), or a paragraph inside a panel that already has one.
Nothing here is decorative-only, so nothing is hidden from assistive technology.
Do
Say what will appear and where it comes from.
Offer the one act that fills the space.
Don’t
Add an icon, illustration or welcome copy.
Blame the user: “You haven’t added anything!”
Usage
HTML
<div class="preceda-empty preceda-empty--desk">
<h2 class="preceda-empty__title">Nothing on the desk yet.</h2>
<p class="preceda-empty__guidance">Instruct the associate in correspondence; the draft will be prepared here.</p>
</div>
React
<EmptyState variant="desk" guidance="Instruct the associate in correspondence; the draft will be prepared here." />
<EmptyState variant="inline" headingLevel={3} title="No authorities on this matter yet." />
08
Error page
Not found and something went wrong, set as a notice in the reporter: the status in words, a serif sentence, one paragraph, and the ways back. No giant numerals.
Anatomy
.preceda-error-page
A <main> at the reading measure, vertically centred in 60dvh.
__head / __code
Small-caps running head over an ink rule; the status figure in tabular folio numerals.
__title / __body
Title role (serif 30); reading-role paragraph in ink-secondary.
__actions
Primary way back first: a button to retry, links back.
__reference
A reference counsel can quote in a report — an error digest, never an internal record id.
Variants
Not found
Paper
Not found404
This page is not in the reporter.
The address may be mistyped, or the page may have moved. Search the corpus, or return to your matters.
The page is the <main> landmark with one h1; move focus to the h1 after a client-side navigation lands here.
The status figure is a word first (“Not found”) and a number second.
The reference is plain text so it can be selected and copied.
Do
Offer the two likeliest ways back.
Log the digest server-side and show only the digest.
Don’t
Show stack traces, internal ids or provider names.
Promise that nothing was lost unless the flow guarantees it.
Usage
HTML
<main class="preceda-error-page">
<p class="preceda-error-page__head"><span>Not found</span><span class="preceda-error-page__code">404</span></p>
<h1 class="preceda-error-page__title">This page is not in the reporter.</h1>
<p class="preceda-error-page__body">The address may be mistyped, or the page may have moved.</p>
<div class="preceda-error-page__actions"><a class="preceda-link" href="/">‹ Back to search</a></div>
</main>
React
// routes/__root.tsx
notFoundComponent: () => <ErrorPage as="div" headingLevel={3} kind="not-found" actions={<Link className="preceda-link" to="/">‹ Back to search</Link>} />,
errorComponent: ({ error }) => <ErrorPage as="div" headingLevel={3} kind="error" reference={digest(error)}
actions={<><button className="preceda-button" onClick={() => location.reload()}>Try again</button><Link …>‹ Back to search</Link></>} />,