New Delhi · September 2026
Preceda

12 Correspondence

Correspondence

Letters, working notes, the fact request, next steps, the memo pointer and the composer: the left column of the matter.

  1. Letter
  2. From the desk
  3. Fact request
  4. Next steps
  5. Memo pointer
  6. Composer

§ The column

The correspondence, at 44 per cent of the desk.

The left column of the matter workspace, built only from this page’s components: three letters, the working notes and the composer. The desk to its right is left bare here; the document sheet is documented with the record.

Paper · correspondence at 44 per cent

  1. Counsel

    Client arrested yesterday under 498-A and 406 IPC, Saket. FIR annexed. Wife’s family in Gurugram; no prior record. Need anticipatory bail for the brother-in-law who is named but was abroad.

    Attached:FIR.pdf · 2 pages

  2. Associate

    I have read the FIR. Two instruments are plausible; the dominant one is an application under Section 482 BNSS before the Sessions Court, Saket, for the brother-in-law, with Arnesh Kumar directions as the spine.

    Before I draft, two facts I could not find in the file:

    • Dates the brother-in-law was outside India (passport stamps will do).
    • Whether a notice under Section 35(3) BNSS was served on him.
  3. Counsel

    Abroad 3 March to 19 August 2026. No notice served.

  4. Associate

    Drafting the document

    From the deskDrafting began
    1. 1 s elapsed
    2. 2 s elapsed
    3. 44 s elapsed
    4. 44 s elapsed
    5. 45 s elapsed
    6. 1 min 12 s elapsed
    7. 1 min 13 s elapsed

Lamp · correspondence at 44 per cent

  1. Counsel

    Client arrested yesterday under 498-A and 406 IPC, Saket. FIR annexed. Wife’s family in Gurugram; no prior record. Need anticipatory bail for the brother-in-law who is named but was abroad.

    Attached:FIR.pdf · 2 pages

  2. Associate

    I have read the FIR. Two instruments are plausible; the dominant one is an application under Section 482 BNSS before the Sessions Court, Saket, for the brother-in-law, with Arnesh Kumar directions as the spine.

    Before I draft, two facts I could not find in the file:

    • Dates the brother-in-law was outside India (passport stamps will do).
    • Whether a notice under Section 35(3) BNSS was served on him.
  3. Counsel

    Abroad 3 March to 19 August 2026. No notice served.

  4. Associate

    Drafting the document

    From the deskDrafting began
    1. 1 s elapsed
    2. 2 s elapsed
    3. 44 s elapsed
    4. 44 s elapsed
    5. 45 s elapsed
    6. 1 min 12 s elapsed
    7. 1 min 13 s elapsed

01

Letter

Correspondence is set like letters in a file, not messages in a chat: a hairline, the sender in small caps with the time at right, then the body in the reading serif. Counsel and the associate share one measure and one ink; neither is a bubble.

Anatomy

.preceda-letter
The entry (<article>). A hairline above; the first letter in a column has none.
.preceda-letter__head
Sender and time on one line.
.preceda-letter__sender
Counsel, Associate or Note in serif small caps, ink-2.
.preceda-letter__time
<time> in chrome sans, ink-3, tabular figures.
.preceda-letter__body
Serif body at 15/1.55 (17 on the mobile sheet). Paragraphs, lists and quotes.
.preceda-letter__quote
A quoted excerpt: indented italic on a hairline left rule, with an optional <cite>.
.preceda-letter__attachments
One line: “Attached: FIR.pdf · 2 pages”. Never pills. attachmentsProps names the line for assistive technology.
.preceda-letter__after
What follows the body: a fact request, next steps, a memo pointer.
.preceda-letter--note
The clerk’s note for system messages, bounded partials and errors. Body in ink-2.
.preceda-letter--streaming
Set while text arrives (with aria-busy). The text grows; there is no caret.
.preceda-correspondence
The column: __letters (scrolls), __status (working line and notes), __composer.

Variants

Counsel

Paper

Counsel

Client arrested yesterday under 498-A and 406 IPC, Saket. FIR annexed. Wife’s family in Gurugram; no prior record. Need anticipatory bail for the brother-in-law who is named but was abroad.

