Little LoopsTechnologies, LLC
Brand Kit · v4.16 · 2026-08-31

Small machines,
carefully made.

The identity system for Little Loops Technologies, LLC and its family of properties. One hand draws every loop: shared type, shared paper, shared voice — one accent per property, and every rule stated as something a person or an agent can check. v4.0 ships the assets, closes the ten defects the v3.0 review found, and passes its own harnesses — including the voice-lint, on this very page, by mechanism rather than by exemption.

Parent · littleloops.tech
OSS · little-loops.ai
Product · reserved
Supersedes · v4.15
Canonical · littleloops.tech/brand
01 / architecture

One house, three rooms — and one front door.

A hybrid model, OSS-led. The parent and the toolkit share DNA — the double-loop mark. The commercial product will get its own name and accent, but inherits the type system, the paper, and the mechanical-toy conceptual language. The flagship's identity is specified first-class in §03, ahead of the parent's color and type, because the hierarchy is enacted in the document's own order.

Little Loops Technologies, LLC
parent · littleloops.tech · redirects: littleloopstechnologies.com → 301
open source

little-loops

The autonomous development toolkit and the flagship of the brand. Speaks to developers in the full poetic register. Its identity — the ll: treatment, its lockup, its refresh spec — is §03.

little-loops.ai · docs.little-loops.ai
product · TBD

[Product name]

Commercial offering. Own name, own accent hue, inherited type and voice at a cooler temperature. Launches as “from the makers of little-loops.” Named before its site is designed, against the criteria in §13.

domain · reserved with name
Hierarchy statement. little-loops is the front door of the family. Developers arrive at little-loops.ai; credibility flows from the toolkit outward. The parent site exists as a one-screen registry — proof of the system, a legal home, and nothing more. It stays that small forever.

Inheritance

Always sharedTypography, paper & ink palette, semantic colors, loop motif, voice principles, figure system, iconography, favicon glyph geometry (colorway varies per property — §12).
Property-specificAccent hue, logo lockup, domain, tagline, diagram density, default color mode, favicon colorway. Taglines are assigned, not improvised — the parent’s and the flagship’s are decided in §08; the product’s waits for its name.
Attribution ruleEvery property's footer reads “A Little Loops Technologies project” and links to littleloops.tech.

Naming in prose

The company“Little Loops Technologies, LLC” in legal, invoice, and contract contexts; “Little Loops” elsewhere. Title case, no hyphen, never a monospace treatment.
The toolkitAlways little-loops: lowercase, hyphenated, and set in mono whenever the surrounding sentence could confuse it with the company. In running text where both appear, the company gets the capitals and the toolkit gets the hyphen — that contrast is the rule, not a hazard.
03 / little-loops — the flagship's identity

The front door gets its own key.

The toolkit's identity has two registered assets: the shared double-loop mark (in Blueprint or ink) and the ll: prefix treatment — the wordmark the live site already ships, mirroring the /ll: command namespace developers type every day. The prefix is the most ownable thing the brand has. Face ruling, stated once and echoed nowhere in conflict: the ll: treatment is JetBrains Mono 700, always — the §06 scale lends it only its size (--t-h). v3.0's scale table filed it under Archivo; that contradiction is retired.

ll:little-loops
JetBrains Mono 700 · prefix in Blueprint · name in ink
fig. 07ll: wordmark · light · site headers, README, badges
ll:little-loops
prefix in Blueprint dark variant · name in Paper
fig. 08ll: wordmark · dark · docs, terminal contexts

Rules for the ll: treatment

CompositionAlways JetBrains Mono 700, always lowercase, no space around the colon. The prefix takes the accent (Blueprint light, --d-oss dark); the name takes text color. Never the reverse.
Where it livesSite header, docs header, README, GitHub social card, package listings. It may sit beside the double-loop mark (mark left, wordmark right, clearspace per the §02 table) or stand alone in text-first contexts.
Where it doesn'tNever on parent or product surfaces. Never expanded to “ll: Little Loops.” The colon is not punctuation to be corrected — it is the namespace, load-bearing.

The little-loops.ai refresh — before and after, decided

AxisLive site todayAfter refresh
SurfaceDark-leaning presentationDark stays the default — the audience lives in dark editors, and flipping the flagship to light-default is a redesign, not an alignment. Light mode ships as the alternative.
PaletteUnalignedInk surface, Paper text, Blueprint accent, Pass/Signal semantics — the §05 dark token set verbatim.
TypeUnalignedNewsreader display ≥ 28px, Archivo UI, JetBrains Mono code and the ll: wordmark.
CopyCanonicalUnchanged. The site is the voice spec's source, not its subject (§08).
Diagrams & tabsStyled ad hocRestyled to the §10 diagram spec. Figure numbering for tabbed panels, decided: a tab group is one figure; its panels are lettered states of it (“fig. 03a Generate · 03b Run · 03c Resume”), so numbers never change when tabs switch.
IconsUnicode arrows (↗), unstyled copy buttonsThe §10 set — external-link, copy, and close are drawn in v4.0 precisely because the live site needs them on day one.

Hierarchy, enacted: this section precedes color, type, and states because the flagship outranks the parent. The parent is a proof; little-loops is the product of the brand.

04 / color

Paper, ink, one accent each — and a semantic layer.

The parent brand is near-monochrome: warm paper and warm black ink, like a well-made instruction manual. Each property claims exactly one brand accent; accents never mix on the same surface. Separately, two semantic colors — Pass and Signal — carry meaning family-wide and belong to no property. Every ratio below is computed, not estimated, and was independently re-verified for v4.0.

Specimen exemption, scoped once and broadly. This document may display any regulated element as a captioned specimen: every accent side by side, both interaction languages, schematic wordmarks, full-opacity loops at exhibit scale, and quoted or pattern-quoted banned vocabulary. The exemption covers display-as-specimen on this page only; it covers nothing on any other surface, and it never covers this page using a regulated element rather than exhibiting it. v3.0 scoped its exemption to accents alone and then cited it for three things outside that scope; this paragraph is the whole exemption, and it is the only one.
Ink
#16130F · --ink
Text, marks, dark surfaces. A warm black — never pure #000.
Paper
#F5F1E8 · --paper
Primary background. From the logo's own stock.
Paper Deep
#EAE4D6 · --paper-deep
Wells, alternating sections. One step of depth, no shadows.
Paper Lift
#FBF8F1 · --paper-lift
Raised cards on Paper or Paper Deep. The only “lighter than paper” value; pure white is banned.
Line
#D8D0BE · --line
Hairline borders. Decorative only — never text, never a focus indicator.

Brand accents · one per property

Blueprint · OSS
#2741D6 · --oss
Reserved for little-loops. Links, diagrams, the ll: prefix, syntax accents — OSS surfaces only.
Verdigris · Product
#0B6B4F · --product
Provisional — held for the commercial product; revisit once named.

Semantic layer · family-wide, no property owns these

Pass
#20643A · --ok
Success states: tests green, harness passed, loop done. Pass means a state; Verdigris means a property.
Signal
#9A4414 · --error
Errors and warnings only, never decorative. Coloring a fail status in the matrix below is semantic use — a WCAG fail is a fail state.

Contrast matrix · computed WCAG 2.1 ratios · independently re-verified 2026-08-21

Tokenon Paperon Paper Deepon InkText use
Ink16.4:1 AAA14.6:1 AAAAll sizes
Ink Soft10.6:1 AAA9.5:1 AAAAll sizes
Blueprint6.6:1 AA5.9:1 AA2.5:1 failLight surfaces only; use --d-oss on Ink
Verdigris5.8:1 AA5.1:1 AA2.9:1 failLight surfaces only; use --d-product on Ink
Pass6.3:1 AA5.6:1 AA2.6:1 failLight surfaces only; use --d-ok on Ink
Signal5.8:1 AA5.2:1 AA2.8:1 failLight surfaces only; use --d-error on Ink
Line1.4:1 n/a1.2:1 n/aNever text; borders only
Paper16.4:1 AAAText on dark surfaces
Paper on Blueprint6.6:1 AAProperty tags, filled buttons — new row; v3.0 shipped tags on an unverified pair
Paper on Verdigris5.8:1 AAProperty tags only
Ink on --d-oss6.7:1 AAParent tags on Ink surfaces (v4.6): the light fills sit under 3:1 against Ink, so the chip inverts — dark fill, Ink text
Ink on --d-product8.0:1 AAAParent tags on Ink surfaces (v4.6) — same inversion

Rule: no accent or semantic color may be used as text on Ink surfaces — the dark-mode counterparts in §05 exist for that. Any text-on-color pair a surface ships must have a row in this matrix; a pair without a row is a defect, not an oversight. When a claim in this table and a design in the wild disagree, recompute; never eyeball.

