OVERSCANUI KIT
no button at all a worn bezel with weight channels do not converge zero depth instrumented, full of smoke a field of real characters a camera looking out additive, so no shadow hairlines, no new shader no raster, so no scanlines

chrome.css

Overscan chrome, P0 scope: what one panel needs. Static furniture only. No JavaScript, no canvas, everything reachable from the cascade so the theme, contrast and motion switches reach all of it.

src/chrome.css · 27 blocks · blocks that belong to a custom element are on that element's page

.ov-alarm

pressure loss
selectorkind
.ov-alarmblock

Used on index.html, standalone.html, index.html, themes.html.

.ov-aside

🔴 AN INSTRUMENT SHOWS ITS VISUAL CONTENT AND NOTHING ELSE, BY DEFAULT. What that means is the instrument face, the reading, the unit that reading is in, and anything the instrument is refusing or qualifying. What it does NOT mean is the supporting prose: the element's own name, the declared-rules footnote, the hint line, the per-row restatement of what a mark already shows. A wall writes the name and the rules once above twenty tiles, and twenty instruments repeating them is noise rather than rigour.

data-ov-chrome="full" opts back in, on the element or on any container above it, for a single instrument on a page of its own where there is no wall to carry the name.

<ov-balance label="TANK 912"> name hidden <ov-balance label="TANK 912" data-ov-chrome="full"> name shown <div data-ov-chrome="full"> … twenty elements … </div>

data-ov-chrome="bare" is the default said out loud, and it is worth having a word for because it can be nested INSIDE a full container to put one instrument back to dense.

🔴 A REFUSAL IS NEVER CHROME. None of this may hide a refusal, a qualifier, a READING or the unit that reading is in: it is a density control, not a way to make an instrument look calmer than it is. Anything an element marks .ov-aside is prose the reading does not depend on, and nothing else may carry the class.

⚠️ THE LINE IS MEASURED VERSUS DECLARED, NOT NUMBER VERSUS WORD, and it is worth stating because the declared rules are full of numbers. ±1.5, RED AT 3, MARGIN 0.50 nm and EXPIRES 30m 00s are all hidden, and every one of them is an AUTHOR-SET ATTRIBUTE - what this instrument was told to do. What is never hidden is what the instrument MEASURED, what it is refusing to measure, and what it has to say about how a measurement was arrived at.

⚠️ AND IT CHANGES NOTHING THAT IS READ ALOUD. Every element in the kit opens its accessible name with its label, and none of this touches that, so a screen reader is given the identical sentence either way. A hidden name is still a spoken name. That is the condition under which a name - the one piece of prose that is also an identity - is allowed to leave the screen at all, and tools/bare-test holds all seven elements to it.

⚠️ THE SELECTORS LOOK ODD ON PURPOSE, both halves of them.

The class is DOUBLED because these rules have to win against an element's own stylesheet without !important: .ov-aside and .ov-mosaic__probe are both one class, so which one won would come down to the order the sheets happened to load. .ov-aside.ov-aside is (0,2,0) and settles it.

And full is written as an EXEMPTION from the hiding rather than as a rule that sets display back, because there is no one value to set it back TO. .ov-position__cap is display: none in position.css for its own reasons, and a rule here saying display: block would overrule that and force a footnote back on screen that the element had decided not to draw. Under full this file contributes no display at all, and each element's own rules govern, which is the only correct answer.

selectorkind
.ov-asideblock
[data-ov-chrome="full"]state

Written into markup by src/ov-authority.js, src/ov-balance.js, src/ov-clearance.js, src/ov-datablock.js, src/ov-geomap.js, src/ov-mosaic.js, src/ov-position.js, src/ov-quorum.js, src/ov-score.js, src/ov-station.js, src/ov-switch.js, src/ov-tactical.js, src/ov-vitals.js, src/ov-watchdog.js, so an element sets it for you.

.ov-aux

aux bus
selectorkind
.ov-auxblock
.ov-aux__barpart

Used on index.html, standalone.html, index.html, themes.html.

.ov-badge