Lamp

Counsel

Client arrested yesterday under 498-A and 406 IPC, Saket. FIR annexed. Wife’s family in Gurugram; no prior record. Need anticipatory bail for the brother-in-law who is named but was abroad.

Associate, with a list

Paper

Associate

I have read the FIR. Two instruments are plausible; the dominant one is an application under Section 482 BNSS before the Sessions Court, Saket, for the brother-in-law, with Arnesh Kumar directions as the spine.

Before I draft, two facts I could not find in the file:

  • Dates the brother-in-law was outside India (passport stamps will do).
  • Whether a notice under Section 35(3) BNSS was served on him.

Lamp

Associate

I have read the FIR. Two instruments are plausible; the dominant one is an application under Section 482 BNSS before the Sessions Court, Saket, for the brother-in-law, with Arnesh Kumar directions as the spine.

Before I draft, two facts I could not find in the file:

  • Dates the brother-in-law was outside India (passport stamps will do).
  • Whether a notice under Section 35(3) BNSS was served on him.

Quote block

From “Quote selection” on the desk. The excerpt is counsel’s reference, not the associate’s words.

Paper

Counsel

The allegations against the Applicant are omnibus and general, of the kind this Hon’ble Court has repeatedly declined to act upon.

Draft ¶ 3

Find an authority for this or cut it. I will not argue it bare.

Lamp

Counsel

The allegations against the Applicant are omnibus and general, of the kind this Hon’ble Court has repeatedly declined to act upon.

Draft ¶ 3

Find an authority for this or cut it. I will not argue it bare.

Attachments line

Paper

Counsel

FIR and the Magistrate’s order attached.

Attached:FIR.pdf · 2 pages;Order 12 Aug.pdf · 1 page

Lamp

Counsel

FIR and the Magistrate’s order attached.

Attached:FIR.pdf · 2 pages;Order 12 Aug.pdf · 1 page

Clerk’s note

System messages and bounded partials. Never a red banner and never an emoji.

Paper

Note

The draft is on the desk, but the turn ran out of time before paragraph 5 was checked. Its authority is marked VERIFY; ask again to finish the check.

Lamp

Note

The draft is on the desk, but the turn ran out of time before paragraph 5 was checked. Its authority is marked VERIFY; ask again to finish the check.

Clerk’s note, error

The word “Note” takes the error ink; the sentence says what failed and what to do.

Paper

Lamp

State matrix

StatePaperLamp
default

Counsel

Abroad 3 March to 19 August 2026. No notice served.

Counsel

Abroad 3 March to 19 August 2026. No notice served.

streaming

Associate

Thank you. With the dates confirmed, paragraph 1 can rest on the passport annexed as A-3, and the

Associate

Thank you. With the dates confirmed, paragraph 1 can rest on the passport annexed as A-3, and the

empty (streaming, no text yet)

Associate

Associate

note

Note

Two authorities could not be quoted from the corpus and are marked VERIFY.

Note

Two authorities could not be quoted from the corpus and are marked VERIFY.

error

Note

This turn stopped before a draft was prepared. Nothing on the desk changed.

Note

This turn stopped before a draft was prepared. Nothing on the desk changed.

At 390 px

On the correspondence sheet the body rises to the 17 px reading size and the column runs edge to edge at 16 px gutters. Sender and time stay on one line; long names wrap under the time, never beside it.

390 px

  1. Counsel

    Client arrested yesterday under 498-A and 406, Saket. FIR attached. Anticipatory bail for the brother-in-law, who was abroad.

  2. Associate

    I have read the FIR. The dominant instrument is an application under s. 482 BNSS before the Sessions Court, Saket, with the Arnesh Kumar directions as the spine.

Accessibility

  • Each letter is an <article>; put letters in an ordered list (or a role="feed") so the order is announced.
  • The time is a <time> with a machine-readable dateTime.
  • Streaming sets aria-busy="true" on the letter. Announce the finished letter once (the product’s live region), not every token.
  • An error note may carry role="alert" when it reports the result of counsel’s own action; routine notes do not.
  • Sender is a word, not a colour or an alignment: counsel and associate are distinguished in the accessibility tree.

