# Pencil 95

Pencil 95 is a hand-drawn Windows 95-inspired design system: gray surfaces, teal desktops, navy title bars, pixel typography and visibly uneven marker outlines. It ships light and dark themes, functional color tokens, a 4px spacing scale and framework-free components.

Open `demo.html` directly for the interactive reference. Everything works offline. A static HTTP server also works. `demo.css`, `demo.js` and `demo-choices.js` belong to the reference page; applications only need `pencil-95.css` and `assets/`.

## Start a project

Copy this directory into your project's public assets, preserving the relative paths. Keep the bundled font license with the font.

```html
<link rel="stylesheet" href="/design-system/pencil-95.css">
<body class="p95" data-p95-theme="light">
  <main class="p95-window">
    <header class="p95-titlebar"><h1>A small good thing</h1></header>
    <div class="p95-window-body p95-stack">
      <label class="p95-field" for="name">Project name
        <input class="p95-input" id="name" required>
      </label>
      <button class="p95-button p95-button--primary">Save project</button>
    </div>
  </main>
</body>
```

Put `.p95` on the body or a container around the UI. Every selector and token is scoped to it. Set `data-p95-theme="dark"` on that same element for dark mode. The default is light; the kit does not read system preferences or persist a theme choice. Applications own theme selection and persistence.

## Use tokens consistently

All tokens start with `--p95-`. Color names describe their job. Avoid raw colors, arbitrary spacing, new font families and project-specific button styles. Add missing roles to the token layer first.

| Token family | Roles |
| --- | --- |
| `color-desktop`, `color-surface`, `color-paper` | Page, chrome, reading/input surfaces |
| `color-surface-hover`, `color-surface-active` | Interactive surface states |
| `color-text`, `color-text-muted`, `color-text-disabled` | Text hierarchy |
| `color-ink`, `color-edge-light`, `color-edge-shadow` | Marker outlines and secondary edges |
| `color-title`, `color-on-title` | Window title bars |
| `color-accent`, `color-on-accent` | Primary actions |
| `color-link`, `color-link-visited`, `color-focus` | Links and keyboard focus |
| `color-selection`, `color-on-selection` | Selected content |
| `color-success`, `color-warning`, `color-danger`, `color-info` | Status text and borders |
| `color-*-surface` | Background paired with each status role |
| `color-backdrop`, `color-grid` | Modal scrim and desktop texture |

The spacing scale is `space-0` through `space-8`: 0, 4, 8, 12, 16, 24, 32, 48 and 64px. Use role aliases `panel-padding`, `section-gap` and `control-gap` for layout. `p95-stack`, `p95-row` and `p95-grid` consume this scale.

The type scale is 14, 16, 20, 24, 32 and 48px. W95FA is the UI and heading face. Code uses the operating system's Courier New or monospace fallback. Avoid synthetic italics and bold for general chrome; strong emphasis in prose remains available. The font is a vector pixel-style recreation. Browser rasterization and zoom affect pixel sharpness. Latin glyphs are bundled; other scripts use the declared system fallback.

The compact breakpoint is 640px and reduces panel padding and display type. The demo adds navigation layout changes at 768px and 1024px. Supported viewport range starts at 320px. CSS variables cannot control media conditions; reuse these literal breakpoints in consuming layouts. Keep overflow in local code/table scrollers and let controls wrap. Primary actions have a 44px minimum height; other controls have a 36px minimum, with 24px title-bar controls.

## Build with primitives

