Reference
Snippets for every component used on the site. Copy a block, paste it into any
markdown page (docs/*.md), tweak the contents.
The markdown attribute on every wrapper <div> / <section> is required –
it tells Python-Markdown to keep parsing markdown inside the HTML tag.
Most components below are thin compositions on top of Zensical / mkdocs-material primitives. Each section ends with an Upstream link pointing to the official docs for the underlying feature.
Section (screen)
Every page is composed of <section class="screen"> blocks. Each one is a
hard color block: it paints its background full-bleed, and stacked sections
butt against each other.
Background variants (light sections turn their contents dark-on-light):
| Class | Token (--bg-*) |
|---|---|
.screen--bg-white |
warm cream #fff8f1 |
.screen--bg-black |
near-black #1a1a1a |
.screen--bg-green |
mint --oa-green-300 |
.screen--bg-orange |
ember --oa-orange-400 |
.screen--bg-yellow |
pale --oa-yellow-100 |
.screen--bg-purple |
lavender --oa-purple-200 |
Optional modifiers
.screen--full-height makes the section at least 100 vh – useful for landing
heroes.
Headings: a page has one h1, its title (# Title, or a hero's); with
hide: [title] and no h1 of its own, the theme's title stays as a visually
hidden h1. Sections open with ## …, which gets the large section headline.
h1 and h2 are set in Sligoil, h3 and h4 in bold Inter; a hero's h2 stays bold
Inter, as does a feature card's, and on the blog (listings, posts, the News
excerpts) only the h1 is Sligoil.
.screen--narrow keeps a section at the default content width (1024px) on a
wide page (wide: true, 1280px), like the team section at the bottom of the
landing page. Elsewhere it changes nothing.
Page header: it takes the color of the section under it, with the dark
logo (extra.logo_light) on light ones. header: in the front matter picks
the layout:
standard(the default): centered logo, burger on the right.zone: a smaller logo on the left, Login and Sign up on the right (extra.signininmkdocs.yml,primary: truefills one), no menu. zone.md uses it.
Menu sections: extra.drawer in mkdocs.yml lists landing page sections
(title, url: ./#updates); the menu shows them above the pages, on every
page.
Project-specific component – no upstream.
Hero – landing variant
A single centered column for splash blocks. Sligoil-mono h1, lighter weights, larger button row.
<section class="screen screen--bg-white screen--full-height" markdown>
<div class="hero hero--landing" markdown>
**Tagline above the title**
# Big headline<br>two lines
A short paragraph of teaser copy describing what this site / project is about.
[See solutions](#){.btn} [Talk to us](#){.btn .btn--primary}
</div>
</section>
Use <br> for hard line-breaks inside the # headline. Markdown's two-trailing-spaces
rule does not apply inside headings.
Project-specific component – no upstream.
Hero – two-column with media
.hero is a 2-column grid (1 col on mobile, 5fr 6fr on tablet+). The two
direct children are: a content wrapper and an image. Swap sides by swapping
their order.
Content on left, media on right
<div class="hero" markdown>
<div markdown>
**Tagline**
## Section title
Body prose explaining the feature.
[Primary CTA](#){.btn .btn--primary} [Secondary](#){.btn}
</div>
{style="aspect-ratio:4/3"}
</div>
Media on left, content on right
<div class="hero" markdown>
{style="aspect-ratio:4/3"}
<div markdown>
**Tagline**
## Section title
Body prose explaining the feature.
[Read the docs](#){.btn}
</div>
</div>
The inner <div markdown> wrapper groups the content blocks into a single
grid item – without it each paragraph would land in its own grid cell.
A framed image (a screenshot, with the default border and shadow) fills its
column; an unframed one, a logo or symbol ({.no-border}, {.section-icon}),
sits inset in its cell.
Project-specific component – no upstream.
Buttons
Two intents only. Apply via attribute lists on inline links or directly on
<button> / <a> HTML.
Secondary = transparent, outlined in the text color; primary = filled with the text color (white on dark sections, black on light ones).
<button> works the same – drop the class on a real form button:
Upstream: Zensical – Buttons
(we override .md-button ↦ .btn with the design's pill shape and color logic).
Form / input
Plain <form> + <input> markup. No component classes – generic CSS handles
the pill shape, border, and per-scheme colors.
<form action="https://example.com/subscribe" method="post">
<input type="email" name="email" placeholder="email@example.org" required>
<button type="submit" class="btn btn--primary">Subscribe</button>
</form>
Project-specific styling – no upstream.
Card grid
Zensical's built-in pattern – <div class="grid cards" markdown> wrapping a
markdown list. Each list item becomes a card. Cards stack to full width on
mobile and lay out in 2–3 columns when there's room.
<div class="grid cards" markdown>
- :material-database: __Aleph__
Search across leaks and structured public records.
[Learn more](#){.btn}
- :material-graph: __FollowTheMoney__
Standardise entities across investigations and feeds.
[Documentation](#){.btn}
- :material-file-search: __ICIJ Datashare__
Local-first document discovery with redaction tooling.
[GitHub](#){.btn}
</div>
The action paragraph (last paragraph containing .btn links) is auto-pushed
to the bottom of every card so all CTAs align.
Full-width card modifier
.card--full makes a single card span every column of the grid.
<div class="grid cards" markdown>
- :material-megaphone: __Featured announcement__
A wider card spanning the entire grid row.
[Read more](#){.btn}
{ .card--full }
- :material-database: __Aleph__
Description… [Learn more](#){.btn}
</div>
The { .card--full } line right after the item content attaches the modifier;
:has(.card--full) on the parent <li> triggers the column span.
Feature cards (landing page)
Block syntax, two per row (.grid--wide, one per row on narrow screens;
.grid--three for three per row). .card--feature adds room
and a large title; a screen--bg-* class fills the card with that color. A
<form role="search"> renders as one search pill.
<div class="grid grid--wide" markdown>
<div class="card card--feature" markdown>
## Search
<form action="https://darc.zone/search" method="get" role="search">
<input type="search" name="q" placeholder="Search" aria-label="Search">
<button class="btn btn--primary" type="submit">Search</button>
</form>
</div>
<div class="card card--feature screen--bg-yellow" markdown>
## A filled card
- A bullet point
[Call to action](#){.btn .btn--primary}
</div>
</div>
.card--media (image left, content right, strip underneath; used by the
topic cards in scripts/templates/topics.html) takes a figure.card__media,
a div.card__body and an optional div.card__footer, and spans the full row.
Upstream: Zensical – Card grids.
The base .grid.cards markup ships with the theme; we only override the
border thickness/radius and disable the hover effect.
Project card grid (case studies)
Same <div class="grid cards"> pattern. Each item starts with a cover image,
then chip tags (<kbd>), title, partner/date in italics, prose, and CTA buttons.
<div class="grid cards" markdown>
- {.no-shadow}
<kbd>EU</kbd> <kbd>FinCrime</kbd> <kbd>Aleph</kbd>
__Tracing oligarch real estate across the EU__
*Süddeutsche Zeitung – March 2026*
A six-month cross-border investigation linking shell-company ownership
of premium properties back to a small set of beneficial owners.
[Read case study](#){.btn} [View project](#){.btn .btn--primary}
</div>
{.no-shadow} removes the offset hard shadow on the cover (still keeps the
3px black border). Use {.no-border} to drop the border too.
Upstream: same Zensical card grid as above – no separate primitive.
Profile card grid (team)
Add the profiles modifier to the grid. Each list item lays out as
avatar (left) | name + title (right), with bio + buttons spanning both
columns below.
<div class="grid cards profiles" markdown>
- 
__Jane Doe__ <span class="muted">she/they</span>
*Investigations editor*
Bio paragraph describing their work and focus.
[:material-email: Email](mailto:jane@example.org){.btn}
- 
__Alex Chen__ <span class="muted">he/him</span>
*Research lead*
Bio paragraph.
[:material-email: Email](mailto:alex@example.org){.btn}
</div>
The .profile-card__avatar class on a markdown image gives it a 4 × 4 rem
circular crop with a 3px border (no shadow).
Upstream: extends Zensical card grids
with a project-specific .profiles modifier on the grid.
Tag chips
<kbd> is repurposed as a chip. Filled with the inverse of the page (white
on dark sections, black on light ones).
Upstream: Zensical – Keyboard keys (repurposed for short label chips).
Images
Every <img> in markdown content gets the iconic 3px black border + offset
hard shadow automatically.
Per-image opt-outs:
{.no-border} <!-- drop the border -->
{.no-shadow} <!-- drop the shadow -->
{.no-border .no-shadow} <!-- drop both -->
{style="aspect-ratio:4/3"} <!-- inline override -->
{.center} <!-- center in the text flow -->
{.section-icon} <!-- feature symbol in a hero: borderless, centered, max 200px -->
Upstream: Zensical – Images (we add the global border + offset shadow on top).
Inline text utilities
Apply via attribute lists.
__Title__ <span class="muted">subtitle text</span> <!-- lower opacity -->
__Title__ <span class="dim">subtitle text</span> <!-- darc dim text token -->
Or on inline markdown elements (italic, code, link):
Upstream: Zensical – Attribute lists
(the { .class } syntax that powers all the inline attributes above).
Admonitions
!!! note
Use `note`, `tip`, `warning`, `danger`, `info`, `success`, `question`,
`example`, `quote` – colors come from darc-zensical.
Upstream: Zensical – Admonitions.
Collapsible details
Upstream: Zensical – Admonitions § Collapsible.
Content tabs
Upstream: Zensical – Content tabs.
Icons
Any of these shortcodes resolves to an inline SVG via Zensical's emoji index:
:lucide-mail:– Lucide (default UI set):material-database:– Material Symbols:simple-github:– Simple Icons (brand logos):octicons-arrow-right-24:– Octicons:fontawesome-solid-heart:– Font Awesome
Combinable with attr_list on links: [GitHub :simple-github:](#){.btn}.
Upstream: Zensical – Icons & emojis.
Layer stack
A stack of labeled rows of linked boxes, top layer first (the open-source page). One paragraph per layer: a bold label, then its links, one per line. The boxes share three columns; a lone one spans them. On phones the label sits above its boxes, two to a row. Use it instead of Mermaid when the boxes should link somewhere (the theme's Mermaid can't link nodes).
<div class="stack" markdown>
**2 · Application**
[OpenAleph](https://openaleph.org/docs/)
[openaleph-search](https://openaleph.org/docs/lib/openaleph-search/)
**1 · Storage**
[anystore](https://docs.investigraph.dev/lib/anystore/)
</div>
Project-specific component – no upstream.
Diagrams (Mermaid)
A ```mermaid block becomes a diagram (the theme loads Mermaid on pages
that have one). It's drawn in the text color of the section it sits in,
outlined like the cards. Wrap a wide one in <div class="diagram" markdown>
so it scrolls sideways on phones instead of shrinking its labels; add
classDef default stroke-width:2px and linkStyle default stroke-width:2px
for the brand stroke.
<div class="diagram" markdown>
```mermaid
flowchart TD
classDef default stroke-width:2px
linkStyle default stroke-width:2px
app(OpenAleph) --> search(openaleph-search)
search --> ftmq(ftmq)
ftmq -. optional .-> putfs(putfs)
```
</div>
Upstream: Zensical – Diagrams.
Code blocks & syntax highlighting
Upstream: Zensical – Code blocks.