Do

  • Use “Counsel” and “Associate”; never “user”, “assistant” or “AI”.
  • Keep the attachments as one line under the body.
  • Put the bounded-partial sentence from the note to counsel in a clerk’s note.

Don’t

  • Align counsel right and the associate left, or put either in a bubble.
  • Draw a typing caret, shimmer or dots while the text streams.
  • Set a system error as a red banner with an icon.

Usage

HTML
<ol class="preceda-correspondence__letters">
  <li>
    <article class="preceda-letter preceda-letter--counsel" data-sender="counsel">
      <header class="preceda-letter__head">
        <p class="preceda-letter__sender">Counsel</p>
        <time class="preceda-letter__time" datetime="2026-09-20T10:42">10:42</time>
      </header>
      <div class="preceda-letter__body"><p>Client arrested yesterday under 498-A…</p></div>
      <p class="preceda-letter__attachments">
        <span class="preceda-letter__attachments-label">Attached:</span>
        <span class="preceda-letter__attachment"><span class="preceda-letter__attachment-name">FIR.pdf</span> · 2 pages</span>
      </p>
    </article>
  </li>
</ol>
React
import { Letter, LetterQuote } from '@luvkapur/preceda-design-system/react';

<Letter sender="associate" time="10:43" dateTime={sentAt} streaming={isStreaming}
  after={<NextSteps steps={steps} onSelect={runStep} />}>
  <p>I have read the FIR…</p>
</Letter>

<Letter sender="note" tone="error" time="10:59">
  <p>Your instruction was not sent. It is kept in the composer; send it again.</p>
</Letter>

02

From the desk

A chronological account of typed work stages and saved changes. The active line carries the present action; the disclosure retains each substantiated step.

Anatomy

.preceda-working-notes
Native disclosure beneath the active working line, collapsed by default.
.preceda-working-notes__summary
From the desk and the latest recorded step.
.preceda-working-notes__entries
Hairline ledger of observed stages and elapsed times.
.preceda-working-notes__link
Optional route to a saved draft or authority on the desk.

Variants

Running, collapsed

Paper

From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed

Lamp

From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed

Open

Paper

From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed

Lamp

From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed

No recorded steps

Paper

From the desk

No desk entries yet.

Lamp

From the desk

No desk entries yet.

State matrix

StatePaperLamp
queued
From the desk

No desk entries yet.

From the desk

No desk entries yet.

running
From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed
From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed
done
From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed
From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed

At 390 px

The summary stays one line; opening correspondence reveals the observed work and desk links.

390 px

From the deskUnsaved candidate on the desk
  1. 1 s elapsed
  2. 2 s elapsed
  3. 44 s elapsed
  4. 44 s elapsed
  5. 45 s elapsed
  6. 1 min 12 s elapsed
  7. 1 min 13 s elapsed
  8. 1 min 30 s elapsed

Accessibility

  • Native details and summary support Enter and Space.
  • The active working line is the polite live region; the ledger is read on demand.
  • Desk links are buttons with explicit destinations.

Do

  • Supply stages and milestones derived from structured events and persisted artifacts.
  • Call candidate decisions candidates until a verification receipt exists.
  • Coalesce repeated work into one milestone.

Don’t

  • Pass free-form runtime prose or tool arguments to the disclosure.
  • Imply that an authority was verified from a search result.
  • Create activity merely because time has passed.

Usage

HTML
<details class="preceda-working-notes"><summary class="preceda-working-notes__summary">From the desk · Drafting began</summary><ol class="preceda-working-notes__entries"><li>Instruction recorded</li><li>Instruction review began</li><li>Working brief prepared</li><li>Legal research began</li><li>Drafting began</li></ol></details>
React
import { WorkingNotes } from '@luvkapur/preceda-design-system/react';

<WorkingNotes status="running" entries={closedEventBackedEntries} />

03

Fact request

The associate asks for what the file does not hold as a short numbered list, each answer written on its own printed line beneath the question. It is the one place a request is answered. A suggestion is never a fact until counsel confirms it, and a failed save never loses an answer.

