The Visual System

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 reasoning behind each choice lives in docs/.ai/decisions.html — the web font in ADR-92, the palette in ADR-93, where a gradient may go in ADR-94. Deployment moved to the TDD, which owns the container shape and the nginx path list.

The one rule

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.

Where the values live

FileWhat it holds
app/web/static/verbatim.cssEvery 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.cssThe assistant dock. No colour of its own.
app/web/static/tour.cssThe first-login tour. No colour of its own.
app/web/static/workflow.cssThe approval-route editor. No colour of its own.
deploy/site/site.cssThe marketing site. Its own token names, the same hexes, mirrored by hand.
The component sheets write no colour, and a test holds two of them to it. 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.
The site mirrors the application by hand, and the mirror is checked. 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.
No build step, no CDN, one web font. There is no 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.

Colour

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.

The schemes

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.

TokenLightDarkHigh-contrast lightHigh-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.

The ground under the shell

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.

Every browser-measured pixel figure in the ground and pane comments belongs to the teal palette this product carried until 2026-08-07. The desk and sheet are alpha layers, so the indigo page moves all of them and nothing has re-read them. They are left marked as expired in the stylesheet rather than recomputed, because arithmetic is not what took them. The argument holds — a crisp edge on open ground, softened where you see it through the pane — and the digits are the old page's.

The glass ladder

The longer a surface lives and the more words it carries, the more opaque it is. The masthead holds two words per item and you look past it a thousand times, so it can be the most transparent thing on screen. A tip holds a paragraph you read once, so it is nearly solid. The reflex — small and fleeting means see-through — produces exactly the wrong legibility.
G1 — attachedG2 — floatingG3 — 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
Alpha0.620.860.92
Filter, lightblur(20px) saturate(180%) blur(30px) saturate(170%)blur(14px) saturate(160%)
Filter, darkthe 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.

The rule holds, and it is held by reading rather than by a test. The surfaces that carry a 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 blockgrep -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.

Type

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.

TokenWhat it isWho speaks in it
--face-uithe system sans stackVerbatim's own voice: interface text, labels, actions, and a claim's statement
--face-docIowan Old Style, Charter, Palatino, Georgiathe document speaking: quoted regulatory prose, and only that
--face-datathe system mono stackthe coordinates that make a quote checkable: version, offsets, codes
--face-displayManrope, from the repositoryheadlines and the wordmark. Never body text
The brand does not ship as one mark, and the stylesheet says it does. Nearly everywhere it is one inline SVG lockup — the indigo tile with three white bars and the name beside it, which takes --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: Nothing tests any of this. 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 scaleDisplay scale
--t-micro12px — uppercase labels, codes, coordinates --t-display48px — the hero line, marketing only
--t-small13px — secondary interface text --t-title32px — page and section titles
--t-ui15px — interface base --t-lead20px — the sentence under a title
--t-ui-lg17px — section headings
--t-doc18px — quoted source text
--t-claim19px — a claim's statement
--t-count22px — a count read across a grid of cards
--t-h124px — 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.

Shape and layout

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.

RecordChrome
--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.

Sticky chrome, and the heights it is measured against

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.

Motion

The settle: one orchestrated moment, and the record is not in it

Bands on page load, 420ms end to end, and it never repeats. Nothing else in the product is choreographed.

BandWhatDelayDurationFrom
1.masthead0ms260ms opacity 0, translateY(-6px)
2.page-head — title, note, rule60ms260ms opacity 0, translateY(8px)
3the frame around the record — h2, hr, .tabs120ms300msopacity 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.

The rest of it