The parent site at littleloops.tech uses no brand accent at all — ink and paper only, with Blueprint and Verdigris appearing solely as small tags where the properties are listed. Semantic colors are permitted everywhere, including the parent (a form error is a form error). Restraint is the parent's signature — and it is fully specified in §07, because removing color means the interaction language has to work harder, not less.

05 / dark mode

Dark is a surface, and the surface carries the class.

The audience lives in dark editors and dark terminals. Dark mode is the same system inverted: Ink becomes the surface, Paper becomes the text, and every accent has a lightened counterpart tuned to pass on Ink. The governing rule is stated against the surface, not a component list: any element whose resting background is Ink carries the .dark class — dark panels, dark figure stages, swatch chips, and every code block. Transient state inversions (a hovered button) are states, not surfaces. v3.0 patched the class onto its dark panels and left every code block with an invisible selection; the surface rule closes the category, and it is grep-checkable: a non-state ruleset with background:var(--ink) whose markup lacks .dark fails review.

RoleLight tokenDark tokenDark ratio on Ink
Surface--paper #F5F1E8--ink #16130F
Text--ink--d-text #F5F1E816.4:1 AAA
Text, soft--ink-soft--d-text-soft #C9C2B210.4:1 AAA
Border--line--d-line #4A443A1.9:1 borders only
OSS accent--oss--d-oss #8895F26.7:1 AA
Product accent--product--d-product #3FBF978.0:1 AAA
Pass--ok--d-ok #57B87A7.5:1 AAA
Signal--error--d-error #EE8F557.7:1 AAA
Code comment--code-comment #C9C2B210.4:1 AAA
Focus--ink outline--d-text outline16.4:1 AAA
Selectionink bg / paper textpaper bg / ink text16.4:1 AAA

Live specimen — interaction states included

little-loops docs · dark

Body text in Paper on Ink. A Blueprint link, dark variant ✓ harness passed ✕ 2 checks failed — run ll-doctor soft caption text

Mode rules

Default per propertyParent: dark default, light available — the front door meets the dark-editor audience where it lives — on every parent surface, the legal sub-paths included, with a reader-run toggle in the footer beside the legal nav; the choice persists, and the page never follows the system. Tags invert per §04. OSS site and docs: dark default, light available, following the live site. Product: decided at naming. This kit page: dark default — its readers live in dark editors — with a reader-run toggle; the choice persists, and the page never follows the system.
Focus on darkFocus outline on Ink surfaces is --d-text (Paper), 2px, offset --s1, on every focusable element — the selector is universal :focus-visible, not an element list. --d-line fails the 3:1 non-text minimum and is never a focus indicator.
Warmth invariantBoth modes stay warm. Dark surfaces are Ink, never neutral gray or pure black; dark text is Paper, never pure white.
06 / typography

Three voices, one hand.

Newsreader for the poetic beat, Archivo for structure and UI, JetBrains Mono for the machine's own voice. All three are open-source (Google Fonts / SIL OFL). Loaded lean: the webfont request carries only the axis ranges this scale uses — Newsreader 300–450 with italics, Archivo 400–900, Mono 400/500/700 — with preconnects to both font origins. v3.0 requested the full 100–900 spectrum of two variable families and used a third of it.

Display — Newsreader · 300–450 · italics for emphasisdisplay roles only · never below 28px
Wind it up. Let it run.
Pull quote — Newsreader · 400 · romanexactly 28px (--t-pull) · the boundary case, named
A loop to discover bugs. A loop to score results. A loop to write code that feels inevitable. A loop made of these loops.
Heading / UI — Archivo · 600–90024px (--t-h) · matches the wordmark's geometric weight
Durable state. Consistent process. Harness-gated verification.
Body — Archivo · 400–50016px (--t-body) · 1.6 line height · 60–68ch measure

A loop is a small machine you define once and run forever. Describe what to check, what to fix, and when to stop — the rest runs without you. Body copy stays plain, warm, and declarative; the italics live in the display layer.

Code — JetBrains Mono · 400–70014px (--t-code) · the machine speaks in ink blocks
# two commands to start
pip install little-loops
ll-init

The complete scale — every size, one table

TokenSizeFaceRoles
display / h1clamp(44px … 84px)Newsreader 300–450Cover and hero display.
display / h2clamp(30px … 44px)Newsreader 450Section headings. This row existed in v3.0's CSS and not in its scale — the token-lint exemption now enumerates all three clamp pairs, and a clamp absent from this table fails the lint.
display / specimenclamp(30px … 52px)Newsreader 300–450Type-specimen display. Floor across all clamps is 28px by clamp minimum.
--t-pull28px · 1.75remNewsreader 400 romanPull quotes. The Newsreader floor — any Newsreader glyph under 28px is a defect.
--t-h24px · 1.5remArchivo 600–900Headings and the schematic wordmark. The ll: treatment borrows only this size; its face is JetBrains Mono 700 by §03.
--t-lede17px · 1.0625remArchivo 400Intros and ledes.
--t-body16px · 1remArchivo 400–500Body default.
--t-code14px · 0.875remJetBrains Mono / ArchivoCode blocks, buttons, card body, table body, small prose.
--t-label13px · 0.8125remArchivo 800 capsSection labels (h3), card labels, the header brandline.
--t-caption12px · 0.75remJetBrains Mono / Archivo 600Captions, nav, kickers, matrix cells, swatch metadata.
--t-micro10px · 0.625remJetBrains Mono / Archivo 500–600Leader indices and lockup sublines. Nothing may be smaller — v3.0's sublines were a 9px calc() the lint couldn't see; the calc is gone, the role has a token, and token-lint v2 flags any calc() on a type token.

The scale is hand-picked, not ratio-derived — and that is a decision, recorded in §13's decision record. A generator ratio was considered for v4.8 and rejected: retrofitting derived values changes every token, a breaking bump for zero visual gain, and additions are already governed better than a formula would govern them — a new size needs a row in this table and a version bump, and a size computed from another is exactly what the token-lint calc() rule bans. The rem values assume the 16px root this page ships; they are conveniences for builders, and the px column stays canonical.

Rules

The 28px boundaryNewsreader appears only in display roles — headlines and pull quotes — and never below 28px. Archivo never appears above 28px in display roles. Testable: any Newsreader glyph under 28px is a defect.
Italic budgetOne italic phrase per headline, maximum. Pull quotes are set roman — the quote itself is the emphasis. The budget marks the poetic beat; spend it once.
Case & glyphsSentence case everywhere except the wordmark, nav labels, and eyebrow kickers; quoted live copy keeps its source capitalization. Glyph rule: the ℓℓ notation (U+2113) is set only in JetBrains Mono and caption faces whose coverage is verified by rendering, never in Newsreader display — a brand may not gamble its namesake glyph on a fallback font.
07 / interaction states

Every state, both modes — and both implemented.

Removing decoration means interactivity must be legible from behavior alone. Two interaction languages exist: the parent's accent-free language (ink does everything) and the property language (the accent carries links and focus). This document runs the parent language on light surfaces and the dark language inside every .dark element — the buttons and links on this page are the spec running, in both modes. Property-language specimens below are covered by the §04 specimen exemption.

Parent · accent-free (littleloops.tech)

  • Link, restink text · 1px underline at 50% ink · offset --s1
  • Link, hoverunderline to 100% ink · 120ms ease
  • Link, visitedunchanged — a one-page site has no visited semantics
  • Focus2px solid ink outline · offset --s1 · universal :focus-visible — inputs and summaries included, not just links and buttons
  • Button, rest2px ink border · paper fill · ink text · min-height --touch (44px)
  • Button, hoverinverted: ink fill, paper text
  • Disabled40% opacity · no hover response · cursor not-allowed
  • Selectionink background · paper text

Try it: an ink link ·

Property · accented (little-loops.ai shown)

  • Link, restaccent text · underline at 50% accent
  • Link, hoverunderline to 100% accent
  • Link, visitedunchanged — docs convention; developers revisit pages
  • Focus, light2px solid accent outline (Blueprint 6.6:1 — passes 3:1 non-text)
  • Focus, dark2px solid --d-text (Paper) outline — never --d-line
  • Selection, darkpaper background · ink text — inverted, always visible, including inside code blocks (the surface rule, §05)
  • Success--ok light · --d-ok dark · e.g. “✓ harness passed”
  • Error / warning--error light · --d-error dark · states the fix, never apologizes
  • Disabledsame as parent — semantics don't vary by property

Specimen: a Blueprint link · ✓ 12 passed · ✕ config not found — run ll-init

Form controls — the components the matrix always implied

Until v4.8 the §04 matrix carried rows for filled buttons — Paper on Blueprint, Ink on --d-oss — that no component in this kit shipped, and the universal :focus-visible ruling named inputs no spec had drawn. Both gaps close here: an input, its label, a switch, and the primary button, every dimension a token. The switch's interactive box stands on the --touch floor with the track and knob drawn inside it; its on-state pairs are the §04 inversion rows doing their work. One motion ruling travels with it: the knob's travel is an activation transition (--hover-dur, --hover-ease), not a hover one — §09's "nothing moves position" binds hover, and hover still moves nothing. The accented specimens below are property language on a parent surface, covered by the §04 exemption; the dark variants render live in §12's fig. 10.