Anatomy

.preceda-fact-request
A <form>, labelled by its title. data-state: unanswered, partially-answered, ready, submitting, accepted, partial, rejected.
.preceda-fact-request__title
Small caps, e.g. “Two facts the file does not hold”. __progress at right: “1 of 2 answered”.
.preceda-fact-request__item
One question: __number in the gutter, __question (the <label>), __hint, the control, actions and __outcome.
.preceda-fact-request__input
The answer on a printed underline: text (with an optional native <datalist> of known values), date, <select> (with __select-chevron), or <textarea>.
.preceda-fact-request__group
Grouped fields (a party roster): one fieldset per __entry, labelled sub-fields, “Add another …”.
.preceda-fact-request__basis
Where a suggestion came from, in italic. The suggestion needs “Confirm suggestion” (aria-pressed).
.preceda-fact-request__attached
Per-question files: “Attached: passport.pdf · 4 pages”, with Remove, and an “Attach …” text link. With onOpenAttachment a finished file’s name opens it.
.preceda-fact-request__recorded
Particulars recorded as not available at present: listed in a disclosure, with “Provide now”.
.preceda-fact-request__outcome
Per-question result after a save: “saved”, or “not saved” with the reason inline.
.preceda-fact-request__foot
What remains (“1 still open”) and the one act: “Save 2 answers”.
.preceda-fact-request__note
A clerk’s note for partial and rejected results.
.preceda-fact-request--history
An earlier or superseded request as a read-only disclosure.

Variants

Two facts (live)

Answer one or both and save: the request reads back the record, and a question left blank stays open for later.

Paper

Two facts the file does not hold

0 of 2 answered
  1. Passport stamps will do; attach them if you have them.

2 still open

Lamp

Two facts the file does not hold

0 of 2 answered
  1. Passport stamps will do; attach them if you have them.

2 still open

Every field kind (live)

Text, date, select, a suggested textarea, a document question, a grouped roster whose fields follow the party type, and a recorded blank. Saving returns a partial result.

Paper

Complete the record

1 of 6 answered
  1. The FIR

  2. The applicant

  3. Suggested from the FIR (p. 3) and counsel’s first instruction. Confirm or edit.

  4. Documents

  5. Parties

    Respondents to be arrayed.

    Respondent 1
1 particular recorded as not available at present · left blank in the draft

You told me these are not to hand. The draft keeps a blank for each; nothing is asked again.

  • Aadhaar number of the applicant.
5 still open; save what you have and answer the rest later

Lamp

Complete the record

1 of 6 answered
  1. The FIR

  2. The applicant

  3. Suggested from the FIR (p. 3) and counsel’s first instruction. Confirm or edit.

  4. Documents

  5. Parties

    Respondents to be arrayed.

    Respondent 1
1 particular recorded as not available at present · left blank in the draft

You told me these are not to hand. The draft keeps a blank for each; nothing is asked again.

  • Aadhaar number of the applicant.
5 still open; save what you have and answer the rest later

History and superseded

Paper

Earlier fact request · 1 of 2 answered

Kept for reference. Answer outstanding questions in the current request.

  1. 1Dates the brother-in-law was outside India.Answered in saved facts
  2. 2Was a notice under s. 35(3) BNSS served on him?No saved answer
Previous instrument’s fact request

These questions belonged to an instrument that is no longer on the desk.

  1. 1Dates the brother-in-law was outside India.Previous instrument

Lamp

Earlier fact request · 1 of 2 answered

Kept for reference. Answer outstanding questions in the current request.

  1. 1Dates the brother-in-law was outside India.Answered in saved facts
  2. 2Was a notice under s. 35(3) BNSS served on him?No saved answer
Previous instrument’s fact request

These questions belonged to an instrument that is no longer on the desk.

  1. 1Dates the brother-in-law was outside India.Previous instrument

State matrix

StatePaperLamp
unanswered

Two facts the file does not hold

0 of 2 answered
  1. Passport stamps will do; attach them if you have them.

2 still open

Two facts the file does not hold

