# Sqrl Design System

Single-file reference for product UI (humans and AI). Do not scrape the docs site.

- Theme overlay: https://design.sqrl.nl/dist/sqrl-theme.min.css
- Load **Bootstrap 5 CSS first**, then the overlay. Markup is Bootstrap 5; use Sqrl custom classes only where a page is tagged Sqrl custom.
- **`sq-preview`** is a docs-only example frame. Copy the markup **inside** it (or the HTML fence below). Do not emit `sq-preview` in an app.
- **`sq-source-tags`** are docs-only. **Bootstrap** = stock Bootstrap 5 classes (themed). **Sqrl custom** = extra classes (`sq-*`, `btn-ghost`, …).
- **Rules** sections are constraints. Pages below follow the docs sidebar.



---

<!-- Source: getting-started/introduction.md -->

# Introduction

This design system is a warm-paper interface layer on **Bootstrap 5**: tokens, typography, and component patterns so product screens stay consistent.

## What you get

- **Theme** — compiled overlay CSS (`sqrl-theme.min.css`) on top of Bootstrap 5; [Quick start](/getting-started/quick-start) has the `<link>` tags.
- **Docs** — Design foundations and component examples you can copy into an app. One-file copy for AI: [design.md](https://design.sqrl.nl/dist/design.md).
- **Principles** — One clear primary action per view; follow-up and conversion first.
## Who this is for

Designers and developers working on product UI. You should be comfortable with HTML and Bootstrap utility classes; the theme handles the rest.

## Source tags

Component pages show small tags under the title (or under a section heading when only part of the page is custom):

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

- **Bootstrap** — standard Bootstrap 5 markup; `theme.scss` maps Sqrl tokens onto these classes.
- **Sqrl custom** — extra classes or patterns Bootstrap does not ship (`sq-*`, `btn-ghost`, …).
## Next steps

Read [Quick start](/getting-started/quick-start) to add the theme to a project, then explore [Colors](/design/colors), [Iconography](/design/iconography), and [Buttons](/components/buttons).


---

<!-- Source: getting-started/quick-start.md -->

# Quick start

Put this in the document `<head>`. **Bootstrap first**, then Sqrl.

```html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
/>
<link rel="stylesheet" href="https://design.sqrl.nl/dist/sqrl-theme.min.css" />
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;700&family=Manrope:wght@400;500;600;700&family=Newsreader:opsz,wght@6..72,600&display=swap"
/>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
```

Use Bootstrap 5 classes. Add Sqrl custom classes only where a page shows the **Sqrl custom** tag. Patterns: [Buttons](/components/buttons).

## Design.md

Whole design system in one Markdown file. Give this to a model instead of scraping the site.
[Download here](https://design.sqrl.nl/dist/design.md)

When a model reads that file:

- **`sq-preview`** is a docs-only example frame. Copy the markup **inside** it (or the HTML fence below). Do not emit `sq-preview` in an app.
- **`sq-source-tags`** are docs-only. **Bootstrap** = stock Bootstrap 5 classes (themed). **Sqrl custom** = extra classes (`sq-*`, `btn-ghost`, …) — use only those.
- Load Bootstrap CSS, then `sqrl-theme.min.css`. Follow **Rules** on each page as constraints.


---

<!-- Source: design/colors.md -->

# Colors

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Sqrl palette: warm paper, one brand green, stone neutrals, and named status/accent hues. Swatches below; **when to use which** → [Rules](#rules).

## Green

Brand scale. **`green-600`** is Bootstrap **primary**; **`green-700`** maps to **success** / default links.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #1f3f28;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Pressed</div>
          <div class="sq-color-var">green-900</div>
          <div class="sq-color-hex">#1F3F28</div>
          <p class="sq-color-use mb-0">Pressed success button (`btn-success` active).</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #2c5a38;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Active</div>
          <div class="sq-color-var">green-800</div>
          <div class="sq-color-hex">#2C5A38</div>
          <p class="sq-color-use mb-0">Link hover, primary/success pressed, active accordion and list text.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #356c44;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Success</div>
          <div class="sq-color-var">green-700</div>
          <div class="sq-color-hex">#356C44</div>
          <p class="sq-color-use mb-0">Links, success text, solid success badges.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-primary"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Primary</div> 
          <div class="sq-color-var">green-600</div>
          <div class="sq-color-hex">#418252</div>
          <p class="sq-color-use mb-0">Primary buttons, checks, progress.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #a9cbb2;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Border subtle</div>
          <div class="sq-color-var">green-300</div>
          <div class="sq-color-hex">#A9CBB2</div>
          <p class="sq-color-use mb-0">Borders on tinted primary/success badges and alerts.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #dceadf;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Subtle</div>
          <div class="sq-color-var">green-100</div>
          <div class="sq-color-hex">#DCEADF</div>
          <p class="sq-color-use mb-0">Tinted success badge fill and alert backgrounds.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch  bg-primary-subtle "></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Selected</div>
          <div class="sq-color-var">green-50</div>
          <div class="sq-color-hex">#EDF4EE</div>
          <p class="sq-color-use mb-0">Selected rows, accordion open, dropdown hover/active, tinted primary badges.</p>
        </div>
      </div>
    </div>
  </div>
</div>

## Stone

Warm neutrals — all text and borders tint from **`stone-900`**. **`stone-100`** is Bootstrap **secondary** (subtle fills), not terracotta.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-dark"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Body & headings</div>
          <div class="sq-color-var">stone-900</div>
          <div class="sq-color-hex">#3B342F</div>
          <p class="sq-color-use mb-0">Body, headings, scope bar, active pagination and pill nav.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #4e463f;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Nav emphasis</div>
          <div class="sq-color-var">stone-800</div>
          <div class="sq-color-hex">#4E463F</div>
          <p class="sq-color-use mb-0">Sidebar nav links, breadcrumb hover, `btn-dark` hover.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-neutral"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Muted & neutral</div>
          <div class="sq-color-var">stone-700</div>
          <div class="sq-color-hex">#6B625B</div>
          <p class="sq-color-use mb-0">Secondary copy, neutral badges, helper text.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #8a807a;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Subtle text</div>
          <div class="sq-color-var">stone-600</div>
          <div class="sq-color-hex">#8A807A</div>
          <p class="sq-color-use mb-0">Tertiary text and micro-caps (`text-body-tertiary`).</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #a79d95;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Placeholder</div>
          <div class="sq-color-var">stone-500</div>
          <div class="sq-color-hex">#A79D95</div>
          <p class="sq-color-use mb-0">Placeholders, disabled controls, chevrons, close icon.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #c6bcb2;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Focus ring</div>
          <div class="sq-color-var">stone-400</div>
          <div class="sq-color-hex">#C6BCB2</div>
          <p class="sq-color-use mb-0">Focused inputs and secondary button hover border.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #ded5cb;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Control border</div>
          <div class="sq-color-var">stone-300</div>
          <div class="sq-color-hex">#DED5CB</div>
          <p class="sq-color-use mb-0">Default input and select borders.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch" style="background-color: #e9e2da;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Default border</div>
          <div class="sq-color-var">stone-200</div>
          <div class="sq-color-hex">#E9E2DA</div>
          <p class="sq-color-use mb-0">Dividers, preview outlines, bordered cards.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-secondary"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Secondary surface</div>
          <div class="sq-color-var">stone-100</div>
          <div class="sq-color-hex">#F1EBE5</div>
          <p class="sq-color-use mb-0">Secondary fills, disabled inputs, neutral subtle backgrounds.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-light"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Light badge fill</div>
          <div class="sq-color-var">stone-50</div>
          <div class="sq-color-hex">#F6F2EE</div>
          <p class="sq-color-use mb-0">Light badges and chips; same as **`surface-paper`** (`bg-surface-paper`).</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined" style="background-color: #fdfbf8;"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Inverse text</div>
          <div class="sq-color-var">stone-white</div>
          <div class="sq-color-hex">#FDFBF8</div>
          <p class="sq-color-use mb-0">Text and icons on dark fills — not a card background.</p>
        </div>
      </div>
    </div>
  </div>
</div>

## Status

Semantic fills for badges, alerts, and banners (`text-bg-*`). Each tone has matching **`-subtle`** / border tokens in the theme. **`text-bg-neutral`** / **`alert-neutral`** are Sqrl custom — Bootstrap has no `neutral` color.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-success"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Success</div>
          <div class="sq-color-var">green-700</div>
          <div class="sq-color-hex">#356C44</div>
          <p class="sq-color-use mb-0">Solid success badges and status — pair with a label.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-warning"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Warning</div>
          <div class="sq-color-var">ochre-600</div>
          <div class="sq-color-hex">#B07B1E</div>
          <p class="sq-color-use mb-0">Caution, due-soon, and attention states.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-danger"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Danger</div>
          <div class="sq-color-var">crimson-600</div>
          <div class="sq-color-hex">#B23A34</div>
          <p class="sq-color-use mb-0">Errors and destructive actions.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-info"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Info</div>
          <div class="sq-color-var">azure-600</div>
          <div class="sq-color-hex">#2F6BA8</div>
          <p class="sq-color-use mb-0">Informational badges and labels.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-neutral"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Neutral status</div>
          <div class="sq-color-var">stone-700</div>
          <div class="sq-color-hex">#6B625B</div>
          <p class="sq-color-use mb-0">Open or draft tags when no status tone fits.</p>
        </div>
      </div>
    </div>
  </div>
</div>

## Accents

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Named hues for charts and highlights — **not** status. Utilities: `text-accent-*`, `bg-accent-*`, `text-bg-accent-*`, `border-accent-*`. **Azure is info**, not an accent.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-accent-teal"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Teal accent</div>
          <div class="sq-color-var">teal-600</div>
          <div class="sq-color-hex">#2E7D77</div>
          <p class="sq-color-use mb-0">Charts and accent badges only.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-accent-terracotta"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Terracotta accent</div>
          <div class="sq-color-var">terracotta-600</div>
          <div class="sq-color-hex">#C0623C</div>
          <p class="sq-color-use mb-0">Charts and accent badges — not secondary actions.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-accent-slate"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Slate accent</div>
          <div class="sq-color-var">slate-600</div>
          <div class="sq-color-hex">#5C6B72</div>
          <p class="sq-color-use mb-0">Charts and accent badges only.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-accent-taupe"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Taupe accent</div>
          <div class="sq-color-var">taupe-600</div>
          <div class="sq-color-hex">#8A7256</div>
          <p class="sq-color-use mb-0">Charts and accent badges only.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-accent-violet"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Violet accent</div>
          <div class="sq-color-var">violet-600</div>
          <div class="sq-color-hex">#6B5B95</div>
          <p class="sq-color-use mb-0">Charts and accent badges only.</p>
        </div>
      </div>
    </div>
  </div>
</div>

## Surfaces

Layout backgrounds and elevation. Use **`bg-surface-*`** utilities (`bg-surface-app`, `bg-surface-page`, `bg-surface-card`, …) or **`var(--sq-surface-*)`**. **Inputs** use **`surface-card`** (same family as cards). Cards use shadow, not border, unless the surface matches — then **`card-bordered`**.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch bg-surface-app"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">App background</div>
          <div class="sq-color-var">surface-app</div>
          <div class="sq-color-hex">#E8E0D7</div>
          <p class="sq-color-use mb-0">Full app shell; sidebar shares this. Work panel floats lighter on top.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-surface-page"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Page canvas</div>
          <div class="sq-color-var">surface-page</div>
          <div class="sq-color-hex">#F4F0EA</div>
          <p class="sq-color-use mb-0">Raised work panel (`bg-surface-page` / `bg-body`), not the outer shell.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-surface-card"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Card & modal</div>
          <div class="sq-color-var">surface-card</div>
          <div class="sq-color-hex">#FCFAF7</div>
          <p class="sq-color-use mb-0">Cards, modals, menus, and form field background.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-surface-code"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Code background</div>
          <div class="sq-color-var">surface-code</div>
          <div class="sq-color-hex">#F8F5F1</div>
          <p class="sq-color-use mb-0">Docs and in-app code block background.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-surface-sunken"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Sunken well</div>
          <div class="sq-color-var">surface-sunken</div>
          <div class="sq-color-hex">#F1EBE5</div>
          <p class="sq-color-use mb-0">Inset wells, placeholders, doc preview backdrops.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-surface-paper"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Soft paper fill</div>
          <div class="sq-color-var">surface-paper</div>
          <div class="sq-color-hex">#F6F2EE</div>
          <p class="sq-color-use mb-0">Warm neutral bands and chrome; token **`stone-50`**.</p>
        </div>
      </div>
    </div>
    <div class="col-6 col-md-4 col-lg-3">
      <div class="sq-color-card">
        <div class="sq-color-swatch sq-color-swatch--outlined bg-surface-selected"></div>
        <div class="sq-color-meta">
          <div class="sq-color-title">Selected highlight</div>
          <div class="sq-color-var">surface-selected</div>
          <div class="sq-color-hex">#EDF4EE</div>
          <p class="sq-color-use mb-0">Table, list, and accordion selection (green-50).</p>
        </div>
      </div>
    </div>
  </div>
</div>

## Rules

### Palette

- Warm, low-chroma **paper** UI with one saturated **brand green**. **Stone** is the secondary action colour — not terracotta.
- **Colour never carries meaning alone** — pair with a dot, icon, or word ([Iconography](/design/iconography), [badges](/components/badge), alerts).
### Bootstrap mapping

- **Primary** → `green-600` (`btn-primary`, `bg-primary`, focus rings, selection).
- **Success / link hover** → `green-700` (`text-success`, `text-bg-success`, links).
- **Secondary** → `stone-100` (`bg-secondary`, subtle chips) — not terracotta.
- **Dark / strong UI** → `stone-900` (`bg-dark`, body text, scope bar, active pagination/pills).
- **Neutral** → `stone-700` — Sqrl custom utilities: `text-neutral`, `bg-neutral`, `text-bg-neutral`, `bg-neutral-subtle` (Bootstrap has no `neutral`).
- **Info** → `azure-600` (`text-bg-info`) — not an accent.
- **Warning / danger** → `ochre-600` / `crimson-600`.
- **Accents** → `teal`, `terracotta`, `slate`, `taupe`, `violet` — highlights and charts only; never primary actions or `btn-secondary`.
### Surfaces & text

- **Surface utilities** — `bg-surface-app`, `bg-surface-page`, `bg-surface-card`, `bg-surface-raised`, `bg-surface-code`, `bg-surface-sunken`, `bg-surface-paper`, `bg-surface-hover`, `bg-surface-active`, `bg-surface-selected`, `bg-surface-overlay` (also `--sq-surface-*` on `:root`). **`surface-paper`** = **`stone-50`**.
- **App background** (`surface-app`) wraps the UI; **work panel** (`surface-page`) sits raised inside it — see [Layout](/design/layout).
- **Cards** on `surface-card` with shadow; **`card-bordered`** when adjacent surfaces match.
- **Inputs** use **`surface-card`** (`$input-bg`). **`stone-white`** is inverse text on dark UI only.
- **Body** `stone-900`, **muted** `stone-700`, **tertiary** `stone-600` (`text-body-tertiary`).


---

<!-- Source: design/typography.md -->

# Typography

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Three families on a fixed scale (largest → smallest below). **Copy tone** → [Content](/design/content). **When to use which** → [Rules](#rules).

| Family                      | Role                                                   |
| --------------------------- | ------------------------------------------------------ |
| **Newsreader** (600)        | Display and headings — names things                    |
| **Manrope** (400–700)       | Body, UI, labels, **dates**                            |
| **IBM Plex Mono** (tabular) | Counts, money, IDs in tables and summaries — not dates |

## Type scale

Largest to smallest. Samples use **Bootstrap markup** (`h1`, `display-1`, …); **`theme.scss` replaces CDN Bootstrap** heading styles.

<div class="sq-preview">
  <div class="sq-type-scale">
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">44px</span>
      <div>
        <p class="display-1 mb-0">Sqrl CRM</p>
        <p class="sq-type-scale__meta mb-0">Display / hero · Newsreader · 600 · marketing and empty-state heroes only</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">36px</span>
      <div>
        <h1 class="mb-0">Sqrl CRM</h1>
        <p class="sq-type-scale__meta mb-0">H1 / page title · Newsreader · 600 · one per screen in the page header</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">30px</span>
      <div>
        <h2 class="card-title mb-0">Sqrl CRM</h2>
        <p class="sq-type-scale__meta mb-0">H2 / card title · Newsreader · 600 · cards and primary section titles</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">25px</span>
      <div>
        <h3 class="modal-title mb-0">Sqrl CRM</h3>
        <p class="sq-type-scale__meta mb-0">H3 / panel title · Newsreader · 600 · modals, drawers, nested panels</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">21px</span>
      <div>
        <h4 class="mb-0">Sqrl CRM</h4>
        <p class="sq-type-scale__meta mb-0">H4 / subheading · Newsreader · 600 · groups inside a panel or long form</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">18px</span>
      <div>
        <p class="h5 fw-medium mb-0">Sqrl CRM</p>
        <p class="sq-type-scale__meta mb-0">Large body / metric · Manrope · 500 · KPIs and emphasized single lines</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">16px</span>
      <div>
        <p class="h6 mb-0">Sqrl CRM</p>
        <p class="sq-type-scale__meta mb-0">Body / UI base · Manrope · 400 · dense toolbars and compact UI blocks</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">14px</span>
      <div>
        <p class="mb-0">Sqrl CRM</p>
        <p class="sq-type-scale__meta mb-0">Body default · Manrope · 400 · paragraphs, buttons, fields, nav links</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">13px</span>
      <div>
        <label class="form-label mb-0">Sqrl CRM</label>
        <p class="sq-type-scale__meta mb-0">Label · Manrope · 600 · field labels, compact inputs, dropdown rows</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">12px</span>
      <div>
        <p class="form-text mb-0">Sqrl CRM</p>
        <p class="sq-type-scale__meta mb-0">Caption · Manrope · 500 · helper text and pagination chrome</p>
      </div>
    </div>
    <div class="sq-type-scale__row">
      <span class="sq-type-scale__px">11px</span>
      <div>
        <p class="small text-uppercase fw-bold text-body-tertiary mb-0">Sqrl CRM</p>
        <p class="sq-type-scale__meta mb-0">Micro-caps (min size) · Manrope · 700 · badges, table headers, uppercase metadata</p>
      </div>
    </div>
  </div>
</div>

**Mono** (IBM Plex Mono, 13px typical): `font-monospace`, `sq-cell--num` — not on this scale; see [Tables and summaries](#tables-and-summaries).

## Tables and summaries

- **Money and counts:** `sq-cell--num` — [Table](/components/table).
- **Dates and times:** Manrope — `sq-cell--date` ([Content](/design/content#numbers-and-dates)).
- **Pagination numerals:** `font-monospace fw-bold` on the range/total only — [Pagination](/components/pagination).
## Rules

### Families

1. **Serif** for display + `h1`–`h4` — [Layout](/design/layout#page-header) page title uses `h1`. Count in metric cards.
2. **Sans** for UI and dates; **mono** for numeric data only.

### Weights and case

1. Serif headings **600**; body **400**; labels / caption **500**; micro-caps **700** + `text-uppercase`.
2. Sentence case in UI; uppercase only for micro-caps and table column headers — [Content](/design/content#voice).

### Data

1. `sq-cell--num` vs `sq-cell--date` — never swap.
2. Dutch grouping (`18.400`); spaced euro (`€ 482K`) — [Content](/design/content#numbers-and-dates).


---

<!-- Source: design/iconography.md -->

# Iconography

Three layers — pick by **role**, not by size alone:

| Layer                   | Source                                                                                                        | Where                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Flat icons**          | [Bootstrap Icons 1.11.3](https://icons.getbootstrap.com/) (CDN — [Quick start](/getting-started/quick-start)) | System UI: nav, settings, toolbars, row actions, toasts, alerts, **empty states** (may be larger, still flat) |
| **Textured icons**      | PNG (transparent) from [Sqrl Icon Generator](https://design.sqrl.nl/icons/)                                   | Tasks, flow nodes, and other **entity** icons at list or node scale                                           |
| **Paper illustrations** | Supplied collage art (hero, dashboard)                                                                        | Large marketing / welcome surfaces only                                                                       |

Do not mix icon sets, use emoji as icons, or rely on colour without a word ([Content](/design/content), [Colors](/design/colors)).

## Flat icons (system UI)

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

**Default: filled** — prefer Bootstrap’s **`-fill`** glyphs where they exist (`bi-house-fill`, `bi-people-fill`, `bi-check-circle-fill`, …). These are **flat**, monochrome, and inherit text colour (`text-muted` at rest, `text-body` on hover).

**13–16px** in chrome. **One icon** per sidebar item, table row action, and toolbar control. Icon-only controls need **`aria-label`**; labelled buttons put the icon **before** the text ([Buttons](/components/buttons)). Toast and alert lead icons: [Feedback](/components/feedback).

**Empty states** use the same flat set inside a neutral tile (for example `bi-inbox-fill` at `fs-3`) — not textured PNGs ([Feedback](/components/feedback#empty-state)).

### Semantic vocabulary (flat)

<div class="row row-cols-2 row-cols-md-3 g-3 mb-4">
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-house-fill text-muted" aria-hidden="true"></i>
        <span>Home</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-buildings-fill text-muted" aria-hidden="true"></i>
        <span>Accounts</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-people-fill text-muted" aria-hidden="true"></i>
        <span>Contacts</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-check-square-fill text-muted" aria-hidden="true"></i>
        <span>Tasks</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-clock-fill text-muted" aria-hidden="true"></i>
        <span>Activities</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-diagram-3-fill text-muted" aria-hidden="true"></i>
        <span>Flows</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-gear-fill text-muted" aria-hidden="true"></i>
        <span>Settings</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-bell-fill text-muted" aria-hidden="true"></i>
        <span>Notifications</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-star-fill text-warning" aria-hidden="true"></i>
        <span>Key step</span>
      </div>
    </div>
  </div>
  <div class="col">
    <div class="card shadow-sm border-0">
      <div class="card-body d-flex align-items-center gap-2 py-3">
        <i class="bi bi-exclamation-triangle-fill text-danger" aria-hidden="true"></i>
        <span>Needs attention</span>
      </div>
    </div>
  </div>
</div>

Use **outline** Bootstrap icons only where no filled variant fits a control (chevrons, three-dots, pencil). Do not mix filled and outline nav sets in one rail — [Navigation](/components/navigation).

```html
<i class="bi bi-people-fill text-muted" aria-hidden="true"></i>
<span>Contacts</span>
```

Sortable table headers: `bi-chevron-expand` — [Table](/components/table).

### Flat icon tiles (fallback)

When no textured PNG exists yet: **34×34px** tile, **10px** radius, light **`bg-*-subtle`** + darker flat glyph. Same palette mapping as below. **Modal/offcanvas** headers use theme **`modal-icon`** with flat glyphs — [Modals](/components/modals).

## Textured icons

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Export from [Sqrl Icon Generator](https://design.sqrl.nl/icons/): Bootstrap icon shape + relief texture, **PNG with transparent background**. Use for **task types**, **flow nodes**, and similar **named entities** — not for settings, nav, or empty states.

- **Do not recolour** or re-tint the PNG.
- **Flow canvas / nodes:** use at **24px or larger** on the node surface (no flat glyph substitute at that scale).
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-end gap-4 mb-4">
    <div class="text-center">
      <span class="d-inline-flex align-items-center justify-content-center rounded mb-2" style="width: 34px; height: 34px">
        <img src="/assets/icon-task-call.png" width="24" height="24" alt="" />
      </span>
      <div class="small text-muted">Call</div>
    </div>
    <div class="text-center">
      <span class="d-inline-flex align-items-center justify-content-center rounded mb-2" style="width: 34px; height: 34px">
        <img src="/assets/icon-task-email.png" width="24" height="24" alt="" />
      </span>
      <div class="small text-muted">Email</div>
    </div>
    <div class="text-center">
      <span class="d-inline-flex align-items-center justify-content-center rounded mb-2" style="width: 34px; height: 34px">
        <img src="/assets/icon-task-meeting.png" width="24" height="24" alt="" />
      </span>
      <div class="small text-muted">Meeting</div>
    </div>
  </div>

  <div class="card card-bordered mb-0">
    <ul class="list-group list-group-flush">
      <li class="list-group-item d-flex align-items-center gap-3 py-3">
        <input class="form-check-input flex-shrink-0 mt-0" type="checkbox" aria-label="Select task" />
        <span class="d-inline-flex align-items-center justify-content-center rounded bg-info-subtle flex-shrink-0" style="width: 34px; height: 34px">
          <img src="/assets/icon-task-call.png" width="24" height="24" alt="" />
        </span>
        <div class="min-w-0">
          <div class="fw-semibold">Chase signature – Delta Staal</div>
          <div class="small text-muted">Van den Berg Logistics · Marieke de Groot</div>
        </div>
      </li>
      <li class="list-group-item d-flex align-items-center gap-3 py-3">
        <input class="form-check-input flex-shrink-0 mt-0" type="checkbox" aria-label="Select task" />
        <span class="d-inline-flex align-items-center justify-content-center rounded bg-success-subtle flex-shrink-0" style="width: 34px; height: 34px">
          <img src="/assets/icon-task-meeting.png" width="24" height="24" alt="" />
        </span>
        <div class="min-w-0">
          <div class="fw-semibold">Draft onboarding plan – Havenstad Groep</div>
          <div class="small text-muted">TechBuild · Pieter Janssens</div>
        </div>
      </li>
    </ul>
  </div>
</div>

```html
<span
  class="d-inline-flex align-items-center justify-content-center rounded bg-info-subtle flex-shrink-0"
  style="width: 34px; height: 34px"
>
  <img src="/assets/icon-task-call.png" width="24" height="24" alt="" />
</span>
```

## Paper illustrations

Large **paper-collage** art (dashboard welcome, campaign hero) sits **behind** or **beside** functional content — never as chrome. When building an app, reserve a **placeholder region** (fixed aspect ratio, `bg-body-secondary` or neutral panel); drop in supplied artwork later. **Do not** ask implementation tools to generate these illustrations in place of real assets.

## Rules

- **Flat / filled Bootstrap Icons** for all **system UI**, including **large empty-state** icons.
- **Textured PNGs** from [design.sqrl.nl/icons](https://design.sqrl.nl/icons/) for **tasks**, **flow nodes**, and entity lists — **not** recoloured.
- **Illustrations** for hero-scale only; use a **placeholder container** until art is supplied.
- **Never:** emoji, mixed sets, colour-only meaning, hand-drawn SVG substitutes for generator icons.
- **Icon-only:** `aria-label`. **Labelled buttons:** icon before text.
- **Related:** [Navigation](/components/navigation), [Buttons](/components/buttons), [Feedback](/components/feedback)


---

<!-- Source: design/spacing.md -->

# Spacing

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

4px base grid, corner radius, elevation, and motion. Page shell and control sizes → [Layout](/design/layout) and [Buttons](/components/buttons). **When to use which** → [Rules](#rules).

## Scale

Use **`p-*`**, **`m-*`**, **`g-*`**, **`gap-*`** — utility index **`n`** = **`n` × 4px** for steps **1–4**.
Bar **width = token in px** (1:1) — compare steps side by side; in markup use utilities (`gap-4`, `px-4`, …), not inline widths.

<div class="sq-preview">
  <div class="d-flex flex-column gap-2">
    <div class="d-flex align-items-center gap-3">
      <span class="small font-monospace text-muted text-end" style="width: 2rem">4px</span>
      <div class="bg-primary border border-primary rounded-1" style="width: 4px; height: 12px" aria-hidden="true"></div>
    </div>
    <div class="d-flex align-items-center gap-3">
      <span class="small font-monospace text-muted text-end" style="width: 2rem">8px</span>
      <div class="bg-primary border border-primary rounded-1" style="width: 8px; height: 12px" aria-hidden="true"></div>
    </div>
    <div class="d-flex align-items-center gap-3">
      <span class="small font-monospace text-muted text-end" style="width: 2rem">16px</span>
      <div class="bg-primary border border-primary rounded-1" style="width: 16px; height: 12px" aria-hidden="true"></div>
    </div>
    <div class="d-flex align-items-center gap-3">
      <span class="small font-monospace text-muted text-end" style="width: 2rem">24px</span>
      <div class="bg-primary border border-primary rounded-1" style="width: 24px; height: 12px" aria-hidden="true"></div>
    </div>
    <div class="d-flex align-items-center gap-3">
      <span class="small font-monospace text-muted text-end" style="width: 2rem">32px</span>
      <div class="bg-primary border border-primary rounded-1" style="width: 32px; height: 12px" aria-hidden="true"></div>
    </div>
  </div>
</div>

Utility index **`1`–`4`** matches the preview (`gap-1` … `gap-4`). **Page gutters** (16px vs 32px) → [Layout](/design/layout#page-content).

## Shape

Soft corners — nothing sharp. Use Bootstrap **`rounded-*`** utilities (theme tokens in `theme.scss`).

<div class="sq-preview">
  <div class="d-flex flex-wrap gap-3 align-items-end">
    <div class="text-center">
      <div class="border bg-white rounded-0" style="width: 4.5rem; height: 3rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-0</p>
      <p class="small text-muted mb-0">0</p>
    </div>
    <div class="text-center">
      <div class="border bg-white rounded-1" style="width: 4.5rem; height: 3rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-1</p>
      <p class="small text-muted mb-0">8px</p>
    </div>
    <div class="text-center">
      <div class="border bg-white rounded-2" style="width: 4.5rem; height: 3rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-2</p>
      <p class="small text-muted mb-0">10px</p>
    </div>
    <div class="text-center">
      <div class="border bg-white rounded-3" style="width: 4.5rem; height: 3rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-3</p>
      <p class="small text-muted mb-0">14px</p>
    </div>
    <div class="text-center">
      <div class="border bg-white rounded-4" style="width: 4.5rem; height: 3rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-4</p>
      <p class="small text-muted mb-0">18px</p>
    </div>
    <div class="text-center">
      <div class="border bg-white rounded-5" style="width: 4.5rem; height: 3rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-5</p>
      <p class="small text-muted mb-0">20px</p>
    </div>
    <div class="text-center">
      <div class="border bg-white rounded-pill" style="width: 5.5rem; height: 2rem"></div>
      <p class="small font-monospace mb-0 mt-2">rounded-pill</p>
      <p class="small text-muted mb-0">pill</p>
    </div>
  </div>
</div>

`rounded` (no suffix) equals **`rounded-2`** (10px). **`rounded-circle`** = 50% — avatars only, not a fixed px radius.

| Class / token          | Radius | Theme variable                                                      |
| ---------------------- | ------ | ------------------------------------------------------------------- |
| `rounded-0`            | 0      | —                                                                   |
| `rounded-1`            | 8px    | `$border-radius-sm`                                                 |
| `rounded-2`, `rounded` | 10px   | `$border-radius`                                                    |
| `rounded-3`            | 14px   | `$border-radius-lg` (cards, dropdowns)                              |
| `rounded-4`            | 18px   | `$border-radius-xl` ([page panel](/design/layout#app-shell), `sq-panel`) |
| `rounded-5`            | 20px   | `$border-radius-xxl` (modals)                                       |
| `rounded-pill`         | pill   | `$border-radius-pill` (badges, nav-pills)                           |
| `rounded-circle`       | 50%    | circular avatars                                                    |
| — (4px affordances)    | 4px    | `$border-radius-xs` — checkboxes, tooltips; no `rounded-*` class    |

## Elevation

Warm, subtle shadows. Cards default **borderless** with **`shadow-md`**; **`card-bordered`** + lighter shadow when the background is close to the card. Inputs use **inset** shadow so fields read recessed.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-md-4">
      <div class="card h-100">
        <div class="card-body">
          <h3 class="card-title h6 mb-1">shadow-sm</h3>
          <p class="card-text text-muted small mb-0">Bordered / low lift</p>
        </div>
      </div>
    </div>
    <div class="col-md-4">
      <div class="card shadow h-100">
        <div class="card-body">
          <h3 class="card-title h6 mb-1">shadow / md</h3>
          <p class="card-text text-muted small mb-0">Default card, menus</p>
        </div>
      </div>
    </div>
    <div class="col-md-4">
      <div class="card shadow-lg h-100">
        <div class="card-body">
          <h3 class="card-title h6 mb-1">shadow-lg</h3>
          <p class="card-text text-muted small mb-0">Page panel, toasts</p>
        </div>
      </div>
    </div>
  </div>
</div>

CSS variables: **`--sq-shadow-sm`**, **`--sq-shadow-md`**, **`--sq-shadow-lg`**, **`--sq-shadow-inset`** — see [Colors](/design/colors) surfaces.

## Motion

Fast, functional timing — no decorative motion.

| Token / use    | Duration |
| -------------- | -------- |
| Press          | 80ms     |
| Hover          | 120ms    |
| Shadow, switch | 180ms    |
| Modal rise     | 260ms    |

Easing: **`cubic-bezier(.2, 0, .2, 1)`** — no overshoot or bounce. No looping or pulsing. Rows and buttons do not shift on hover.

## Rules

### Grid and utilities

1. Prefer Bootstrap **`gap-*`** / **`g-*`** on flex and grid before one-off margins.
2. Stack vertical rhythm with **`mb-*`** or **`gap-*`**, not empty spacer divs.
3. Page-level insets and shell measures — [Layout](/design/layout); control heights — [Forms](/components/forms), [Buttons](/components/buttons).

### Shape, shadow, motion

1. Pick **`rounded-*`** from the table — cards **`rounded-3`**, page panel **`rounded-4`**, modals **`rounded-5`**; smaller controls via component styles (`rounded-1` / `rounded-2`).
2. Default cards: raised **`shadow-md`**, no border; **`card-bordered`** when contrast is low.
3. Motion stays short and ease-out; never animate layout shift on hover for rows or buttons.


---

<!-- Source: design/layout.md -->

# Layout

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Application **shell**: sidebar rail and floating work panel. Tokens: [Colors](/design/colors) (`surface-app`, `surface-page`), [Spacing](/design/spacing). **Responsive rules** for narrow viewports are documented separately when added.

This page is **layout guidance**. **Strongly recommended** on every app screen: **sidebar** → **page panel** → **page header** → scrollable **page content**. That shell is fixed; only the optional [scope bar](#scope-bar) sits above the header when scoped. **Inside** page content, patterns (filter row, list card, split columns, etc.) are optional — pick per page. Copy, entities, and controls are not prescribed here.

## App shell

One outer **horizontal flex** row, full viewport (`100vw` × `100vh`), background **`surface-app`** (`#E8E0D7`) — the desk the rail and work panel sit on.

| Region         | Role                                                                                                                                                                                                                                              |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sidebar**    | Fixed **248px**, full height, flush on the rail (same `surface-app`). Does not scroll with page content.                                                                                                                                          |
| **Page panel** | **`flex: 1`**, background **`surface-page`** (`#F4F0EA`), **`rounded-4`** (18px), **`box-shadow: var(--sq-shadow-lg)`**, margin **`10px 10px 10px 0`** — floats above the desk on the top, right, and bottom; the rail stays visible on the left. |

Inside the page panel: optional [scope bar](#scope-bar), then **page header** (fixed), then **page content** (scrolls). Only page content uses `flex-grow-1 overflow-auto` + **`min-height: 0`**.

**Recommended stack** (top → bottom):

| Layer                         | Required?                               |
| ----------------------------- | --------------------------------------- |
| [Scope bar](#scope-bar)       | Optional — scoped context only          |
| [Page header](#page-header)   | **Yes** — title/actions; density varies |
| [Page content](#content-area) | **Yes** — everything else scrolls here  |

Within page content, the [filter row](#filter-row) and other patterns are optional.

```html
<!-- Structure only — omit optional blocks per screen -->
<div class="d-flex vh-100" style="background: var(--sq-surface-app)">
  <aside><!-- 248px sidenav --></aside>
  <div
    class="sq-panel flex-grow-1 d-flex flex-column"
    style="margin: 10px 10px 10px 0"
  >
    <div class="sq-scope-bar" role="region"><!-- optional --></div>
    <header class="border-bottom flex-shrink-0">
      <!-- page header (recommended) -->
    </header>
    <div class="flex-grow-1 overflow-auto min-h-0">
      <!-- page content -->
      <div><!-- optional filter row --></div>
      <!-- page body: lists, cards, forms, … -->
    </div>
  </div>
</div>
```

Use **`sq-panel`** (**Sqrl custom** — same as `overflow-hidden border rounded-4`; tag on [Scope bar](#scope-bar) below) when the scope bar caps the panel ([Navigation](/components/navigation#scope-bar)); otherwise the raised **`surface-page`** shell alone is enough.

## Sidebar rail

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Top to bottom ([Navigation](/components/navigation)):

1. **Scope control** — only selector in the rail ([Scope switch](/components/scope-switch); workspace, tenant, or account).
2. **Divider**
3. **Primary nav** — flat list; icon + label + optional mono count; one **`active`** + **`aria-current="page"`**. Labels and order: [Navigation](/components/navigation).
4. **Footer** (`margin-top: auto`) — search (⌘K), then user row (avatar, name, profile link, sign-out control).

## Scope bar

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

When the UI is **scoped** to one context (one record, project, tenant slice, etc.), show [`sq-scope-bar`](/components/navigation#scope-bar) at the **top of the work panel** — above the [page header](#page-header). It names the scope (title + optional meta) and one **exit** control back to the wider app; it is not a second primary nav.

- Rail: [scope control](/design/layout#sidebar-rail) enters/exits scope; nav items may reorder ([Navigation](/components/navigation#account-context)).
- Panel: bar flush to the panel top inside **`sq-panel`**; header and content sit below.
- Same markup/tokens for any scope type — only labels and icon change.

## Page header

Top of the page panel after an optional [scope bar](#scope-bar). **Fixed** above [page content](#content-area) (recommended on every screen). The filter row is **not** part of the header — it lives inside page content. The **`<header>` spans the full width** of the panel. Put **`border-bottom`** on that outer element so the rule runs edge to edge; **padding** lives on an **inner wrapper** only (`px-4`, `pt-3`, `pb-3` — match list content inset, usually **16px** horizontal).

[breadcrumb](/components/navigation#breadcrumb) (optional), **Newsreader** `h1`, optional **subtitle** (`text-muted`), **primary action** on the right with **`align-items-start`**.

<div class="sq-preview p-0">
  <header class="border-bottom mb-0">
    <div class="px-4 pt-3 pb-3">
      <div class="d-flex align-items-start justify-content-between gap-3">
        <div>
          <nav aria-label="breadcrumb" class="mb-2">
            <ol class="breadcrumb mb-0">
              <li class="breadcrumb-item"><a href="#">Home</a></li>
              <li class="breadcrumb-item active" aria-current="page">Accounts</li>
            </ol>
          </nav>
          <h1 class="h1">Accounts</h1>
          <p class="text-muted mb-0"><span class="font-monospace">24</span> companies in this view</p>
        </div>
        <button type="button" class="btn btn-primary flex-shrink-0 align-self-start">
          <i class="bi bi-plus-lg me-1" aria-hidden="true"></i>
          New account
        </button>
      </div>
    </div>
  </header>
</div>

```html
<header class="border-bottom">
  <div class="px-4 pt-3 pb-3">
    <nav aria-label="breadcrumb" class="mb-2">
      <ol class="breadcrumb mb-0">
        <li class="breadcrumb-item"><a href="#">Home</a></li>
        <li class="breadcrumb-item active" aria-current="page">Accounts</li>
      </ol>
    </nav>
    <div class="d-flex align-items-start justify-content-between gap-3">
      <div>
        <h1>Accounts</h1>
        <p class="text-muted mb-0">
          <span class="font-monospace">24</span> companies in this view
        </p>
      </div>
      <button
        type="button"
        class="btn btn-primary flex-shrink-0 align-self-start"
      >
        <i class="bi bi-plus-lg me-1" aria-hidden="true"></i>
        New account
      </button>
    </div>
  </div>
</header>
```

## Page content {#content-area}

Everything below the [page header](#page-header): [tables](/components/table), [cards](/components/card), search, filters, forms, empty states, section grids, optional [filter row](#filter-row), etc. Fills the **rest of the page panel** and **scrolls as one block** (unless a nested region scrolls on its own, e.g. [`overflow-auto` + `sq-table-sticky-head`](/components/table#sticky-header)).

There is **no single mandatory layout** inside this region. The subsections below are **optional patterns** (list shell, overview grid, split columns, form stacks) — use, merge, or skip them per page.

### Loading content

While data or a view is still fetching, keep fixed chrome ([page header](#page-header); optional [filter row](#filter-row) when tab labels are already known) and fill **page content** with [skeleton placeholders](/components/feedback#skeleton) shaped like the loaded layout — same inset, card shell, or table band you will show when ready. Do not leave the scroll region blank or use a full-page spinner; swap skeletons for real markup when the response arrives.

### Filter row

**Optional.** Part of **page content**, not the page header — when used, it usually sits **at the top** of the scroll region (first band below the header). It **scrolls with** the body unless you make it sticky. Many pages omit it entirely.

Full width within the content inset; **same horizontal padding** as the header (`px-4`). Typical layout: **property filters / other page content** on the left ([pill tabs](/components/navigation#pill-tabs) — All / Mine / Active); **presentation of the same data** on the right (table ↔ cards via [segmented](/components/segmented#icons); sort [dropdown](/components/dropdown#sort-menu)) — **`align-items-start`**, `justify-content-between`. Exact controls depend on the page. **Tabs vs segmented vs pill radio** → [Navigation — Choose a control](/components/navigation#choose-a-control).

<div class="sq-preview p-0">
  <div class="px-4 d-flex flex-wrap align-items-start justify-content-between gap-3 py-3 mb-0">
    <ul class="nav nav-pills mb-0">
      <li class="nav-item">
        <a class="nav-link active" href="#" aria-current="page">All <span class="font-monospace">24</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Active <span class="font-monospace">19</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Inactive <span class="font-monospace">5</span></a>
      </li>
    </ul>
    <div class="d-flex align-items-center gap-2">
      <div class="dropdown">
        <button
          type="button"
          class="btn btn-sm btn-ghost fw-medium text-body py-0"
          data-bs-toggle="dropdown"
          aria-expanded="false"
        >
          <i class="bi bi-arrow-down-up me-1" aria-hidden="true"></i>
          Name (A-Z)
        </button>
        <div class="dropdown-menu dropdown-menu-end">
          <button type="button" class="dropdown-item active" aria-current="true">Name (A-Z)</button>
          <button type="button" class="dropdown-item">Name (Z-A)</button>
          <button type="button" class="dropdown-item">Quote potential (high-low)</button>
          <button type="button" class="dropdown-item">Quote potential (low-high)</button>
        </div>
      </div>
      <div class="sq-segmented sq-segmented-sm" role="group" aria-label="Layout">
        <input type="radio" class="btn-check" name="layout-demo" id="layout-demo-list" autocomplete="off" checked aria-label="List" />
        <label class="btn" for="layout-demo-list"><i class="bi bi-list-ul" aria-hidden="true"></i></label>
        <input type="radio" class="btn-check" name="layout-demo" id="layout-demo-grid" autocomplete="off" aria-label="Grid" />
        <label class="btn" for="layout-demo-grid"><i class="bi bi-grid" aria-hidden="true"></i></label>
      </div>
    </div>
  </div>
</div>

```html
<div
  class="px-4 d-flex flex-wrap align-items-start justify-content-between gap-3"
>
  <ul class="nav nav-pills mb-0">
    <li class="nav-item">
      <a class="nav-link active" href="#" aria-current="page"
        >All <span class="font-monospace">24</span></a
      >
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#"
        >Active <span class="font-monospace">19</span></a
      >
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#"
        >Inactive <span class="font-monospace">5</span></a
      >
    </li>
  </ul>
  <div class="d-flex align-items-center gap-2">
    <div class="dropdown">
      <button
        type="button"
        class="btn btn-sm btn-ghost fw-medium text-body py-0"
        data-bs-toggle="dropdown"
        aria-expanded="false"
      >
        <i class="bi bi-arrow-down-up me-1" aria-hidden="true"></i>
        Name (A-Z)
      </button>
      <div class="dropdown-menu dropdown-menu-end">
        <button type="button" class="dropdown-item active" aria-current="true">
          Name (A-Z)
        </button>
        <button type="button" class="dropdown-item">Name (Z-A)</button>
        <button type="button" class="dropdown-item">
          Quote potential (high-low)
        </button>
        <button type="button" class="dropdown-item">
          Quote potential (low-high)
        </button>
      </div>
    </div>
    <div class="sq-segmented sq-segmented-sm" role="group" aria-label="Layout">
      <input
        type="radio"
        class="btn-check"
        name="layout"
        id="layout-list"
        autocomplete="off"
        checked
        aria-label="List"
      />
      <label class="btn" for="layout-list"
        ><i class="bi bi-list-ul" aria-hidden="true"></i
      ></label>
      <input
        type="radio"
        class="btn-check"
        name="layout"
        id="layout-grid"
        autocomplete="off"
        aria-label="Grid"
      />
      <label class="btn" for="layout-grid"
        ><i class="bi bi-grid" aria-hidden="true"></i
      ></label>
    </div>
  </div>
</div>
```

### Padding

| Context                             | Horizontal / vertical inset                                                                             |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------- |
| **Dense list / table pages**        | **`16px`** (`px-4`, `pb-4`) — align with header/filter [`px-4`](/design/spacing)                        |
| **Looser overview / section grids** | **`32px`** page gutter (`p-4` on the scroll container or section wrappers) — [Spacing](/design/spacing) |

### List and table pages (optional pattern)

When the main body is a **data table**, an optional [filter row](#filter-row) can sit above a **raised container** on `surface-page` — often **[`card-bordered`](/components/card#bordered)** so the toolbar and grid read as one object; **[pagination](/components/pagination)** sits **below** the card on `surface-page`, not in **`card-footer`**.

Typical vertical stack ([Table](/components/table#toolbar)):

1. **Toolbar** — search, facet [`form-select`](/components/forms) filters, secondary actions as needed; often **`border-bottom`** before the grid.
2. **`table.table`** ([Table](/components/table) — optional **`overflow-hidden`** when not inside a card). Tables and `thead` are square (no `rounded`). Inside a **card**, wrap the table in **`mx-3`** so it does not flush to the card edges.
3. **[Pagination](/components/pagination)** — summary + pages **outside** the card (same horizontal inset as the list — e.g. **`px-4`** on the scroll area).

**Guideline:** **property filters and other page content** as [pill tabs](/components/navigation#pill-tabs) in the filter row; **search and field filters** in the toolbar; **table ↔ cards** as [segmented](/components/segmented) — [Choose a control](/components/navigation#choose-a-control).

<div class="sq-preview p-0">
  <div class="px-4 py-4 mb-0">
    <div class="card card-bordered mb-0">
      <div class="px-3 py-3  d-flex flex-wrap align-items-center justify-content-between gap-3">
        <div class="d-flex flex-wrap align-items-center gap-2">
          <div class="input-group input-group-sm" style="width: 14rem">
            <span class="input-group-text"><i class="bi bi-search" aria-hidden="true"></i></span>
            <input type="search" class="form-control" placeholder="Search accounts…" aria-label="Search accounts" />
          </div>
          <select class="form-select form-select-sm" style="width:7rem" aria-label="Type">
            <option selected>All types</option>
            <option>Client</option>
            <option>Prospect</option>
          </select>
          <select class="form-select form-select-sm" style="width:7rem" aria-label="Market">
            <option selected>All markets</option>
            <option>Benelux</option>
            <option>DACH</option>
          </select>
        </div>
        <button type="button" class="btn btn-sm btn-secondary">
          <i class="bi bi-download me-1" aria-hidden="true"></i>
          Export
        </button>
      </div>
      <div class="mx-3 mb-3">
        <div class="overflow-hidden mb-0">
          <table class="table mb-0">
            <thead>
              <tr>
                <th scope="col">Name</th>
                <th scope="col">City</th>
                <th scope="col">Status</th>
                <th class="text-end" scope="col">Quote potential</th>
              </tr>
            </thead>
            <tbody>
              <tr class="sq-row--clickable">
                <td>Van Dijk Logistics</td>
                <td>Rotterdam</td>
                <td><span class="badge badge-borderless badge-dotted text-bg-success">Active</span></td>
                <td class="sq-cell--num">€ 132.000</td>
              </tr>
              <tr class="sq-row--clickable">
                <td>North Sea Marine</td>
                <td>Den Helder</td>
                <td><span class="badge badge-borderless badge-dotted text-bg-secondary">Inactive</span></td>
                <td class="sq-cell--num">€ 78.000</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
    <div class="d-flex flex-wrap align-items-center justify-content-between gap-3 mt-3">
      <p class="small text-secondary mb-0">
        Showing
        <span class="font-monospace fw-bold">1–10</span>
        of
        <span class="font-monospace fw-bold">24</span>
      </p>
      <nav aria-label="Accounts pages">
        <ul class="pagination mb-0">
          <li class="page-item disabled">
            <span class="page-link" aria-label="Previous page">
              <i class="bi bi-chevron-left" aria-hidden="true"></i>
            </span>
          </li>
          <li class="page-item active" aria-current="page"><span class="page-link">1</span></li>
          <li class="page-item"><a class="page-link" href="#">2</a></li>
          <li class="page-item">
            <a class="page-link" href="#" aria-label="Next page">
              <i class="bi bi-chevron-right" aria-hidden="true"></i>
            </a>
          </li>
        </ul>
      </nav>
    </div>
  </div>
</div>

### Overview-style pages (optional pattern)

Hub or summary pages: often **`32px`** gutter ([Spacing](/design/spacing)), **no filter row**; body is [cards](/components/card) and/or sections in the scroll area (intro block may live in the header or content — either is fine).

**Preferred (optional):** **`row`** / **`g-4`** with **mixed column widths** and **at least one row that breaks the rhythm** — avoid a single column of identical boxes.

### Split content (optional pattern)

When one full-width column is not enough, **page content** may use a **horizontal split** (this is not the 248px app sidebar):

| Column                             | Role                                                                                                                            |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **Secondary column** (fixed width) | Optional local nav, outline, progress, or meta — **whatever the page needs**; scrolls with the page or sticky within the split. |
| **Primary column**                 | Main body — detail, forms, [cards](/components/card), etc.                                                                      |

Often paired with a [scope bar](#scope-bar) and/or a compact [page header](#page-header), but the split is a **layout option**, not a requirement for scoped or multi-step flows. Default list pages stay **single column**.

### Forms and detail blocks (optional pattern)

Full-width **field rows** on `surface-page` or inside a card: **`border-subtle`** between rows; **no border on the last row**. Destructive or save actions belong in the [page header](#page-header) when they apply to the whole page, not repeated on every row.

## Rules

1. **Default shell (strongly recommended):** **sidebar** (248px) + **page panel** (`surface-page`, **`rounded-4`**, `--sq-shadow-lg`, 10px margin top/right/bottom) + **page header** + scrollable **page content**. Do not drop parts of this shell without a clear reason.
2. **`surface-app`** = outer desk behind the sidebar; **only page content scrolls** (unless a deliberate inner scroll on table wrap or split layout).
3. Primary nav structure and labels: [Navigation](/components/navigation).
4. **Scope:** rail scope control + optional [`sq-scope-bar`](/components/navigation#scope-bar) on scoped screens — [Scope bar](#scope-bar).
5. **One `btn-primary`** in the page header title row when that row has a primary action; **Newsreader** `h1`. **Full-width** `<header>` with **`border-bottom`** on the outer element; padding on an inner wrapper. Optional breadcrumb or micro-caps eyebrow — not both unless the hierarchy needs it.
6. Fixed chrome = scope bar (if any) + page header; **page content** = **`overflow-auto`** + **`min-height: 0`**, with optional [filter row](#filter-row) as the first block when needed.
7. **List pattern (optional):** filter row → bordered shell → toolbar → table wrap → pagination; property filters vs presentation vs search as in [List and table pages](#list-and-table-pages-optional-pattern).
8. Prefer the **simplest** stack — omit filter row, card shell, or [split content](#split-content-optional-pattern) when a single column suffices.
9. **Loading:** skeleton placeholders in [page content](#content-area) only — [Loading content](#loading-content); empty lists use [empty state](/components/feedback#empty-state), not skeletons.


---

<!-- Source: design/content.md -->

# Content

Tone: formal, business-like, tight, unambiguous. The UI states facts and next steps; it does not chat, apologise or cheer. Vibe: an instrument, not a companion.

## Voice

- Address the user as _you_ only where an action is theirs ("Assign owners"). The system never says I.
- Data lines are impersonal and name the source when it is known: "Imported from Sqrl ABM", "Imported from CSV".
- Sentence case everywhere. The only uppercase is [micro-caps](/design/typography) for section headers and table columns.
- Emoji: never. Meaning is carried by Bootstrap Icons and colour — never colour alone ([Iconography](/design/iconography), [Colors](/design/colors), [badges](/components/badge)).
## Buttons

Verb + object: "Assign owners", "Save changes", "Import prospects", "Delete contact". **Create** actions may use **New** or **Add** + entity: "New contact", "Add contact". Not "Submit", "OK", or "Click here". Destructive buttons name the object.

Add a **Bootstrap Icon** when it makes the action obvious at a glance — for example **plus** on create/add and **trash** on delete. Icon before the label; keep the text unless the control is icon-only ([Iconography](/design/iconography), [Buttons](/components/buttons)).

<div class="d-flex flex-wrap gap-2 mb-4">
  <button type="button" class="btn btn-primary btn-sm">
    <i class="bi bi-plus-lg me-1" aria-hidden="true"></i>
    New contact
  </button>
  <button type="button" class="btn btn-secondary btn-sm">Assign owners</button>
  <button type="button" class="btn btn-secondary btn-sm">Save changes</button>
  <button type="button" class="btn btn-danger btn-sm">
    <i class="bi bi-trash me-1" aria-hidden="true"></i>
    Delete contact
  </button>
</div>

## Labels

Field and control labels are **nouns**, sentence case, **no colon**: "Company name", "Due date", "Owner". Placeholder and helper text follow the same tone — impersonal where it is system data, not instructions disguised as labels.

<div class="mb-4" style="max-width: 20rem;">
  <label class="form-label" for="content-demo-company">Company name</label>
  <input class="form-control" id="content-demo-company" type="text" autocomplete="off" />
  <label class="form-label mt-3" for="content-demo-due">Due date</label>
  <input class="form-control" id="content-demo-due" type="date" />
</div>

Form layout and validation copy: [Forms](/components/forms).

## Errors and confirmations

**Inline alerts** ([Feedback](/components/feedback#alert)) use three copy shapes:

- **Success** — past-tense outcome, often impersonal: what happened and from where ("18 prospects imported from CSV.").
- **Warning** — **fact** in the semibold line, **impact or next step** in smaller body text; when the user can fix it in place, one **`btn-secondary`** on the alert ("Assign owners").
- **Danger** — what blocks progress and what to do next, in one or two short sentences ("Assign an owner before activating this step.").
Transient save/create confirmations use **toasts** instead: past tense, no full stop — "Contact created", "Changes saved".

<div class="alert alert-success d-flex align-items-start gap-2 mb-3" role="status">
  <i class="bi bi-check-circle-fill" aria-hidden="true"></i>
  <div>18 prospects imported from CSV.</div>
</div>
<div class="alert alert-warning d-flex align-items-center gap-2 mb-3" role="status">
  <i class="bi bi-exclamation-triangle-fill flex-shrink-0 align-self-start" aria-hidden="true"></i>
  <div class="flex-grow-1 min-w-0">
    <div class="fw-semibold">12 prospects are missing an owner</div>
    <div class="small text-body">Unassigned prospects are not included in flow automation.</div>
  </div>
  <button type="button" class="btn btn-sm btn-secondary flex-shrink-0">Assign owners</button>
</div>
<div class="alert alert-danger d-flex align-items-start gap-2 mb-4" role="alert">
  <i class="bi bi-x-circle-fill" aria-hidden="true"></i>
  <div>Assign an owner before activating this step.</div>
</div>

Never "Something went wrong". Validation and forms: [Forms](/components/forms), [Feedback](/components/feedback).

## Numbers and dates

Counts and money are always numerals with tabular figures: `412 contacts`, `€ 482K`, `31%`. Dutch thousand separators (`18.400`) since the data is Dutch; the € sign is spaced from the number.

Dates use **Manrope** (same as body), not monospace. Format `12 Mar 2026`; append time for activities: `12 Mar 2026, 14:20`. Relative words only for the near horizon: "Today", "Tomorrow". In tables, right-align with **`sq-cell--date`** ([Table](/components/table)).

Abbreviations are allowed for people in dense tables ("M. de Groot") and expanded in headers and panels ("Marieke de Groot").

## Rules

- UI copy is **English**; numeric formatting follows **Dutch** conventions where data is Dutch.
- **Sentence case**; micro-caps only for section headers and table columns.
- **Buttons:** verb + object; **New** / **Add** + entity for create; destructive buttons name the object; icons when they clarify (plus, trash, …) with label kept.
- **Labels:** nouns, no colon.
- **Errors:** specific and actionable; **confirmations:** short past tense.
- **No** emoji, "Submit", "OK", "Click here", or generic "Something went wrong".
- **Icons + colour** carry meaning together — see [Iconography](/design/iconography) and [Colors](/design/colors).


---

<!-- Source: components/accordion.md -->

# Accordion

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap **`accordion`**: expandable FAQ-style sections with one panel open per group (**`data-bs-parent`**). Markup below; **default vs flush** and **when to use** → [Rules](#rules).

## Default

Bordered card (**`accordion`** on **`--bs-accordion-border-radius`**). Rows divided by **`border-subtle`**. Chevron on the button rotates when open (Bootstrap **`accordion-button::after`**).

<div class="sq-preview">
  <div class="accordion" id="sq-accordion-default">
    <div class="accordion-item">
      <h2 class="accordion-header">
        <button
          class="accordion-button"
          type="button"
          data-bs-toggle="collapse"
          data-bs-target="#sq-accordion-default-item-1"
          aria-expanded="true"
          aria-controls="sq-accordion-default-item-1"
        >
          Who can change account settings?
        </button>
      </h2>
      <div
        id="sq-accordion-default-item-1"
        class="accordion-collapse collapse show"
        data-bs-parent="#sq-accordion-default"
      >
        <div class="accordion-body">
          Admins and account owners. Members can view but not edit billing or ownership.
        </div>
      </div>
    </div>
    <div class="accordion-item">
      <h2 class="accordion-header">
        <button
          class="accordion-button collapsed"
          type="button"
          data-bs-toggle="collapse"
          data-bs-target="#sq-accordion-default-item-2"
          aria-expanded="false"
          aria-controls="sq-accordion-default-item-2"
        >
          How do notifications work?
        </button>
      </h2>
      <div
        id="sq-accordion-default-item-2"
        class="accordion-collapse collapse"
        data-bs-parent="#sq-accordion-default"
      >
        <div class="accordion-body">
          Email and in-app alerts use the same tone rules as [toasts](/components/feedback). You can dismiss each item from the drawer.
        </div>
      </div>
    </div>
    <div class="accordion-item">
      <h2 class="accordion-header">
        <button
          class="accordion-button collapsed"
          type="button"
          data-bs-toggle="collapse"
          data-bs-target="#sq-accordion-default-item-3"
          aria-expanded="false"
          aria-controls="sq-accordion-default-item-3"
        >
          Can I export a list?
        </button>
      </h2>
      <div
        id="sq-accordion-default-item-3"
        class="accordion-collapse collapse"
        data-bs-parent="#sq-accordion-default"
      >
        <div class="accordion-body">
          Yes — use <strong>Export</strong> on any table view; CSV includes visible columns for the current filter.
        </div>
      </div>
    </div>
  </div>
</div>

```html
<div class="accordion" id="accordionExample">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button
        class="accordion-button"
        type="button"
        data-bs-toggle="collapse"
        data-bs-target="#collapseOne"
        aria-expanded="true"
        aria-controls="collapseOne"
      >
        Who can change account settings?
      </button>
    </h2>
    <div
      id="collapseOne"
      class="accordion-collapse collapse show"
      data-bs-parent="#accordionExample"
    >
      <div class="accordion-body">…</div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button
        class="accordion-button collapsed"
        type="button"
        data-bs-toggle="collapse"
        data-bs-target="#collapseTwo"
        aria-expanded="false"
        aria-controls="collapseTwo"
      >
        How do notifications work?
      </button>
    </h2>
    <div
      id="collapseTwo"
      class="accordion-collapse collapse"
      data-bs-parent="#accordionExample"
    >
      <div class="accordion-body">…</div>
    </div>
  </div>
</div>
```

## Flush

**`accordion accordion-flush`**: no outer border or radius — full-bleed dividers only. Use inside a [card](/components/card) or panel that already defines the surface.

<div class="sq-preview">
      <div class="accordion accordion-flush" id="sq-accordion-flush">
        <div class="accordion-item">
          <h2 class="accordion-header">
            <button
              class="accordion-button"
              type="button"
              data-bs-toggle="collapse"
              data-bs-target="#sq-accordion-flush-item-1"
              aria-expanded="true"
              aria-controls="sq-accordion-flush-item-1"
            >
              Who can change account settings?
            </button>
          </h2>
          <div
            id="sq-accordion-flush-item-1"
            class="accordion-collapse collapse show"
            data-bs-parent="#sq-accordion-flush"
          >
            <div class="accordion-body">
              Admins and account owners. Members can view but not edit billing or ownership.
            </div>
          </div>
        </div>
        <div class="accordion-item">
          <h2 class="accordion-header">
            <button
              class="accordion-button collapsed"
              type="button"
              data-bs-toggle="collapse"
              data-bs-target="#sq-accordion-flush-item-2"
              aria-expanded="false"
              aria-controls="sq-accordion-flush-item-2"
            >
              How do notifications work?
            </button>
          </h2>
          <div
            id="sq-accordion-flush-item-2"
            class="accordion-collapse collapse"
            data-bs-parent="#sq-accordion-flush"
          >
            <div class="accordion-body">
              Email and in-app alerts use the same tone rules as [toasts](/components/feedback). You can dismiss each item from the drawer.
            </div>
          </div>
        </div>
        <div class="accordion-item">
          <h2 class="accordion-header">
            <button
              class="accordion-button collapsed"
              type="button"
              data-bs-toggle="collapse"
              data-bs-target="#sq-accordion-flush-item-3"
              aria-expanded="false"
              aria-controls="sq-accordion-flush-item-3"
            >
              Can I export a list?
            </button>
          </h2>
          <div
            id="sq-accordion-flush-item-3"
            class="accordion-collapse collapse"
            data-bs-parent="#sq-accordion-flush"
          >
            <div class="accordion-body">
              Yes — use <strong>Export</strong> on any table view; CSV includes visible columns for the current filter.
            </div>
          </div>
        </div>
      </div>

</div>

```html
<div class="accordion accordion-flush" id="accordionFlush">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button
        class="accordion-button"
        type="button"
        data-bs-toggle="collapse"
        data-bs-target="#flush-collapseOne"
        aria-expanded="true"
        aria-controls="flush-collapseOne"
      >
        Section title
      </button>
    </h2>
    <div
      id="flush-collapseOne"
      class="accordion-collapse collapse show"
      data-bs-parent="#accordionFlush"
    >
      <div class="accordion-body">…</div>
    </div>
  </div>
</div>
```

## Rules

### Default accordion

- Standalone FAQ or help blocks on page background — bordered **`accordion`**, subtle row dividers.
- One open section per group: set the same **`data-bs-parent`** on each **`accordion-collapse`** (value = root **`accordion`** `id`).
- Open panel: **`accordion-button`** (no **`collapsed`**) + **`accordion-collapse collapse show`**. Closed: **`accordion-button collapsed`** + **`collapse`** only.
- Active/open header uses theme selected surface + green title; chevron rotates — colour transition only, no motion tricks.
### Flush accordion

- **`accordion accordion-flush`** when the parent [card](/components/card) or panel already provides border and radius.
- Same header/collapse markup as default; often **`card-body p-0`** so dividers run edge to edge.


---

<!-- Source: components/avatar.md -->

# Avatar

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Initials or image in **`avatar`** + **`text-bg-*`**. Sizes and patterns below; **usage** → [Rules](#rules).

## Sizes

**`avatar-xs`**, **`avatar-sm`**, default **`avatar`**, **`avatar-lg`**, **`avatar-xl`** (16 / 24 / 32 / 44 / 56px). **`avatar-xs`** in compact lists and meta rows; **`avatar-xl`** on profile headers and empty states.
<div class="sq-preview">
  <div class="d-flex align-items-center gap-2">
    <span class="avatar avatar-xs text-bg-info">MD</span>
    <span class="avatar avatar-sm text-bg-info">MD</span>
    <span class="avatar text-bg-info">MD</span>
    <span class="avatar avatar-lg text-bg-info">MD</span>
    <span class="avatar avatar-xl text-bg-info">MD</span>
  </div>
</div>

```html
<span class="avatar avatar-xs text-bg-info">MD</span>
<span class="avatar avatar-sm text-bg-info">MD</span>
<span class="avatar text-bg-info">MD</span>
<span class="avatar avatar-lg text-bg-info">MD</span>
<span class="avatar avatar-xl text-bg-info">MD</span>
```

## Tones

Status: same **`text-bg-*`** tokens as [badges — Tones](/components/badge#tones).
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <span class="avatar text-bg-success">WN</span>
    <span class="avatar text-bg-warning">DT</span>
    <span class="avatar text-bg-danger">LS</span>
    <span class="avatar text-bg-info">MD</span>
    <span class="avatar text-bg-neutral">OP</span>
  </div>
</div>

```html
<span class="avatar text-bg-success">WN</span>
<span class="avatar text-bg-warning">DT</span>
<span class="avatar text-bg-danger">LS</span>
<span class="avatar text-bg-info">MD</span>
<span class="avatar text-bg-neutral">OP</span>
```

## Accents

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Decorative only: **`text-bg-accent-*`** — see [Colors — Accents](/design/colors#accents).
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <span class="avatar text-bg-accent-teal">TL</span>
    <span class="avatar text-bg-accent-terracotta">TC</span>
    <span class="avatar text-bg-accent-slate">SL</span>
    <span class="avatar text-bg-accent-taupe">TP</span>
    <span class="avatar text-bg-accent-violet">VL</span>
  </div>
</div>

```html
<span class="avatar text-bg-accent-teal">TL</span>
<span class="avatar text-bg-accent-terracotta">TC</span>
<span class="avatar text-bg-accent-slate">SL</span>
<span class="avatar text-bg-accent-taupe">TP</span>
<span class="avatar text-bg-accent-violet">VL</span>
```

## Shape

Circle (default): people. **`avatar-square`**: organisations (default **10px** corners; **`avatar-sm`** **8px**, **`avatar-xs`** **4px**).
<div class="sq-preview">
  <div class="d-flex align-items-center gap-2">
    <span class="avatar text-bg-warning">DT</span>
    <span class="avatar avatar-square text-bg-light">SK</span>
  </div>
</div>

```html
<span class="avatar text-bg-warning">DT</span>
<span class="avatar avatar-square text-bg-light">SK</span>
```

## Group

**`avatar-group`**: overlapping stack; show at most two faces + **`+N`** on **`text-bg-light`**.
<div class="sq-preview">
  <div class="avatar-group">
    <span class="avatar text-bg-info">ML</span>
    <span class="avatar text-bg-warning">DT</span>
    <span class="avatar text-bg-light">+4</span>
  </div>
</div>

```html
<div class="avatar-group">
  <span class="avatar text-bg-info">ML</span>
  <span class="avatar text-bg-warning">DT</span>
  <span class="avatar text-bg-light">+4</span>
</div>
```

## Rules

### Shape and tone

- Do not mix circle and square in one row without a label explaining the difference.
- Initials without **`src`**: always a **`text-bg-*`** tint (hash or semantic).
### Group

**`avatar-group`** summarizes assignees — not a full roster; link out for detail.
### Popover

Avatar may trigger a [popover](/components/popover) for a person summary.


---

<!-- Source: components/badge.md -->

# Badge

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap `badge` + **`text-bg-*`**. Modifiers and examples below; **usage** → [Rules](#rules).

## Tones

- Status: **`text-bg-success`**, **`warning`**, **`danger`**, **`info`**. **`text-bg-neutral`** is Sqrl custom ([Colors](/design/colors#status)).
- UI chips: **`text-bg-secondary`**, **`light`**, **`dark`** (strong fill).
- Class order: **`badge`**, then **`badge-*`** modifiers, then **`text-bg-*`**.
<div class="sq-preview">
  <div class="d-flex flex-wrap gap-2">
    <span class="badge text-bg-success">Done</span>
    <span class="badge text-bg-warning">Today</span>
    <span class="badge text-bg-danger">Overdue</span>
    <span class="badge text-bg-info">Scheduled</span>
    <span class="badge text-bg-neutral">Open</span>
    <span class="badge text-bg-light">Light</span>
    <span class="badge text-bg-dark">Dark</span>
    <span class="badge text-bg-secondary">Secondary</span>
  </div>
</div>

```html
<span class="badge text-bg-success">Done</span>
<span class="badge text-bg-warning">Today</span>
<span class="badge text-bg-danger">Overdue</span>
<span class="badge text-bg-info">Scheduled</span>
<span class="badge text-bg-neutral">Open</span>
<span class="badge text-bg-light">Light</span>
<span class="badge text-bg-dark">Dark</span>
<span class="badge text-bg-secondary">Secondary</span>
```

## Accents

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Decorative only: **`text-bg-accent-*`** — see [Colors — Accents](/design/colors#accents).

<div class="sq-preview">
  <div class="d-flex flex-wrap gap-2">
    <span class="badge text-bg-accent-teal">Teal</span>
    <span class="badge text-bg-accent-terracotta">Terracotta</span>
    <span class="badge text-bg-accent-slate">Slate</span>
    <span class="badge text-bg-accent-taupe">Taupe</span>
    <span class="badge text-bg-accent-violet">Violet</span>
  </div>
</div>

```html
<span class="badge text-bg-accent-teal">Teal</span>
<span class="badge text-bg-accent-terracotta">Terracotta</span>
<span class="badge text-bg-accent-slate">Slate</span>
<span class="badge text-bg-accent-taupe">Taupe</span>
<span class="badge text-bg-accent-violet">Violet</span>
```

## Dotted

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`badge-dotted`**: dot in **`currentColor`** — pair with any tone.

<div class="sq-preview">
  <div class="d-flex flex-wrap gap-2">
    <span class="badge badge-dotted text-bg-success">Done</span>
    <span class="badge badge-dotted text-bg-warning">Today</span>
    <span class="badge badge-dotted text-bg-danger">Overdue</span>
    <span class="badge badge-dotted text-bg-info">Scheduled</span>
    <span class="badge badge-dotted text-bg-neutral">Open</span>
  </div>
</div>

```html
<span class="badge badge-dotted text-bg-success">Done</span>
<span class="badge badge-dotted text-bg-warning">Today</span>
<span class="badge badge-dotted text-bg-danger">Overdue</span>
<span class="badge badge-dotted text-bg-info">Scheduled</span>
<span class="badge badge-dotted text-bg-neutral">Open</span>
```

## Borderless

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`badge-borderless`**: no border; pair with **`badge-dotted`** in dense layouts.

<div class="sq-preview">
  <div class="d-flex flex-wrap gap-2">
    <span class="badge badge-borderless badge-dotted text-bg-light">Draft</span>
    <span class="badge badge-borderless badge-dotted text-bg-info">Scheduled</span>
    <span class="badge badge-borderless badge-dotted text-bg-neutral">In review</span>
    <span class="badge badge-borderless badge-dotted text-bg-warning">Due soon</span>
    <span class="badge badge-borderless badge-dotted text-bg-success">Done</span>
    <span class="badge badge-borderless badge-dotted text-bg-danger">Cancelled</span>
  </div>
</div>

```html
<span class="badge badge-borderless badge-dotted text-bg-light">Draft</span>
<span class="badge badge-borderless badge-dotted text-bg-info">Scheduled</span>
<span class="badge badge-borderless badge-dotted text-bg-neutral"
  >In review</span
>
<span class="badge badge-borderless badge-dotted text-bg-warning"
  >Due soon</span
>
<span class="badge badge-borderless badge-dotted text-bg-success">Done</span>
<span class="badge badge-borderless badge-dotted text-bg-danger"
  >Cancelled</span
>
```

## With icon

One Bootstrap Icon before the label (inherits colour) — [Iconography](/design/iconography).

<div class="sq-preview">
  <div class="d-flex flex-wrap gap-2">
    <span class="badge text-bg-warning">
      <i class="bi bi-exclamation-triangle-fill"></i>
      Overdue
    </span>
    <span class="badge text-bg-success">
      <i class="bi bi-check-circle-fill"></i>
      Completed
    </span>
    <span class="badge text-bg-danger">
      <i class="bi bi-exclamation-circle-fill"></i>
      Needs attention
    </span>
  </div>
</div>

```html
<span class="badge text-bg-warning">
  <i class="bi bi-exclamation-triangle-fill"></i>
  Overdue
</span>
<span class="badge text-bg-success">
  <i class="bi bi-check-circle-fill"></i>
  Completed
</span>
<span class="badge text-bg-danger">
  <i class="bi bi-exclamation-circle-fill"></i>
  Needs attention
</span>
```

## Square

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`badge-square`**: 4px radius for dense [table](/components/table) cells.

<div class="sq-preview">
  <div class="d-flex flex-wrap gap-2">
    <span class="badge badge-square text-bg-success">Done</span>
    <span class="badge badge-square text-bg-danger">Overdue</span>
    <span class="badge badge-square text-bg-neutral">Open</span>
  </div>
</div>

```html
<span class="badge badge-square text-bg-success">Done</span>
<span class="badge badge-square text-bg-danger">Overdue</span>
<span class="badge badge-square text-bg-neutral">Open</span>
```

## Rules

### Meaning

- Never **colour alone** — always a word, **`badge-dotted`**, or icon ([Iconography](/design/iconography)).
- Status → **`text-bg-success`** / **`warning`** / **`danger`** / **`info`** / **`neutral`** (Sqrl custom). Accents → decorative only, not semantic status.

### Tables

Status columns: **`badge-borderless badge-dotted`** + tone — see [table](/components/table).

### Naming

New modifiers: **`badge-{name}`** (`badge-dotted`, `badge-square`, `badge-borderless`).


---

<!-- Source: components/buttons.md -->

# Buttons

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap `btn` classes. Variants, sizes, and examples below; **usage** → [Rules](#rules). Icons: [Iconography](/design/iconography).

## Variants

**`btn-primary`**, **`btn-secondary`**, **`btn-danger`**, **`btn-link`**, **`btn-dark`** (selected/chosen, not dark theme).
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <button type="button" class="btn btn-primary">New contact</button>
    <button type="button" class="btn btn-secondary">Assign owners</button>
    <button type="button" class="btn btn-dark">Selected</button>
    <button type="button" class="btn btn-danger">Delete contact</button>
    <button type="button" class="btn btn-link">View all</button>
  </div>
</div>

```html
<button type="button" class="btn btn-primary">New contact</button>
<button type="button" class="btn btn-secondary">Assign owners</button>
<button type="button" class="btn btn-dark">Selected</button>
<button type="button" class="btn btn-danger">Delete contact</button>
<button type="button" class="btn btn-link">View all</button>
```

## Ghost

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`btn-ghost`** — borderless icon/text for row actions and toolbars (not **`btn-link`**).
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
      <i class="bi bi-pencil" aria-hidden="true"></i>
    </button>
  </div>
</div>

```html
<button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
  <i class="bi bi-pencil" aria-hidden="true"></i>
</button>
```

## Other variants

**`btn-success`**, **`btn-warning`**, **`btn-info`** — contextual status, not page CTAs. Prefer **`btn-secondary`** over **`btn-light`**.
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <button type="button" class="btn btn-success">Success</button>
    <button type="button" class="btn btn-warning">Warning</button>
    <button type="button" class="btn btn-info">Info</button>
    <button type="button" class="btn btn-light">Light</button>
  </div>
</div>

```html
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-light">Light</button>
```

## Sizes

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span> <span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

**`btn-xxs`**, **`btn-xs`**, **`btn-sm`**, default, **`btn-lg`** (22 / 26 / 32 / 36 / 42px control heights; **`btn-xxs`** and **`btn-xs`** use 11px type and the same horizontal padding). Use **`btn-xxs`** / **`btn-xs`** for dense toolbars and inline actions; not for primary page CTAs or form fields (**`form-control-sm`** stays 32px).
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <button type="button" class="btn btn-primary btn-xxs">New contact</button>
    <button type="button" class="btn btn-primary btn-xs">New contact</button>
    <button type="button" class="btn btn-primary btn-sm">New contact</button>
    <button type="button" class="btn btn-primary">New contact</button>
    <button type="button" class="btn btn-primary btn-lg">New contact</button>
  </div>
</div>

```html
<button type="button" class="btn btn-primary btn-xxs">New contact</button>
<button type="button" class="btn btn-primary btn-xs">New contact</button>
<button type="button" class="btn btn-primary btn-sm">New contact</button>
<button type="button" class="btn btn-primary">New contact</button>
<button type="button" class="btn btn-primary btn-lg">New contact</button>
```

## Icon buttons

One Bootstrap Icon; icon **before** label. Icon-only: **`btn-sm`** + **`aria-label`**.
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <button type="button" class="btn btn-primary">
      <i class="bi bi-plus-lg me-1"></i>
      New contact
    </button>
    <button type="button" class="btn btn-secondary btn-sm" aria-label="Search">
      <i class="bi bi-search"></i>
    </button>
    <button type="button" class="btn btn-ghost btn-sm" aria-label="More">
      <i class="bi bi-three-dots"></i>
    </button>
  </div>
</div>

```html
<button type="button" class="btn btn-primary">
  <i class="bi bi-plus-lg me-1"></i>
  New contact
</button>
<button type="button" class="btn btn-secondary btn-sm" aria-label="Search">
  <i class="bi bi-search"></i>
</button>
<button type="button" class="btn btn-ghost btn-sm" aria-label="More">
  <i class="bi bi-three-dots"></i>
</button>
```

## States

**`disabled`** attribute for inactive actions (theme matches Bootstrap opacity/cursor). No scale or layout shift on interaction.
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-2">
    <button type="button" class="btn btn-primary" disabled>Save changes</button>
    <button type="button" class="btn btn-secondary" disabled>Assign owners</button>
    <button type="button" class="btn btn-dark" disabled>Selected</button>
  </div>
</div>

```html
<button type="button" class="btn btn-primary" disabled>Save changes</button>
<button type="button" class="btn btn-secondary" disabled>Assign owners</button>
<button type="button" class="btn btn-dark" disabled>Selected</button>
```

## Rules

### Hierarchy

**One `btn-primary` per view** — other actions secondary, ghost, link, or dark (selected).
### Labels

- **Verb + object**, sentence case (“New contact”, “Assign owners”). Not “Submit”, “OK”, or “Click here”.
- Destructive: name the effect (“Delete contact”).
### Icon-only

Always **`aria-label`**. Pair with [tooltip](/components/tooltip) only for extra hint, not essential copy. Flat icons: [Iconography](/design/iconography).


---

<!-- Source: components/card.md -->

# Card

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap `card`. Layout patterns below; **usage** → [Rules](#rules).

## Default

Borderless **`card`** on page surface (**`bg-body`** in previews). Metric / summary tiles.
<div class="sq-preview">
  <div class="bg-body rounded-3 p-4">
    <div class="row g-3">
      <div class="col-md-6">
        <div class="card h-100">
          <div class="card-body">
            <p class="small text-uppercase fw-bold text-body-tertiary mb-2">
              <i class="bi bi-check2-square me-1"></i>
              Open tasks
            </p>
            <p class="card-title h1 mb-2">18</p>
            <p class="small mb-0">
              <span class="text-danger fw-semibold">
                <i class="bi bi-arrow-down"></i>
                -3
              </span>
              <span class="text-muted">vs. last week</span>
            </p>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        <div class="card h-100">
          <div class="card-body">
            <p class="small text-uppercase fw-bold text-body-tertiary mb-2">
              <i class="bi bi-graph-up me-1"></i>
              View details
            </p>
            <p class="card-title h1 mb-2">€ 482K</p>
            <p class="small mb-0">
              <span class="text-success fw-semibold">
                <i class="bi bi-arrow-up"></i>
                +12%
              </span>
              <span class="text-muted">vs. last month</span>
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

```html
<div class="card">
  <div class="card-body">
    <p class="small text-uppercase fw-bold text-body-tertiary mb-2">
      <i class="bi bi-check2-square me-1"></i>
      Open tasks
    </p>
    <p class="card-title h1 mb-2">18</p>
    <p class="small mb-0">
      <span class="text-danger fw-semibold">
        <i class="bi bi-arrow-down"></i>
        -3
      </span>
      <span class="text-muted">vs. last week</span>
    </p>
  </div>
</div>
<div class="card">
  <div class="card-body">
    <p class="small text-uppercase fw-bold text-body-tertiary mb-2">
      <i class="bi bi-graph-up me-1"></i>
      View details
    </p>
    <p class="card-title h1 mb-2">€ 482K</p>
    <p class="small mb-0">
      <span class="text-success fw-semibold">
        <i class="bi bi-arrow-up"></i>
        +12%
      </span>
      <span class="text-muted">vs. last month</span>
    </p>
  </div>
</div>
```

## Bordered

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`card-bordered`** when the card sits on paper/white or another card.
<div class="sq-preview">
  <div class="card card-bordered">
    <div class="card-body d-flex justify-content-between align-items-start">
      <div>
        <h3 class="card-title h4 mb-1">Van den Berg Logistics</h3>
        <p class="card-text text-muted small mb-0">Account · 12 contacts</p>
      </div>
      <span class="badge badge-dotted text-bg-accent-teal">Active</span>
    </div>
  </div>
</div>

```html
<div class="card card-bordered">
  <div class="card-body d-flex justify-content-between align-items-start">
    <div>
      <h3 class="card-title h4 mb-1">Van den Berg Logistics</h3>
      <p class="card-text text-muted small mb-0">Account · 12 contacts</p>
    </div>
    <span class="badge badge-dotted text-bg-accent-teal">Active</span>
  </div>
</div>
```

## Header

**`card-header`**: identity (avatar, title). Facts grid in **`card-body`**.
<div class="sq-preview">
  <div class="bg-body rounded-3 p-4">
    <div class="card">
      <div class="card-header d-flex align-items-center gap-3">
        <span class="avatar avatar-lg avatar-square text-bg-info">AP</span>
        <div>
          <h3 class="card-title h4">Anouk Peters</h3>
          <p class="card-text text-muted small mb-0">Sales Director, Sqrl B.V.</p>
        </div>
      </div>
      <div class="card-body">
        <div class="row g-3">
          <div class="col-6">
            <p class="small text-uppercase fw-bold text-body-tertiary mb-1">Email</p>
            <p class="mb-0">anouk@sqrl.nl</p>
          </div>
          <div class="col-6">
            <p class="small text-uppercase fw-bold text-body-tertiary mb-1">Phone</p>
            <p class="mb-0">+31 6 1234 5678</p>
          </div>
          <div class="col-6">
            <p class="small text-uppercase fw-bold text-body-tertiary mb-1">Deals</p>
            <p class="mb-0 font-monospace">3</p>
          </div>
          <div class="col-6">
            <p class="small text-uppercase fw-bold text-body-tertiary mb-1">Value</p>
            <p class="mb-0 font-monospace">€ 84K</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

```html
<div class="card">
  <div class="card-header d-flex align-items-center gap-3">
    <span class="avatar avatar-lg avatar-square text-bg-info">AP</span>
    <div>
      <h3 class="card-title h4">Anouk Peters</h3>
      <p class="card-text text-muted small mb-0">Sales Director, Sqrl B.V.</p>
    </div>
  </div>
  <div class="card-body">
    <div class="row g-3">
      <div class="col-6">
        <p class="small text-uppercase fw-bold text-body-tertiary mb-1">
          Email
        </p>
        <p class="mb-0">anouk@sqrl.nl</p>
      </div>
      <div class="col-6">
        <p class="small text-uppercase fw-bold text-body-tertiary mb-1">
          Phone
        </p>
        <p class="mb-0">+31 6 1234 5678</p>
      </div>
      <div class="col-6">
        <p class="small text-uppercase fw-bold text-body-tertiary mb-1">
          Deals
        </p>
        <p class="mb-0 font-monospace">3</p>
      </div>
      <div class="col-6">
        <p class="small text-uppercase fw-bold text-body-tertiary mb-1">
          Value
        </p>
        <p class="mb-0 font-monospace">€ 84K</p>
      </div>
    </div>
  </div>
</div>
```

## Footer

**`card-footer`**: actions ( **`btn-sm`** ).
<div class="sq-preview">
  <div class="bg-body rounded-3 p-4">
    <div class="card">
      <div class="card-body">
        <h3 class="card-title h4 mb-1">Van den Berg Logistics</h3>
        <p class="card-text text-muted small mb-0">12 contacts</p>
      </div>
      <div class="card-footer d-flex justify-content-end gap-2">
        <button type="button" class="btn btn-sm btn-secondary">Cancel</button>
        <button type="button" class="btn btn-sm btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

```html
<div class="card">
  <div class="card-body">
    <h3 class="card-title h4 mb-1">Van den Berg Logistics</h3>
    <p class="card-text text-muted small mb-0">12 contacts</p>
  </div>
  <div class="card-footer d-flex justify-content-end gap-2">
    <button type="button" class="btn btn-sm btn-secondary">Cancel</button>
    <button type="button" class="btn btn-sm btn-primary">Save changes</button>
  </div>
</div>
```

## Rules

### When to use

Group related content: metrics, record summary, [flow step nodes](/design/iconography#textured-icons), optional shell for dense lists (not required for [empty state](/components/feedback)).
### Structure

**`card-header`** / **`card-body`** / **`card-footer`** are **siblings** — never nest header/footer inside body.
### Surface

Default borderless on **`bg-body`**. **`card-bordered`** on low-contrast backgrounds.


---

<!-- Source: components/close-button.md -->

# Close button

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap [`btn-close`](https://getbootstrap.com/docs/5.3/components/close-button/), restyled. Sizes and examples below; **usage** → [Rules](#rules).

## Sizes

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

| Class | Use |
| --- | --- |
| `btn-close btn-close-sm` | [Toasts](/components/feedback), dense UI |
| `btn-close` (medium; `btn-close-md` alias) | [Modals](/components/modals), offcanvas headers |
| `btn-close btn-close-lg` | Larger surfaces when needed |

Always set **`aria-label="Close"`** (or a specific label).

<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-4">
    <button type="button" class="btn-close btn-close-sm" aria-label="Close"></button>
    <button type="button" class="btn-close" aria-label="Close"></button>
    <button type="button" class="btn-close btn-close-lg" aria-label="Close"></button>
    <button type="button" class="btn-close btn-close-sm" disabled aria-label="Close"></button>
  </div>
</div>

```html
<button type="button" class="btn-close btn-close-sm" aria-label="Close"></button>
<button type="button" class="btn-close" aria-label="Close"></button>
<button type="button" class="btn-close btn-close-lg" aria-label="Close"></button>
```

## Rules

### Where to use

- Dismissible [toasts](/components/feedback), [modals](/components/modals), alerts, and offcanvas headers.
- Not as a generic icon control — use **`btn-ghost`** + Bootstrap Icon instead ([Iconography](/design/iconography)).
### Dark surfaces

Do not use **`btn-close-white`**. On a dark surface, set **`data-bs-theme="dark"`** on the button or parent.
### Disabled

Bootstrap disabled behaviour (reduced opacity, no pointer events) applies as usual.


---

<!-- Source: components/dropdown.md -->

# Dropdown

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap **`dropdown`**: compact menus for sort, filters, and actions. Markup below; **when to use which trigger** → [Rules](#rules).

## Sort menu

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

- Trigger: current label + **`bi-arrow-down-up`**; **`btn-ghost`** (Sqrl custom — or link-style), **`data-bs-toggle="dropdown"`**, **no** **`dropdown-toggle`**.
- Menu: **`dropdown-menu`** → **`button.dropdown-item`**; selection = **`active`** + **`aria-current="true"`**.
<div class="sq-preview">
  <p class="small text-uppercase fw-bold text-body-tertiary mb-2">Sort menu</p>
  <div class="dropdown" aria-hidden="true">
    <div class="btn btn-ghost p-0 align-baseline fw-medium text-body mb-2">
      <i class="bi bi-arrow-down-up me-2" aria-hidden="true"></i>
      Name (A-Z)
    </div>
    <div class="dropdown-menu show position-static d-block mt-0">
      <button type="button" class="dropdown-item active" tabindex="-1">Name (A-Z)</button>
      <button type="button" class="dropdown-item" tabindex="-1">Name (Z-A)</button>
      <button type="button" class="dropdown-item" tabindex="-1">Quote potential (high-low)</button>
      <button type="button" class="dropdown-item" tabindex="-1">Quote potential (low-high)</button>
    </div>
  </div>
</div>

```html
<div class="dropdown">
  <button
    type="button"
    class="btn btn-ghost align-baseline fw-normal text-body"
    data-bs-toggle="dropdown"
    aria-expanded="false"
  >
    <i class="bi bi-arrow-down-up me-1" aria-hidden="true"></i>
    Name (A-Z)
  </button>
  <div class="dropdown-menu">
    <button type="button" class="dropdown-item active" aria-current="true">
      Name (A-Z)
    </button>
    <button type="button" class="dropdown-item">Name (Z-A)</button>
    <button type="button" class="dropdown-item">
      Quote potential (high-low)
    </button>
    <button type="button" class="dropdown-item">
      Quote potential (low-high)
    </button>
  </div>
</div>
```

Docs static block: **`dropdown-menu show position-static d-block`** (omit in product).

## Button trigger

- Trigger: contextual **`btn-*`** + **`dropdown-toggle`** + **`data-bs-toggle="dropdown"`**.
- Same **`dropdown-menu`** / **`dropdown-item`** pattern; labels in the menu are plain text rows, not nested **`btn-*`** buttons.
<div class="sq-preview">
  <p class="small text-uppercase fw-bold text-body-tertiary mb-2">Primary button trigger</p>
  <div class="pe-none user-select-none" aria-hidden="true">
    <button type="button" class="btn btn-success dropdown-toggle" tabindex="-1">Success</button>
    <div class="dropdown-menu show position-static d-block">
      <button type="button" class="dropdown-item active" tabindex="-1">Success</button>
      <button type="button" class="dropdown-item" tabindex="-1">Warning</button>
      <button type="button" class="dropdown-item" tabindex="-1">Danger</button>
    </div>
  </div>
</div>

```html
<div class="dropdown">
  <button
    type="button"
    class="btn btn-success dropdown-toggle"
    data-bs-toggle="dropdown"
    aria-expanded="false"
  >
    Success
  </button>
  <div class="dropdown-menu">
    <button type="button" class="dropdown-item active" aria-current="true">
      Success
    </button>
    <button type="button" class="dropdown-item">Warning</button>
    <button type="button" class="dropdown-item">Danger</button>
  </div>
</div>
```

## Rules

### When to use

- **Dropdown:** user picks one option from a short list (sort, filter, status, overflow actions).
- **Not** a [popover](/components/popover) (explanation/tooltip-style content) or a [modal](/components/modals) (multi-step or blocking task).
- Look and spacing live in **`theme.scss`** — implement with Bootstrap classes only; do not re-specify colours or sizes in app CSS.
### Behaviour

- **Close on selection** (Bootstrap default). For sort-style triggers, **update the trigger label** to match the new **`active`** item.
- One **`active`** row at a time for single-select menus.
### Sort-style trigger

- Toolbar/table **sort**, **view**, or **filter** — shows **current value** + sort icon.
- **No** **`dropdown-toggle`** on the trigger (no caret); icon is **`bi-arrow-down-up`** only — [Iconography](/design/iconography).
### Button trigger

- Primary/secondary [button](/components/buttons) that opens a menu — add **`dropdown-toggle`**.
- Menu copy describes the action or state (e.g. “Warning”, “Delete”); use **`btn-danger`** on a **footer/header button**, not as a **`dropdown-item`** styled like a full button.


---

<!-- Source: components/feedback.md -->

# Feedback

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Toast, alert, empty state, and loading placeholders. Markup and examples below; **when to use which** → [Rules](#rules). Icons (flat only): [Iconography](/design/iconography).

## Toast

- Markup: `toast` → `toast-header` (optional tone icon, `strong.me-auto` title, [`btn-close btn-close-sm`](/components/close-button)) + `toast-body`.
- Show/hide: `bootstrap.Toast.getOrCreateInstance(el, { autohide: true, delay: 3000 }).show()`; close button needs `data-bs-dismiss="toast"`.
- Tone icons: `check-circle-fill` + `text-success`, `exclamation-triangle-fill` + `text-warning`, `x-circle-fill` + `text-danger`, `info-circle-fill` + `text-info`.
<div class="sq-preview">
  <div class="d-flex flex-column gap-3 align-items-start mb-4">
    <div class="toast show mb-0" role="status" aria-live="polite">
      <div class="toast-header">
        <i class="bi bi-check-circle-fill text-success mt-1" aria-hidden="true"></i>
        <strong class="me-auto">Changes saved</strong>
        <button type="button" class="btn-close btn-close-sm" data-bs-dismiss="toast" aria-label="Close"></button>
      </div>
      <div class="toast-body">Contact details were updated.</div>
    </div>
    <div class="toast show mb-0" role="alert" aria-live="assertive">
      <div class="toast-header">
        <i class="bi bi-x-circle-fill text-danger mt-1" aria-hidden="true"></i>
        <strong class="me-auto">Import failed</strong>
        <button type="button" class="btn-close btn-close-sm" data-bs-dismiss="toast" aria-label="Close"></button>
      </div>
      <div class="toast-body">Assign an owner before activating this step.</div>
    </div>
  </div>
  <div class="d-flex flex-wrap gap-2">
    <button type="button" class="btn btn-primary" data-sq-show-toast="success">Show success toast</button>
    <button type="button" class="btn btn-secondary" data-sq-show-toast="error">Show error toast</button>
  </div>
</div>

```html
<div class="toast-container sq-toast-stack">
  <div class="toast" role="status" aria-live="polite">
    <div class="toast-header">
      <i class="bi bi-check-circle-fill text-success" aria-hidden="true"></i>
      <strong class="me-auto">Changes saved</strong>
      <button
        type="button"
        class="btn-close btn-close-sm"
        data-bs-dismiss="toast"
        aria-label="Close"
      ></button>
    </div>
    <div class="toast-body">Contact details were updated.</div>
  </div>
</div>
```

## Live toast stack

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Append to **`toast-container sq-toast-stack`** on `document.body` (fixed bottom-right).
Docs demo buttons (`data-sq-show-toast`) are **docs-only** — do not copy into an app; call `bootstrap.Toast` yourself.

## Alert

- Bootstrap `alert` + variant: `alert-success`, `alert-warning`, `alert-danger`, `alert-info`. **`alert-neutral`** is Sqrl custom (same family as **`text-bg-neutral`**).
- Simple row: `d-flex align-items-start gap-2` + icon + text.
- Warning with action: `align-items-center`, title `fw-semibold`, detail `small text-body`, **`btn btn-sm btn-secondary`** on the right (not primary).
<div class="sq-preview">
  <div class="alert alert-success d-flex align-items-start gap-2 mb-3" role="status">
    <i class="bi bi-check-circle-fill"></i>
    <div>18 prospects imported from CSV.</div>
  </div>
  <div class="alert alert-warning d-flex align-items-center gap-2 mb-3" role="status">
    <i class="bi bi-exclamation-triangle-fill flex-shrink-0 align-self-start"></i>
    <div class="flex-grow-1 min-w-0">
      <div class="fw-semibold">12 prospects are missing an owner</div>
      <div class="small text-body">Unassigned prospects are not included in flow automation.</div>
    </div>
    <button type="button" class="btn btn-sm btn-secondary flex-shrink-0">Assign owners</button>
  </div>
  <div class="alert alert-danger d-flex align-items-start gap-2 mb-0" role="alert">
    <i class="bi bi-x-circle-fill"></i>
    <div>Assign an owner before activating this step.</div>
  </div>
</div>

```html
<div class="alert alert-warning d-flex align-items-center gap-2" role="status">
  <i class="bi bi-exclamation-triangle-fill flex-shrink-0 align-self-start"></i>
  <div class="flex-grow-1 min-w-0">
    <div class="fw-semibold">12 prospects are missing an owner</div>
    <div class="small text-body">
      Unassigned prospects are not included in flow automation.
    </div>
  </div>
  <button type="button" class="btn btn-sm btn-secondary flex-shrink-0">
    Assign owners
  </button>
</div>
```

### Neutral

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`alert-neutral`** — extra tone (not Bootstrap). Same family as **`text-bg-neutral`**.

### Accents

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`alert-accent-*`** — same suffixes as [Colors — Accents](/design/colors#accents) (`text-bg-accent-*`).

## Empty state

State the fact, then the next step. No exclamation marks. One primary action (optional); secondary actions (optional) use **`btn-secondary`**.

Centered block in the content area (no **`card`** required): icon tile (`rounded bg-body-secondary`, 3×3rem) + `.h2` title + `text-muted` line + actions.

<div class="sq-preview">
  <div class="text-center py-5 mb-0">
    <span class="d-inline-flex align-items-center justify-content-center rounded bg-body-secondary text-muted mb-3" style="width: 3rem; height: 3rem" aria-hidden="true">
      <i class="bi bi-inbox-fill fs-3"></i>
    </span>
    <h4 class="h4 mb-2">No tasks yet</h4>
    <p class="text-muted mb-4">Create a task or import follow-ups from a CSV file.</p>
    <div class="d-flex justify-content-center gap-2">
      <button type="button" class="btn btn-primary">New task</button>
      <button type="button" class="btn btn-secondary">Import from CSV</button>
    </div>
  </div>
</div>

```html
<div class="text-center py-5 mb-0">
  <span
    class="d-inline-flex align-items-center justify-content-center rounded bg-body-secondary text-muted mb-3"
    style="width: 3rem; height: 3rem"
    aria-hidden="true"
  >
    <i class="bi bi-inbox-fill fs-3"></i>
  </span>
  <h4 class="h4 mb-2">No tasks yet</h4>
  <p class="text-muted mb-4">
    Create a task or import follow-ups from a CSV file.
  </p>
  <div class="d-flex justify-content-center gap-2">
    <button type="button" class="btn btn-primary">New task</button>
    <button type="button" class="btn btn-secondary">Import from CSV</button>
  </div>
</div>
```

## Skeleton

- Bootstrap [placeholders](https://getbootstrap.com/docs/5.3/components/placeholders/): **`placeholder`** (+ `col-*` / fixed sizes). **Default: `placeholder-glow` on the loading shell** (parent wrapper — Bootstrap animation, no custom CSS).
- Loading shell: **`aria-hidden="true"`** until real content replaces it.
- Table-shaped: **`border overflow-hidden placeholder-glow`** + flex rows (`min-height: 44px`); then **`overflow-hidden`** + **`table.table`** when data arrives — [Table](/components/table).
- Card-shaped: **`card shadow-sm`** with **`card-body placeholder-glow`**.
<div class="sq-preview">
  <div class="border overflow-hidden placeholder-glow mb-3" aria-hidden="true">
    <div class="d-flex align-items-center gap-3 px-3 border-bottom" style="min-height: 44px">
      <span class="placeholder rounded-circle flex-shrink-0 d-inline-block" style="width: 28px; height: 28px"></span>
      <span class="placeholder flex-shrink-0 d-inline-block" style="width: 140px; height: 10px"></span>
      <span class="placeholder flex-shrink-0 d-inline-block" style="width: 90px; height: 10px"></span>
      <span class="placeholder rounded-pill flex-shrink-0 ms-auto d-inline-block" style="width: 60px; height: 18px"></span>
    </div>
    <div class="d-flex align-items-center gap-3 px-3" style="min-height: 44px">
      <span class="placeholder rounded-circle flex-shrink-0 d-inline-block" style="width: 28px; height: 28px"></span>
      <span class="placeholder flex-shrink-0 d-inline-block" style="width: 140px; height: 10px"></span>
      <span class="placeholder flex-shrink-0 d-inline-block" style="width: 90px; height: 10px"></span>
      <span class="placeholder rounded-pill flex-shrink-0 ms-auto d-inline-block" style="width: 60px; height: 18px"></span>
    </div>
  </div>
  <div class="card card-bordered shadow-sm mb-0" aria-hidden="true">
    <div class="card-body placeholder-glow">
      <p class="mb-3"><span class="placeholder rounded d-inline-block" style="width: 40px; height: 40px"></span></p>
      <p class="mb-1"><span class="placeholder placeholder-lg col-7"></span></p>
      <p class="mb-2"><span class="placeholder col-4"></span></p>
      <p class="mb-0"><span class="placeholder col-12"></span></p>
    </div>
  </div>
</div>

```html
<div class="border overflow-hidden placeholder-glow" aria-hidden="true">
  <div
    class="d-flex align-items-center gap-3 px-3 border-bottom"
    style="min-height: 44px"
  >
    <span
      class="placeholder rounded-circle d-inline-block"
      style="width: 28px; height: 28px"
    ></span>
    <span
      class="placeholder d-inline-block"
      style="width: 140px; height: 10px"
    ></span>
    <span
      class="placeholder d-inline-block"
      style="width: 90px; height: 10px"
    ></span>
    <span
      class="placeholder rounded-pill ms-auto d-inline-block"
      style="width: 60px; height: 18px"
    ></span>
  </div>
</div>
<div class="card card-bordered shadow-sm mb-0" aria-hidden="true">
  <div class="card-body placeholder-glow">
    <p class="mb-3">
      <span
        class="placeholder rounded d-inline-block"
        style="width: 40px; height: 40px"
      ></span>
    </p>
    <p class="mb-1"><span class="placeholder placeholder-lg col-7"></span></p>
    <p class="mb-2"><span class="placeholder col-4"></span></p>
    <p class="mb-0"><span class="placeholder col-12"></span></p>
  </div>
</div>
```

## Rules

### Toast

- Use after a **completed or failed user action** (save, import, create, delete) — feedback that can disappear without blocking the page.
- Do **not** use for ongoing data problems the user must fix while working (use **alert**). Do **not** use for an empty list (use **empty state**).
- Mount in **`toast-container sq-toast-stack`** (fixed bottom-right); stack multiple toasts there.
- Default **3s auto-hide** via Bootstrap `Toast` (`autohide: true`); user can dismiss earlier with **`btn-close-sm`**.
- Title **past tense**; success `role="status"` / `aria-live="polite"`, error `role="alert"` / `aria-live="assertive"`.

### Alert

- Use for **persistent inline** messages: import summaries, bulk data warnings, blocking validation on a page region.
- Place **above** the related content (toolbar, table, form section) — not floating like a toast.
- Do **not** use for transient “saved” confirmations (use **toast**).
- Actionable warnings: **`btn-secondary`** on the alert (the alert is already the signal; not **`btn-primary`**).

### Empty state

- Use when a **list or panel has zero items** and filters are not hiding results — the main content area is otherwise empty.
- Center in that content area; a **`card`** wrapper is optional.
- Copy: state the fact, then the next step. No exclamation marks. One primary action; secondary actions use **`btn-secondary`**. Tone: [Content](/design/content). Header icon: flat Bootstrap only — [Iconography](/design/iconography).
- Do **not** use for load errors or permission failures (use **alert** or **toast** as appropriate).

### Skeleton

- Use **while the real layout is loading** (table rows, cards, list) — same shape as the content that replaces it.
- Replace placeholders with real data when ready; remove `aria-hidden` from the live region.
- **Default animation:** **`placeholder-glow`** on the shell (`border` panel, **`card-body`**, etc.) — [Bootstrap markup](https://getbootstrap.com/docs/5.3/components/placeholders/#animation), not on each `placeholder`. Do not use **`placeholder-wave`**.
- Table data: glow panel → then **`table.table`** (often in **`overflow-hidden`**) when loaded.


---

<!-- Source: components/forms.md -->

# Forms

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap form controls. Patterns below; **usage** → [Rules](#rules).

## Input

`form-label` + `form-control`. Optional `form-text` for hints.

<div class="sq-preview">
  <form class="row g-3">
    <div class="col-md-6">
      <label class="form-label" for="company-name">Company name</label>
      <input class="form-control" id="company-name" type="text" placeholder="Van den Berg Logistics" />
    </div>
    <div class="col-md-6">
      <label class="form-label" for="due-date">Due date</label>
      <input class="form-control" id="due-date" type="date" placeholder="12 Mar 2026" />
      <div class="form-text">Display as 12 Mar 2026</div>
    </div>
  </form>
</div>

```html
<label class="form-label" for="company-name">Company name</label>
<input
  class="form-control"
  id="company-name"
  type="text"
  placeholder="Van den Berg Logistics"
/>
<label class="form-label" for="due-date">Due date</label>
<input
  class="form-control"
  id="due-date"
  type="date"
  placeholder="12 Mar 2026"
/>
<div class="form-text">Display as 12 Mar 2026</div>
```

## Input group

Prefix with `input-group-text`.

<div class="sq-preview">
  <div class="d-flex flex-column gap-3">
    <div>
      <label class="form-label" for="currency">Amount</label>
      <div class="input-group">
        <span class="input-group-text">€</span>
        <input class="form-control" id="currency" type="text" placeholder="12.400" />
      </div>
    </div>
  </div>
</div>

```html
<label class="form-label" for="currency">Amount</label>
<div class="input-group">
  <span class="input-group-text">€</span>
  <input class="form-control" id="currency" type="text" placeholder="12.400" />
</div>
```

### Search

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`input-group-merge`** (not a Bootstrap class): `type="text"` + `role="searchbox"` (not `type="search"`), and `bi-x-circle-fill` to clear.

<div class="sq-preview">
  <div>
    <label class="form-label" for="search-contacts">Search</label>
    <div class="input-group input-group-merge">
      <span class="input-group-text"><i class="bi bi-search"></i></span>
      <input class="form-control" id="search-contacts" type="text" role="searchbox" autocomplete="off" placeholder="Search contacts" value="Marieke" />
      <button type="button" class="input-group-text" aria-label="Clear search">
        <i class="bi bi-x-circle-fill"></i>
      </button>
    </div>
  </div>
</div>

```html
<label class="form-label" for="search-contacts">Search</label>
<div class="input-group input-group-merge">
  <span class="input-group-text"><i class="bi bi-search"></i></span>
  <input
    class="form-control"
    id="search-contacts"
    type="text"
    role="searchbox"
    autocomplete="off"
    placeholder="Search contacts"
    value="Marieke"
  />
  <button type="button" class="input-group-text" aria-label="Clear search">
    <i class="bi bi-x-circle-fill"></i>
  </button>
</div>
```

## Shortcut

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Command or global search: trailing **`input-group-shortcut`** inside **`input-group-merge`**. Same action as the shortcut; `aria-label` on the control.

<div class="sq-preview">
  <div class="input-group input-group-merge">
    <span class="input-group-text"><i class="bi bi-search"></i></span>
    <input class="form-control" type="text" role="searchbox" autocomplete="off" placeholder="Search…" aria-label="Search" />
    <button type="button" class="input-group-shortcut" aria-label="Open search (⌘K)">⌘K</button>
  </div>
</div>

```html
<div class="input-group input-group-merge">
  <span class="input-group-text"><i class="bi bi-search"></i></span>
  <input
    class="form-control"
    type="text"
    role="searchbox"
    autocomplete="off"
    placeholder="Search…"
    aria-label="Search"
  />
  <button
    type="button"
    class="input-group-shortcut"
    aria-label="Open search (⌘K)"
  >
    ⌘K
  </button>
</div>
```

## Sizes

`form-control-sm` is 32px / 13px (the floor). Default is 36px / 14px. `-lg` is 42px / 14px. Same for `form-select`.

<div class="sq-preview">
  <div class="d-flex flex-column gap-3">
    <input class="form-control form-control-sm" type="text" placeholder="Small — 32px · 13px" />
    <input class="form-control" type="text" placeholder="Default — 36px · 14px" />
    <input class="form-control form-control-lg" type="text" placeholder="Large — 42px · 14px" />
  </div>
</div>

```html
<input
  class="form-control form-control-sm"
  type="text"
  placeholder="Small — 32px · 13px"
/>
<input class="form-control" type="text" placeholder="Default — 36px · 14px" />
<input
  class="form-control form-control-lg"
  type="text"
  placeholder="Large — 42px · 14px"
/>
```

## Textarea

`form-control` with `rows`. Same label pattern as input.

<div class="sq-preview">
  <label class="form-label" for="note">Note</label>
  <textarea class="form-control" id="note" rows="4" placeholder="Imported from CSV"></textarea>
</div>

```html
<label class="form-label" for="note">Note</label>
<textarea
  class="form-control"
  id="note"
  rows="4"
  placeholder="Imported from CSV"
></textarea>
```

## Select

`form-select` for a single owner or category choice.

<div class="sq-preview">
  <label class="form-label" for="owner">Owner</label>
  <select class="form-select" id="owner">
    <option>Marieke de Groot</option>
    <option>Anouk Peters</option>
    <option>Lars Hendriks</option>
  </select>
</div>

```html
<label class="form-label" for="owner">Owner</label>
<select class="form-select" id="owner">
  <option>Marieke de Groot</option>
  <option>Anouk Peters</option>
  <option>Lars Hendriks</option>
</select>
```

## Checkbox

`form-check` with `type="checkbox"`. Label-less in table rows (`aria-label` on the input). Optional `.desc` inside the label for a sub-line.

<div class="sq-preview">
  <div class="d-flex align-items-start gap-3 mb-3">
    <input class="form-check-input" type="checkbox" checked aria-label="Checked" />
    <input class="form-check-input" type="checkbox" aria-label="Unchecked" />
  </div>
  <div class="form-check">
    <input class="form-check-input" id="email-opt-in" type="checkbox" checked />
    <label class="form-check-label" for="email-opt-in">
      Email opt-in
      <span class="desc">Include in campaign sends.</span>
    </label>
  </div>
</div>

```html
<input class="form-check-input" type="checkbox" checked aria-label="Checked" />
<input class="form-check-input" type="checkbox" aria-label="Unchecked" />
<div class="form-check">
  <input class="form-check-input" id="email-opt-in" type="checkbox" checked />
  <label class="form-check-label" for="email-opt-in">
    Email opt-in
    <span class="desc">Include in campaign sends.</span>
  </label>
</div>
```

## Radio

Same `form-check` pattern with `type="radio"` and a shared `name`.

<div class="sq-preview">
  <div class="form-check">
    <input class="form-check-input" id="priority-normal" name="priority" type="radio" checked />
    <label class="form-check-label" for="priority-normal">Normal</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" id="priority-urgent" name="priority" type="radio" />
    <label class="form-check-label" for="priority-urgent">Urgent</label>
  </div>
</div>

```html
<div class="form-check">
  <input class="form-check-input" id="priority-normal" name="priority" type="radio" checked />
  <label class="form-check-label" for="priority-normal">Normal</label>
</div>
<div class="form-check">
  <input class="form-check-input" id="priority-urgent" name="priority" type="radio" />
  <label class="form-check-label" for="priority-urgent">Urgent</label>
</div>
```

### Pill radio group

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Two to four short labels in a form. Same `form-check` markup inside `sq-pill-radio`. Icons are CSS on the label.

<div class="sq-preview">
  <div class="sq-pill-radio" role="radiogroup" aria-label="Interested">
    <div class="form-check">
      <input class="form-check-input" id="pill-interested-yes" name="pill-interested" type="radio" checked />
      <label class="form-check-label" for="pill-interested-yes">Yes</label>
    </div>
    <div class="form-check">
      <input class="form-check-input" id="pill-interested-no" name="pill-interested" type="radio" />
      <label class="form-check-label" for="pill-interested-no">No</label>
    </div>
    <div class="form-check">
      <input class="form-check-input" id="pill-interested-unsure" name="pill-interested" type="radio" />
      <label class="form-check-label" for="pill-interested-unsure">Not sure</label>
    </div>
  </div>
</div>

```html
<div class="sq-pill-radio" role="radiogroup" aria-label="Interested">
  <div class="form-check">
    <input class="form-check-input" id="pill-interested-yes" name="pill-interested" type="radio" checked />
    <label class="form-check-label" for="pill-interested-yes">Yes</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" id="pill-interested-no" name="pill-interested" type="radio" />
    <label class="form-check-label" for="pill-interested-no">No</label>
  </div>
  <div class="form-check">
    <input class="form-check-input" id="pill-interested-unsure" name="pill-interested" type="radio" />
    <label class="form-check-label" for="pill-interested-unsure">Not sure</label>
  </div>
</div>
```

## Switch

`form-check form-switch` — same checkbox input, toggle styling.

<div class="sq-preview">
  <div class="form-check form-switch">
    <input class="form-check-input" id="notify-updates" type="checkbox" checked />
    <label class="form-check-label" for="notify-updates">Notify me on status changes</label>
  </div>
</div>

```html
<div class="form-check form-switch">
  <input class="form-check-input" id="notify-updates" type="checkbox" checked />
  <label class="form-check-label" for="notify-updates">Notify me on status changes</label>
</div>
```

## Range

Bootstrap **`form-range`**. Label row: **`d-flex justify-content-between align-items-baseline`**, **`output.font-monospace.small.text-secondary`** (`for` matches the input `id`).

<div class="sq-preview">
  <div class="mb-0">
    <div class="d-flex justify-content-between align-items-baseline gap-3 mb-1">
      <label class="form-label mb-0" for="deal-probability">Deal probability</label>
      <output class="font-monospace small text-secondary mb-0" for="deal-probability">35%</output>
    </div>
    <input class="form-range" id="deal-probability" type="range" min="0" max="100" value="35" step="1" />
  </div>
</div>

```html
<div class="mb-3">
  <div class="d-flex justify-content-between align-items-baseline gap-3 mb-1">
    <label class="form-label mb-0" for="deal-probability">Deal probability</label>
    <output class="font-monospace small text-secondary mb-0" for="deal-probability">35%</output>
  </div>
  <input
    class="form-range"
    id="deal-probability"
    type="range"
    min="0"
    max="100"
    value="35"
    step="1"
  />
</div>
```

## Validation

`is-valid` / `is-invalid` with `valid-feedback` or `invalid-feedback`.

<div class="sq-preview">
  <div class="row g-3">
    <div class="col-md-6">
      <label class="form-label" for="company-valid">Company name</label>
      <input class="form-control is-valid" id="company-valid" type="text" value="Van den Berg Logistics" />
      <div class="valid-feedback">Looks good.</div>
    </div>
    <div class="col-md-6">
      <label class="form-label" for="owner-required">Owner</label>
      <select class="form-select is-invalid" id="owner-required">
        <option value="">Select an owner</option>
      </select>
      <div class="invalid-feedback">Assign an owner before activating this step.</div>
    </div>
  </div>
</div>

```html
<label class="form-label" for="company-valid">Company name</label>
<input
  class="form-control is-valid"
  id="company-valid"
  type="text"
  value="Van den Berg Logistics"
/>
<div class="valid-feedback">Looks good.</div>
<label class="form-label" for="owner-required">Owner</label>
<select class="form-select is-invalid" id="owner-required">
  <option value="">Select an owner</option>
</select>
<div class="invalid-feedback">Assign an owner before activating this step.</div>
```

## Disabled

45% opacity, `not-allowed` cursor, no colour change.

<div class="sq-preview">
  <label class="form-label" for="company-locked">Company name</label>
  <input class="form-control" id="company-locked" type="text" value="Van den Berg Logistics" disabled />
</div>

```html
<label class="form-label" for="company-locked">Company name</label>
<input
  class="form-control"
  id="company-locked"
  type="text"
  value="Van den Berg Logistics"
  disabled
/>
```

## Rules

### Labels and validation

- Labels are **nouns**, no colon (“Company name”, “Owner”).
- Validation: name the missing field and next step — not “Something went wrong”.
### Control choice

- **Switch**: takes effect immediately. **Checkbox**: saved with the form submit.
- Short exclusive pair: stacked radios. Two–four options: **`sq-pill-radio`**. More: **select**. Not [segmented](/components/segmented) (presentation) or `nav-pills` (page content / property filter) — [Choose a control](/components/navigation#choose-a-control).
### Input groups

Search: **`input-group-merge`** (Sqrl custom), **`role="searchbox"`**, clear with **`bi-x-circle-fill`**. Command palette: **`input-group-shortcut`**. Chrome icons: [Iconography](/design/iconography).
### Sizes

**`form-control-sm`** is the floor (32px); default and **`-lg`** for larger fields.


---

<!-- Source: components/modals.md -->

# Modals

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap **modal** and **offcanvas** (side panel). Markup below; **when to use which** → [Rules](#rules).

## Modal

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Standard task modal: Bootstrap **`modal-content`** (20px radius, overlay shadow via theme) with padded **`modal-header`**, **`modal-body`**, **`modal-footer`**. Header icon tile **`modal-icon`** is Sqrl custom (contextual **`bg-*-subtle`** + **`text-*`**, flat glyph — [Iconography](/design/iconography)) + serif **`modal-title`** (21px) + [`btn-close`](/components/close-button). Body = [form](/components/forms) (`row g-3` or stacked fields). Footer = actions **right-aligned** — Cancel **`btn-secondary`**, primary **`btn-primary`**.

<div class="sq-preview bg-body-secondary p-4">
  <div class="modal-dialog mb-0 mx-auto">
    <div class="modal-content shadow-lg">
      <div class="modal-header">
        <div class="d-flex align-items-center gap-3 me-auto min-w-0">
          <span class="modal-icon bg-success-subtle text-success" aria-hidden="true">
            <i class="bi bi-diagram-3"></i>
          </span>
          <h2 class="modal-title mb-0">New flow</h2>
        </div>
        <button type="button" class="btn-close" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <div class="row g-3">
          <div class="col-12">
            <label class="form-label" for="modal-flow-name">Name <span class="text-danger">*</span></label>
            <input class="form-control" id="modal-flow-name" type="text" placeholder="Flow name" />
          </div>
          <div class="col-12">
            <label class="form-label" for="modal-flow-type">Type</label>
            <select class="form-select" id="modal-flow-type">
              <option selected>General</option>
            </select>
          </div>
          <div class="col-12">
            <label class="form-label" for="modal-flow-template">Template <span class="text-muted fw-normal">(optional)</span></label>
            <select class="form-select" id="modal-flow-template">
              <option selected disabled>Select a template</option>
            </select>
          </div>
          <div class="col-12">
            <label class="form-label" for="modal-flow-account">Account <span class="text-danger">*</span></label>
            <div class="input-group input-group-merge">
              <span class="input-group-text"><i class="bi bi-search" aria-hidden="true"></i></span>
              <input
                class="form-control"
                id="modal-flow-account"
                type="text"
                role="searchbox"
                autocomplete="off"
                placeholder="Search account"
              />
            </div>
          </div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary">Cancel</button>
        <button type="button" class="btn btn-primary">Create</button>
      </div>
    </div>
  </div>
</div>

```html
<div class="modal-content">
  <div class="modal-header">
    <div class="d-flex align-items-center gap-3 me-auto min-w-0">
      <span
        class="modal-icon bg-success-subtle text-success"
        aria-hidden="true"
      >
        <i class="bi bi-diagram-3"></i>
      </span>
      <h2 class="modal-title mb-0">New flow</h2>
    </div>
    <button type="button" class="btn-close" aria-label="Close"></button>
  </div>
  <div class="modal-body">
    <!-- body content -->
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-secondary">Cancel</button>
    <button type="button" class="btn btn-primary">Create</button>
  </div>
</div>
```

Padding comes from Bootstrap **`modal-header`** / **`modal-body`** / **`modal-footer`** (theme: 1.5rem). No header/footer divider lines.

## Confirmation

Short copy-only modal: **`modal-dialog modal-dialog-centered modal-sm`** (centered on the viewport). **Centered** title and body copy; **no header close** — dismiss via **Cancel** (and the primary action). Footer actions share the row at **full width** (theme: **`flex-grow-1`** on each **`.btn`**). No icon tile. Destructive primary **`btn-danger`**.

<div class="sq-preview bg-body-secondary d-flex align-items-center justify-content-center py-4" style="min-height: 18rem">
  <div class="modal-dialog modal-dialog-centered modal-sm my-0">
    <div class="modal-content shadow-lg">
      <div class="modal-header justify-content-center">
        <h3 class="modal-title mb-0 text-center">Delete contact</h3>
      </div>
      <div class="modal-body py-3 text-center">
        <p class="mb-0">Anouk Peters will be removed from Van den Berg Logistics. Activities stay on the account.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary">Cancel</button>
        <button type="button" class="btn btn-danger">Delete</button>
      </div>
    </div>
  </div>
</div>

## Side panel

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Bootstrap **`offcanvas-end`**: square edges (no border radius), **`offcanvas-header`** (**`modal-icon`** tile — Sqrl custom — + **`offcanvas-title`** + close, **border-bottom** via theme), and **`offcanvas-body`**. Example: a notifications drawer with stacked [toast](/components/feedback) cards.

<div class="sq-preview">
  <button
    type="button"
    class="btn btn-primary"
    data-bs-toggle="offcanvas"
    data-bs-target="#sq-doc-notifications-offcanvas"
    aria-controls="sq-doc-notifications-offcanvas"
  >
    Open notifications
  </button>
</div>

<div
  class="offcanvas offcanvas-end"
  tabindex="-1"
  id="sq-doc-notifications-offcanvas"
  aria-labelledby="sq-doc-notifications-offcanvas-title"
>
  <div class="offcanvas-header">
    <div class="d-flex align-items-center gap-3 me-auto min-w-0">
      <span class="modal-icon bg-info-subtle text-info" aria-hidden="true">
        <i class="bi bi-bell"></i>
      </span>
      <h2 class="offcanvas-title h4 mb-0" id="sq-doc-notifications-offcanvas-title">Notifications</h2>
    </div>
    <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body d-flex flex-column gap-3">
    <div class="toast show mb-0 w-100" role="status" aria-live="polite">
      <div class="toast-header">
        <i class="bi bi-check-circle-fill text-success mt-1" aria-hidden="true"></i>
        <strong class="me-auto">Changes saved</strong>
        <button type="button" class="btn-close btn-close-sm" aria-label="Close"></button>
      </div>
      <div class="toast-body">Contact details were updated.</div>
    </div>
    <div class="toast show mb-0 w-100" role="status" aria-live="polite">
      <div class="toast-header">
        <i class="bi bi-info-circle-fill text-info mt-1" aria-hidden="true"></i>
        <strong class="me-auto">New task assigned</strong>
        <button type="button" class="btn-close btn-close-sm" aria-label="Close"></button>
      </div>
      <div class="toast-body">Follow up with Van den Berg Logistics before Friday.</div>
    </div>
    <div class="toast show mb-0 w-100" role="alert" aria-live="assertive">
      <div class="toast-header">
        <i class="bi bi-exclamation-triangle-fill text-warning mt-1" aria-hidden="true"></i>
        <strong class="me-auto">Needs attention</strong>
        <button type="button" class="btn-close btn-close-sm" aria-label="Close"></button>
      </div>
      <div class="toast-body">Follow up with Van den Berg Logistics before Friday.</div>
    </div>
  </div>
</div>

```html
<button
  type="button"
  class="btn btn-primary"
  data-bs-toggle="offcanvas"
  data-bs-target="#notificationsOffcanvas"
  aria-controls="notificationsOffcanvas"
>
  Open notifications
</button>

<div
  class="offcanvas offcanvas-end"
  tabindex="-1"
  id="notificationsOffcanvas"
  aria-labelledby="notificationsOffcanvasTitle"
>
  <div class="offcanvas-header">
    <div class="d-flex align-items-center gap-3 me-auto min-w-0">
      <span class="modal-icon bg-info-subtle text-info" aria-hidden="true">
        <i class="bi bi-bell"></i>
      </span>
      <h2 class="offcanvas-title h3 mb-0" id="notificationsOffcanvasTitle">
        Notifications
      </h2>
    </div>
    <button
      type="button"
      class="btn-close"
      data-bs-dismiss="offcanvas"
      aria-label="Close"
    ></button>
  </div>
  <div class="offcanvas-body d-flex flex-column gap-3">
    <div class="toast show mb-0 w-100" role="status" aria-live="polite">
      <div class="toast-header">
        <i class="bi bi-check-circle-fill text-success" aria-hidden="true"></i>
        <strong class="me-auto">Changes saved</strong>
        <button
          type="button"
          class="btn-close btn-close-sm"
          aria-label="Close"
        ></button>
      </div>
      <div class="toast-body">Contact details were updated.</div>
    </div>
    <!-- more notification toasts -->
  </div>
</div>
```

## Rules

### Modal

- Focused create/edit or confirmation — blocks the page until dismissed (backdrop + **`--shadow-overlay`**).
- **Standard task modal:** **`modal-icon`** (Sqrl custom) + contextual Bootstrap subtle/text utilities + **`modal-title`** in header; **form in body**; **Cancel** + one primary action in footer (right-aligned).
- **Confirmation:** **`modal-sm`** + **`modal-dialog-centered`**; **centered** title and body; **no `btn-close`** in the header — **Cancel** dismisses; footer **`.btn`** actions equal full width; name the object; destructive → **`btn-danger`** with explicit label.
- Cancel is always **`btn-secondary`**. Primary verb matches the task (“Create”, “Save changes”).

### Side panel

- Secondary content **beside the main view** (notifications, filters, record detail) — use **`offcanvas-end`**, not a centered modal.
- **No border radius** on the panel (theme); **`offcanvas-header`** with **`modal-icon`** (Sqrl custom) + **`offcanvas-title`** + **`btn-close`**; header **border-bottom** (theme).
- Stack related items in **`offcanvas-body`** (e.g. full-width **`toast`** cards with **`gap-3`**).


---

<!-- Source: components/navigation.md -->

# Navigation

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Sidebar, tabs, breadcrumb, scope bar. Patterns below; **usage** → [Rules](#rules).

## Choose a control

Pick by **what changes**, not by look. Segmented and tabs can both look like a pill row.

| What changes | Use this | Not that |
| --- | --- | --- |
| **Presentation only** — same records, different chrome (table ↔ cards) | [Segmented](/components/segmented) (`sq-segmented`) | Tabs, [pill radio](/components/forms#pill-radio-group) |
| **Page content or a property filter** — another slice of the page (All / Mine / Active), or a different panel | [Pill tabs](#pill-tabs) in the [filter row](/design/layout#filter-row); [underline tabs](#underline-tabs) on a section edge | Segmented |
| **Form field** — two to four exclusive options the user saves with the form | [Pill radio](/components/forms#pill-radio-group) (`sq-pill-radio`) | Segmented, `nav-pills` |

App chrome (rail, scope, breadcrumb) is not interchangeable with these — see sections below.

## Sidenav

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Rail anatomy (see [Layout](/design/layout#sidebar-rail)): [Scope switch](/components/scope-switch) → divider → nav list → footer (search, user). Nav lives in **`sq-sidenav`** (tag below).

- **`sq-sidenav`** → Bootstrap **`list-group list-group-flush`** → **`list-group-item-action`** + filled **`bi-*-fill`** icons ([Iconography](/design/iconography)).
- Labels in order: Home, Accounts, Contacts, Tasks, Activities, Flows.
- Optional count: **`span.font-monospace`**. Active: **`active`** + **`aria-current="page"`** (paper chip — not primary green).
<div class="sq-preview">
  <nav class="sq-sidenav" aria-label="Main">
    <div class="list-group list-group-flush">
      <a class="list-group-item list-group-item-action" href="#">
        <i class="bi bi-house-fill" aria-hidden="true"></i>
        Home
      </a>
      <a class="list-group-item list-group-item-action" href="#">
        <i class="bi bi-buildings-fill" aria-hidden="true"></i>
        Accounts
        <span class="font-monospace">128</span>
      </a>
      <a class="list-group-item list-group-item-action active" href="#" aria-current="page">
        <i class="bi bi-people-fill" aria-hidden="true"></i>
        Contacts
        <span class="font-monospace">412</span>
      </a>
      <a class="list-group-item list-group-item-action" href="#">
        <i class="bi bi-check-square-fill" aria-hidden="true"></i>
        Tasks
        <span class="font-monospace">16</span>
      </a>
      <a class="list-group-item list-group-item-action" href="#">
        <i class="bi bi-clock-fill" aria-hidden="true"></i>
        Activities
      </a>
      <a class="list-group-item list-group-item-action" href="#">
        <i class="bi bi-diagram-3-fill" aria-hidden="true"></i>
        Flows
      </a>
    </div>
  </nav>
</div>

```html
<nav class="sq-sidenav" aria-label="Main">
  <div class="list-group list-group-flush">
    <a class="list-group-item list-group-item-action" href="#">
      <i class="bi bi-house-fill" aria-hidden="true"></i>
      Home
    </a>
    <a class="list-group-item list-group-item-action" href="#">
      <i class="bi bi-buildings-fill" aria-hidden="true"></i>
      Accounts
      <span class="font-monospace">128</span>
    </a>
    <a
      class="list-group-item list-group-item-action active"
      href="#"
      aria-current="page"
    >
      <i class="bi bi-people-fill" aria-hidden="true"></i>
      Contacts
      <span class="font-monospace">412</span>
    </a>
    <a class="list-group-item list-group-item-action" href="#">
      <i class="bi bi-check-square-fill" aria-hidden="true"></i>
      Tasks
      <span class="font-monospace">16</span>
    </a>
    <a class="list-group-item list-group-item-action" href="#">
      <i class="bi bi-clock-fill" aria-hidden="true"></i>
      Activities
    </a>
    <a class="list-group-item list-group-item-action" href="#">
      <i class="bi bi-diagram-3-fill" aria-hidden="true"></i>
      Flows
    </a>
  </div>
</nav>
```

## Pill tabs

- **`ul.nav.nav-pills`** → **`nav-link`**; optional **`font-monospace`** count on the link.
- Different **page content** or a **property filter** (All / Mine / Active) in the [filter row](/design/layout#filter-row) — not presentation (table ↔ cards). [Choose a control](#choose-a-control).
<div class="sq-preview">
  <ul class="nav nav-pills">
    <li class="nav-item">
      <a class="nav-link active" href="#" aria-current="page">All <span class="font-monospace">412</span></a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">My contacts</a>
    </li>
  </ul>
</div>

```html
<ul class="nav nav-pills">
  <li class="nav-item">
    <a class="nav-link active" href="#" aria-current="page"
      >All <span class="font-monospace">412</span></a
    >
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">My contacts</a>
  </li>
</ul>
```

## Underline tabs

**`ul.nav.nav-tabs`** on a content edge for **another panel of content** (not table ↔ cards). Same optional count pattern as pills.
<div class="sq-preview">
  <ul class="nav nav-tabs">
    <li class="nav-item">
      <a class="nav-link active" href="#" aria-current="page">Overview</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">Contacts <span class="font-monospace">12</span></a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">Activity</a>
    </li>
  </ul>
</div>

```html
<ul class="nav nav-tabs">
  <li class="nav-item">
    <a class="nav-link active" href="#" aria-current="page">Overview</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#"
      >Contacts <span class="font-monospace">12</span></a
    >
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Activity</a>
  </li>
</ul>
```

## Scope bar

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`sq-panel`** → **`sq-scope-bar`** (`role="region"`) at top: icon + **`sq-scope-bar__title`** + optional **`sq-scope-bar__meta`**; exit **`btn btn-sm btn-outline-light rounded-pill sq-scope-bar__exit`**.
<div class="sq-preview">
  <div class="sq-panel">
    <div class="sq-scope-bar" role="region" aria-label="Account scope">
      <div class="sq-scope-bar__main">
        <i class="bi bi-funnel-fill sq-scope-bar__icon" aria-hidden="true"></i>
        <span class="sq-scope-bar__title">Van den Berg Logistics</span>
        <span class="sq-scope-bar__meta">30 contacts</span>
      </div>
      <button type="button" class="btn btn-sm btn-outline-light rounded-pill sq-scope-bar__exit">
        <i class="bi bi-x-lg" aria-hidden="true"></i>
        Leave account
      </button>
    </div>
  </div>
</div>

```html
<div class="sq-scope-bar" role="region" aria-label="Account scope">
  <div class="sq-scope-bar__main">
    <i class="bi bi-funnel-fill sq-scope-bar__icon" aria-hidden="true"></i>
    <span class="sq-scope-bar__title">Van den Berg Logistics</span>
    <span class="sq-scope-bar__meta">30 contacts</span>
  </div>
  <button
    type="button"
    class="btn btn-sm btn-outline-light rounded-pill sq-scope-bar__exit"
  >
    <i class="bi bi-x-lg" aria-hidden="true"></i>
    Leave account
  </button>
</div>
```

## Breadcrumb

**`nav`** → **`ol.breadcrumb`** → **`breadcrumb-item`**; current page **`active`** + **`aria-current="page"`**.
<div class="sq-preview">
  <nav aria-label="breadcrumb">
    <ol class="breadcrumb mb-0">
      <li class="breadcrumb-item"><a href="#">Accounts</a></li>
      <li class="breadcrumb-item"><a href="#">Van den Berg Logistics</a></li>
      <li class="breadcrumb-item active" aria-current="page">Contacts</li>
    </ol>
  </nav>
</div>

```html
<nav aria-label="breadcrumb">
  <ol class="breadcrumb mb-0">
    <li class="breadcrumb-item"><a href="#">Accounts</a></li>
    <li class="breadcrumb-item"><a href="#">Van den Berg Logistics</a></li>
    <li class="breadcrumb-item active" aria-current="page">Contacts</li>
  </ol>
</nav>
```

## Rules

### App shell

- Primary nav is a **sidebar** (248px, flush on `surface-app`), not a topbar — [Layout](/design/layout#app-shell).
- Top-level labels: Home, Accounts, Contacts, Tasks, Activities, Flows.
- Rail footer: search + user block pinned with **`margin-top: auto`** on the nav column.
### Account context

Inside an account: first item = that account’s overview; Accounts drops out, Quotes appears.
### Tabs and filters

- **`nav-pills`** vs **`sq-segmented`**: [Choose a control](#choose-a-control) — tabs change **content or a property filter**; segmented changes **presentation of the same data**.
- **`nav-pills`**: filter row. **`nav-tabs`**: underline on a content edge for another panel. Not **`btn-group`**.
- Optional mono counts on nav items.
### Scope bar

- **`sq-scope-bar`** inside **`sq-panel`**: flat bar, pill exit with icon — not **`btn-primary`**.
- On **record/detail** views scoped to an account, place the scope bar **above** the page header ([Layout](/design/layout#scope-bar)).


---

<!-- Source: components/pagination.md -->

# Pagination

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap `pagination` + optional **Showing … of …** summary. Markup below; **usage** → [Rules](#rules).

- Summary: **`p.small.text-secondary.mb-0`** with **`font-monospace fw-bold`** on range and total only.
- Controls: **`nav`** → **`ul.pagination`** → **`page-item`** / **`page-link`**. Active page: **`page-item active`** + **`span.page-link`**.
<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
    <p class="small text-secondary mb-0">
      Showing
      <span class="font-monospace fw-bold">26–50</span>
      of
      <span class="font-monospace fw-bold">412</span>
    </p>
    <nav aria-label="Contacts pages">
      <ul class="pagination mb-0">
        <li class="page-item">
          <a class="page-link" href="#" aria-label="Previous page">
            <i class="bi bi-chevron-left" aria-hidden="true"></i>
          </a>
        </li>
        <li class="page-item"><a class="page-link" href="#">1</a></li>
        <li class="page-item active" aria-current="page"><span class="page-link">2</span></li>
        <li class="page-item"><a class="page-link" href="#">3</a></li>
        <li class="page-item"><a class="page-link" href="#">4</a></li>
        <li class="page-item disabled" aria-hidden="true"><span class="page-link">…</span></li>
        <li class="page-item"><a class="page-link" href="#">8</a></li>
        <li class="page-item">
          <a class="page-link" href="#" aria-label="Next page">
            <i class="bi bi-chevron-right" aria-hidden="true"></i>
          </a>
        </li>
      </ul>
    </nav>
  </div>
</div>

```html
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
  <p class="small text-secondary mb-0">
    Showing
    <span class="font-monospace fw-bold">26–50</span>
    of
    <span class="font-monospace fw-bold">412</span>
  </p>
  <nav aria-label="Contacts pages">
    <ul class="pagination mb-0">
      <li class="page-item">
        <a class="page-link" href="#" aria-label="Previous page">
          <i class="bi bi-chevron-left" aria-hidden="true"></i>
        </a>
      </li>
      <li class="page-item"><a class="page-link" href="#">1</a></li>
      <li class="page-item active" aria-current="page"><span class="page-link">2</span></li>
      <li class="page-item"><a class="page-link" href="#">3</a></li>
      <li class="page-item"><a class="page-link" href="#">4</a></li>
      <li class="page-item disabled" aria-hidden="true"><span class="page-link">…</span></li>
      <li class="page-item"><a class="page-link" href="#">8</a></li>
      <li class="page-item">
        <a class="page-link" href="#" aria-label="Next page">
          <i class="bi bi-chevron-right" aria-hidden="true"></i>
        </a>
      </li>
    </ul>
  </nav>
</div>
```

## Rules

### Placement

Pair with [table](/components/table) list pages: summary left, controls right, **`mt-3`** (or equivalent) **below** the table **`card-bordered`** — not inside the card or **`card-footer`**. Align with the list page inset ([Layout — List and table pages](/design/layout#list-and-table-pages-optional-pattern)).
### Controls

- Prev/next: chevron icons inside **`page-link`**; **`aria-label`** on the link (“Previous page”, “Next page”) — [Iconography](/design/iconography).
- Ellipsis: disabled **`page-item`** with **`span.page-link`** (not a link).
- Active page uses filled stone treatment (theme); inactive links are stone text, not link green.
### Copy

Summary pattern: **Showing** {range} **of** {total} — mono bold on numerals only.


---

<!-- Source: components/popover.md -->

# Popover

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap popover — context or explanation, not a menu. Markup below; **usage** → [Rules](#rules).

Docs init popovers in `bootstrap-overlays.js`. Default **`data-bs-trigger="hover focus"`**, **`data-bs-placement="bottom"`**.

## Info

Field help: **`btn-ghost btn-sm`** + **`bi-info-circle`**, **`data-bs-title`** + **`data-bs-content`**.

<div class="sq-preview">
  <button
    type="button"
    class="btn btn-ghost btn-sm"
    aria-label="Quote potential"
    data-bs-toggle="popover"
    data-bs-trigger="hover focus"
    data-bs-placement="bottom"
    data-bs-title="Quote potential"
    data-bs-content="Estimated deal value based on company size and the products in scope. Updates when the account’s profile changes."
  >
    <i class="bi bi-info-circle"></i>
  </button>
</div>

```html
<button
  type="button"
  class="btn btn-ghost btn-sm"
  aria-label="Quote potential"
  data-bs-toggle="popover"
  data-bs-trigger="hover focus"
  data-bs-placement="bottom"
  data-bs-title="Quote potential"
  data-bs-content="Estimated deal value based on company size and the products in scope. Updates when the account’s profile changes."
>
  <i class="bi bi-info-circle"></i>
</button>
```

## Contact

Person summary: trigger can be an [**avatar**](/components/avatar) with **`role="button"`**, **`tabindex="0"`**, and **`aria-label`**.

<div class="sq-preview">
  <span
    class="avatar text-bg-info"
    role="button"
    tabindex="0"
    aria-label="Marieke de Groot"
    data-bs-toggle="popover"
    data-bs-trigger="hover focus"
    data-bs-placement="bottom"
    data-bs-title="Marieke de Groot"
    data-bs-content="Owner · 12 open tasks"
  >MD</span>
</div>

```html
<span
  class="avatar text-bg-info"
  role="button"
  tabindex="0"
  aria-label="Marieke de Groot"
  data-bs-toggle="popover"
  data-bs-trigger="hover focus"
  data-bs-placement="bottom"
  data-bs-title="Marieke de Groot"
  data-bs-content="Owner · 12 open tasks"
  >MD</span
>
```

## Rules

### When to use

- Explanatory copy on hover/focus — closes without choosing an item.
- Not a selectable list (dropdown) or task flow ([modal](/components/modals)).
### Content

- One title line + short body — longer than a tooltip, shorter than a side panel.
- No primary or destructive actions inside the popover.
### Triggers

Info fields: icon button. People: avatar trigger as above. Flat icons: [Iconography](/design/iconography).


---

<!-- Source: components/progress.md -->

# Progress

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Determinate progress only. Markup and sizes below; **usage** → [Rules](#rules).

- Label row: **`small fw-semibold`** + **`small font-monospace`** percent above the track.
- Track: **`progress`** + size modifier; fill **`progress-bar`**; set **`role="progressbar"`**, **`aria-valuenow`**, **`aria-valuemin`**, **`aria-valuemax`**, **`aria-label`** (or visible label).
- Default height: **`progress-sm`** (plain **`progress`** matches sm).
<div class="sq-preview">
  <div class="d-flex align-items-baseline justify-content-between mb-2">
    <span class="small fw-semibold">Import prospects</span>
    <span class="small font-monospace">75%</span>
  </div>
  <div
    class="progress progress-sm"
    role="progressbar"
    aria-label="Import prospects"
    aria-valuenow="75"
    aria-valuemin="0"
    aria-valuemax="100"
  >
    <div class="progress-bar w-75"></div>
  </div>
</div>

```html
<div class="d-flex align-items-baseline justify-content-between mb-2">
  <span class="small fw-semibold">Import prospects</span>
  <span class="small font-monospace">75%</span>
</div>
<div
  class="progress progress-sm"
  role="progressbar"
  aria-label="Import prospects"
  aria-valuenow="75"
  aria-valuemin="0"
  aria-valuemax="100"
>
  <div class="progress-bar w-75"></div>
</div>
```

## Sizes

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Modifier on the **track** (`progress`): **`progress-sm`** (default), **`progress-md`**, **`progress-lg`**.

<div class="sq-preview">
  <div class="d-flex flex-column gap-4">
    <div>
      <div class="d-flex align-items-baseline justify-content-between mb-2">
        <span class="small fw-semibold">Small (4px)</span>
        <span class="small font-monospace">40%</span>
      </div>
      <div
        class="progress progress-sm"
        role="progressbar"
        aria-label="Small progress"
        aria-valuenow="40"
        aria-valuemin="0"
        aria-valuemax="100"
      >
        <div class="progress-bar" style="width: 40%"></div>
      </div>
    </div>
    <div>
      <div class="d-flex align-items-baseline justify-content-between mb-2">
        <span class="small fw-semibold">Medium (6px)</span>
        <span class="small font-monospace">60%</span>
      </div>
      <div
        class="progress progress-md"
        role="progressbar"
        aria-label="Medium progress"
        aria-valuenow="60"
        aria-valuemin="0"
        aria-valuemax="100"
      >
        <div class="progress-bar" style="width: 60%"></div>
      </div>
    </div>
    <div class="mb-0">
      <div class="d-flex align-items-baseline justify-content-between mb-2">
        <span class="small fw-semibold">Large (8px)</span>
        <span class="small font-monospace">85%</span>
      </div>
      <div
        class="progress progress-lg mb-0"
        role="progressbar"
        aria-label="Large progress"
        aria-valuenow="85"
        aria-valuemin="0"
        aria-valuemax="100"
      >
        <div class="progress-bar" style="width: 85%"></div>
      </div>
    </div>
  </div>
</div>

```html
<div
  class="progress progress-md"
  role="progressbar"
  aria-valuenow="60"
  aria-valuemin="0"
  aria-valuemax="100"
>
  <div class="progress-bar" style="width: 60%"></div>
</div>
```

## Rules

### When to use

Known completion (import, export, multi-step job) — always show a **percentage**, never indeterminate animation.
### Accessibility

**`aria-valuenow`** and label on the track; keep the visible percent in sync.
### Size

One size per bar; **`progress-md`** / **`progress-lg`** when the bar needs more weight (e.g. import panel header).


---

<!-- Source: components/segmented.md -->

# Segmented control

<p><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

**`sq-segmented`** wrapper + Bootstrap **`btn-check`** / **`btn`** segments. Switches **presentation of the same data** (table ↔ cards) — not another page slice or a property filter ([Choose a control](/components/navigation#choose-a-control)). Patterns below; **usage** → [Rules](#rules).

- Wrapper: **`sq-segmented`** (+ optional **`sq-segmented-sm`** / **`sq-segmented-lg`**, **`rounded-pill`**).
- One **`role="group"`** + shared **`name`** on radios; labels are **`label.btn`** for each **`input.btn-check`**.

## Labels

Text segments: presentation names (List, Cards) — not filters (All / Mine) and not button-style verb + object.

<div class="sq-preview">
  <div class="sq-segmented" role="group" aria-label="Layout">
    <input type="radio" class="btn-check" name="seg-layout" id="seg-layout-list" autocomplete="off" checked />
    <label class="btn" for="seg-layout-list">List</label>
    <input type="radio" class="btn-check" name="seg-layout" id="seg-layout-cards" autocomplete="off" />
    <label class="btn" for="seg-layout-cards">Cards</label>
  </div>
</div>

```html
<div class="sq-segmented" role="group" aria-label="Layout">
  <input
    type="radio"
    class="btn-check"
    name="seg-layout"
    id="seg-layout-list"
    autocomplete="off"
    checked
  />
  <label class="btn" for="seg-layout-list">List</label>
  <input
    type="radio"
    class="btn-check"
    name="seg-layout"
    id="seg-layout-cards"
    autocomplete="off"
  />
  <label class="btn" for="seg-layout-cards">Cards</label>
</div>
```

## Icons

Icon-only: **`aria-label`** on each **`input.btn-check`**.

<div class="sq-preview">
  <div class="sq-segmented" role="group" aria-label="Layout">
    <input type="radio" class="btn-check" name="seg-icons" id="seg-icons-list" autocomplete="off" checked aria-label="List" />
    <label class="btn" for="seg-icons-list"><i class="bi bi-list-ul"></i></label>
    <input type="radio" class="btn-check" name="seg-icons" id="seg-icons-cards" autocomplete="off" aria-label="Cards" />
    <label class="btn" for="seg-icons-cards"><i class="bi bi-grid"></i></label>
  </div>
</div>

```html
<div class="sq-segmented" role="group" aria-label="Layout">
  <input
    type="radio"
    class="btn-check"
    name="seg-icons"
    id="seg-icons-list"
    autocomplete="off"
    checked
    aria-label="List"
  />
  <label class="btn" for="seg-icons-list"><i class="bi bi-list-ul"></i></label>
  <input
    type="radio"
    class="btn-check"
    name="seg-icons"
    id="seg-icons-cards"
    autocomplete="off"
    aria-label="Cards"
  />
  <label class="btn" for="seg-icons-cards"><i class="bi bi-grid"></i></label>
</div>
```

## Sizes

**`sq-segmented-sm`**, default, **`sq-segmented-lg`** (aligns with [button](/components/buttons) heights).

<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-3">
    <div class="sq-segmented sq-segmented-sm" role="group" aria-label="Small">
      <input type="radio" class="btn-check" name="seg-size-sm" id="seg-size-sm-a" autocomplete="off" checked />
      <label class="btn" for="seg-size-sm-a">List</label>
      <input type="radio" class="btn-check" name="seg-size-sm" id="seg-size-sm-b" autocomplete="off" />
      <label class="btn" for="seg-size-sm-b">Cards</label>
    </div>
    <div class="sq-segmented" role="group" aria-label="Default">
      <input type="radio" class="btn-check" name="seg-size-md" id="seg-size-md-a" autocomplete="off" checked />
      <label class="btn" for="seg-size-md-a">List</label>
      <input type="radio" class="btn-check" name="seg-size-md" id="seg-size-md-b" autocomplete="off" />
      <label class="btn" for="seg-size-md-b">Cards</label>
    </div>
    <div class="sq-segmented sq-segmented-lg" role="group" aria-label="Large">
      <input type="radio" class="btn-check" name="seg-size-lg" id="seg-size-lg-a" autocomplete="off" checked />
      <label class="btn" for="seg-size-lg-a">List</label>
      <input type="radio" class="btn-check" name="seg-size-lg" id="seg-size-lg-b" autocomplete="off" />
      <label class="btn" for="seg-size-lg-b">Cards</label>
    </div>
  </div>
</div>

```html
<div class="sq-segmented sq-segmented-sm">…</div>
<div class="sq-segmented">…</div>
<div class="sq-segmented sq-segmented-lg">…</div>
```

## Radius

Default track radius matches buttons; add **`rounded-pill`** on **`sq-segmented`** for a pill track.

<div class="sq-preview">
  <div class="d-flex flex-wrap align-items-center gap-3">
    <div class="sq-segmented" role="group" aria-label="Default radius">
      <input type="radio" class="btn-check" name="seg-radius-default" id="seg-radius-default-a" autocomplete="off" checked />
      <label class="btn" for="seg-radius-default-a">List</label>
      <input type="radio" class="btn-check" name="seg-radius-default" id="seg-radius-default-b" autocomplete="off" />
      <label class="btn" for="seg-radius-default-b">Cards</label>
    </div>
    <div class="sq-segmented rounded-pill" role="group" aria-label="Pill radius">
      <input type="radio" class="btn-check" name="seg-radius-pill" id="seg-radius-pill-a" autocomplete="off" checked />
      <label class="btn" for="seg-radius-pill-a">List</label>
      <input type="radio" class="btn-check" name="seg-radius-pill" id="seg-radius-pill-b" autocomplete="off" />
      <label class="btn" for="seg-radius-pill-b">Cards</label>
    </div>
  </div>
</div>

```html
<div class="sq-segmented">…</div>
<div class="sq-segmented rounded-pill">…</div>
```

## More than two options

Two to four segments per group; same **`name`** on all radios in the group. Still presentation of the same set — not All / Mine filters.

<div class="sq-preview">
  <div class="sq-segmented" role="group" aria-label="Layout">
    <input type="radio" class="btn-check" name="seg-layout3" id="seg-layout3-list" autocomplete="off" checked />
    <label class="btn" for="seg-layout3-list">List</label>
    <input type="radio" class="btn-check" name="seg-layout3" id="seg-layout3-cards" autocomplete="off" />
    <label class="btn" for="seg-layout3-cards">Cards</label>
    <input type="radio" class="btn-check" name="seg-layout3" id="seg-layout3-board" autocomplete="off" />
    <label class="btn" for="seg-layout3-board">Board</label>
  </div>
</div>

```html
<div class="sq-segmented" role="group" aria-label="Layout">
  <input
    type="radio"
    class="btn-check"
    name="layout"
    id="layout-list"
    autocomplete="off"
    checked
  />
  <label class="btn" for="layout-list">List</label>
  <input
    type="radio"
    class="btn-check"
    name="layout"
    id="layout-cards"
    autocomplete="off"
  />
  <label class="btn" for="layout-cards">Cards</label>
  <input
    type="radio"
    class="btn-check"
    name="layout"
    id="layout-board"
    autocomplete="off"
  />
  <label class="btn" for="layout-board">Board</label>
</div>
```

## Disabled

**`disabled`** on **`input.btn-check`** (single option or whole group).

<div class="sq-preview">
  <div class="sq-segmented" role="group" aria-label="Layout">
    <input type="radio" class="btn-check" name="seg-disabled" id="seg-disabled-list" autocomplete="off" checked disabled />
    <label class="btn" for="seg-disabled-list">List</label>
    <input type="radio" class="btn-check" name="seg-disabled" id="seg-disabled-cards" autocomplete="off" disabled />
    <label class="btn" for="seg-disabled-cards">Cards</label>
  </div>
</div>

```html
<input
  type="radio"
  class="btn-check"
  name="seg-disabled"
  id="seg-disabled-list"
  checked
  disabled
/>
<label class="btn" for="seg-disabled-list">List</label>
```

## Rules

### When to use

- **Exactly one** presentation of the **same records** (list ↔ cards, list ↔ board) — not independent actions (use [buttons](/components/buttons)), not property filters or another page of content (use [tabs](/components/navigation#choose-a-control)).
- Usually in a [toolbar](/components/table#toolbar) or list header, not a [form field](/components/forms).

### Implementation

- Mutually exclusive **`btn-check`** radios only — not **`btn-group`**, not mixed **`btn-primary`** inside the track.
- Two to four options; larger sets → **select** or **tabs**.

### Labels

Short nouns; icon-only inputs need **`aria-label`** on the **`input`** — [Iconography](/design/iconography).


---

<!-- Source: components/table.md -->

# Table

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

List/data tables. Markup and helpers below; **usage** → [Rules](#rules). Sort/action icons: [Iconography](/design/iconography).

## Helper classes

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Bootstrap **`table.table`** alone gives base layout (header, zebra, borders, hover — do not add **`table-striped`** / **`table-hover`**). Optional helpers (see **Sqrl custom** tag above). **`sortable`** is theme-only, not a Bootstrap table modifier.

| Class                  | On                                                | Purpose                                                                                                                                           |
| ---------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sortable`             | `th`                                              | Sortable column: pointer, darker label on hover, `bi-chevron-expand` after the label (before the label when **`text-end`**, **`sq-cell--num`**, or **`sq-cell--date`**). |
| `sq-checkcell`         | `th`, `td`                                        | First column: fixed width for row/select checkboxes and left edge padding.                                                                        |
| `sq-cell--num`         | `th`, `td`                                        | Right-aligned column; monospace tabular nums on **body cells** only (header stays Manrope). Or Bootstrap `text-end` when you only need alignment. |
| `sq-cell--date`        | `th`, `td`                                        | Right-aligned **dates and times** in Manrope (`tabular-nums` on body cells). Not monospace — see [Content](/design/content#numbers-and-dates).    |
| `sq-cell--muted`       | `td`                                              | Muted copy (e.g. em dash when owner is empty).                                                                                                    |
| `sq-col-actions`       | `th`, `td`                                        | Narrow trailing column for row actions; right edge padding.                                                                                       |
| `sq-rowactions`        | `div` in actions cell                             | Wraps icon buttons; hidden until row hover or focus-within.                                                                                       |
| `sq-row--clickable`    | `tr`                                              | Row opens record / navigates (`cursor: pointer`).                                                                                                 |
| `sq-row--selected`     | `tr`                                              | Bulk selection or current row — green-50 background.                                                                                              |
| `sq-cell--wrap`        | `td`                                              | Opt out of default single-line truncation (e.g. long notes).                                                                                      |
| `sq-table-sticky-head` | scroll container (`overflow-auto` + `max-height`) | Header row sticks to the **top of the scroll area** while the body scrolls. |

Status cells use [badges](/components/badge) (`badge-borderless badge-dotted`), not table helpers.

## Data table

- **Required:** **`table.table`** (Sqrl styles in `theme.scss`). Optional [helpers](#helper-classes) in the example below.
- **Clip overflow:** wrap in Bootstrap **`overflow-hidden`** when needed (sticky head, horizontal scroll). Tables and headers are **square** — no `rounded` on the table, `thead`, or wrap.
- List pages: optional toolbar + [pagination](/components/pagination) footer.
<div class="sq-preview">
  <div class="overflow-hidden mb-0">
    <table class="table mb-0">
      <thead>
        <tr>
          <th class="sq-checkcell" scope="col">
            <input class="form-check-input" type="checkbox" aria-label="Select all" />
          </th>
          <th class="sortable" scope="col">
            Account<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col">
            Owner<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col">
            Status<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable sq-cell--num" scope="col">
            Value<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable sq-cell--date" scope="col">
            Last activity<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sq-col-actions" scope="col">
            <span class="visually-hidden">Actions</span>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Van den Berg Logistics" />
          </td>
          <td>Van den Berg Logistics</td>
          <td>Marieke de Groot</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-info">Open</span></td>
          <td class="sq-cell--num">€ 18K</td>
          <td class="sq-cell--date">28 Feb 2026</td>
          <td class="sq-col-actions">
            <div class="sq-rowactions">
              <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
                <i class="bi bi-pencil" aria-hidden="true"></i>
              </button>
            </div>
          </td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select TechBuild" />
          </td>
          <td>TechBuild</td>
          <td>Pieter Janssens</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-warning">In review</span></td>
          <td class="sq-cell--num">€ 124K</td>
          <td class="sq-cell--date">19 Feb 2026</td>
          <td class="sq-col-actions">
            <div class="sq-rowactions">
              <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
                <i class="bi bi-pencil" aria-hidden="true"></i>
              </button>
            </div>
          </td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Delta IT" />
          </td>
          <td>Delta IT</td>
          <td>Koen Vermeer</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-success">Done</span></td>
          <td class="sq-cell--num">€ 45K</td>
          <td class="sq-cell--date">10 Feb 2026</td>
          <td class="sq-col-actions">
            <div class="sq-rowactions">
              <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
                <i class="bi bi-pencil" aria-hidden="true"></i>
              </button>
            </div>
          </td>
        </tr>
        <tr class="sq-row--clickable sq-row--selected">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" checked aria-label="Select Hoofstad Finance" />
          </td>
          <td>Hoofstad Finance</td>
          <td>Sara Jansen</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-accent-teal">Active</span></td>
          <td class="sq-cell--num">€ 92K</td>
          <td class="sq-cell--date">5 Feb 2026</td>
          <td class="sq-col-actions">
            <div class="sq-rowactions">
              <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
                <i class="bi bi-pencil" aria-hidden="true"></i>
              </button>
            </div>
          </td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Bakker &amp; Zn" />
          </td>
          <td>Bakker &amp; Zn</td>
          <td class="sq-cell--muted">—</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-warning">In review</span></td>
          <td class="sq-cell--num">€ 9K</td>
          <td class="sq-cell--date">1 Feb 2026</td>
          <td class="sq-col-actions">
            <div class="sq-rowactions">
              <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
                <i class="bi bi-pencil" aria-hidden="true"></i>
              </button>
            </div>
          </td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Noordzee Retail" />
          </td>
          <td>Noordzee Retail</td>
          <td>Marieke de Groot</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-info">Open</span></td>
          <td class="sq-cell--num">€ 64K</td>
          <td class="sq-cell--date">28 Jan 2026</td>
          <td class="sq-col-actions">
            <div class="sq-rowactions">
              <button type="button" class="btn btn-ghost btn-sm" aria-label="Edit">
                <i class="bi bi-pencil" aria-hidden="true"></i>
              </button>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

```html
<div class="overflow-hidden">
  <table class="table mb-0">
    <thead>
      <tr>
        <th class="sq-checkcell" scope="col">
          <input
            class="form-check-input"
            type="checkbox"
            aria-label="Select all"
          />
        </th>
        <th class="sortable" scope="col">
          Account<i class="bi bi-chevron-expand" aria-hidden="true"></i>
        </th>
        <th class="sortable sq-cell--num" scope="col">
          Value<i class="bi bi-chevron-expand" aria-hidden="true"></i>
        </th>
        <th class="sq-col-actions" scope="col">
          <span class="visually-hidden">Actions</span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr class="sq-row--clickable">
        <td class="sq-checkcell">
          <input
            class="form-check-input"
            type="checkbox"
            aria-label="Select Van den Berg Logistics"
          />
        </td>
        <td>Van den Berg Logistics</td>
        <td class="sq-cell--num">€ 18K</td>
        <td class="sq-col-actions">
          <div class="sq-rowactions">
            <button
              type="button"
              class="btn btn-ghost btn-sm"
              aria-label="Edit"
            >
              <i class="bi bi-pencil" aria-hidden="true"></i>
            </button>
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>
```

## Sticky header

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--sqrl"><img src="/assets/sqrl.svg" width="14" height="14" alt="" aria-hidden="true" /> Sqrl custom</span></p>

Use Bootstrap **`overflow-auto`** on the scroll container, add Sqrl **`sq-table-sticky-head`**, and set **`max-height`** (inline or in layout CSS) so the body scrolls while the header stays visible. The preview uses a wide table so you can scroll horizontally as well.

<div class="sq-preview">
  <div
    class="overflow-auto sq-table-sticky-head mb-0"
    style="max-height: 16rem"
  >
    <table class="table mb-0" style="min-width: 56rem">
      <thead>
        <tr>
          <th class="sq-checkcell" scope="col">
            <input class="form-check-input" type="checkbox" aria-label="Select all" />
          </th>
          <th class="sortable" scope="col">
            Account<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col">
            Owner<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col">
            Status<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable sq-cell--num" scope="col">
            Value<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable sq-cell--date" scope="col">
            Last activity<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col">
            Region<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col">
            Industry<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
          <th class="sortable" scope="col" style="min-width: 14rem">
            Notes<i class="bi bi-chevron-expand" aria-hidden="true"></i>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Van den Berg Logistics" />
          </td>
          <td>Van den Berg Logistics</td>
          <td>Marieke de Groot</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-info">Open</span></td>
          <td class="sq-cell--num">€ 18K</td>
          <td class="sq-cell--date">28 Feb 2026</td>
          <td>West</td>
          <td>Logistics</td>
          <td>Renewal discussion in Q2</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select TechBuild" />
          </td>
          <td>TechBuild</td>
          <td>Pieter Janssens</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-warning">In review</span></td>
          <td class="sq-cell--num">€ 124K</td>
          <td class="sq-cell--date">19 Feb 2026</td>
          <td>North</td>
          <td>Construction</td>
          <td>Multi-site rollout pending sign-off</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Delta IT" />
          </td>
          <td>Delta IT</td>
          <td>Koen Vermeer</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-success">Done</span></td>
          <td class="sq-cell--num">€ 45K</td>
          <td class="sq-cell--date">10 Feb 2026</td>
          <td>East</td>
          <td>Software</td>
          <td>Onboarding complete</td>
        </tr>
        <tr class="sq-row--clickable sq-row--selected">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" checked aria-label="Select Hoofstad Finance" />
          </td>
          <td>Hoofstad Finance</td>
          <td>Sara Jansen</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-accent-teal">Active</span></td>
          <td class="sq-cell--num">€ 92K</td>
          <td class="sq-cell--date">5 Feb 2026</td>
          <td>Central</td>
          <td>Finance</td>
          <td>Security review scheduled</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Bakker &amp; Zn" />
          </td>
          <td>Bakker &amp; Zn</td>
          <td class="sq-cell--muted">—</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-warning">In review</span></td>
          <td class="sq-cell--num">€ 9K</td>
          <td class="sq-cell--date">1 Feb 2026</td>
          <td>South</td>
          <td>Retail</td>
          <td>Waiting on owner assignment</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Noordzee Retail" />
          </td>
          <td>Noordzee Retail</td>
          <td>Marieke de Groot</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-info">Open</span></td>
          <td class="sq-cell--num">€ 64K</td>
          <td class="sq-cell--date">28 Jan 2026</td>
          <td>West</td>
          <td>Retail</td>
          <td>Seasonal campaign follow-up</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Greenfield Energy" />
          </td>
          <td>Greenfield Energy</td>
          <td>Lars de Vries</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-info">Open</span></td>
          <td class="sq-cell--num">€ 210K</td>
          <td class="sq-cell--date">22 Jan 2026</td>
          <td>North</td>
          <td>Energy</td>
          <td>Enterprise tier evaluation</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Studio Oranje" />
          </td>
          <td>Studio Oranje</td>
          <td>Emma Bakker</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-warning">In review</span></td>
          <td class="sq-cell--num">€ 31K</td>
          <td class="sq-cell--date">15 Jan 2026</td>
          <td>Central</td>
          <td>Creative</td>
          <td>Design partner intro call done</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Haven Services" />
          </td>
          <td>Haven Services</td>
          <td>Tom van Dijk</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-success">Done</span></td>
          <td class="sq-cell--num">€ 78K</td>
          <td class="sq-cell--date">8 Jan 2026</td>
          <td>West</td>
          <td>Maritime</td>
          <td>Annual contract signed</td>
        </tr>
        <tr class="sq-row--clickable">
          <td class="sq-checkcell">
            <input class="form-check-input" type="checkbox" aria-label="Select Polder Agri" />
          </td>
          <td>Polder Agri</td>
          <td>Pieter Janssens</td>
          <td><span class="badge badge-borderless badge-dotted text-bg-info">Open</span></td>
          <td class="sq-cell--num">€ 52K</td>
          <td class="sq-cell--date">3 Jan 2026</td>
          <td>East</td>
          <td>Agriculture</td>
          <td>Demo requested for field teams</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

```html
<div
  class="overflow-auto sq-table-sticky-head"
  style="max-height: 16rem"
>
  <table class="table mb-0" style="min-width: 56rem">
    <thead>
      <tr>
        <th class="sq-checkcell" scope="col">…</th>
        <th class="sortable" scope="col">Account</th>
        <!-- extra columns → horizontal scroll -->
      </tr>
    </thead>
    <tbody>
      <tr>
        <td class="sq-checkcell">…</td>
        <td>Van den Berg Logistics</td>
        <!-- … -->
      </tr>
    </tbody>
  </table>
</div>
```

## Toolbar

Optional row above the wrap: search, filters, primary action — often same panel with **`border-bottom`** before the table. **Table ↔ cards** (same records) uses [segmented](/components/segmented); All / Mine / Active uses [pill tabs](/components/navigation#pill-tabs) — [Choose a control](/components/navigation#choose-a-control).

## Rules

### When to use

- Tabular **list screens** (contacts, tasks, etc.) with sortable columns and row actions.
- Empty list → [empty state](/components/feedback); loading → [skeleton placeholders](/components/feedback#skeleton).

### Structure

- List page stack (inside the scrolling content area — [Layout](/design/layout#content-area)): **`card-bordered`** with **toolbar** + **`table.table`** → **[pagination](/components/pagination)** on **`surface-page` below the card** (not **`card-footer`**).
- Always **`table.table`**. Do not add Bootstrap **`table-striped`** / **`table-hover`** (built into theme).

### Cells and columns

- Default text cells ellipsis; badges, checkbox, actions excluded. **`sq-cell--wrap`** when wrapping is required.
- Sortable **`th`**: include **`bi-chevron-expand`** (see Sticky header / examples).
- Row edit: **`btn-ghost btn-sm`** + pencil in **`sq-rowactions`**. Status: [badges](/components/badge), not table helper classes.


---

<!-- Source: components/tooltip.md -->

# Tooltip

<p class="sq-source-tags"><span class="sq-source-tag sq-source-tag--bootstrap"><img src="/assets/bootstrap.png" width="14" height="14" alt="" aria-hidden="true" /> Bootstrap</span></p>

Bootstrap tooltip via **`data-bs-toggle="tooltip"`** and **`data-bs-title`**. Examples below; **usage** → [Rules](#rules).

Docs init tooltips in `bootstrap-overlays.js` after navigation.

<div class="sq-preview">
  <div class="d-flex gap-2">
    <button type="button" class="btn btn-primary btn-sm" data-bs-toggle="tooltip" data-bs-title="More information">
      Hover me
    </button>
    <button type="button" class="btn btn-ghost btn-sm" aria-label="More actions" data-bs-toggle="tooltip" data-bs-title="More actions">
      <i class="bi bi-three-dots"></i>
    </button>
  </div>
</div>

```html
<button
  type="button"
  class="btn btn-primary btn-sm"
  data-bs-toggle="tooltip"
  data-bs-title="More information"
>
  Hover me
</button>
<button
  type="button"
  class="btn btn-ghost btn-sm"
  aria-label="More actions"
  data-bs-toggle="tooltip"
  data-bs-title="More actions"
>
  <i class="bi bi-three-dots"></i>
</button>
```

## Rules

### When to use

- Short label for **icon-only** controls ( **`aria-label`** on the control + matching tooltip is fine) — [Iconography](/design/iconography).
- Do not hide essential copy in a tooltip.
### Content

A few words only. Longer than one line → [Popover](/components/popover).