nominalauxfault
selectorkind
.ov-badgeblock
.ov-badge--auxmodifier
.ov-badge--faultmodifier

Used on chrome.html, index.html, screen.html, index.html.

.ov-bar

selectorkind
.ov-barblock
.ov-bar__cellpart
.ov-bar--altmodifier
.ov-bar--onmodifier
.ov-bar--overmodifier
--ov-bar-gapcustom property
--ov-bar-heightcustom property

Used on standalone.html, index.html, themes.html.

.ov-btn

Form comes from tokens, so the themes are different OBJECTS rather than one object recoloured. A terminal has no buttons: it has bracketed text you can select. 2001 has a flat colour block with no border at all. Industrial has a heavy bezel and a cut corner. Cyber leans.

⭐ FOUR MORE EDGE TREATMENTS, ALL DRAWN UNCONDITIONALLY AND ALL INERT AT ZERO, which is the move --ov-shear already makes at 0deg. A theme carries at most one of them and this file never learns which:

--ov-ctl-tick crop marks at the corners instead of a continuous edge --ov-ctl-over pushes those marks off their edges so they CROSS --ov-ctl-edge one bar on the leading side only --ov-ctl-base an underline and nothing else --ov-ctl-chamfer all four corners taken off

See FURNITURE in tools/palette.py for what each one is FOR. The reason this axis exists at all is that the four newest themes were strong backgrounds with the same rule-box button underneath, which fails the kit's own test that a theme is a mechanism and not a hue.

selectorkind
.ov-btnblock

Also styled in control.css. Written into markup by src/ov-allocator.js, src/ov-hold.js, src/ov-player.js, src/ov-sound-switch.js, src/ov-timeline.js, src/ov-transport.js, so an element sets it for you. Used on allocator.html, annunciator.html, authority.html, aux.html, baseline.html, chrome.html, control.html, corner.html and 19 more.

.ov-code

No still yet.

selectorkind
.ov-codeblock
.ov-code__prepart

Also styled in code.css, motion.css. Written into markup by src/ov-reveal.js, so an element sets it for you. Used on about.html, allocator.html, annunciator.html, ascii.html, authority.html, aux.html, avatar.html, balance.html and 69 more.

.ov-dot

selectorkind
.ov-dotblock

Also styled in motion.css. Used on chrome.html, data.html, index.html, screen.html, standalone.html, index.html, themes.html.

.ov-head

No still yet.

A name on the left, and on the right the RULES THE INSTRUMENT IS JUDGING BY: the window it averages over, the tolerance it allows, the threshold it triggers at. Those belong together because they are one sentence - "this is what I am, and this is what I was told to do" - and because a reading whose rule is off screen is a reading you cannot check.

🔴 IT LIVES HERE BECAUSE SIX ELEMENTS HAD WRITTEN IT OUT SEPARATELY, byte for byte identical, which is the drift tools/specimens.py exists to end: one source per use, not six copies of one. Anything in the kit can now open with <div class="ov-head"><span class="ov-head__name">…</span> <span class="ov-head__note">…</span></div>.

⚠️ AND MOST INSTRUMENTS SHOULD NOT USE IT. A kit where every element opens with the same bar reads as a template rather than as a set of instruments, and the head is only right where the name and the declared rule genuinely are the first thing to say. Where an element has a loud primary readout of its own - a verdict, a mode badge, an age - the name belongs IN that block and the rules belong under it, which is what ov-mosaic, ov-balance, ov-position and ov-clearance do.

selectorkind
.ov-headblock
.ov-head__namepart
.ov-head__notepart
.ov-head--tightmodifier
[data-ov-chrome="full"]state

Written into markup by src/ov-authority.js, src/ov-datablock.js, src/ov-quorum.js, src/ov-score.js, src/ov-station.js, src/ov-switch.js, src/ov-vitals.js, src/ov-watchdog.js, so an element sets it for you. Used on standalone.html.

.ov-input

selectorkind
.ov-inputblock

Used on chrome.html, index.html, input.html, index.html.

.ov-instrument

flux / instrument
selectorkind
.ov-instrumentblock
.ov-instrument__labelpart