0 of 2 answered
  1. Passport stamps will do; attach them if you have them.

2 still open

partially answered

Two facts the file does not hold

1 of 2 answered
  1. Passport stamps will do; attach them if you have them.

1 still open; save what you have and answer the rest later

Two facts the file does not hold

1 of 2 answered
  1. Passport stamps will do; attach them if you have them.

1 still open; save what you have and answer the rest later

ready

Two facts the file does not hold

2 of 2 answered
  1. Passport stamps will do; attach them if you have them.

Ready to save

Two facts the file does not hold

2 of 2 answered
  1. Passport stamps will do; attach them if you have them.

Ready to save

submitting

Two facts the file does not hold

2 of 2 answered
  1. Passport stamps will do; attach them if you have them.

Saving to the matter…

Saving answers.

Two facts the file does not hold

2 of 2 answered
  1. Passport stamps will do; attach them if you have them.

Saving to the matter…

Saving answers.

accepted

Two facts the file does not hold

2 of 2 answered
  1. Dates the brother-in-law was outside India.

    3 March – 19 August 2026

    saved

  2. Was a notice under s. 35(3) BNSS served on him?

    No notice was served

    saved

2 answers saved to the matter.

Two facts the file does not hold

2 of 2 answered
  1. Dates the brother-in-law was outside India.

    3 March – 19 August 2026

    saved

  2. Was a notice under s. 35(3) BNSS served on him?

    No notice was served

    saved

2 answers saved to the matter.

partial

Two facts the file does not hold

2 of 2 answered
  1. Dates the brother-in-law was outside India.

    3 March – 19 August 2026

    saved

  2. not savedThe record was busy and did not take this answer. It is kept here.

Ready to save

Note1 answer could not be saved and is kept here to save again. The rest are on the record.

1 answer saved; 1 answer not saved.

Two facts the file does not hold

2 of 2 answered
  1. Dates the brother-in-law was outside India.

    3 March – 19 August 2026

    saved

  2. not savedThe record was busy and did not take this answer. It is kept here.

Ready to save

Note1 answer could not be saved and is kept here to save again. The rest are on the record.

1 answer saved; 1 answer not saved.

rejected

Two facts the file does not hold

2 of 2 answered
  1. Passport stamps will do; attach them if you have them.

    not savedNot saved: the connection dropped before the record answered.

  2. not savedNot saved: the connection dropped before the record answered.

Ready to save

NoteNothing was saved. Every answer is kept here; save again when ready.

The answers were not saved. They are kept here.

Two facts the file does not hold

2 of 2 answered
  1. Passport stamps will do; attach them if you have them.

    not savedNot saved: the connection dropped before the record answered.

  2. not savedNot saved: the connection dropped before the record answered.

Ready to save

NoteNothing was saved. Every answer is kept here; save again when ready.

The answers were not saved. They are kept here.

disabled (turn running)

Two facts the file does not hold

1 of 2 answered
  1. Passport stamps will do; attach them if you have them.

1 still open; save what you have and answer the rest later

Two facts the file does not hold

1 of 2 answered
  1. Passport stamps will do; attach them if you have them.

1 still open; save what you have and answer the rest later

suggestion to confirm

One fact to confirm

0 of 1 answered
  1. The applicant

    Suggested from the FIR (p. 3) and counsel’s first instruction. Confirm or edit.

1 still open

One fact to confirm

0 of 1 answered
  1. The applicant

    Suggested from the FIR (p. 3) and counsel’s first instruction. Confirm or edit.

1 still open

known values while typing

One fact the file does not hold

0 of 1 answered
1 still open

One fact the file does not hold

0 of 1 answered
1 still open

attached, uploading, error

One document

1 of 1 answered
  1. Documents

    • · 1 page
    • passport-p5.pdf · uploading
    • stamps.heic · HEIC is not accepted; send a PDF or JPEG
Waiting for a file to finish uploading

One document

1 of 1 answered
  1. Documents

    • · 1 page
    • passport-p5.pdf · uploading
    • stamps.heic · HEIC is not accepted; send a PDF or JPEG
Waiting for a file to finish uploading