Specimen · light (property language)

Rules

  • Input1px Line border · Paper Lift fill · mono at --t-code · --r1 · min-height --touch · focus per this section's languages
  • LabelArchivo 600 caps at --t-caption · Ink Soft · --s2 above its input · every input has one, associated by for
  • Switch--touch hit box · --s7 × --s5 track, --s4 knob · on = accent fill, off = Paper Deep · always role="switch", aria-checked, and a name
  • Primary buttonBlueprint fill · Paper text (6.6:1); dark: --d-oss fill · Ink text (6.7:1) — the §04 rows, now with a component
  • One per viewat most one primary button per screen; every other action is the bordered neutral

Verification path, stated so it can be walked: tab through this page and every stop shows a 2px ring — ink on paper, Paper on ink. Select text anywhere, including the YAML block in §08 and the code specimen in §06, and the selection is visible. If either fails, the surface rule was broken somewhere; grep for background:var(--ink) and find the element missing .dark.

08 / voice

The toymaker who ships.

The voice already exists on little-loops.ai; this codifies it. The metaphor is the wind-up machine: small, complete, self-running. Sentences are short and declarative. Wonder is earned by precision, never by hype. Quotations from the live site are verbatim; where a clause is excerpted, the caption says so — the completeness claim v3.0 made and broke is retired in favor of one the page can keep. v4.4 adds the tagline ruling: the line, its placement, and the candidates it beat, recorded so the ground is not walked twice.

Principle · Machines, not magic

A loop to discover bugs. A loop to score results. A loop to write code that feels inevitable. A loop made of these loops.

Describe mechanisms, not miracles. Every claim names what actually happens. “AI-powered” is banned; say what the loop does. (Live-site litany, verbatim and complete.)

Principle · Short, then shorter

Wind it up. Let it run.

Declarative fragments are allowed and encouraged in display copy. Body copy uses full sentences but stays under three clauses. (Live-site heading, verbatim and complete.)

Principle · Craft vocabulary

little-loops imagines Software Engineering as the art of crafting simple machines that run themselves.

The lexicon: wind, run, loop, machine, harness, handoff, done. The banned list lives in the YAML below and only there — a word is banned by a rule, not by a prose list that drifts from it. Spelling ruling: handoff, one word, matching the live docs' “Session Handoff.” (Live-site sentence, verbatim and complete — v3.0 clipped its opening clause while claiming completeness.)

Principle · Honest scale

Small machines, carefully made.

The parent never inflates. Marketing copy avoids a first-person plural that implies a floor of employees that doesn't exist. Little Loops Technologies has multiple founders, so a "we" scoped to them is honest — but a regex can't tell a founder-scoped "we" from a headcount-inflating one, so the rule doesn't try: parent-we flags every "we" and a person confirms the scope, the same treatment unlock-metaphor and handoff-spaced already get below. Legal pages (privacy, terms) require first person and are excluded by path in the YAML — not by an exception in someone's head.

Parent · low temperaturePlain, warm, brief. States what the company is and makes. One poetic line maximum on the whole site.
OSS · full registerThe complete voice — poetic display beats, mechanical metaphor, developer directness. This is the flagship of the tone.
Product · cool + concreteInherits the lexicon but leads with outcomes and specifics. Buyers get proof; poetry stays in the hero only.

The tagline — decided, and the candidates it beat

Taglines are property-specific by §01, so this is an assignment, not a slogan. Two lines are decided here. The product’s is deferred on purpose: its register leads with an outcome (above), and an outcome cannot be written before there is a buyer to name it for. The specimens below are mentions under the §04 exemption; the single use on this document is the footer.

Parent · littleloops.tech · decided v4.4Newsreader 400 roman · --t-pull · sentence case, full stop
Order from the machine.
OSS · little-loops.ai · decided v4.4full register · two beats, matching “Wind it up. Let it run.”
Noise in. Order out.
Product · unnamed · deferred to the naming (§13)cool + concrete · must lead with an outcome
Pending the name.
Why this lineThe name already spends the word loop; the tagline spends machine. Read together, the lockup states the whole system — little loops, assembled into a machine, producing order — and no word is paid for twice. It carries the deus ex machina weight without asking the reader for Latin, and it paints the problem and the answer in one breath.
Why it is keepableThe claim sits at the machine, never at the model. Order is what a harness produces and a reader can check; determinism is what the model underneath will never provide. §13 binds this kit to claims it can keep, and a tagline is the most-repeated claim the brand makes — the worst possible place to put an unkeepable one.
What it does not replace“Small machines, carefully made.” stays the hero display line. The two have different jobs: the hero is set once at display size and may run long; the tagline rides the lockup, the footer, and the OG eyebrow, and must stay legible at --t-caption. Poetic budget: one line per view. Hero and tagline never share a viewport — on this document the cover carries one and the footer the other, a full page apart.

Placement — where the line may stand

SurfaceTreatmentRule
LockupBeneath the wordmark · Archivo 400 · --t-captionAt lockup size the tagline is Archivo, always — Newsreader under 28px is a defect (§06), and a tagline set at 28px would out-shout the wordmark. Sits one clearspace below the lockup’s lowest ink, never inside the mark’s clearspace (§02).
FooterSign-off line, under the legal lineStands beside the §01 attribution line, never instead of it.
OG / socialEyebrow above the Newsreader headline · Ink Soft for parent, accent for properties (§12)The tagline is the eyebrow or the headline, never both on one card.
Nav, buttons, CTAsBannedStanding alone as a call to action, “Order from…” reads as a purchase instruction. Adjacent to the name that reading collapses; inside a button it does not. Testable: the line never appears as the sole text of a link or button.
Body copyOnce per surface, maximumThe parent runs at low temperature — one poetic line for the whole site. The tagline is that line; a page that prints it twice has spent a budget it does not have.

Rejected candidates — recorded, so the ground is not walked twice

A rejected line with no recorded reason comes back. Each row states the ruling and, where the line survives in another role, the role it was reassigned to.

CandidateRuling
Determinism in a non-deterministic worldRejected as tagline; kept as thesis. It promises what the model cannot deliver — the same prompt does not return the same output — and this kit does not ship claims it cannot keep. Retained for the about page and the OG description, where the next sentence can qualify it. Spelling ruling, should it run: nondeterministic, closed, no hyphen — the standard form in computer science, faster to read at display size, and the same class of call as handoff.
Small, deterministic machines for a nondeterministic worldRunner-up thesis. “Small” repairs most of the credibility gap: a small machine plausibly is deterministic even when the thing inside it is not. Too long for a lockup; approved for about-page and OG use.
Order from the loopRejected on the echo. The name already spends loop; the tagline repeating it reads as a stutter, not a rhyme. This rejection is what produced the decided line.
Order in a world that driftsHeld in reserve. The best-flowing line of the set, and drift names a failure every reader has watched happen. Reserved for the product, whose register must name the problem before it claims the outcome.
Probabilistic parts. Deterministic machines.Reassigned to technical surfaces. The most precise line considered, and the only survivor that keeps the word — it locates determinism at the machine and never at the model. README opening and conference abstracts, where its vocabulary is native.
Small machines that run themselves — and prove itRejected on length and on the dash, which survives neither a lockup nor a caption setting. Its second clause is the honest half and stays in the principles above.
Ordo ex machina · Ordo ab chaoRejected. The first is a translation exercise; the second is the Scottish Rite’s 33rd-degree motto, and a borrowed motto carries its lender’s meaning wherever it goes. The English asks nothing of the reader and says more.
A jig for a machine that guessesNot rejected — reassigned to §09. A jig makes every cut identical regardless of whose hand holds the tool: the harness, described without metaphor. Filed as a candidate figure, not as a tagline.

The lexicon as a lint — with the use/mention distinction in the machine

A banned word is only banned when it is used. The linter parses HTML, not raw text, and skips three containers: code, pre, and anything marked data-mention. That is the whole mechanism — no page-level exemptions, no excluded spec pages. Which puts the burden on honest markup: a code exhibit carries a code element, never mono styling alone, because a linter that parses HTML can only see what the HTML says a thing is. The rule below the specimen is the rule: banned words survive only inside code, pre, or data-mention — and a listing styled as code but not marked as code is a defect in the page, not a gap in the lint. This page passes the lint it defines: every banned word on it sits inside a code element or a data-mention span, and the harness proves it on every version bump. v3.0 failed its own lint and disclosed the failure nowhere in the document; both defects are closed by mechanism, not confession.

