Brand & Design System

From the Ewe deka (one) and wɔwɔ (the making) — "the making of one." A system built on oneness: warm earth, honest material, every token in service of a single coherent whole.

01 · Foundation

Brand Identity

Ðekawɔwɔ takes its name from Ewe, a Gbe language of Ghana, Togo and Benin. Deka = one; wɔwɔ = doing / making. Together: the making of oneness — a fitting root for a design system, whose whole purpose is to make many parts read as one.

Wordmark forms
Form Rendering Use
Canonical Ðekawɔwɔ Primary. Uses Ð (U+00D0) + ɔ open-o (U+0254). Requires a font with full Latin-Extended coverage.
ASCII fallback Dekawowo Filenames, URLs, terminals, any context where Ð / ɔ may not render.
Monogram App icon, favicon, avatar, compositing mark on generated wallpapers.
Live glass panel (inspiration: aluminium shimmer + burnished clay)
Glass panel
blur(18px) + saturate(1.15) + inset highlight rim. The gradient behind bleeds through warm and rich.
Logo assets (SVG, font-independent)

All three marks are true vector outlines — the wordmark glyphs are converted to paths from DejaVu Serif Bold, so they render identically with no font dependency. Letterforms use currentColor (inherit the surrounding text color); the gold crossbar & container stroke are fixed brand #c8862a (#d9a441 on dark grounds). Toggle the theme — the marks follow.

Monogram · dekawowo-monogram.svg

App icon, favicon, avatar, compositing mark on wallpapers. The Ð drawn as geometric strokes — not a font glyph.

Wordmark · dekawowo-wordmark.svg

Outline paths, no font needed. Use where the full name reads at size.

Lockup · dekawowo-lockup.svg

Monogram + wordmark, horizontal. Primary signature for headers and document tops.

Rendering spec — what's needed to render Ðekawɔwɔ
Concern Requirement
Characters Ð U+00D0 (capital eth) · e k a w ASCII · ɔ U+0254 (open-o) ×2
SVG marks self-contained, font-independent (glyphs pre-converted to paths). No webfont load required. Safe in email, OG images, any renderer.
Live HTML text if rendering the name as text (not SVG), load a webfont with U+00D0 + U+0254: Noto Serif, Charis SIL, or Gentium. System Georgia/DejaVu also carry both but vary by platform.
Color binding letterforms = currentColor (theme-adaptive). Gold accent = literal #c8862a light / #d9a441 on dark grounds. Never bind the gold to currentColor — it must stay gold.
Min size monogram ≥ 32px; wordmark ≥ 120px wide for the open-o counters to stay legible.
File outputs vector source in assets/; raster via rsvg-convert -w <px> mark.svg -o mark.png for PNG needs.
Orthography note

Strict Ewe orthography writes the initial consonant as ɖ (U+0256, d-with-tail / retroflex d). The brand deliberately adopts Ð (U+00D0, capital eth) for its stronger geometric crossbar — cleaner as a monogram and widely font-supported. Treat Ð as a stylistic brand choice, not a claim of linguistic correctness. The ɔ (open-o) is kept faithful. Safe rendering fonts: Noto Serif, Noto Sans, Charis SIL, Gentium — all carry Ð and ɔ.

02 · Tokens

Color Palette

A warm-earth pigment system — ochre, terracotta, umber, forest green — mixed the way a painter would, not assembled from screen primaries. Dark mode shifts surfaces to warm-dark (never pure black) and desaturates rather than inverts. Toggle the theme to see every swatch resolve.

Drawn from: kente gold thread, Ga Mashie rooftop rust, Volta region grass green, Paa Joe’s workshop shadow, unfired clay warmth. Every hex traces to a physical material in the Accra art scene.

Reading the tables: the live chip shows the token resolved in the current theme (toggle to watch it swap). The Light and Dark hex columns are the literal values defined in :root and [data-theme=dark].

A · Brand Foundation
Token Light Dark Role Inspiration
--dkw-brand-primary #c8862a #d4943a gold / ochre — primary accent Kente gold thread & the brass warmth of trotro lettering
--dkw-brand-secondary #9c3b1b #c25a35 rust / terracotta — links, emphasis Fired clay & the rusted steel of Ga Mashie rooftops
--dkw-brand-ink #1a1410 #f7f2e9 ink (flips: dark text ↔ light text) Carved-wood shadow of Paa Joe's workshop
--dkw-brand-paper #f7f2e9 #1a1410 paper (flips: cream ↔ warm-black) Raw canvas & unfired clay before the kiln
--dkw-brand-accent-green #2f5d44 #5a9b78 deep forest — secondary accent The lush green Volta-region grass behind Sutherland's silks & kente green
B · Warmth + Accent
Token Light Dark Role Inspiration
--dkw-warm-gold #c8862a #d4943a warm gold Polished brass & Bolga-basket straw
--dkw-warm-ochre #d9a441 #e0b25a ochre highlight Sun on a Ga Mashie wall & dried elephant grass
--dkw-warm-terracotta #b85333 #cf6a45 terracotta Freshly worked clay in the sculptor's hand
--dkw-warm-rust #9c3b1b #c25a35 rust Oxidised metal & Agorsor's deep-layered reds
--dkw-warm-lavender-ground #5a1f0a #7a2d12 hero deep ground Kiln-shadow & the dark ground of a painted canvas
C · Status
Token Light Dark Badge Inspiration
--dkw-status-success #2f5d44 #5a9b78 success Volta grass green — renewal & growth in kente
--dkw-status-warning #b8860b #d9a441 warning Raw ochre pigment
--dkw-status-error #9c3b1b #d4683f error Deep rust — fired clay's hottest tone
--dkw-status-info #3a6b6b #6aa3a3 info Verdigris — copper wire greening with age