hover / focus-visible
1

Dates the brother-in-law was outside India.

1

Dates the brother-in-law was outside India.

At 390 px

On the correspondence sheet the questions and answers rise to 17 px, targets to 44 px, and grouped fields stack to one column. Opening the sheet from “1 question waiting” scrolls to the first open item (scroll-margin keeps it clear of the sheet head).

390 px

Two facts the file does not hold

1 of 2 answered
  1. Passport stamps will do; attach them if you have them.

1 still open; save what you have and answer the rest later

Accessibility

  • The form is labelled by its title. Each question is the <label> of its answer; hints, suggestion bases and failure reasons are tied in with aria-describedby.
  • A failed answer sets aria-invalid and keeps its value. The outcome is announced once through a polite status region.
  • Grouped answers are a role="group" labelled by the question; each entry is a <fieldset> with its own legend.
  • “Confirm suggestion” is a toggle (aria-pressed). A rendered suggestion is never counted as answered.
  • The submit stays disabled until every open question is answered and no file is uploading; “1 still open” says why.
  • Answers never depend on the display index: questions are keyed by their canonical id.

Do

  • Title the request in counsel’s terms: “Two facts the file does not hold”.
  • Return the typed result: accepted, partial or rejected, with per-question reasons.
  • Keep every answer on screen after a failed save.

Don’t

  • Treat a resolved promise as success without a disposition.
  • Pre-accept a derived or proposed value because it is shown.
  • Render a second copy of the request elsewhere with its own submit.

Usage

HTML
<form class="preceda-fact-request" data-state="partially-answered" aria-labelledby="fr-title">
  <div class="preceda-fact-request__head">
    <h3 class="preceda-fact-request__title" id="fr-title">Two facts the file does not hold</h3>
    <span class="preceda-fact-request__progress">1 of 2 answered</span>
  </div>
  <ol class="preceda-fact-request__list">
    <li class="preceda-fact-request__item">
      <span class="preceda-fact-request__number" aria-hidden="true">1</span>
      <div class="preceda-fact-request__body">
        <label class="preceda-fact-request__question" for="fr-1">Dates the brother-in-law was outside India.</label>
        <div class="preceda-fact-request__control">
          <input id="fr-1" class="preceda-fact-request__input" placeholder="Answer…" aria-required="true">
        </div>
      </div>
    </li>
  </ol>
  <div class="preceda-fact-request__foot">
    <span class="preceda-fact-request__remaining">1 still open</span>
    <button type="submit" class="preceda-fact-request__submit" disabled>Save 1 answer</button>
  </div>
</form>
React
import { FactRequest } from '@luvkapur/preceda-design-system/react';

<FactRequest
  data-testid="fact-request-card"
  title="Two facts the file does not hold"
  questions={items.map(toFactQuestion)}       // id = canonicalKey
  defaultValues={prefills}
  attachments={filesByQuestion}
  onAttach={uploadForQuestion}
  onSubmit={async (values) => deliver(values)} // → { disposition, items }
  disabled={turnInProgress}
/>

04

Next steps

What counsel might ask for next is offered as one line of text links in binding ink, separated by middots, after the letter. They are suggestions in the associate’s voice, not buttons competing with the composer.

Anatomy

.preceda-next-steps
A <nav> named “Suggested next”.
.preceda-next-steps__list
An inline list; items wrap as a line of text wraps.
.preceda-next-steps__item
Each item but the last is followed by a presentational middot, so a wrapped line ends on the separator.
.preceda-next-steps__link
A <button> (runs a prompt) or an <a> (goes somewhere), serif, binding ink on a hairline underline.

Variants

Three steps

Paper

Lamp

One step

Paper

Lamp

Wrapping

Long lines wrap at the middot, never inside a step.

Paper

Lamp

State matrix

StatePaperLamp
default
hover
focus-visible
disabled (turn running)
empty

No steps: the component renders nothing.

No steps: the component renders nothing.

At 390 px

At 390 px each step is a 44 px target in the 17 px serif; the line wraps at the middots.

390 px