# voice-lint.yaml · v4 · runs as a little-loops harness
version: 4
defaults: { scope: all, severity: error, flags: iw } # i = case-insensitive, w = word-boundary
ignore_within: ['code', 'pre', '[data-mention]'] # the use/mention distinction, machine-enforced
rules:
  - id: hype-compound
    pattern: 'AI[- ]powered'
  - id: leverage-verb
    pattern: 'leverag(e|es|ed|ing)'
    allow: ['leverage ratio']
  - id: seamless
    pattern: 'seamless(ly)?'
  - id: supercharge
    pattern: 'supercharg\w*'
    allow: ['supercharger'] # the car part is a car part
  - id: revolutionize
    pattern: 'revolutioniz\w*'
  - id: unlock-metaphor
    pattern: 'unlock(s|ed|ing)?'
    severity: warn # literal vs metaphor needs a human; the loop flags, a person rules
  - id: parent-we
    pattern: 'we'
    scope: parent
    severity: warn # founder-scoped "we" is honest, headcount-inflating "we" isn't; a regex can't tell them apart, a person can
    exclude_paths: ['/privacy', '/terms', '/legal/*']
  - id: handoff-hyphen
    pattern: 'hand-off'
    fix: 'handoff' # hyphenated form is always wrong; auto-fixable
  - id: handoff-spaced
    pattern: 'hand off'
    severity: warn # legal as a verb phrase, wrong as a noun — a human rules.
                                   # v3.0's prose promised an error no regex can deliver; demoted honestly
# encouraged: wind, run, loop, machine, harness, handoff, done
09 / motif & motion

The loop is the ornament; the figure is the frame.

Two decorative devices family-wide, and only two. First, the double-loop mark itself, used decoratively — dividers, loading states, low-opacity background geometry. Second, the instruction-manual figure system. Nothing else decorates — no blobs, no gradients, no stock illustration, no photography.

Mark vs. motif — the boundary, decided by function

It's the mark when……it identifies. Adjacent to a wordmark, in a header, avatar, favicon, OG image, or anywhere it names the brand. Mark rules apply in full: colorways, 24px floor, clearspace, no deformation.
It's the motif when……it decorates. At ≤ --motif-opacity (0.10) as background geometry, or full-opacity as a divider or loading stroke at ≤ 32px tall. Motif loops never sit within one clearspace of a mark — the two must not read as one.
Banned middle groundFull-opacity decorative loops above 32px are banned on every surface. On this page, larger full-opacity loops appear only inside captioned figures — display-as-specimen under the §04 exemption, which now actually covers it.

The figure system — required, not optional

The figure system is the counterweight to a familiar type-and-cream palette, and a counterweight only works if it carries load. It is therefore mandatory wherever exhibits appear: docs diagrams, README screenshots, OG images, slide exhibits, and changelog illustrations all render as numbered figures with mono captions. Numbering restarts per page; a tab group is one figure with lettered panel states (§03); cross-references are namespaced — “docs/loops fig. 03.” A figure without a number and caption is a defect on any family surface.

fig. 09 · a numbered figure caption

The divider specimen above is 32px tall — at the boundary, deliberately, so the boundary is visible.

Motion spec — complete