Used on standalone.html, index.html, themes.html.

.ov-panel

probe
stage0

🔴 A CUT IS NOT A HOLE. clip-path REMOVES; it never draws. Every cut corner in this kit was therefore an outline that simply STOPPED: the border ran along the four straight sides and nothing at all ran along the diagonal, so the corner read as broken rather than as cut - on panels, buttons, inputs, selects, modals and the viewport alike.

⚠️ IT WAS FILED AS AN iOS RENDERING BUG AND PARKED WAITING ON A DEVICE, which is why it survived being reported several times. It reproduces in every browser, and the tell was there from the beginning: this was never a rendering difference between engines, because NOTHING WAS EVER DRAWING THAT EDGE. demo/corner.html compares five ways to perform the same cut and not one of them strokes the diagonal, so the whole page was asking the wrong question.

The diagonal is drawn as a background layer, one per corner, sized by the cut it belongs to and inert at zero like every other treatment in this file.

🔴 DECLARED ON THE COMPONENTS, NOT ON :root. var() inside a custom property is substituted WHERE THE PROPERTY IS DECLARED, so a definition on :root would freeze --ov-furn at the root's value and the diagonal would never follow hover, pressed or refused. That is the same trap --ov-ctl-clip fell into one commit ago.

selectorkind
.ov-panelblock
.ov-panel__labelpart

Also styled in layout.css. Written into markup by src/ov-reveal.js, so an element sets it for you. Used on ascii.html, chrome.html, cli.html, index.html, instrument.html, motion.html, radar.html, reticle.html and 5 more.

.ov-pop

No still. A popover lives in the top layer and is nothing until it is opened.

selectorkind
.ov-popblock

Also styled in control.css. Used on control.html.

.ov-rail

No still yet.

selectorkind
.ov-railblock

Also styled in layout.css. Used on screen.html, index.html.

.ov-row

flux0.912
ventopen

Right-aligned in a column so decimal points land in the same place. A monospace face alone does not do this.

Two corrections here, both found by rendering it rather than by reading it:

1. letter-spacing is ZEROED. A readout is never tracked. Tracking is for labels; on digits it breaks column alignment and, worse, it inflates the rendered width without changing ch, because ch is the advance width of digit zero and knows nothing about the spacing added between characters. 2. min-width and nowrap, not a fixed width. At width:7ch the string "318.4 K" is exactly 7 characters and still wrapped in every theme with tracking on, putting the unit on its own line. A ch-sized box is a claim about width that stops being true the moment anything else touches the advance.

This is the ch trap in TOKENS.md, committed by the file that documents it.

selectorkind
.ov-rowblock
.ov-row__keypart
.ov-row__valuepart
.ov-row--faintmodifier
.ov-row--inkmodifier

Used on chrome.html, fault.html, index.html, motion.html, radar.html, shader.html, standalone.html, surface.html and 2 more.

.ov-rule

No still yet.

selectorkind
.ov-ruleblock
.ov-rule--strongmodifier

No demo page uses it, and no script writes it.

.ov-screen

No still yet.

selectorkind
.ov-screenblock
.ov-screen__bodypart

Also styled in layout.css. Used on screen.html, index.html.

.ov-select

selectorkind
.ov-selectblock

Also styled in form.css. Used on form.html, index.html.

.ov-state

---- THE STATUS BOX IS A WORD, NOT A HEADER ------------------------------

With the name and the explanation gone, what was left on top of every instrument was the BOX: a bordered panel, a bar, a badge, holding one word. It still read as a header, because it was built as one.

So by default the box gives up its frame - no padding, border, background or shear - and an ORDINARY reading (data-ov-tone="ok": agrees, fix, complete, fresh) does not draw it at all. The instrument face below already shows an ordinary reading, and a box announcing that nothing is wrong is the header this rule exists to remove.