WhatHow
The citation chip fills120ms ease, colour only. The central interaction, so the most restrained.
The source panel revealsopacity 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 arrivestranslateX(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 pills240ms --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 hovertranslateY(-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.

What has no motion

Reduced motion removes motion. It does not shorten it.

@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.

The cost, stated rather than discovered. 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 withheld surface

THE ONLY SURFACE IN THIS PRODUCT WITH NO EFFECTS AT ALL.
No blur. No shadow. No transform. No transition. No animation. No hover. No cursor change.

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.

It is no longer last in the file, and its own comment still says it is. 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.
PropertyEvery other surfaceThe 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-filterthe blur ladder on chromenone, stated rather than left to inherit, so a glass rule written later with a wider selector cannot reach in.
box-shadow, text-shadow, filteras needed none. It casts nothing and it is lit by nothing.
transform, will-changea lift, a slide none and auto. Not promoted to its own layer, because it has nothing to composite.
transition120–160ms on colour, border, shadow none, on every property, including the Approve and Reject buttons inside a queue row. Their hover still appears — instantly.
animationthe settle bands, the dock, the pills none !important.
opacityas needed1. Never faded, never dimmed. A greyed-out assertion is still an assertion; the reader's eye completes it.
:hover, :active, :focus-withinborder, shadow, lift, fillno 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.
cursorpointer where something happens default. The links and buttons inside a queue row keep their own pointer, because those do something.
:focus-visiblea 2px outline plus a --focus-halo box-shadowthe outline survives in full. Only the halo is lost, because the halo is a box-shadow.
The refusal animation is declared and it does not run. 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.

The stylesheet is not what withholds the claim, and that is why this is safe. 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.

The accessibility floor

The ratios, pinned

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.

SchemeInkGroundRatioNote
light--ink--bg15.82:1
light--ink-2--bg7.48:1
light--ink-3--bg4.27:1 conceded under AA
light--ink-2--surface-sunk6.82:1
light--ink-3--surface-sunk3.89:1 conceded under AA
light--ink--glass-solid16.96:1ceiling
light--ink-2--glass-solid8.01:1ceiling
light--ink-3--glass-solid4.57:1ceiling
dark--ink-3--bg5.69:1
dark--ink-3--surface5.15:1
dark--ink-3--surface-sunk5.90:1
hc-light--ink-3--bg6.80:1
hc-light--ink-3--surface-sunk6.20:1
hc-dark--ink-3--bg8.20:1
hc-dark--ink-3--surface7.42:1
A figure against --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.

The border tokens get their own test and it is the weak one. --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.

Focus

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.

What those guards cannot do, in their own words. They read source, not a browser. They cannot tell you a ring is visible against the surface behind it, cannot measure a rendered contrast ratio, and cannot tell you whether the words in an accessible name are the right words. tests/test_glass_contrast.py carries the token arithmetic; the rest needs eyes.

What is not known, and what ships broken

  1. The refusal animation is dead. Two rules in 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.
  2. Nothing here has been opened on a handset. Every 390px figure comes from a headless Chromium at a fixed viewport. A phone has a real 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.
  3. The rendered contrast on a translucent pane over the indigo page is unknown. The pinned figures are token arithmetic and the pane figures that existed were measured against the palette this product no longer uses.
  4. Nobody has tabbed the whole product with the current palette. The source guards above stop a ring being deleted; nothing asserts a ring is visible on G1, G2 or G3, in either scheme.
  5. The 62rem bound on the table scroll rule is a hole, not a decision, and is named as one in the stylesheet rather than left looking deliberate.
  6. Whether dark glass earns its compositor pass is unknown. --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.
  7. The brand ships in more than one form, and a reader sees it. The lockup nearly everywhere, the old text-and-bars form in login.html, and a micro-label in invite_accept.html, which is the first Verbatim screen an invited colleague meets. Detailed under Type.
  8. The withheld block is not last in verbatim.css and its comment says it is. Nothing asserts the position.
  9. --r-glass is declared and read by nothing. One line, no consumer.
  10. workflow.css obeys the no-colour rule and no test enforces it, unlike clerk.css and tour.css.
  11. Most of this document is still unguarded. Tests read the mirror numbers and every ratio it prints, and re-derive both from the tree. Nothing else here is checked: the alphas, the blurs, the type scale, the sticky heights and the browser figures were read back by hand, and a stylesheet edit tomorrow can make any of them false with the suite green. This round dropped every count whose sentence survived without it, so less is left to rot. Not nothing.
  12. No user has seen this palette, or the one before it. The argument for indigo is reasoned from the category rather than from evidence, and 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.