Lacuna Labs · Pan-African economic platform

Baobab

Visual Canon · v1.0 · 2026-05-12
The wordmark
Baobab wordmark, Fraunces italic 600, forest
The B · standalone
B monogram, Fraunces italic 600, bark

The wordmark is the identity. The substrate is cream paper. The mark holds its terminals. The platform serves the operator's commercial agency, and beauty is part of the contract.

Status
Canon. Load-bearing. Walk-back-registered.
Supersedes
Pre-canon design memos at research/2026-05-12-redesign-*.md (now informational).
Successor of
None. Baobab v1.0 is the first canon.
Companion canon
lacuna-canon-v0.4.3 (LLM routing protocol); lacuna-positioning-principle (operator memory).
Merkle anchor
shasum -a 256 baobab-visual-canon-v1.0.pdf
Authored by
PM (Claude session) synthesizing four parallel section leads (typography, color, layout/motion, voice/icon) on 2026-05-12.

Canon · 01The B is the trademark

The B is the mark. An adinkra-style geometric crest in bark, derived from Canva design DAHJfCx22YE. It carries Baobab the way Sakura’s blossom carries Curator. “That B means Baobab.”

1.0 Trademark notice

Baobab and the adinkra B mark are trademarks of Lacuna Labs, pending USPTO registration. The mark, the wordmark, and the B+wordmark lockup are reserved use; their appearance outside Baobab’s own surfaces or operator-authorized contexts is not permitted. The favicon set ships as a transparent SVG (vector, infinite scale) plus PNG raster fallbacks (16, 32, 180, 192, 512). Co-marketing surfaces require explicit Lacuna Labs sign-off.

The trademark
B monogram, Fraunces italic 600, bark
Paired with the wordmark
B Baobab wordmark

The B leads. The wordmark follows. At the top of every Baobab surface this is the lockup — B as the trademark on the left, "Baobab" on the right.

The B also stands alone where the word doesn’t fit — favicons, app icons, social avatars, in-product chrome where the wordmark is too wide.

The wordmark also stands alone where the trademark is implicit — running mast on internal-only surfaces, footer attributions, in-prose mentions.

1.1 The wordmark, fully specified

PropertyValue
FamilyFraunces (variable)
Style / weightItalic 600
opsz axisBound to render size: 9 / 24 / 72 / 96 / 144 (see 1.3)
SOFT axis0. Terminals stay firm. Never softened.
Tracking-0.018em display, -0.01em masthead, 0 below 24px
Default color--forest #2D5016 on cream
Identity-warm color--bark #6B4423 on masthead and warm contexts
Photographic substrate--ink #1A1A1A
Inverted (dark substrate)--ink-on-dark #F1ECDE
Minimum width88px
Clear spaceEqual to the cap-height of the lowercase “b” on all four sides
Minimum contrast4.5:1 against the mean luminance of any substrate
BaselineOptical baseline of the italic “b”-stem foot — never bounding-box bottom

1.2 The B — where and how it lives

What the B never does

1.3 Optical-size response

Render sizeopszTracking
14–18px (inline)90
19–28px (in-flow)24-0.005em
29–56px (masthead)72-0.01em
≥ 57px (hero / share)96-0.018em
≥ 96px (canvas / billboard)144-0.02em

1.4 What the wordmark never does

Canon · 02Type system

Three families plus one transitional fallback. All OFL-licensed. Self-hostable. Loaded with the variable axes the canon uses, no more.

FamilyRoleAxes
FrauncesDisplay, headlines, wordmark, emphasis, drop caps.opsz (9–144), wght (100–900), ital. SOFT always 0.
Crimson ProLong-form body, reading surfaces, captions, pull-quotes, LLM voice on dark substrate (see 2.5).wght (200–900), ital.
JetBrains MonoData, ticker, code, metadata, attribution, eyebrows, operator-typed input.wght (100–800). Italic loaded but never used in product.
InterUI-chrome fallback only where serif is too soft below 14px (compact form fields, lang-picker dropdown options). Transitional concession.wght (100–900).

2.1 Hosting

2.2 Type scale

Mobile baseline (≤ 639px). Two breakpoint bumps. Body and metadata sizes do not grow on larger viewports — legibility doesn’t get bigger because the screen does.