🔴 A REFUSAL OR A QUALIFIER STILL DRAWS ITS WORD. note and bad keep the word, in its tone colour, at its size: DISPUTED, DEAD RECKONED, NOT QUALIFIED, NO MAJORITY, the composite's age. On five of these seven instruments that word is the ONLY place the refusal is drawn - nothing in the face changes when it refuses - so it is the one thing on top that may not go. What goes is the frame around it and the sentence after it.

.ov-state--reading IS A BOX THAT HOLDS THE READING ITSELF. ov-quorum's voted value and ov-score's total are printed nowhere else, so for those two an ordinary tone keeps the box too, frameless: hiding it would hide the number, which is the one thing a density control may never do.

The inverted badge (position, when derived) paints its word in the field colour on a filled ground. With the ground gone that word would be dark on dark and simply vanish, so the word takes the tone colour back.

⚠️ THE FRAME RULE CARRIES THREE CLASSES, and two was measured not to be enough. .ov-state--panel[data-ov-tone="bad"] and .ov-state--badge[data-ov-tone="note"] are each (0,2,0), the same as a doubled class, so which won came down to source order - and on a refusing quorum panel the 3px double border stayed while the gate's badge kept its filled ground. Three classes is (0,3,0) and outranks every tone rule.

selectorkind
.ov-stateblock
.ov-state__whypart
.ov-state__wordpart
.ov-state--badgemodifier
.ov-state--barmodifier
.ov-state--baremodifier
.ov-state--edgemodifier
.ov-state--panelmodifier
.ov-state--readingmodifier
.ov-state--tagmodifier
[data-ov-chrome="full"]state
[data-ov-tone="bad"]state
[data-ov-tone="note"]state
[data-ov-tone="ok"]state

Written into markup by src/ov-authority.js, src/ov-balance.js, src/ov-clearance.js, src/ov-mosaic.js, src/ov-position.js, src/ov-quorum.js, src/ov-score.js, src/ov-switch.js, src/ov-watchdog.js, so an element sets it for you.

.ov-status

pump apump bvalve 3coolantaux bussensor 7link 2

⭐ A STATUS WITH NO DECLARED STATE IS NOT OK. .ov-badge is a label and is drawn in the accent, which on most themes is the colour of "good"; a status light that looked like that by default would report every unwired channel as healthy. So the bare .ov-status is UNKNOWN: a "?" marker, a hatched ground and the words NO STATE. Only data-ov-state="ok" is ever drawn as ok. Silence cannot pass for green by forgetting an attribute.

Every state has its own marker SHAPE as well as colour (filled dot, triangle, square, hollow ring, dash), and the two states that are about the channel rather than the thing, unknown and nosignal, write their own words, so none of this rests on colour alone. data-ov-age adds STALE and the age.

selectorkind
.ov-statusblock
[data-ov-age]state
[data-ov-state="alarm"]state
[data-ov-state="caution"]state
[data-ov-state="nosignal"]state
[data-ov-state="off"]state
[data-ov-state="ok"]state
--ov-status-ccustom property

Used on chrome.html, index.html.

.ov-strip

pressure loss / sector 4 / acknowledge
selectorkind
.ov-stripblock

Used on chrome.html, data.html, index.html.

.ov-tab

selectorkind
.ov-tabblock

Used on allocator.html, annunciator.html, ascii.html, authority.html, aux.html, avatar.html, balance.html, baseline.html and 68 more.

.ov-tabs

selectorkind
.ov-tabsblock

Also styled in code.css. Written into markup by src/ov-tabs.js, so an element sets it for you. Used on allocator.html, annunciator.html, ascii.html, authority.html, aux.html, avatar.html, balance.html, baseline.html and 68 more.

.ov-tip

No still. A tooltip lives in the top layer and is nothing until it is shown.

selectorkind
.ov-tipblock

Also styled in aux.css. Used on aux.html.

.ov-titlebar

sensor
selectorkind
.ov-titlebarblock

Used on index.html.

.ov-toggle

selectorkind
.ov-toggleblock
.ov-toggle__knobpart
.ov-toggle__trackpart

Used on chrome.html, index.html.

.ov-viewport

No still yet.

selectorkind
.ov-viewportblock

Also styled in layout.css. Used on screen.html, index.html.