| Need | Classes and semantic HTML |
| --- | --- |
| Window | `p95-window`, `p95-titlebar`, `p95-window-body`, `p95-statusbar` |
| Panels | `p95-panel` for chrome, `p95-inset` for reading surfaces |
| Actions | `p95-button`, `p95-button--primary`, `p95-button--danger` on buttons or links |
| Input | `p95-field` label + `p95-input` on input, select or textarea |
| Validation | `aria-invalid="true"`, `aria-describedby`, `p95-field-error` |
| Choice | `p95-check` label with native checkbox or radio; fieldset + legend for groups |
| Single select | `p95-choice`, `p95-input p95-choice-trigger`, `p95-menu-list p95-choice-popup`, `p95-choice-option`; labelled combobox + listbox semantics |
| Multi-select | The same trigger/popup, a named group of `p95-check` checkboxes and `p95-choice-chips` containing removable `p95-choice-chip` buttons |
| Tabs | `p95-tabs` + tablist/tab/tabpanel semantics and application-owned selection |
| Menu | Native `details.p95-menu`, `summary.p95-button`, `p95-menu-list` containing links/buttons |
| Table | `p95-table` in `p95-table-scroll`; focusable named region when horizontally scrollable |
| Status | `p95-badge` or `p95-alert` + `p95-success`, `p95-warning`, `p95-danger`, `p95-info` |
| Progress | Native `progress.p95-progress`, with a visible label and value |
| Loading | `p95-skeleton` decorative lines inside a named loading region |
| Empty state | `p95-empty` with explanation and a real next action |
| Modal | Native `dialog.p95-window.p95-dialog`, named by `aria-labelledby` |
| Visual explanation | `figure.p95-diagram.p95-inset.p95-stack` with a visible `figcaption` |
| Binary flowchart | `p95-flow`, `p95-flow-node`, decorative `p95-flow-arrow`, `p95-flow-branches` with two `p95-flow-branch` children and `p95-flow-label` conditions |
| Handoff sequence | `ol.p95-sequence` with a sender, receiver, action and result in each list item |
| Before / after | `p95-grid` with two labelled `p95-panel` sections, before first |

CSS supplies appearance and states. Application code owns actions, validation, tabs, menus and dialogs. The demo demonstrates arrow keys/Home/End for tabs, native modal focus containment and Escape dismissal, form submission/reset and pressed button state. It never sends data or saves application state. Native HTML still renders when JavaScript is disabled; demo interactions use `demo.js` and `demo-choices.js`.

Use one primary action per task. Use native disabled/readonly states. Give icon-only controls accessible names, label inputs, preserve the dotted focus ring, and pair every status color with clear text. Hand-authored SVG borders carry uneven pressure, drifting corners and short retraced strokes. Their grain filter lives inside the border assets, leaving text and hit targets undistorted. Nine-slice scaling keeps marker weight steady. Frame strokes tile at their natural spacing on both axes, so compact elements avoid compressed bends. Buttons and choice triggers use a separate single-pass outline with gentle curves, an 8px slice width and a 2px outset, keeping compact edges calm. Larger windows and panels retain the heavier retraced marker frame. Flat surfaces replace machine-perfect beveled edges. `p95-sketch` applies the shared outline to an additional container. Reduced motion and forced-color overrides are included. Theme colors are authored in paired foreground/background roles. Recheck contrast after overriding tokens.

## Choose values

The project-type example uses a fully styled select-only combobox. Arrow keys open and navigate its list, Home/End jump to enabled endpoints, typing locates an option, Enter/Space commit, and Escape cancels the pending choice. The active option uses `data-active="true"`; the committed option uses `aria-selected="true"`. Disabled options use `aria-disabled="true"` and stay out of keyboard navigation. Keep focus on the trigger and point `aria-activedescendant` at the active option only while the list is open.

The included-tools example uses a native button with `aria-expanded` and `aria-controls` to disclose a named group of checkboxes. Tab reaches the choices and Space toggles them without closing the popup. Selected values appear as removable chips. Escape returns focus to the trigger; outside interaction dismisses the popup. Removing the last chip returns focus to the trigger and shows “Choose tools.”

`demo-choices.js` is the dependency-free reference behavior. It keeps hidden native selects synchronized for `FormData`, change events and form reset. Without JavaScript those selects remain visible and usable. Applications own state, keyboard behavior and validation; direct validation feedback and focus to the visible control. Reuse the CSS with your framework's accessible controls, or adapt the reference handlers to your form.

Serve the repository over HTTP and open `src/lib/design-system/design-system-choices.browser.html` to run the choice-control regression checks against the real demo. The same-origin requirement belongs to that iframe-based test fixture; the standalone demo still works directly from disk.

