What Verbatim looks like and the rules that hold it together: the palette and where its values live, the type, the shape and layout rules, the motion rules, and the accessibility floor. Everything here is true of the stylesheets as they stand. Where a figure is not known, it says so.
The chrome is glass. The record is paper. The refusal gets nothing.
Navigation, rails, panes and controls are translucent, because you look past them a thousand times a day. Claims, citations, quoted source text, the diff and every table of record are flat and opaque, because a document a regulator may read should not shimmer. Blur behind body text costs legibility, and a translucent tariff clause is a worse tariff clause.
Then one surface goes past paper. A claim the system refused to assert carries no effect at all — no blur, no shadow, no transform, no transition, no hover, no cursor change. Everything else on a Verbatim screen answers a cursor. A reader who moves across a change page and feels the interface go dead at exactly the claim the system declined to assert has understood the product without being told. That is the argument of this design, and the section The withheld surface is where it is specified.
| File | What it holds |
|---|---|
app/web/static/verbatim.css | Every token and every colour in the
application: one :root block, then override blocks for dark, for each high-contrast
scheme, for print and for reduced transparency. Plus the shared components and the withheld-surface
block, which sits after every rule that adds an effect — but no longer last in the file. See
The withheld surface. |
app/web/static/clerk.css | The assistant dock. No colour of its own. |
app/web/static/tour.css | The first-login tour. No colour of its own. |
app/web/static/workflow.css | The approval-route editor. No colour of its own. |
deploy/site/site.css | The marketing site. Its own token names, the same hexes, mirrored by hand. |
tests/test_chat_surface.py::test_the_dock_borrows_the_apps_palette_rather_than_inventing_one
and tests/test_tour.py::test_the_tour_borrows_the_apps_palette_rather_than_inventing_one
fail on any hex literal or any rgba( followed by a digit, outside comments. So every
alpha, blur and shadow is declared once in verbatim.css and reached with var().
workflow.css obeys the same rule — grep it and there is no hex and no numeric
rgba() in it — but no test enforces that for workflow.css.
It holds by habit.site.css does not import verbatim.css and must not: the site
may carry a gradient on its chrome that the application may not (ADR-94). So each mirrored token names
the application token it copies, in a trailing comment:
--paper: #eef1f9; /* verbatim.css --bg */.
tests/test_design_guards.py::test_the_site_palette_is_what_it_says_it_mirrors reads those
comments, resolves the named token in the right scheme, and fails when the two hexes disagree.
It reads 21 claims and fails below
20, so the slack is one claim. Delete one mirror
comment and the guard stays green checking one token fewer; delete a second and it goes red. Both
numbers are marked in this page and re-derived from the tree by
::test_the_mirror_count_this_document_prints_is_the_count_the_guard_reads, because two
versions of this paragraph running shipped a count nobody had counted. A looser grep catches comments
the guard cannot read: one sits after an rgba() rather than a hex, another is prose with
no declaration in front of it.package.json, no bundler and no preprocessor; every stylesheet is served as it sits in the
repository. The one font is Manrope, a latin subset under OFL 1.1, committed at
app/web/static/fonts/manrope-latin.woff2 and again under deploy/site/fonts/.
tests/test_design_guards.py asserts both files exist and are woff2, and that no template
and no stylesheet on either surface names a font CDN. A reviewer with no network gets the whole
design.One hue for anything a person can act on, one for escalation and refusal, and no
third — --accent and --alarm. The greys are --accent desaturated,
so the page reads as one family rather than a neutral with a colour dropped on it. Meaning never rests
on colour alone: draft, final, material and withheld are carried by label, weight and shape first, so
they survive colour blindness and a monochrome screenshot.
Light is the base :root. It is overridden by
@media (prefers-color-scheme: dark), and by prefers-contrast: more paired with
each of light and dark. The high-contrast pair moves the inks and the rules and nothing else.
| Token | Light | Dark | High-contrast light | High-contrast dark |
|---|---|---|---|---|
--accent |
#2f4bd8 |
#a8b9ff |
unchanged | |
--alarm |
#a02c1d |
#ef9d80 |
unchanged | |
--ink | #0f1729 | #e9edf7 |
#05090f | #ffffff |
--ink-2 | #414d68 | #adb7cd |
#2b3547 | #ccd4e6 |
--ink-3 | #65728f | #818da8 |
#49536b | #9fabc4 |
--bg | #eef1f9 | #0b1020 |
unchanged | |
--surface | #fbfcfe | #141b2e |
unchanged | |
--surface-sunk | #e2e7f2 | #070b16 |
unchanged | |
--paper | #ffffff | #151c30 |
unchanged | |
--glass-solid | #f7f9fd | #161d31 |
unchanged | |
--paper is the record: the diff, the claim cards, the source extract and every table of
record sit on it. --surface-sunk is the withheld ground, and it is deliberately not paper,
because a withheld claim is not a record of anything.
A frosted pane over one flat colour is a flat pane. Blur only reads as glass when there is something
varied behind it, and probing /proceedings in Chromium at dpr 2 returned the same value at
every point probed across the frame — both gutters, mid-column, and 1200px down. Probed,
not exhaustively sampled. The claim is that no probe found any variation, which is weaker than
saying there was none, and it is what was actually done; verbatim.css hedges its own comment
the same way and this page keeps the hedge. The filter was running correctly on a page that gave it no
work. So the
page floor takes structure from the subject rather than from a hero gradient: a sheet of ruled filing
paper on a desk. --ground is layered — the desk stepping down outside the
76rem shell, a writing rule every 32px, a docket column every 96px — and only its colours
flip between schemes; the geometry is written once. It is switched off entirely under
@media print, under prefers-contrast: more and under
prefers-reduced-transparency: reduce, and a test asserts each.
| G1 — attached | G2 — floating | G3 — transient | |
|---|---|---|---|
| Wears it | .masthead, and the review tab rail .tabs |
the assistant dock .clerk-dock and the bug sheet .clerk-bug |
the floating assistant launcher .clerk-launch--floating |
| Alpha | 0.62 | 0.86 | 0.92 |
| Filter, light | blur(20px) saturate(180%) |
blur(30px) saturate(170%) | blur(14px) saturate(160%) |
| Filter, dark | the same blurs, with less saturation and a little added brightness, because a blur of a dark page returns a dark page | ||
| No filter | --glass-solid, for all
three | ||
Solid first, unconditionally. Every pane declares
background: var(--glass-solid) outside its @supports block and the
translucent value only inside it. Written the other way round — declare the alpha and hope
— a browser without the filter renders the raw translucent value over whatever is behind it,
which is the grey-text-on-a-grey-rectangle failure this design may not have.
backdrop-filter are .masthead and
.tabs in verbatim.css, and .clerk-dock, .clerk-bug and
.clerk-launch--floating in clerk.css. Every one of those blurs sits inside
an @supports block, and every one has a
background: var(--glass-solid) above it — read out of the two files today, not
asserted anywhere. Nothing in tests/ parses an @supports block
— grep -rn "supports" tests/*.py finds only prose in docstrings and comments. So a
new pane written the other way round ships green./* Solid for everyone, first and unconditionally. */ .masthead { background: var(--glass-solid); box-shadow: var(--edge), var(--glass-lift); } /* Glass only where the filter exists. A browser that ignores this block never sees the translucent value at all. */ @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .masthead { background: var(--glass-1); -webkit-backdrop-filter: var(--blur-1); backdrop-filter: var(--blur-1); } }
--glass-solid is not decoration: it is what a reader without
backdrop-filter, and every reader who asked for reduced transparency, actually sees. It
must stay --glass-1 composited over --bg, and
tests/test_glass_contrast.py::test_the_flat_pane_token_matches_the_translucent_one_it_stands_in_for
holds it there to one value per channel. That literal has gone stale against its source before.
prefers-contrast: more takes a different route again: it drops the filter and paints the
panes on opaque --surface instead.
Each face stands for a different kind of truth. A reader must never mistake a quotation for the product's own words, so the registers never share a face.
| Token | What it is | Who speaks in it |
|---|---|---|
--face-ui | the system sans stack | Verbatim's own voice: interface text, labels, actions, and a claim's statement |
--face-doc | Iowan Old Style, Charter, Palatino, Georgia | the document speaking: quoted regulatory prose, and only that |
--face-data | the system mono stack | the coordinates that make a quote checkable: version, offsets, codes |
--face-display | Manrope, from the repository | headlines and the wordmark. Never body text |
--face-display from .wordmark .logo text
in the application and .brand .logo text on the site.
grep -rl 'class="logo" viewBox="0 0 132 32"' app/web/templates/
deploy/site/ lists the files that carry it: base.html and the marketing pages.
Templates that paint something else:
login.html keeps the form the lockup replaced: the bare text Verbatim at
--t-ui-lg, weight 650, over .wordmark__mark — a CSS-painted three-bar
glyph, 4.6rem by 8px. Both are still in verbatim.css. The comment on
.wordmark .logo says "the old text node and the three-rule span underneath it are gone".
They are not gone; login.html does not extend base.html and was missed.invite_accept.html is standalone and renders the brand as a
--t-micro uppercase --ink-3 micro-label, .invite__mark, declared
inline in its own <style> and matching neither the lockup nor the login form. It is
the first Verbatim screen an invited colleague sees.docs/.ai/gaps.html closes row P2-11 with "One mark", which was
true of the two files it compared and is not true of the tree.Display only is the point of the font decision. Interface text keeps the system stack, because the dense screens were measured against those metrics and because swapping body text is what makes a page lurch on load. ADR-12 said no web font, as part of no build step and no CDN; the build step and the CDN still hold and only the font moved.
| Interface scale | Display scale | ||
|---|---|---|---|
--t-micro | 12px — uppercase labels, codes, coordinates | --t-display | 48px — the hero line, marketing only |
--t-small | 13px — secondary interface text | --t-title | 32px — page and section titles |
--t-ui | 15px — interface base | --t-lead | 20px — the sentence under a title |
--t-ui-lg | 17px — section headings | ||
--t-doc | 18px — quoted source text | ||
--t-claim | 19px — a claim's statement | ||
--t-count | 22px — a count read across a grid of cards | ||
--t-h1 | 24px — page title. The page does not shout. |
Twelve pixels is the floor, not a preference. --t-micro is the
most-used size in the application, it is nearly always uppercase and tracked, and tracked uppercase at
eleven pixels is where a reader stops reading and starts guessing. The analyst this is built for is
often past forty and often on a laptop in somebody else's meeting room.
Tracking and leading, and the rules behind them. Tracking slackens as the
type grows: --track-display −0.02em at 48px, --track-title
−0.014em at 32px, --track-h1 −0.009em at 24px. One value across them
would either loosen the hero or close up the page title. Uppercase labels take
--track-label 0.09em, and --track-label-tight 0.04em where the same label
sits in a narrow grid track. Leading runs the other way: --lh-micro is 1.55, more
than --lh-ui's 1.5, because letter-spacing pushes glyphs apart across the line and tight
leading then crowds the lines into each other until the label reads as a grey block.
--lh-doc is 1.72 and --measure is 66ch, because document prose gets read
closely rather than scanned.
A weight floor on glass, and a size floor with it. A blurred backdrop lowers
apparent contrast even where the measured figure holds, because the eye reads edges and a blur softens
them. Nothing on a pane goes below weight 500, and no text on glass goes below
--t-small — which is the rule that rules out the thing that would actually
break it, body prose on a pane. Do not reach for -webkit-font-smoothing: antialiased to
compensate: on a Mac it thins the strokes, which is the opposite of what is wanted.
Chrome is soft, evidence is square. The radii split in two, and the split is the design rather than a preference: a filing with rounded corners is a card about a filing.
| Record | Chrome |
|---|---|
--r 3px, --r-sm 2px. The diff, the claims, the quoted source, the
citation viewer. |
--r-card 14px, --r-control 10px, --r-pill 999px. Named for
what a thing is, not for what it is made of, so there is one scale rather than a token per
component. |
--r-glass is declared and nothing reads it. It was
10px, for the one surface that was genuinely a window; the dock now takes --r-card,
because both were chrome radii and they were never two ideas. The declaration is still in
verbatim.css and has no consumer anywhere in the application or on the site. Deleting it is
a one-line change nobody has made.The shell and the grid. --shell is 76rem, the width everything
lines up inside. Space is a 4px grid, --s1 through --s8. Document prose is
bounded by --measure, 66ch, wherever it appears.
The masthead sticks from 48rem up. Below that it does not, and that is deliberate: the nav wraps to two rows at 640px and three below 480px, so a sticky bar would take a quarter of a phone screen permanently. The tab rail sticks at every width, including phones, because it is 46px and it is the only thing telling a reader where they are on a page thousands of pixels long.
--stuck is the masthead's own height and it is not one number. Nothing
here runs on scroll, so the bar does not collapse; what changes with width is how many rows the nav
wraps to. Measured in Chromium stepping 4px from 760 to 1460, across the screens and every
demonstration account, taking the worst case — the administrator gets an extra nav item, so the
nav wraps at a different width for each account and a table measured on one is short for another:
768 to 855 233px nav on three rows --stuck: 14.5625rem (@media min-width: 48rem) 856 to 1171 164px nav on two rows --stuck: 10.25rem (@media min-width: 53.5rem) 1172 and up 110px nav on one row --stuck: 7rem (@media min-width: 73.25rem) --rail-h: 2.875rem the tab rail, measured at 46px --anchor: calc(var(--stuck) + var(--rail-h) + var(--s4)) --focus-anchor: var(--anchor)
--anchor is what every scroll target uses, and it clears the rail as well as the
masthead, because the rail sticks underneath it. --focus-anchor is the same clearance for
focus rather than for anchors — WCAG 2.2 added 2.4.11, Focus Not Obscured, and this layout was
failing it: every rule that carried --anchor was on something a fragment link points at,
none on the controls a person tabs through. It is a separate token because a scroll container must lower it for
its own descendants; ten rem of clearance inside a panel twenty rem tall would solve 2.4.11 on the page
and break it in the panel.
Tables scroll themselves. Below 62rem a table becomes its own scrolling
box — display: block, width: max-content, min-width: 100%
— so a table wider than the viewport does not push the whole page sideways. Fixed in the
stylesheet rather than by wrapping every table in every template, so a table added tomorrow is covered
without anybody remembering. The 62rem bound is a known hole and the stylesheet says so:
a table is too wide when it is wider than the space it has, which is a fact about the table and not
about the screen. The registers on /admin/sources and /admin/invites push a
1280px laptop sideways — measured in a browser, scrollWidth 1368 and 1377 against a
clientWidth of 1280 — while sitting perfectly inside a 390px handset, where the rule
fires. Until that is settled, a table known to be wide wears .table-scroll by hand.
Bands on page load, 420ms end to end, and it never repeats. Nothing else in the product is choreographed.
| Band | What | Delay | Duration | From |
|---|---|---|---|---|
| 1 | .masthead | 0ms | 260ms | opacity 0, translateY(-6px) |
| 2 | .page-head — title, note, rule | 60ms | 260ms | opacity 0, translateY(8px) |
| 3 | the frame around the record — h2, hr,
.tabs | 120ms | 300ms | opacity 0 only |
Every band takes --ease-settle. Claims, quotes, source extracts, tables and the
diff are in band nothing. They paint at full opacity in the first frame. The frame assembles
around a document that was already there, which is the sequence saying what the product says: the
filing is not something this software produced and it should not appear to arrive.
Band 3 selects the frame and not the containers, and that is load-bearing rather than tidy. Selecting a parent would composite its opacity onto every claim inside it, including a withheld one, and the signature would be gone with no line in the diff mentioning it.
| What | How |
|---|---|
| The citation chip fills | 120ms ease, colour only. The central interaction, so the most restrained. |
| The source panel reveals | opacity 0→1,
translateX(6px)→0, 200ms --ease-sheet. No scale, no overshoot: an
overshoot on a panel showing the text of an order is a small lie about how serious the thing is. The
marked span inside it gets no motion at all. |
| The assistant dock arrives | translateX(100%)→0 plus fade, 340ms
--ease-sheet. No scrim: the dock sits beside the page, and a scrim would hide the screen
it exists to answer questions about. |
| Suggestion pills | 240ms --ease-offer, which overshoots about four per cent,
stagger 40ms capped at four. The one spring in the product, because a suggestion is
the only thing on screen that is an offer rather than a record. |
| Card hover | translateY(-1px) and a shadow, 160ms. One pixel, not four. |
Arrivals animate. Departures do not. The dock and the source panel are
toggled with the hidden attribute, which the stylesheet forces to
display: none !important. A transition cannot run out of display: none, but
an animation restarts every time an element becomes displayed — so both reveals are animations
and neither needs a line of JavaScript. Closing is instant: a person closing a panel has already
decided.
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important;
}
}Shortening every duration to a hundredth of a millisecond leaves every animation and transition
running: the events still fire, the compositor still works, and an element mid-animation at a repaint
can still flash. With animation: none the fill mode goes too, so every band renders at its
natural state, which is exactly the intended end state.
transition: none !important is blunt. It removes colour transitions on hover as well as
movement, which is more than the preference strictly asks for. It is the reading the rule requires
— remove, do not shorten — but a person who set the preference for vestibular reasons has
also lost a 120ms colour fade that would not have troubled them.The refusal takes more than one form and they are one thing, so the block names each:
.claim--withheld on a change page and on a shared claim, .queue__row in the
escalation queue, and .withheld — the hatched slot — wherever it appears,
including inside an assistant reply and inside a blocked plan step. .withheld__label and
.withheld__reason are named separately because admin templates use the reason with no
.withheld parent, and a refusal has to look the same on an admin screen as on a change
page. The block sits after every rule in verbatim.css that adds an effect, so at equal
specificity it wins against all of them on order.
verbatim.css reads "It is placed LAST so that it wins against anything added above it later".
The login page's .demo-signin, .demo-signin__one and
.demo-signin__one .btn rules were added below it and now end the file. Nothing asserts the
position — nothing in tests/ reads where the block sits — so the cascade
guarantee named for this product's central surface eroded and no test noticed. A rule written at the
foot of the file today, at the same specificity, would beat it. What still holds is the
!important on animation and the class-level specificity, which a bare
* { transition: … } could not have beaten in any order.| Property | Every other surface | The withheld surface |
|---|---|---|
background | --paper for the record,
--glass-1/2/3 for the chrome | --surface-sunk. Not paper, because it
is not a record of anything. |
backdrop-filter | the blur ladder on chrome | none,
stated rather than left to inherit, so a glass rule written later with a wider selector cannot reach
in. |
box-shadow, text-shadow, filter | as needed | none. It casts nothing and it is lit by nothing. |
transform, will-change | a lift, a slide | none and auto. Not promoted to its own layer, because it has nothing to
composite. |
transition | 120–160ms on colour, border, shadow | none, on every property, including the Approve and Reject buttons inside a queue row.
Their hover still appears — instantly. |
animation | the settle bands, the dock, the pills | none !important. |
opacity | as needed | 1. Never faded, never dimmed. A
greyed-out assertion is still an assertion; the reader's eye completes it. |
:hover, :active, :focus-within | border, shadow, lift, fill | no rule exists. Not a rule that changes nothing — no rule at all, because an empty rule is an invitation and the next person will fill it. |
cursor | pointer where something happens |
default. The links and buttons inside a queue row keep their own pointer, because
those do something. |
:focus-visible | a 2px outline plus a
--focus-halo box-shadow | the outline survives in full. Only the halo is lost, because the halo is a box-shadow. |
verbatim.css defines a refuse keyframe — down 2px and up to full, 200ms
on --ease-refuse, no overshoot — and applies it to .claim--withheld
with a long comment arguing it is the one piece of the record allowed to move. The block above then
sets animation: none !important on the same selector. An important declaration beats a
normal one whatever the order, so the animation never fires. Checked in Chromium against
verbatim.css: getComputedStyle on .claim--withheld reports
animation-name: none. Two rules in one file disagree about the product's central
surface and nothing tells you which won. One of them has to go, and which one is a design
decision rather than a tidy-up: the stillness is the argument, and the motion was added to mark the
moment the argument lands.The differences that carry the refusal, and none of them is colour. A broken left rule where a verified claim has a solid one; inset from the column so it does not sit on the assertion axis; sunk instead of raised; the statement position occupied by a 135° hatched slot naming the reason; no citation chip; and a quoted-against-source pair a verified claim never carries. It survives a monochrome screenshot and needs no legend.
On paper, all but one of them are read rather than measured. The print block
sets print-color-adjust: exact on .claim--withheld, .queue__row
and .withheld, so a printer is not free to drop the hatch or the rule, and every one of
those differences is structural rather than colour. Nothing in the suite renders a printed page
— the only print assertions are token-level, that --ground is none under
@media print. The one with a test behind it is the missing statement: it is not
in the markup at all, and
tests/test_change_view.py::test_a_withheld_claims_statement_never_appears_in_the_response_body
holds the response body to that. Print renders the same markup, so that one carries over. The rest
are styled and have been read, not measured.
WithheldClaim has no statement field at all and uses
slots=True, so there is no attribute for a template to render and nothing can be attached
to the object later. tests/test_claims.py asserts the field is absent, that assigning it
raises, and that the text does not appear in the object's repr. No CSS change and no stray
{{ claim.statement }} can leak an assertion whose citation failed.The rule that keeps it the signature, and nothing enforces it. The withheld surface must be the stillest thing on any screen it appears on. If a second element ever competes, the second element gets motion, or it is cut.
Every ratio verbatim.css states in prose is pinned to two decimals in
tests/test_glass_contrast.py, so moving a colour without revisiting the comment that
describes it fails there rather than in front of a reviewer. scripts/contrast_report.py
regenerates the literal from the stylesheet. Every ratio cell below carries the scheme, the ink
and the ground it came from, and tests/test_design_guards.py recomputes it out of
verbatim.css to 0.01. A second guard fails if the table stops covering the whole
PINNED list, so a row cannot go missing quietly either.
| Scheme | Ink | Ground | Ratio | Note |
|---|---|---|---|---|
| light | --ink | --bg | 15.82:1 | |
| light | --ink-2 | --bg | 7.48:1 | |
| light | --ink-3 | --bg | 4.27:1 | conceded under AA |
| light | --ink-2 | --surface-sunk | 6.82:1 | |
| light | --ink-3 | --surface-sunk | 3.89:1 | conceded under AA |
| light | --ink | --glass-solid | 16.96:1 | ceiling |
| light | --ink-2 | --glass-solid | 8.01:1 | ceiling |
| light | --ink-3 | --glass-solid | 4.57:1 | ceiling |
| dark | --ink-3 | --bg | 5.69:1 | |
| dark | --ink-3 | --surface | 5.15:1 | |
| dark | --ink-3 | --surface-sunk | 5.90:1 | |
| hc-light | --ink-3 | --bg | 6.80:1 | |
| hc-light | --ink-3 | --surface-sunk | 6.20:1 | |
| hc-dark | --ink-3 | --bg | 8.20:1 | |
| hc-dark | --ink-3 | --surface | 7.42:1 |
--glass-solid is a ceiling, not a
measurement. The masthead and the tab rail are translucent panes over a blurred backdrop, and
their rendered colour is whatever is scrolling underneath at the time. No arithmetic over tokens
reaches that; it is a range, and its worst pixel sits below its best. Nobody has put a
browser in front of the indigo pane, so the rendered figure is unknown — not a best
pixel, not a worst one, not a range. The stylesheet records that as unknown rather than replacing it
with a plausible number, which is the error it has already had to correct four times on one comment.
Assume --ink-3 on a pane fails AA until somebody measures it.The two concessions, and why they are kept. Light --ink-3 is
under 4.5:1 on --bg and on --surface-sunk. It is the second level of a
deliberate two-level ink hierarchy, and the worst case for it is .nav__link--off: a nav
item that leads nowhere is a <span aria-disabled>, not a link, and being drawn in
--ink-3 while its neighbours are --ink-2 is the only thing on screen saying
so. Raising it would make an unreachable screen look exactly like a reachable one, and a nav item that
leads nowhere while looking live is a small lie this product's argument says it does not tell.
Tests hold the shape of that trade rather than leaving it to a comment. All but one are here; the
weak one is below.
--ink-3 may never equal --ink-2, in every scheme,
with at least 1.3:1 between them — it shipped equal once, in the prefers-contrast
block, which flattened a two-level hierarchy across the stylesheets for the one reader who asked to see
more. And asking
for more contrast must actually get more: high-contrast --ink-3 beats base
--ink-3 on every ground, and in high-contrast light it clears 4.5:1 on every opaque
ground. That is what the query is for; a reader who asks for more contrast and is handed something
still under the floor has been gestured at, not answered.
--rule against --rule-strong is
tests/test_glass_contrast.py::test_the_two_rule_levels_are_never_the_same_colour, a
separate test from the ink one, and its only assertion is that the two hexes differ.
There is no separation floor on it. Two border levels a hundredth of a ratio apart would pass. They
stand at
1.60:1
in light,
1.48:1
in dark,
1.93:1
in high-contrast light and
1.72:1
in high-contrast dark — comfortable today, held there by nobody. Marked and re-derived by the
same guard as the table above, so they cannot rot unnoticed even though nothing stops them
moving.The focus ring is an outline, in every scheme, on every surface, glass included, and it
is declared once. The halo beside it is a box-shadow, which makes it an enhancement: the
withheld surface drops it and keeps the ring.
outline: none outside
:focus:not(:focus-visible), which is the browser's own judgement that a pointer put the
focus there. tests/test_a11y_guards.py walks every stylesheet under
app/web/static/ and fails on anything else.prefers-reduced-motion itself rather than leaning on the global sweep.
Both are asserted per sheet. The tour is the first thing a new reader meets and it had no ring.outline-color. Any new filled control joins that list..shell, out on the darkened desk, needs an opaque fill or
it belongs inside the shell. The skip link is the one element that does, and a test holds its
background opaque.tests/test_glass_contrast.py carries the token arithmetic; the rest needs
eyes.verbatim.css contradict
each other on .claim--withheld and the !important one wins. Detailed above.
It is not the only defect here that changes what a reader sees — the wordmark below is
another.backdrop-filter cost, a real
address bar that resizes the viewport, and a real thumb. verbatim.css says the same at the
foot of its table rules, and tests/test_responsive.py says plainly in its docstring that
it cannot lay out a page.--glass-solid at #161d31 over a #0b1020 page is a real step, but
a 20px blur of a dark, mostly empty page returns something close to a flat tint. If it reads as a plain
panel on a real dark screen, the honest move is to drop backdrop-filter in dark, keep the
tint, the edge and the shadow, and save the pass. Nobody has looked at it on an actual display in
dark.login.html, and a micro-label in
invite_accept.html, which is the first Verbatim screen an invited colleague meets.
Detailed under Type.verbatim.css and its comment says it is.
Nothing asserts the position.--r-glass is declared and read by nothing. One line, no consumer.workflow.css obeys the no-colour rule and no test enforces it, unlike
clerk.css and tour.css.docs/user-research.html still
records zero interviews. That is the weakest claim on this page and it is not a small one: every rule
above is a designer's judgement that nobody in the intended job has been asked about.