TokenFamilyWeightMobileTabletDesktopItalic
--type-mastheadFraunces opsz 96600 ital30/3240/4256/56locked
--type-display-xlFraunces opsz 7260034/3848/5264/64lead story
--type-displayFraunces opsz 4860026/3036/4044/46roman default
--type-headlineFraunces opsz 3660022/2626/3030/34lead only
--type-subheadFraunces opsz 2450018/2420/2622/28optional
--type-bodyCrimson Pro40017/2817/2818/30inline em
--type-body-emphasisCrimson Pro50019/3019/3021/32pull-quote
--type-metadataJetBrains Mono50011/1611/1611/16never
--type-captionCrimson Pro40013/1813/1813/18italic default
--type-codeJetBrains Mono40013/2013/2013.5/20never
--type-data-tabularJetBrains Mono50013/1813/1814/20never
--type-tickerJetBrains Mono60012/1812/1812/18never
--type-attributionJetBrains Mono5009.5/12 ALL-CAPS9.5/129.5/12never

2.3 Italic policy

Italic is allowed in five places only:

Italic is forbidden in: UI chrome (buttons, tabs, nav, breadcrumbs, form labels, inputs, dropdowns, toasts, tooltips); metadata, byline, timestamp, attribution, eyebrow; all data surfaces (ticker, tables, prices, counters, wallet balances); code blocks; the mono family in any product context; all-caps anything.

2.4 Numerals — scope discipline

Tabular figures with slashed zero on data surfaces. Proportional figures everywhere else.

/* Data surfaces only */
.ticker, .market-tile, .wallet, .tabular, .data {
  font-variant-numeric: tabular-nums slashed-zero;
  font-feature-settings: "tnum" 1, "zero" 1;
}

/* Body, headlines, captions: proportional (default) */

Lining numerals in flowing prose break the reading rhythm. font-variant-numeric is set on the data token, not inherited globally.

2.5 The Baobab LLM speaks in serif — the LLM voice rule

When the Baobab LLM renders its own speech, the type is serif. Crimson Pro italic 400 on the dark --ink substrate, color --ink-on-dark #F1ECDE.

The conversational overlay is the one dark surface in the system. Inside it: the operator’s typed input renders in JetBrains Mono (operator voice = typing, characters in a fixed pitch); system metadata (timestamps, handles, tool calls) renders in JetBrains Mono uppercase letter-spaced; the LLM’s own utterances render in Crimson Pro italic — the literary register, the broker’s memo, the considered reply.

ElementFamilyStyleColor
LLM utteranceCrimson Proitalic 400, 16/24--ink-on-dark
Operator inputJetBrains Monoregular 400, 14/22--ink-on-dark
System metadataJetBrains Mono500, 10/14 letter-spaced 0.08em ALL-CAPS--ink-on-dark-mute
Tool call / inline citationJetBrains Mono500, 11/14--ink-on-dark-mute

2.6 Type anti-patterns

Canon · 03Color and surfaces

The substrate is warm cream paper. Six surfaces, seven inks, fifteen accents, eight state tokens, four rules. Each accent has one job; if you cannot decide between two accents, the job decides.

3.1 Surfaces

TokenHexRole
--surface-paper#FDFCF7Default page substrate. The cream. The brand.
--surface-soft#FAF6ECCard body, table-row hover, sidebar fill.
--surface-warm#F6F1E6Section bands. Eyebrow strips.
--surface-elevated#FFFFFFReserved: modal interior, popover body, image-card mat. Never page background.
--surface-overlayrgba(253,252,247,0.78)Frost scrim. Translucent paper, never translucent ink.
--surface-ink#1A1A1ADark inverted. LLM overlay only. One dark moment.

3.2 Inks

TokenHexRole
--ink#1A1A1AHeadlines, body emphasis. Not #000.
--ink-soft#3A3A3ABody text default.
--ink-mute#6E6A60Metadata, byline, timestamp.
--ink-faint#9A9588Disabled state. Affordance for disabled only — fails AA on every surface.
--ink-on-dark#F1ECDEBody on the Baobab LLM overlay. Cream-tinted, not pure white.
--ink-on-dark-mute#C9C2B0Metadata on the Baobab LLM overlay.
--ink-inverse#FDFCF7Type on saturated accent fills.

3.3 Accents

TokenHexJob
--forest#2D5016Action. CTAs, links, active-tab, focus rings.
--forest-deep#1F3A0FHover/pressed forest.
--bark#6B4423Identity. Wordmark, masthead, the color that says “this is Baobab.”
--bark-deep#4A2E16Deep bark headings; the hex behind every warm-tinted shadow alpha.
--bark-soft#C9A87CAdinkra glyph in empty states.
--terracotta#B5503EDown / alert. Deliberately not red. Red is alarm; terracotta is signal.
--gold#C9A24FUp / earned / winning. Price up, audit-tick, adinkra on dark.
--sage#8FA68EAmbient. Neutral metadata pills, peace-state indicators, selection background.

