AvisoMétodoAPI← o jornalv0.23.6

The design review

The design review, item by item

The editor commissioned a design and readability review, with the complaint that «the current design is hard to read, and doesn't look as professional and smooth as a news or powerful blogging site should look like». The review arrived in an encrypted vault and did something unusual for a design review: it measured. This page is what was done about each of its items, and — for the ones that were not done — what specifically blocks them. A review with items silently dropped is worse than one with items marked undone, because the reader of the first cannot tell «considered and rejected» from «forgotten». The review's second part arrived as vault v0.5.0 and is about the back office: §5 below. It found the console to be «a report about the newsroom, not a console for operating it» — 7,058px of state across nine pages with zero controls on eight of them — and it is right. What the review counted as good and what survived unchanged is not listed as work done, because it was not work: the pipeline model, the department boundaries, the gates and above all the mail protocol are still exactly what they were.

25 done 8 deferred 5 partly done 4 the editor decides

Source: the encrypted vault e54hfntq, version v0.5.0, reviewed against site build v0.6.0. The review is not copied into this repository: it is a vault the editor holds, and a copy here would disagree with it the first time it was updated. What this page carries is the disposition of each item, which is this repository's business and not the vault's.

Where the review was wrong, and how we know

The review measured rather than asserted, which is why it was worth implementing. Two of its numbers were still wrong, and one of them changed the answer. Recording that is not scoring a point: an implementation that had followed the review exactly would have shipped a column that still missed the review's own target, and nobody would have known.

§2.1 — «.std: 34em ≈ 66 characters» and «.sm: 38em ≈ 68 characters», from an assumed average glyph width of 0.48em.

Newsreader's average glyph, measured in Chromium on a canvas at the element's own computed font with real Portuguese text, is 0.405em — about 18% narrower than assumed. Two things follow. The problem was WORSE than reported: the 758px column held ≈104 characters, not 88, and the 828px entity column ≈114, not 96. And the prescription did not reach its own target: 34em is 612px, which measures 84 characters — still above the 75 that §4.4 fixes as the ceiling.

Consequence: The site is set to 29em, not 34em, and measures 71 characters. Gate 29 uses 0.405 and says where the number came from. An implementation that had followed the review exactly would have shipped a column that missed the review's own target.

§2.1b — 34em and 38em give «≈66» and «≈68» characters respectively.

They cannot both be right. Characters per line is width divided by average glyph width, and with the width expressed in `em` the font size cancels — the same `em` measure gives the same character count at any size. 34em and 38em cannot yield 66 and 68.

Consequence: Minor next to the other, and worth recording because it is the kind of internal inconsistency that a reader of the review would otherwise carry forward. Both classes are set to the same measure.

§4.1 — pure CSS, shipped · 10 items

done §2.1 held by gate 29 + gate 30

Measure: the column ran 88–96 characters

`.std` and `.sm` now carry `max-width: 29em` in the stylesheet, and the 54 inline `max-width` declarations the generators emitted on body-text classes were removed — an inline value beats the class, so a single survivor would have undone the fix on that page without failing anything.

measured: 71 characters on the front page, 70 on an entity page, measured in Chromium on a canvas at the element's own computed font

assets/site.css · build/build.py · build/artigos.py · build/entidades.py · build/paginas_extra.py

done §2.2 held by gate 29

Leading: 1.45 where a serif on cream wants 1.6–1.65

`.std` 1.62, `.sm` 1.6, `.xs` 1.55.

measured: line-height 29.16px at 18px

assets/site.css

done §2.3 held by gate 32

`-webkit-font-smoothing` was thinning the serif

Deleted, and a comment in its place says why it must not come back — it forces grayscale antialiasing and draws the type lighter than specified, which takes weight out of exactly the strokes Newsreader needs at 15–18px.

assets/site.css

done §2.4 held by gate 27

The hairlines could not be seen: 1.36:1 and 1.62:1

`--filete` → #9f9780 and `--filete-2` → #8f8873. The stylesheet's whole thesis is «filetes, não caixas» — structure carried by rules — and the structure was being carried by lines that are not there on a bright screen. That is why the front-page blocks appeared to run into each other.

measured: 2.65:1 and 3.22:1 against the paper

assets/site.css

done §3.3 held by gate 28

Three of four status colours failed or scraped WCAG AA

