{
  "id": "v1-tm-7124",
  "long_id": "v1.terminal.app.s07.p01.t02.u04",
  "name": "Terminal, a chat client in commander blue",
  "era": {
    "slug": "terminal",
    "code": "tm",
    "name": "Terminal",
    "years": [
      2015,
      2026
    ],
    "description": "The text-terminal look of 2015 to 2026: a monospace face for everything, bright text on a dark screen, boxes and rules drawn with borders like character frames, prompts and cursors, status lines and key hints instead of buttons with chrome."
  },
  "archetype": "app",
  "mode": "mix",
  "viewport": {
    "width": 1280,
    "fluid": false,
    "responsive": true
  },
  "summary": "This is a chat client of 2015 to 2026 that dresses as the text-mode programs people ran in a terminal for the same job: a topic line at the top, a log of timed lines beside a column of names, and at the foot a bar that lists the open windows above the line you type into. One monospace face sets everything, on the blue screen of the DOS file managers and editors with their cyan bars, grey key line, yellow titles and hard black shadows. It was the look of web front ends to chat networks, of community chats of software projects, and of the dashboards their people built for themselves.",
  "url": "https://chrono.skin/s/v1-tm-7124",
  "preview_url": "https://chrono.skin/s/v1-tm-7124/specimen.html",
  "files": {
    "STYLE.md": "# Terminal, a chat client in commander blue\n\n## Summary\n\nThis is a chat client of 2015 to 2026 that dresses as the text-mode programs people ran in a terminal for the same job: a topic line at the top, a log of timed lines beside a column of names, and at the foot a bar that lists the open windows above the line you type into. One monospace face sets everything, on the blue screen of the DOS file managers and editors with their cyan bars, grey key line, yellow titles and hard black shadows. It was the look of web front ends to chat networks, of community chats of software projects, and of the dashboards their people built for themselves.\n\n## Layout\n\n- The page is designed for a 1280px window and does not stretch beyond it: `.ds-client` is a column of `--size-page` (1280px) on `--color-canvas`, at least as tall as the window. Top to bottom it holds the topic line `.ds-topbar`, `.ds-main` (the views, padded `--space-3` and `2ch`), the `.ds-footer`, and the `.ds-dock`.\n- The navigation is at the foot, not at the top. `.ds-dock` sticks to the lower edge of the window and holds `.ds-nav`, the window list on `--fill-bar-alt` (a clock, the windows as numbered words in brackets, the count of unread lines at the right), and under it `.ds-dock__input`, the line the reader types into. The window that shows is a hole in the bar: `--color-canvas` with `--color-heading`.\n- `.ds-topbar` is one line on `--fill-bar`: the `.ds-brand`, the topic of the place in `.ds-topbar__topic`, and one pulled-down `.ds-menu` at the right.\n- Every view is `.ds-cols`: the work at the left and `.ds-side`, a column of `--size-side` (260px) at the right, parted from it by one upright line that runs the height of the view. `--form` is 3 to 2 without that line (settings, help). `.ds-col` is a column that may shrink; `.ds-stack` piles frames `--space-3` apart.\n- The home view (the lobby) stacks in its left column: `.ds-hero`, the message of the day as a box that stands off the screen with `--shadow-dialog`; the `.ds-stats` line; then `.ds-section` blocks `--space-4` (32px) apart, each opened by a `.ds-section__title` rule: the `.ds-grid` of four pinned channels and the table of channels. The side column holds the names that are on, a panel about the server with two `.ds-progress` bars, and a panel of lines that named the reader.\n- Inner pages have no hero. They open with the `.ds-breadcrumb` as a path, then `.ds-page-header`, then `.ds-cols`. Notices sit directly above the log; tabs sit directly above the list they sort.\n- Views. The specimen is one small client with five views, one showing at a time; topic line, footer and dock are written once around them. `lobby` is the home view. `channel` is one channel: two notices, the `.ds-log` with a day rule, joins, a line that names the reader and a line of links, pagination to older lines, beside the names and the legend of badges. `logs` is a typed search, tabs, the list of hits, the empty state of shared files, beside the archive as a folding tree. `settings` is the account form with its error and four buttons, beside the switches and the question before a nick is dropped. `help` is the rules as running text beside the commands as a folding tree and a panel of keys. A view is `<section class=\"ds-view\" id=\"...\">`; links between views are plain `href=\"#id\"`.\n- Spacing scale, in parts of one 16px step: `--space-1` 4px is the vertical padding of bar items, buttons, inputs, table cells, tabs and log lines; `--space-2` 8px the padding above the text in a frame, the gap between a rule and what follows, between list rows and between notices; `--space-3` 16px the gap between paragraphs, between frames in a stack, under a page header and around the text of the hero; `--space-4` 32px the gap between sections and under the hero, which leaves room for its shadow; `--space-5` 48px is kept for a break larger than a section. Horizontal steps are character cells written in `ch`.\n- Fixed sizes: `--size-label` 140px the label column of a form, `--size-field` 420px a text input, `--size-date` 100px the date column of the list, `--size-dialog` 400px a dialog.\n- Below 900px there is one column: the side column goes under the work with a rule above it, the topic is left out, the window list keeps its numbers and shows a name only for the window that is open (the clock and the word before the count are left out), a log line puts time and name on one row and the text under them, the stats line and the grid become two by two, form labels sit above their fields, list dates sit above their entries, and table cells marked `.ds-table__extra` are left out. The dock stays stuck to the foot. The page never scrolls sideways.\n\n## Typography and colour roles\n\nThis style combines the parts of different styles of one era. Where a note below names a value that differs from `tokens.css`, the tokens are right.\n\n- One face for everything: `--font-body`, `--font-heading`, `--font-ui` and `--font-mono` are the same monospace stack (\"IBM Plex Mono\", \"Courier Prime\", \"Courier New\", Courier, monospace). Weights are `--weight-body` 400, `--weight-ui` 500 and 600 for bold and headings. The stack starts with IBM Plex Mono and Courier Prime and falls back to Courier New: a typewriter face suits paper. Nothing is tracked: `--heading-tracking` and `--display-tracking` are 0.\n- Sizes stay close to one size, as on a screen of character cells: `--text-base` 16px with `--line-body` 1.5 is all running text, `--text-ui` 15px navigation, buttons, inputs, tabs and pagination, `--text-small` 14px meta lines, hints, badges, code blocks and the status line, `--text-large` 18px the hero's lead and the brand name. Headings are told apart by weight and colour more than by size: `--text-display` 38px is the hero title only, `--text-h1` 26px a page title and the first heading of running text, `--text-h2` 19px section rules and second headings, `--text-h3` 16px frame titles, grid titles and third headings. `--heading-transform` is none, `--ui-transform` is lowercase.\n- Dark brown ink on warm paper, the light scheme of the era: the bars and inverse video are the ink colour, links and frame titles a burnt orange, and one blue marks flags.\n- The screen: `--color-page` #efe6c8 is the window, `--color-canvas` #fbf5dc the sheet the text stands on, `--color-surface` #fbf5dc the inside of frames and table rows, `--color-surface-alt` #f1e9c9 alternate rows, code blocks and the install line, `--color-surface-strong` #e4d9b0 group rows and inline code. `--color-text` #3b2a1a is running text, `--color-text-muted` #7a6748 dates, counts, hints and the brackets of fields, `--color-heading` #1f140a headings, typed commands and figures, `--color-heading-alt` #9a4a00 frame titles, third headings and tags.\n- Links: `--color-link` #a64b00, `--color-link-quiet` #3b2a1a for navigation, breadcrumb, tabs and sidebar links, `--color-link-visited` #6b4a6e, `--color-link-hover` #1f140a, `--color-link-active` #c2410c. `--link-decoration` is none for links in text and titles, `--link-decoration-quiet` none for navigation, and every link takes `--link-decoration-hover` (underline) when hovered. A link may also be marked by brackets (`.ds-link--bracket`).\n- Bars: `--color-bar` #3b2a1a with `--color-bar-text` #fbf5dc is the head row of a table and, where a layout has one, the menu line and the labels of the key bar. `--color-bar-alt` #e4d9b0 with `--color-bar-alt-text` #3b2a1a is the status line at the foot. `--color-inverse` #3b2a1a with `--color-inverse-text` #fbf5dc is inverse video: the current navigation link, tab, page number and sidebar link, the selected table row, a text selection.\n- Lines: `--color-border` #8c7a58 at `--border-width` 1px `--border-style` dashed draws every frame and rule; `--color-border-strong` #3b2a1a at `--border-width-strong` 3px is the rule under a page header, the left edge of a notice and the frame of a dialog; `--color-border-muted` #cfc39c parts rows inside a frame and boxes the empty state.\n- Accents: `--color-accent` #c2410c with `--color-accent-text` #fffbdc is the count badge; `--color-accent-alt` #1a6fb0 is the prompt sign and flag letters. `--color-fill-1` to `--color-fill-4` (#fbf5dc, #f1e9c9, #e4d9b0, #f1e9c9) are the four grid cells. Status words are text in brackets: `--color-success` #3d7a1c, `--color-warning` #a86400, `--color-danger` #b3123f; meters use the first two.\n- Controls: the primary button is `--color-button` #3b2a1a with `--color-button-text` #fbf5dc; the secondary button is `--fill-button-secondary` with `--color-button-secondary-text` #3b2a1a and a frame in `--color-border`; fields are `--fill-input` with `--color-input-text` #1f140a and a line in `--color-input-border` #8c7a58; disabled is `--color-disabled` #e4d9b0 with `--color-disabled-text` #9c8c6a. The notice is `--color-notice` #f1e9c9 with `--color-notice-text` #3b2a1a, the error notice `--color-danger-surface` #f8e1d4 with `--color-danger`. `--color-overlay` #e4d9b0 is the block a dialog stands on; `--color-focus` #c2410c is the focus outline.\n- Surface: Lines are dashed, the way a frame is typed with hyphens, and the heavy rule is 3px. `--fill-panel` is transparent, so frames show the canvas; `--fill-button-secondary` and `--fill-input` are their own colours; `--fill-button-hover` darkens the button (80% of it over black). The only shadows are states drawn with hard lines: `--shadow-control-hover` is a 2px underline in `--color-border-strong`, `--shadow-control-pressed` a 1px inner line; `--shadow-panel`, `--shadow-control`, `--shadow-dialog` and `--shadow-text` are none. All four radii are 0 and `--backdrop-blur` is 0px. `--focus-ring` is 2px dashed var(--color-focus); `--transition` is none: states change at once. The only motion is the blinking `.ds-cursor`, and only under `prefers-reduced-motion: no-preference`.\n- The era's rule for which text stands on which fill (all three layouts keep it, so any palette works with any layout): `--color-text`, `--color-text-muted`, the two heading colours, every link colour and the three status colours stand on `--fill-page`, `--color-canvas`, the three surfaces, `--fill-panel` and the four fills, and on nothing else. `--color-bar-text` only on `--fill-bar`; `--color-bar-alt-text` only on `--fill-bar-alt`; `--color-inverse-text` only on `--fill-inverse`; `--color-accent-text` only on `--fill-accent`; `--color-button-text` and `--color-button-hover-text` only on `--fill-button` and its hover; `--color-notice-text` only on `--color-notice`; `--color-danger` also on `--color-danger-surface`; `--color-disabled-text` on `--color-disabled`. Two tokens must read in two places, because a surface set may leave a control unfilled: `--color-button-secondary-text` on `--fill-button-secondary` and on the canvas and surfaces, `--color-input-text` on `--fill-input` and on the canvas and surfaces. Where the navigation stands on `--fill-bar`, its current item is a hole in the bar: `--color-canvas` with `--color-heading`. Nothing but a button, a badge or a key label stands on a bar or an inverse block.\n- One-off sizes written with `calc()` or `ch`: a frame title is lifted by half of `--text-h3` times `--line-body` so that the frame's top line runs through it; the brand tile is one text line square (`--text-base` times `--line-body`); horizontal paddings and column gaps are whole character cells (`1ch`, `2ch`, `3ch`, `4ch`); the checkbox is `2ch` square.\n\n## Components\n\n- `.ds-page` on `<body>`: page fill and base type, no margin. `.ds-client` is the screen; `.ds-main` holds the views; `.ds-cols` (`--form`) are the column pairs, `.ds-col` a column, `.ds-side` the column of names at the right, `.ds-stack` a pile of frames, `.ds-section` a block of the page.\n- `.ds-nav`: the window list in the dock at the foot. `.ds-nav__clock` is the time in brackets, `.ds-nav__list` holds `.ds-nav__link` items, each a `.ds-nav__num` and a `.ds-nav__name` in brackets, and `.ds-nav__act` at the right holds a `.ds-nav__word` and the count of unread lines as a `.ds-badge`. The stylesheet marks the link whose `href` names the view that is showing (one selector per view, and the first when the address names none); on a page of its own give the link `is-current`. `.ds-dock` is the sticky block around it; `.ds-dock__input` is the input line: `.ds-dock__who`, the reader's name in brackets, and a `.ds-form__input`.\n- `.ds-topbar`: the topic line at the top, on `--fill-bar`: the brand, `.ds-topbar__topic` (one line, cut with an ellipsis) and a `.ds-menu`.\n- `.ds-hero`: the message of the day on the home view: a box in `--color-border-strong` with a heavy left edge and `--shadow-dialog`. It holds `.ds-hero__motd` (a small line opened by `.ds-hero__sign`, the `-!-` of a server line), `.ds-hero__title` (`--text-display`), `.ds-hero__lead`, a `.ds-buttons` row and `.ds-hero__note`.\n- `.ds-footer`: one quiet line above the dock, with a faint rule: a `.ds-keys` list of `.ds-footer__link` items and `.ds-footer__text` at the right.\n- `.ds-brand`: the site's mark and name, a link to the home view, first thing in the topic line. `.ds-brand__mark` is a tile one text line square, dressed like the primary button (`--fill-button`, `--color-button-text`, `--radius-control`) with a line in the bar's text colour; `.ds-brand__name` is bold at `--text-large`. The name `chronoskin` and the mark are placeholders for the installing project's own name and logo.\n- `.ds-breadcrumb`: a path: `.ds-breadcrumb__link` items with `.ds-breadcrumb__sep` (`/`) between them, ending in a bold `.ds-breadcrumb__current`.\n- `.ds-page-header`: the head of an inner page: `.ds-page-header__main` with `.ds-page-header__title` (`--text-h1`) and one muted `.ds-page-header__text` line (in a channel, its topic); `.ds-page-header__action` at the right holds one button. A rule of `--border-width-strong` closes it.\n- `.ds-prose`: running text, at most 78 characters wide: h1, h2, h3, paragraphs, lists whose bullet is a typed dash, `code` on `--color-surface-strong`, `strong` in the heading colour. Anything typed literally goes in `.ds-code`, a `<pre>` at `--text-small` on `--color-surface-alt` in a frame; it scrolls sideways inside itself.\n- `.ds-link`: text link with `is-visited`, `is-hover`, `is-active`, `is-focus`. `.ds-link--quiet` for meta and tool links, `.ds-link--bracket` for a link written as a word in brackets. `.ds-links` sets several in a wrapping line.\n- `.ds-button`: a `<button>`, or an `<a>` when it only leads to another view. It is a word in square brackets, which the stylesheet adds. The primary one is a block of `--fill-button`; `.ds-button--secondary` is a frame in `--color-border`; `.ds-button--danger` is the destructive action in `--color-danger` on `--color-danger-surface`; `disabled` or `is-disabled` is greyed. `is-hover`, `is-active` and `is-focus` show the states. Group with `.ds-buttons`.\n- `.ds-form`: rows (`.ds-form__row`) of a `.ds-form__label` and a `.ds-form__field`. Controls take `.ds-form__input` (`--wide` for the full width, `--auto` for selects). `is-invalid` plus a bold `.ds-form__error` marks a validation error, `.ds-form__hint` is help text, `.ds-form__check` holds a `.ds-form__checkbox` (one empty cell, a filled block when set), and `.ds-form__actions` lines the buttons up with the fields.\n- `.ds-table`: aligned columns under a head row on `--fill-bar`. `.ds-table__num` right-aligns a numeric column, `.ds-table__code` is a bold first column, `.ds-table__date` a muted one, `tr.is-alt` an alternate row, `.ds-table__group` a group row, `tr.is-selected` the row under the cursor in inverse video, `tr.is-unread` a bold row, `.ds-table__title` the link in a row, `.ds-table__extra` cells a phone leaves out.\n- `.ds-list`: dated entries, here the hits of a search. Each `.ds-list__item` is a muted `.ds-list__date` in a `--size-date` column and a `.ds-list__main` with a bold `.ds-list__title` link, a `.ds-list__excerpt` and a small `.ds-list__meta` line; faint rules part the items.\n- `.ds-log`: the lines of a channel, an ordered list. A `.ds-log__line` is a `.ds-log__time`, a right-aligned bold `.ds-log__nick` and the `.ds-log__text` behind an upright line. `.ds-log__line--event` is a muted server line (a join, a mode change) whose name is `-!-`; `is-mention` sets a line that names the reader on `--color-surface-strong` with a mark in `--color-accent` at its left edge; `.ds-log__day` is the rule with the date that parts two days.\n- `.ds-panel`: a frame with its `.ds-panel__title` cut into the top line, and a `.ds-panel__body` of `.ds-panel__text` paragraphs. The title row draws the top line itself, so the frame works on any fill and with any border style; a panel always has a title.\n- `.ds-stat`: one figure: a `.ds-stat__value` at `--text-h1` followed on the same line by a small muted `.ds-stat__label`. `.ds-stats` is the row: four figures between two rules, parted by upright rules.\n- `.ds-grid`: four `.ds-grid__cell` boxes (four across, two by two on a phone), each a frame on `--color-fill-1` (`--2`, `--3`, `--4` select the other fills), with a `.ds-grid__title`, `.ds-grid__text` and a muted `.ds-grid__label`.\n- `.ds-tabs`: a row of words on a rule; each `.ds-tabs__tab` is a link, the current one a `<span class=\"ds-tabs__tab is-current\">` in inverse video. Content goes in `.ds-tabs__body`.\n- `.ds-badge`: a count: bold `--text-small` on `--fill-accent`. `.ds-badge--tag` is a word after a `#` in `--color-heading-alt`. Status labels are `.ds-badge--success`, `.ds-badge--warning` and `.ds-badge--danger`: a word in brackets in the status colour, with no fill and no frame. `.ds-badges` sets several in a line.\n- `.ds-sidebar`: the names of a channel, in the side column at the right. Each `.ds-sidebar__block` is a frame with a `.ds-sidebar__title` cut into its top line and a `.ds-sidebar__list` of `.ds-sidebar__link` items (`is-current` in inverse video), each opened by a `.ds-avatar` and followed by an optional `.ds-sidebar__count` (a sign or a word); `.ds-sidebar__text` is a small muted paragraph.\n- `.ds-notice`: a sentence in a frame of `--color-border-strong` with a heavy left edge, starting with a bold `.ds-notice__title`. `.ds-notice--error` uses `--color-danger` on `--color-danger-surface`. Stack several in `.ds-notices`.\n- `.ds-pagination`: a line of `.ds-pagination__link` items: older, numbers, newer. The current page is a `<span>` with `is-current` in inverse video; `is-disabled` is muted.\n- `.ds-dialog`: a frame in `--color-border-strong`, `--size-dialog` wide, with `--shadow-dialog`. It sits in the page flow on `.ds-dialog__backdrop`, a flat block of `--color-overlay`; it has a `.ds-dialog__title`, a `.ds-dialog__body`, `.ds-dialog__text` and `.ds-dialog__actions`. No dimming of the page, no blur.\n- `.ds-empty`: a faint frame with a centred muted `.ds-empty__text` sentence and one secondary button.\n- `.ds-menu`: a pulled-down menu, a `<details>` in a bar. `.ds-menu__title` is its `<summary>`, a word in brackets with a `v`; open, it is a hole in the bar. `.ds-menu__list` is the framed list under it, on `--color-surface` with `--shadow-dialog`; each `.ds-menu__item` is a link with its command in a muted `.ds-menu__key` at the right, inverse video when hovered (`is-hover`); `.ds-menu__rule` parts two groups. It is closed until asked for.\n- `.ds-accordion`: a folding tree. Each `.ds-accordion__item` is a `<details>`; its `.ds-accordion__title` is the `<summary>`, marked `[+]` when closed and `[-]` when open; `.ds-accordion__body` is indented four cells.\n- `.ds-tooltip`: a word with a dotted underline that can take the focus; its `.ds-tooltip__tip` is a small boxed hint on `--color-surface-strong` that shows above it on hover or focus (`is-open` shows it statically).\n- `.ds-switch`: an on/off setting, a `<label>` holding `.ds-switch__label`, a hidden `.ds-switch__input` checkbox and `.ds-switch__track`, which draws the pair `on` `off`; the half that holds is inverse video. `.ds-setting` is a ruled row for one.\n- `.ds-progress`: a quantity: a muted `.ds-progress__label`, a `.ds-progress__bar` typed in cells between brackets (`#` for the filled part in `.ds-progress__on`, `.` for the rest; `--warning` and `--danger` recolour it) and a bold `.ds-progress__value`.\n- `.ds-avatar`: a person as two initials in a cell on `--color-surface-strong`; `--2` and `--3` use two of the block fills. Used before a name in the lists of names.\n- Text-mode pieces: `.ds-prompt` is a typed command line (`.ds-prompt__sign` the command, `.ds-prompt__path` its option); `.ds-cursor` is the block cursor; `.ds-key` is a key hint whose `.ds-key__cap` is set in brackets, several in a `.ds-keys` line; `.ds-meter` is the older name of a typed bar; `.ds-section__title` is a heading followed by a rule to the right edge; `.ds-note` is a small muted line under a block.\n\n## Never\n\n- `font-families <= 1`: one monospace face sets everything, headings and buttons included.\n- `font-size <= 38px`: the largest text is the hero title; everything else is within a few pixels of the body size.\n- `font-size >= 14px`: small text is the meta size; nothing is set smaller.\n- `letter-spacing <= 0px`: the grid of the typeface is never stretched.\n- `line-height <= 1.6`: lines sit as close as a terminal sets them.\n- `border-radius <= 0px`: a character cell has no round corner; every box, button and field is square.\n- `box-shadow-blur <= 0px`: a shadow is a hard block set off to the right and below, never soft.\n- `gradient-fills <= 0%`: every fill is one flat colour.\n- `border-width <= 2px`: there is one weight of line.\n- `text-shadow = none`: ink does not glow.\n- `transition = none`: states change at once, as a screen redraws.\n\n## Extending\n\nDerive a new component from the nearest one in the specimen. A boxed thing copies `.ds-panel`: a frame of `--border-width` in `--color-border` with its title cut into the top line and `--space-2` and `2ch` of padding. A row type copies a `.ds-log__line`, a `.ds-table` row or a `.ds-list__item`. A set of choices copies `.ds-tabs`, and whatever is current or selected is inverse video (`--fill-inverse` with `--color-inverse-text`), or a hole when it stands in a bar. A status is a word in brackets in its status colour; a quantity is a `.ds-progress` typed in cells; a setting that is on or off is a `.ds-switch`; an action is a word dressed as `.ds-button`, or a line in a `.ds-menu` when the bar should offer it. Use only the tokens of `tokens.css` and the `--size-*` and `--space-*` tokens of `components.css`, write horizontal steps in `ch`, and pair each text token with its own fill as listed above. When in doubt do less: text before a box, a rule before a fill, a typed character before an icon, and never a radius, a soft shadow, a picture or a second typeface.\n",
    "components.css": "/* Layout tokens (structure part). Vertical steps are quarters, halves and\n   multiples of one 16px step; horizontal steps are written in ch. */\n:root {\n  --size-page: 1280px;\n  --size-side: 260px;\n  --size-label: 140px;\n  --size-field: 420px;\n  --size-dialog: 400px;\n  --size-date: 100px;\n  --space-1: 4px;\n  --space-2: 8px;\n  --space-3: 16px;\n  --space-4: 32px;\n  --space-5: 48px;\n}\n\n/* ---------- shell: one face, one size, a screen of text ---------- */\n.ds-page {\n  margin: 0;\n  padding: 0;\n  background: var(--fill-page);\n  color: var(--color-text);\n  font-family: var(--font-body);\n  font-size: var(--text-base);\n  font-weight: var(--weight-body);\n  line-height: var(--line-body);\n}\n/* Selection is inverse video. */\n.ds-page ::selection {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n}\n/* ---------- views: one screen of the example site shows at a time ---------- */\n.ds-view { display: none; }\n.ds-view:target, .ds-page:not(:has(.ds-view:target)) .ds-view--home { display: block; }\n.ds-view:target { scroll-margin-top: 100vh; }\n\n/* ---------- frames: a box of 1-cell lines with its title cut into the top edge.\n   The top edge is drawn by the title row (a short rule, the title, a long rule),\n   so it works on any fill and with any border style. ---------- */\n.ds-panel,\n.ds-dialog,\n.ds-sidebar__block,\n.ds-term {\n  position: relative;\n  display: flow-root;\n  box-sizing: border-box;\n  min-width: 0;\n  margin: calc(var(--text-h3) * var(--line-body) * 0.5) 0 0;\n  border: var(--border-width) var(--border-style) var(--color-border);\n  border-top: 0;\n  border-radius: var(--radius-panel);\n  background: var(--fill-panel);\n  box-shadow: var(--shadow-panel);\n}\n.ds-panel__title,\n.ds-dialog__title,\n.ds-sidebar__title,\n.ds-term__title {\n  display: flex;\n  align-items: center;\n  gap: 1ch;\n  margin: calc(var(--text-h3) * var(--line-body) * -0.5) calc(var(--border-width) * -1) 0;\n  padding: 0;\n  overflow: hidden;\n  white-space: nowrap;\n  color: var(--color-heading-alt);\n  font-family: var(--font-heading);\n  font-size: var(--text-h3);\n  font-weight: var(--weight-heading);\n  line-height: var(--line-body);\n  letter-spacing: var(--heading-tracking);\n  text-transform: var(--heading-transform);\n}\n.ds-panel__title::before,\n.ds-dialog__title::before,\n.ds-sidebar__title::before,\n.ds-term__title::before {\n  content: \"\";\n  flex: none;\n  width: 1ch;\n  border-top: var(--border-width) var(--border-style) var(--color-border);\n}\n.ds-panel__title::after,\n.ds-dialog__title::after,\n.ds-sidebar__title::after,\n.ds-term__title::after {\n  content: \"\";\n  flex: 1;\n  min-width: 1ch;\n  border-top: var(--border-width) var(--border-style) var(--color-border);\n}\n.ds-panel__body {\n  padding: var(--space-2) 2ch var(--space-3);\n}\n.ds-panel__text {\n  margin: 0 0 var(--space-2);\n}\n.ds-panel__text:last-child {\n  margin-bottom: 0;\n}\n\n/* ---------- a section rule: the name, then a line to the right edge ---------- */\n.ds-section {\n  margin: 0 0 var(--space-4);\n}\n.ds-section__title {\n  display: flex;\n  align-items: center;\n  gap: 1ch;\n  margin: var(--space-3) 0 var(--space-2);\n  color: var(--color-heading);\n  font-family: var(--font-heading);\n  font-size: var(--text-h2);\n  font-weight: var(--weight-heading);\n  line-height: var(--line-heading);\n  letter-spacing: var(--heading-tracking);\n  text-transform: var(--heading-transform);\n}\n.ds-section__title:first-child {\n  margin-top: 0;\n}\n.ds-section__title::after {\n  content: \"\";\n  flex: 1;\n  border-top: var(--border-width) var(--border-style) var(--color-border);\n}\n.ds-note:last-child {\n  margin-bottom: 0;\n}\n.ds-note {\n  margin: var(--space-2) 0 var(--space-3);\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n\n/* ---------- prompt, cursor, key hints, meters ---------- */\n.ds-prompt {\n  margin: 0 0 var(--space-2);\n  color: var(--color-heading);\n  font-family: var(--font-mono);\n  font-weight: var(--weight-bold);\n  overflow-wrap: anywhere;\n}\n.ds-prompt__sign {\n  color: var(--color-accent-alt);\n}\n.ds-prompt__path {\n  color: var(--color-heading-alt);\n}\n/* The block cursor: one cell of inverse video. It holds a no-break space. */\n.ds-cursor {\n  background: currentColor;\n}\n@media (prefers-reduced-motion: no-preference) {\n  .ds-cursor {\n    animation: ds-blink 1.2s steps(1) infinite;\n  }\n}\n@keyframes ds-blink {\n  0% { opacity: 1; }\n  50% { opacity: 0; }\n  100% { opacity: 0; }\n}\n.ds-key {\n  white-space: nowrap;\n}\n.ds-key__cap {\n  font-weight: var(--weight-bold);\n}\n.ds-key__cap::before {\n  content: \"[\";\n}\n.ds-key__cap::after {\n  content: \"]\";\n}\n/* A progress bar typed in block characters. */\n.ds-meter {\n  color: var(--color-border);\n  white-space: nowrap;\n}\n.ds-code {\n  box-sizing: border-box;\n  max-width: 100%;\n  margin: 0 0 var(--space-3);\n  padding: var(--space-2) 2ch;\n  overflow-x: auto;\n  border: var(--border-width) var(--border-style) var(--color-border);\n  border-radius: var(--radius-panel);\n  background: var(--color-surface-alt);\n  color: var(--color-text);\n  font-family: var(--font-mono);\n  font-size: var(--text-small);\n  line-height: var(--line-body);\n  white-space: pre;\n}\n.ds-code:last-child {\n  margin-bottom: 0;\n}\n\n/* ---------- links ---------- */\n.ds-link {\n  color: var(--color-link);\n  text-decoration: var(--link-decoration);\n}\n.ds-link:visited,\n.ds-link.is-visited {\n  color: var(--color-link-visited);\n}\n.ds-link:hover,\n.ds-link.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-link:active,\n.ds-link.is-active {\n  color: var(--color-link-active);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-link:focus-visible,\n.ds-link.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-link--quiet,\n.ds-link--quiet:visited,\n.ds-link--quiet.is-visited {\n  color: var(--color-link-quiet);\n  text-decoration: var(--link-decoration-quiet);\n}\n.ds-link--quiet:hover,\n.ds-link--quiet.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n/* A link marked by brackets instead of an underline: [copy]. */\n.ds-link--bracket,\n.ds-link--bracket:visited {\n  color: var(--color-link);\n  text-decoration: none;\n  white-space: nowrap;\n}\n.ds-link--bracket::before {\n  content: \"[\";\n}\n.ds-link--bracket::after {\n  content: \"]\";\n}\n.ds-links {\n  display: flex;\n  flex-wrap: wrap;\n  gap: var(--space-1) 3ch;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n\n/* ---------- brand: the mark on a one-line tile dressed like the primary button ---------- */\n.ds-brand {\n  display: inline-flex;\n  align-items: center;\n  gap: 1ch;\n  color: var(--color-heading);\n  text-decoration: none;\n}\n.ds-brand__mark {\n  flex: none;\n  display: block;\n  box-sizing: border-box;\n  width: calc(var(--text-base) * var(--line-body));\n  height: calc(var(--text-base) * var(--line-body));\n  border: var(--border-width) var(--border-style) var(--color-button);\n  border-radius: var(--radius-control);\n  background: var(--fill-button);\n  box-shadow: var(--shadow-control);\n  color: var(--color-button-text);\n}\n.ds-brand__mark svg {\n  display: block;\n  width: 100%;\n  height: 100%;\n}\n.ds-brand__name {\n  font-family: var(--font-heading);\n  font-size: var(--text-large);\n  font-weight: var(--weight-display);\n  line-height: var(--line-heading);\n  letter-spacing: var(--display-tracking);\n  text-shadow: var(--shadow-text);\n}\n.ds-brand:hover .ds-brand__name,\n.ds-brand.is-hover .ds-brand__name {\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-brand:focus-visible,\n.ds-brand.is-focus {\n  outline: var(--focus-ring);\n}\n\n/* ---------- breadcrumb: a path ---------- */\n.ds-breadcrumb {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0 1ch;\n  margin: 0 0 var(--space-2);\n  padding: 0;\n  list-style: none;\n}\n.ds-breadcrumb__link {\n  color: var(--color-link-quiet);\n  text-decoration: var(--link-decoration-quiet);\n}\n.ds-breadcrumb__link:hover,\n.ds-breadcrumb__link.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-breadcrumb__sep {\n  color: var(--color-text-muted);\n}\n.ds-breadcrumb__current {\n  color: var(--color-heading);\n  font-weight: var(--weight-bold);\n}\n\n/* ---------- page header: title, one line, an action at the right, a heavy rule ---------- */\n.ds-page-header {\n  display: flex;\n  justify-content: space-between;\n  align-items: flex-end;\n  gap: var(--space-2) 2ch;\n  margin: 0 0 var(--space-3);\n  padding: 0 0 var(--space-2);\n  border-bottom: var(--border-width-strong) var(--border-style) var(--color-border-strong);\n}\n.ds-page-header__main {\n  min-width: 0;\n}\n.ds-page-header__title {\n  margin: 0;\n  color: var(--color-heading);\n  font-family: var(--font-heading);\n  font-size: var(--text-h1);\n  font-weight: var(--weight-heading);\n  line-height: var(--line-heading);\n  letter-spacing: var(--heading-tracking);\n  text-transform: var(--heading-transform);\n  text-shadow: var(--shadow-text);\n}\n.ds-page-header__text {\n  margin: var(--space-1) 0 0;\n  color: var(--color-text-muted);\n}\n.ds-page-header__action {\n  flex: none;\n}\n\n/* ---------- stats ---------- */\n.ds-stats {\n  display: grid;\n  grid-template-columns: repeat(4, minmax(0, 1fr));\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.ds-stat {\n  min-width: 0;\n}\n.ds-stat__value {\n  color: var(--color-heading);\n  font-family: var(--font-heading);\n  font-weight: var(--weight-display);\n}\n.ds-stat__label {\n  color: var(--color-text-muted);\n}\n\n/* ---------- prose ---------- */\n.ds-prose {\n  max-width: 78ch;\n}\n.ds-prose h1,\n.ds-prose h2,\n.ds-prose h3 {\n  margin: 0 0 var(--space-2);\n  color: var(--color-heading);\n  font-family: var(--font-heading);\n  font-weight: var(--weight-heading);\n  line-height: var(--line-heading);\n  letter-spacing: var(--heading-tracking);\n  text-transform: var(--heading-transform);\n}\n.ds-prose h1 {\n  font-size: var(--text-h1);\n}\n.ds-prose h2 {\n  margin-top: var(--space-4);\n  font-size: var(--text-h2);\n}\n.ds-prose h3 {\n  margin-top: var(--space-3);\n  font-size: var(--text-h3);\n  color: var(--color-heading-alt);\n}\n.ds-prose p {\n  margin: 0 0 var(--space-3);\n}\n.ds-prose ul,\n.ds-prose ol {\n  margin: 0 0 var(--space-3);\n  padding: 0 0 0 3ch;\n}\n.ds-prose ul {\n  list-style-type: \"- \";\n  padding-left: 2ch;\n}\n.ds-prose code {\n  padding: 0 0.5ch;\n  background: var(--color-surface-strong);\n  color: var(--color-heading);\n  font-family: var(--font-mono);\n}\n.ds-prose strong {\n  color: var(--color-heading);\n  font-weight: var(--weight-bold);\n}\n.ds-prose > :first-child {\n  margin-top: 0;\n}\n.ds-prose > :last-child {\n  margin-bottom: 0;\n}\n\n/* ---------- buttons: a word in brackets, the primary one in inverse video ---------- */\n.ds-buttons {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: var(--space-2) 2ch;\n}\n.ds-button {\n  display: inline-block;\n  box-sizing: border-box;\n  margin: 0;\n  padding: var(--space-1) 1ch;\n  border: var(--border-width) var(--border-style) var(--color-button);\n  border-radius: var(--radius-control);\n  background: var(--fill-button);\n  box-shadow: var(--shadow-control);\n  color: var(--color-button-text);\n  font-family: var(--font-ui);\n  font-size: var(--text-ui);\n  font-weight: var(--weight-ui);\n  line-height: var(--line-body);\n  text-transform: var(--ui-transform);\n  text-decoration: none;\n  white-space: nowrap;\n  transition: var(--transition);\n  cursor: pointer;\n}\n.ds-button::before {\n  content: \"[ \";\n}\n.ds-button::after {\n  content: \" ]\";\n}\n.ds-button:hover,\n.ds-button.is-hover {\n  background: var(--fill-button-hover);\n  box-shadow: var(--shadow-control-hover);\n  color: var(--color-button-hover-text);\n}\n.ds-button:active,\n.ds-button.is-active {\n  box-shadow: var(--shadow-control-pressed);\n}\n.ds-button:focus-visible,\n.ds-button.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-button--secondary,\n.ds-button--secondary:hover,\n.ds-button--secondary.is-hover {\n  border-color: var(--color-border);\n  background: var(--fill-button-secondary);\n  color: var(--color-button-secondary-text);\n}\n.ds-button--secondary:hover,\n.ds-button--secondary.is-hover {\n  border-color: var(--color-border-strong);\n}\n.ds-button--danger,\n.ds-button--danger:hover,\n.ds-button--danger.is-hover {\n  border-color: var(--color-danger);\n  background: var(--color-danger-surface);\n  color: var(--color-danger);\n}\n.ds-button:disabled,\n.ds-button.is-disabled {\n  border-color: var(--color-border-muted);\n  background: var(--color-disabled);\n  box-shadow: none;\n  color: var(--color-disabled-text);\n  cursor: default;\n}\n\n/* ---------- form ---------- */\n.ds-form {\n  margin: 0;\n}\n.ds-form__row {\n  display: grid;\n  grid-template-columns: var(--size-label) minmax(0, 1fr);\n  gap: 0 2ch;\n  align-items: start;\n  margin: 0 0 var(--space-2);\n}\n.ds-form__label {\n  padding: var(--space-1) 0;\n  color: var(--color-heading);\n}\n.ds-form__field {\n  min-width: 0;\n}\n.ds-form__input {\n  box-sizing: border-box;\n  width: 100%;\n  max-width: var(--size-field);\n  margin: 0;\n  padding: var(--space-1) 1ch;\n  border: var(--border-width) var(--border-style) var(--color-input-border);\n  border-radius: var(--radius-control);\n  background: var(--fill-input);\n  box-shadow: var(--shadow-control);\n  color: var(--color-input-text);\n  font-family: var(--font-ui);\n  font-size: var(--text-ui);\n  line-height: var(--line-body);\n  transition: var(--transition);\n}\n.ds-form__input--wide {\n  max-width: none;\n}\n.ds-form__input--auto {\n  width: auto;\n}\n.ds-form__input:focus-visible,\n.ds-form__input.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-form__input:disabled,\n.ds-form__input.is-disabled {\n  background: var(--color-disabled);\n  color: var(--color-disabled-text);\n}\n.ds-form__input.is-invalid {\n  border-color: var(--color-danger);\n}\n.ds-form__error {\n  margin: var(--space-1) 0 0;\n  color: var(--color-danger);\n  font-weight: var(--weight-bold);\n}\n.ds-form__hint {\n  margin: var(--space-1) 0 0;\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n.ds-form__check {\n  display: flex;\n  align-items: center;\n  gap: 1ch;\n  padding: var(--space-1) 0;\n}\n/* A checkbox is one cell: an empty box, or a filled block when set. */\n.ds-form__checkbox {\n  appearance: none;\n  flex: none;\n  box-sizing: border-box;\n  width: 2ch;\n  height: 2ch;\n  margin: 0;\n  border: var(--border-width) var(--border-style) var(--color-input-border);\n  border-radius: var(--radius-control);\n  background: var(--fill-input);\n}\n.ds-form__checkbox:checked {\n  border-style: solid;\n  background: var(--color-input-text);\n}\n.ds-form__checkbox:focus-visible {\n  outline: var(--focus-ring);\n}\n.ds-form__actions {\n  display: flex;\n  flex-wrap: wrap;\n  gap: var(--space-2) 2ch;\n  margin: var(--space-3) 0 0;\n  padding-left: calc(var(--size-label) + 2ch);\n}\n\n/* ---------- table: aligned columns under a head line in the bar colours ---------- */\n.ds-table {\n  width: 100%;\n  border-collapse: collapse;\n  border-radius: var(--radius-panel);\n}\n.ds-table th,\n.ds-table td {\n  padding: var(--space-1) 1ch;\n  border-style: var(--border-style);\n  border-color: var(--color-border-muted);\n  border-width: 0 0 var(--border-width);\n  text-align: left;\n  vertical-align: top;\n}\n.ds-table th {\n  background: var(--fill-bar);\n  color: var(--color-bar-text);\n  border-color: var(--color-border);\n  font-family: var(--font-heading);\n  font-weight: var(--weight-bold);\n  text-transform: var(--heading-transform);\n  white-space: nowrap;\n}\n.ds-table td {\n  background: var(--color-surface);\n}\n.ds-table tr.is-alt td,\n.ds-table__row--alt td {\n  background: var(--color-surface-alt);\n}\n.ds-table th.ds-table__num,\n.ds-table td.ds-table__num {\n  text-align: right;\n  white-space: nowrap;\n}\n.ds-table td.ds-table__code {\n  color: var(--color-heading);\n  font-family: var(--font-mono);\n  font-weight: var(--weight-bold);\n  white-space: nowrap;\n}\n.ds-table td.ds-table__date {\n  color: var(--color-text-muted);\n  white-space: nowrap;\n}\n.ds-table__group td {\n  background: var(--color-surface-strong);\n  color: var(--color-heading-alt);\n  font-weight: var(--weight-bold);\n}\n/* The row under the cursor: inverse video. */\n.ds-table tr.is-selected td {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n}\n.ds-table tr.is-selected .ds-table__title {\n  color: var(--color-inverse-text);\n}\n.ds-table tr.is-unread td {\n  font-weight: var(--weight-bold);\n}\n.ds-table__title {\n  color: var(--color-link);\n  text-decoration: var(--link-decoration);\n}\n.ds-table__title:visited,\n.ds-table__title.is-visited {\n  color: var(--color-link-visited);\n}\n.ds-table__title:hover,\n.ds-table__title.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n\n/* ---------- list ---------- */\n.ds-list {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.ds-list__item {\n  display: grid;\n  grid-template-columns: var(--size-date) minmax(0, 1fr);\n  gap: 0 2ch;\n  padding: var(--space-2) 0;\n  border-bottom: var(--border-width) var(--border-style) var(--color-border-muted);\n}\n.ds-list__item:first-child {\n  padding-top: 0;\n}\n.ds-list__item:last-child {\n  padding-bottom: 0;\n  border-bottom: 0;\n}\n.ds-list__date {\n  color: var(--color-text-muted);\n  white-space: nowrap;\n}\n.ds-list__main {\n  min-width: 0;\n}\n.ds-list__title {\n  color: var(--color-link);\n  font-weight: var(--weight-bold);\n  text-decoration: var(--link-decoration);\n}\n.ds-list__title:visited,\n.ds-list__title.is-visited {\n  color: var(--color-link-visited);\n}\n.ds-list__title:hover,\n.ds-list__title.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-list__excerpt {\n  margin: 0;\n}\n.ds-list__meta {\n  margin: 0;\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n\n/* ---------- grid: four framed cells on the block fills ---------- */\n.ds-grid {\n  display: grid;\n  grid-template-columns: repeat(4, minmax(0, 1fr));\n  gap: var(--space-2) 2ch;\n}\n.ds-grid__cell {\n  min-width: 0;\n  padding: var(--space-2) 2ch var(--space-3);\n  border: var(--border-width) var(--border-style) var(--color-border);\n  border-radius: var(--radius-page);\n  background: var(--color-fill-1);\n}\n.ds-grid__cell--2 {\n  background: var(--color-fill-2);\n}\n.ds-grid__cell--3 {\n  background: var(--color-fill-3);\n}\n.ds-grid__cell--4 {\n  background: var(--color-fill-4);\n}\n.ds-grid__label {\n  margin: 0;\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n.ds-grid__title {\n  margin: 0 0 var(--space-1);\n  color: var(--color-heading);\n  font-family: var(--font-heading);\n  font-size: var(--text-h3);\n  font-weight: var(--weight-heading);\n  line-height: var(--line-heading);\n  letter-spacing: var(--heading-tracking);\n  text-transform: var(--heading-transform);\n}\n.ds-grid__text {\n  margin: 0;\n}\n\n/* ---------- tabs: words on a rule, the current one in inverse video ---------- */\n.ds-tabs {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0 1ch;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  border-bottom: var(--border-width) var(--border-style) var(--color-border);\n  font-family: var(--font-ui);\n  font-size: var(--text-ui);\n  font-weight: var(--weight-ui);\n  text-transform: var(--ui-transform);\n}\n.ds-tabs__tab {\n  display: block;\n  padding: var(--space-1) 1ch;\n  color: var(--color-link-quiet);\n  text-decoration: var(--link-decoration-quiet);\n}\n.ds-tabs__tab:hover,\n.ds-tabs__tab.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-tabs__tab:focus-visible,\n.ds-tabs__tab.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-tabs__tab.is-current {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n  font-weight: var(--weight-bold);\n  text-decoration: none;\n}\n.ds-tabs__body {\n  padding: var(--space-2) 0 var(--space-3);\n}\n\n/* ---------- badge: a count on the accent fill; a tag; a status word in brackets ---------- */\n.ds-prose + .ds-links {\n  margin-top: var(--space-3);\n}\n.ds-badges {\n  margin: 0 0 var(--space-2);\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: var(--space-1) 2ch;\n}\n.ds-badge {\n  display: inline-block;\n  padding: 0 1ch;\n  border-radius: var(--radius-pill);\n  background: var(--fill-accent);\n  color: var(--color-accent-text);\n  font-family: var(--font-ui);\n  font-size: var(--text-small);\n  font-weight: var(--weight-bold);\n  line-height: var(--line-body);\n  white-space: nowrap;\n}\n.ds-badge--tag,\n.ds-badge--success,\n.ds-badge--warning,\n.ds-badge--danger {\n  padding: 0;\n  background: transparent;\n  font-weight: var(--weight-body);\n}\n.ds-badge--tag {\n  color: var(--color-heading-alt);\n}\n.ds-badge--tag::before {\n  content: \"#\";\n}\n.ds-badge--success::before,\n.ds-badge--warning::before,\n.ds-badge--danger::before {\n  content: \"[\";\n}\n.ds-badge--success::after,\n.ds-badge--warning::after,\n.ds-badge--danger::after {\n  content: \"]\";\n}\n.ds-badge--success {\n  color: var(--color-success);\n}\n.ds-badge--warning {\n  color: var(--color-warning);\n}\n.ds-badge--danger {\n  color: var(--color-danger);\n}\n\n/* ---------- sidebar: framed blocks of links ---------- */\n.ds-sidebar {\n  display: grid;\n  gap: var(--space-2);\n  align-content: start;\n  min-width: 0;\n}\n.ds-sidebar__list {\n  margin: 0;\n  padding: var(--space-1) 1ch var(--space-2);\n  list-style: none;\n}\n.ds-sidebar__list li {\n  display: flex;\n  justify-content: space-between;\n  gap: 1ch;\n}\n.ds-sidebar__link {\n  flex: 1;\n  min-width: 0;\n  padding: 0 1ch;\n  color: var(--color-link-quiet);\n  text-decoration: var(--link-decoration-quiet);\n}\n.ds-sidebar__link:hover,\n.ds-sidebar__link.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-sidebar__link.is-current {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n  font-weight: var(--weight-bold);\n  text-decoration: none;\n}\n.ds-sidebar__count {\n  flex: none;\n  padding: 0 1ch 0 0;\n  color: var(--color-text-muted);\n}\n.ds-sidebar__text {\n  margin: 0;\n  padding: var(--space-1) 2ch var(--space-2);\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n\n/* ---------- notice: a box with a heavy left edge ---------- */\n.ds-notices {\n  display: grid;\n  gap: var(--space-2);\n  margin: 0 0 var(--space-3);\n}\n.ds-notice {\n  margin: 0;\n  padding: var(--space-2) 2ch;\n  border: var(--border-width) var(--border-style) var(--color-border-strong);\n  border-left-width: var(--border-width-strong);\n  border-radius: var(--radius-panel);\n  background: var(--color-notice);\n  color: var(--color-notice-text);\n}\n.ds-notice__title {\n  font-weight: var(--weight-bold);\n  text-transform: var(--heading-transform);\n}\n.ds-notice--error {\n  border-color: var(--color-danger);\n  background: var(--color-danger-surface);\n  color: var(--color-danger);\n}\n\n/* ---------- pagination ---------- */\n.ds-pagination {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: var(--space-1) 1ch;\n  margin: var(--space-3) 0 0;\n  padding: 0;\n  list-style: none;\n  font-family: var(--font-ui);\n  font-size: var(--text-ui);\n}\n.ds-pagination__link {\n  display: block;\n  padding: 0 1ch;\n  color: var(--color-link);\n  text-decoration: var(--link-decoration-quiet);\n}\n.ds-pagination__link:hover,\n.ds-pagination__link.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-pagination__link:focus-visible,\n.ds-pagination__link.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-pagination__link.is-current {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n  font-weight: var(--weight-bold);\n  text-decoration: none;\n}\n.ds-pagination__link.is-disabled {\n  color: var(--color-text-muted);\n  text-decoration: none;\n}\n\n/* ---------- dialog: a framed box on a block of the overlay colour, in the page flow ---------- */\n.ds-dialog__backdrop {\n  box-sizing: border-box;\n  padding: var(--space-3) 2ch;\n  border-radius: var(--radius-panel);\n  background: var(--color-overlay);\n}\n.ds-dialog {\n  max-width: var(--size-dialog);\n  margin-left: auto;\n  margin-right: auto;\n  border-color: var(--color-border-strong);\n  box-shadow: var(--shadow-dialog);\n}\n.ds-dialog__title::before,\n.ds-dialog__title::after {\n  border-color: var(--color-border-strong);\n}\n.ds-dialog__body {\n  padding: var(--space-2) 2ch var(--space-3);\n}\n.ds-dialog__text {\n  margin: 0 0 var(--space-3);\n}\n.ds-dialog__actions {\n  display: flex;\n  flex-wrap: wrap;\n  gap: var(--space-2) 2ch;\n}\n\n/* ---------- empty ---------- */\n.ds-empty {\n  padding: var(--space-3) 2ch;\n  border: var(--border-width) var(--border-style) var(--color-border-muted);\n  border-radius: var(--radius-panel);\n  text-align: center;\n}\n.ds-empty__text {\n  margin: 0 0 var(--space-2);\n  color: var(--color-text-muted);\n}\n.ds-note code,\n.ds-notice code,\n.ds-panel__text code {\n  color: var(--color-heading);\n  font-family: var(--font-mono);\n}\n.ds-notice code {\n  color: inherit;\n  font-weight: var(--weight-bold);\n}\n\n/* ---------- pieces of the period beyond the checklist ---------- */\n/* menu: an item of a bar that pulls down a framed list. A <details>; closed until asked for. */\n.ds-menu {\n  position: relative;\n  flex: none;\n}\n.ds-menu__title {\n  display: block;\n  padding: var(--space-1) 1ch;\n  color: inherit;\n  font-weight: var(--weight-ui);\n  text-transform: var(--ui-transform);\n  white-space: nowrap;\n  list-style: none;\n  cursor: pointer;\n}\n.ds-menu__title::-webkit-details-marker {\n  display: none;\n}\n.ds-menu__title::after {\n  content: \" v\";\n  text-transform: none;\n}\n.ds-menu__title:hover,\n.ds-menu__title.is-hover,\n.ds-menu[open] > .ds-menu__title {\n  background: var(--color-canvas);\n  color: var(--color-heading);\n}\n.ds-menu__title:focus-visible,\n.ds-menu__title.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-menu__list {\n  position: absolute;\n  z-index: 4;\n  top: 100%;\n  right: 0;\n  box-sizing: border-box;\n  min-width: 28ch;\n  max-width: 90vw;\n  margin: 0;\n  padding: var(--space-1) 0;\n  list-style: none;\n  border: var(--border-width) var(--border-style) var(--color-border-strong);\n  border-radius: var(--radius-panel);\n  background: var(--color-surface);\n  box-shadow: var(--shadow-dialog);\n  color: var(--color-text);\n  font-weight: var(--weight-body);\n  text-shadow: none;\n}\n.ds-menu__item {\n  display: flex;\n  justify-content: space-between;\n  gap: 2ch;\n  padding: 0 1ch;\n  color: var(--color-link-quiet);\n  text-decoration: var(--link-decoration-quiet);\n  white-space: nowrap;\n}\n.ds-menu__item:hover,\n.ds-menu__item.is-hover {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n}\n.ds-menu__key {\n  color: var(--color-text-muted);\n}\n.ds-menu__item:hover .ds-menu__key,\n.ds-menu__item.is-hover .ds-menu__key {\n  color: inherit;\n}\n.ds-menu__rule {\n  margin: var(--space-1) 0;\n  border-top: var(--border-width) var(--border-style) var(--color-border-muted);\n}\n\n/* accordion: nodes of a tree that fold; [+] closed, [-] open */\n.ds-accordion {\n  margin: 0;\n}\n.ds-accordion__item {\n  border-bottom: var(--border-width) var(--border-style) var(--color-border-muted);\n}\n.ds-accordion__item:last-child {\n  border-bottom: 0;\n}\n.ds-accordion__title {\n  display: block;\n  padding: var(--space-1) 0;\n  color: var(--color-heading);\n  font-weight: var(--weight-bold);\n  list-style: none;\n  cursor: pointer;\n}\n.ds-accordion__title::-webkit-details-marker {\n  display: none;\n}\n.ds-accordion__title::before {\n  content: \"[+] \";\n  color: var(--color-accent-alt);\n}\n.ds-accordion__item[open] > .ds-accordion__title::before {\n  content: \"[-] \";\n}\n.ds-accordion__title:hover,\n.ds-accordion__title.is-hover {\n  color: var(--color-link-hover);\n}\n.ds-accordion__title:focus-visible,\n.ds-accordion__title.is-focus {\n  outline: var(--focus-ring);\n}\n.ds-accordion__body {\n  margin: 0;\n  padding: 0 0 var(--space-2) 4ch;\n}\n.ds-accordion__body p {\n  margin: 0 0 var(--space-1);\n}\n.ds-accordion__body code {\n  color: var(--color-heading);\n  font-family: var(--font-mono);\n}\n\n/* tooltip: a boxed hint over its trigger, shown on hover or focus only */\n.ds-tooltip {\n  text-decoration: underline dotted;\n  cursor: help;\n}\n.ds-tooltip:focus-visible {\n  outline: var(--focus-ring);\n}\n.ds-tooltip__tip {\n  display: none;\n  position: absolute;\n  z-index: 3;\n  left: 1ch;\n  box-sizing: border-box;\n  width: max-content;\n  max-width: min(34ch, calc(100% - 2ch));\n  padding: 0 1ch;\n  border: var(--border-width) var(--border-style) var(--color-border-strong);\n  border-radius: var(--radius-panel);\n  background: var(--color-surface-strong);\n  box-shadow: var(--shadow-panel);\n  color: var(--color-text);\n  font-size: var(--text-small);\n  font-weight: var(--weight-body);\n  letter-spacing: 0;\n  text-align: left;\n  text-transform: none;\n  white-space: normal;\n}\n.ds-tooltip:hover .ds-tooltip__tip,\n.ds-tooltip:focus .ds-tooltip__tip,\n.ds-tooltip.is-open .ds-tooltip__tip {\n  display: block;\n}\n\n/* switch: an on/off pair over a checkbox; the half that holds is inverse video */\n.ds-switch {\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 2ch;\n  padding: var(--space-1) 0;\n  cursor: pointer;\n}\n.ds-switch__label {\n  min-width: 0;\n}\n.ds-switch__input {\n  position: absolute;\n  appearance: none;\n  margin: 0;\n  opacity: 0;\n}\n.ds-switch__track {\n  flex: none;\n  display: inline-flex;\n  border: var(--border-width) var(--border-style) var(--color-input-border);\n  border-radius: var(--radius-control);\n  background: var(--fill-input);\n  color: var(--color-input-text);\n  font-size: var(--text-small);\n  white-space: nowrap;\n}\n.ds-switch__track::before {\n  content: \"on\";\n  padding: 0 1ch;\n}\n.ds-switch__track::after {\n  content: \"off\";\n  padding: 0 1ch;\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n  font-weight: var(--weight-bold);\n}\n.ds-switch__input:checked + .ds-switch__track::before {\n  background: var(--fill-inverse);\n  color: var(--color-inverse-text);\n  font-weight: var(--weight-bold);\n}\n.ds-switch__input:checked + .ds-switch__track::after {\n  background: transparent;\n  color: inherit;\n  font-weight: var(--weight-body);\n}\n.ds-switch__input:focus-visible + .ds-switch__track {\n  outline: var(--focus-ring);\n}\n\n/* progress: a bar typed in cells between brackets, then its figure */\n.ds-progress {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: baseline;\n  gap: 0 1ch;\n  margin: 0 0 var(--space-2);\n}\n.ds-progress:last-child {\n  margin-bottom: 0;\n}\n.ds-progress__label {\n  color: var(--color-text-muted);\n}\n.ds-progress__bar {\n  color: var(--color-border);\n  white-space: nowrap;\n}\n.ds-progress__bar::before {\n  content: \"[\";\n  color: var(--color-text-muted);\n}\n.ds-progress__bar::after {\n  content: \"]\";\n  color: var(--color-text-muted);\n}\n.ds-progress__on {\n  color: var(--color-success);\n}\n.ds-progress__on--warning {\n  color: var(--color-warning);\n}\n.ds-progress__value {\n  color: var(--color-heading);\n  font-weight: var(--weight-bold);\n}\n\n/* avatar: initials in a cell */\n.ds-avatar {\n  display: inline-block;\n  box-sizing: border-box;\n  min-width: 4ch;\n  padding: 0 0.5ch;\n  border-radius: var(--radius-pill);\n  background: var(--color-surface-strong);\n  color: var(--color-heading-alt);\n  font-weight: var(--weight-bold);\n  text-align: center;\n  text-transform: uppercase;\n  white-space: nowrap;\n}\n.ds-avatar--2 {\n  background: var(--color-fill-3);\n  color: var(--color-heading);\n}\n.ds-avatar--3 {\n  background: var(--color-fill-4);\n  color: var(--color-accent-alt);\n}\n\n/* ---------- layout 7: a chat client: a topic line at the top, the log beside a\n   column of names, and the window list with the input line docked at the foot ---------- */\n.ds-client {\n  display: flex;\n  flex-direction: column;\n  box-sizing: border-box;\n  max-width: var(--size-page);\n  min-height: 100vh;\n  margin: 0 auto;\n  border-radius: var(--radius-page);\n  background: var(--color-canvas);\n}\n.ds-main {\n  flex: 1;\n  min-width: 0;\n  padding: var(--space-3) 2ch var(--space-4);\n}\n.ds-cols {\n  display: grid;\n  grid-template-columns: minmax(0, 1fr) var(--size-side);\n  gap: var(--space-3) 2ch;\n  align-items: stretch;\n}\n.ds-cols--form {\n  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);\n}\n.ds-col {\n  min-width: 0;\n}\n/* the column of names: parted from the log by one upright line */\n.ds-side {\n  display: flex;\n  flex-direction: column;\n  gap: var(--space-3);\n  min-width: 0;\n  padding: 0 0 0 2ch;\n  border-left: var(--border-width) var(--border-style) var(--color-border);\n}\n.ds-stack {\n  display: grid;\n  gap: var(--space-3);\n  align-content: start;\n  min-width: 0;\n}\n\n/* topic line: the name, what the place is about, one pulled-down menu */\n.ds-topbar {\n  position: relative;\n  z-index: 3;\n  display: flex;\n  align-items: center;\n  gap: 0 2ch;\n  padding: 0 2ch;\n  background: var(--fill-bar);\n  color: var(--color-bar-text);\n  font-family: var(--font-ui);\n  font-size: var(--text-ui);\n}\n.ds-topbar .ds-brand {\n  padding: var(--space-1) 0;\n}\n.ds-topbar .ds-brand,\n.ds-topbar .ds-brand__name {\n  color: var(--color-bar-text);\n}\n.ds-topbar .ds-brand__mark {\n  border-color: var(--color-bar-text);\n  box-shadow: none;\n}\n.ds-topbar__topic {\n  flex: 1;\n  min-width: 0;\n  margin: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.ds-menu__title::before {\n  content: \"[\";\n}\n.ds-menu__title::after {\n  content: \" v]\";\n}\n\n/* dock: the window list (the navigation) and the input line, stuck to the foot of the window */\n.ds-dock {\n  position: sticky;\n  z-index: 2;\n  bottom: 0;\n  background: var(--color-canvas);\n}\n.ds-nav {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: 0 1ch;\n  padding: 0 1ch;\n  background: var(--fill-bar-alt);\n  color: var(--color-bar-alt-text);\n  font-family: var(--font-ui);\n  font-size: var(--text-ui);\n  font-weight: var(--weight-ui);\n}\n.ds-nav__clock,\n.ds-nav__act {\n  flex: none;\n  margin: 0;\n  padding: var(--space-1) 0;\n  font-weight: var(--weight-body);\n}\n.ds-nav__act {\n  margin-left: auto;\n}\n.ds-nav__word {\n  font-weight: var(--weight-body);\n}\n.ds-nav__list {\n  display: flex;\n  flex-wrap: wrap;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.ds-nav__link {\n  display: block;\n  padding: var(--space-1) 1ch;\n  color: var(--color-bar-alt-text);\n  text-decoration: var(--link-decoration-quiet);\n  text-transform: var(--ui-transform);\n  white-space: nowrap;\n}\n.ds-nav__link::before {\n  content: \"[\";\n}\n.ds-nav__link::after {\n  content: \"]\";\n}\n.ds-nav__num {\n  font-weight: var(--weight-bold);\n}\n.ds-nav__name::before {\n  content: \":\";\n}\n.ds-nav__link:hover,\n.ds-nav__link.is-hover {\n  text-decoration: var(--link-decoration-hover);\n}\n.ds-nav__link:focus-visible,\n.ds-nav__link.is-focus {\n  outline: var(--focus-ring);\n}\n/* the window that is showing is a hole in the bar */\n.ds-nav__link.is-current,\n.ds-page:not(:has(.ds-view:target)) .ds-nav__link[href=\"#lobby\"],\n.ds-page:has(#lobby:target) .ds-nav__link[href=\"#lobby\"],\n.ds-page:has(#channel:target) .ds-nav__link[href=\"#channel\"],\n.ds-page:has(#logs:target) .ds-nav__link[href=\"#logs\"],\n.ds-page:has(#settings:target) .ds-nav__link[href=\"#settings\"],\n.ds-page:has(#help:target) .ds-nav__link[href=\"#help\"] {\n  background: var(--color-canvas);\n  color: var(--color-heading);\n  text-decoration: none;\n}\n.ds-dock__input {\n  display: flex;\n  align-items: center;\n  gap: 1ch;\n  padding: var(--space-1) 1ch var(--space-2);\n}\n.ds-dock__who {\n  flex: none;\n  color: var(--color-accent-alt);\n  font-weight: var(--weight-bold);\n}\n.ds-dock__input .ds-form__input {\n  flex: 1;\n  min-width: 0;\n  max-width: none;\n}\n\n/* hero: the message of the day, a box that stands off the screen */\n.ds-hero {\n  box-sizing: border-box;\n  margin: 0 0 var(--space-4);\n  padding: var(--space-3) 3ch;\n  border: var(--border-width) var(--border-style) var(--color-border-strong);\n  border-left-width: var(--border-width-strong);\n  border-radius: var(--radius-page);\n  background: var(--fill-panel);\n  box-shadow: var(--shadow-dialog);\n}\n.ds-hero__motd {\n  margin: 0 0 var(--space-2);\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n.ds-hero__sign {\n  color: var(--color-accent-alt);\n}\n.ds-hero__title {\n  margin: 0 0 var(--space-2);\n  color: var(--color-heading);\n  font-family: var(--font-heading);\n  font-size: var(--text-display);\n  font-weight: var(--weight-display);\n  line-height: var(--line-display);\n  letter-spacing: var(--display-tracking);\n  text-transform: var(--heading-transform);\n  text-shadow: var(--shadow-text);\n}\n.ds-hero__lead {\n  max-width: 72ch;\n  margin: 0 0 var(--space-3);\n  font-size: var(--text-large);\n}\n.ds-hero__note {\n  margin: var(--space-2) 0 0;\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n\n/* stats: one ruled line of figures, each a number and its word */\n.ds-stats {\n  margin: 0 0 var(--space-4);\n  border-style: var(--border-style);\n  border-color: var(--color-border);\n  border-width: var(--border-width) 0;\n}\n.ds-stat {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: baseline;\n  gap: 0 1ch;\n  padding: var(--space-2) 2ch;\n  border-left: var(--border-width) var(--border-style) var(--color-border);\n}\n.ds-stat:first-child {\n  padding-left: 0;\n  border-left: 0;\n}\n.ds-stat__value {\n  font-size: var(--text-h1);\n  line-height: var(--line-heading);\n  text-shadow: var(--shadow-text);\n}\n.ds-stat__label {\n  font-size: var(--text-small);\n}\n\n/* the log: time, name, what was said; one line an entry */\n.ds-log {\n  margin: 0 0 var(--space-3);\n  padding: 0;\n  list-style: none;\n}\n.ds-log__day {\n  display: flex;\n  align-items: center;\n  gap: 1ch;\n  margin: var(--space-2) 0;\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n.ds-log__day::before,\n.ds-log__day::after {\n  content: \"\";\n  flex: 1;\n  border-top: var(--border-width) var(--border-style) var(--color-border-muted);\n}\n.ds-log__line {\n  display: grid;\n  grid-template-columns: 6ch 17ch minmax(0, 1fr);\n  gap: 0 1ch;\n  padding: var(--space-1) 1ch var(--space-1) 0;\n  border-left: var(--border-width-strong) var(--border-style) transparent;\n}\n.ds-log__time {\n  color: var(--color-text-muted);\n  text-align: right;\n}\n.ds-log__nick {\n  overflow: hidden;\n  color: var(--color-heading);\n  font-weight: var(--weight-bold);\n  text-align: right;\n  white-space: nowrap;\n}\n.ds-log__text {\n  min-width: 0;\n  margin: 0;\n  padding: 0 0 0 1ch;\n  border-left: var(--border-width) var(--border-style) var(--color-border);\n  overflow-wrap: anywhere;\n}\n.ds-log__text code {\n  padding: 0 0.5ch;\n  background: var(--color-surface-alt);\n  color: var(--color-heading);\n  font-family: var(--font-mono);\n}\n.ds-log__line--event .ds-log__nick,\n.ds-log__line--event .ds-log__text {\n  color: var(--color-text-muted);\n  font-weight: var(--weight-body);\n}\n/* a line that names the reader */\n.ds-log__line.is-mention {\n  border-left-color: var(--color-accent);\n  background: var(--color-surface-strong);\n}\n.ds-log__line.is-mention .ds-log__nick {\n  color: var(--color-heading-alt);\n}\n.ds-log__text .ds-links {\n  display: inline-flex;\n}\n\n/* names in a sidebar block carry their cell of initials */\n.ds-sidebar__link .ds-avatar {\n  margin-right: 1ch;\n}\n.ds-panel__text code {\n  white-space: nowrap;\n}\n.ds-setting {\n  border-bottom: var(--border-width) var(--border-style) var(--color-border-muted);\n}\n.ds-setting:last-child {\n  border-bottom: 0;\n}\n.ds-keys {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0 2ch;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n\n/* footer: one quiet line above the dock */\n.ds-footer {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: space-between;\n  gap: var(--space-1) 3ch;\n  padding: var(--space-2) 2ch;\n  border-top: var(--border-width) var(--border-style) var(--color-border-muted);\n  color: var(--color-text-muted);\n  font-size: var(--text-small);\n}\n.ds-footer__text {\n  margin: 0;\n}\n.ds-footer__link {\n  color: var(--color-link-quiet);\n  text-decoration: var(--link-decoration-quiet);\n}\n.ds-footer__link:hover,\n.ds-footer__link.is-hover {\n  color: var(--color-link-hover);\n  text-decoration: var(--link-decoration-hover);\n}\n\n/* ---------- narrow windows: one column, nothing scrolls sideways but code ---------- */\n@media (max-width: 900px) {\n  .ds-page-header {\n    flex-direction: column;\n    align-items: flex-start;\n  }\n  .ds-stats,\n  .ds-grid {\n    grid-template-columns: repeat(2, minmax(0, 1fr));\n  }\n  .ds-form__row {\n    grid-template-columns: minmax(0, 1fr);\n  }\n  .ds-form__label {\n    padding: 0;\n  }\n  .ds-form__actions {\n    padding-left: 0;\n  }\n  .ds-table__extra {\n    display: none;\n  }\n  .ds-dialog__backdrop {\n    padding: var(--space-3) 1ch;\n  }\n  .ds-button {\n    white-space: normal;\n  }\n  .ds-table td.ds-table__code {\n    white-space: normal;\n    overflow-wrap: anywhere;\n  }\n  .ds-list__item {\n    grid-template-columns: minmax(0, 1fr);\n  }\n\n  .ds-main {\n    padding: var(--space-3) 2ch var(--space-4);\n  }\n  .ds-topbar {\n    padding: 0 1ch;\n  }\n  .ds-topbar__topic {\n    visibility: hidden;\n  }\n  .ds-cols,\n  .ds-cols--form {\n    grid-template-columns: minmax(0, 1fr);\n  }\n  .ds-side {\n    padding: var(--space-3) 0 0;\n    border-left: 0;\n    border-top: var(--border-width) var(--border-style) var(--color-border);\n  }\n  .ds-hero {\n    padding: var(--space-3) 2ch;\n  }\n  .ds-hero__title {\n    font-size: var(--text-h1);\n  }\n  .ds-stat:nth-child(odd) {\n    padding-left: 0;\n    border-left: 0;\n  }\n  .ds-stat:nth-child(n + 3) {\n    border-top: var(--border-width) var(--border-style) var(--color-border);\n  }\n  .ds-log__line {\n    grid-template-columns: 6ch minmax(0, 1fr);\n  }\n  .ds-log__line {\n    padding-left: 1ch;\n  }\n  .ds-log__time,\n  .ds-log__nick {\n    text-align: left;\n  }\n  .ds-nav__link {\n    padding: var(--space-1) 0.5ch;\n  }\n  .ds-log__text {\n    grid-column: 1 / -1;\n    padding: 0;\n    border-left: 0;\n  }\n  /* the window list keeps its numbers; only the window that shows keeps its name */\n  .ds-nav__name {\n    display: none;\n  }\n  .ds-nav__link.is-current .ds-nav__name,\n  .ds-page:not(:has(.ds-view:target)) .ds-nav__link[href=\"#lobby\"] .ds-nav__name,\n  .ds-page:has(#lobby:target) .ds-nav__link[href=\"#lobby\"] .ds-nav__name,\n  .ds-page:has(#channel:target) .ds-nav__link[href=\"#channel\"] .ds-nav__name,\n  .ds-page:has(#logs:target) .ds-nav__link[href=\"#logs\"] .ds-nav__name,\n  .ds-page:has(#settings:target) .ds-nav__link[href=\"#settings\"] .ds-nav__name,\n  .ds-page:has(#help:target) .ds-nav__link[href=\"#help\"] .ds-nav__name {\n    display: inline;\n  }\n  .ds-nav__clock,\n  .ds-nav__word {\n    display: none;\n  }\n}\n",
    "specimen.html": "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>chronoskin chat: a text-mode chat client. Terminal, 2015 to 2026: specimen</title>\n<link rel=\"stylesheet\" href=\"tokens.css\">\n<link rel=\"stylesheet\" href=\"components.css\">\n</head>\n<body class=\"ds-page\" data-component=\"shell\">\n<div class=\"ds-client\">\n\n<header class=\"ds-topbar\">\n  <a class=\"ds-brand\" data-component=\"brand\" href=\"#lobby\"><span class=\"ds-brand__mark\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" aria-hidden=\"true\"><polyline points=\"4,6 11,12 4,18\"/><line x1=\"13\" y1=\"19\" x2=\"21\" y2=\"19\"/></svg></span><span class=\"ds-brand__name\">chronoskin</span></a>\n  <p class=\"ds-topbar__topic\">chat.chronoskin.example | 42 online in 12 channels | release 3.2 is out, notes in #announce</p>\n  <details class=\"ds-menu\">\n    <summary class=\"ds-menu__title\">server</summary>\n    <ul class=\"ds-menu__list\">\n      <li><a class=\"ds-menu__item\" href=\"#channel\">join a channel <span class=\"ds-menu__key\">/join</span></a></li>\n      <li><a class=\"ds-menu__item\" href=\"#logs\">search the logs <span class=\"ds-menu__key\">/search</span></a></li>\n      <li><a class=\"ds-menu__item is-hover\" href=\"#settings\">change nick <span class=\"ds-menu__key\">/nick</span></a></li>\n      <li class=\"ds-menu__rule\"></li>\n      <li><a class=\"ds-menu__item\" href=\"#help\">all commands <span class=\"ds-menu__key\">/help</span></a></li>\n      <li><a class=\"ds-menu__item\" href=\"#lobby\">disconnect <span class=\"ds-menu__key\">/quit</span></a></li>\n    </ul>\n  </details>\n</header>\n\n<main class=\"ds-main\">\n\n<!-- View 1, the lobby: message of the day, figures, pinned channels and the channel list, beside who is on. -->\n<section class=\"ds-view ds-view--home\" id=\"lobby\">\n  <div class=\"ds-cols\">\n    <div class=\"ds-col\">\n      <section class=\"ds-hero\" data-component=\"hero\">\n        <p class=\"ds-hero__motd\"><span class=\"ds-hero__sign\">-!-</span> message of the day, set by the operators on 2026-10-05</p>\n        <h1 class=\"ds-hero__title\">Welcome to chronoskin chat</h1>\n        <p class=\"ds-hero__lead\">One server, twelve channels, plain text. Ask about the program in #help, follow the work in #dev, and say hello in #general.</p>\n        <div class=\"ds-buttons\">\n          <a class=\"ds-button\" href=\"#channel\">Join #general</a>\n          <a class=\"ds-button ds-button--secondary\" href=\"#help\">Read the rules</a>\n          <a class=\"ds-link ds-link--bracket\" href=\"#logs\">search the logs</a>\n        </div>\n        <p class=\"ds-hero__note\">You are connected as <strong>reader</strong> over TLS. Your nick is not registered yet.</p>\n      </section>\n\n      <ul class=\"ds-stats\" data-component=\"stats\">\n        <li class=\"ds-stat\"><span class=\"ds-stat__value\">42</span><span class=\"ds-stat__label\">people online</span></li>\n        <li class=\"ds-stat\"><span class=\"ds-stat__value\">12</span><span class=\"ds-stat__label\">channels</span></li>\n        <li class=\"ds-stat\"><span class=\"ds-stat__value\">1,204</span><span class=\"ds-stat__label\">lines today</span></li>\n        <li class=\"ds-stat\"><span class=\"ds-stat__value\">311 d</span><span class=\"ds-stat__label\">server uptime</span></li>\n      </ul>\n\n      <section class=\"ds-section\">\n        <h2 class=\"ds-section__title\">pinned channels</h2>\n        <div class=\"ds-grid\" data-component=\"grid\">\n          <div class=\"ds-grid__cell\">\n            <h3 class=\"ds-grid__title\"><a class=\"ds-link\" href=\"#channel\">#general</a></h3>\n            <p class=\"ds-grid__text\">Everything about the program that has no better place.</p>\n            <p class=\"ds-grid__label\">31 here, 3 unread</p>\n          </div>\n          <div class=\"ds-grid__cell ds-grid__cell--2\">\n            <h3 class=\"ds-grid__title\"><a class=\"ds-link\" href=\"#channel\">#help</a></h3>\n            <p class=\"ds-grid__text\">Questions and answers. Paste the error, not a picture of it.</p>\n            <p class=\"ds-grid__label\">18 here, quiet</p>\n          </div>\n          <div class=\"ds-grid__cell ds-grid__cell--3\">\n            <h3 class=\"ds-grid__title\"><a class=\"ds-link\" href=\"#channel\">#dev</a></h3>\n            <p class=\"ds-grid__text\">Patches, reviews and the build. Logged in public.</p>\n            <p class=\"ds-grid__label\">9 here, 1 mention</p>\n          </div>\n          <div class=\"ds-grid__cell ds-grid__cell--4\">\n            <h3 class=\"ds-grid__title\"><a class=\"ds-link\" href=\"#channel\">#announce</a></h3>\n            <p class=\"ds-grid__text\">Releases and planned downtime. Operators write, all read.</p>\n            <p class=\"ds-grid__label\">40 here, read only</p>\n          </div>\n        </div>\n      </section>\n\n      <section class=\"ds-section\">\n        <h2 class=\"ds-section__title\">/list</h2>\n        <table class=\"ds-table\" data-component=\"table\">\n          <thead>\n            <tr><th>channel</th><th class=\"ds-table__extra\">topic</th><th class=\"ds-table__num\">here</th><th class=\"ds-table__num\">lines today</th><th class=\"ds-table__extra\">last line</th></tr>\n          </thead>\n          <tbody>\n            <tr class=\"is-selected\"><td class=\"ds-table__code\">#general</td><td class=\"ds-table__extra\">Release 3.2 is out. Be kind, stay on topic.</td><td class=\"ds-table__num\">31</td><td class=\"ds-table__num\">486</td><td class=\"ds-table__extra\">14:01</td></tr>\n            <tr class=\"is-alt\"><td class=\"ds-table__code\"><a class=\"ds-table__title\" href=\"#channel\">#help</a></td><td class=\"ds-table__extra\">Ask your question, then wait. Someone will read it.</td><td class=\"ds-table__num\">18</td><td class=\"ds-table__num\">212</td><td class=\"ds-table__date ds-table__extra\">13:48</td></tr>\n            <tr><td class=\"ds-table__code\"><a class=\"ds-table__title\" href=\"#channel\">#dev</a></td><td class=\"ds-table__extra\">Freeze for 3.3 starts on 2026-10-19.</td><td class=\"ds-table__num\">9</td><td class=\"ds-table__num\">340</td><td class=\"ds-table__date ds-table__extra\">13:57</td></tr>\n            <tr class=\"is-alt\"><td class=\"ds-table__code\"><a class=\"ds-table__title\" href=\"#channel\">#announce</a></td><td class=\"ds-table__extra\">Releases and downtime.</td><td class=\"ds-table__num\">40</td><td class=\"ds-table__num\">2</td><td class=\"ds-table__date ds-table__extra\">09:30</td></tr>\n            <tr><td class=\"ds-table__code\"><a class=\"ds-table__title\" href=\"#channel\">#themes</a></td><td class=\"ds-table__extra\">Show your colours. One screenshot a day, please.</td><td class=\"ds-table__num\">14</td><td class=\"ds-table__num\">97</td><td class=\"ds-table__date ds-table__extra\">12:20</td></tr>\n            <tr class=\"is-alt\"><td class=\"ds-table__code\"><a class=\"ds-table__title\" href=\"#channel\">#offtopic</a></td><td class=\"ds-table__extra\">Everything else.</td><td class=\"ds-table__num\">22</td><td class=\"ds-table__num\">67</td><td class=\"ds-table__date ds-table__extra\">13:15</td></tr>\n          </tbody>\n        </table>\n        <p class=\"ds-note\">6 of 12 channels shown. Type <code>/list -all</code> for the rest, or <code>/join #name</code> to open one.</p>\n      </section>\n    </div>\n\n    <aside class=\"ds-side\">\n      <div class=\"ds-sidebar\">\n        <div class=\"ds-sidebar__block\">\n          <h2 class=\"ds-sidebar__title\">on now</h2>\n          <ul class=\"ds-sidebar__list\">\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar\">mk</span>mika</a><span class=\"ds-sidebar__count\">op</span></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--2\">jo</span>jonas</a><span class=\"ds-sidebar__count\">op</span></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--3\">ai</span>aiko</a></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar\">te</span>tereza</a></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--2\">ld</span>ludo</a></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--3\">bt</span>buildbot</a><span class=\"ds-sidebar__count\">bot</span></li>\n          </ul>\n          <p class=\"ds-sidebar__text\">36 more. <a class=\"ds-link ds-link--quiet\" href=\"#channel\">/names</a> lists them all.</p>\n        </div>\n      </div>\n      <div class=\"ds-panel\" data-component=\"panel\">\n        <h2 class=\"ds-panel__title\">this server</h2>\n        <div class=\"ds-panel__body\">\n          <p class=\"ds-panel__text\">Run by volunteers. Channels are logged for 90 days, private messages never.</p>\n          <p class=\"ds-progress\"><span class=\"ds-progress__label\">history</span><span class=\"ds-progress__bar\"><span class=\"ds-progress__on\">########</span>....</span><span class=\"ds-progress__value\">67%</span></p>\n          <p class=\"ds-progress\"><span class=\"ds-progress__label\">log disk</span><span class=\"ds-progress__bar\"><span class=\"ds-progress__on ds-progress__on--warning\">##########</span>..</span><span class=\"ds-progress__value\">84%</span></p>\n          <p class=\"ds-panel__text\"><span class=\"ds-tooltip\" tabindex=\"0\">lag 38 ms<span class=\"ds-tooltip__tip\" role=\"tooltip\">The time a line takes from your key to the server and back.</span></span>, last netsplit 61 days ago.</p>\n        </div>\n      </div>\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">named you</h2>\n        <div class=\"ds-panel__body\">\n          <p class=\"ds-panel__text\"><a class=\"ds-link\" href=\"#channel\">#general 13:50</a> jonas: your patch for the status line went in.</p>\n          <p class=\"ds-panel__text\"><a class=\"ds-link\" href=\"#channel\">#dev 11:32</a> mika: reader, can you test the tarball?</p>\n          <p class=\"ds-panel__text\"><a class=\"ds-link is-visited\" href=\"#logs\">#help yesterday</a> aiko: thanks, reader, that fixed it.</p>\n        </div>\n      </div>\n    </aside>\n  </div>\n</section>\n\n<!-- View 2, a channel: the log with its day rule, joins and a mention, beside the names. -->\n<section class=\"ds-view\" id=\"channel\">\n  <ol class=\"ds-breadcrumb\" data-component=\"breadcrumb\">\n    <li><a class=\"ds-breadcrumb__link\" href=\"#lobby\">chronoskin</a></li>\n    <li class=\"ds-breadcrumb__sep\">/</li>\n    <li><a class=\"ds-breadcrumb__link\" href=\"#lobby\">channels</a></li>\n    <li class=\"ds-breadcrumb__sep\">/</li>\n    <li class=\"ds-breadcrumb__current\">#general</li>\n  </ol>\n  <header class=\"ds-page-header\" data-component=\"page-header\">\n    <div class=\"ds-page-header__main\">\n      <h1 class=\"ds-page-header__title\">#general</h1>\n      <p class=\"ds-page-header__text\">Topic: release 3.2 is out. Be kind, stay on topic. Set by mika on 2026-10-05.</p>\n    </div>\n    <div class=\"ds-page-header__action\"><a class=\"ds-button ds-button--secondary\" href=\"#lobby\">Leave</a></div>\n  </header>\n  <div class=\"ds-cols\">\n    <div class=\"ds-col\">\n      <div class=\"ds-notices\" data-component=\"notice\">\n        <p class=\"ds-notice\"><span class=\"ds-notice__title\">Joined.</span> You are in #general with 30 others. The last 200 lines were replayed.</p>\n        <p class=\"ds-notice ds-notice--error\"><span class=\"ds-notice__title\">Bridge down.</span> Lines from the mail gateway are late since 13:20. Nothing is lost.</p>\n      </div>\n      <ol class=\"ds-log\">\n        <li class=\"ds-log__day\">Tuesday, 6 October 2026</li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:41</time><span class=\"ds-log__nick\">mika</span><p class=\"ds-log__text\">3.2 is tagged. Packages follow within the hour.</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:42</time><span class=\"ds-log__nick\">aiko</span><p class=\"ds-log__text\">Does the new pager keep its place after a resize?</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:42</time><span class=\"ds-log__nick\">mika</span><p class=\"ds-log__text\">It does. Set <code>pager.keep = true</code> if you ran an older config.</p></li>\n        <li class=\"ds-log__line ds-log__line--event\"><time class=\"ds-log__time\">13:44</time><span class=\"ds-log__nick\">-!-</span><p class=\"ds-log__text\">ludo has joined #general</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:45</time><span class=\"ds-log__nick\">ludo</span><p class=\"ds-log__text\">Morning. The tarball builds clean on my old laptop, 41 seconds.</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:47</time><span class=\"ds-log__nick\">buildbot</span><p class=\"ds-log__text\">Build 3.2.0 passed on 6 of 6 targets.</p></li>\n        <li class=\"ds-log__line is-mention\"><time class=\"ds-log__time\">13:50</time><span class=\"ds-log__nick\">jonas</span><p class=\"ds-log__text\">reader: your patch for the status line went in, thank you.</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:52</time><span class=\"ds-log__nick\">tereza</span><p class=\"ds-log__text\">Where do the release notes live now?</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:53</time><span class=\"ds-log__nick\">buildbot</span><div class=\"ds-log__text\"><ul class=\"ds-links\" data-component=\"links\">\n          <li><a class=\"ds-link\" href=\"#help\">release notes</a></li>\n          <li><a class=\"ds-link is-visited\" href=\"#help\">upgrade guide (visited)</a></li>\n          <li><a class=\"ds-link is-hover\" href=\"#logs\">yesterday's log (hover)</a></li>\n          <li><a class=\"ds-link is-active\" href=\"#help\">known issues (active)</a></li>\n        </ul></div></li>\n        <li class=\"ds-log__line ds-log__line--event\"><time class=\"ds-log__time\">13:55</time><span class=\"ds-log__nick\">-!-</span><p class=\"ds-log__text\">mode/#general [+v ludo] by mika</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">13:58</time><span class=\"ds-log__nick\">aiko</span><p class=\"ds-log__text\">Upgraded two machines. Nothing to report, which is the best report.</p></li>\n        <li class=\"ds-log__line\"><time class=\"ds-log__time\">14:01</time><span class=\"ds-log__nick\">ludo</span><p class=\"ds-log__text\">Same here. Off to read the notes.</p></li>\n      </ol>\n      <ul class=\"ds-pagination\" data-component=\"pagination\">\n        <li><a class=\"ds-pagination__link\" href=\"#logs\">&lt; older</a></li>\n        <li><a class=\"ds-pagination__link\" href=\"#logs\">1</a></li>\n        <li><a class=\"ds-pagination__link\" href=\"#logs\">2</a></li>\n        <li><span class=\"ds-pagination__link is-current\">3</span></li>\n        <li><span class=\"ds-pagination__link is-disabled\">newer &gt;</span></li>\n      </ul>\n    </div>\n\n    <aside class=\"ds-side\">\n      <div class=\"ds-sidebar\" data-component=\"sidebar\">\n        <div class=\"ds-sidebar__block\">\n          <h2 class=\"ds-sidebar__title\">operators</h2>\n          <ul class=\"ds-sidebar__list\">\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar\">mk</span>mika</a><span class=\"ds-sidebar__count\">@</span></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--2\">jo</span>jonas</a><span class=\"ds-sidebar__count\">@</span></li>\n          </ul>\n        </div>\n        <div class=\"ds-sidebar__block\">\n          <h2 class=\"ds-sidebar__title\">here, 31</h2>\n          <ul class=\"ds-sidebar__list\">\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--3\">ai</span>aiko</a></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--3\">bt</span>buildbot</a><span class=\"ds-sidebar__count\">bot</span></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar ds-avatar--2\">ld</span>ludo</a><span class=\"ds-sidebar__count\">+</span></li>\n            <li><a class=\"ds-sidebar__link is-current\" href=\"#settings\"><span class=\"ds-avatar\">re</span>reader</a><span class=\"ds-sidebar__count\">you</span></li>\n            <li><a class=\"ds-sidebar__link\" href=\"#channel\"><span class=\"ds-avatar\">te</span>tereza</a></li>\n          </ul>\n          <p class=\"ds-sidebar__text\">26 more are idle. <span class=\"ds-tooltip\" tabindex=\"0\">What the signs mean<span class=\"ds-tooltip__tip\" role=\"tooltip\">@ may set the topic and remove people. + may speak when the channel is moderated.</span></span></p>\n        </div>\n      </div>\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">status words</h2>\n        <div class=\"ds-panel__body\">\n          <div class=\"ds-badges\" data-component=\"badge\">\n            <span class=\"ds-badge\">3</span>\n            <span class=\"ds-badge ds-badge--success\">here</span>\n            <span class=\"ds-badge ds-badge--warning\">away</span>\n            <span class=\"ds-badge ds-badge--danger\">muted</span>\n            <span class=\"ds-badge ds-badge--tag\">release</span>\n          </div>\n          <p class=\"ds-panel__text\">The count is unread lines that name you.</p>\n        </div>\n      </div>\n    </aside>\n  </div>\n</section>\n\n<!-- View 3, the logs: a search, its hits under tabs, the empty state of shared files, the archive by month. -->\n<section class=\"ds-view\" id=\"logs\">\n  <ol class=\"ds-breadcrumb\">\n    <li><a class=\"ds-breadcrumb__link\" href=\"#lobby\">chronoskin</a></li>\n    <li class=\"ds-breadcrumb__sep\">/</li>\n    <li class=\"ds-breadcrumb__current\">logs</li>\n  </ol>\n  <header class=\"ds-page-header\">\n    <div class=\"ds-page-header__main\">\n      <h1 class=\"ds-page-header__title\">Logs</h1>\n      <p class=\"ds-page-header__text\">Every public channel, kept for 90 days. Search them or read a day from the top.</p>\n    </div>\n    <div class=\"ds-page-header__action\"><a class=\"ds-button ds-button--secondary\" href=\"#settings\">Log settings</a></div>\n  </header>\n  <div class=\"ds-cols\">\n    <div class=\"ds-col\">\n      <p class=\"ds-prompt\"><span class=\"ds-prompt__sign\">/search</span> <span class=\"ds-prompt__path\">-channel #general</span> pager resize</p>\n      <ul class=\"ds-tabs\" data-component=\"tabs\">\n        <li><span class=\"ds-tabs__tab is-current\">lines 18</span></li>\n        <li><a class=\"ds-tabs__tab\" href=\"#logs\">files 0</a></li>\n        <li><a class=\"ds-tabs__tab\" href=\"#logs\">pinned 3</a></li>\n      </ul>\n      <div class=\"ds-tabs__body\">\n        <ul class=\"ds-list\" data-component=\"list\">\n          <li class=\"ds-list__item\">\n            <span class=\"ds-list__date\">10-06 13:42</span>\n            <div class=\"ds-list__main\">\n              <a class=\"ds-list__title\" href=\"#channel\">#general, aiko</a>\n              <p class=\"ds-list__excerpt\">Does the new pager keep its place after a resize?</p>\n              <p class=\"ds-list__meta\">2 replies in the next minute</p>\n            </div>\n          </li>\n          <li class=\"ds-list__item\">\n            <span class=\"ds-list__date\">10-02 09:15</span>\n            <div class=\"ds-list__main\">\n              <a class=\"ds-list__title is-visited\" href=\"#channel\">#dev, jonas</a>\n              <p class=\"ds-list__excerpt\">The pager loses its line on resize when wrapping is off. Patch attached.</p>\n              <p class=\"ds-list__meta\">7 replies, closed by a commit</p>\n            </div>\n          </li>\n          <li class=\"ds-list__item\">\n            <span class=\"ds-list__date\">09-28 21:03</span>\n            <div class=\"ds-list__main\">\n              <a class=\"ds-list__title\" href=\"#channel\">#help, tereza</a>\n              <p class=\"ds-list__excerpt\">After a resize the pager jumps to the top. Is that a setting?</p>\n              <p class=\"ds-list__meta\">4 replies, answered</p>\n            </div>\n          </li>\n          <li class=\"ds-list__item\">\n            <span class=\"ds-list__date\">09-11 16:40</span>\n            <div class=\"ds-list__main\">\n              <a class=\"ds-list__title\" href=\"#channel\">#general, ludo</a>\n              <p class=\"ds-list__excerpt\">Small request: let the pager remember its place when the window changes size.</p>\n              <p class=\"ds-list__meta\">11 replies, where it all began</p>\n            </div>\n          </li>\n        </ul>\n      </div>\n      <h2 class=\"ds-section__title\">files 0</h2>\n      <div class=\"ds-empty\" data-component=\"empty\">\n        <p class=\"ds-empty__text\">No file that matches was shared in the last 90 days.</p>\n        <a class=\"ds-button ds-button--secondary\" href=\"#logs\">Search all channels</a>\n      </div>\n    </div>\n    <aside class=\"ds-side\">\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">archive</h2>\n        <div class=\"ds-panel__body\">\n          <div class=\"ds-accordion\">\n            <details class=\"ds-accordion__item\" open>\n              <summary class=\"ds-accordion__title\">2026-10</summary>\n              <div class=\"ds-accordion__body\">\n                <p><a class=\"ds-link\" href=\"#channel\">10-06, today</a></p>\n                <p><a class=\"ds-link is-visited\" href=\"#channel\">10-05, 1,512 lines</a></p>\n                <p><a class=\"ds-link\" href=\"#channel\">10-04, 640 lines</a></p>\n              </div>\n            </details>\n            <details class=\"ds-accordion__item\">\n              <summary class=\"ds-accordion__title\">2026-09</summary>\n              <div class=\"ds-accordion__body\"><p>30 days, 28,204 lines.</p></div>\n            </details>\n            <details class=\"ds-accordion__item\">\n              <summary class=\"ds-accordion__title\">2026-08</summary>\n              <div class=\"ds-accordion__body\"><p>31 days, 24,880 lines.</p></div>\n            </details>\n          </div>\n        </div>\n      </div>\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">search words</h2>\n        <div class=\"ds-panel__body\">\n          <p class=\"ds-panel__text\"><code>-channel</code> limits to one channel, <code>-nick</code> to one person, <code>-since</code> to a date.</p>\n        </div>\n      </div>\n    </aside>\n  </div>\n</section>\n\n<!-- View 4, settings: the account form beside the switches and the question before an account is removed. -->\n<section class=\"ds-view\" id=\"settings\">\n  <ol class=\"ds-breadcrumb\">\n    <li><a class=\"ds-breadcrumb__link\" href=\"#lobby\">chronoskin</a></li>\n    <li class=\"ds-breadcrumb__sep\">/</li>\n    <li class=\"ds-breadcrumb__current\">settings</li>\n  </ol>\n  <header class=\"ds-page-header\">\n    <div class=\"ds-page-header__main\">\n      <h1 class=\"ds-page-header__title\">Settings</h1>\n      <p class=\"ds-page-header__text\">Your nick, what counts as a mention, and what the client shows.</p>\n    </div>\n    <div class=\"ds-page-header__action\"><a class=\"ds-button ds-button--secondary\" href=\"#help\">Help</a></div>\n  </header>\n  <div class=\"ds-cols ds-cols--form\">\n    <div class=\"ds-col\">\n      <h2 class=\"ds-section__title\">account</h2>\n      <form class=\"ds-form\" data-component=\"form\">\n        <div class=\"ds-form__row\">\n          <label class=\"ds-form__label\" for=\"f-nick\">nick</label>\n          <div class=\"ds-form__field\"><input class=\"ds-form__input\" id=\"f-nick\" type=\"text\" value=\"reader\"></div>\n        </div>\n        <div class=\"ds-form__row\">\n          <label class=\"ds-form__label\" for=\"f-mail\">mail</label>\n          <div class=\"ds-form__field\">\n            <input class=\"ds-form__input is-invalid\" id=\"f-mail\" type=\"text\" value=\"reader@example\">\n            <p class=\"ds-form__error\">This address has no domain ending. A nick is registered by mail.</p>\n          </div>\n        </div>\n        <div class=\"ds-form__row\">\n          <label class=\"ds-form__label\" for=\"f-away\">when away</label>\n          <div class=\"ds-form__field\">\n            <select class=\"ds-form__input ds-form__input--auto\" id=\"f-away\">\n              <option>keep the lines for me</option>\n              <option>mail me the mentions</option>\n              <option>do nothing</option>\n            </select>\n          </div>\n        </div>\n        <div class=\"ds-form__row\">\n          <label class=\"ds-form__label\" for=\"f-words\">mention on</label>\n          <div class=\"ds-form__field\">\n            <textarea class=\"ds-form__input ds-form__input--wide\" id=\"f-words\" rows=\"3\">reader\nstatus line\npager</textarea>\n            <p class=\"ds-form__hint\">One word or phrase a line. Your nick always counts.</p>\n          </div>\n        </div>\n        <div class=\"ds-form__row\">\n          <span class=\"ds-form__label\">privacy</span>\n          <div class=\"ds-form__field\">\n            <label class=\"ds-form__check\"><input class=\"ds-form__checkbox\" type=\"checkbox\" checked> hide my address from /whois</label>\n          </div>\n        </div>\n        <div class=\"ds-form__actions\" data-component=\"buttons\">\n          <button class=\"ds-button\" type=\"button\">Save</button>\n          <button class=\"ds-button ds-button--secondary\" type=\"button\">Reset</button>\n          <button class=\"ds-button ds-button--danger\" type=\"button\">Drop nick</button>\n          <button class=\"ds-button\" type=\"button\" disabled>Export</button>\n        </div>\n      </form>\n    </div>\n    <div class=\"ds-stack\">\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">the client shows</h2>\n        <div class=\"ds-panel__body\">\n          <div class=\"ds-setting\"><label class=\"ds-switch\"><span class=\"ds-switch__label\">joins and parts</span><input class=\"ds-switch__input\" type=\"checkbox\" checked><span class=\"ds-switch__track\"></span></label></div>\n          <div class=\"ds-setting\"><label class=\"ds-switch\"><span class=\"ds-switch__label\">seconds in the time</span><input class=\"ds-switch__input\" type=\"checkbox\"><span class=\"ds-switch__track\"></span></label></div>\n          <div class=\"ds-setting\"><label class=\"ds-switch\"><span class=\"ds-switch__label\">a bell on mentions</span><input class=\"ds-switch__input\" type=\"checkbox\" checked><span class=\"ds-switch__track\"></span></label></div>\n          <div class=\"ds-setting\"><label class=\"ds-switch\"><span class=\"ds-switch__label\">names in colour</span><input class=\"ds-switch__input\" type=\"checkbox\"><span class=\"ds-switch__track\"></span></label></div>\n        </div>\n      </div>\n      <div class=\"ds-dialog__backdrop\">\n        <div class=\"ds-dialog\" data-component=\"dialog\" role=\"dialog\" aria-labelledby=\"dlg-1\">\n          <h2 class=\"ds-dialog__title\" id=\"dlg-1\">drop the nick?</h2>\n          <div class=\"ds-dialog__body\">\n            <p class=\"ds-dialog__text\">reader will be free for anyone to take after 30 days. Your lines stay in the logs.</p>\n            <div class=\"ds-dialog__actions\">\n              <button class=\"ds-button ds-button--danger\" type=\"button\">Drop it</button>\n              <a class=\"ds-button ds-button--secondary\" href=\"#settings\">Keep it</a>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</section>\n\n<!-- View 5, help: the rules and first steps as running text, beside the commands as a folding tree. -->\n<section class=\"ds-view\" id=\"help\">\n  <ol class=\"ds-breadcrumb\">\n    <li><a class=\"ds-breadcrumb__link\" href=\"#lobby\">chronoskin</a></li>\n    <li class=\"ds-breadcrumb__sep\">/</li>\n    <li class=\"ds-breadcrumb__current\">help</li>\n  </ol>\n  <header class=\"ds-page-header\">\n    <div class=\"ds-page-header__main\">\n      <h1 class=\"ds-page-header__title\">Help</h1>\n      <p class=\"ds-page-header__text\">The rules of the place and the commands that get you around it.</p>\n    </div>\n    <div class=\"ds-page-header__action\"><a class=\"ds-button\" href=\"#channel\">Ask in #help</a></div>\n  </header>\n  <div class=\"ds-cols ds-cols--form\">\n    <div class=\"ds-col\">\n      <div class=\"ds-prose\" data-component=\"typography\">\n        <h1>Rules and first steps</h1>\n        <p>chronoskin chat is a small server for people who use and build <strong>chronoskin</strong>. It speaks a plain line protocol, so any client works; this page is one of them.</p>\n        <h2>Three rules</h2>\n        <ul>\n          <li>Be kind. Disagree with the idea, not with the person.</li>\n          <li>Paste text, not pictures of text. Long pastes go to a file.</li>\n          <li>Ask your question at once; do not ask whether you may ask.</li>\n        </ul>\n        <h2>Getting around</h2>\n        <p>Everything is a command typed into the input line at the foot. A command starts with a slash: <code>/join #help</code> opens a channel, <code>/part</code> leaves it.</p>\n        <h3>Windows</h3>\n        <p>Each channel is a window with a number. The window list above the input line shows them, and the one you are reading is cut out of the bar.</p>\n        <h3>Mentions</h3>\n        <p>A line that names you is set on a stronger ground with a mark at its left edge, and its window gets a count.</p>\n      </div>\n    </div>\n    <div class=\"ds-stack\">\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">commands</h2>\n        <div class=\"ds-panel__body\">\n          <div class=\"ds-accordion\">\n            <details class=\"ds-accordion__item\" open>\n              <summary class=\"ds-accordion__title\">channels</summary>\n              <div class=\"ds-accordion__body\">\n                <p><code>/join #name</code> open a channel</p>\n                <p><code>/part</code> leave this one</p>\n                <p><code>/topic text</code> set the topic</p>\n              </div>\n            </details>\n            <details class=\"ds-accordion__item\">\n              <summary class=\"ds-accordion__title\">people</summary>\n              <div class=\"ds-accordion__body\"><p><code>/msg nick text</code> write to one person</p></div>\n            </details>\n            <details class=\"ds-accordion__item\">\n              <summary class=\"ds-accordion__title\">yourself</summary>\n              <div class=\"ds-accordion__body\"><p><code>/nick name</code> take another name</p></div>\n            </details>\n            <details class=\"ds-accordion__item\">\n              <summary class=\"ds-accordion__title\">the server</summary>\n              <div class=\"ds-accordion__body\"><p><code>/list</code> every public channel</p></div>\n            </details>\n          </div>\n        </div>\n      </div>\n      <div class=\"ds-panel\">\n        <h2 class=\"ds-panel__title\">keys</h2>\n        <div class=\"ds-panel__body\">\n          <ul class=\"ds-keys\">\n            <li class=\"ds-key\"><span class=\"ds-key__cap\">alt 1..9</span> window</li>\n            <li class=\"ds-key\"><span class=\"ds-key__cap\">tab</span> finish a nick</li>\n            <li class=\"ds-key\"><span class=\"ds-key__cap\">pgup</span> older lines</li>\n            <li class=\"ds-key\"><span class=\"ds-key__cap\">ctrl l</span> redraw</li>\n          </ul>\n        </div>\n      </div>\n    </div>\n  </div>\n</section>\n\n</main>\n\n<footer class=\"ds-footer\" data-component=\"footer\">\n  <ul class=\"ds-keys\">\n    <li><a class=\"ds-footer__link\" href=\"#help\">rules</a></li>\n    <li><a class=\"ds-footer__link\" href=\"#logs\">logs</a></li>\n    <li><a class=\"ds-footer__link\" href=\"#settings\">settings</a></li>\n  </ul>\n  <p class=\"ds-footer__text\">chronoskin chat 3.2.0, a plain text server run by its users</p>\n</footer>\n\n<div class=\"ds-dock\">\n  <nav class=\"ds-nav\" data-component=\"nav\">\n    <p class=\"ds-nav__clock\">[14:02]</p>\n    <ul class=\"ds-nav__list\">\n      <li><a class=\"ds-nav__link\" href=\"#lobby\"><span class=\"ds-nav__num\">1</span><span class=\"ds-nav__name\">lobby</span></a></li>\n      <li><a class=\"ds-nav__link\" href=\"#channel\"><span class=\"ds-nav__num\">2</span><span class=\"ds-nav__name\">#general</span></a></li>\n      <li><a class=\"ds-nav__link\" href=\"#logs\"><span class=\"ds-nav__num\">3</span><span class=\"ds-nav__name\">logs</span></a></li>\n      <li><a class=\"ds-nav__link\" href=\"#settings\"><span class=\"ds-nav__num\">4</span><span class=\"ds-nav__name\">settings</span></a></li>\n      <li><a class=\"ds-nav__link\" href=\"#help\"><span class=\"ds-nav__num\">5</span><span class=\"ds-nav__name\">help</span></a></li>\n    </ul>\n    <p class=\"ds-nav__act\"><span class=\"ds-nav__word\">unread</span> <span class=\"ds-badge\">3</span></p>\n  </nav>\n  <label class=\"ds-dock__input\"><span class=\"ds-dock__who\">[reader]</span><input class=\"ds-form__input\" type=\"text\" placeholder=\"type a line, or /help\"></label>\n</div>\n\n</div>\n</body>\n</html>\n",
    "style.json": "{\n  \"id\": \"v1.terminal.app.s07.p01.t02.u04\",\n  \"library\": \"2026.10.09-1346\",\n  \"era\": {\n    \"slug\": \"terminal\",\n    \"years\": [\n      2015,\n      2026\n    ]\n  },\n  \"archetype\": \"app\",\n  \"mode\": \"mix\",\n  \"markup\": \"modern\",\n  \"viewport\": {\n    \"width\": 1280,\n    \"fluid\": false,\n    \"responsive\": true\n  },\n  \"source\": \"https://chrono.skin/s/v1-tm-7124\",\n  \"short\": \"v1-tm-7124\"\n}\n",
    "tokens.css": "/* @part palette */\n:root {\n  --color-page: #000000;\n  --color-canvas: #030a05;\n  --color-surface: #061208;\n  --color-surface-alt: #0a1a0d;\n  --color-surface-strong: #0f2614;\n  --color-bar: #38c85a;\n  --color-bar-text: #000000;\n  --color-bar-alt: #0f2614;\n  --color-bar-alt-text: #6fe38a;\n  --color-inverse: #9df5ae;\n  --color-inverse-text: #000000;\n  --color-text: #38c85a;\n  --color-text-muted: #2a8f44;\n  --color-heading: #9df5ae;\n  --color-heading-alt: #d7ff5f;\n  --color-link: #9df5ae;\n  --color-link-quiet: #38c85a;\n  --color-link-visited: #5fa87a;\n  --color-link-hover: #e8f0e8;\n  --color-link-active: #d7ff5f;\n  --color-border: #1f6b33;\n  --color-border-strong: #38c85a;\n  --color-border-muted: #12401f;\n  --color-accent: #d7ff5f;\n  --color-accent-text: #000000;\n  --color-accent-alt: #5fd7af;\n  --color-fill-1: #061208;\n  --color-fill-2: #0a1a0d;\n  --color-fill-3: #0f2614;\n  --color-fill-4: #0a1a0d;\n  --color-button: #38c85a;\n  --color-button-text: #000000;\n  --color-button-hover-text: #000000;\n  --color-button-secondary: #0a1a0d;\n  --color-button-secondary-text: #9df5ae;\n  --color-input: #000000;\n  --color-input-text: #9df5ae;\n  --color-input-border: #1f6b33;\n  --color-disabled: #0a1a0d;\n  --color-disabled-text: #1f6b33;\n  --color-danger: #ff5f5f;\n  --color-danger-surface: #1a0505;\n  --color-success: #5fff00;\n  --color-warning: #ffd75f;\n  --color-notice: #0a1a0d;\n  --color-notice-text: #9df5ae;\n  --color-focus: #d7ff5f;\n  --color-shadow: #000000;\n  --color-overlay: #0a1a0d;\n}\n\n/* @part type */\n:root {\n  --font-body: \"IBM Plex Mono\", \"Courier Prime\", \"Courier New\", Courier, monospace;\n  --font-heading: \"IBM Plex Mono\", \"Courier Prime\", \"Courier New\", Courier, monospace;\n  --font-ui: \"IBM Plex Mono\", \"Courier Prime\", \"Courier New\", Courier, monospace;\n  --font-mono: \"IBM Plex Mono\", \"Courier Prime\", \"Courier New\", Courier, monospace;\n  --text-base: 16px;\n  --text-small: 14px;\n  --text-ui: 15px;\n  --text-large: 18px;\n  --text-display: 38px;\n  --text-h1: 26px;\n  --text-h2: 19px;\n  --text-h3: 16px;\n  --line-body: 1.5;\n  --line-heading: 1.25;\n  --line-display: 1.1;\n  --weight-body: 400;\n  --weight-bold: 600;\n  --weight-heading: 600;\n  --weight-display: 600;\n  --weight-ui: 500;\n  --heading-transform: none;\n  --heading-tracking: 0;\n  --display-tracking: 0;\n  --figure-shift: 0em;\n  --ui-transform: lowercase;\n  --link-decoration: none;\n  --link-decoration-hover: underline;\n  --link-decoration-quiet: none;\n}\n\n/* @part surface */\n:root {\n  --border-width: 2px;\n  --border-width-strong: 2px;\n  --border-style: solid;\n  --radius-control: 0;\n  --radius-panel: 0;\n  --radius-pill: 0;\n  --radius-page: 0;\n  --shadow-panel: 4px 4px 0 var(--color-shadow);\n  --shadow-control: 2px 2px 0 var(--color-shadow);\n  --shadow-control-hover: 4px 4px 0 var(--color-shadow);\n  --shadow-control-pressed: inset 2px 2px 0 var(--color-shadow);\n  --shadow-dialog: 12px 12px 0 var(--color-shadow);\n  --shadow-text: none;\n  --fill-page: var(--color-page);\n  --fill-bar: var(--color-bar);\n  --fill-bar-alt: var(--color-bar-alt);\n  --fill-inverse: var(--color-inverse);\n  --fill-accent: var(--color-accent);\n  --fill-panel: var(--color-surface);\n  --fill-button: var(--color-button);\n  --fill-button-hover: color-mix(in srgb, var(--color-button) 85%, white);\n  --fill-button-secondary: var(--color-button-secondary);\n  --fill-input: transparent;\n  --focus-ring: 2px dotted var(--color-focus);\n  --transition: none;\n  --backdrop-blur: 0px;\n}\n"
  }
}