3.4 The cream substrate is the brand

3.5 Accent application rules

3.6 Cleared contrast pairings (excerpt)

ForegroundBackgroundRatioLevel
--ink--surface-paper~16.1AAA
--ink-soft--surface-paper~11.3AAA
--ink-mute--surface-paper~5.0AA
--forest--surface-paper~9.0AAA
--bark--surface-paper~6.4AA
--terracotta--surface-paper~4.5AA ≥14px
--ink-faint--surface-paper~2.6Below AA — disabled affordance only
--gold--surface-paper~2.2Below AA — never on type

3.7 Elevation

--shadow-1: 0 1px 2px rgba(74,46,22,.04), 0 2px 8px rgba(74,46,22,.04);
--shadow-2: 0 4px 14px rgba(74,46,22,.10), 0 2px 4px rgba(74,46,22,.05);
--shadow-3: 0 18px 48px rgba(74,46,22,.16), 0 6px 12px rgba(74,46,22,.08);
--shadow-3-dark: 0 18px 48px rgba(0,0,0,.55), 0 6px 12px rgba(0,0,0,.30);

The canon’s banking move: 1px --rule hairline preferred to shadow at rest in 80% of cases. Shadow wins only when an element is literally lifting off the page (hover, focus, drawer-in-transit), floating over cream (popovers), or seating itself on white (modal interiors).

Canon · 04Layout, spacing, and the grid

4.1 The grid

BreakpointRangeColumnsGutterGap
mobile≤639px116px--space-5 (20px)
tablet640–1023px224px--space-7 (32px)
desktop≥1024px324px--space-7 (32px)

Container max-width: 1080px. Centered. Three surfaces and three only break the container for full-bleed: the kente masthead, the hero block on landing, the ticker frame.

4.2 The 11-step spacing scale

TokenpxCanonical use
--space-00reset
--space-14tight inline; chip flex-gap
--space-28pill internal padding
--space-312button vertical; desktop tab padding
--space-416card internal padding mobile; mobile gutter
--space-520sibling stack default; mobile grid gap
--space-624section internal padding; desktop gutter
--space-732desktop grid gap; distinct content blocks
--space-840section margin only. Never sibling stack.
--space-956generous section break
--space-1080hero / page-top breathing

4.3 The four destinations

Read · Trade · Talk · Wallet. Locked. Atlas is a substrate, not a tab — appears inside Read (story-clusters), inside Trade (dealer-flow, corridors), inside Wallet (Sankey).

4.4 The masthead — stacking order locked

RowComponentDesktopMobile
1Kente hairline gradient (4–6px)full-bleedfull-bleed
2Wordmark left + meta + lang + sign-in + B monogram upper-right56px48px
3Ticker frame40px36px
4Tabs (Read · Trade · Talk · Wallet)48pxhidden (bottom-nav serves)
5Main content

4.5 Tap targets

Every actionable element has a minimum 44×44px tap target. Hard rule. touch-action: manipulation on every tap surface (cards, chips, tabs, pills, menu rows, buttons, links). This removes the 300ms tap delay and disables double-tap-to-zoom.

Canon · 05Motion and the seamless window pattern

5.1 The motion tokens

--ease-in:  cubic-bezier(0.32, 0.72, 0.2, 1);   /* every enter */
--ease-out: cubic-bezier(0.4, 0, 0.6, 1);       /* every exit */
--dur-in:    240ms;   /* overlay enter, drawer enter */
--dur-out:   180ms;   /* overlay exit, drawer exit */
--dur-cross: 160ms;   /* content swap inside same surface */

Two easings, three durations. No custom cubic-beziers outside this pair. No ease-in-out. No springs, no bouncing, no overshoot. Baobab is paper, not gummy. Hover transitions are 120ms; press states are 60ms scale(0.97).

5.2 Windows — the seamless overlay pattern

WindowDirectionDesktop widthMobile
Article readerright720pxbottom-sheet
Room overlaybottom720pxbottom-sheet
Account drawertop-right360pxbottom-sheet
Ask palettecenter fade-up640pxbottom-sheet
Atlas focusright1080pxfull-screen
Audio mini-playerbottom-pinned, persistent1080pxfull-width 64px

Backdrop: cream-paper frost (rgba(253,252,247,0.78) + blur(8px) saturate(140%)). Never a black scrim. Mobile uses solid cream at 0.92 instead of blur.

Stacking rule: replace, not stack. Three-deep is rejected. The audio mini-player is the one exception — it survives navigation across destinations.