## Explain with visuals

Open [Visual explanations in the demo](./demo.html#diagrams) for three worked examples of the same task: saving and reopening a draft. Each figure includes a native disclosure explaining its construction. These patterns need only `pencil-95.css` and the existing assets. They work offline, without JavaScript, in both themes.

| The reader needs to understand | Choose | Include |
| --- | --- | --- |
| Which action follows a condition | Flowchart | A start, a question, labelled outcomes and next actions |
| Who acts next and what they pass along | Handoff sequence | Ordered steps with sender, receiver, action and result |
| How an approach changes the task | Before / after | The same task and comparable detail on both sides |

Use one question per figure and short verb-led node labels. Put the takeaway in a visible caption. Keep labels and outcomes in HTML so they wrap, remain selectable and survive CSS being unavailable. Every path needs a text label; color only reinforces meaning. Decorative arrows use `aria-hidden="true"`. A diagram is explanatory content, so its nodes have no button roles or tab stops. Any real actions inside it use native links or buttons.

### Flowcharts

This binary decision layout connects one question to two outcomes. Read top to bottom, then follow the labelled branch. The caption states the same relationship in prose. Use unique caption IDs when including several figures.

```html
<figure class="p95-diagram p95-inset p95-stack"
        aria-labelledby="draft-flow-title" aria-describedby="draft-flow-summary">
  <figcaption>
    <h3 id="draft-flow-title">Open a workspace</h3>
    <p id="draft-flow-summary">If a saved copy exists, open it. Otherwise, create a draft.</p>
  </figcaption>
  <div class="p95-flow">
    <div class="p95-flow-node p95-inset">Open workspace</div>
    <span class="p95-flow-arrow" aria-hidden="true"></span>
    <div class="p95-flow-node p95-inset p95-info">Saved copy exists?</div>
    <span class="p95-flow-arrow" aria-hidden="true"></span>
    <div class="p95-flow-branches">
      <div class="p95-flow-branch">
        <p class="p95-flow-label"><span class="p95-flow-arrow" aria-hidden="true"></span>Yes</p>
        <div class="p95-flow-node p95-inset">Open saved draft</div>
      </div>
      <div class="p95-flow-branch">
        <p class="p95-flow-label"><span class="p95-flow-arrow" aria-hidden="true"></span>No</p>
        <div class="p95-flow-node p95-inset">Create a draft</div>
      </div>
    </div>
  </div>
</figure>
```

`p95-flow` stacks nodes vertically. `p95-flow-branches` supports exactly two branches; connectors are decorative CSS borders. At 640px and below, branches stack in document order. Separate side rules group the alternatives; branch arrows and horizontal connectors disappear so the outcomes do not look sequential. Keep the condition attached to its outcome. Change the heading level to fit the surrounding document.

For a linear process, omit the branches and alternate nodes with decorative arrows. For loops, many-way decisions, shared destinations or cross-links, use your project's existing diagram renderer or a hand-authored SVG with a `viewBox`, an accessible name and a visible text equivalent listing the connections. Pencil 95 includes no auto-layout or diagram engine. Use the existing color and type tokens for SVG fills, strokes and labels. Keep dense diagrams in a named, keyboard-focusable local scroller at a readable size instead of shrinking text to fit a phone.

### Handoff sequences

An ordered trace makes a request or a short timeline readable without a wide lifeline canvas. Each step names the participants and explains what happens. The numbering remains meaningful without styling.

```html
<figure class="p95-diagram p95-inset p95-stack" aria-labelledby="save-trace-title">
  <figcaption><h3 id="save-trace-title">Follow a save</h3><p>The editor confirms success after the file is written.</p></figcaption>
  <ol class="p95-sequence">
    <li class="p95-inset"><p>Editor → Workspace</p><strong>Save draft</strong><p>Send the text and file name.</p></li>
    <li class="p95-inset"><p>Workspace → Disk</p><strong>Write file</strong><p>Store the draft locally.</p></li>
    <li class="p95-inset"><p>Disk → Editor</p><strong>Confirm saved</strong><p>Show the result to the writer.</p></li>
  </ol>
</figure>
```

Use an explicit result or failure step when it changes the reader's next action. Real dates belong in `<time datetime="…">` for a timeline. A sequence's order describes the events; it does not imply measured duration.

### Before and after

Compose existing layout and panel primitives. The heading and copy carry the comparison, so it remains understandable in monochrome and when columns stack. Compare like with like; measured improvements need a source and units.

```html
<figure class="p95-diagram p95-inset p95-stack" aria-labelledby="draft-comparison-title">
  <figcaption><h3 id="draft-comparison-title">Reopen a draft</h3><p>Explicit conditions replace guesswork.</p></figcaption>
  <div class="p95-grid">
    <section class="p95-panel p95-stack" aria-labelledby="draft-before-title">
      <h4 id="draft-before-title">Before: find it yourself</h4>
      <p>Read the setup notes and guess which command comes next.</p>
    </section>
    <section class="p95-panel p95-stack" aria-labelledby="draft-after-title">
      <h4 id="draft-after-title">After: follow the signposts</h4>
      <p>Check for a saved copy. Open it, or create a new draft.</p>
    </section>
  </div>
</figure>
```

Serve the repository over HTTP and open `src/lib/design-system/design-system-diagrams.browser.html` to check the examples' text relationships and CSS-only rendering at 320, 768, 1024 and 1440px in both themes.

## Render Markdown

```html
<article class="p95-prose">
  <!-- Sanitized HTML emitted by your existing Markdown renderer. -->
</article>
```

The prose layer covers h1 through h6, paragraphs, hard breaks, strong/emphasis, links, strikethrough, ordered/unordered and nested lists, GFM task lists, nested blockquotes, inline and fenced code, tables, images, figures/captions, horizontal rules and footnotes. It also supports definition lists, keyboard hints, highlights, superscripts/subscripts and native disclosures emitted by renderer extensions. Task-list items use `.task-list-item`; footnotes use `.footnotes` and regular anchor IDs. Optional Prism-style `.token.comment`, `.token.punctuation`, `.token.keyword`, `.token.function` and `.token.string` colors are available.

Pencil 95 styles HTML. It includes no Markdown parser, sanitizer, syntax highlighter, math renderer or diagram engine. Use your project's existing renderer and sanitize untrusted HTML. Render semantic headings in order. Add `tabindex="0"` and an accessible label to overflowing code blocks, and put wide tables in a named, focusable `p95-table-scroll` wrapper. Images require descriptive alt text. Focus/selection styles apply to all prose links.

## Assets and licensing

- `assets/w95fa.css` embeds the 7.9 KB WOFF2 font as a data URL. This keeps the whole bundle text-only and offline-safe. A strict CSP must allow `font-src 'self' data:` and the local stylesheet import.
- W95FA is by Alina Sava, distributed under SIL Open Font License 1.1. The unmodified font comes from [Fontsource](https://github.com/fontsource/font-files/tree/main/fonts/other/win95fa). Its license is in `assets/FONT-LICENSE.txt`.
- `assets/frame.svg` and `assets/frame-dark.svg` are the original nine-slice marker borders, paired with each theme's ink color. The `frame-button` variants supply the calmer single-pass button outlines. The `frame-danger` variants preserve error outlines in each theme; the `rule` variants draw uneven separators. `assets/computer.svg` is the original desk illustration. `assets/icons.svg` contains original folder, disk, pencil, file, check and arrow symbols. The CSS, demo and original SVGs are available under the bundled MIT license.
- The icon sprite can be copied inline, then referenced with `<svg class="p95-icon" aria-hidden="true"><use href="#folder"></use></svg>`. External sprite references need an HTTP origin; the demo inlines its icons to work directly from disk.
- The computer illustration intentionally keeps the same light, pencil-on-paper palette in both themes.

This is an independent interpretation of classic desktop UI. It includes no Microsoft fonts, logos or original Windows assets.