The whole ramp darkened. `--disputa` was at 4.48:1 — below the line — while carrying verification state at 11px, on a publication whose entire proposition is that a reader can see the verification state of every claim.

measured: --acento 6.83:1, --aviso 6.06:1, --disputa 5.81:1, --sec-2 5.80:1, --falta 5.89:1

assets/site.css

done §3.7 held by gate 32

No focus styles anywhere, on a design with no underlines

`:focus-visible` with a 2px accent outline, and a variant that switches to the light accent over the dark panel. This was an accessibility failure and not a preference.

assets/site.css

done §2.16 held by gate 32

`color-scheme` undeclared

`color-scheme: light` on `:root`, so form controls and scrollbars follow the page rather than the operating system. Dark mode itself is decision 3 and was not taken.

assets/site.css

done §2.6 held by gate 31

Mono was setting the whole site — the dominant cause of «doesn't look like a news site»

`.kick`, `.sect`, `<th>` and the prose of the `.agent` block all move to Newsreader; the `<code>` inside the agent block stays mono, because that is what it is. The rule now written into the stylesheet: mono means one thing, a machine fact — a hash, a byte count, an identifier, a timestamp, a path, code.

assets/site.css

done §2.5

The accent had seven jobs, so it signalled none

The kicker came off the accent. The accent now means two things: interactive, and confirmed.

assets/site.css

done §3.6 held by gate 31

`.kick` and `.sect` combined all four legibility penalties

Both to the serif at 13px; the kicker loses uppercase and drops to .01em tracking, the section label keeps small caps at .08em. Uppercase at .14em is only legible above ~14px.

assets/site.css

§4.2 — generator fixes · 8 items

done §3.1 held by gate 33

A 60-row table with an entirely empty column, in production

The generator drops a column that is empty on every row of that table. The review counted 67 of 67 in /empresas/; the new gate found the same fault in /instituicoes/ and /casos-de-uso/, which the review had not visited. Worse than a blank column: it pushed «Fonte congelada» about 1100px away from the name it belongs to.

build/build.py

done §3.4 held by gate 33

`nao resolve` — an unaccented word in the status vocabulary

The identifier `nao_resolve` is ASCII and stays so; what was wrong was the generator turning `_` into a space and putting an identifier dressed as a word on the page. There is now a written label vocabulary, and a state with no label shows its raw identifier — visible and odd — rather than a laundered one. The review then said the right thing: that a missing accent suggests the strings are being written somewhere ASCII-only, and that is worth an audit. It was: the audit of `dados/` found the same pattern in the board card titles, which this very session had introduced hours earlier by de-slugging filenames.