5.3 Reduced motion is canon

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Surfaces remain functional. The audio mini-player still pins; it just does not slide. Color flashes on price ticks remain (200ms is not motion in the sense reduced-motion targets — the operator still needs to see the price moved).

Canon · 06Iconography — two systems, two jobs

6.1 Phosphor Regular — chrome only

Single SVG sprite. 16px in compact rows; 20px in default chrome; 24px in section openers. Regular weight only — not Thin, not Bold, not Light. Single-color always: --ink-soft at rest, --forest on hover and active, --ink-on-dark on dark substrates, --ink-faint for disabled. Never multi-color. Never gradient.

Phosphor lives at: search, close, settings, menu, expand, collapse, chevrons, sort arrows, kebab, hamburger, share, bookmark, upload, download, eye, copy, edit, trash, plus, minus, check, x, alert-triangle, info-circle, calendar, clock, link, paperclip.

6.2 Adinkra — identity and structure

12px (ticker provenance), 14px (eyebrow co-marks), 24–32px (avatar discs, station glyphs in Tune, ticker tile marks), 64px (empty states). Single-color, 1px stroke on cream. Default --bark; --forest on nav active; --gold on dark substrates. Single SVG sprite, 25–30 glyphs maximum.

6.3 The adinkra stance — canon position

Adinkra are named, sourced, and used as identity-bearing marks — never as decorative African pattern.

Every adinkra used in the system appears in the canon appendix table with: Twi name, one-line meaning, source citation (museum / archive / scholarly), and the Baobab surface it lives on. No mock adinkra. No flattening to pattern. No religious / funerary glyphs in commercial-transaction surfaces. The kente hairline carries any decorative-band role; adinkra carry meaning roles.

6.4 Iconography anti-patterns

Canon · 07Voice and copy

7.1 The register

7.2 Before / after — from real surfaces

SurfaceBefore (off-canon)After (canon)
Splash CTAGet Early Access!Sign in
Empty walletNo transactions yet 😢 Make your first move!No transactions yet. Your first deposit lands here.
Markets provenanceTrusted Source ✓Source: COCOBOD daily · attribution audit ok
News emptyDiscover the latest from across Africa!Pan-African channel. Today’s wires below.
Upload toastAwesome! Your file is uploading!Uploading. You can keep working.
Send confirmYou’re all set! Funds on their way!Sent. Settling in two to three minutes.
Fill rowCongrats on your fill! 🎉Filled. 0.5 MT sesame · Abuja · settled.

7.3 The scientific register

Canon · 08Photography and texture

8.1 Photography — the locked treatment

PropertyValue
Max widths760px article reader; 380px grid cell; 220px compact row.
Aspect ratios4:5 portrait; 16:9 landscape; 1:1 square in three-up grids only.
Border-radius4px. Never circular.
Ground1px --rule border on every photo. No drop shadow.
Color treatmentNone. No filter, no vignette, no duotone, no preset.
Caption typeJetBrains Mono 12/16, --ink-mute, letter-spaced 0.04em.
AttributionRequired. PHOTO · {source} in mono ALL-CAPS 0.06em, --space-2 below image.

8.2 Texture — two atmospheric treatments, no more

Treatment 1 — warm-tinted paper grain at 3% opacity over --surface-paper. SVG noise, biased toward bark, fixed-attachment. Sensed-not-seen at all zoom levels. Disabled under prefers-contrast: more.

Treatment 2 — kente hairline at the masthead top. Exactly one 4–6px band, full-bleed, gradient gold→forest→gold→bark→gold. The only kente in the system. Never repeated. Never on cards. Never on borders elsewhere.

8.3 Texture anti-patterns

Canon · 09Consolidated anti-patterns

What marks a bad Baobab implementation. Each item is a canon decision, not a preference. Reviewers reject on hit.

  1. Pure white as a page background.
  2. Pure black drop shadows on cream.
  3. Red for price-down or any down semantic.
  4. Theme-park African color clichés (sunset-orange, mustard-yellow brick-red).
  5. Purple gradients (the 2026 AI-design cliché).
  6. Gradient meshes.
  7. Three or more accent colors in a single composition.
  8. box-shadow on a flat at-rest card with no hover state.
  9. The system-blue focus ring.
  10. Skeuomorphic paper textures beyond the 3% noise treatment.
  11. Adinkra used as decoration (background pattern, repeating motif, watermark).
  12. Title Case marketing headlines.
  13. Drop shadows on text.
  14. “Trust us we’re for you” first-person platform voice.
  15. Loading spinners on every state change (use skeletons on --surface-soft).
  16. Modal dialogs that thank the operator.
  17. Identity-marker chiplets on every card (no “Black-Owned ✓” ribbons).
  18. Decorative photos in empty states.
  19. Persistent floating helper bubbles (the LLM helper, chat peek).
  20. Page-level slide transitions between Read / Trade / Talk / Wallet.
  21. Spring overshoot / bouncy easing.
  22. Modal stacks deeper than two visible overlays.
  23. Tap targets smaller than 44×44px.
  24. Animations longer than 320ms for page transitions.
  25. Raw pixel values in component CSS (except 1/2/4px hairlines).