The revealThe mark is a filled shape, not a stroke path, so it can't be drawn on — it fades and scales in instead: opacity 0→var(--motif-opacity), scale(.94)scale(1). --draw-dur 900ms, --draw-ease. Triggers on load or first scroll into view, once. Maximum one revealed animation per viewport.
Background geometryCompleted strokes at --motif-opacity 0.10, never animated, never behind body text under 10:1 effective contrast.
Reduced motionprefers-reduced-motion: reduce renders every stroke completed and disables all transitions. Hover transitions elsewhere: --hover-dur 120ms, --hover-ease, opacity and color only — nothing moves position. Activation transitions (a switch knob's travel, §07) may move exactly what they toggle; hover still moves nothing.
10 / iconography & diagrams

The same hand draws the small things.

Single ink strokes, round caps, the mark's own pen — and every icon is drawn in currentColor, so the same SVG is legible on Paper and on Ink without a variant. v3.0 hardcoded light-mode hex into the pass and fail icons, which the §04 matrix itself scores as failing on Ink: the flagship's default surface would have shipped illegible status glyphs. The set also grows from five to eight, because the live site already needs the other three: its external links are Unicode arrows and its copy buttons are unstyled today.

The icon set — drawn strokes, currentColor, not fonts

pass · fail · step · install · running · copy · external · close · light · dark — 2.5-unit strokes on a 24 grid, round caps

The same SVGs, on Ink — nothing re-drawn, nothing re-colored by hand

Pass and Signal resolve to their dark counterparts via the .dark cascade — the matrix rows in §05 are the ones doing the work.
Construction24-unit grid, 2.5-unit stroke, round caps and joins — the mark's pen at icon scale. Icons ship as inline SVG in currentColor, never icon fonts, never emoji, never raw Unicode glyphs, never literal hex.
ColorInk by default via cascade. Pass and Signal icons take their semantic class (.icon-ok, .icon-err) and always travel with a word — color is never the sole carrier of meaning. Close is ink; fail is Signal — same geometry, different job, and the color states which.
Growth ruleNew icons are added by version bump (§13), drawn on the same grid. If an icon can't be one or two strokes, it's a diagram, not an icon.

Diagram spec — for docs, tabs, and exhibits

Strokes & fillsInk strokes on Paper (or Paper strokes on Ink), 2px, square corners (--r0), no fills except Paper Deep wells. Dashed leaders label parts, mono captions name them.
One accentThe owning property's accent, used once per diagram to mark the active state, path, or focus. Never two accents; semantic Pass/Signal allowed for outcome markers.
Framed as figuresEvery diagram is a numbered figure with a mono caption (§09). Tab groups are one figure with lettered panels (§03), so the live site's Generate/Run/Resume becomes one stable figure, not three renumbering ones.
11 / layout & accessibility

The measurements an agent will ask for.

If a build needs a value not listed here, the kit is incomplete — file it as an issue, don't invent the value. This document's own stylesheet passes token-lint v2, and its own navigation works: sticky-header anchor offset is specified below because v3.0 shipped thirteen section links that scrolled their targets under the header.

Spacing scale4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96 px as --s1…--s9. Section padding: --s9 desktop, --s8 under 720px. Card padding: --s4–--s5. Hand-picked, not ratio-derived — the §06 ruling covers both scales, stated once.
GridMax width 1080px · 32px gutters · single breakpoint at 720px (multi-column collapses to one).
MeasureFloor 60ch, cap --measure 68ch. --measure-narrow 52ch for ledes and asides. Nothing exceeds 68ch.
Sticky offsetsAny surface with a sticky header sets scroll-padding-top to the header's token sum plus --s5 breathing room. An anchor whose heading lands under the header is a defect — testable by clicking every nav link.
Radii & elevation--r0 0 (default) · --r1 4px (code, inputs) · --r-pill (tags only). Depth is Paper → Paper Deep → Paper Lift plus 1px Line borders. Box shadows are banned family-wide.
Borders--bw-hair 1px hairlines · --bw-rule 2px structural rules, buttons, focus · --bw-bar 3px callout bars. Border widths are tokens too.

Accessibility — beyond contrast

FloorAA minimum for all text (verified §04–05) · visible focus on every focusable element via universal :focus-visible, both modes · reduced motion honored · touch targets ≥ --touch (44px), enforced by min-height on every button.
Names for marksThe mark is aria-hidden when decorative and carries role="img" with an accessible name when it identifies — this document's own header does it. A linked logo's accessible name is the destination (“little-loops home”), not “logo.”
Meaning & motionSemantic colors always travel with an icon and a word (§10) · figure captions are real text, never baked into images · alt text on exhibit images states what the figure shows, in the voice · keyboard order follows reading order.

Print & email

PrintInk prints as rich black on the stock at hand — Paper is the screen's memory of paper, not an ink to reproduce. Mark minimum 12mm wide; favicon glyph never prints. Accents print only on OSS/product collateral, one per piece. Figure system applies to printed exhibits.
EmailSignatures are plain text: name · role · “Little Loops Technologies, LLC” · littleloops.tech. No image marks, no HTML signatures. Transactional/HTML email, if ever needed, uses Paper/Ink with system font fallbacks (Archivo → Helvetica/Arial stack) and no webfont dependencies.
12 / applications & assets

Where the kit lands — with the files it lands as.

v3.0's every mark was a “schematic stand-in” for artwork that didn't exist; nothing could be built from it without inventing the assets. v4.0 ships them: everything in the table below is a real file in /brand/assets, emitted by make-mark.py, regenerated on every version bump. The kit links its sources; a surface that needs an asset copies a file, never redraws a figure.

The system, composed — one screen, end to end

Every exhibit before this one exercises a subsystem at a time; a kit whose thesis is checkability owes an integration test. Fig. 10 is a docs settings panel for the flagship, rendered dark because the flagship is (§03), composed entirely from §04–§10 tokens: no value in it exists outside this document. The table after it names where each subsystem appears, so "the system composes" is a claim a reader can walk, not one the kit asserts. Folded from the brand-kit-synth prototype, which mocked a screen the same way — the idea crosses; its values do not.

little-loops · settingsconfig valid · ✓ harness passed
Loop defaults

These defaults govern every loop this project runs. Changes apply on save; a loop already running finishes under the config it started with.

Harness gate
No loop completes until its harness passes
Session handoff
Write a continuation prompt when a run ends early
Draft pull requests
Open PRs as drafts until the harness signs off
Verbose transcripts
Keep full run logs in the state directory
Relative to the repo root. Loops read and write nowhere else.
fig. 10docs.little-loops.ai · settings panel · composed from §04–§10 tokens only · dark, the flagship default · form controls per §07

What fig. 10 exercises

SubsystemWhere it appears in the figure
Color · surfacesInk resting background, so the element carries .dark by the §05 surface rule; depth is --d-line hairlines, never a lighter tone — the §05 "depth on Ink is border" ruling, obeyed.
Color · accentOne accent, Blueprint's dark variant: the on-state switch tracks and the primary button, with Ink text and knob on --d-oss per the §04 inversion rows (6.7:1). No second accent anywhere.
Color · semanticPass appears once, in the chrome, as --d-ok — and it travels with a glyph and a word (§10), never color alone. Signal is absent because nothing is wrong; a healthy screen spends no Signal.
TypeTitle in Archivo 800 at --t-h; body copy at --t-code; setting labels Archivo 700 caps at --t-caption; chrome, input value, and hint in JetBrains Mono. Newsreader is absent — no display role on a settings panel, per the §06 28px boundary.
SpacingBody pads --s6; the grid gaps --s3; rows pad --s3/--s4; the action row stands off by --s5 with a --s4 pad above the hairline. Every gap is a token.
Borders & radiiThe frame is the 2px rule; internal lines are 1px hairlines; the input rounds --r1; the switch track is the only pill (--r-pill, tags-and-tracks territory); everything else is --r0. No shadows.
InteractionFocus is the universal 2px Paper ring on Ink (§05); selection inverts and stays visible; input, switches, and buttons all stand on the --touch floor. Both buttons and both switch states are §07's spec, running.
MotionThe knob's activation travel at --hover-dur / --hover-ease is the only movement; hover changes color only. Reduced motion completes everything instantly (§09).

Shipped assets

FileWhat it isWhere it goes
make-mark.pyCustodian of the design-frozen canonical curve (/brand/canon). Emits every file below and the §02 clearspace table; never re-derives the geometry.Repo root of /brand; also mirrored in the little-loops repo.
mark-ink.svg / mark-paper.svgFull double-loop mark, filled in Ink or Paper.Headers, OG images, GitHub avatar source, print.
lockup-ink.svg / lockup-paper.svgThe production lockup (v4.7): mark plus wordmark, set from the §06/§08 type tokens, internal gap and clearspace data in mark-data.json's lockup key. Not outlined — <text> in Archivo, so it renders correctly wherever the shared type system is already loaded (§01).Anywhere §02 requires the lockup: parent header, littleloops.tech, GitHub org avatar. Copy the file; never compose the wordmark yourself.
favicon-parent.svgDouble-loop glyph, filled Ink, with an internal prefers-color-scheme block flipping to Paper.littleloops.tech. Ship beside a static PNG/ICO fallback in Ink Soft — the one fill value that reads on both light and dark tab strips — for browsers that ignore SVG media queries.
favicon-oss.svgDouble-loop glyph, filled Blueprint, flipping to --d-oss.little-loops.ai and docs. Property favicons take the accent at every size — v3.0's shared-geometry rule made all three properties' tabs pixel-identical at 16px; colorway is now property-specific because differentiation is the favicon's entire job.
mark-data.jsonParameters, path data, clearspace table — machine-readable for agents.Consumed by build tooling and this document's own regeneration.

Surfaces

SurfaceSpecNotes
littleloops.techSingle page: mark, tagline, one-line thesis, the two properties, contact, legalTagline “Order from the machine.” under the lockup, in Archivo at --t-caption (§08). Build answers, so the page can be built from this document alone — thesis line: “Little Loops Technologies makes small machines, carefully — an open-source toolkit for autonomous development, and the products built with it.” Contact: hello@littleloops.tech, plain text link. Legal: privacy + terms as sub-paths, excluded from parent-we by the YAML. Ink + paper only, parent interaction language (§07). Dark default, light available (§05), on every parent surface including the legal sub-paths: a reader-run toggle in the footer beside the legal nav — icon-only, §10 sun and moon, choice persisted before first paint, never system-followed; property tags invert to --d-oss and --d-product fills with Ink text (§04); color-scheme dark light; theme-color carries both values; print returns to light.
littleloops.tech/brandThis document · dark default · reader-run toggle (§05)Dark since v4.2, and joined by the registry in v4.6 — still the surface that proves the mechanism end-to-end. It is a working document, and its readers live in dark editors, so dark is the default and light is the persisted alternative; the page never follows the system. The header toggle is icon-only: the §10 sun and moon, the visible glyph naming the mode it switches to. Chrome reads the role layer (§ tokens, v4.2); exhibits that demonstrate light-mode rendering pin it (.lt) in both themes, so a specimen never contradicts its caption.
littleloopstechnologies.com301 → littleloops.techKeep registered for email + legal correspondence credibility.
little-loops.ai refreshPer §03: dark default, §05 tokens, ll: wordmark, §10 diagram restyle, §10 icons for ↗/copy/closeContent and voice stay — palette/type alignment plus diagram framing, per the decided before/after table.
docs.little-loops.aiSame tokens · follows system color-scheme preferenceFirst surface where both token sets ship in full.
OG / social images1200×630 · Paper field, mark left, Newsreader headline right, fig-numbered when the image is an exhibitPaper field family-wide — including for dark-default properties; the card renders in feeds, not in the reader's editor theme. Property eyebrows are accent-tinted; parent eyebrow is Ink Soft, and the parent eyebrow default text is the tagline (§08) — eyebrow or headline, never both.
GitHubOrg avatar = vertical lockup on Paper; repo card = ll: wordmark from the OG templateREADME badges use Blueprint. CI status badges use Pass / Signal.
Slides / docsPaper background, Archivo headings, ink tables, mark on title + closing onlyReusable deck template is a fast follow. Figure system is mandatory for exhibits (§09).
voice-lintShip §08's rules file as a little-loops harnessParses HTML; honors ignore_within. The brand's most on-brand artifact: a loop that grades copy against the voice spec — including this page.
token-lint v2Three checks on this file: literal px outside :root (exempt: the 720px breakpoint; clamp() bounds that appear verbatim in the §06 scale table); any calc() multiplying or dividing a type token; literal hex in inline SVG matching a token valueRuns on every version bump. The v3.0 lint passed a 9px calc and an unlisted clamp; v2 of the lint fails both by rule.
13 / governance

Who may change this, and how anyone knows.

A small founding team doesn't need a committee; it needs a changelog and a canonical URL, so that no person or agent ever builds from a stale copy. Three rules, guardrails, one open legal item, and a table.

AuthorityTokens, rules, marks, and assets change only by a version bump of this document, authored by the founders, with make-mark.py re-run so figures and files never diverge. No surface may introduce a value or exception ad hoc — file an issue against the kit; the next version adopts it or names why not. Exemptions exist only where this document states them; an exemption known to a founder but absent from the kit is a defect, not a policy.
VersioningMajor versions change tokens or rules (breaking for built surfaces); minor versions add without changing. Every version is dated in full ISO (YYYY-MM-DD) — v3.0's month-only dates could not order two versions shipped in the same month, which is the one thing a changelog is for. Agents must check the version line before building.
Canonical copyThis document lives at littleloops.tech/brand and in the little-loops repo at /brand/kit.html, beside /brand/assets and the generator — the repo copy is the source of truth; the URL serves it. Any other copy is a cache.

Naming & clearance guardrails — all three marks, not just the next one

FitA product name passes voice-lint, sits comfortably in the wind/run/loop/machine lexicon, and survives being said aloud on a sales call. Two syllables preferred, three maximum.
ClearanceScreened against USPTO and common-law use in developer tooling, with the .com or a credible domain in hand before announcement. v3.0 applied this only to the unnamed product; it now covers every mark the family uses — “Little Loops,” “little-loops,” and the ll: treatment included.
Open legal itemA same-name operation exists at littleloops.org describing itself as tech and software consulting — adjacent services, near-identical name, one TLD over. Seniority, registration status, and actual overlap are unverified; a real USPTO and common-law screen on “Little Loops” is required before littleloops.tech launches and before any registration filing. This item blocks the parent-site launch and is tracked here until it is resolved and this row is versioned out.

The decision record — why, not just when

The changelog records when a thing changed; this table records why it is what it is, so a direction already ruled out cannot return as a fresh idea. §08's rejected-candidates table did this first, for taglines; this generalizes it. Started v4.8, folded from the brand-kit-synth prototype's provenance section. Rows marked reconstructed state the reasoning as read back from the system, because it was never minuted at the time — an honest label beats a confident one, and a future version may replace a reconstruction with the real ruling.

DecisionRuling
Warm paper & ink, near-monochrome parentReconstructed. The instruction-manual register: the brand's conceptual language is the mechanical toy (§01), and a manual is printed ink on warm stock. Pure white and pure black are banned because no manual ever shipped on either; the warmth invariant (§05) is this decision restated for dark mode.
Blueprint #2741D6 for the OSS accentReconstructed. The name is the reasoning: a blueprint is the drawing a machine is built from, which is what little-loops hands an agent. The specific hue is bound by the §04 matrix (AA on Paper and Paper Deep) and by --d-oss passing on Ink — a replacement must clear the same rows, which is the only test that matters now.
Verdigris held provisionalDecided, §04. Reserved for the product and revisited at naming — an accent chosen before its property has a name would be a decision made on no information.
Newsreader / Archivo / JetBrains MonoDecided, v4.10. Three voices, one hand (§06): a text serif carries the poetic beat, Archivo's geometry matches the wordmark's weight, and the Mono is the machine speaking for itself. The serif seat was Fraunces from v3.0 (reconstructed reasoning, never minuted); v4.10 reseats it with Newsreader, taken from the synth prototype's pairing stage — Fraunces's italic at the scale's light weights turns calligraphic and fights the kit's engineered register, where Newsreader's italic stays calm and editorial. All three SIL OFL — the family's faces must be free to travel with an open-source flagship.
Hand-picked scales over ratio-derivedDecided, v4.8. The synth prototype derives its scales from generators (base × ratio); adopting that here was considered and rejected. Retrofitting derived values changes every spacing and type token — a breaking bump for surfaces already built — for zero visual gain, and the lints already govern additions more strictly than a formula would. The idea survives as the §06 rationale note; the values stand.
Dark islands by explicit tokens, not a role remapDecided, v4.8. A .dk class remapping the role layer to dark values — the mirror of .lt — was considered for fig. 10 and refused: every existing dark exhibit already carries explicit --d-* values, and two mechanisms doing one job is how contradictions ship. The screen follows the pattern the darkpanel set.

Changelog

VersionDateChanges
v4.162026-08-31The lockup's internal gap becomes part of the artwork's geometry. v4.13 founded the gap on the ink and named it --s4; v4.15 carried that to the header — and carried it as an absolute 16px, which was the last dimension in the lockup still pinned while everything around it scaled. At fig. 01's native 58px render, 16px runs 43% of the mark's ink height; at the header's 34.4px it ran 72%, and the navbar gap read visibly wider than the artwork it abbreviates — the emitted lockup-ink.svg, which scales its internal 16px like any other dimension, already disagreed with the hand-built brandline at every size but native. The ruling: the internal gap is --s4 at the lockup's native scale, and it scales with the render like the mark, the type, and the clearspace table. The header's ink-to-text is now 16 × 34.4/58 = 9.5px, its flex gap calc(--s4 × .593 − 7px) = 2.5px after the frame's padding is given back — the token stays in the expression, so a change to --s4 still propagates. fig. 01 is untouched: at native scale the factor is 1. mark-data.json's gap_token note now states the scaling rule. The .593 factor is the header's render ratio (34.4/58) and its equality with the subline's .593em tracking (v4.12) is coincidence, recorded here so nobody unifies them into one constant.
v4.152026-08-31The header brandline joins the ink rules, closing the loose end v4.13 recorded. Both rulings now bind it: the gap is ink-to-text --s4 — the frame's 7px of transparent right padding at this render is given back with a solved calc(), so the visible mark-to-text distance drops from ~23px to 16px — and the mark's ink height equals the brandline's text ink height, computed from the same Archivo metrics as v4.14 but in CSS line-box terms, since the header is HTML, not emitted SVG: cap top of the 13px/1.25 line to the 10px line's baseline is 22.3px of ink, so the frame is 38.9×34.4, derived, never declared. The old 38×34 was close by luck and wrong twice over — its aspect (1.118) didn't even match the artwork's (1.131), a pre-v4.9 remnant sized against the retired stroke mark's frame. Closed with it: the header comment block still described that retired mark — "viewBox 70 units tall, loop 27.2px, clearspace 13.6px" — numbers no asset has carried since the mark was replaced; the comment now states the current geometry and derives it. The brandline's type treatment (label register, 800/.14em over the solved .086em subline) is untouched: the header is the lockup's small-size variant, not a scaled copy — a strict scale-down would put the subline below the --t-micro floor, which is why the variant exists.
v4.142026-08-31The mark's size in the lockup is re-founded on the ink, completing what v4.13 started for the gap. The mark's frame height had been a declared 48px, which put its ink at ~31px — between the wordmark's cap height (~17px) and the text block's ink height (~38px), aligned to neither datum: an optical size that was an accident of the artwork's frame padding, chosen by nobody. The ruling: the mark's ink height equals the text block's ink height — cap top of LITTLE LOOPS down to the subline's alphabetic baseline — and their ink tops align. Solved, not centered. make-mark.py derives everything from the webfont's own vertical metrics (Archivo cap height 0.686em, ascender 0.878em, hhea and typo agreeing) and the frozen curve's bbox: text ink 37.61px → frame height 58px, derived, never declared; the wordmark's hanging y is placed so both inks top-align, and both land at 10.98px with bottoms 0.02px apart. mark-data.json records the rule and the metrics under the lockup key; fig. 01's stand-in takes the artwork's own render size (65.6×58) and its gap solve is re-derived for the new scale (the frame's right padding grows to 11.8px with it). The curve, the clearspace table, and every non-lockup asset are untouched. The pattern this closes is now three-for-three: weight, gap, and size were each declared against a convenient box — the font's weight number, the frame's edge, the frame's height — and each is re-founded on what the eye actually measures. A lockup dimension that cannot name its datum is a defect.
v4.132026-08-31The lockup's internal gap is re-founded on the ink. The mark's frozen artwork carries transparent frame right of its ink — bbox x-max 241.02 in a 294-unit viewBox, 9.7px at fig. 01's render — and the gap had always been measured from the frame edge, so the declared --s5 read as ~34px of visible space: a token wearing a third more width than its name. The ruling: the lockup's internal gap is ink-to-text, and it is --s4 (16px). make-mark.py now places the wordmark from the ink edge (x1 of the path bbox, scaled to render height) plus the gap; fig. 01's schematic stand-in gives the frame's 9.7px back with a solved calc(), derivation in the comment beside it, the same shape as the subline solves. lockup-ink/paper.svg and mark-data.json re-emitted; canvas narrows with the move. The frame itself is untouched — it is part of the frozen artwork and the clearspace table still keys off it. One loose end recorded rather than hidden: the header brandline's gap, --s4 from the frame edge since v4.3, reads as ~23px ink-to-text at its 34px render under this ruling — it stands unchanged in this version, and this row is the record that it runs looser than the artwork it abbreviates, so any future tightening is a decision, not drift discovered late.
v4.122026-08-31The lockup's two lines are balanced: TECHNOLOGIES, LLC now runs exactly the width of LITTLE LOOPS, its tracking solved rather than picked — the treatment the header brandline has carried since v4.3, applied at last to the lockup itself. The solution: natural_s + 16·ls = natural_w + 11·(.10em), Archivo 600 at --t-micro against 700 at --t-h, computed from the webfont's own advance widths; ls = .593em, and both visible runs land on the same 198.74px. The old .3em was a picked value from the two-line era, sized against a LOOPS line that no longer exists — v4.11 moved the wordmark to one line and left the subline tracked for the layout it had left behind. .wordmark small and make-mark.py's SUB_LS both carry the solved value with the derivation in a comment beside each, the same shape as the header's; lockup-ink/paper.svg and mark-data.json are re-emitted. One rule implied since v4.3 is now stated: a lockup subline's tracking is always solved against the line above it — when either line's text, face, weight, or tracking changes, the subline's spacing is re-derived, never inherited.
v4.112026-08-31The wordmark is retuned and reset on one line. Two changes, one ruling. First, weight: Archivo 900 drops to 700, and the tracking widens from +0.06em to +0.10em to hold the engineered register at the lower volume — beside the v4.10 Newsreader display, the Black cut read as blocky shout rather than machined plate, and the §06 heading range (Archivo 600–900) already contains the new weight, so no scale row moves. Second, layout: LITTLE LOOPS stands on a single line with TECHNOLOGIES, LLC beneath it — the stacked two-line wordmark survives nowhere; the header brandline had been single-line since v4.3, so fig. 01 and the emitted artwork now agree with the header instead of contradicting it. make-mark.py carries both: L_WEIGHT 900→700, L_LS .06em→.10em, the two-line layout math collapses to one line with the text block vertically centered against the mark, and the canvas allowance widens for the longer run. lockup-ink/paper.svg and mark-data.json's lockup key are re-emitted; the mark's geometry, the clearspace table, and every other asset are untouched — the curve is frozen and this change never touches it. Heavier faces were considered for the seat itself — Barlow 800, Hanken Grotesk 900, JetBrains Mono 700, the prototype's Space Grotesk — and set aside: the defect was the 900 cut's volume, not Archivo, and one sans doing every structural job is worth more than a second family's flavor.
v4.102026-08-31The display serif is reseated: Fraunces gives its chair to Newsreader, taken from the synth prototype's font-pairing stage (output/brand-kit-synth-20260831T051836Z.html) — the first of its values to cross, where v4.8 ruled that only its structural ideas do; a ruling scoped to scales and tokens does not bind a typeface judgment. The reason is the italic: the §06 emphasis weights sit at 330–340, and Fraunces's italic at light weights and display optical sizes turns calligraphic — swashy terminals, an unstable rhythm — which fights the engineered register the grid, the mono, and the wordmark all speak. Newsreader's italic at the same weights stays calm and editorial; its roman takes the same seat without ceremony. Nothing else moves: Archivo and JetBrains Mono keep their voices, every size, weight, and tracking value in the §06 scale stands, and the 28px boundary, the italic budget, and the U+2113 glyph rule carry over with only their face renamed. The webfont request swaps families and stays lean — Newsreader 300–450 with italics over its 6–72 optical range, against Fraunces's 9–144. The §13 provenance row for the type trio is rewritten from reconstructed to decided: the trio's reasoning was read back from the system in v4.8; the serif's seat now has a minuted ruling, which is the upgrade that table was built to receive. Space Grotesk was considered alongside — the prototype pairs it with Newsreader — and refused: the italics were the defect, not the sans, and Archivo carries the wordmark's 900-weight geometry, which Space Grotesk does not offer.
v4.92026-08-31The mark is replaced. The double-loop mark was a single unbroken cursive stroke — an open, stroked polyline, stroke-width and stroke-linecap carrying the letterform. It is superseded by a new mark: two interlocking loops rendered as one solid filled shape (fill-rule nonzero, no dot, no stroke). The old mark's canonical data and every asset it emitted are archived under archive/ll-mark/, unchanged, rather than deleted — its own history (the v3.0 bias parameter, the v4.0 cycloid regression, the v4.1 fix) documents that mark, not this one. canon/mark-path.txt now holds the new curve; make-mark.py is reworked from a stroke-model to a fill-model generator — bbox math now scans path coordinates by regex instead of parsing a straight-line-only polyline, so it tolerates the new curve's Béziers and closed subpaths, and every emitted asset (mark-*.svg, favicon-*.svg, lockup-*.svg) swaps stroke for fill. The favicon showcase (fig. 03) now reuses the one mark path scaled down rather than a separate favicon-only glyph, which retires along with the stroke it existed to thicken. The mark's aspect ratio changes with it — roughly 1.94:1 (wide) to roughly 1.13:1 (near-square) — so every instance's width/height and the §02 clearspace table (loop height, now the curve's bbox height rather than its stroke-excluded polyline height) are recomputed from the new geometry. The cover's hero animation changes with the render model: a stroke path can be "drawn on" with stroke-dashoffset and pathLength; a filled shape cannot, so the reveal is now a fade + scale-in, and the cover's literal duplicate path (kept only for pathLength on a light-DOM copy) is gone — every instance, cover included, is now a plain <use> of the one #llt-mark def.
v4.82026-08-31Four additions folded from the brand-kit-synth prototype (output/brand-kit-synth-20260831T051836Z.html) — a specimen generator, not a family surface: its structural ideas cross; its values do not. First, the composed screen: §12 opens with fig. 10, a docs settings panel built end to end from §04–§10 tokens, dark because the flagship is, followed by a table naming where each subsystem appears — the integration test every prior exhibit only unit-tested. Second, form controls: §07 gains the input, label, switch, and primary-button spec. The §04 matrix had carried filled-button rows (Paper on Blueprint; Ink on --d-oss) for a component that did not exist, and the universal focus ruling named inputs no spec had drawn — both dangling ends now terminate in components. The switch stands its hit box on the --touch floor with the track and knob drawn inside from spacing tokens, and one motion ruling ships with it: knob travel is an activation transition, not a hover one — §09 binds hover, and hover still moves nothing. Third, scale rationale: the §06 note records that both scales are hand-picked and that a generator ratio was considered and rejected (retrofitting derived values is a breaking bump for zero visual gain); rem equivalents join the type table as builder conveniences, px canonical. Fourth, the §13 decision record generalizes §08's rejected-candidates pattern to design decisions, with reconstructed reasoning labeled as such. Hygiene closed with it: the hover ease was the one literal in every transition — --hover-ease tokenizes the keyword, rendering unchanged; and the cover's supersedes line had read v4.4 since that version shipped, three versions stale against the footer, which was correct throughout — the cover now reads v4.7, and both lines move together or the mismatch is a defect.
v4.72026-08-24Two issues closed. First: §02 banned setting the wordmark in anything but "the production lockup artwork," and §12 required the tagline sit under the lockup, but no lockup artwork shipped in assets/ — only the mark — leaving a downstream parent nothing to copy without composing a wordmark the kit itself forbade. make-mark.py now emits lockup-ink.svg / lockup-paper.svg: the mark plus wordmark, set from the §06/§08 type tokens (font, weight, tracking, line-height, the --s5 internal gap), with the layout computed from those tokens rather than eyeballed and recorded in mark-data.json's new lockup key, the way the clearspace table already documents the mark. The wordmark is <text>, not outlined — consistent with how this kit's own header and fig. 01 already render it — so a surface with the shared type system loaded (§01) renders it correctly without a font negotiation. Second: the parent-we voice-lint rule banned every "we" on the parent with no allowance, while the §08 prose only asked marketing copy to avoid a first-person plural that implies a floor of employees that doesn't exist — different readings for copy that names the founders. Little Loops Technologies has multiple founders, so a founder-scoped "we" is honest, but a regex can't distinguish it from a headcount-inflating one; parent-we is now severity: warn, the same treatment unlock-metaphor and handoff-spaced already get, so a person rules on scope instead of the lint ruling for them. Closed with it: §13 wrongly called this "a one-founder company" — corrected to name the founders, plural, throughout. And a dangling cross-reference from v4.6 is fixed — the parent-row citation named a §14 that has never existed in this document; it meant §12.
v4.62026-08-24The parent flips to dark default. The registry ran light-only from the kit's first publication — one page doesn't need a toggle, the ruling said — and the reasoning was right about the page and wrong about the visitor: the parent is the front door of the family, and the audience §05 was built for arrives from dark editors and dark terminals, so a registry that meets them in light meets them in the wrong register. Every parent surface now ships both modes — the registry and the legal sub-paths alike — dark as the default, light as the persisted alternative, with a reader-run toggle in the footer beside the legal nav: icon-only, the §10 sun and moon, the visible glyph naming the mode it switches to, choice applied before first paint, never system-followed, print returns to light — the v4.2 mechanism, carried over unchanged. One new ruling ships with the flip, because the parent's tags could not cross as-is: the Blueprint and Verdigris chip fills sit at 2.5:1 and 2.9:1 against Ink, under the 3:1 non-text minimum, and Paper text on the dark counterparts computes to 2.4:1 and 2.0:1, worse — so the chip inverts, --d-oss and --d-product fills with Ink text at 6.7:1 and 8.0:1, the same inversion §05 already mandates for text and focus. Two §04 rows record the pairs. The color-scheme meta turns dark light and theme-color carries both values. The §05 mode card and the §12 parent row state the ruling; /brand's row no longer claims the only dark surface on the parent domain.
v4.52026-08-23The favicon becomes the name. v4.1 restored the single-loop glyph as its own frozen artwork, but a lone l was never the name: the brand is the double loop, and a tab that reads as a solitary l reads as a letter the company does not have. The favicon glyph is now the frozen mark itself, uniformly scaled into the 32×32 box — scale is one of the parameters the design-freeze already allows — and canon/favicon-path.txt retires with the separate artwork it froze: one canonical curve, and the custodian derives the favicon from it at emit time, so §02's claim that every asset comes from the frozen curve is now literally true. The stroke drops from 4.5 to 3.0 to hold the quarter-of-loop-height ratio the approved single-loop favicon carried (4.5 of 18 then, 3.0 of 12 now): at the smaller loop, 4.5 closed both counters at 16px, caught by §02's rendered-raster check. mark-ink and mark-paper are byte-identical; the clearspace table is unchanged; §02 is retitled — the glyph is the mark wound small, not a sibling — and its don'ts and fig. 03's caption are reworded to match. Colorways, the 24px floor, and the §12 delivery rule stand.
v4.42026-08-23The tagline is decided and specified. Parent: “Order from the machine.” Flagship: “Noise in. Order out.” The product line is deferred to its naming (§13), because its register leads with an outcome and there is no buyer yet to name one for. §08 gains the whole ruling — three specimens, the placement table, and the rejected candidates with their reasons, so a line already ruled out cannot return as a fresh idea. Three rules ship with it. The tagline at lockup size is Archivo at --t-caption, never Fraunces, which the §06 28px floor already forbids. The line is banned as the sole text of a link or button, where “Order from…” reads as a purchase instruction — adjacent to the name that reading collapses, alone in a button it does not. And the poetic budget is one line per view: the hero display line and the tagline never share a viewport, so this document carries the hero on the cover and the tagline in the footer, which is now its single use position on the page — every other appearance in §08 is a specimen, a mention under the §04 exemption. The rejected front-runner is recorded rather than erased: “Determinism in a non-deterministic world” is kept as an about-page thesis and refused as a tagline, because the same prompt does not return the same output and §13 binds this kit to claims it can keep. Its spelling is ruled now rather than later — nondeterministic, closed, no hyphen, the same class of call as handoff. §01 records that taglines are assigned, not improvised; §12 puts the line under the parent lockup and in the parent OG eyebrow. The footer sign-off changes from “Small machines, carefully made.” to the tagline; the hero line is unchanged and keeps the cover. Closed with it, by markup rather than by exemption: the §06 and §08 code exhibits were mono-styled divs, which is none of the three containers their own ignore_within names, so every pattern the voice-lint spec quotes — its we, its unlock, its hyphenated handoff — sat in plain prose as far as the linter could see, and the page failed the lint it defines while claiming to pass it. Both listings now carry a code element and are covered by the rules file untouched: no fourth container, no style class exempted, no rule relaxed. Exempting .s-mono was considered and refused — it would exempt a presentation class, making any prose set in mono invisible to the lint, which is the page-level exemption §08 bans wearing a different hat. One CSS line resets the browser default inside the exhibits; they render unchanged. The §08 rule-note now states the markup obligation the mechanism always implied: a listing styled as code but not marked as code is a defect in the page, not a gap in the lint.
v4.32026-08-23Dark becomes this page's default mode, and the header toggle goes icon-only. The kit's readers live in dark editors — §05's own premise — so the working document now opens as its audience does: the first-paint script applies dark when no stored choice exists, while stored choice still wins, still persists, and is still never system-followed; print still returns to light, because ink prints on stock (§11). The toggle's semantics stand; its text label becomes two icons — sun and moon — and the visible glyph still names the mode the reader switches to. Sun and moon join the §10 set under its growth rule, drawn on the same grid. The §05 mode card and the §12 surfaces row restate the ruling; light stays fully specified and renders unchanged, and the .lt exhibits still pin it in both themes. The header brandline's subline is tracked to fit: letter-spacing .086em, solved — not picked — so TECHNOLOGIES, LLC runs exactly the width of the LITTLE LOOPS line above it; the lockup's two lines now start and end together, and the mark-to-text gap in the same lockup tightens from --s5 to --s4. And the header itself is rebuilt in two rows. v3.0's single row held all thirteen nav links between the lockup and the toggle and wrapped them midair at every desktop width — a sticky bar two links tall over an offset sized for one, so the page buried its own targets again: the very defect the offset was written to close. Row one is now the lockup and the toggle; row two is the nav, the column's full width, its links standing on the --touch floor by min-height rather than padding, so every target is exactly 44px. The offset is the header's token sum at its tallest state plus --s5 (§11), and widths where the nav fits one row take the difference as clearance. Under the breakpoint the wrapped nav would stand several rows tall, so the header leaves sticky position and joins the document flow: the offset rule binds sticky headers, and an anchor cannot bury under a bar that scrolls away. And the cover's background loop is anchored vertically as it already was horizontally. Its box top stood at --s6 — inside the cover's own top padding, sixty-four pixels above the content line — so the loop's tops floated over the kicker while only its bottom stroke reached the heading; the box top now stands on the same --s9 the cover pads by, and the loop, taller than the display lines, brackets them and centers on the heading.
v4.22026-08-23Reader-run dark theme for this page, behind a header toggle. Light stays the default and renders byte-identical: page chrome now reads a role layer (--surface, --surface-deep, --surface-lift, --text, --text-soft, --border, --rule, --state-ok, --state-err) that maps to the §05 dark tokens under [data-theme=dark]; every pair the dark theme produces already has a §04/§05 matrix row. The remap assigns custom properties only — never background: or color: — so the surface rule's grep (background:var(--ink) ⇒ .dark) holds in both themes; ink islands gain a --d-line hairline under the dark theme to keep reading as exhibits. Exhibits that demonstrate light-mode rendering (figs. 01, 03, 04, 05, 07 and the §07 language cards) pin it via .lt, which resets the role layer to light values inside the pinned surface. Kit's own mode ruling added to the §05 mode card; littleloops.tech/brand added to the §12 surfaces table. The page's first script: choice applied before first paint, persisted, never system-followed; print returns to light.
v4.12026-08-21Mark geometry regression fixed. v4.0’s generator re-derived the curve from a prolate cycloid and shipped wide, round, symmetric loops in place of the approved tall, right-leaning cursive ll — mathematically tidier, no longer a letterform. The approved curve is restored as canonical and declared design-frozen, stored as sampled path data in /brand/canon; make-mark.py is rewritten as custodian (emits sizes, strokes, colorways, favicon, clearspace table from the frozen curve; never re-derives geometry) and a usage rule now bans regeneration outright. Favicon glyph likewise restored to the approved single-loop cursive ℓ. All assets re-emitted; clearspace table unchanged (identical 56⁄70 viewBox ratio); 16px favicon legibility re-verified against a rendered raster. Bias remains deleted per the v4.0 ruling. Same-day revision: the symbol/use definition clipped every mark instance slightly at the bottom-right (a symbol instantiates a nested viewport at 0,0 in user space, offsetting the −7 −7 viewBox by +7,+7); replaced with bare path defs, which draw in the host svg’s own coordinates. Every other v4.0 change stands.
v4.02026-08-21Assets shipped: make-mark.py written and run; mark, favicon, and data files emitted to /brand/assets; every figure in this document renders from the generator's path via a single symbol definition. Bias parameter reverted — four parameters, symmetric mark, favicon and motif consistent with it. Clearspace datum defined (path y-extent, stroke excluded); per-size table generator-emitted; v3.0's three conflicting worked examples retired. Surface rule for dark: Ink background ⇒ .dark, closing invisible selection in code blocks; focus made universal via :focus-visible. Token-lint v2: clamp bounds must appear in the §06 scale (the unlisted h2 clamp is now listed), calc() on type tokens banned (the 9px sublines are now --t-micro), hex banned from inline SVG (everything is currentColor). Voice-lint v4: ignore_within puts use/mention in the machine; hand-off split into an auto-fixable hyphen rule and an honest warn; this page passes its own lint by mechanism. ll: face contradiction resolved (JetBrains Mono 700, §03 rules; §06 lends size only). Icons currentColor, set grown to eight for the live site's real needs, dark specimen shown. Favicon colorways made deliverable (adaptive SVG + static fallback) and property-differentiated. Sticky-header anchor offset implemented and specified. Fonts subset to used axes; preconnect corrected. Kit page carries its own meta/OG. Specimen exemption rewritten to cover what the kit actually exhibits. Clearance guardrail extended to all marks; littleloops.org collision logged as a blocking legal item. Live-site quotes verbatim with excerpts labeled; the clipped §08 sentence restored in full. U+2113 confined to verified faces. Full ISO dates from this version on. Superseded — the generator’s cycloid re-derivation replaced the approved mark geometry; fixed in v4.1.
v3.02026-08Every CSS value tokenized (two loopholes found in review); §03 flagship identity and ll: wordmark; dark focus/selection partially implemented; clearspace amended to ½ loop height (datum left undefined); voice-lint with scope/severity/allow (failed on its own page); exhibit exemption named (scoped too narrowly); mark/motif boundary; bias parameter added (reverted in v4.0); iconography drawn (light-mode hex); governance and naming guardrails. Superseded — ten defects found in review.
v2.02026-08Computed contrast matrices; semantic Pass/Signal layer; dark token set; interaction-state spec; layout/motion tokens; favicon glyph; pull-quote rule; voice lint list; OSS-led hierarchy declared. Superseded — ten defects found in review.
v1.02026Initial system. Superseded — failed its own rules three ways.