Skip to content

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.

<section class="screen screen--bg-orange" markdown>

Section content here…

</section>

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

<section class="screen screen--bg-white screen--full-height" markdown>
…
</section>

.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.signin in mkdocs.yml, primary: true fills 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>

![](path/to/image.jpg){style="aspect-ratio:4/3"}

</div>

Media on left, content on right

<div class="hero" markdown>

![](path/to/image.jpg){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 action](#){.btn}
[Primary action](#){.btn .btn--primary}

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:

<button type="submit" class="btn btn--primary">Subscribe</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>

-   ![Case study](path/to/cover.jpg){.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](https://i.pravatar.cc/160?img=49)

    __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](https://i.pravatar.cc/160?img=33)

    __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).

<kbd>EU</kbd> <kbd>FinCrime</kbd> <kbd>Aleph</kbd>

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.

![Caption](path/to/image.jpg)

Per-image opt-outs:

![](path.jpg){.no-border}                  <!-- drop the border -->
![](path.jpg){.no-shadow}                  <!-- drop the shadow -->
![](path.jpg){.no-border .no-shadow}       <!-- drop both -->
![](path.jpg){style="aspect-ratio:4/3"}    <!-- inline override -->
![](path.jpg){.center}                     <!-- center in the text flow -->
![](icon.svg){.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):

*subtle*{.muted}
`code`{.muted}

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

???+ tip "Click to expand"
    Body content goes here.

Upstream: Zensical – Admonitions § Collapsible.

Content tabs

=== "Python"
    ```python
    print("hello")
    ```

=== "Bash"
    ```bash
    echo hello
    ```

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

```python title="example.py"
def hello():
    print("Hello, world")
```

Upstream: Zensical – Code blocks.