Canon · 10Compliance — the grep-able checklist

The canon’s enforcement layer. Every item is mechanizable in CI.

10.1 Typography

  1. No font-family with Inter as the primary face for body / article / reader surfaces.
  2. No Arial, Helvetica, Helvetica Neue in any font stack.
  3. The string “Baobab” is the only spelling of the wordmark in source.
  4. The wordmark uses var(--font-head) + italic + 600.
  5. Data surfaces set font-variant-numeric: tabular-nums slashed-zero.
  6. Body / paragraph / heading selectors do not set tabular-nums.
  7. No text-shadow declaration anywhere.
  8. No background-clip: text.
  9. No italic on UI chrome (.button, .tab, .nav, .label, .ticker, .data).
  10. Favicon set ships both favicon-16.png (B alone) and favicon-32.png (full or B).

10.2 Color & surfaces

  1. No background: #fff on body / html / page-section selectors.
  2. No rgba(0, 0, 0, in box-shadow on cream substrates.
  3. No color: red, #ff0000, crimson, firebrick anywhere.
  4. No color: #000 or background: #000 on operator-facing surfaces.
  5. No purple / violet / indigo / #6b46c1 / #8b5cf6 values.
  6. No more than two accent tokens per component file.
  7. outline: none always paired with a forest box-shadow focus ring.
  8. No hex literal where a token name exists (e.g., #2D5016var(--forest)).
  9. No linear-gradient outside three permitted sites (kente band, hero overlay, chart axis).
  10. All text pairings pass WCAG AA at the rendered size.

10.3 Layout & motion

  1. Zero hits for rgba(0, *0, *0 in overlay backdrop selectors.
  2. Every cubic-bezier is (0.32, 0.72, 0.2, 1) or (0.4, 0, 0.6, 1).
  3. No transition-duration or animation-duration > 320ms (annotated exceptions only).
  4. Every motion-using file includes a prefers-reduced-motion block.
  5. Every interactive class sets touch-action: manipulation.
  6. Container max-width: 1080px appears in the page wrapper, not duplicated inside cards.
  7. Every backdrop-filter uses blur(8px) saturate(140%) (or removes the filter inside a mobile media block).
  8. No scale(1.x) hover on cards (only graph nodes 1.15; treemap uses inset border).
  9. Breakpoints are exactly 640px and 1024px. No 768, 992, 1200.
  10. No bounce, spring, or elastic in any transform or animation.

10.4 Voice & iconography

  1. No ! in operator copy strings (outside legal, code, UGC).
  2. No emoji codepoints (U+1F300–U+1FAFF) in operator chrome.
  3. Every image has a paired [data-photo-source] attribute or .photo-attribution sibling.
  4. No banned-CTA strings (regex: get started | explore | discover | unlock | join now | learn more | find out more | experience).
  5. No Title Case headlines in h1–h3 (>50% words uppercase first letter and not all proper names).
  6. No imports from lucide-react, @heroicons/*, @material-ui/icons, react-icons/*. Only Phosphor + local adinkra sprite.
  7. No emoji in aria-label, alt, or button text.
  8. No text-shadow in stylesheets (also in 10.1, mirrored here).
  9. Toast text strings carry no !.
  10. Marketing-pronoun we / our / us capped at 2 per page in marketing directories (colophon, legal, about exempt).
  11. Every adinkra glyph used appears in research/canon-appendix-adinkra.json.
  12. No multi-color icon SVGs in the sprite (single fill or stroke per symbol).

Canon · 11Walkback registry

This v1.0 entry does not supersede any prior Baobab canon (none existed). It supersedes the design memos at research/2026-05-12-redesign-*.md, which become informational. Future revisions register here.

VersionDateChangeAuthored by
v1.02026-05-12Initial canon. Wordmark + B monogram, three font families, cream substrate, four destinations, motion + window pattern, voice register, photo + texture, anti-patterns, 42-point compliance checklist.Claude session (PM) synthesizing four parallel section leads.
Baobab Visual Canon v1.0 · Baobab · B · 2026-05-12 · Lacuna Labs · not for distribution outside the team