Accessibility

  • A <nav aria-label="Suggested next"> with a list, so the count of steps is announced.
  • Middots are CSS content with empty alternative text: they are not read.
  • Each step is a real button or link with a 40 px target (44 on mobile).
  • Disabled steps use the disabled attribute and lose their underline; the word stays legible in ink-3.

Do

  • Keep steps to one line of three or four.
  • Write each step as the act counsel would ask for.

Don’t

  • Use pills, icons or chips for suggestions.
  • Add a step that duplicates Send or Approve.

Usage

HTML
<nav class="preceda-next-steps" aria-label="Suggested next">
  <ul class="preceda-next-steps__list">
    <li class="preceda-next-steps__item"><button type="button" class="preceda-next-steps__link">Draft the application</button></li>
    <li class="preceda-next-steps__item"><button type="button" class="preceda-next-steps__link">Check each citation</button></li>
  </ul>
</nav>
React
import { NextSteps } from '@luvkapur/preceda-design-system/react';

<NextSteps
  steps={actions.map((action, index) => ({ id: String(index), label: action.label }))}
  onSelect={(step) => onActionClick(actions[Number(step.id)].prompt)}
/>

05

Memo pointer

A memorandum is a document, so it lives on the desk. The correspondence carries one ruled line that points to it; choosing the line puts the memorandum on the desk and offers the way back to the current draft.

Anatomy

.preceda-memo-pointer
The ruled line (hairlines above and below).
.preceda-memo-pointer__open
The control: a toggle button (aria-pressed = on the desk).
.preceda-memo-pointer__kind
“Memorandum” in small caps.
.preceda-memo-pointer__title
The memorandum’s title in the serif, underlined like a link.
.preceda-memo-pointer__meta
Pages and time in chrome sans.
.preceda-memo-pointer__action
“Open on the desk ›”, or “On the desk” once opened.
.preceda-memo-pointer__back
“Back to current draft”, shown while the memorandum is on the desk.

Variants

Closed

Paper

Lamp

On the desk

Paper

Lamp

Without meta

Paper

Lamp

State matrix

StatePaperLamp
default
hover
focus-visible
active (on the desk)
disabled

At 390 px

On the phone the pointer closes the correspondence sheet and opens the memorandum on the desk; the title wraps under the kind and the action moves to its own line.

390 px

Accessibility

  • The line is one button; aria-pressed says whether the memorandum is on the desk.
  • Opening moves the desk, not focus: announce “Memorandum on the desk” from the desk’s live region.
  • “Back to current draft” is a separate button so it is reachable without toggling.

Do

  • Point to the memorandum from the letter that produced it.
  • Restore the previously selected draft on “Back”.

Don’t

  • Paste the memorandum into the letter.
  • Style the pointer as a card with a shadow.

Usage

HTML
<div class="preceda-memo-pointer">
  <button type="button" class="preceda-memo-pointer__open" aria-pressed="false">
    <span class="preceda-memo-pointer__kind">Memorandum</span>
    <span class="preceda-memo-pointer__title">Strategy on anticipatory bail</span>
    <span class="preceda-memo-pointer__meta">4 pages · 10:47</span>
    <span class="preceda-memo-pointer__action">Open on the desk</span>
  </button>
</div>
React
import { MemoPointer } from '@luvkapur/preceda-design-system/react';

<MemoPointer
  data-testid="strategy-artifact"
  title={strategy.title}
  meta={`${strategy.pages} pages`}
  onDesk={selectedDocument === strategy.id}
  onOpen={() => selectDocument(strategy.id)}
  onBack={restorePreviousDraft}
/>

06

Composer

Counsel instructs; the composer is a plain sheet to write on. The attach affordance is words, the files queued for the next send are a line, and Send is a small ink button — the only filled control in the column.

Anatomy

