Ascenda Wiki
Ledger
Ascenda · internal documents

Ledger

A system for pages that explain a mechanism. Bone paper, ink rules, one teal accent — prose that reads, data that lines up, and structure you can scan without reading a word.

3 typefaces 1 accent 0 shadows 2px corner radius
principles

Five rules that make it cohere

One

Three faces, three jobs

Grotesque names things. Serif explains them. Mono is for anything the machine produced — descriptors, keys, counts, labels. A number the system computed is always mono; a number you wrote in a sentence is not.

Two

Rules, never shadows

Depth comes from hairlines and inverted bars. There is no box-shadow anywhere in the system. Two line weights only: --rule separates regions, --hair separates rows inside one.

Three

Spend the accent on meaning

Teal marks the thing being pointed at — the match, the answer, the path taken. It is never decoration, never a section header, never a border for its own sake. If everything is accented, nothing is.

Four

Corners are square

2px everywhere. The one exception is .chip, which is a pill so it reads as tappable rather than as a cell. Resist rounding anything else; the squareness is most of the ledger feeling.

Five

Prose stays in the column

Running text is capped at --col (66ch). Panels, figures and grids break out past it — that contrast between a narrow argument and a wide instrument is the page's rhythm.

colour

Tokens

Every value below is read live from the stylesheet, so this page cannot drift from the CSS. Switch the theme above and watch them change.

The theming contract

The viewer has three states, not two. An explicit choice stamps data-theme on the root; the default “system” setting stamps nothing, and only prefers-color-scheme separates light from dark. So dark is defined twice, and the media query is guarded so an explicit light choice beats a dark OS.

:root { --paper:#E7E6DE; --ink:#141917; /* complete light palette */ }

@media (prefers-color-scheme:dark) {
  :root:not([data-theme="light"]) { --paper:#101412; --ink:#E6E8E2; }
}
:root[data-theme="dark"] { --paper:#101412; --ink:#E6E8E2; }

Never declare a colour only inside a media or [data-theme] block — it will be undefined for the majority of viewers, who are in the un-stamped default state. Always give body an explicit background token; a transparent body borrows the host's ground and breaks in one theme.

contrast

Every pair, audited live

Computed from the tokens currently in effect. AA wants 4.5:1 for body text and 3:1 for large text, icons and UI edges. Switch themes and the numbers recompute — both palettes have to hold.

WCAG 2.1 contrastsystem
type

Scale and specimens

Uppercase mono labels always carry letter-spacing — .18em for eyebrows, .16em for block labels, .12em to .14em for badges and micro-labels. Without it they read as shouting rather than as signage.

components

The parts

Panel

The workhorse. A bordered readout with an inverted title bar, divided into labelled blocks. Use it for anything that behaves like an instrument.

Resolver
Data rows & states
  1. fullMERCADO LIVRE COMPRAmiss
  2. phraseMERCADO LIVREmatched
  3. tokenMERCADOnot reached
  4. skippedLIVRE COMPRAstopword edge
  5. tokenMERCADOwrong merchant
Controls
Result grid
Merchant
Mercado Livre
Category
shopping
Matched on
MERCADO LIVRE
How
alias, exact
<div class="panel">
  <div class="panel-bar"><span class="eyebrow">Title</span></div>
  <div class="panel-body">
    <div class="block">
      <div class="block-label">Section</div>
      <ol class="rows">
        <li class="is-hit">
          <span class="badge accent">phrase</span>
          <span class="row-value">MERCADO LIVRE</span>
          <span class="row-note">matched</span>
        </li>
      </ol>
    </div>
  </div>
</div>

Callouts

One line of consequence, not a paragraph. Accent for the conclusion, warn for the broken path, flag for something a human still has to decide.

Matched on the phrase tier — the rung that did not exist before.
A generic word earlier in the string outranked the two-word brand.
Three merchants still have no category prior and will cold-start.

Stats

Figures that should be read at a glance, not in a sentence. Display face for the number, mono for the label, tabular figures so columns align.

310aliases
269merchants
251priors
0regex rules

Figure

Hand-authored inline SVG only. Strokes and text in currentColor so both themes work; a literal var(--accent) is reserved for the one mark carrying the argument. Label the arrows — an unlabelled arrow means “related somehow”.

descriptor normalize lookup keys match merchant
Caption states what the picture shows, in mono, under 70ch. The aria-label carries the same claim for readers who cannot see it.
using it

Starting a page

Link the fonts, link ledger.css, then write structure. The system assumes a single-column document with occasional full-width instruments.

<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,800&family=IBM+Plex+Mono:wght@400;600&family=Source+Serif+4:opsz,wght@8..60,400;8..60,600&display=swap">
<link rel="stylesheet" href="ledger.css">

<header class="masthead">
  <div class="eyebrow">Project · context</div>
  <h1>Page name</h1>
  <p class="standfirst">One sentence saying what this explains.</p>
  <div class="meta"><span><b>310</b> aliases</span></div>
</header>

<section class="section">
  <div class="sec-head col"><span class="eyebrow">label</span><h2>Heading</h2></div>
  <div class="col"><p>Prose stays in the column.</p></div>
  <!-- panels, figures and grids break out past it -->
</section>

For an Artifact, inline ledger.css into a <style> block instead of linking it — the sandbox blocks every external host except Google Fonts.

Scope. Ledger is for internal explainers, plans and post-mortems — documents that argue something. It is deliberately not the Ascenda product identity: the app keeps Poppins and the blue-to-purple gradient. Two systems, two jobs.

  • Section labels are words, not numbers. Number a sequence only when the order carries information.
  • Every eyebrow is a noun naming its region — principles, contrast, using it. If you cannot name it in one word, the section is doing two things.
  • Semantic colour (accent, warn, flag) is separate from decoration. A row is not teal because teal is nice; it is teal because it matched.
Copied