build/build.py · build/backoffice_team.py · redacao/correio/*/assuntos/

done §3.5 held by gate 33

The version was displayed but not linked

Both the chrome badge and the version in every page's agent block are now links to that version's own row, and all twelve rows in admin/versions.html gained the anchor their number names. sgit.ai's guidance asks for both halves; half was done, and on a site whose entire proposition is traceability this was the one place the site did not trace itself.

build/paginas.py · admin/versions.html · assets/site.css

done §2.9

Article cards had no dateline

Every card on the front page now carries the date of its article's folder. /empresas/ already had it in a column; the front page did not.

build/build.py

done §2.1b held by gate 30

Remove the inline `max-width:46em` the generators emit

54 removed, from the body-text classes only. The ones on `.h-lead`, `.h-2` and `.prosa` were left: those control where a HEADLINE wraps, which is a per-instance typographic choice, and the review is explicit that the headline wants the full column even where the body does not.

build/build.py · build/artigos.py · build/entidades.py · build/paginas_extra.py

done §3.8a

The mobile nav rule did nothing

The media query set `overflow-x: auto` but never unset `flex-wrap: wrap`, and a flex container that wraps never overflows — so the rule had no effect and the eleven items broke onto three rows with the `|` separator dangling at the start of the third. `flex-wrap: nowrap` was the missing line; the nav is now one row that scrolls inside itself.

assets/site.css

the editor decides §3.2

Three of six front-page cards repeat stories already on screen

NOT done, and deliberately. The fix is a five-line filter. But §4.5 decision 5 asks the editor to confirm that a front page showing three stories instead of six — visibly emptier, and more honest — is acceptable. De-duplicating without that answer would be an agent making an editorial judgement about how thin the edition may look.

What blocks it: Decision 5. The filter is ready; it is one condition in build/build.py.

deferred §2.14

Raw identifiers used as human link text

Not done. The path is the truth and must stay reachable, and replacing it with a label needs a label to exist — which means deciding, per edge, what a human-readable rendering of that relation is. That is the same work as §2.13's entity template and belongs with it.

What blocks it: Needs the entity template (§2.13), which is §4.3 structural work.

§4.4 — measurement · 2 items

done §4.4 held by it is the gate

«Do not re-review by eye» — the numbers, asserted

build/gates_desenho.py, gates 27–33, wired into build/tudo.py as the fourth of five gates. It asserts contrast for every rule and status token, the measure and leading, that no generator emits an inline max-width on a body class, that mono appears only where the stylesheet means a machine fact, that the focus ring exists, that no table ships an empty column, that no status chip lost its accent, and that the version badge links. A design review without a gate undoes itself over three releases.

build/gates_desenho.py · build/tudo.py

partly done §4.4b

The two numbers a file cannot hold

Chrome height above the masthead at 390px, and the count of elements the BROWSER resolves to mono, both need a browser and the cascade. They are measured by hand this release — 131px and 81 elements — and neither is at its target, because both depend on splitting the header strip, which is §4.3 work. They belong in admin/build/render.mjs, where there is a Chromium.

What blocks it: Both are consequences of §2.12 / §4.3 item 20, not separate fixes.

measured: chrome 131px against a target of ≤48px; 81 mono elements on the front page

§4.3 — structural, not done · 9 items

partly done §3.9

The design system lives in generated HTML, not the stylesheet

The review calls this the blocker and it is: column spans, borders, padding, gaps and even colours are emitted as inline `style=` by the generators, and nobody can change this site's rhythm from site.css while that is true. This release removed the 54 that were actively fighting the measure fix, and gate 30 stops those coming back. The rest — named classes for `.lead-col`, `.rail`, `.bloco-nota`, `.stat-linha` — is untouched.

What blocks it: A large mechanical change across five generators, with no visible result on its own. It wants its own release and its own review, not a corner of this one.

deferred §2.10

No spacing scale — the rhythm lives in inline styles

Not done. Depends on §3.9: a scale in the stylesheet is only useful once the generator emits class names instead of padding literals.

What blocks it: Blocked on §3.9.

deferred §2.12

The utility chrome outranks the publication

Not done. Two of the six things in the strip are editorial (dateline, countdown) and four are operator tooling (back office, wallet, version, API), set identically so the reader cannot tell which is which. Splitting the strip is also what fixes the 131px of chrome above the masthead on a phone, and it interacts with decision 4 — whether the wallet belongs in a reader's header at all.

What blocks it: Interacts with decision 4, which is the editor's.

deferred §3.8b

On a phone the operator chrome takes the first third of the screen

The nav half is fixed (see §3.8a). The strip half is not: 131px of dateline, countdown, four tool links, a wallet balance and a version string still arrive before the masthead.

What blocks it: Same change as §2.12, same decision 4.

measured: 131px measured at 390×844, against the review's target of ≤48px

deferred §2.11

The front-page grid leaves a hole

Not done, and visible: roughly 270px of empty paper in the left column before the next rule. Column balancing needs the grid to be describable from the stylesheet first.

What blocks it: Blocked on §3.9.

deferred §2.13

Entity pages have no shape

Not done. These are the most numerous pages on the site — 312 nodes — and they are an h1, a wide definitional paragraph, a ONE-ROW table used for a single key/value pair, a two-item list and the graph. They want one template with a stat strip, and the one-row table pattern killed entirely.

What blocks it: A template is a design decision of its own size; it also carries §2.14.

the editor decides §2.8

Provenance telemetry occupies the lead position

NOT done. Directly under the lead headline, where a newspaper puts the dek, sit three bordered 11px chips of character counts. The provenance IS the product and stays on the page — but where it ranks is an editorial position about what this publication leads with, and that is decision 2.

What blocks it: Decision 2.

partly done §2.7

Two competing heading ladders on the same page

Partly resolved as a side-effect: `.sect` and `.h-2` are no longer in the same face, so the two ladders stopped looking like one system badly applied. The rule about which is which — structural label vs title of content — is not yet written down or enforced.

assets/site.css

the editor decides §2.15

The site has one image, and it is the graph

NOT done. The review's own framing: there is no photography, which is a defensible position for a publication that will not reproduce what it cannot verify, but the consequence is that every module below the masthead has identical weight and the page has no focal point. The proposed answer — the graph as the site's visual language, a generated thumbnail per entity and per card — is a significant build and changes what the front page is. Decision 1.

What blocks it: Decision 1.

§1 — what had to survive, and did · 1 items

done §1.x

The ten things the review said not to break

The face selection and the subset for Portuguese accents, the masthead, the double nav rule, the warm paper and cool near-black, the «filetes, não caixas» discipline, the mobile work, the `a.ent` link-density pattern, the honest content model, and — the one most at risk from a redesign — the stylesheet's own comments. §4.6 warns that an agent which changes a rule and leaves its comment has made the file actively misleading. Every comment over a changed rule was rewritten, one superseded block was deleted rather than left above the block that replaced it, and the header's colour list now carries the measured ratio of each token.

assets/site.css

§5 — the back office, a console of its own · 12 items

done §5.1 held by gate 40 (browser) + the render gate's pt-queue check

«The back office is a report about the newsroom, not a console for operating it»

The console page now opens with what is waiting on the editor of record, as `pt-queue` — the first thing on the page and the only filled rank on it. The list is derived by `backoffice.fila()` from four sources that each already knew a piece of the answer: the editor's own board lane, cards on another agent's lane whose `bloqueado_por` is the editor, paper issues the formula assigns to the editor, and mail sitting in their inbox. There is no count attribute anywhere — the rail badge and the queue heading are both `len()` of the same list, so they cannot disagree.

measured: 13 items derived, against the 1 the old console showed — a single cell in row 6 of the first table, in the base chip style

build/backoffice.py · assets/components/pt-queue/v1/v1.0/v1.0.0/

partly done §5.2

It wore the newspaper's clothes: the console loaded site.css

`assets/console.css` is adopted from the vault: cool neutrals, a dark rail, system sans, tabular numerals, real buttons, and the publication's serif surviving only in `.quote`, where the console shows the newspaper's own words. It is loaded second and wins everything below the operator strip.

What blocks it: site.css is still loaded first, for the operator strip and for nothing else. The editor's instruction in v0.11.0 is that the top-level menu must not move when you cross from the paper to the back office, and the proposal replaces the whole chrome, which would have moved it again. So the strip keeps the paper's rules and the paper's ground, gate 40 measures both pages in a browser and fails on a difference of more than a pixel, and the one cost — site.css's `.nav` landing on the rail's items and rendering the rail centred — is answered by a closed reset in console.css.

measured: the strip at x=56 y=8 1168×33 on the paper and in the console, measured in Chromium

assets/console.css · build/backoffice.py · admin/build/render.mjs

done §5.3 held by gate 33 (no state without its accent)

Nothing told you what needed you, and «a human is blocking this» was said ten ways

One scale, four ranks, and only rank 1 is filled. The pipeline's own stage 6 — the most important state in the back office and previously the least visible of the ten, because it used the base chip style while nine lesser places used `.chip.miss` — is rank 1 on a tinted stage. Two mappings the paper's classes had backwards were corrected at the source rather than in the layer: the design review's `parcial` was rendering filled red (which now means a human must act) and `editor` — the one disposition that does mean that — was rendering as the quiet neutral outline.

measured: 159 distinct chip labels → 4 ranks; the board 158 chips → 25 ranks; the design review 124 → 39

build/backoffice.py · build/backoffice_team.py · build/backoffice_design.py · build/backoffice_bridges.py

done §5.4 held by gate 19

Every page opened with the same 70 words

The preamble is on `guidance.html` and nowhere else. What every page carries instead is one sentence in the rail — permanently visible, never above the content. That is not a softening of the rule: gate 19 requires every back-office page to say it is not the publication, because the whole area is in English by the editor's decision and the condition of that exception is that a reader who lands here can see it. The gate is unchanged and still finds its string.

measured: 9 of 9 pages repeating ~300px of prose → 1 page carrying it in full, 10 carrying one sentence in the rail

build/backoffice.py · assets/console.css

done §5.5

Zero `<h2>` in the entire back office, and five of nine pages with no heading at all

All 34 section titles became real `<h2>` elements — they were `.sect` divs, which are styling and not structure, so nothing could outline these pages. Every page now has exactly one `<h1>` and it NAMES the place: the console's used to be a sentence in the publication's voice, «What the newsroom has done, what it is waiting on, and who is allowed to do what», which describes a page rather than labelling where you are standing. What still wears `.sect` is a field label inside a card — «Refuses», «Writes in» — because promoting those would have put 60 more entries in every outline and made it useless a different way.

measured: h1: 1 on every one of the 10 pages, against 4 of 9 before. h2: 2–10 per page, against 0 across the whole back office

build/backoffice.py · build/backoffice_team.py · build/backoffice_bridges.py · build/backoffice_design.py

deferred §5.6

The console declared itself English and was 30–40% Portuguese

The furniture is English throughout — the rail's labels, the headings, the page names. Nothing was translated.

What blocks it: The Portuguese that remains in the running prose is QUOTED: an agent's mission, a board card's own reading of its work, the formula's `porque` column, a mail subject. Those are records this publication keeps about itself, in the language it keeps them in, and the arrangement for reading them is the one the ontology already uses — the record stands and the `en` block annotates it. Paraphrasing a record on the way to a screen is how a console starts to drift from the files it reports on. Where a record has no `en` annotation, adding one is Redação's write and not this agent's.

dados/agentes.json · dados/quadro.json

done §5.7

Eleven flat navigation items at 12px mono, no grouping, no counts

A rail, grouped Operate / Understand / Reference, with the current page marked by `aria-current="page"` rather than by weight alone — weight is a styling convention and not something an outline or a screen reader can read. Counts sit on the three items that can be behind, and a zero is never a badge: a count that is always there has stopped being a signal.

measured: 11 flat links → 3 groups of 11, 3 carrying a count

build/backoffice.py · assets/console.css

partly done §5.8

«Eight of the nine pages have zero buttons, inputs, selects or textareas»

The bridges page's controls — which were the only real controls in the back office and were dressed as status chips, in the same box as «secret» and «in transit» — are now real buttons and real fields: primary for keeping a credential, danger for forgetting one. The queue's action names the file it would write in its `title`, so an operator who does not trust a button can do the same thing by hand.

What blocks it: A button cannot write a file on a static site: there is no server to write it. So the queue's buttons GO TO THE PLACE THE WRITE HAPPENS — the document browser for a file, the mail page for a thread, the bridges page for a message to the newsroom — and nothing claims to have written anything. Making them act is the append lane's job, and the lane is built and has no credentials: that is §5.10 and the editor's.

measured: console 0 controls → 13 (one per queue item); bridges 7 chips-as-buttons → 6 buttons and 3 fields

build/backoffice_bridges.py · build/backoffice.py

done §5.9

The mail model is the best thing here and was explained in a paragraph and a table

Shown as the route a message walks — `saida/ → expedicao/ → entrada/ → tratado/`, each folder carrying the rank its state means — which needs no paragraph. The protocol's own four-row table is still published, folded into a `<details>`: the detail is real and worth having and it is not what the page is for. The mailbox table gained a state column and the editor's row is marked on the ROW, because a state marked only inside a cell is one you have to hunt for by reading every row.

build/backoffice_team.py · assets/console.css

the editor decides §5.10

«The vault channel gets a real thread view» with a reply box that writes a file

Not built. The threads are rendered and the route is visible; the reply box is not.

What blocks it: A reply box that writes a file needs the append lane, and the lane needs three values this repository may not hold: the vault id, the append token and the public key. They go to the editor's own browser via /backoffice/bridges.html and nowhere else — `admin/build/validate.js` carries a key-shaped-string tripwire and would fail the build if one appeared. Until the editor hands a browser those values there is nothing to write with, and inventing a box that does nothing would be the one thing this publication says it never does.

build/backoffice_bridges.py · assets/ponte.js

done §5.11

Filenames: the proposal asks for mail.html / board.html / team.html

Renamed. `correio.html` → `mail.html`, `quadro.html` → `board.html`, `equipa.html` → `team.html`, `pontes.html` → `bridges.html`, `desenho.html` → `design.html`, and no redirect page left behind for any of them. The editor's ruling is what unblocked it: this site has no users and no SEO yet, so it is still cheap to break an address, and a set of stub pages saying «this moved» is worse than a clean tree. `/backoffice/viewer.html` went with them — it was exactly such a stub, kept since v0.3.1 to forward to `docs.html`, and it is deleted rather than renamed. `index.html` is NOT renamed to `console.html`: `/backoffice/` is the address the rail and the paper's footer link, a directory wants an index, and a `console.html` beside an `index.html` that both had to exist is the stub this rename exists to avoid. The three generator modules took English names too — a module called `equipa.py` that writes `team.html` is the same drift one level down.

measured: 5 pages renamed, 1 deleted, 0 redirect stubs; 238 pages and every link resolving

build/backoffice.py · build/backoffice_team.py · build/backoffice_bridges.py · build/backoffice_design.py · admin/build/render.mjs · build/gates_artigos.py

deferred §5.12

Page height: «7,058px on the console, proposed ~2,600px»

The queue's own prose is cut to one line per item — thirteen cards printed in full made the queue 4,000px tall, which is the same failure as the 70-word preamble one screen further down. The preamble going saved ~300px on eight pages.

What blocks it: The rest of the height is CONTENT: the agent roster, every article, every section, the delivery records, the run records, the commit log. Reaching 2,600px means deciding which of those the console stops showing, and that is an editorial decision about what the operator needs to see rather than a design one. The measured page is longer than before because the queue was added, not because anything was padded.

measured: console 11,056px; the queue itself 13 items in ~1,400px

build/backoffice.py

The five decisions the review reserved for the editor

§4.5 of the review says, in as many words: "Agents: do not pick these yourself." None of them is picked here. Each is a card on the editor's board.

decision 1§4.5.1

Should the graph become the site's visual language?

It is the one intervention that would give the site a visual identity without importing a single unverifiable photograph — and it is a significant build that changes what the front page is. The review offers: yes, no, or prototype one page first.

The options: yes / no / prototype one entity page first

on the board: redacao/correio/dinis.humano/assuntos/abertos/005

decision 2§4.5.2

Where do the provenance chips go?

All three options preserve the information; they rank it differently, and that ranking is an editorial position about what this publication leads with. An agent choosing it would be choosing the paper's voice.

The options: a line of prose under the lead / expand on click / move to the rail

on the board: redacao/correio/dinis.humano/assuntos/abertos/006

decision 3§4.5.3

Dark mode?

Worth having for a reading site, but it doubles the palette work and the paper-and-ink metaphor does not transfer for free — a cream page inverted is not a newspaper, it is a terminal.

The options: yes / no / later

on the board: redacao/correio/dinis.humano/assuntos/abertos/007

decision 4§4.5.4

Does the wallet stay in the reader's header?

A balance immediately above a masthead is unusual. The question is whether it is there to be seen by readers or is operator tooling that belongs behind the back-office link — and the answer decides how the header strip gets split, which blocks §2.12, §3.8b and the 131px of chrome on a phone.

The options: reader header / operator strip / behind the back office

on the board: redacao/correio/dinis.humano/assuntos/abertos/008

decision 5§4.5.5

How thin is the edition allowed to look?

De-duplicating the card grid means the front page shows three stories instead of six. By this publication's own standards that is better — the reader currently reads the lead headline twice before scrolling once — but it is visibly emptier, and «visibly emptier» is a judgement about the paper and not about the code.

The options: de-duplicate now / keep six and make the second cut mean something else / wait for more stories

on the board: redacao/correio/dinis.humano/assuntos/abertos/009

On the one item that looks small and is not. §3.9 is the item to read twice. The design system lives in inline `style=` attributes in the Python generators — column spans, borders, padding, gaps, colours — and not in site.css. The review is right that most of its own section 2 cannot be delivered until that is fixed, and right that fixing it changes nothing visible on its own. This release took the 54 inline declarations that were actively cancelling the measure fix and added a gate so they cannot return; the rest is a release of its own. Anyone picking it up should read §4.6 first: the stylesheet's comments are the best documentation in this repository, and the work touches nearly every rule they describe.

For an agent. Generated by build/newsroom.py from the files in this repository; nothing here is hand-written. The machine-readable index of the publication is at llms.txt. Source: github.com/SGit-AI/SGit-AI__Website__Newsroom__PT · file: newsroom/design.html · version v0.23.6.