.preceda-composer
A <form>; the whole composer is the drop target. data-state: empty, ready, sending, disabled.
.preceda-composer__sheet
Hairline border on paper-raised. The focus ring is drawn on the sheet, not the textarea.
.preceda-composer__input
The textarea, “Ask a question or instruct the associate…”, growing with its content to about eight lines.
.preceda-composer__attached
“Attached: FIR.pdf · Order 12 Aug.pdf”, each with a quiet remove mark; uploading and refused files say so.
.preceda-composer__attach
A <label> around a hidden file input: “Attach FIR, orders, correspondence · PDF, DOCX”.
.preceda-composer__send
The ink Send button (type="submit"). Pass data-matter-send through sendButtonProps.
.preceda-composer__drop
The ruled overlay while a file is held over the composer.
.preceda-composer--dock
The mobile line: Send inside the box, attach below.

Variants

Sheet (live)

Type and press Enter or Cmd/Ctrl+Enter; Shift+Enter is a new line. Attach a file to see the attached line.

Paper

Nothing sent yet.

Lamp

Nothing sent yet.

With attached files

Paper

  • FIR.pdf
  • Order 12 Aug.pdf

Lamp

  • FIR.pdf
  • Order 12 Aug.pdf

Dock (mobile)

Paper

Lamp

Dock with a file

Paper

  • FIR.pdf

Lamp

  • FIR.pdf

State matrix

StatePaperLamp
empty
ready
focus-visible
Attach FIR, orders, correspondence · PDF, DOCX
Attach FIR, orders, correspondence · PDF, DOCX
hover (Send)
sending
  • FIR.pdf
  • FIR.pdf
uploading (guarded)
  • Order 12 Aug.pdfuploading
  • Order 12 Aug.pdfuploading
error
  • Scan.heicnot a PDF or DOCX
  • Scan.heicnot a PDF or DOCX
disabled
drop target

At 390 px

In the dock the composer is one line with Send inside the box (ph-desk-paper). Targets are 44 px, the text is 17 px so iOS does not zoom, and the dock respects the safe-area inset and the keyboard.

390 px

Accessibility

  • The textarea is named “Instruction to the associate”; the placeholder is not the label.
  • Enter sends and Shift+Enter breaks the line (unchanged from today). Cmd/Ctrl+Enter always sends. IME composition never sends.
  • Send is a real submit button, disabled until there is text or a finished file, and while sending or uploading; aria-busy is set while sending.
  • The attach control is a native file input inside a visible label; its focus ring is drawn on the label.
  • Each remove mark is named “Remove FIR.pdf” and has a 40 px hit area (44 on mobile).
  • Attachment and send errors are announced with role="alert" and tied to the textarea.

Do

  • Keep data-matter-send on the Send button: sendButtonProps={{ "data-matter-send": "" }}.
  • Let the product own uploads; pass files with their status.
  • Keep the text while a send is in flight; clear it only when the turn is accepted.

Don’t

  • Replace Send with a paper-plane icon.
  • Show files as pills or chips.
  • Use the placeholder “Ask anything about your case…”.

Usage

HTML
<form class="preceda-composer preceda-composer--sheet" data-state="empty">
  <div class="preceda-composer__sheet">
    <textarea class="preceda-composer__input" rows="1" placeholder="Ask a question or instruct the associate…"
      aria-label="Instruction to the associate"></textarea>
  </div>
  <div class="preceda-composer__row">
    <label class="preceda-composer__attach">
      <input type="file" class="preceda-composer__file-input" multiple accept=".pdf,.docx">
      <span><span class="preceda-composer__attach-verb">Attach</span> FIR, orders, correspondence · PDF, DOCX</span>
    </label>
    <button type="submit" class="preceda-composer__send" data-matter-send disabled>Send</button>
  </div>
  <div class="preceda-composer__drop" aria-hidden="true">Drop to attach · PDF, DOCX</div>
</form>
React
import { Composer } from '@luvkapur/preceda-design-system/react';

<Composer
  value={draft}
  onValueChange={setDraft}
  onSend={send}
  sending={turnInProgress}
  uploadsPending={batchSettling}
  files={pendingFiles.map((f) => ({ id: f.localId, name: f.filename, status: f.status, error: f.error }))}
  onFilesSelected={uploadFiles}
  onRemoveFile={removeFile}
  inputRef={textareaRef}
  sendButtonProps={{ 'data-matter-send': '' }}
  variant={isMobile ? 'dock' : 'sheet'}
/>