Each status also has a -bg tint token (e.g. --dkw-status-success-bg: #e3ece5 light / #1e3328 dark) used behind the badge.

D · Surface + Elevation
Token Light Dark Role Inspiration
--dkw-surface-base #f7f2e9 #1a1410 page background Unprimed canvas / kiln-dark
--dkw-surface-1 #fffdf8 #231a12 card / raised surface Bleached cotton weave
--dkw-surface-2 #f0e8d8 #2d2118 hover / inset Raw straw before dyeing
--dkw-surface-3 #e8dcc8 #3a2a1d active / pressed Sanded wood / packed earth
--dkw-text-high #1a1410 #f7f2e9 primary text Charcoal mark on canvas
--dkw-text-mid #6b5d4f #b9a888 secondary text Weathered concrete grey-brown
--dkw-color-line #d8cab2 rgba(255 255 255 / .10) hairline Dried-grass fibre edge
03 · Tokens

Typography Scale & Emphasis

A 1.25 modular scale (major third) on a 16px base. Serif (Georgia) carries the reading voice; sans (Helvetica Neue) carries labels, kickers and data. The split keeps the system feeling like printed arts journalism.

display / 49pxÐekawɔwɔ
h1 / 39pxThe making of one
h2 / 31pxWarm earth, honest material
h3 / 25pxA coherent whole
h4 / 20pxSection heading
lead / 20pxLead paragraph, introducing a section in a softer voice.
body / 16pxBody text. The default reading size, Georgia at 1.6 line-height.
body-sm / 14pxSecondary body, captions with substance.
caption / 12pxKicker · Label · Metadata
Emphasis hierarchy
Role Token Treatment
Wordmark display 800 weight, brand-primary, letter-spacing -0.03em
Kicker caption sans, uppercase, letter-spacing 0.1em, text-mid
Body body Georgia 16px, text-high, 1.6 line-height
Inline link body brand-secondary, underline offset 3px
Code 0.82em mono family, surface-base background
Font stacks
--dkw-font-serif: Georgia, "Times New Roman", serif;
--dkw-font-sans:  "Noto Sans", "Helvetica Neue", Arial, sans-serif;
--dkw-font-mono:  "SF Mono", "Cascadia Code", Consolas, monospace;

/* glyph coverage: Ð (U+00D0) + ɔ (U+0254) need
   Noto Serif / Charis SIL / Gentium for faithful display */
04 · Tokens

Surfaces & Elevation

Five elevation steps. In light mode, elevation reads as a darker shadow on cream. In dark mode, surfaces grow warmer-lighter as they rise (the Material overlay model), and an inset hairline replaces the shadow's edge.

Drawn from: terracotta relief carving (shadow-relief token), burnished clay sheen (fill-burnish), El Anatsui metal cloth drape (shadow-dramatic). Elevation steps mirror how physical materials cast shadows in Ghanaian afternoon sun.

flat
shadow-flat
raised
shadow-raised
overlay
shadow-overlay
modal
shadow-modal
dramatic
shadow-dramatic
Token Light Dark
--dkw-shadow-raised 0 1px 3px rgb(0 0 0/.10) + inset hairline rgb(255 255 255/.05)
--dkw-shadow-overlay 0 10px 15px -3px /.10 /.50 deeper
--dkw-shadow-modal 0 20px 25px -5px /.10 /.60 deeper
--dkw-shadow-dramatic 0 25px 50px -12px /.25 /.70 deeper
Live elevation demos (inspiration: terracotta relief + metal cloth drape)
flat
level 0
raised
level 1
overlay
level 2
modal
level 3
dramatic
level 4
05 · Tokens

Border & Radius

Soft, generous corners suit the warm palette. Borders are hairline tan in light, low-opacity white in dark.

Drawn from: Bolga basket coils (generous curves), abebuu adekai vessel edges (angular clip-paths at xl), kente strip-weave seams (the smaller radii). Soft corners = woven organic; sharp corners = carved geometric.

sm 4
md 8
lg 16
xl 24
pill
round
Token Value
--dkw-border 1px solid line (#d8cab2 / rgba white .10)
--dkw-border-strong 1px solid line-strong
--dkw-border-accent 1px solid brand-primary
Live radius demos
sm
md
lg
xl
pill
round
/* Radius use cases mapped to inspiration */
--dkw-radius-sm: 4px;    /* kente strip-seam join — tight, structural */
--dkw-radius-md: 8px;    /* Bolga basket rim — moderate curve */
--dkw-radius-lg: 16px;   /* cards, panels — generous, woven-organic */
--dkw-radius-xl: 24px;   /* FAB, modals — sculptural, vessel-like */
--dkw-radius-pill: 9999px; /* chips, badges — the trotro sticker edge */
--dkw-radius-round: 50%; /* avatars, progress rings — Bolga spiral */
06 · Tokens

Spacing Scale

A 4px base ladder. Sections breathe at 3xl; cards pad at lg.

xs / 4px
sm / 8px
md / 16px
lg / 24px
xl / 32px
2xl / 48px
3xl / 64px
Live ruler (inspiration: Bolga coil rhythm — each step a revolution outward)
xs · 4px
sm · 8px
md · 16px
lg · 24px
xl · 32px
2xl · 48px
3xl · 64px
07 · Behavior

Links & Interactive States

Hover lifts and brightens; active presses in; focus shows a gold ring via :focus-visible (keyboard only) per WCAG 2.2 SC 2.4.13. Disabled drops to 0.5 opacity.

Drawn from: The 4px base unit echoes the tight coil-spacing of a Bolga basket: each revolution adds one consistent increment outward. Larger steps (2xl, 3xl) mark section boundaries like the dye-bands that separate colour zones in the weave.

Inline link →
State Treatment
hover surface-2 bg / translateY(-1px) on cards / brightness(1.05) on solids
focus 2px solid focus-ring, offset 2px, :focus-visible only
active surface-3 bg / scale(0.97)
disabled opacity 0.5 / pointer-events none
Live interactive demos (inspiration: aluminium shimmer + terracotta press)
08 · Behavior

Motion & Animations

Short, purposeful, earthy. Standard easing for most; spring only for playful affordances. All motion collapses under prefers-reduced-motion.

Drawn from: àṣẹ pulse (the expanding life-force), aerial silk drape easing (fabric falling under gravity), copper wire flow (energy moving through connections). Slow = ambient (àṣẹ), fast = responsive (silk snap).

Duration Value Use
instant 75ms state echoes
fast 150ms color/opacity
base 250ms transforms, cards
slow 400ms entrances
slower 700ms hero / large reveals
Easing cubic-bezier
standard 0.2, 0, 0.38, 0.9
decelerate 0, 0, 0.3, 1
accelerate 0.4, 0.14, 1, 1
spring 0.34, 1.56, 0.64, 1
Live animation demos
àṣẹ pulse
shimmer
hover lift
ray spin
/* Easing tokens (inspiration-sourced) */
--dkw-ease-standard: cubic-bezier(0.2, 0, 0.38, 0.9); /* copper wire flex */
--dkw-ease-decelerate: cubic-bezier(0, 0, 0.3, 1);    /* silk fabric settling */
--dkw-ease-accelerate: cubic-bezier(0.4, 0.14, 1, 1); /* gravity pull */
--dkw-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Bolga coil snap-back */

/* Duration tokens */
--dkw-dur-instant: 75ms;  /* state echo — too fast to track */
--dkw-dur-fast: 150ms;    /* colour transition — a blink */
--dkw-dur-base: 250ms;    /* standard interaction response */
--dkw-dur-slow: 400ms;    /* panel entrance — deliberate arrival */
--dkw-dur-ambient: 28s;   /* floating orb drift — subconscious */
09 · Patterns

Glassmorphism & Surface Patterns

Translucent surfaces that let the content behind enrich what’s in front. Not just frosted glass — each variant draws from a different physical material in our inspiration library.

Drawn from: aluminium foil shimmer (specular highlight), burnished clay sheen (directional gradient), El Anatsui metal cloth light-wash (broad diagonal catchlight), terracotta kiln-glaze (crackle translucency). Glass = metal + clay + light + air.

Live glass variants (on gradient stage)
Burnished clay
Standard glass. Warm cream translucency, rust-tinted border, top rim highlight. The default panel surface.
Kiln-fired
Deep glass for dark contexts. Higher blur, gold-tinted border, heavier shadow. Use for modals, popovers on dark grounds.
Aluminium shimmer
Lower opacity + diagonal highlight streak. Higher saturate. For CTAs, featured cards, premium elements.
Clay grain
Glass + feTurbulence grain overlay. Adds terracotta tactile feel. For cards that need to feel hand-made rather than digital.
Token table
Token Light Dark Inspiration
--dkw-glass-bg rgba(247,242,233, 0.72) rgba(35,26,18, 0.65) Burnished clay translucency
--dkw-glass-bg-deep rgba(58,36,24, 0.75) rgba(26,20,16, 0.82) Kiln-fired depth (terracotta)
--dkw-glass-bg-shimmer rgba(247,242,233, 0.55) rgba(58,36,24, 0.5) Aluminium foil (lower opacity = more bleed-through)
--dkw-glass-blur blur(18px) blur(20px) Deeper blur in dark (glass thickens at night)
--dkw-glass-saturate saturate(1.15) saturate(1.2) Enriches bleed-through (metal cloth catchlight)
--dkw-glass-border rgba(156,59,27, 0.18) rgba(212,148,58, 0.15) Rust edge (light) / gold edge (dark)
--dkw-glass-rim inset 0 1px 0 rgba(255,255,255, 0.5) inset 0 1px 0 rgba(255,255,255, 0.1) Top-edge light catch (sells "glass" over "transparent box")
--dkw-glass-shadow 0 6px 28px rgba(156,59,27, 0.15) 0 4px 24px rgba(0,0,0, 0.35) Warm coloured shadow (light) / deep shadow (dark)
Surface pattern overlays (layer ON TOP of glass)
Pattern Inspiration Implementation Use when
grain Terracotta raw surface feTurbulence (baseFreq 0.8) at 0.08 opacity Cards that need tactile, hand-made feel
weave Kente interlace Crossing repeating-linear-gradients at 0.04 opacity Feature panels, hero cards
fibre Veta vera grass Vertical lines (92deg) at 0.03 opacity Subtle texture on any card surface
crackle Kiln-fired pottery SVG crack polylines at 0.05 opacity Map cards, aged/established content
shimmer-streak Aluminium specular Diagonal linear-gradient (transparent→white-15%→transparent) Premium CTAs, featured glass panels
Implementation
/* Base glass (burnished clay variant) */
.dkw-glass {
  background: var(--dkw-glass-bg);
  backdrop-filter: var(--dkw-glass-blur) var(--dkw-glass-saturate);
  border: 1px solid var(--dkw-glass-border);
  border-radius: 16px;
  box-shadow: var(--dkw-glass-shadow), var(--dkw-glass-rim);
  isolation: isolate;
  overflow: hidden;
}

/* Deep variant (kiln-fired — for modals/popovers) */
.dkw-glass--deep {
  --dkw-glass-bg: var(--dkw-glass-bg-deep);
  --dkw-glass-blur: blur(20px);
  --dkw-glass-saturate: saturate(1.2);
}

/* Shimmer variant (aluminium — for featured/premium) */
.dkw-glass--shimmer {
  --dkw-glass-bg: var(--dkw-glass-bg-shimmer);
  --dkw-glass-saturate: saturate(1.3);
  background-image: linear-gradient(135deg,
    transparent 40%, rgba(255,255,255,0.15) 50%, transparent 60%);
}

/* Grain overlay (terracotta tactile) */
.dkw-glass--grain::after {
  content: ""; position: absolute; inset: 0;
  pointer-events: none; border-radius: inherit;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.08;
}
.dkw-glass--grain { position: relative; }

/* Accessibility fallback — non-negotiable */
@media (prefers-reduced-transparency: reduce) {
  .dkw-glass, .dkw-glass--deep, .dkw-glass--shimmer {
    background: var(--surface-container);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background-image: none;
  }
}

/* Double-glass prevention */
.dkw-glass .dkw-glass {
  background: transparent; border: none;
  backdrop-filter: none; box-shadow: none;
}
Where each variant lives in the app
Component Glass variant Why
Top nav bar Standard (burnished clay) Readable text over scrolling content
Action footer Standard Input buttons need maximum legibility
Modal / bottom sheet Deep (kiln-fired) Stronger separation from page content
Drop-a-pin hero Shimmer (aluminium) Featured action, premium feel
Language dropdown Standard + grain Tactile, feels hand-crafted
Feed cards (on hover) None (solid surface) Feed cards need fast scanning — no glass blur
Map overlay controls Deep Controls over busy map content need strong contrast
10 · Components

Timeline & Video Embed

A vertical timeline with gold nodes on a tan connector, and a 16:9 responsive video frame with a gold play affordance over a surface poster.

Drawn from: Bolga basket coiling process (sequential stages building outward), veta vera grass transformation (harvest → split → dye → twist → coil). Each timeline node = one revolution of the spiral.

Stage 01
Transcribe

Whisper audio → timestamped segments.

Stage 02
See

Vision model describes each frame.

Stage 03
Make one

Synthesis into a single narrative whole.

Timeline component (inspiration: Bolga coiling process)
Stage 01
Report received
Citizen uploads photo + description via app
Stage 02
AI triage
Severity classification + recommended response
Stage 03
Dispatch
Nearest responder alerted, ETA calculated
Stage 04
Resolved
Ask/Give closed, outcome logged
/* Timeline component */
.dkw-timeline { position: relative; padding-left: 2rem; }
.dkw-timeline::before {
  content: ""; position: absolute; left: 7px; top: 0; bottom: 0;
  width: 2px; background: var(--md-outline-variant, #d8cab2);
}
.dkw-timeline-item { position: relative; margin-bottom: 1.5rem; }
.dkw-timeline-item::before {
  content: ""; position: absolute;
  left: -2.45rem; top: 2px;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--surface-bg);
}
/* Severity-coded timeline nodes */
.dkw-timeline-item[data-stage="1"]::before { background: #c8862a; }
.dkw-timeline-item[data-stage="2"]::before { background: #d9a441; }
.dkw-timeline-item[data-stage="3"]::before { background: #9c3b1b; }
.dkw-timeline-item[data-stage="4"]::before { background: #2f5d44; }
11 · Standards

Image Generation Standards

Target resolutions for generated atmospheres. Backgrounds are palette-locked — the hero gradient only, no AI-chosen colors. The brand mark is composited, never generated: place the Ð as a vector/raster layer over the atmosphere. On mobile, keep the mark within the center 80% safe-area.

Drawn from: the hand-painted signage doctrine: the mark is COMPOSITED over atmosphere, never generated. Just as Ga Mashie signwriters paint directly onto a prepared surface, we place our Ð mark onto generated backgrounds — the mark is always vector-precise, the ground is always atmosphere.

Ð
Wallpaper QHD
2560 × 1440
16:9 desktop · safe 2048×1152
Ð
Wallpaper 4K
3840 × 2160
16:9 high-DPI · safe 3072×1728
Ð
Mobile
1290 × 2796
portrait · mark in center 80% · safe 1032×2237
Rule Detail
Palette lock background = hero gradient #1a1410 → #3a2418 → #5a1f0a only. No generated colors.
Composited mark Ð placed as a layer over the atmosphere. Never diffusion-generated pixel art.
Safe area all marks + text within center 80%. Mobile especially (notch / rounded corners).
12 · Catalog

Reusable Component Library

The catalog of brand-canonical building blocks — each with its tokens, integrity rules, and a from-scratch reproduction guide. The Ð logo is entry 01.

Entry 01 · Logo / Mark

Tokens

container bg --dkw-surface-1
container border --dkw-border-accent
container radius --dkw-radius-lg
glyph crossbar --dkw-brand-primary
glyph stem --dkw-text-high

Integrity rules

  • never stretch or skew the glyph
  • never recolor outside the token set
  • never render below 32px
  • never apply drop-shadow to the glyph — shadow lives on the container
  • do keep cap-height clear space on all sides
  • do composite the mark over generated atmospheres, never generate it

From-scratch reproduction (SVG)

<svg viewBox="0 0 120 120">
  <!-- container: rounded square, gold stroke -->
  <rect x="5" y="5" width="110" height="110" rx="24"
        fill="none" stroke="#c8862a" stroke-width="3"/>
  <!-- D bowl: stem up, across, curve, back -->
  <path d="M46 88 V32 H60 C80 32 90 46 90 60
           C90 74 80 88 60 88 H46 Z"
        fill="none" stroke="currentColor" stroke-width="11"
        stroke-linejoin="round" stroke-linecap="round"/>
  <!-- eth crossbar, gold, extends left of stem -->
  <path d="M31 60 H58" stroke="#c8862a" stroke-width="11"
        stroke-linecap="round"/>
</svg>

stroke ratios (lock these):  border 3 : letter 11 : crossbar 11
crossbar overshoot:          15px left of the stem (31 → 46)
container radius:            24 / 120 = 0.2 of side
gold:  #c8862a light · #d9a441 on dark grounds
letter: currentColor (theme-adaptive)
ASCII fallback where Ð unsupported → "D"
Entry 02 · Favicon

Tokens

background --dkw-brand-ink (#1a1410)
container radius 6px (18.75% of 32px)
letter stroke --dkw-brand-paper (#f7f2e9)
crossbar --dkw-brand-primary (#c8862a)
stroke-width 3px (at 32px canvas)

Sizes & formats

File Size Use
favicon.svg any Modern browsers (scales infinitely)
favicon-32.png 32×32 Legacy browser tab
favicon-16.png 16×16 Legacy fallback
apple-touch-icon.png 180×180 iOS home screen bookmark

HTML implementation

<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">

Integrity rules

  • dark background always (ink #1a1410) — ensures visibility on any browser chrome
  • never invert for dark mode — the favicon is always dark-ground with light letter
  • gold crossbar must remain visible at 16px (test at actual size)
  • do use the SVG version as primary (infinite scaling, tiny file)
  • do regenerate PNGs from the SVG source via rsvg-convert

From-scratch reproduction

<svg viewBox="0 0 32 32">
  <rect width="32" height="32" rx="6" fill="#1a1410"/>
  <path d="M12 24 V8 H16 C22 8 25 12 25 16
    C25 20 22 24 16 24 H12 Z"
    fill="none" stroke="#f7f2e9" stroke-width="3"
    stroke-linejoin="round" stroke-linecap="round"/>
  <path d="M8 16 H15" fill="none" stroke="#c8862a"
    stroke-width="3" stroke-linecap="round"/>
</svg>

/* PNG generation */
rsvg-convert -w 32 favicon.svg -o favicon-32.png
rsvg-convert -w 180 favicon.svg -o apple-touch-icon.png
13A · Integration

Material Design 3 Token Layer

Ðekawɔwɔ tokens mapped to M3 naming conventions. The design-tokens.json file (download) follows Material Theme Builder export format and can be ingested by v0, shadcn/ui, and any M3-compatible tooling.

Drawn from: The component catalog follows the abebuu adekai principle: each component encodes its purpose in its form. The logo’s reproduction guide mirrors how Paa Joe’s apprentices learn—proportional rules that produce the form from scratch every time.

Core colour mapping
M3 role Ðekawɔwɔ source Hex Rationale
md.sys.color.primary Gold / ochre #c8862a Dominant brand accent — kente gold thread, trotro lettering warmth
md.sys.color.secondary Deep forest green #2f5d44 Cool contrast — Volta grass, kente green bands
md.sys.color.tertiary Rust / terracotta #9c3b1b Warm expressive accent — fired clay, Ga Mashie rooftops
md.sys.color.neutral Warm near-black #1a1410 Surfaces + text — carved-wood shadow, workshop dark
md.sys.color.error M3 default #ba1a1a Standard error red (not customized)
Typescale mapping
M3 token Ðekawɔwɔ value
md.sys.typescale.display-large Georgia 3.052rem / 800 / -0.03em
md.sys.typescale.headline-large Georgia 1.953rem / 700
md.sys.typescale.title-large Helvetica Neue 1.25rem / 600
md.sys.typescale.body-large Georgia 1rem / 400 / 1.6lh
md.sys.typescale.label-large Helvetica Neue 0.875rem / 500 / 0.05em
Shape + Motion
M3 token Value
md.sys.shape.corner.none 0px
md.sys.shape.corner.extra-small 4px
md.sys.shape.corner.small 8px
md.sys.shape.corner.medium 16px
md.sys.shape.corner.large 24px
md.sys.shape.corner.full 9999px
md.sys.motion.easing.standard cubic-bezier(0.2, 0, 0.38, 0.9)
md.sys.motion.duration.medium1 250ms
JSON ingest for v0 / shadcn
/* Import design-tokens.json into your project */
/* Map M3 scheme roles → shadcn CSS variables: */

:root {
  --primary: #c8862a;           /* schemes.light.primary */
  --primary-foreground: #ffffff; /* schemes.light.onPrimary */
  --secondary: #2f5d44;         /* schemes.light.secondary */
  --background: #f7f2e9;        /* schemes.light.background */
  --foreground: #1a1410;        /* schemes.light.onBackground */
  --muted: #d8cab2;             /* schemes.light.surfaceContainerHighest */
  --border: #9a8a78;            /* schemes.light.outline */
  --ring: #c8862a;              /* schemes.light.primary */
  --radius: 0.5rem;             /* md.sys.shape.corner.small */
}

.dark {
  --primary: #d4943a;           /* schemes.dark.primary */
  --primary-foreground: #3d2600;/* schemes.dark.onPrimary */
  --background: #1a1410;        /* schemes.dark.background */
  --foreground: #f7f2e9;        /* schemes.dark.onBackground */
}

Drawn from: The M3 mapping preserves our inspiration sourcing: gold (kente thread) becomes primary, green (Volta grass) becomes secondary, rust (fired clay) becomes tertiary. These cultural associations travel with every component, even inside Material’s generic role names.

Complete token mapping: Ðekawɔwɔ → M3 → shadcn/v0
Ðekawɔwɔ token M3 sys role shadcn variable Light value Dark value
--dkw-brand-primary md.sys.color.primary --primary #c8862a #d4943a
--dkw-brand-paper md.sys.color.background --background #f7f2e9 #1a1410
--dkw-brand-ink md.sys.color.on-background --foreground #1a1410 #f7f2e9
--dkw-brand-secondary md.sys.color.tertiary --destructive #9c3b1b #c25a35
--dkw-brand-accent-green md.sys.color.secondary --secondary #2f5d44 #5a9b78
--dkw-surface-1 md.sys.color.surface-container --card #fffdf8 #231a12
--dkw-surface-2 md.sys.color.surface-container-high --muted #f0e8d8 #2d2118
--dkw-text-mid md.sys.color.on-surface-variant --muted-foreground #6b5d4f #b9a888
--dkw-color-line md.sys.color.outline-variant --border #d8cab2 rgba(255,255,255,0.1)
--dkw-brand-primary md.sys.color.primary --ring #c8862a #d4943a
--dkw-radius-md md.sys.shape.corner.medium --radius 16px (0.5rem in shadcn format)
/* Auto-generate shadcn globals.css from design-tokens.json: */
import tokens from './design-tokens.json';

function hexToOklch(hex) { /* convert hex → oklch for modern shadcn */ }

const lightVars = {
  '--primary': hexToOklch(tokens.schemes.light.primary),
  '--primary-foreground': hexToOklch(tokens.schemes.light.onPrimary),
  '--secondary': hexToOklch(tokens.schemes.light.secondary),
  '--secondary-foreground': hexToOklch(tokens.schemes.light.onSecondary),
  '--background': hexToOklch(tokens.schemes.light.background),
  '--foreground': hexToOklch(tokens.schemes.light.onBackground),
  '--card': hexToOklch(tokens.schemes.light.surfaceContainerLow),
  '--muted': hexToOklch(tokens.schemes.light.surfaceContainerHighest),
  '--border': hexToOklch(tokens.schemes.light.outline),
  '--ring': hexToOklch(tokens.schemes.light.primary),
  '--radius': tokens.shape.corner.medium,
};
// Write to globals.css as :root { } and .dark { }
13B · Responsive

Mobile-First Strategy

Every component designs for touch first, then adapts upward. No hover-only states. No targets smaller than 44px. Safe-area-aware from day one.

Touch targets
Concern Requirement Implementation
Minimum tap size 44 × 44px (WCAG 2.5.5) min-width: 2.75rem; min-height: 2.75rem;
Spacing between targets ≥ 8px gap gap: var(--dkw-space-sm)
Text selection Disabled on UI, enabled on content select-none on shell, select-text on inputs
Safe area handling
/* Viewport meta (Next.js app/layout.tsx) */
export const viewport = {
  width: 'device-width',
  initialScale: 1,
  viewportFit: 'cover',
};

/* CSS — one root wrapper owns all insets */
.app-shell {
  padding: env(safe-area-inset-top)
           env(safe-area-inset-right)
           env(safe-area-inset-bottom)
           env(safe-area-inset-left);
  min-height: 100dvh;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* Re-enable selection where needed */
input, textarea, [contenteditable] {
  -webkit-user-select: text;
  user-select: text;
}
Hover guard
/* NEVER write a bare :hover — always guard */
@media (hover: hover) {
  .btn:hover {
    background: var(--dkw-brand-primary);
    filter: brightness(1.05);
    transform: translateY(-1px);
  }
}

/* On touch devices this block is skipped entirely.
   Use :active and :focus-visible for touch feedback. */
.btn:active { transform: scale(0.97); }
.btn:focus-visible {
  outline: 2px solid var(--dkw-color-focus-ring);
  outline-offset: 2px;
}

/* Tailwind note: hover: variant already compiles
   to @media (hover: hover) internally — safe. */
Responsive breakpoint strategy
Breakpoint Width Layout
Base (mobile) 0 – 639px Single column, full-width cards, stacked nav
sm 640px+ 2-column grid begins
md 768px+ Side navigation appears
lg 1024px+ 3-column grid, wider content measure
xl 1280px+ Max content width (1200px) centred
13C · Native Wrapper

Capacitor / Mobile Wrapper Prep

How to take a v0/Next.js app built with these tokens and wrap it for iOS + Android via Capacitor. The design system's tokens work identically in both web and WebView — no branching needed.

Drawn from: 44px touch targets = the same minimum hand-clearance a Bolga weaver needs between coil rows. The mobile-first grid mirrors kente strip-weaving: start with one narrow column (the loom width) and stitch additional strips edge-to-edge as the viewport widens.

1. Static export (SSG)
// next.config.mjs
const nextConfig = {
  output: 'export',        // static HTML/CSS/JS → out/
  images: { unoptimized: true }, // no server-side optimization
  trailingSlash: true,     // /about/index.html for local file serving
};
export default nextConfig;
2. Client components
// Any component using hooks, events, or Capacitor plugins:
'use client';

import { Share } from '@capacitor/share';

export function ShareButton() {
  return (
    <button onClick={() => Share.share({ title: 'Ðekawɔwɔ' })}
      className="min-tap">
      Share
    </button>
  );
}
3. Routing
Rule Why
Use <Link href="/path/"> only Client-side nav; no server to handle reloads
Never window.location = ... Causes full WebView reload → white flash
trailingSlash: true Capacitor resolves /about/index.html locally
4. Init + sync
# Install
npm install @capacitor/core
npm install -D @capacitor/cli

# Init (webDir = Next.js output)
npx cap init dekawowo com.dekawowo.app --web-dir out

# Add platforms
npx cap add ios
npx cap add android

# Build + deploy to device
npm run build && npx cap sync
npx cap open ios     # opens Xcode
npx cap open android # opens Android Studio
5. capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.dekawowo.app',
  appName: 'Ðekawɔwɔ',
  webDir: 'out',
  ios: { contentInset: 'never' }, // CSS env() owns insets
};
export default config;
Cross-platform token compatibility
Token Web browser Capacitor WebView
env(safe-area-inset-*) Resolves to 0px (no notch) Real device insets
@media (hover: hover) Matches on desktop Does NOT match → hover skipped
select-none Optional PWA feel Essential native-app feel
44px touch target Good practice Mandatory — no cursor precision
Complete build-to-device pipeline
Step Command What happens
1. Build npm run build Next.js compiles to static HTML/CSS/JS in out/ folder. No server code remains.
2. Sync npx cap sync Copies out/ into iOS (ios/App/App/public/) and Android (android/app/src/main/assets/public/) native projects + installs plugin native code.
3. Open iOS npx cap open ios Opens Xcode. Build target = your physical device or simulator. Hit Run.
4. Open Android npx cap open android Opens Android Studio. Select device/emulator. Hit Run.
5. Live reload (dev) npx cap run ios --livereload --external Points the WebView at your dev server URL instead of bundled files. Changes appear instantly on device.
What the wrapper does vs what our code does
Concern Handled by Capacitor (native) Handled by our code (web)
Status bar Native status bar plugin controls colour/style CSS padding-top: env(safe-area-inset-top) prevents overlap
Navigation WebView loads out/index.html; all nav is client-side Next.js <Link> handles route changes without reload
Camera access @capacitor/camera plugin bridges to native APIs Our report-ask flow calls the plugin from a 'use client' component
Push notifications @capacitor/push-notifications registers with APNS/FCM Our alert system receives + displays the notification data
Geolocation @capacitor/geolocation bridges GPS Our map component reads coordinates for ask location
Biometric auth Native biometric APIs (Face ID, fingerprint) Our auth flow can gate sensitive actions behind biometric check
App icon + splash Native asset catalogs (generated from our favicon/brand mark) N/A — these are native-only assets
iOS-specific requirements
/* Info.plist additions (Capacitor handles base, plugins add more): */
NSCameraUsageDescription = "To photograph asks for reports"
NSLocationWhenInUseUsageDescription = "To show nearby asks"
NSPhotoLibraryUsageDescription = "To attach existing photos to reports"

/* App Store requirements: */
- App icon: 1024×1024 PNG (generate from brand mark SVG)
- Screenshots: 6.7" (1290×2796), 6.5" (1284×2778), 12.9" iPad
- Privacy policy URL required
- Min deployment target: iOS 16+
Android-specific requirements
/* AndroidManifest.xml (plugins add permissions automatically): */
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

/* Build config: */
- Min SDK: 24 (Android 7.0)
- Target SDK: 34 (Android 14)
- App icon: adaptive icon (foreground + background layers from brand mark)
- Google Play: feature graphic 1024×500, screenshots per device tier
Design tokens in native context
/* Our CSS tokens work identically in Capacitor WebView.
   The ONLY differences: */

/* 1. env(safe-area-inset-*) resolves to REAL values (not 0px) */
/* 2. @media (hover: hover) does NOT match — hover styles are skipped */
/* 3. -webkit-touch-callout: none actually prevents long-press menu */
/* 4. 100dvh = real device viewport (accounts for browser chrome absence) */

/* Platform detection (use sparingly — only for native plugin calls): */
import { Capacitor } from '@capacitor/core';
const isNative = Capacitor.isNativePlatform();
const isIOS = Capacitor.getPlatform() === 'ios';
const isAndroid = Capacitor.getPlatform() === 'android';
13H · Modes

Light & Dark Mode Design

Dark mode is NOT "light mode with inverted colours." Each mode is independently designed. Light leans warm-paper with gold accent; dark leans warm-ink with a brighter gold. The accent colour literally swaps intensity between modes. That deliberate asymmetry is what makes each mode feel designed rather than auto-generated.

Core principle: one class, cascaded everywhere
/* Set once on <html> — every descendant resolves automatically */
:root { /* light */
  --surface-bg: #f7f2e9;
  --surface-container: #f0e8d8;
  --text-primary: #1a1410;
  --text-secondary: #6b5d4f;
  --accent: #c8862a;
  --accent-bright: #d9a441;
  --glass-bg: rgba(247, 242, 233, 0.82);
  --glass-border: rgba(156, 59, 27, 0.18);
  --glass-shadow: 0 6px 28px rgba(156, 59, 27, 0.15);
  --glow-primary: rgba(200, 134, 42, 0.16);
  --glow-secondary: rgba(47, 93, 68, 0.14);
  --glow-tertiary: rgba(156, 59, 27, 0.08);
}

.dark { /* independently designed, NOT auto-inverted */
  --surface-bg: #1a1410;
  --surface-container: #2d2118;
  --text-primary: #f7f2e9;
  --text-secondary: #b9a888;
  --accent: #d4943a;           /* BRIGHTER gold on dark */
  --accent-bright: #e0b25a;
  --glass-bg: rgba(26, 20, 16, 0.78);
  --glass-border: rgba(212, 148, 58, 0.15);
  --glass-shadow: 0 4px 24px rgba(212, 148, 58, 0.10);
  --glow-primary: rgba(212, 148, 58, 0.07);   /* HALF intensity */
  --glow-secondary: rgba(90, 155, 120, 0.06);
  --glow-tertiary: rgba(194, 90, 53, 0.05);
}
Theme toggle: draw from inspiration, not icon fonts
Aspect Implementation
Sun icon Inline SVG, 22×22 viewBox. Àṣẹ-inspired: gold core + 8 radiating ray lines. Rays rotate 18s, core breathes (scale 1→1.08 over 4s). Two slow independent animations = organic.
Moon icon Inline SVG, 22×22. Bolga-spiral-inspired: fat crescent path + coil detail inside. 6s glow-and-scale pulse.
Glow Three stacked drop-shadow filters at increasing radius/decreasing opacity. overflow: visible on the SVG (critical — without it glow clips at bounding box).
Convention Icon shown = mode you switch TO. aria-label updates dynamically (“Switch to dark mode”).
Motion gate All animation inside @media (prefers-reduced-motion: no-preference). Static glowing icon for reduced-motion users.
State source Driven off the same class that themes everything. Toggle class + icon + animation + page theme never disagree.
/* Toggle glow — layered for believable light bloom */
.toggle-sun {
  overflow: visible;
  filter:
    drop-shadow(0 0 2px rgba(200,134,42,0.85))
    drop-shadow(0 0 5px rgba(200,134,42,0.45))
    drop-shadow(0 0 12px rgba(200,134,42,0.2));
}

@media (prefers-reduced-motion: no-preference) {
  .toggle-sun .rays {
    animation: ray-spin 18s linear infinite;
    transform-origin: center;
  }
  .toggle-sun .core {
    animation: core-breathe 4s ease-in-out infinite;
  }
  @keyframes ray-spin { to { transform: rotate(360deg); } }
  @keyframes core-breathe {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.08); }
  }
}
Nav bar: gradient surface, not flat
Property Light Dark
background linear-gradient(180deg, #f7f2e9, #f0e8d8) linear-gradient(180deg, #1a1410, #231a12)
border-bottom 1px solid rgba(200,134,42,0.12) (gold tint) 1px solid rgba(212,148,58,0.1) (brighter gold)
box-shadow 0 2px 8px rgba(200,134,42,0.06) 0 2px 8px rgba(0,0,0,0.2)
shimmer 24s sweep: 200%-wide transparent→white-3%→transparent gradient. Almost subliminal. Gated by prefers-reduced-motion.
/* Nav bar with ambient shimmer */
.top-nav {
  background: linear-gradient(180deg, var(--surface-bg), var(--surface-container));
  border-bottom: 1px solid rgba(200,134,42,0.12);
  box-shadow: 0 2px 8px rgba(200,134,42,0.06);
  position: sticky; top: 0; isolation: isolate;
}
.dark .top-nav {
  border-bottom-color: rgba(212,148,58,0.1);
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}

/* 24s shimmer — barely perceptible, adds polish */
@media (prefers-reduced-motion: no-preference) {
  .top-nav::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg,
      transparent 0%, rgba(255,255,255,0.03) 50%, transparent 100%);
    background-size: 200% 100%;
    animation: shimmer 24s linear infinite;
    pointer-events: none;
  }
  @keyframes shimmer {
    from { background-position: -100% 0; }
    to { background-position: 200% 0; }
  }
}

/* Nav link hover: inset accent bar + soft glow */
.nav-link:hover {
  box-shadow: inset 3px 0 0 var(--accent), 0 0 12px rgba(200,134,42,0.1);
  padding-left: calc(1rem + 3px); /* tactile nudge */
}
Logo: inline SVG with theme-adaptive fills
Property Light Dark
letter stroke currentColor (ink) currentColor (paper)
crossbar / border var(--accent) (#c8862a) var(--accent) (#d4943a)
filter drop-shadow(0 2px 4px rgba(26,20,16,0.2)) drop-shadow(0 0 6px rgba(212,148,58,0.35))
sizing height: calc(100% - 10px) constrained to nav, with min/max clamps
/* Logo reads CSS vars — one component, two modes */
.brand-mark {
  --accent: var(--md-primary, #c8862a);
  height: calc(100% - 10px);
  min-height: 28px; max-height: 40px;
}
/* light: crisp shadow */
.brand-mark { filter: drop-shadow(0 2px 4px rgba(26,20,16,0.2)); }
/* dark: coloured glow */
.dark .brand-mark { filter: drop-shadow(0 0 6px rgba(212,148,58,0.35)); }

/* SVG fills reference vars, never baked hex */
<svg>
  <rect stroke="var(--accent)" .../>
  <path stroke="currentColor" .../>  <!-- inherits text color -->
  <path stroke="var(--accent)" .../> <!-- crossbar, always gold -->
</svg>
Backgrounds: layered radial gradients
/* A flat background = "template" feel. Layer ambient depth. */
.app-shell {
  background-color: var(--surface-bg);
  background-image:
    radial-gradient(ellipse at 8% 12%, var(--glow-primary) 0%, transparent 35%),
    radial-gradient(ellipse at 92% 88%, var(--glow-secondary) 0%, transparent 35%),
    radial-gradient(ellipse at 50% 40%, var(--glow-tertiary) 0%, transparent 50%);
}
/* In dark mode the glow vars are already halved — no extra rule needed */
Dark-mode heading glow (light mode: no glow)
/* Glows read as "premium" on dark and as "smudge" on light — don't apply in light */
.dark h1, .dark h2 {
  text-shadow: 0 0 12px rgba(212, 148, 58, 0.4);
}

/* Wordmark: layered extrusion shadows + ground blur */
.brand-wordmark {
  text-shadow:
    1px 1px 0 #5a3e12,
    2px 2px 0 #3d2600,
    3px 3px 0 #2d2118,
    4px 4px 6px rgba(26,20,16,0.3);
}
Ambient floating orbs
/* Two big blurred circles behind everything — life without distraction */
@media (prefers-reduced-motion: no-preference) {
  .orb {
    position: fixed; z-index: -1;
    width: 40vw; height: 40vw;
    border-radius: 50%;
    filter: blur(80px);
    opacity: 0.035;
    animation: drift 28s ease-in-out infinite alternate;
  }
  .orb-gold { background: var(--accent); top: 10%; left: 5%; }
  .orb-green { background: #2f5d44; bottom: 10%; right: 5%; animation-delay: -14s; }
  @keyframes drift {
    from { transform: translate(0, 0); }
    to { transform: translate(3vw, 2vh); }
  }
}
Entrance stagger
/* Cards assemble in sequence, not all-at-once pop */
@media (prefers-reduced-motion: no-preference) {
  .card { animation: fade-up 0.4s ease-out both; }
  .card:nth-child(1) { animation-delay: 0.05s; }
  .card:nth-child(2) { animation-delay: 0.10s; }
  .card:nth-child(3) { animation-delay: 0.15s; }
  @keyframes fade-up {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
  }
}
Themed micro-details
/* Scrollbars */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 9999px; }

/* Text selection */
::selection { background: var(--accent-container); color: var(--text-primary); }

/* Focus ring — accessibility + polish */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Gradient sheen divider (replaces <hr>) */
.sheen-hr {
  height: 2px; border: none;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
}

/* Gradient button with mode-specific direction */
.cta-btn {
  background: linear-gradient(135deg, var(--accent), var(--accent-bright));
  box-shadow: 0 4px 14px rgba(200,134,42,0.3);
}
.dark .cta-btn {
  background: linear-gradient(135deg, var(--accent-bright), var(--accent));
  box-shadow: 0 4px 14px rgba(212,148,58,0.2);
}

/* Hover: shadow grows + lift */
@media (hover: hover) {
  .cta-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(200,134,42,0.4);
  }
}
Dark-mode failure modes (audit these)
Common miss Fix
Section headers illegible Explicitly set color: var(--text-primary) on every heading level
Link text washed out Use var(--accent) for links in both modes (it’s brighter in dark)
Dropdown items invisible Chase every text role: label, body-secondary, menu-item, table-cell
Input text black-on-dark Set color: var(--text-primary) on all form controls
Disabled state indistinguishable Use opacity: 0.5 + var(--text-secondary)
Double-glass muddy panels Neutralize inner glass (background: transparent; border: none) when nested inside a glass wrapper
The thread tying it together

Independent per-mode design (not auto-inversion), layered cheap effects (stacked drop-shadows, gradient surfaces, slow ambient motion), and every animation gated behind prefers-reduced-motion. The toggle, nav, and logo all read the same theme state so they can never visually disagree. Always audit both modes on a real device — the failures hide in text contrast, not the parts that look obviously broken.

Drawn from: Light mode = the warm paper surface of unfired clay, bright afternoon in Ga Mashie. Dark mode = the workshop interior where Paa Joe carves by lamplight—warm-dark, not cold-dark. The àṣẹ sun/moon toggle mirrors the dual nature of the life-force: radiant by day, concentrated by night.

Ready-to-use CSS utility file
/* Import the utility classes into your project */
@import url("dkw-utilities.css");

/* Or link it: */
<link rel="stylesheet" href="/dkw-utilities.css">

/* Available classes:
   .dkw-cornrow-hr         — wavy cornrow section divider
   .dkw-sheen-hr           — gradient sheen divider
   .dkw-gouge-hr           — embossed carved divider
   .dkw-sticker-badge      — rotated sticker toast
   .dkw-severity-band      — tricolour severity indicator
   .dkw-kente-border       — warp-weft card border
   .dkw-btn-shimmer        — metallic hover sheen
   .dkw-btn-terra:active   — warm pressed state
   .dkw-card-stack         — layered depth card
   .dkw-vessel-shape       — angular clip-path container
   .dkw-plywood-bg         — warm grain texture overlay
   .dkw-grass-overlay      — natural fibre texture
   .dkw-ashe-loader        — concentric pulse spinner
   .dkw-bolga-progress     — coil progress ring
   .dkw-copper-line (SVG)  — animated connection line
   .dkw-glass              — glassmorphism panel
   .dkw-silk-nav           — scroll-hide nav
*/
13I · Layout

Page Layout & Grid

Mobile-first responsive grid. Single column base, expanding to 2-col at sm, 3-col at lg. The app shell uses CSS Grid with named areas.

App shell grid
/* Mobile: stacked */
.app-shell {
  display: grid;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 1fr;
  grid-template-areas:
    "topbar"
    "main"
    "bottom-nav";
  min-height: 100dvh;
}

/* Desktop 768px+: nav rail appears */
@media (min-width: 768px) {
  .app-shell {
    grid-template-columns: 80px 1fr;
    grid-template-areas:
      "rail topbar"
      "rail main"
      "rail .";
  }
  .bottom-nav { display: none; }
}
Content grid (cards, feed)
.content-grid {
  display: grid;
  gap: var(--dkw-space-md);
  grid-template-columns: 1fr;             /* mobile: 1 col */
}
@media (min-width: 640px) {
  .content-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .content-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Full-bleed card */
.content-grid .card-full { grid-column: 1 / -1; }

/* Featured + sidebar layout */
.content-grid .card-featured { grid-column: span 2; grid-row: span 2; }

/* Max content width */
.content-area { max-width: 1200px; margin: 0 auto; padding: 0 var(--dkw-space-lg); }
Spacing rhythm
Context Token Value
Between feed items --dkw-space-md 16px
Card internal padding --dkw-space-lg 24px
Section spacing --dkw-space-3xl 64px
Nav rail width fixed 80px
Top bar height fixed 56px (mobile) / 64px (desktop)
Bottom nav height fixed 80px + safe-area-inset-bottom
FAB position fixed bottom: calc(80px + safe-bottom + 1rem); right: 1.25rem
13J · States

Component States

Every interactive element has 5 states. Each state has a defined visual treatment drawn from our inspiration tokens.

Drawn from: The grid’s named areas (topbar, rail, main, bottom) map to the anatomy of a Ga Mashie painted sign: border frame (the nav), portrait zone (main content), text band (bottom nav). The FAB = the signwriter’s brush—always within reach, the primary tool for creating.

State Visual Token
Default Base fill + shadow-raised background: var(--surface-container); box-shadow: var(--glass-shadow)
Hover (desktop only) Aluminium shimmer sweep + translateY(-2px) .dkw-btn-shimmer::after + @media (hover:hover)
Focus Gold ring, 2px offset (WCAG) outline: 2px solid var(--accent); outline-offset: 2px
Active / Pressed Terracotta inset shadow + translateY(1px) .dkw-btn-terra:active
Disabled 50% opacity, no pointer-events opacity: 0.5; pointer-events: none; cursor: not-allowed
Loading states
Context Implementation Token
Page/section loading Àṣẹ concentric pulse .dkw-ashe-loader
Progress completion Bolga coil ring .dkw-bolga-progress
Skeleton cards Shimmer gradient (background-size: 200%, position animation) background: linear-gradient(90deg, var(--surface-container) 25%, var(--surface-container-high) 50%, var(--surface-container) 75%); background-size: 200%; animation: shimmer 1.5s infinite
Connection status Copper wire flowing dashes .dkw-copper-line on SVG lines
Status states
Level Colour Hex (light/dark) Use
Critical Deep lavender-ground #5a1f0a / #cf6a45 Urgent ask — immediate help needed
High Rust #9c3b1b / #cf6a45 Time-sensitive ask — same-day response
Medium Gold #c8862a / #d4943a Standard ask — training, referral, connection
Low Forest green #2f5d44 / #5a9b78 Give offered — volunteer time, resources, skill
Empty states
/* Empty state: àṣẹ glyph as a placeholder icon + message */
.empty-state {
  text-align: center; padding: var(--dkw-space-3xl);
  color: var(--text-secondary);
}
.empty-state .icon {
  width: 64px; height: 64px; margin: 0 auto var(--dkw-space-lg);
  opacity: 0.4;
  /* Use the àṣẹ radiance SVG as background-image */
}
.empty-state p { font-size: 0.9rem; max-width: 28ch; margin: 0 auto; }
13K · Type

Typography in Practice

How the type scale applies to the emergency response UI. Georgia serif for emotional weight (headlines, stats, brand), sans-serif for utility (labels, nav, data).

/* Base type styles */
body {
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--text-primary);
}

/* Headings: Georgia serif for warmth + authority */
h1, h2, h3 { font-family: var(--font-serif); font-weight: 700; }
h1 { font-size: clamp(1.5rem, 4vw, 2.4rem); line-height: 1.1; }
h2 { font-size: clamp(1.2rem, 3vw, 1.9rem); }
h3 { font-size: 1.1rem; }

/* Dark mode heading glow */
.dark h1, .dark h2 {
  text-shadow: 0 0 12px rgba(212, 148, 58, 0.4);
}

/* Stats/numbers: serif at large size for impact */
.stat-number {
  font-family: var(--font-serif);
  font-size: 2rem; font-weight: 700;
  color: var(--accent);
}

/* Labels/kickers: sans, uppercase, tracked */
.label, .kicker {
  font-family: var(--font-sans);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-secondary);
}

/* Body: sans, readable */
.body-text { font-size: 0.85rem; line-height: 1.6; }
.body-text-sm { font-size: 0.78rem; color: var(--text-secondary); }

/* Ask/Give title */
.ask-title {
  font-size: 0.9rem; font-weight: 600;
  /* No serif — utility context, needs to scan fast */
}

/* Code/data */
.mono { font-family: var(--font-mono); font-size: 0.82em; }

/* Brand wordmark — hand-painted style (SVG strokes, not font) */
.brand-wordmark {
  /* Rendered as inline SVG with stroked paths */
  /* Text-shadow extrusion for depth: */
  text-shadow:
    1px 1px 0 #5a3e12,
    2px 2px 0 #3d2600,
    3px 3px 6px rgba(26,20,16,0.3);
}
Font loading strategy
Font Source Fallback Use
Georgia System (pre-installed) Times New Roman, serif Headings, stats, brand
Helvetica Neue System (macOS) / Arial (Windows) Arial, sans-serif UI, labels, body
SF Mono / Cascadia System Consolas, monospace Code, data values

Noto Sans is the body standard — required for the Volta Region languages: Ewe (ʃ, ɗ, ƒ), Dagbani (ŋ, ɣ), and Hausa (ɓ, ɗ, ƙ) carry extended-Latin glyphs that Helvetica and Arial do not include. Noto Sans is self-hosted as a subset woff2 (~40KB) served from our own CloudFront Accra edge — not the Google Fonts CDN — cached immutably so the cost is paid once, fast even on Volta 2G. font-display: swap avoids render-block. The brand wordmark uses SVG stroked paths for the hand-painted look (never a webfont). Headings fall back to Georgia / Noto Serif.

Drawn from: System fonts = immediate rendering, like how the signwriter uses paint already mixed on the palette. No waiting for a font to load = no FOUT = the text appears like a brush hitting plywood—instant, confident, one pass.

13L · Icons

Iconography

App icons drawn from our inspirations. Inline SVG, 24×24 viewBox, stroked (not filled) for crispness at small sizes. Colour via currentColor (inherits text colour per mode).

Report
àṣẹ radiance
Scan
QR grid
Response
time ring
Location
map pin
Connect
copper coil
Alert
àṣẹ pulse
Feed
sign panel
Divider
cornrow
Icon rules
Rule Implementation
ViewBox 24×24 (matches Material icon grid)
Stroke 2px for primary, 1.5px for secondary detail
Colour currentColor always — inherits from parent, adapts per mode
Fill Avoid — stroked icons are crisper at small sizes
Min size 24px display (inside 44px touch target)
Accessibility aria-hidden="true" when paired with text label; role="img" aria-label="..." when standalone
13M · Forms

Form Elements

Inputs, selects, textareas styled with the token system. All 44px min-height for touch, select-text re-enabled, focus ring via --accent.

Drawn from: Each icon derives from an inspiration: Report = àṣẹ radiance (sending energy outward), Scan = QR grid (structured data), Connect = copper coil (energy flowing), Alert = àṣẹ pulse (expanding urgency), Feed = sign panel (contained information), Divider = cornrow (rhythm separating).

/* Base input */
.dkw-input {
  width: 100%; min-height: 2.75rem; /* 44px touch target */
  padding: 0.6rem 0.75rem;
  font-family: var(--font-sans); font-size: 0.9rem;
  color: var(--text-primary);
  background: var(--surface-container);
  border: 1px solid var(--md-outline-variant, #d8cab2);
  border-radius: var(--dkw-radius-sm, 8px);
  transition: border-color 150ms, box-shadow 150ms;
  -webkit-user-select: text; user-select: text; /* re-enable text selection */
}
.dkw-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(200,134,42,0.2);
}
.dkw-input::placeholder { color: var(--text-secondary); opacity: 0.7; }
.dark .dkw-input {
  background: var(--surface-container);
  border-color: var(--md-outline-variant, #3a2a1d);
}
.dark .dkw-input:focus { box-shadow: 0 0 0 2px rgba(212,148,58,0.15); }

/* Label */
.dkw-label {
  display: block; font-size: 0.78rem; font-weight: 600;
  color: var(--text-secondary); margin-bottom: 0.3rem;
  text-transform: uppercase; letter-spacing: 0.04em;
}

/* Textarea */
.dkw-textarea { min-height: 6rem; resize: vertical; }

/* Select */
.dkw-select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1 L6 6 L11 1' stroke='%236b5d4f' stroke-width='2' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.5rem;
}

/* Error state */
.dkw-input--error { border-color: var(--severity-high, #9c3b1b); }
.dkw-input--error:focus { box-shadow: 0 0 0 2px rgba(156,59,27,0.2); }
.dkw-error-text { font-size: 0.72rem; color: var(--severity-high, #9c3b1b); margin-top: 0.25rem; }

/* Checkbox/Radio: custom using accent colour */
.dkw-checkbox {
  appearance: none; width: 20px; height: 20px;
  border: 2px solid var(--md-outline, #9a8a78);
  border-radius: 4px; cursor: pointer;
  transition: background 150ms, border-color 150ms;
}
.dkw-checkbox:checked {
  background: var(--accent); border-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='10'%3E%3Cpath d='M1 5 L4 8 L11 1' stroke='white' stroke-width='2' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center;
}

Drawn from: The input’s focus glow uses àṣẹ radiance (golden ring expanding from the point of attention). Error states use severity-high rust (clay pushed past its firing point). The checkbox tick is a single stroked path—one confident brush mark, like a signwriter’s check.

13N · Data

Data Visualization

Charts, badges, and data displays for the emergency response dashboard. On-brand severity palette only.

Status colour scale (ask urgency & give type — on-brand)
Critical #5a1f0a High #9c3b1b Medium #c8862a Low #2f5d44
Badge component
.dkw-badge {
  display: inline-block; font-size: 0.6rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.15rem 0.5rem; border-radius: 9999px;
}
.dkw-badge--critical { background: rgba(90,31,10,0.15); color: #5a1f0a; }
.dkw-badge--high { background: rgba(156,59,27,0.12); color: #9c3b1b; }
.dkw-badge--medium { background: rgba(200,134,42,0.12); color: #c8862a; }
.dkw-badge--low { background: rgba(47,93,68,0.12); color: #2f5d44; }

/* Dark mode: lighter text, same bg-opacity approach */
.dark .dkw-badge--critical { background: rgba(207,106,69,0.15); color: #cf6a45; }
.dark .dkw-badge--high { background: rgba(207,106,69,0.12); color: #cf6a45; }
.dark .dkw-badge--medium { background: rgba(212,148,58,0.12); color: #d4943a; }
.dark .dkw-badge--low { background: rgba(90,155,120,0.12); color: #5a9b78; }
Stat card
.dkw-stat {
  background: var(--surface-container);
  border: 1px solid var(--md-outline-variant);
  border-radius: var(--dkw-radius-md);
  padding: 0.75rem; text-align: center;
}
.dkw-stat .number {
  font-family: var(--font-serif);
  font-size: 1.8rem; font-weight: 700;
  color: var(--accent);
}
.dkw-stat .label {
  font-size: 0.65rem; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--text-secondary);
  margin-top: 0.2rem;
}
Map pin
/* Status-coded map pins */
.dkw-pin {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid #f7f2e9;
  box-shadow: 0 2px 4px rgba(26,20,16,0.3);
  position: absolute; transform: translate(-50%, -50%);
}
.dkw-pin--critical { background: #5a1f0a; }
.dkw-pin--high { background: #9c3b1b; }
.dkw-pin--medium { background: #c8862a; }
.dkw-pin--low { background: #2f5d44; }

/* Animated pulse ring for active asks */
@media (prefers-reduced-motion: no-preference) {
  .dkw-pin--active::after {
    content: ""; position: absolute;
    inset: -4px; border-radius: 50%;
    border: 2px solid currentColor; opacity: 0;
    animation: pin-pulse 2s ease-out infinite;
  }
  @keyframes pin-pulse {
    0% { transform: scale(0.8); opacity: 0.8; }
    100% { transform: scale(2); opacity: 0; }
  }
}
Ask/Give feed item (inspired by sign-panel + status band)
.dkw-card-feed {
  display: grid;
  grid-template-columns: 4px 1fr auto;
  gap: 0.75rem; align-items: start;
  background: var(--surface-container);
  border: 1px solid var(--md-outline-variant);
  border-radius: var(--dkw-radius-md);
  padding: 0.75rem;
  transition: box-shadow 200ms var(--md-motion);
}
@media (hover: hover) {
  .dkw-card-feed:hover { box-shadow: 0 2px 8px var(--glass-shadow); }
}
.dkw-card-feed .sev-bar {
  width: 4px; border-radius: 2px; align-self: stretch;
}
/* Severity colours applied via data-severity attribute */
.dkw-card-feed[data-status="urgent"] .sev-bar { background: #5a1f0a; }
.dkw-card-feed[data-status="timely"] .sev-bar { background: #9c3b1b; }
.dkw-card-feed[data-status="standard"] .sev-bar { background: #c8862a; }
.dkw-card-feed[data-status="give"] .sev-bar { background: #2f5d44; }
13Q · Product

Goals, Coverage & Connections

Ðekawɔwɔ connects people who need help with people and organizations who can give it. Coverage: Volta & Greater Accra regions of Ghana. The platform is community mutual support — not just emergency response.

Supported settlements
Tier Settlements
Major cities Ho · Aflao/Denu · Hohoe · Keta/Anloga · Kpandu
District capitals Sogakope · Dzodze · Akatsi · Adidome · Peki · Kpetoe · Dzolokpuita · Ve Golokwati · Ave Dakpa
Eco/tourism villages Amedzofe · Wli Agbama · Tafi Atome · Liati Wote · Agbozume · Dagbamatey · Anyako
Connection types (what the platform connects people to)
Category Key organizations Hubs
Workforce & training Ho Technical University, UHAS, Anlo Technical Institute, Agotime Kente Weavers Association, HCDP Ghana Ho, Anloga, Kpandu, Kpetoe
Agricultural incubation Adidome Farm Institute, EPDRA Adidome, Ho
Healthcare Ho Teaching Hospital, Battor Catholic Hospital, Gosanet Foundation, Pro-Link Ghana Ho, Battor, Hohoe
Inclusion & disability Voice Ghana, Gbi Special School for the Disabled Ho, Hohoe
Youth & women’s welfare Village Exchange Ghana, Values For Life-Ghana, Municipal Assemblies (LEAP) Ho, Aflao, all district capitals
Conflict resolution & traditional Anlo Traditional Council, Avatime Traditional Leadership, Apetorku Shrine Anloga, Vane, Dagbamatey
Eco-tourism & community dev Local Eco-Tourism Committees, Dream Big Ghana Foundation Tafi Atome, Wli Agbama, Liati Wote
Data sources
Source Use
StatsGhana / Data Commons APIs District boundaries, population baselines
API Ghana / HDX HAPI Public service coordinates (police, fire, hospitals)
Amazon Location Services Points of interest, geocoding, drop-a-pin reverse lookup
Core vocabulary
Term Meaning UI location
Ask A request for community support (any kind) Nav item, feed cards, action footer
Give An offer of help, resources, time, or skill Nav item, feed cards
Me Personal profile, history, preferences Nav item
Drop a pin Share your location with no other context. For hikes, runs, dangerous areas, or witnessing a situation. Friends/loved ones + authorities see the position. Prominent hero button above feed
Input modes (action footer)
Mode Icon Use
Type Pen/pencil stroke Text description of ask or give
Speak Microphone Voice recording (critical for low-literacy users)
Image Camera frame Photo of situation, resource, or location
Video Video camera Video capture for complex situations
Languages

English · Eʋegbe (Ewe) · Avatime · Logba · Tafi · Nyagbo · Sekpele · Siwu · Sélé · Akan · French

The language selector displays “Eʋegbe” as default text (acknowledging the primary local language), cycling through available options. Voice input (speak mode) supports all listed languages via device speech recognition.

13R · Layout

App Layout Components

Each component of the Ðekawɔwɔ app layout as a design-system-level specification. These are the building blocks for v0 generation. Live prototype →

Drop a Pin (hero action)
drop a pin share your location with no other context
Specs:
• Gold border (2px, --accent)
• Serif title, 1.3rem bold
• Animated pin with Ð-branded head
• Full-width, rounded-lg
• On tap: sends GPS coordinates only
• Dark mode: gold glow text-shadow
Action footer (static, 5 input modes)
pin type speak picture video
Specs:
• Static position (not floating)
• Glass backdrop-filter
• 5 buttons: pin | type | speak | picture | video
• Pin in tertiary (rust) — stands apart
• 44px min touch targets
• SVG icons (stroked, currentColor)
• safe-area-inset-bottom padding
Stats rows (regional + personal)
WITHIN 8 KM 3 open asks 7 gives nearby 43m avg response YOUR ACTIVITY 1 4 23
Regional (within 8km):
• Open asks · Gives nearby · Avg response
• Serif numbers (Georgia, bold, --accent)
• Cubism-stack depth (offset pseudo behind)

Personal (your activity):
• Your open ask · Your gives · Asks answered
• Same styling, smaller cards
• Both rows: uppercase label above
Feed card (ask/give)
Looking for kente apprenticeship Young person in Kpetoe seeking connection to weavers ASK 14 min ago 0.8 km IMG
Specs:
• 4px gradient status bar (left edge, full height)
• Title: 0.9rem, weight 600
• Description: 0.78rem, muted
• Meta row: status badge + time + distance
• Optional 56×56 thumbnail (right)
• Hover: box-shadow lift (desktop)
• Active: scale(0.98)
• Cornrow divider between items
• Entrance stagger animation
Navigation icons (inspiration-derived)
Home
àṣẹ eye
Ask
radiance
Map
framed pins
Give
flowing check
Me
person
Language selector
Eʋegbe English Eʋegbe ✓ Akan
Specs:
• Pill-shaped button in top nav
• Default text cycles through languages
• On click: dropdown with all 11 languages
• Selected language: accent colour + check
• Languages: English, Eʋegbe, Avatime, Logba, Tafi, Nyagbo, Sekpele, Siwu, Sélé, Akan, French
Cornrow hamburger
3 wavy lines (cornrow-inspired). Mobile only. Replaces generic ☰. Each line follows the same bezier curve rhythm as the --dkw-line-sign-cornrow token.
Map card with kente border
Volta & Greater Accra
13P · Implementation

v0 Prompt Guide

Ready-to-paste prompt blocks for v0. Each block follows Vercel’s framework: product surface + context of use + constraints. Copy any block directly into v0 to generate on-brand components.

Project Instructions (paste into v0 Settings → Instructions)
You are building Ðekawɔwɔ, a community mutual support platform for the Volta Region of Ghana. It connects people who need help (Ask) with people and organizations who can give it (Give). NOT just emergencies — training, healthcare, agriculture, eco-tourism, traditional welfare, youth services.

Design system tokens (use these EXACTLY):
- Primary: #c8862a (gold/ochre — kente thread warmth)
- Secondary: #2f5d44 (forest green — Volta grass)
- Tertiary: #9c3b1b (rust — fired terracotta)
- Background: #f7f2e9 (warm paper) / dark: #1a1410 (warm ink)
- Surface: #f0e8d8 / dark: #2d2118
- Text: #1a1410 / dark: #f7f2e9
- Muted: #6b5d4f / dark: #b9a888
- Border: #d8cab2 / dark: rgba(255,255,255,0.1)
- Error: #9c3b1b (rust, NOT generic red)
- Radius: 16px (cards), 8px (inputs), 9999px (pills/chips)

Typography:
- Headings: Georgia, serif (font-weight: 700)
- Body/UI: system sans-serif (Helvetica Neue, Arial)
- Stats/numbers: Georgia, serif at large size

Layout:
- Mobile-first. 1 col base → 2 col at 640px → 3 col at 1024px
- Nav rail (80px) on desktop, bottom nav on mobile
- 44px minimum touch targets. All interactive elements.
- Safe area insets via env(safe-area-inset-*)

Dark mode:
- Toggle via .dark class on html (or data-theme="dark")
- Dark is NOT inverted light — it's warm-ink (#1a1410) with brighter gold (#d4943a)
- Glow intensities halve in dark mode
- Headings get text-shadow: 0 0 12px rgba(212,148,58,0.4) in dark only

Interactions:
- Hover: ONLY inside @media (hover: hover) — never bare :hover
- Active/pressed: inset shadow (terracotta press)
- Focus: 2px solid #c8862a outline, offset 2px
- Loading: concentric pulse rings in gold
- All motion gated by prefers-reduced-motion

Use shadcn/ui components. Map tokens to shadcn variables:
--primary: #c8862a / --primary-foreground: #ffffff
--secondary: #2f5d44 / --secondary-foreground: #ffffff
--background: #f7f2e9 / --foreground: #1a1410
--card: #fffdf8 / --muted: #d8cab2
--border: #9a8a78 / --ring: #c8862a / --radius: 0.5rem

NEVER use:
- Generic red (#ff0000, #ef4444) or green (#00ff00, #22c55e) — use severity scale only
- Pure black (#000000) or pure white (#ffffff) for backgrounds
- Flat backgrounds — layer radial-gradient glows at corners
- Hover-only states without active/focus alternatives
Prompt: Full app shell
Build a community mutual support app with:
- Top nav bar (gradient background, Ð monogram logo, language selector showing "Eʋegbe")
- Nav rail on desktop (Home, Ask, Map, Give, Me)
- Bottom nav on mobile (Home, Ask, Map, Give)
- Main content area with responsive card grid
- Action footer (static, 5 buttons): drop-a-pin | type | speak | image | video
- "drop a pin" hero button above feed (animated Ð-branded pin, gold border, serif text)
- Stats row: "1 open ask · 4 gives offered · 23 answered · 43m avg response"
- Feed: cards with colour bar (left edge), title, description, time, distance. Mix of asks and gives.

Used by citizens in the Volta Region of Ghana,
on phones (mobile-first) at any time,
to ask for community support, offer help, or share their location with loved ones.

Constraints:
- Mobile-first, dark mode support
- Palette: gold #c8862a, green #2f5d44, rust #9c3b1b, ink #1a1410, paper #f7f2e9
- 44px touch targets, safe-area padding
- Severity: critical=#5a1f0a, high=#9c3b1b, medium=#c8862a, low=#2f5d44
- Georgia serif for headings/stats, sans-serif for UI
- shadcn/ui components with custom theme
Prompt: Auth flow (login/signup)
Build login and signup pages for Ðekawɔwɔ community support app.

Product surface:
- Login: email + password fields, "Sign in" button, "Forgot password?" link, "Create account" link
- Signup: email + password + confirm password, "Create account" button
- Both: Ð monogram logo above form, warm paper background with subtle grain texture

Used by Ghanaian citizens (varied tech literacy) on phones,
in a moment of calm (not during emergency — they sign up before they need it),
to create an account that lets them report asks later.

Constraints:
- Mobile-first. Form centered vertically. Max-width 400px.
- Inputs: 44px height, 8px radius, focus ring #c8862a
- Primary button: full-width, #c8862a background, pill radius
- Background: #f7f2e9 with faint grain overlay (feTurbulence)
- Error messages in #9c3b1b (not red)
- Password: min 8 chars, show/hide toggle
- Logo: inline SVG Ð monogram (rounded square, gold crossbar)
- Dark mode: #1a1410 background, brighter gold accent
Prompt: Ask/Give report flow
Build a multi-step "ask" flow for a community support app.

Product surface:
- Step 1: Choose input mode (type, speak, image, or video — 4 large buttons)
- Step 2: Provide context (text, voice recording, photo, or video)
- Step 3: Confirm location (auto-detected, manual adjust)
- Step 4: Confirm & send (summary card with content preview + location)
- Progress indicator at top showing 4 steps

Used by citizens in Accra/Volta Ghana on phones,
in a moment of need (not always urgent — could be seeking training, healthcare referral, or offering volunteer time),
to ask for community support or offer help.

Constraints:
- Mobile-only flow (full screen, no side nav)
- BIG touch targets (camera button 80px+, submit 56px height)
- Minimal text — icons + short labels
- Step indicator: 4 dots, active=#c8862a, complete=#2f5d44, pending=#d8cab2
- Camera button: FAB-style, #9c3b1b background (urgency colour), centered
- Textarea: warm surface background, gold focus ring
- Location map: dark ink background, gold pin
- Confirm card: kente-border top, severity auto-detected by AI shown as badge
- Submit button: full-width, gradient gold→ochre, large text
Prompt: Individual components
/* Severity badge */
Build a severity badge component with 4 variants: critical, high, medium, low.
- critical: bg rgba(90,31,10,0.15) text #5a1f0a
- high: bg rgba(156,59,27,0.12) text #9c3b1b
- medium: bg rgba(200,134,42,0.12) text #c8862a
- low: bg rgba(47,93,68,0.12) text #2f5d44
- Pill shape (border-radius: 9999px), uppercase, 0.6rem, font-weight 700
- Dark mode: lighter text variants (#cf6a45, #d4943a, #5a9b78)

/* Loading spinner */
Build a loading spinner: two concentric circles pulsing outward from centre.
- Outer ring: #c8862a, inner ring: #9c3b1b
- Animation: scale 0.5→1.8, opacity 1→0, 1.5s ease-out infinite
- Inner ring delayed 0.5s
- Gate inside @media (prefers-reduced-motion: no-preference)
- Fallback: static gold circle at reduced opacity

/* Ask/Give feed card */
Build an ask/give feed card with:
- 4px status colour bar on left edge (vertical, full height)
- Title (font-weight 600, 0.9rem)
- Description (0.78rem, muted colour)
- Meta row: status badge (ask/give) + time ago + distance
- Optional thumbnail (56x56, rounded 4px) on right
- Hover: subtle box-shadow lift (desktop only, @media hover:hover)
- Active: scale(0.98) press
Prompt: globals.css for v0 project
/* Paste this as your globals.css in a v0 project */
@import "tailwindcss";

@layer base {
  :root {
    --background: #f7f2e9;
    --foreground: #1a1410;
    --card: #fffdf8;
    --card-foreground: #1a1410;
    --popover: #fffdf8;
    --popover-foreground: #1a1410;
    --primary: #c8862a;
    --primary-foreground: #ffffff;
    --secondary: #2f5d44;
    --secondary-foreground: #ffffff;
    --muted: #f0e8d8;
    --muted-foreground: #6b5d4f;
    --accent: #f5deb3;
    --accent-foreground: #3d2600;
    --destructive: #9c3b1b;
    --destructive-foreground: #ffffff;
    --border: #d8cab2;
    --input: #d8cab2;
    --ring: #c8862a;
    --radius: 0.5rem;
  }
  .dark {
    --background: #1a1410;
    --foreground: #f7f2e9;
    --card: #231a12;
    --card-foreground: #f7f2e9;
    --popover: #231a12;
    --popover-foreground: #f7f2e9;
    --primary: #d4943a;
    --primary-foreground: #3d2600;
    --secondary: #5a9b78;
    --secondary-foreground: #0a2016;
    --muted: #2d2118;
    --muted-foreground: #b9a888;
    --accent: #5a3e12;
    --accent-foreground: #f5deb3;
    --destructive: #cf6a45;
    --destructive-foreground: #f7f2e9;
    --border: rgba(255,255,255,0.1);
    --input: #3a2a1d;
    --ring: #d4943a;
  }
}
v0 iteration tips for this design system
When v0 does this Say this to fix it
Uses generic red/green for status "Replace red with #9c3b1b and green with #2f5d44 — our palette, not traffic lights. These are ask/give status colours."
Flat background "Add radial-gradient glows at corners: rgba(200,134,42,0.16) at 8% 12%, rgba(47,93,68,0.14) at 92% 88%"
Bare :hover without media query "Wrap all hover styles in @media (hover: hover). Add :active with scale(0.98) for touch."
Pure black/white backgrounds "Use #1a1410 for dark, #f7f2e9 for light — warm, never pure"
Generic sans-serif headings "Use Georgia, serif for all headings and stat numbers. Sans only for UI labels."
Small touch targets "All interactive elements need min-height: 44px and min-width: 44px"
Missing dark mode "Add .dark class variant. Dark is warm-ink #1a1410 with brighter gold #d4943a. Add text-shadow glow on headings."
13O · Texture

Textures & Grain

Usable CSS texture patterns derived from our inspirations. Apply these as background overlays to break flat-surface monotony. All implemented as inline SVG filters or CSS gradients — zero external files.

Drawn from: plywood grain (sign panels), split veta vera fibre (baskets), fired clay surface (terracotta), elephant grass weave (Bolga), brushstroke body (sign painting), crackle glaze (kiln-fired pottery).

SVG noise grain (feTurbulence — the universal texture layer)
Fine grain
baseFrequency: 0.8
Medium grain
baseFrequency: 0.4
Coarse grain
baseFrequency: 0.15
Implementation
/* Universal grain overlay — inline SVG, zero network requests */
.dkw-grain {
  position: relative;
}
.dkw-grain::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0.3;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Variants via baseFrequency token */
--dkw-grain-fine: 0.8;    /* terracotta raw surface */
--dkw-grain-medium: 0.4;  /* plywood texture */
--dkw-grain-coarse: 0.15; /* elephant grass bundle */

/* Grainy gradient (grain + colour in one layer) */
.dkw-grainy-gradient {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='g'%3E%3CfeTurbulence baseFrequency='0.65'/%3E%3CfeColorMatrix values='0 0 0 9 -4 0 0 0 9 -4 0 0 0 9 -4 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"),
    linear-gradient(135deg, #c8862a, #9c3b1b);
  background-blend-mode: overlay;
}
Named texture tokens
Token Source inspiration CSS implementation Use case
--dkw-tex-plywood Sign panel substrate Vertical repeating-linear-gradient (varied widths, 0.06 opacity) Hero backgrounds, feature cards
--dkw-tex-fibre Veta vera split grass Vertical lines at 92deg, green/muted tones, 0.04 opacity Card overlays, subtle depth
--dkw-tex-clay Terracotta raw surface feTurbulence grain (baseFreq 0.8) at 0.3 opacity over warm fill Buttons, badges, containers
--dkw-tex-weave Kente interlace Crossing repeating-linear-gradients (90deg + 0deg) at low opacity Section backgrounds, borders
--dkw-tex-brushstroke Sign-painter body Thick wavy path SVG at 0.05 opacity as background-image Hero sections, pull quotes
--dkw-tex-crackle Kiln-fired pottery Random polyline SVG paths at 0.04 opacity (crack network) Aged/vintage elements, dividers
--dkw-tex-coil Bolga spiral Concentric circle SVG at 0.03 opacity behind circular elements Progress rings, avatars, badges
Mesh gradients (organic colour blending)
/* CSS mesh gradient approximation using radial-gradient layers */
.dkw-mesh {
  background:
    radial-gradient(ellipse at 20% 30%, rgba(200,134,42,0.4) 0%, transparent 50%),
    radial-gradient(ellipse at 80% 70%, rgba(47,93,68,0.3) 0%, transparent 50%),
    radial-gradient(ellipse at 50% 90%, rgba(156,59,27,0.25) 0%, transparent 40%),
    var(--surface-bg);
}

/* Animated mesh (ambient background) — gated */
@media (prefers-reduced-motion: no-preference) {
  .dkw-mesh-animated {
    background-size: 200% 200%;
    animation: mesh-drift 20s ease-in-out infinite alternate;
  }
  @keyframes mesh-drift {
    0% { background-position: 0% 0%; }
    100% { background-position: 100% 100%; }
  }
}
Scroll-driven texture reveal (CSS scroll-timeline)
/* Progressive texture reveal as user scrolls — modern CSS */
@supports (animation-timeline: scroll()) {
  .dkw-scroll-reveal {
    animation: reveal linear;
    animation-timeline: scroll();
    animation-range: entry 0% cover 40%;
  }
  @keyframes reveal {
    from { opacity: 0; filter: blur(4px); transform: translateY(20px); }
    to { opacity: 1; filter: blur(0); transform: translateY(0); }
  }
}

/* Fallback for browsers without scroll-timeline */
@supports not (animation-timeline: scroll()) {
  .dkw-scroll-reveal { opacity: 1; }
}
13D · Architecture

Three-Layer Token Inheritance

JSON primitives → semantic CSS variables (redefined per theme) → components read roles only. One theme class on <html>, inherited everywhere via the cascade. No prop-drilling, no JS re-render.

Drawn from: The severity bar on each feed card = the trotro colour band (identity stripe). Map pins pulse with the àṣẹ animation (active life-force at that location). The stat card’s large serif number = the bold painted number on a trotro route panel. Badges use the same border-radius logic as the Bolga rim binding.

The layers
Layer Format Contains Example
1 · Primitives design-tokens.json Raw values, no semantics "gold": "#c8862a"
2 · Semantic CSS custom properties Roles, redefined per .dark --accent: #c8862a
3 · Components CSS rules Read only Layer 2 tokens color: var(--accent)
Semantic tokens (the inheritance hinge)
:root {
  --surface-bg: #f7f2e9;
  --surface-container: #f0e8d8;
  --text-primary: #1a1410;
  --text-secondary: #6b5d4f;
  --accent: #c8862a;
  --accent-container: #f5deb3;
  --glass-bg: rgba(247, 242, 233, 0.82);
  --glass-border: rgba(156, 59, 27, 0.18);
  --glass-shadow: 0 6px 28px rgba(156, 59, 27, 0.15);
  --glow-primary: rgba(200, 134, 42, 0.16);
  --glow-secondary: rgba(47, 93, 68, 0.14);
}

.dark {
  --surface-bg: #1a1410;
  --surface-container: #2d2118;
  --text-primary: #f7f2e9;
  --text-secondary: #b9a888;
  --accent: #d4943a;            /* brighter gold on dark */
  --accent-container: #5a3e12;
  --glass-bg: rgba(26, 20, 16, 0.78);
  --glass-border: rgba(212, 148, 58, 0.15);
  --glass-shadow: 0 4px 24px rgba(212, 148, 58, 0.10);
  --glow-primary: rgba(212, 148, 58, 0.07);  /* half intensity */
  --glow-secondary: rgba(90, 155, 120, 0.06);
}
Key discipline
Rule Why
Dark mode is NOT inverted light Each mode independently designed. Light = warm paper + gold accent; dark = warm-dark + brighter gold, lower glow intensity.
One class, set once, inherited everywhere Flip .dark on <html> — cascade handles the rest. Never toggle per-component.
No hex values in component CSS Only var(--token). A rebrand = one token swap, not a hex hunt.
Accent can swap roles between modes The same logical token resolves to deliberately different values per mode. Asymmetry = designed, not generated.
13E · Surfaces

Ambient Backgrounds & Glassmorphism

A flat background is the single biggest "looks like a template" tell. Layer large, low-opacity radial gradients at different corners for ambient depth. Glass panels combine five properties.

Layered radial background
.shell {
  background-color: var(--surface-bg);
  background-image:
    radial-gradient(ellipse at 8% 12%, var(--glow-primary) 0%, transparent 35%),
    radial-gradient(ellipse at 92% 88%, var(--glow-secondary) 0%, transparent 35%),
    radial-gradient(ellipse at 50% 40%, var(--glow-tertiary) 0%, transparent 50%);
}
/* Dark mode: drop opacities by ~half (warm→garish on dark fields) */
Glass panel (5 properties, always together)
.glass {
  background-color: var(--glass-bg);
  backdrop-filter: blur(18px) saturate(1.15);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  box-shadow: var(--glass-shadow), inset 0 1px 0 rgba(255,255,255,0.4);
  isolation: isolate;
  overflow: hidden;
}

/* saturate() enriches bleed-through (not muddy)
   inset 0 1px 0 sells "glass" over "transparent box"
   isolation keeps stacking context clean */

@media (prefers-reduced-transparency: reduce) {
  .glass {
    background-color: var(--surface-container);
    backdrop-filter: none;
  }
}
Glows & shadows per mode
Element Light Dark
Headings no glow text-shadow: 0 0 12px rgba(212,148,58,0.4)
Wordmark layered 1-5px offset shadows (extrusion) same + outer glow ring
Logo drop-shadow(0 2px 4px ...) drop-shadow(0 0 6px rgba(212,148,58,0.3))
CTA buttons coloured box-shadow shadow + brightness(1.1) on hover
Section dividers gradient sheen ::before bar same, lower opacity
Gradient sheen divider
.sheen-hr {
  height: 2px; border: none;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
}
13F · Motion

Ambient Motion & Micro-interactions

Many slow, subtle, layered animations beat one fast flashy one. Long durations (6–30s) and low opacities keep it ambient. Every animation gated by prefers-reduced-motion. No exceptions.

Drawn from: Ambient radial gradients = the way afternoon sun falls through a workshop window in Ga Mashie—warm pools of light at the edges, never uniform. The glass panel’s saturate(1.15) = the way colours intensify when seen through a burnished clay surface. The sheen divider = a single gold thread catching light in kente cloth.

Pattern Duration Opacity Use
Ambient floating orbs 25–30s 0.035 Background life, behind everything (z-index:-1, blur:80px)
Entrance stagger 0.4s per card 1.0 Cards assemble in sequence (delay: 0.05s increments)
Shimmer sweep 24s subtle Top nav polish, barely perceptible
Card hover-lift 0.2s translateY(-2px) + 1° perspective tilt
Button glow 0.2s box-shadow grows on hover
Skeleton loader 1.5s 0.3–0.6 Moving gradient (background-size:200% + position animation)
@media (prefers-reduced-motion: no-preference) {
  .ambient-orb {
    position: fixed; z-index: -1;
    width: 40vw; height: 40vw;
    border-radius: 50%;
    filter: blur(80px);
    opacity: 0.035;
    animation: drift 28s ease-in-out infinite alternate;
  }
  @keyframes drift {
    from { transform: translate(0, 0); }
    to { transform: translate(3vw, 2vh); }
  }

  .card {
    animation: fade-up 0.4s ease-out both;
  }
  .card:nth-child(n) {
    animation-delay: calc(0.05s * var(--i, 0));
  }
  @keyframes fade-up {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
  }
}
Themed details that complete the system
Detail Implementation
Scrollbars ::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 9999px; }
Text selection ::selection { background: var(--accent-container); color: var(--text-primary); }
Focus ring :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
Gradient border headings border-image: linear-gradient(90deg, var(--accent), var(--glow-secondary)) 1
13G · Applied

Inspiration → Web Component

Each inspiration mapped to a tangible, reusable web element in the app. Live CSS + visual preview showing the token in context.

Feed & Layout
--dkw-line-sign-cornrow
Section divider
Alert: New report
--dkw-shape-trotro-badge
Notification toast
--dkw-fill-trotro-band
Severity indicator
--dkw-surface-kente-cloth
Card border pattern
Loading & Progress
--dkw-motion-ashe-pulse
Loading spinner
72%
--dkw-surface-bolga-spiral
Progress ring
--dkw-line-copper-stitch
Map connections
Buttons & Interactive
RESPOND
--dkw-fill-alum-shimmer
Button hover sheen
ACTIVE
--dkw-shadow-terra-relief
Pressed state
--dkw-surface-cubism-stack
Layered card
Surfaces & Containers
HERO SECTION
--dkw-surface-sign-plywood
Feature background
subtle texture overlay
--dkw-surface-grass-split
Card texture
FEATURED angular vessel
--dkw-shape-vessel-angular
Shaped container
--dkw-line-carve-gouge
Embossed divider
hides on scroll ↓
--dkw-line-silk-drape
Scroll-hide nav
CSS implementation for all 15 elements
/* Import the ready-to-use utility file: */
@import url("dkw-utilities.css");

/* Or cherry-pick individual tokens: */

/* Cornrow divider (between feed items) */
.dkw-cornrow-hr {
  border: none; height: 12px;
  background: repeating-linear-gradient(0deg,
    #6b5d4f 0 4px, transparent 4px 6px,
    #1a1410 6px 9px, transparent 9px 16px);
  mask: url("data:image/svg+xml,...") repeat-x;
}

/* Sticker badge (notifications) */
.dkw-sticker-badge {
  transform: rotate(-1.5deg);
  box-shadow: 3px 3px 0 #1a1410;
  border: 2px solid #1a1410;
  font-style: italic; font-weight: 700;
}

/* Shimmer button (hover effect on CTAs) */
.dkw-btn-shimmer { position: relative; overflow: hidden; }
.dkw-btn-shimmer::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(105deg,
    transparent 30%, rgba(217,164,65,0.4) 45%,
    rgba(216,202,178,0.6) 50%, rgba(217,164,65,0.4) 55%,
    transparent 70%);
  background-size: 250% 100%;
  transition: background-position 0.6s;
}
@media (hover:hover) {
  .dkw-btn-shimmer:hover::after { background-position: 100% 0; }
}

/* Àṣẹ pulse loader */
.dkw-ashe-loader { width: 48px; height: 48px; position: relative; }
.dkw-ashe-loader::before, .dkw-ashe-loader::after {
  content: ""; position: absolute; inset: 0;
  border-radius: 50%; border: 3px solid #c8862a;
  animation: dkw-pulse 1.5s ease-out infinite;
}
.dkw-ashe-loader::after { border-color: #9c3b1b; animation-delay: 0.5s; }
@keyframes dkw-pulse { 0%{transform:scale(.5);opacity:1} 100%{transform:scale(1.8);opacity:0} }

/* Bolga progress ring */
.dkw-bolga-progress {
  width: 48px; height: 48px; border-radius: 50%;
  background: conic-gradient(#c8862a var(--pct,0%), #f0e8d8 0%);
  display: grid; place-items: center;
}

/* Kente border (card decoration) */
.dkw-kente-border {
  border: 6px solid transparent;
  border-image: repeating-linear-gradient(90deg,
    #c8862a 0 8px, #2f5d44 8px 16px,
    #9c3b1b 16px 24px, #1a1410 24px 32px) 6;
}

/* Cubism layered card */
.dkw-card-stack { position: relative; }
.dkw-card-stack::before {
  content:""; position:absolute; inset:0; z-index:-1;
  background:#d8cab2; border-radius:inherit;
  transform: translate(4px,4px) rotate(1.5deg);
}
.dkw-card-stack::after {
  content:""; position:absolute; inset:0; z-index:-2;
  background:#6b5d4f; border-radius:inherit;
  transform: translate(8px,8px) rotate(3deg);
}

/* Copper wire connection (SVG) */
.dkw-copper-line {
  stroke: #c8862a; stroke-width: 2;
  stroke-dasharray: 6 4; fill: none;
  animation: wire-flow 1.5s linear infinite;
}
@keyframes wire-flow { to { stroke-dashoffset: -20; } }

/* Vessel clip-path container */
.dkw-vessel-shape {
  clip-path: polygon(10% 0%,90% 0%,100% 8%,100% 85%,92% 100%,8% 100%,0% 85%,0% 8%);
}

/* Glass panel */
.dkw-glass {
  background: var(--glass-bg);
  backdrop-filter: blur(18px) saturate(1.15);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  box-shadow: var(--glass-shadow), inset 0 1px 0 rgba(255,255,255,0.4);
}

/* Silk scroll-hide nav */
.dkw-silk-nav {
  position: fixed; top: 0; width: 100%;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.dkw-silk-nav--hidden { transform: translateY(-100%); }

/* Plywood texture overlay */
.dkw-plywood-bg::after {
  content:""; position:absolute; inset:0; pointer-events:none;
  background: repeating-linear-gradient(92deg,
    transparent 0, rgba(200,134,42,0.06) 2px,
    transparent 4px, rgba(107,93,79,0.04) 7px, transparent 9px);
}

/* Grass fibre overlay */
.dkw-grass-overlay::before {
  content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
  background: repeating-linear-gradient(92deg,
    transparent 0, rgba(47,93,68,0.04) 1px,
    transparent 2px, rgba(47,93,68,0.03) 5px, transparent 6px);
  mix-blend-mode: multiply;
}
14 · Roots

Inspirations & Design Tokens

105 named design tokens across 15 inspirations. Each tile = one reusable token. Each card ends with a composite visual showing all 7 working together. Naming schema →

Vernacular · Sign painting · Ga Mashie tradition

Hand-painted signage

Self-taught artists painting hairstyles, portraits and cultural commentary on plywood with acrylics. Each tile below defines a named design token with a live visual preview and implementation.

--dkw-text-sign-brush Brush-loaded lettering. Strokes vary in width (the brush lifts and presses). Paint drips at terminals where loading is heaviest.
--dkw-line-sign-cornrow Parallel wavy strokes: thick dark + thin highlight offset. Use as horizontal rule, card border-top, or section divider. The wave = natural row curve over the skull.
--dkw-surface-sign-plywood Warm wood grain as a background texture. Wavy horizontal lines (grain) + knot ellipse + paint-drip stain. Apply as a low-opacity overlay on cards or hero sections.
--dkw-fill-sign-block Bold flat-colour zones with thin white dividers. 3-4 colours max per composition. No gradients — each zone is one loaded-brush fill. Use for dashboard quadrants, card colour-coding, or section backgrounds.
STYLES STYLES Unisex Salon BRAIDS · CUTS · COLOUR Est. 2024 · Ga Mashie
--dkw-text-sign-stack Multi-style hierarchy: bold title with drop-shadow + italic subtitle + wavy rule + compact service list + corner brackets + small tagline. Every sign is a miniature typographic poster. Use for hero sections, feature headers, or landing page titles.
--dkw-surface-sign-stroke Visible brushstroke body: thick wavy paths with dry-brush highlight edges. The speed and energy of one-pass painting. Use as a background pattern for feature cards, hero sections, or button hover states.
NEW LOOK Barber & Salon
--dkw-shape-sign-panel Full bordered panel: gold edge, saturated background, portrait zone, dark text band below. The complete sign as a card archetype. Use for profile cards, feature announcements, or hero units.

Composite: all 7 tokens in one component

ÐEKAWƆWƆ ÐEKAWƆWƆ the making of one CHAMPION Est. 2024 · Accra
/* Token definitions */
--dkw-text-sign-brush: font-family: sans-serif; stroke-width varies 4-7px; paint-drip at terminals;
--dkw-line-sign-cornrow: repeating wavy paths (5px dark + 1.2px highlight, 16px apart);
--dkw-surface-sign-plywood: wavy horizontal lines (0.7px, 35% opacity) on #c8862a;
--dkw-fill-sign-block: 3-4 flat rects with 2px white dividers, no gradients;
--dkw-text-sign-stack: title(bold+shadow) + italic-sub + wavy-rule + compact-list + corners;
--dkw-surface-sign-stroke: thick wavy paths (12-16px) + 1px dry-brush highlight offset;
--dkw-shape-sign-panel: bordered rect, saturated bg, portrait zone top, text band bottom;

/* CSS implementation */
.sign-panel {
  background: var(--dkw-warm-gold);
  border: 2px solid var(--dkw-warm-gold);
  border-radius: var(--dkw-radius-sm);
  overflow: hidden;
}
.sign-panel .hero { background: var(--dkw-brand-accent-green); padding: 2rem; }
.sign-panel .text-band { background: var(--dkw-brand-ink); padding: 1rem; }
.sign-panel h2 {
  font-family: sans-serif; font-weight: 700;
  letter-spacing: 0.05em;
  text-shadow: 2px 2px 0 rgba(90,31,10,0.4);
  color: var(--dkw-warm-gold);
}
.cornrow-divider {
  height: 20px;
  background: repeating-linear-gradient(180deg,
    #6b5d4f 0 5px, #1a1410 5px 6px,
    #9a8a78 6px 7px, #1a1410 7px 16px);
}
Reference @handpaintedghana Atlas Obscura
Own palette-locked studies. Note: brush lettering rendered as SVG stroked paths (not a serif font) for authentic hand-painted feel.
Vernacular · Transport · Ga: three pence

Trotros & one-way stickers

Accra's privately-owned minibuses as rolling exhibition. Each tile defines a named design token.

"One People" One Direction
--dkw-shape-trotro-badgeRotated sticker with hard shadow. Use for toast notifications, badges, callouts.
Still Believe Community One People ONE WAY
--dkw-surface-trotro-palimpsestLayered overlapping stickers at varying opacity (age). Use for notification stacks, tag clouds, testimonial walls.
--dkw-fill-trotro-bandHorizontal tricolour accent stripe. Use as card divider, section separator, or progress indicator base.
"No Condition Is Permanent" — trotro wisdom
--dkw-text-trotro-sloganItalic serif proverb with accent-colour keyword + decorative underline. Use for pull quotes, testimonials, wisdom callouts.
--dkw-surface-trotro-dustWarm bottom-up haze gradient over muted ground. Use as a page-bottom fade, card footer overlay, or atmospheric background.
--dkw-shape-trotro-busRounded-rect vehicle with window insets + waistline band. Use as a container shape, illustration element, or loading placeholder.
--dkw-fill-trotro-fleetThree adjacent colour blocks at staggered heights — the fleet as a compositional rhythm. Use for comparative cards, pricing tiers, or feature columns.
"One People" One Direction "Still Believe"

Composite + implementation

/* Token CSS values */
--dkw-shape-trotro-badge: rotate(-1.5deg) + shadow 3px 3px 0 var(--dkw-brand-ink);
--dkw-surface-trotro-palimpsest: stacked rects, opacity 0.9/0.75/0.6 (age layers);
--dkw-fill-trotro-band: linear-gradient(0deg, #9c3b1b 0 36%, #d9a441 36% 64%, #2f5d44 64% 100%);
--dkw-text-trotro-slogan: font-style:italic; font-family:serif; text-shadow: 1px 1px 0 #d9a441;
--dkw-surface-trotro-dust: linear-gradient(0deg, rgba(200,134,42,0.5), rgba(107,93,79,0.2) 60%, transparent);
--dkw-shape-trotro-bus: border-radius: var(--dkw-radius-sm); + window insets as negative-space rects;
--dkw-fill-trotro-fleet: 3 adjacent blocks, heights staggered via clip-path or grid-row offset;
Reference MIT Atlas of Popular Transport
Own renderings. Slogans are illustrative, not transcribed from real vehicles.
Interaction · Easter egg · Inspired by Darko

AR QR easter eggs

Augmented-reality QR codes embedded in artwork — a still image that wakes into video when a viewer steps close. Kwasi Darko buries these in his painted car-door panels so the street exhibition carries a hidden digital layer. Seven studies of QR as a visual motif: the grid, the finder, the data field, and the scan moment.

--dkw-shape-qr-finder
Finder patterns —Three concentric squares at three corners orient the scanner regardless of rotation. The ratio 1:1:3:1:1 (black-white-black-white-black) is what any camera algorithm locks onto first. Reproduce with nested squares (fill-gap-fill) at three corners + alternating small squares connecting them (timing strip).
--dkw-surface-qr-grid
Data modules —The payload: each small square (module) is a single bit. They appear random but encode structured data with Reed-Solomon error correction. As a visual motif, the density and apparent randomness creates a texture unlike any organic pattern. Reproduce with a grid of small squares, ~40% filled, in two tones (primary + muted accent).
--dkw-motion-qr-scan
Scan beam —The moment of reading: a phone camera's scan line sweeps across the code. Corner brackets frame the viewfinder. The beam is the threshold between still image and live video. Reproduce with a bright horizontal rect + a vertical glow gradient around it + four corner bracket strokes (the scanner UI).
--dkw-surface-qr-embed
Embedded in paint —Darko's approach: the QR sits within the painted surface, not beside it. The code becomes part of the composition — discovered only when a viewer brings a phone close. Reproduce with a dark rounded rect (the code field) centred over a painted-stroke background + finder squares + scattered data modules.
--dkw-shape-qr-circle
Circular variant —Non-standard but visually arresting: data modules arranged on concentric rings around a central finder. Not scannable by standard readers, but as a motif it reads "code" while breaking the grid. Reproduce with a dark circle + concentric ring finder at centre + data modules distributed on radius arcs.
--dkw-motion-qr-dissolve
Grid → organic —The conceptual bridge: structured data dissolving into natural form. Left edge is pure grid; right edge is pure blob. The motif encodes the transition from digital layer to physical world that AR performs. Reproduce with a left column of square modules graduating (increasing border-radius, then full ellipses) toward organic shapes on the right.
← scan this
--dkw-surface-qr-hidden
Hidden in plain sight —The final trick: the QR reads as a decorative pattern on the door panel. Only a viewer who brings a phone close discovers the link. The code hides in the artwork's own visual language. Reproduce with rounded-rect modules in the same palette family as the background — low contrast, discoverable only by intent.
scan to reveal → hidden layer activates

Web element: QR reveal + camera scan

/* hover-reveal overlay */
.qr-reveal { position: relative; }
.qr-reveal .cover {
  position: absolute; inset: 0;
  background: var(--dkw-surface-inverse);
  opacity: 0.85;
  transition: opacity 0.3s;
}
.qr-reveal:hover .cover { opacity: 0; }

/* Capacitor barcode scan */
import { BarcodeScanner } from
  "@capacitor-mlkit/barcode-scanning";
const scan = async () => {
  const { barcodes } = await BarcodeScanner.scan();
  location.href = barcodes[0]?.rawValue;
};
Pattern reference QR code (structure) DW · Kwasi Darko segment
Decorative QR motifs — not scannable codes, purely visual reference.
Sculpture · Ga tradition · Proverb boxes

Abebuu adekai — fantasy coffins

The Ga tradition of figurative coffins — abebuu adekai, "proverb boxes." A fisherman rests inside a fish, a pilot inside an eagle, a clan elder inside a totem. Each coffin encodes a life in carved and painted wood. We draw the design principles — encoding identity in form, surface treatment, symbolic motif vocabulary — not specific works. Originated by Seth Kane Kwei in the 1950s, carried on by Paa Joe and the next generation. Seven studies of the form, the surface and the symbolic language.

--dkw-shape-vessel-taper
Fish form —The principle of directional movement encoded in a tapered form. Not a literal fish but the rhythm of arcs and a focal point suggesting flow. Reproduce with a pointed outline ellipse + internal arc repetitions + a focal dot.
--dkw-shape-vessel-pod
Cocoa pod —The origin form: Kane Kwei's first figurative coffin was a cocoa-pod shape for a cocoa farmer. Longitudinal ridges define the silhouette; the ripening gradient signals a life's fullness. Reproduce with a wide ellipse + nested ellipses for ridges + a stem path + a horizontal gradient (green→gold→red = unripe→ripe).
--dkw-fill-vessel-enamel
Enamel surface —The coffins are finished in high-gloss enamel paint — saturated, reflective, smooth enough to catch a specular highlight. Brush marks remain visible in raking light but the surface reads as lacquered. Reproduce with a solid saturated fill + a diagonal highlight gradient + faint horizontal lines (brush pull direction).
--dkw-surface-vessel-grain
Carved wood —Beneath the paint: wawa or onyina softwood carved with adze and chisel. Grain lines flow around knots; gouge marks from the curved chisel leave concave scallops. Reproduce with flowing wavy horizontal lines (grain) + an ellipse (knot) + a concave arc pair (gouge mark: dark cut + light edge).
--dkw-shape-vessel-crest
Cockerel head —The serrated crown motif abstracted from figurative sculpture — zigzag peaks rising from a rounded mass. A pure geometry pattern: the sawtooth silhouette signals importance. Reproduce with a zigzag polygon + an ellipse base + horizontal paint-stroke arcs.
--dkw-surface-vessel-motif
Motif vocabulary —Surfaces carry painted geometric motifs — concentric circles (watchfulness), crosses (direction), diamonds (endurance), spirals (journey). Not strictly adinkra but adjacent in grammar; the coffin-painter draws from a shared West African geometric lexicon. Reproduce with simple stroked geometric elements (circle+dot, cross, diamond polygon, spiral arc, zigzag border) on a saturated ground.
--dkw-shape-vessel-angular
Abstract vessel —A life encoded in geometric form — angular planes, internal facets, a symbolic core. The principle of containment shaped to meaning. Reproduce with a custom polygon + internal diagonals + a central motif.

Web element: clip-path shaped card

/* custom polygon container */
.shaped-card {
  clip-path: polygon(
    10% 0%, 90% 0%, 100% 12%,
    100% 88%, 90% 100%, 10% 100%,
    0% 88%, 0% 12%
  );
  padding: 2rem;
}

/* Tailwind */
<div class="[clip-path:polygon(10%_0%,90%_0%,
  100%_12%,100%_88%,90%_100%,10%_100%,
  0%_88%,0%_12%)] bg-[#c8862a] p-8">
  Shaped vessel
</div>
Reference & context Paa Joe Fantasy coffin tradition MFA Boston collection
Own form & motif studies in the Ðekawɔwɔ palette — the sculptural language, not any specific coffin.
Painting · Texture · Inspired by Kofi Agorsor

Layered cubism & mixed media

Paint built three and four layers deep — structural impasto where the surface is architecture, not just colour. Cubism claimed as an African freedom to fracture form "without boundaries." Charcoal, oil pastel, acrylic and found materials collide on one canvas. Seven studies of how material stacks, fractures and textures.

--dkw-surface-cubism-impasto
Impasto ridges —The palette knife drags paint across the surface in a single loaded pass — thick enough to cast its own shadow. The lit upper edge of each ridge reads as a second colour entirely. Reproduce with thick wavy stroked paths + a thin bright stroke offset 1px above each.
--dkw-line-cubism-hatch
Charcoal crosshatch —Fast angular strokes at 45° build tone through density, not through value. A second lighter pass crosses in opposition. The soft smudge where the palm rested is accidental and kept. Reproduce with two groups of diagonal line elements at opposing angles (different opacity/weight) + a soft ellipse for the palm smudge.
--dkw-surface-cubism-pastel
Oil pastel —Waxy, opaque, crayon-thick. Each stroke sits on top of the last without blending — the layering order is permanently visible. Paper grain pokes through as tiny bright specks where the wax didn't press in. Reproduce with very thick rounded stroked paths (16–20px) at reduced opacity + scattered tiny bright dots (the grain showing through).
--dkw-shape-cubism-facet
Fractured planes —The cubist fracture: space shattered into angular facets, each a different colour-value, reassembled as a flat puzzle. No vanishing point — every plane faces the viewer simultaneously. Reproduce with adjacent polygon elements filling the viewport, palette-varied fills, + thin bright edges on upper-left-facing seams (implied light direction).
--dkw-surface-cubism-collage
Collage edge —Mixed media: torn paper glued under paint layers, its text partially visible through translucent acrylic. The ragged tear-line is a compositional edge. Reproduce with an irregular zigzag path as a clip boundary between two fills + a semi-transparent rect with horizontal line strokes (the newspaper) + a thick paint stroke over it.
--dkw-surface-cubism-scrape
Palette-knife scrape —Paint applied thick, then scraped back with the knife edge — a subtractive gesture that reveals the layer below as a thin bright line. The scrape is as important as the application. Reproduce with horizontal colour bands of varied height/opacity over a base fill + thin bright horizontal lines between (the exposed underlayer).
--dkw-surface-cubism-stack
Full stack —All four layers visible at once: canvas weave at the bottom, big gestural acrylic planes (layer 1), charcoal drawing over the paint (layer 2), oil pastel highlight (layer 3), and a palette-knife scrape revealing through (layer 4). The painting's depth is its structure — each layer is a moment in time, permanently visible.

Web element: stacked depth card

/* offset pseudo-element layers */
.depth-card { position: relative; }
.depth-card::before {
  content: ""; position: absolute; inset: 0;
  background: var(--dkw-warm-rust);
  border-radius: inherit;
  transform: translate(6px,6px) rotate(1.5deg);
  z-index: -1;
}
.depth-card::after {
  content: ""; position: absolute; inset: 0;
  background: var(--dkw-warm-gold);
  border-radius: inherit;
  transform: translate(12px,12px) rotate(3deg);
  z-index: -2;
}
Reference & context Kofi Agorsor (Artsy) Agorsor — artist profile
Own technique studies in the Ðekawɔwɔ palette — the process, not any specific painting.
Cosmology · Bedrock · Yoruba

Àṣẹ — life force

The Yoruba concept of àṣẹ: "the power to make things happen," the invisible force connecting and animating everything. Afroscope's conceptual bedrock — and ours. Ðekawɔwɔ means "the making of one"; àṣẹ is the force that makes anything one at all. Seven visual readings of an invisible concept: radiance, connection, concentration, pulse.

--dkw-motion-ashe-radiance
Concentric radiance —Àṣẹ radiates outward from a source point — strongest at centre, fading but never disappearing. Reproduce with nested circles at decreasing opacity, centred on a solid bright dot. The spacing stays even; the fade is in opacity alone.
--dkw-line-ashe-web
Connection web —Everything tied to one source. Twelve radial lines from centre to edge nodes: the force flows equally in all directions, connecting every point. Reproduce with a central dot + evenly-spaced radial lines + small endpoint dots at the periphery.
--dkw-motion-ashe-pulse
Pulse —Àṣẹ as a single emanation: a pulse that expands outward, weakening into dashes as it travels. The arcs at the wavefront suggest outward motion. Reproduce with solid inner circle + dashed expanding circles + small arc strokes at cardinal points (the wave crest pushing outward).
--dkw-shape-ashe-network
Network —Àṣẹ as a connective tissue: every node linked both to the source and to each other. The force is not top-down but omnidirectional. Reproduce with a central node + peripheral nodes connected both radially (to centre) and laterally (to neighbours) forming a closed polygon + star pattern.
--dkw-motion-ashe-vortex
Vortex —The force spiralling: àṣẹ as a concentrating inward motion rather than a dispersing outward one. Energy funnelling into a single point where it becomes action. Reproduce with a multi-arm spiral path widening outward from a centre dot, alternating gold tones at decreasing opacity.
--dkw-shadow-ashe-aura
Aura —The force as warmth: soft layered glows intensifying toward centre. No hard edges — àṣẹ does not stop, it attenuates. Reproduce with nested filled circles at increasing opacity (largest=faintest, smallest=brightest) on a dark ground. The glow reads as heat or presence.
àṣẹ
--dkw-text-ashe-glyph
Glyph as motif —The word àṣẹ itself rendered as a brand-adjacent mark: the diacritics (à, ṣ, ẹ) become design elements. The underdot on ẹ echoes as a concentric ring below the word. Reproduce with the text in serif + faint concentric rings radiating from it + the underdot amplified as a dot-and-ring motif.
ashe

Web element: concentric pulse loader

@keyframes ase-pulse {
  0%,100% { transform: scale(1); opacity: 0.6; }
  50% { transform: scale(1.6); opacity: 0; }
}

/* React */
const AseLoader = () => (
  <div className="relative w-12 h-12">
    {[0, 0.2, 0.4].map((d, i) => (
      <span key={i}
        className="absolute rounded-full bg-[#c8862a]
          animate-ping"
        style={{ inset: i*8+"px",
          animationDelay: d+"s" }} />
    ))}
  </div>
);
Reference & context Àṣẹ (Wikipedia) DW · Afroscope segment
Own radiance & connection studies — the concept as visual motif.
Performance · Movement · Elisabeth Efua Sutherland

Aerial silks & movement

The body crossing fabric the way a shuttle crosses a warp — Elisabeth Efua Sutherland's Weaving in the Wild inserts embodied performance into Ghana's textile tradition. The silk is both apparatus and thread; the dancer's suspension maps the vertical tension of a loom. Seven studies of drape, tension, figure and weave.

--dkw-line-silk-drape
Hanging drape —Two silks from a single rigging point fall in natural catenary curves. The fabric is heavy enough to hang with weight but light enough to billow. Reproduce with two thick stroked paths from the top edge curving outward + thin dark fold shadows + thin bright highlight on the leading edge of each.
--dkw-shape-silk-wrap
Wrapped pose —The dancer wraps silk around torso and limbs, creating hold points where the fabric bears weight. The body is simultaneously supported and constrained — the wrap is architecture. Reproduce with a thick S-curved stroke path (the silk) + a stick figure within it + smaller crossing arcs where fabric wraps the body.
--dkw-line-silk-tension
Tension —At the grip point, all force concentrates into one hand-sized area. Below, the fabric fans into multiple tension lines — each carrying a portion of the body's weight. Reproduce with a bright dot (grip) + a vertical line above (to rigging) + 5 diverging lines below (the fanned fabric under load) + soft connecting arcs at the hem (slack between tension lines).
--dkw-shape-silk-invert
Inversion —Upside down: legs hooked in silk, head hanging free, arms open. The body's relationship to gravity reverses entirely. The silk holds from above while the figure falls toward the ground without reaching it. Reproduce with two thick fabric paths from top + an inverted stick figure (head at bottom) + small hook arcs where ankles grip fabric.
--dkw-line-silk-warp
Warp & weft —Sutherland's metaphor made literal: vertical silks are the warp threads of a loom. The body moving horizontally through them is the weft — the shuttle. Reproduce with vertical stroked lines (the silks/warp) + a horizontal figure crossing through them + small crossing marks at alternate intersections (over-under weave).
--dkw-motion-silk-billow
Billow —Fabric caught mid-release: filled with air for a half-second before gravity reclaims it. The silk holds volume like a sail. Internal fold lines show the trapped air; outer motion-blur traces the path it's falling from. Reproduce with two S-curved thick paths diverging (the catching silks) + thin internal fold arcs (air pockets) + faint outer traces (motion ghost).
--dkw-shape-silk-compose
Full composition —Everything together: twin silks falling from rigging, a figure suspended between them hands gripping each, the body as the weft crossing between two warp threads. The ground shadow below marks the height. Reproduce with two thick vertical S-curves (silks) + centred stick figure + connection lines from hands to fabric + a ground-shadow ellipse.

Web element: scroll-hide nav

/* silk-drape nav */
.silk-nav {
  position: fixed; top: 0; width: 100%;
  transition: transform 0.6s
    cubic-bezier(0.22, 1, 0.36, 1);
}
.silk-nav[data-hidden] {
  transform: translateY(-100%);
}

/* Hook: hide on scroll-down, show on up */
const [hidden, set] = useState(false);
useEffect(() => {
  let last = 0;
  const fn = () => {
    set(scrollY > last && scrollY > 80);
    last = scrollY;
  };
  addEventListener("scroll", fn);
  return () => removeEventListener("scroll", fn);
}, []);
Reference & context Elisabeth Efua Sutherland Aerial silk (apparatus)
Own movement & textile studies in the Ðekawɔwɔ palette.
Textile · Asante & Ewe

Kente cloth & weave

Interlocking strip-weaving where every pattern is named and every colour carries meaning — a non-verbal language in thread. Seven readings of the weave: the warp, the weft, the block, the motif.

--dkw-line-kente-warp
Warp stripes —The vertical foundation threads. Digital: evenly-spaced vertical bands in named-colour sequence.
--dkw-line-kente-weft
Weft bands —The horizontal threads carried across. Digital: horizontal bands crossing the warp at right angles.
--dkw-surface-kente-weave
Plain weave —Over-under checker of two colours. Digital: a 2-colour checkerboard, the atomic interlace unit.
--dkw-fill-kente-babadua
Babadua block —Ribbed weft floats over warp. Digital: dense horizontal bars + thin vertical accents = the raised "bamboo" block.
--dkw-shape-kente-diamond
Adweneasa motif —The "my skill is exhausted" all-over diamond figure. Digital: tessellated diamonds in two accent tones over a dark warp.
--dkw-line-kente-seam
Strip seam —Narrow woven strips sewn edge-to-edge, motifs deliberately offset. Digital: colour columns + dashed seam lines + staggered motif blocks.
--dkw-surface-kente-cloth
Full cloth —Warp, weft, blocks and motif combined. Digital: layered bands + warp accents + scattered diamond figures — the whole reading at once.

Web element: repeating border / divider

/* kente-strip divider */
.kente-hr {
  height: 6px; border: none;
  background: repeating-linear-gradient(90deg,
    #c8862a 0 8px, #2f5d44 8px 16px,
    #9c3b1b 16px 24px, #1a1410 24px 32px);
}

/* Tailwind */
<hr class="h-1.5 border-0
  bg-[repeating-linear-gradient(90deg,
  #c8862a_0_8px,#2f5d44_8px_16px,
  #9c3b1b_16px_24px,#1a1410_24px_32px)]" />
Reference & context Khan Academy · Kente
Own palette-locked weave studies — inspired by, not real cloth.
Craft · Bolgatanga · Gurunsi people

Bolga baskets

Veta vera elephant grass, split and twisted by hand in Bolgatanga, Upper East Ghana. The Gurunsi weave tight coiled spirals outward from a centre point, dye bands with local plant extracts, and finish with a leather-wrapped paired handle. The form is functional and geometric at once — a vocabulary of twill, coil, band and rim that translates directly into digital surface language.

--dkw-surface-bolga-twill
Twill close-up —Split straw passes over two, under one, stepping right each row. The diagonal emerges from the offset — never drawn explicitly, it's a byproduct of the weave rhythm. Reproduce with a staggered rect grid (18×12 blocks, half-step offset per row) over a warm straw base, plus faint horizontal grain lines.
--dkw-fill-bolga-band
Dye bands —The weaver dips bundled straw in boiled bark (red-brown), leaf extract (green) or mud (black) before weaving. Band width signals pattern vocabulary — narrow accent, wide field, narrow accent. Reproduce with horizontal rects of varied height + faint warp lines bleeding through from the undyed layer beneath.
--dkw-shape-bolga-spiral
Spiral centre —Every Bolga basket begins here — a single coiled rope of bundled straw, wound outward one revolution at a time. The base is flat, so the spiral stays in-plane until the weaver curves the wall up. Reproduce with a true spiral path (sequential arcs stepping outward) rather than concentric circles — the gap between coils narrows slightly toward the centre.
--dkw-surface-bolga-zigzag
Zigzag field —The weaver reverses the twill direction every few rows, creating a herringbone or zigzag. Named patterns (like zana — the mat) emerge from these reversals. Reproduce with tessellated triangles / diamond-halves filling each band, alternating palette tones.
--dkw-line-bolga-rim
Rim binding —The top edge rolls inward and wraps with a contrasting straw rope — structural reinforcement that doubles as a decorative band. Vertical wraps lock the basket wall to the rolled rim every ~16mm. Reproduce with a horizontal leather-toned band, two scalloped stroke paths inside it (the wrapping), and evenly-spaced vertical strokes binding wall to rim.
--dkw-shape-bolga-handle
Paired handle —Two thick straw ropes twisted together into an arch, seated into the basket wall and locked with a leather collar at the crown. The twist creates a diamond-pattern surface that grips the hand. Reproduce with two nested arch strokes (different widths = front/back rope), diagonal slash marks along each side (the twist), and a rounded rect at the crown with vertical stitch lines.
--dkw-shape-bolga-full
Full form —Everything together: the pot-shaped body built from outward-spiralling coils, dye bands as horizontal colour zones, faint radial warp lines, a rolled rim, and the paired arched handle with leather collar. The Bolga silhouette is unmistakable from across a room — round body, narrow mouth, high paired handle. Reproduce as a filled parabola (body) + ellipse (shadow) + dye-band overlays + rim stroke + nested handle arcs + collar rect.

Web element: conic-gradient progress ring

/* coil progress indicator */
.coil-ring {
  width: 5rem; height: 5rem;
  border-radius: 50%;
  background: conic-gradient(
    var(--dkw-brand-primary) var(--pct, 0%),
    var(--dkw-surface-2) 0%);
  display: grid; place-items: center;
}

/* React */
const CoilProgress = ({ pct }) => (
  <div className="w-20 h-20 rounded-full
    grid place-items-center"
    style={{ background:
      \ }}>
    <span className="w-14 h-14 rounded-full
      bg-white grid place-items-center
      font-bold">{pct}%</span>
  </div>
);
Reference & context CNN · Bolga weavers Garland Magazine On veta vera / kinkahe fibre
Own weave & form studies in the Ðekawɔwɔ palette.
Material · Fibre · Upper East Ghana

Veta vera grass & coiling

Elephant grass (Vetiveria zizanioides, locally kinkahe) grows tall and stiff in the savanna north of Bolgatanga. Harvested green, split by thumbnail into thin strips, sun-dried to golden, then twisted into rope and coiled outward — the entire basket vocabulary starts in this single grass blade. Seven studies of the raw fibre, from harvest to coil.

--dkw-surface-grass-split
Split straw —A single grass blade splits into 3–5 strips by thumbnail pressure along the central vein. Each strip is 2–4mm wide and dries to a slightly different tone — paler at the edge, richer at the pith. Reproduce with varied-width vertical rects in adjacent warm tones + thin dark gap lines between them.
--dkw-fill-grass-dyed
Dyed bundles —Stripped straw bundled and dipped: undyed (golden), boiled mango-bark (green), dawadawa-pod extract (rust-brown). The dye penetrates unevenly — tips darker, base lighter. Reproduce with three rounded-rect bundles at different palette fills + vertical grain lines + binding arcs holding each bundle.
--dkw-line-grass-twist
Twisted rope —The weaver rolls 4–6 split strips between palm and thigh to form a single rope. Two of these ropes then twist around each other to build the coil foundation. Reproduce with two phase-mirrored sine-like paths (stroke-width 6), the front path carrying a thin highlight.
--dkw-shape-grass-coil
Coil cross-section —Seen from the side: each coil sits atop the last, bound by a wrapping stitch of thinner straw. The binding pulls tight and compresses the coil slightly oval. Reproduce with stacked ellipses (each coil in cross-section) + small arc strokes between them (the bind) + an arrow indicating build direction.
--dkw-surface-grass-wet
Wet fibre —Before weaving, straw is soaked to make it pliable. Wet kinkahe darkens to olive-green and takes on a slight translucency. Reproduce with close-packed vertical strips in muted green/teal tones (darker than the dry golden) + a diagonal gradient for the water sheen.
--dkw-motion-grass-build
Coiling in progress —The active edge: the weaver feeds new rope alongside the previous coil, binding them together with a wrapping stitch pulled through with an awl (bicycle spoke). The loose end (dashed) waits to be folded into the next revolution. Reproduce with a spiral built from sequential arc segments + a dashed tail + small radial stitch marks between adjacent coils.
--dkw-surface-grass-dry
Sun-drying —Freshly split straw laid in rows on a flat surface to dry in savanna sun — each strip lightens from olive to gold over 2–3 days. The subtle colour variation in a finished basket traces back to this drying gradient. Reproduce with horizontal strip-rects on a light ground in varied warm tones + thin shadow gaps between rows.

Web element: organic grain texture overlay

/* fibre texture via pseudo-element */
.grain::after {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg,
    rgba(200,134,42,0.04) 0 3px,
    transparent 3px 7px);
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* Tailwind */
<div class="relative">
  <div class="absolute inset-0
    bg-[repeating-linear-gradient(90deg,
    rgba(200,134,42,0.04)_0_3px,
    transparent_3px_7px)]
    mix-blend-multiply pointer-events-none" />
  Content
</div>
Reference & context On veta vera / kinkahe fibre Garland Magazine · weaving process
Own fibre & process studies in the Ðekawɔwɔ palette.
Material · Metal · flattened & folded

Aluminium

The flattened liquor-bottle cap and seal — light, reflective, infinitely repeatable. Before it is stitched into anything, aluminium is its own material: foil-bright, crimped, scored, oxidised. Seven readings of the metal and how its shimmer survives a flat palette.

--dkw-surface-alum-caps
Cap field —Tessellated flattened caps, brick-offset. Digital: a repeating rounded-rect grid, rows offset by half a cell, palette-cycled fills.
--dkw-line-alum-crimp
Crimp ridges —The fluted edge of a bottle cap. Digital: alternating bright/dark vertical stripes + thin white specular line on each ridge crest.
--dkw-surface-alum-brush
Brushed grain —Directional polish on raw aluminium. Digital: many fine horizontal lines, two tones, slight waver for hand-finished feel.
--dkw-fill-alum-shimmer
Specular shimmer —The opalescent flash of foil catching light. Digital: a multi-stop diagonal gradient with sharp light/dark transitions on a warm base.
--dkw-surface-alum-punch
Punctured —Holes pierced for the wire to pass. Digital: a dot-grid of dark circles with a faint lit upper rim = pierced-through depth.
--dkw-fill-alum-patina
Oxidised —Weathered metal blooms green-grey. Digital: soft organic patches of muted green/teal over a grey-metal base, low opacity.
--dkw-surface-alum-fold
Folded drape —Stiff sheet made to ripple. Digital: stacked wavy horizontal bands + thin specular line on each fold crest = rigid-cloth illusion.

Web element: foil-shimmer hover

/* moving highlight on hover */
.shimmer {
  position: relative; overflow: hidden;
}
.shimmer::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(105deg,
    transparent 40%,
    rgba(255,255,255,0.5) 45%,
    transparent 50%);
  background-size: 250% 100%;
  transition: background-position 0.6s;
}
@media (hover:hover) {
  .shimmer:hover::after {
    background-position: 100% 0;
  }
}
Material context El Anatsui (the artist who reads this metal as cloth)
Own texture studies — the aluminium material on its own terms. Inspired by, not a copy.
Material · Wire · the binding thread

Copper wire

The thread that holds the cloth together — pliable, warm-toned, structural. Copper wire is the joinery: it loops, twists, coils and meshes. It stays bendable, so the finished sheet can be re-draped each time it hangs. Seven readings of wire as line, weave and connection.

--dkw-line-copper-coil
Coil —A single wire wound in a spring. Digital: two phase-shifted sine paths (front/back of the loop) + a thin highlight on the front strand.
--dkw-line-copper-twist
Twisted pair —Two strands wound around each other. Digital: two mirrored sine paths per twist, alternating which crosses in front.
--dkw-surface-copper-mesh
Mesh —Wires crossing at right angles, knotted at nodes. Digital: two stroke sets + small dark dots at intersections = tied joints.
--dkw-shape-copper-chain
Interlinked loops —Rings hooked through rings, chainmail-style. Digital: offset circle rows, half-step shifted, faint highlight rim on the top row.
--dkw-surface-copper-tangle
Tangled nest —Loose wire bundled freely. Digital: several overlapping bezier loops in palette tones, no grid — controlled chaos.
--dkw-fill-copper-verdigris
Verdigris —Copper greening as it ages. Digital: warm copper strands transitioning to muted green/teal, with soft patina blooms.
--dkw-line-copper-stitch
Stitch binding —Wire sewing caps edge-to-edge — the actual join in the cloth. Digital: cap blocks + looping stitch arcs + dark knot dots between them.

Web element: animated connection line

@keyframes wire-flow {
  to { stroke-dashoffset: -20; }
}

/* SVG line between two nodes */
<svg class="absolute inset-0 w-full h-full
  pointer-events-none">
  <line x1="20%" y1="50%" x2="80%" y2="50%"
    stroke="#c8862a" stroke-width="2"
    stroke-dasharray="5 5"
    style="animation: wire-flow 1s linear infinite;
    filter: drop-shadow(0 0 3px
      rgba(200,134,42,0.4))" />
</svg>
Material context The Met (copper-wire joinery in Anatsui's work)
Own texture studies — copper wire as line, weave and binding. Inspired by, not a copy.
Composite · Inspired by El Anatsui

Metal cloth — aluminium & copper, together

When flattened cap meets binding wire, rigid metal learns to drape like fabric. The whole exceeds its parts: thousands of small hard units, one fluid hanging cloth. Seven studies of the composite — how the two materials combine, drape, fold and catch light as a single surface.

--dkw-surface-cloth-bound
Bound units —Caps as cells, copper as seam. Digital: the cap grid + small green-copper stitch arcs bridging every vertical gap.
--dkw-motion-cloth-drape
Draped cloth —The hanging sheet's rolling hills. Digital: stacked wavy bands following one drape contour, specular line on lit crests.
--dkw-line-cloth-contour
Topographic —The cloth read as a contour map of metal. Digital: nested contour lines climbing in palette order, dark valley fill below.
--dkw-fill-cloth-strip
Strip blocks —Sections of differing caps create colour fields, interrupted by contrast strips. Digital: horizontal colour bands + copper seam rows + vertical dark interruptions.
--dkw-shape-cloth-valley
Folded valley —A sharp crease where the cloth bends. Digital: four triangles meeting at one vertex, lit edges up, shadow seam down.
--dkw-fill-cloth-wash
Light wash —The whole sheet catching one raking light. Digital: cap grid in shadow + a single diagonal specular gradient laid over everything.
--dkw-surface-cloth-full
Full tapestry —Everything together: varied caps, drape-shifted rows, a hanging bottom edge. The composite as one cloth.

Web element: fabric-fold page exit

/* perspective fold transition */
@keyframes cloth-fold {
  to {
    transform: perspective(800px) rotateX(-90deg);
    opacity: 0;
  }
}
.page-exit {
  transform-origin: top;
  animation: cloth-fold 0.7s
    cubic-bezier(0.4,0,0.2,1) forwards;
}

/* Tailwind + conditional class */
<div className={show ? "" :
  "[transform:perspective(800px)_rotateX(-90deg)]
  opacity-0 transition-all duration-700
  [transform-origin:top]"}>
  Page content
</div>
Reference & context El Anatsui The Met Britannica
Own composite studies in our palette — inspired by Anatsui's method, not a copy of any specific work.
Material · Earth · inspired by Nkyinkyim craft

Terracotta & clay

The material itself — fired earth and worked clay — and the hand that carves and molds it. We draw the aesthetic of the Nkyinkyim Museum's sculptural craft: the surface, the incision, the relief, the coil. Seven ways to read terracotta texture and translate it into digital surface.

--dkw-surface-terra-raw
Raw surface —Warm base + dual-tone speckle (dark grog, light temper). Digital: 2-layer noise, low-opacity dots over a flat clay fill.
--dkw-fill-terra-burnish
Burnished —Polished-stone smoothing leaves tonal bands + a directional sheen. Digital: horizontal tone bands + a diagonal highlight gradient.
--dkw-line-terra-incise
Incised lines —Grooves cut into leather-hard clay. Digital: dark stroke + a 1px light stroke just below each = carved-shadow illusion.
--dkw-shadow-terra-relief
Relief —Raised form lit from upper-left. Digital: light edge top/left, dark edge bottom/right on every raised shape.
--dkw-surface-terra-coil
Coil-built —Stacked clay ropes leave horizontal ridges. Digital: thick stroked arcs + a thin highlight arc on the upper edge of each coil.
--dkw-surface-terra-finger
Fingermarks —Thumb presses leave shadowed dimples with a lit rim. Digital: dark ellipse + offset lighter ellipse inside = pressed-in depth.
--dkw-surface-terra-crackle
Fired crackle —Kiln stress + temper grit. Digital: thin irregular crack polylines + sparse dark speckle over a hotter fired tone.

Web element: warm pressed-button

/* terracotta press effect */
.terra-btn {
  background: var(--dkw-warm-terracotta);
  box-shadow: 0 4px 12px rgba(156,59,27,0.4);
  transition: all 0.15s;
}
.terra-btn:active {
  box-shadow: inset 0 2px 6px rgba(0,0,0,0.3);
  transform: translateY(1px);
}

/* Tailwind */
<button class="bg-[#b85333]
  shadow-[0_4px_12px_rgba(156,59,27,0.4)]
  active:shadow-[inset_0_2px_6px_rgba(0,0,0,0.3)]
  active:translate-y-px transition-all">
  Press
</button>
Aesthetic reference Nkyinkyim Museum (craft & material)
Own texture studies — fired earth and the carving hand.
Process · Hand · Subtractive & additive

Carving & molding

The physical act beneath every material in this system — chisel into wood, thumb into clay, knife into form. Subtractive (removing) and additive (building up) processes leave their own irreducible textures: gouge marks, press dents, chip scars, smoothed planes. Seven studies of tool meeting material.

--dkw-line-carve-gouge
Chisel gouges —A curved chisel scoops concave channels — each pass leaves a dark shadow at the cut and a lit rim where the material curves back. The rhythm is the carver's breath. Reproduce with paired arcs: a thick dark one (the cut) and a thin lighter one immediately below (the lit edge of the scallop).
--dkw-surface-carve-adze
Adze facets —A flat adze blade chops broad planes — each swing removes a chip and leaves a flat facet meeting the next at a ridge. The surface reads as a series of tilted planes catching light at different angles. Reproduce with angled line pairs (the ridges) + polygon fills alternating slightly lighter/darker (the tilted planes).
--dkw-shadow-carve-press
Thumb press —Direct hand in clay: the thumb pushes a depression, displacing material into a raised lip around the hole. The gesture is the most basic additive-surface tool — before any instrument, the hand. Reproduce with offset ellipse pairs: a larger darker one (the shadow in the depression) + a smaller lighter one overlapping above (the lit interior floor of the press).
--dkw-line-carve-knife
Knife cut —A sharp blade slices clean: one stroke separates two planes. The exposed face is fresher/lighter than the weathered outer surface. Fine score lines from the blade's edge angle read as directional marks. Reproduce with a diagonal polygon boundary (the cut plane) + a dark line (shadow at the cut) + a thin bright line above (lit edge) + fine angled lines on the exposed face (blade marks).
--dkw-surface-carve-smooth
Smoothed plane —After rough shaping: the surface is sanded or polished until tool marks disappear. Only the faintest grain direction and a satin sheen remain. This is the canvas waiting for paint. Reproduce with a flat fill + barely-visible wavy horizontal lines (residual grain) + a very subtle directional gradient (the satin finish).
--dkw-surface-carve-chips
Chip scatter —The workshop floor evidence: every subtracted piece falls and accumulates. Flat chips (from adze), curled shavings (from gouge), and splinters. The scatter is the negative image of the form being made. Reproduce with randomly rotated small polygons (flat chips) + leaf-shaped paths (curled shavings) in warm tones on a dark ground.
--dkw-surface-carve-stamp
Tool impressions —Found objects pressed into wet clay as stamps: a stick (straight line), a shell edge (scalloped arc), twisted rope (zigzag channel), a fingertip (broad groove), a hollow reed (circle), a stick end (dot grid). Each leaves a unique mark vocabulary. Reproduce with various stroke patterns (lines, arcs, waves, circles, dots) in a shadow tone + a thinner lighter stroke offset above each (the lit impression floor).

Web element: embossed / debossed text

/* carved text shadows */
.embossed {
  text-shadow:
    1px 1px 1px rgba(255,255,255,0.6),
    -1px -1px 1px rgba(0,0,0,0.3);
}
.debossed {
  text-shadow:
    -1px -1px 1px rgba(255,255,255,0.5),
    1px 1px 2px rgba(0,0,0,0.4);
}

/* Tailwind */
<p class="[text-shadow:1px_1px_1px_rgba(255,255,255,0.6),
  -1px_-1px_1px_rgba(0,0,0,0.3)]">
  Embossed
</p>
Context Paa Joe (wood carving) Nkyinkyim Museum (clay + concrete craft)
Own process studies — the hand meeting material.
15 · Workshop

Build Process & MCP Tooling

A design system documents not just the artifact but the workshop that made it. Ðekawɔwɔ was built with AWS Kiro CLI driving a set of Model Context Protocol (MCP) servers — live AWS access, current documentation, and a persistent memory layer — coordinated by custom agents. This section records that toolchain so the craft is reproducible, the same way a carver's bench tells you how the bowl was cut.

⚡ AWS MCP Server

live · authenticated AWS

The GA managed AWS MCP Server (via mcp-proxy-for-aws) gives the agent authenticated access to 15,000+ AWS APIs plus current documentation — bridging local IAM SigV4 credentials to the server. It is why this project's database claims are grounded in what AWS ships today, not a model's training cutoff: Aurora DSQL region sets, DynamoDB MRSC, Aurora Global Database limits were all verified through it.

call_aws run_script search_documentation read_documentation retrieve_skill get_regional_availability
profile: bryanchasko-kiro (AI/ML) · us-west-2 sandboxed run_script: no net, no fs, inherits IAM read-only default; mutation gated on approval

📚 Context7

live · current library docs

Context7 retrieves up-to-date documentation and code examples for any library or framework at query time. Used to ground the Aurora Serverless v2 and autoscaling facts (Terraform AWS RDS Aurora module) and to cross-check Next.js / Vercel edge patterns. Two-step protocol: resolve the library ID, then query the docs.

resolve-library-id query-docs
bridge: supergateway --streamableHttp :8130/mcp/ --outputTransport stdio

🧠 Qdrant Agent Memory

persistent · cross-session memory

A Qdrant vector store holds the agent's working memory across sessions. Project state, the strict brand and vocabulary rules, the corrected DSQL region-set facts, and pointers to specs are written here at the end of a session and recalled at the start of the next. This is how a custom agent picks up exactly where it left off after a CLI restart — semantic recall, not a flat log.

qdrant-store qdrant-find
collection: agent-memory · semantic search bridge: supergateway :8102 → stdio

📁 Filesystem

live · scoped file access

Host-scoped filesystem servers (one per machine: rocm-aibox Linux, mac mini macOS) let the agent read and write project files directly, with path scoping enforced per host so a read on one machine never reaches the other.

read_text_file write_file directory_tree

🔗 Docker MCP

live · container control

Container lifecycle for the local MCP stack and any project services. The persistent HTTP MCP servers (Qdrant, Context7, Valkey, Jaeger) run as Docker containers on rocm-aibox, each fronted by a stdio bridge launcher.

list_containers run_container fetch_container_logs

📊 Valkey & Jaeger

live · state + observability

Valkey (Redis-compatible) carries fast key/value + data-structure state; Jaeger captures OpenTelemetry traces of the build session itself. Together they make a multi-agent session observable — which agent ran, what it called, how long it took.

string_get/set find-traces get-services

How this was built — Kiro CLI + custom agents + Qdrant as memory

Ðekawɔwɔ was built by developers driving AWS Kiro CLI with custom agents whose behavior, scope, and tool access are defined in version-controlled configuration, and a Qdrant vector store serving as durable cross-session memory. The loop that produced every artifact in this design system:

1A custom agent config declares the agent's tools, file-write scope, and the MCP servers it may reach. The agent loads steering rules — the strict brand palette, the ask/give/wish vocabulary, the cultural-inspiration requirement — as persistent context.
2At session start the agent calls qdrant-find to recall prior project state: what was built, what Bryan corrected, which facts were verified. No cold start — it resumes mid-thought.
3During the session it grounds AWS claims through the AWS MCP Server and library facts through Context7, writes files through the scoped filesystem server, and deploys previews to S3 + CloudFront — verifying each step rather than asserting it.
4At session end it calls qdrant-store to persist new state and a pointer to any spec it authored (for example the AWS MCP usage spec at docs/aws-mcp-usage-spec.md), so the next session — even after a CLI restart that loads new MCP configs — opens with full continuity.

The result is craftsmanship that compounds: rules live in config, memory lives in Qdrant, facts come from live AWS, and every claim in this system traces back to something verified — the digital equivalent of a workshop where every tool has its place and every cut is deliberate.

16 · Atelier

Kiro & AI Build Investment

This design system exists because the team invested tooling in it. Beyond writing prompts, the developers built a production AI workshop — multiple AWS Kiro CLI power-user accounts, MCP servers, Firecracker microVMs, and a self-hosted video-transcription pipeline running on an AMD GPU — to research the diverse cultures of the Volta Region rigorously enough that Ðekawɔwɔ would be visually pleasing and intuitive to the people it serves. This card is itself an example of that: it was assembled from a transcribed reference video and corrected through research.

The investment behind the system

Planning, organization, and prototyping ran on a deliberate AI build stack — not a single chat window. The cost was committed up front so the research could be deep instead of shallow.

Kiro power-user accounts · $200/mo each
Kiro Pro Max account
MCP
live AWS, docs, memory servers
Firecracker
microVM isolation for build jobs
AMD GPU
self-hosted video transcription pipeline

The video pipeline runs on an AMD Radeon GPU (ROCm) to organize cultural-reference video: OpenAI Whisper for audio transcription, AMD Instella-VL-1B for frame-by-frame visual analysis, then web research to correct phonetic transcription errors and verify names against gallery and museum records. That pipeline is how the reference below became structured, citable source material.

video URL → yt-dlp → ffmpeg (AMD/ROCm) → Whisper transcript → Instella-VL-1B frame analysis (362 frames) → web-research correction → narrative + design tokens
Reference video transcribed by the pipeline — Accra's Vibrant Contemporary Art Scene, Art.See.Africa / Deutsche Welle. Source: YouTube · DW. Full curated narrative: ghana-art / accra-contemporary-art.

What the pipeline surfaced — one artist whose work maps directly onto Ðekawɔwɔ's home ground (the Volta weaving communities) and the kente / aerial-silks inspiration tokens in this system:

Artist 05 · Performance

Elisabeth Efua Sutherland

Weaving in the Wild — aerial silks, dance-theatre, and the textile tradition of Ghana

Sutherland dances, choreographs, writes and directs from Accra, carrying a BA in Theatre from DePauw and an MA in Performance from Brunel. She founded Terra Alta, an Accra performance hub, in 2017. Weaving in the Wild fuses aerial silks, dance-theatre and a thread of physical theatre to probe Ghana's weaving heritage.

On the composition

Sutherland engineered it to travel — she will stage it in the weaving communities of the Volta region, before the people who make the cloth, so performance and subject breathe the same room. She drives her own body into kente weaving, a craft long reserved for men, contesting that gendering from inside the loom rather than outside it. She aims to bind young people to their culture through movement — "we, as Africans, we default to dance." The silk doubles as apparatus and woven thread, the dancer crossing it the way a shuttle crosses a warp.

"We, as Africans, we default to dance."
performance aerial silks kente / textile gender & tradition

References

Themes that run through

Everything is artAyim's spine: creativity lives on minibus panels, in coffin shapes, in how a person dresses. Darko and Paa Joe build straight from this premise.
Inheritance & the futureEvery studio stands against the weight of slavery and colonialism, against the open question of a Ghanaian future. Stated as thesis at the start, answered at the shore.
Reclaiming formsAgorsor seizes Cubism "as an African." Afroscope resurrects erased knowledge through machine learning. Sutherland drives a woman's body into a male weaving craft.
Non-verbal languagePaa Joe's coffins, Darko's one-way stickers, Sutherland's choreography, Afroscope's àṣẹ — meaning carried without a single word spoken.

MCP Toolkit — Agent Wiring

How Ðekawɔwɔ connects Kiro CLI to v0 and AWS via the Model Context Protocol. Reference configs, launcher patterns, and the mcp-remote bridge that wires Kiro (not on Vercel's official client list) to v0's generation API.

Tooling · MCP · Kiro ⇆ v0

v0 MCP × Kiro CLI

How we connected Vercel's v0 MCP server to the Kiro CLI agent — even though Kiro is not on Vercel's official supported-clients list. The trick: v0's server speaks Bearer-token auth, and mcp-remote bridges any stdio MCP client to it. Seven readings of the pattern: the server, the gap, the wiring, the launcher, the config, the tools, and the payoff.

mcp.v0.dev
The server —Vercel's official MCP endpoint at https://mcp.v0.dev. Five tools: create_chat, send_message, get_chat, list_chats, find_chats. Auth is a Bearer token (V0_API_KEY). Distinct from Vercel MCP (mcp.vercel.com), which is OAuth-only and allowlisted-clients-only.
kiro not on list
OAuth allowlist
The gap —Vercel MCP (mcp.vercel.com) only admits pre-approved clients: Claude, Cursor, Copilot, Goose, Windsurf, Gemini CLI… Kiro is not on that list. But v0 MCP (mcp.v0.dev) uses Bearer-token auth instead of OAuth — so it works with any stdio MCP client, Kiro included.
SSM → mcp-remote
The wiring —The v0 API key lives in AWS SSM at /heraldstack/mcp/v0-api-key (SecureString, profile bryanchasko-kiro, us-west-2). A launcher fetches it at runtime via get-parameter --with-decryption, then runs npx mcp-remote with a --header flag injecting the Bearer token. mcp-remote bridges stdio ⇆ Streamable HTTP. No static env var in the shell profile — the key only lives in SSM.
launchers/v0.sh
The launcher —A small bash script fetches the key from SSM into a local variable and execs mcp-remote against https://mcp.v0.dev with the Authorization header. The full script is shown below the grid.
{ }
mcp.json
The config —The kiro-cli mcp.json registers v0 as a bash -c command pointing at the launcher. run.sh dispatches to AIBOX (Linux) via SSH when invoked on macOS, or runs locally when already on AIBOX — so the SSM fetch + Node.js runtime live on AIBOX, not the Mac Mini. Config shown below the grid.
5 tools
The toolsetcreate_chat starts a new v0 generation chat from a prompt; send_message continues a chat (iterate on components); get_chat retrieves a chat + its generated code; list_chats browses existing chats; find_chats searches chats by content.
Đ
design → code
The payoff —We use v0 MCP to generate React/Next.js components that inherit our @dekawowow/ui design system. Kiro seeds a chat with our token context + UX card specs, iterates on the component output, and retrieves the generated code — without leaving the agent session. This is the programmatic design-to-code pipeline.
kiro-cli stdio AWS SSM v0-api-key mcp-remote bridge mcp.v0.dev HTTP · Bearer fetch key from SSM → inject Bearer header → bridge stdio ⇄ Streamable HTTP runs on AIBOX (Linux) — dispatched via SSH from the Mac Mini

Launcher: SSM-fetched key → mcp-remote

        # launchers/v0.sh
        V0_API_KEY="$(aws ssm get-parameter \
          --name "/heraldstack/mcp/v0-api-key" \
          --with-decryption \
          --profile bryanchasko-kiro \
          --region us-west-2 \
          --query Parameter.Value \
          --output text)"
        
        exec npx mcp-remote \
          "https://mcp.v0.dev" \
          --header "Authorization: Bearer ${V0_API_KEY}"

kiro-cli mcp.json entry

        "v0": {
          "command": "bash",
          "args": ["-c", "/path/to/launchers/run.sh v0.sh"],
          "description": "v0 MCP Server — Vercel AI UI code generation."
        }
        
        // run.sh dispatches to AIBOX (Linux) via SSH if invoked on
        // macOS, or runs locally if already on AIBOX — so the SSM
        // fetch + Node.js runtime live on AIBOX, not the Mac Mini.
Reference & context v0 · MCP server adapter Vercel · MCP & supported clients
This is a first-documented pattern for connecting Kiro CLI to v0 MCP via mcp-remote + SSM-fetched API key. Kiro is not on Vercel's official MCP supported clients list — mcp-remote bridges the gap.
Tooling · Agent ↔ AWS · Managed MCP Server

aws-mcp — the agent's hands on AWS

How agents building Ðekawɔwɔ reach into two AWS accounts — authenticated, least-privilege, no embedded credentials. One managed MCP server replaces the AWS Console in the build loop: query infrastructure, run CDK deploys, sync previews, and pull live docs without leaving the session.

1 · What aws-mcp is

The Managed AWS MCP Server (GA 2026-05-06), reached via mcp-proxy-for-aws. A single server that superseded the old split of aws-docs / aws-iac / aws-api. It exposes 10 tools over one endpoint.

call_aws · 15k+ APIs run_script · sandboxed Python search_documentation read_documentation retrieve_skill get_regional_availability list_regions get_presigned_url

Endpoint: https://aws-mcp.us-east-1.api.aws/mcp

2 · Auth model

SigV4 from local ~/.aws SSO profiles, bridged to the OAuth-only MCP endpoint by mcp-proxy-for-aws. No static API keys. The agent switches profiles per-call across two accounts.

bryanchasko-kiro
<AI-ML-ACCOUNT>
AI/ML · Aurora DSQL · Bedrock · Nova workloads
aerospaceug-admin
<DOMAINS-ACCOUNT>
domains · S3/CloudFront · static hosting

3 · How we wired it for Ðekawɔwɔ

Launcher at /launchers/aws/aws-mcp.sh:

        exec uvx mcp-proxy-for-aws==1.6.3 \
          "https://aws-mcp.us-east-1.api.aws/mcp" \
          --profile bryanchasko-kiro aerospaceug-admin \
          --metadata AWS_REGION=us-west-2

kiro-cli mcp.json entry:

        "aws-mcp": {
          "command": "bash",
          "args": ["-c", "/path/to/launchers/run.sh aws-mcp.sh"]
        }

4 · What we use it for on this project

  • call_aws — CDK stack queries, DynamoDB reads, Cognito user pool inspection, Aurora DSQL cluster status, S3 operations, CloudFront invalidations.
  • search_documentation + read_documentation — current AWS docs for Aurora DSQL, Amazon Location Service, Bedrock Nova.
  • run_script — sandboxed Python data ops.

5 · The two-account pattern

bryanchasko-kiro · <AI-ML-ACCOUNT>
compute + AI

All CDK stacks (Cognito, DynamoDB, Aurora PostGIS, Lambda, API Gateway, Location, Bedrock), Aurora DSQL cluster, Nova inference.

aerospaceug-admin · <DOMAINS-ACCOUNT>
domains + static

S3 buckets, CloudFront distributions (including the _previews/dekawowow-research/ preview path), Route53, ACM.

6 · Key call_aws patterns for Ðekawɔwɔ

        # Check CDK stack status
        call_aws: cloudformation describe-stacks --stack-name DekawowowData
        
        # List DynamoDB tables
        call_aws: dynamodb list-tables --region us-west-2
        
        # Invalidate CloudFront preview
        call_aws: cloudfront create-invalidation \
          --distribution-id EEHVTUEQ97V0X \
          --paths '/_previews/dekawowow-research/*'

7 · Why this matters

The aws-mcp gives agents direct, authenticated, least-privilege access to both AWS accounts without embedding credentials. The agent uses it to deploy CDK stacks, check infrastructure health, sync S3 previews, manage Cognito users, query Aurora DSQL / DynamoDB, and pull live AWS documentation for the specific services Ðekawɔwɔ uses (DSQL, Location Service, Bedrock Nova). No AWS Console needed in the build loop.

Reference & context AWS DevOps Blog · MCP servers for Bedrock Agents GitHub · awslabs/mcp
Tooling pattern card — documents the live aws-mcp wiring this project's agents run against, not a hypothetical setup.
Tooling · Live Docs · Context Injection

Context7 — Live Documentation Fetching

How we feed agents current, version-pinned documentation instead of stale training data. Context7 is an MCP server that resolves @context7/<library> queries to live docs for the exact library version in play. It runs as a persistent HTTP service on AIBOX and is bridged to stdio via supergateway — zero cold-start per agent call. Seven readings: what it is, the deployment, the bridge, how agents use it, why live docs matter, the bridge tool, and the project queries.

@ctx7
@context7/<lib>
The resolver —an MCP server that resolves a library query to live, version-pinned documentation. Pulls current docs for the exact version you're using — not stale training data. Used here for AWS Aurora DSQL, Amazon Location Service, Bedrock Nova, Next.js App Router, and Cognito PKCE.
:8130 /mcp/
localhost:8130/mcp/
The deployment —runs as a persistent HTTP service on AIBOX at http://localhost:8130/mcp/. Not spawned per-call. Bridged to stdio via supergateway --streamableHttp … --outputTransport stdio. The result: zero cold-start on every agent invocation.
HTTP stdio
context7-bridge.sh
The bridge —a one-line exec of supergateway against the persistent HTTP endpoint, emitting stdio for Kiro. The kiro-cli mcp.json entry points at run.sh, which routes to AIBOX via SSH when invoked from macOS — keeping the persistent service and Node.js runtime on Linux. Both shown below the grid.
agent
mid-task lookup
The usage —agents query @context7/aws-sdk or @context7/nextjs mid-task to get current API signatures, method names, and config options. Prevents hallucinated API calls. Used here to verify Aurora DSQL OCC behavior, Cognito PKCE token exchange, CDK L2 construct availability, and the Amazon Location Service Places API shape.
trained GA 2024+
post-cutoff APIs
The stakes —Aurora DSQL is new (GA 2024). Amazon Location Service Places v2 changed shape. Bedrock Nova models shipped after the training cutoff. Without Context7 pulling live docs, agents generate code against stale API surfaces and the build fails.
Streamable HTTP stdio
supergateway
The bridge tool —converts any Streamable HTTP MCP server to stdio transport. Required because Kiro (and most MCP clients) speak stdio, while persistent HTTP services need a bridge. The same pattern is reused for other persistent services in the heraldstack.
build queries
The lookups —the Context7 queries fired during the Ðekawɔwɔ build: @context7/aws-cdk (L2 constructs), @context7/aws-sdk-client-cognito-identity-provider (PKCE), @context7/next (App Router static export), @context7/amazon-location-service (Places + geofence), and @context7/aurora-dsql (OCC, schema). Full list below the grid.
kiro-cli stdio supergateway stdio ⇆ HTTP :8130/mcp/ persistent live docs version-pinned bridge stdio ⇄ Streamable HTTP → persistent service → @context7/<lib> live docs service stays warm on AIBOX (Linux) — zero cold-start per agent call

The bridge: persistent HTTP → stdio

        # context7-bridge.sh
        exec supergateway \
          --streamableHttp http://localhost:8130/mcp/ \
          --outputTransport stdio 2>/dev/null

kiro-cli mcp.json entry

        "context7": {
          "command": "bash",
          "args": ["-c", "/path/to/launchers/run.sh context7-bridge.sh"]
        }
        
        // run.sh routes to AIBOX (Linux) via SSH if invoked on macOS —
        // so the persistent service and Node.js runtime stay on Linux.

Project-specific queries used during the Ðekawɔwɔ build

        @context7/aws-cdk
          → CDK L2 constructs for Cognito, DynamoDB, VPC
        @context7/aws-sdk-client-cognito-identity-provider
          → PKCE token exchange
        @context7/next
          → App Router static export constraints
        @context7/amazon-location-service
          → Places search + geofence API
        @context7/aurora-dsql
          → OCC, snapshot isolation, schema syntax
Reference & context Context7 · context7.com upstash/context7 · GitHub
Context7 runs persistently on AIBOX. The bridge pattern (supergateway stdio→HTTP) is reusable for any persistent MCP service in the heraldstack.
Tooling · Semantic Memory · Agent Knowledge

Qdrant — Agent Memory & Shared Knowledge

How the agent fleet remembers. Qdrant is an open-source vector database running as a local Docker service on AIBOX. We mount it as two distinct MCP servers over one instance: qdrant-agent-memory for per-agent session state and qdrant-shared for project-wide canon. Seven readings: what it is, the two collections, the launcher, the embedding model, how agents use it, what's stored, and why local matters.

localhost:6333
What it is —An open-source vector database running as a local Docker service on AIBOX at http://localhost:6333. Used here as two distinct MCP servers: qdrant-agent-memory for per-agent session memory and qdrant-shared for the shared project knowledge base.
agent-memory & shared-knowledge
The two collectionsagent-memory: each agent stores and retrieves its own session state, decisions, and context across conversations — how Harald remembers past sessions without the LLM context window. shared-knowledge: project-wide facts, architecture decisions, product specs, resolved issues. Readable by all agents, written by Harald at session end.
qdrant.sh <collection>
The launcher —One bash script execs docker run against qdrant-mcp-baked:latest, parameterised by collection name. Two thin launchers call it: qdrant-shared-knowledge.sh passes shared-knowledge; qdrant-agent-memory.sh passes agent-memory. Full script and mcp.json shown below the grid.
all-MiniLM-L6-v2
The embedding modelsentence-transformers/all-MiniLM-L6-v2 runs locally inside the Docker container. No external embedding API calls. No data leaves AIBOX for semantic search. The model is baked into the qdrant-mcp-baked:latest image, so startup is instant.
find store
qdrant-find / qdrant-store
How agents use itqdrant-find retrieves relevant past context before starting a task; qdrant-store persists decisions, specs, and session state at the end. Harald queries before every dispatch to surface prior product decisions, known blockers, and locked constraints (e.g. NOVA-ONLY — no Anthropic in the dekawowow account).
project canon
What's stored —Product spec (the pivot to community mutual support; vocabulary Ask / Give / Wish), infrastructure state (CDK stacks, API routes, Cognito pool IDs), legal-page affiliation disclaimer, architecture decisions (3-DB composition: DSQL + PostGIS + DynamoDB), locked constraints (Nova-only, no generic red/green, David owns the platform), and session-end captures after major work.
AIBOX
single source of truth
Why local matters —All project knowledge — specs, architecture decisions, session history, locked constraints — lives on AIBOX, not a cloud vector DB. No per-query API costs. No data leaving the local network. The agent fleet shares one source of truth that persists across sessions and agents. Search is semantic (similar concepts), not keyword-match.
agent fleet find · store Harald writes canon qdrant-agent-memory agent-memory qdrant-shared shared-knowledge Qdrant localhost:6333 two MCP servers · two collections · one local Qdrant — no cloud, no egress

Docker launcher: one script, parameterised by collection

        # qdrant.sh <collection-name>
        exec docker run --name "mcp-qdrant-${COLLECTION}-$(whoami)-$(date +%s)" \
          -i --rm --network=host \
          -e QDRANT_URL=http://localhost:6333 \
          -e COLLECTION_NAME="$COLLECTION" \
          -e EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 \
          qdrant-mcp-baked:latest
        
        # two launchers call this with different collections:
        #   qdrant-shared-knowledge.sh  → passes  shared-knowledge
        #   qdrant-agent-memory.sh      → passes  agent-memory

kiro-cli mcp.json entries

        "qdrant-shared": {
          "command": "bash",
          "args": ["-c", "/path/to/run.sh qdrant-shared-knowledge-bridge.sh"]
        },
        "qdrant-agent-memory": {
          "command": "bash",
          "args": ["-c", "/path/to/run.sh qdrant-agent-memory-bridge.sh"]
        }
Reference & context Qdrant · vector database qdrant/mcp-server-qdrant
Two collections, one Qdrant instance. agent-memory is per-agent session state. shared-knowledge is project-wide canon. Both run locally on AIBOX — no cloud, no egress cost, no data leak.

Tooling · AWS Tags · CDK ↔ CodeBuild

Tagging Strategy — CDK, CI/CD & Cost Symmetry

Five base tags applied at the CDK App level propagate to every resource in every stack. CodeBuild closes the audit loop by stamping the git SHA at deploy time.

The 5 Base Tags

Applied via cdk.Tags.of(app).add() at the CDK App level in infra/bin/app.ts:

Project dekawowow
Environment dev | production
ManagedBy cdk
Owner david-ametorwobla
CostCenter dekawowow

Why App-Level Tagging

cdk.Tags.of(app).add() propagates to every child construct in every stack — Lambdas, DynamoDB tables, S3 buckets, VPC, RDS cluster, CloudFront, API Gateway. One line tags 50+ resources. No per-resource tagging needed.

Environment Differentiation

Environment: dev vs Environment: production. Dev stacks deploy with cdk deploy -c environment=dev. Prod is the default. This single flag separates resources in Cost Explorer, Config, and CloudWatch.

const environment = app.node.tryGetContext('environment') ?? 'production';

CI/CD Runtime Tags

CodeBuild adds two tags at deploy time to deploy-manifest.json in the S3 bucket root:

  • Build: $CODEBUILD_BUILD_ID
  • GitSha: $CODEBUILD_RESOLVED_SOURCE_VERSION

Full audit trail: every AWS resource → environment tag → git commit that deployed it.

CDK ↔ CodeBuild Symmetry Rules

  1. Every CDK-provisioned S3 bucket and CF distribution exports its ID as a CloudFormation Output — CodeBuild reads via aws cloudformation describe-stacks, no hardcoded IDs
  2. SSM parameters (/dekawowow/dev/* and /dekawowow/prod/*) written by CDK post-deploy, read by CodeBuild at build time
  3. The CodeBuild IAM role is CDK-provisioned (DekawowowHostingStack) — not console/CLI created

Cost Explorer View

Because every resource is tagged CostCenter: dekawowow and Environment: dev|production, AWS Cost Explorer shows:

  • Total spend per environment (dev vs prod)
  • Spend by service within dekawowow (Lambda, DynamoDB, Aurora, CloudFront)
  • Owner attribution (Owner: david-ametorwobla)

No untagged orphan resources.

Deploy Manifest

deploy-manifest.json at the S3 bucket root — publicly readable, no auth needed:

{
          "build": "$CODEBUILD_BUILD_ID",
          "sha": "$CODEBUILD_RESOLVED_SOURCE_VERSION",
          "deployed_at": "2026-06-29T14:00:00Z"
        }

The app footer fetches this at runtime to display the deployed version/SHA. This is how design system previews show build provenance.

Tag once at the App level, pay once. Every AWS resource in every stack inherits the full tag set. CodeBuild adds the git SHA at deploy time — closing the loop from code commit to running infrastructure.

UX Cards — Visitor Personas

Five live UX card designs for distinct visitor personas: hackathon judges & competitors, global visitors, Volta locals, logged-in users, and developers. Each card demonstrates layout, copy voice, and interaction patterns for its target context.

UX · Hackathon Visitor · #H0Hackathon

Hackathon Landing — Judges, Competitors & Spectators

A scrolling hero that welcomes the #H0Hackathon audience — judges, competitors, and spectators alike. Surfaces the origin story, scrolls judge names with titles, states judging criteria, and roots the project in its invention credit and community context.

#H0Hackathon · HO, Ghana

Ðekawɔwɔ

Your neighbor already answered. Now the system will too.

Ðekawɔwɔ is the sole invention of David Ametorwobla, born from a conversation with Bryan Chasko at the AWS Global Community Gatherings . When the #H0Hackathon arrived, they saw their moment. What you are looking at is a live demo — built for the judges, rooted in HO, Ghana.

Welcoming our judges
Joseph Idziorek
Director, Product Management, AWS Databases
Tim Stoakes
Sr. Principal Technologist
Karthik Vijayraghavan
Sr Manager, NoSQL Solutions Architects, AWS
Aditya Samant
Principal Database Specialist SA, AWS Databases
David Castro
Principal Product Manager, AWS Databases
Tony Gibbs
Senior Manager, Specialist Solutions Architects
Rohan Bhatia
Principal Product Manager, AWS Databases
Ravi Yadav
Principal Specialist, Data & AI, AWS
Gowri Balasubramanian
Sr. Manager, Solutions Architecture
Abhinav Anand
Technical Product Marketing, AWS
👩‍⚖️ Judges ⚡ Competitors 👀 Spectators
Judging Criteria
Technological Implementation

Software craftsmanship. AWS Database (Aurora DSQL or DynamoDB) with deliberate data model. Vercel deployment beyond basics. Clean, purposeful, intentional.

Design

UX intuitive and well-considered. Front-end feels designed in relation to the back-end. Cohesive full-stack thinking visible in both layers.

Impact & Real-world Applicability

Meaningful problem for a real audience. Scalable database infrastructure makes the solution viable — not just functional, but potentially shippable.

Originality

Creative and original concept. Insight about what's possible with this stack. If the idea isn't new — how significantly does this push it forward?

Ghana National Fire Service fields over 500,000 prank calls every year — and that's one service in one country. Behind every misdirected call is a neighbor who didn't know where to turn. Ðekawɔwɔ organizes that knowledge, connects people to real local resources, and builds the API layer for providers to receive authorized citizen context — so help arrives before the system hangs up.

Auto-scroll behavior (marquee)

/* Auto-scroll the judge strip */
        .judge-scroll-track {
          animation: judge-scroll 30s linear infinite;
        }
        .judge-scroll-track:hover { animation-play-state: paused; }
        
        @keyframes judge-scroll {
          0%   { transform: translateX(0); }
          100% { transform: translateX(-50%); }
        }
        /* Duplicate judge nodes in JS for seamless loop */
Context AWS Global Community Gatherings
Invention: David Ametorwobla. Collaboration: Bryan Chasko. #H0Hackathon demo, HO Ghana.
UX · Global Visitor · Expansion Invitation

Global Visitor — Bringing Ðekawɔwɔ to Your Region

For someone anywhere in the world who has just discovered Ðekawɔwɔ and wonders whether it could work where they live. The architecture doesn't assume Ghana. The problem is universal. The invitation is open.

🌍

Ðekawɔwɔ doesn't belong only to Volta.

Prank calls overwhelming emergency lines. Neighbors who know exactly what to do — but no channel to reach each other. The gap between distress and real help isn't unique to Ghana. If you recognize that gap where you live, Ðekawɔwɔ was built to travel.

Explore bringing Ðekawɔwɔ to your region →
🏘️
Community-first architecture

Built around neighbor networks and local organizations, not just government infrastructure.

🔌
API-first, provider-ready

Local providers — fire, medical, rescue — can subscribe to events and receive citizen-submitted context from day one.

🌐
No single shape of emergency

The platform adapts to local emergency types, local languages, and local response structures. It doesn't impose a model.

Interested in a regional pilot? Get in touch — the development team is actively exploring expansion partnerships.

Contact the team
Copy voice
Invitation, not pitch. The gap is universal — Ðekawɔwɔ is built to travel.
UX · Volta Local · Sign-up & CTAs

Volta Local — You Know the Problem. Here's the Path.

Speaks directly to someone from Volta who has already lived the experience of calling 112 and nothing moving. Feels like a neighbor talking, not an onboarding flow. Clear CTAs to register and get started.

Volta Region · Ghana

You've already been the help.
Ðekawɔwɔ makes sure that counts.

You know the neighbor with the truck. You know the nurse three compounds over. When 112 didn't pick up, your community moved anyway — because that's what Volta does. Ðekawɔwɔ is built to carry what you already do, and make sure the right people can find it fast.

What you can do with Ðekawɔwɔ
🆘
Report an emergency

Submit location, type, and supporting context — photos, notes, witnesses.

📍
Find your local station

Nearest fire, medical, or community response point — mapped to your location.

🤝
Connect neighbor to neighbor

Alert nearby registered community members when help is needed close to home.

📢
Follow active situations

Stay informed on events near you. Know when help has arrived or is still needed.

Join Ðekawɔwɔ

Free to join. Your data stays yours. No prank calls. No noise.

Copy voice
Neighbor talking to neighbor. Volta-first framing. CTAs are clear and unambiguous.
UX · Logged-in User · Dashboard & Case Submission

Logged-in User — Submit, Track, Connect

For a user with an existing account. All case types accessible. Quick path to find their local station. Active and past submissions visible at a glance.

Ðekawɔwɔ
● Volta Region
KA
Quick actions
Your submissions
Flooding — Kpando road junction
Submitted 14 min ago · 2 neighbours confirmed
Active
Broken water pipe — Market lane
Submitted yesterday · Resolved
Resolved
View all submissions →
Nearby · within 5km
1 active report · 3 neighbors marked available
See what's happening nearby →
UX intent
Dashboard-first. All case types one tap away. Local station surfaced on load. No navigation required for core actions.
UX · Developer / Provider · API & Event Subscriptions

Developer — Receive Events, Access the API

For developers and authorized providers who want to subscribe to Ðekawɔwɔ events or query citizen-submitted context via API. Emergency services, NGOs, research organizations — anyone building on top of community-reported data.

Ðekawɔwɔ API v1
Request API access

Build on top of community context.

When a citizen submits a case to Ðekawɔwɔ, authorized providers can receive that event in real time — with location, type, supporting evidence, and community confirmation. Subscribe to the event stream, or query by location, time, and case type.

REST endpoints
GET /v1/events list events
GET /v1/events/{id} event detail
POST /v1/subscriptions subscribe
GET /v1/stations local stations
🔑 Authorization: Bearer token. API access requires provider approval — identity and intended use reviewed before issuance.
Sample event payload
{
          "id": "evt_gh_vr_00482",
          "type": "emergency.fire",
          "status": "active",
          "submitted_at": "2026-06-29T11:42:00Z",
          "location": {
            "region": "Volta",
            "district": "Ho Municipal",
            "coords": [0.8712, 6.6011]
          },
          "confirmations": 3,
          "evidence": ["photo", "note"],
          "nearest_station": {
            "id": "stn_ho_central_fire",
            "name": "Ho Central Fire Station",
            "distance_km": 1.8
          }
        }
Event-driven subscriptions

Subscribe by region, event type, and severity. Receive webhooks the moment a citizen submits and their case reaches confirmation threshold. Build response workflows on top of community data.

Who this is for

Emergency services, NGOs, research institutions, municipal planning bodies, and community organizations that need authorized, structured access to citizen-submitted emergency context.

API is in active development. Early access available for vetted providers.
UX intent
Developer-tone. Dark surface, monospace code. Auth model is explicit. Audience is builders and providers, not end users.