# Components.

> Markdown copy of [/brand/components](/brand/components).

A component is a behavior rule with a visual form. It has one job, plain
words, every necessary condition, and no surprises between mouse, keyboard,
and touch.

## Rules before parts

1. **Native first.** Start with the correct HTML element.
2. **One job.** Split parts that ask for two decisions.
3. **Every condition.** The uncommon cases are part of the component.
4. **Content sets size.** Never shrink type to rescue a box.

## Core parts

These are recipes, not a software package. Reuse the HTML and token roles;
extract code only after the same part appears twice.

### 01 / Buttons and links

A button changes the current page. A link goes somewhere. The label names the
result, not the shape.

- **Primary button:** orange-600 surface, cream-50 text, orange-700 hover,
  visible orange focus ring, 44px minimum height.
- **Secondary button:** transparent surface, wood-300 border, wood-700 text,
  visible orange focus ring, 44px minimum height.
- **Text link:** orange-600 underlined text, orange-700 hover, 44px minimum
  touch area when it acts as a standalone control.
- **Disabled:** native `disabled`, lower opacity, no pointer events. Nearby copy
  explains why it is unavailable when the reason is not obvious.

The live example announces “Saved. The example is complete.” beside the action
through an `aria-live="polite"` region. Reset becomes available only after the
save action completes.

### 02 / Labels and results

A category is a quiet pill. A result uses a glyph, a word, and color together.

- **Category:** cream-500/60 surface, wood-700 text, pill shape.
- **Complete:** `✓ complete`, sage-100 surface, sage-800 text.
- **Needs correction:** `× needs correction`, orange-100 surface, orange-800
  text.

Never make color carry the meaning alone.

### 03 / Inputs

Every input keeps its visible label, help, and correction together.

- Label sits above the control and remains visible after input.
- Field height is at least 44px.
- Help text names the expected content before an error occurs.
- Invalid input uses `aria-invalid="true"` and `aria-describedby` to connect the
  field to its correction.
- The correction uses a `×`, plain wording, and orange-700. It never erases the
  person’s input.
- Placeholder text is an example, never the label.

### 04 / Surfaces

- **Card:** cream-50 fill, wood-200 hairline, 2xl radius, padding set by the
  content.
- **Aside:** sage-400 left rail, serif heading, italic wood-500 support copy.
- **Code or evidence:** wood-800 surface, cream-100 text, mono face, rounded-lg.
- **Divider:** wood-200 hairline. Use it to show sequence or grouping, not as
  decoration.

### 05 / Feedback after an action

Put the result beside the action that caused it. Preserve context and give the
next useful step.

- **Busy:** say what is being checked or saved; prevent repeat input.
- **Empty:** name what is absent and offer the next valid action.
- **Error:** name the exact correction and keep the person’s work.
- **Complete:** confirm what finished and link to the result when one exists.

## Every condition belongs in the design

The happy path is one row, not the whole specification.

- **Rest:** the job, current value, and available action are clear before anyone
  interacts.
- **Hover + focus:** the same target responds to pointer and keyboard. Focus is
  always visible.
- **Busy:** keep the action label recognizable, prevent repeat input, and say
  what is happening.
- **Empty:** name what is absent and offer the next valid action. Empty space is
  not an explanation.
- **Error:** keep the person’s input, show the exact correction beside it, and
  move focus when needed.
- **Success:** confirm what completed and where the result now lives. Do not
  make people infer completion.

## Release calendar

The shared `components/ReleaseCalendar.tsx` combines month controls, a true
calendar, linked editions, today, the next scheduled item, and a legend. Its
parts stay quiet so the schedule remains the focal object.

- **Structure:** real weekday layout and real month length. A day-31 item lands
  on the last day of a shorter month.
- **Controls:** previous and next are real buttons with 44px targets, visible
  focus, disabled bounds, and labels for screen readers.
- **Meaning:** today lifts; the next item uses orange; an existing edition uses
  sage; every color is reinforced by position, label, or glyph.
- **Links:** an existing edition opens that issue; a future item opens its
  series page.
- **Motion:** the incoming month turns for 220ms. Reduced motion gets a fade.
- **Small screens:** controls and the legend reflow without shrinking labels or
  requiring horizontal scrolling.

Props: `entries: {day, label, seriesSlug}[]`, `editions?: {seriesSlug, issue,
href}[]`. The homepage State of… panel is the live consumer.

## Layout and motion

### Fit the content

- **44px:** minimum action target in either direction.
- **12px:** minimum rendered text, including labels and evidence.
- **66ch:** maximum measure for explanatory prose.
- **390px:** required small-screen proof without sideways scrolling.
- Page copy stays narrow. Evidence and composed parts may use the full shell.
- Mobile becomes one reading column. Do not preserve desktop columns by
  shrinking their contents.

### Move only to explain

- Hover and focus transitions run in 160–240ms.
- Page sections may fade in once for orientation.
- Movement shows entry, exit, order, or changed position.
- Nothing bounces, loops, or moves after the change is understood.
- Reduced motion preserves the same information without the movement.

## Do and don't

**Don't use color as the message.** A red dot, unlabeled icon, or green border
asks people to guess. A fifth hue also breaks the four-board palette.

**Do say the result.** Use a glyph, plain label, and palette color together:
“× needs correction” or “✓ complete.”

**Don't hide the label in placeholder text.** It disappears as soon as someone
types and cannot carry the field's meaning.

**Do keep label, help, and correction together.** The field keeps its name
before, during, and after input; any correction sits beside it.

## Final check before reuse

- The native element does the job before custom JavaScript is added.
- Every button works; every link goes somewhere; every field has a visible
  label.
- Rest, hover, focus, busy, empty, error, success, and disabled behavior are
  accounted for.
- Keyboard order follows reading order, focus is visible, and status never
  depends on color alone.
- Targets are at least 44 by 44 pixels and rendered text is at least 12 pixels.
- The component fits at 390 pixels without clipping, overlap, or horizontal
  scrolling.
- Motion explains a change, honors reduced motion, and stops when the change is
  understood.
- The page and matching Markdown were inspected after the production build.
