About¶
Why it exists¶
Abilian builds and maintains a range of business applications. They share a server stack and share nothing visually: each one accumulated its own Bootstrap fork, its own spacing habits, its own idea of what a "card" is. The cost is not aesthetic. It is that a fix in one is a fix in one, and a developer moving between them starts over.
The usual answer is to adopt an off-the-shelf kit. The usual result is that the kit's opinions leak into the product and its 300 independent values cannot be retuned as a set — so "make it denser for this client" becomes a fork.
The position¶
Tabler provides the taste; we provide the implementation.
Tabler is a mature, well-proportioned admin design language, and reproducing its judgement is cheaper than inventing one. But consuming it means inheriting Bootstrap, a build step, and a vocabulary nobody here controls.
So this is not a Tabler wrapper. It is an independent implementation, held to Tabler's measurements by a calibration harness that renders 78 elements side by side against the real thing and compares them property by property. It reports zero differences.
That separation is the whole point. Tabler decides how it looks; we decide how it is built. When the two goals diverge — and they do, on accessibility — we can take the divergence deliberately instead of forking.
Where the reference is not enough
Tabler's success green measures 2.48:1 as text on its own tint. The floor for body text is 4.5:1. Rather than silently ship the failure or silently diverge, that became a knob: --ads-contrast: 0 is the reference's own palette, 1 moves every intent to a readable ink without touching a single fill, border or tint. Both ends are asserted by tests.
Where it stands¶
Usable, in use by the demo application, and proven once against applications it did not grow around — seven of situ's own demos, ported with their Python untouched and only their markup rewritten. Four of the seven made the system grow. Not yet used by a production application, which is the next thing that would teach it something.
| Stylesheet | 16 files, 3,155 lines — no build step, no runtime dependency |
| Vocabulary | 27 knobs → 128 derived tokens → 264 classes |
| Demo application | 50 routes + 7 inherited from situ · 4 shell layouts · 6 languages · RTL |
| Visual parity | 0 properties differ across 78 elements measured against Tabler |
| Linter | 22 rules, 0 findings |
| Automated checks | 34 library · 25 unit · 40 in a real browser · 1 calibration sweep |
What it has been taught¶
The system is mostly a record of being found wanting, and the four biggest lessons are worth stating because they shape what gets built next.
A colour defined in both themes is not a colour readable in both. Fifty-four contrast
failures came from single-valued intent colours the first time anyone rendered a page in
dark mode. Every intent now has a fourth shade, -ink, for when it is used as text.
Accessibility claims need conditions, not intentions. Contrast in both themes, reflow at 320px, 200% text-only zoom, keyboard traversal, pointer target size and Windows high contrast are each swept across every route on every run. Every one of them was broken when first measured.
The look must not be able to exist without the meaning. State a person can perceive is
an attribute — aria-current, aria-pressed, aria-invalid — and the stylesheet keys off
that attribute, so there is nothing for an author to remember. This replaced ten kinds of
"current item" that were, to a screen reader, ordinary links.
Two things agreeing with each other is not evidence. abilian-ds tokens --check passed
for months against a document describing a design system that had been deleted: the
generator read the dead file, the document was its output, and the check compared the two.
Every gate here now compares against something that did not move.
What is next¶
- A production application. The ports prove the vocabulary survives someone else's
information architecture. They do not prove it survives a deadline, a client's brand, or
a developer who has not read any of this. The thing that blocked this — an adopter had
to hand-write the application frame — is fixed:
syncvendors the shell now. - A real screen reader. Everything tested so far is what a browser can be asked about the DOM, which catches absent semantics and not wrong ones. One known gap: advancing the wizard changes the step and announces nothing.
- Density. The knobs sit at Tabler's values so parity can be measured. Abilian's applications are dense tools and may well want a smaller base type and a sub-1 space scale — a decision to take deliberately, once there is a second real consumer to take it against.
- Publish the package, so "vendored and hashed" becomes a guarantee rather than a
local convention. Unblocked: the install path has been walked from an empty directory —
clean virtualenv, wheel,
sync, a page on the packaged shell,lintclean — though not yet turned into a test, which is what would make it a guarantee rather than a memory.
Deliberately not on the list: more ported demos. Seven found four gaps. Rebuilding two of them into applications that actually read as a mailbox and an issue tracker found five more, which says the next yield is in depth rather than breadth.
Design principles¶
These have not changed since the first spec, and they survived the rewrite that deleted almost everything else in it.
- Tokens are named for intent, not value.
--ads-surfaceis a decision — this is the surface a card sits on. A hex code carries no idea of whether that grey is a card, a hover state or a coincidence. - The rules are a check, not a document. If something is off-system and no rule caught it, that is a gap in the rules. No "but the guidelines said not to".
- Delete the escape hatch, do not discourage it. A person reads the contribution guide once; a model rediscovers the codebase every prompt and takes the path of least resistance. The only way to move the default is to make the wrong thing unavailable.
- Derive, do not enumerate. If two values must move together, one is computed from the
other. A system where
--shadow-mdand--shadow-lgare independent literals cannot answer "less shadow". - Prefer the platform.
<details>before a disclosure widget,hiddenbefore a state class,light-dark()before a second stylesheet,:has()before a script.
Licence and credits¶
Built by Abilian. Visual language after Tabler
by Paweł Kuna. Icons are Tabler Icons. Interactive islands use
situ. The engineering record is in
notes/.