# Bulma Admin & Architecture Guide

This guide is the deep reference for engineers, architects, and design-system maintainers who integrate, customize, build, or extend **Bulma `v1.0.4`** — the modern, CSS-only framework by Jeremy Thomas (`jgthms`). It documents the Sass module architecture, the CSS custom-property engine that powers theming, the complete customization surface, the build pipeline, security posture, and the internals needed to reproduce or fork the project.

---

## 1. Executive Summary

Bulma is a **pure CSS framework**. Its sole runtime artifact is one stylesheet (`css/bulma.css` and its minified twin `css/bulma.min.css`). It ships **zero JavaScript** and has **no runtime dependencies** — the published npm package contains only Sass source, compiled CSS, the license, and the README.

Three architectural decisions define the project:

1. **CSS custom properties as the configuration layer.** Bulma 1.0 registers hundreds of `--bulma-*` variables at `:root` and on component selectors, then builds every rule from them. This is what enables runtime theming, dark mode, and per-subtree overrides without recompiling Sass.
2. **HSL-based, accessibility-aware color generation.** Each base color is decomposed into hue/saturation/lightness variables; Sass functions derive 20 numbered shades plus light/dark/soft/bold/invert variants, automatically selecting WCAG-contrasting text/background pairings.
3. **Modern Dart Sass modules.** The codebase uses `@use`/`@forward` exclusively (no `@import`), organized into clear layers: utilities → themes → base → elements → form → components → grid → layout → helpers.

| Attribute | Value |
|-----------|-------|
| Version | `1.0.4` |
| License | MIT (© Jeremy Thomas) |
| Language | Sass (Dart Sass), compiled to CSS |
| Runtime dependencies | None |
| JavaScript | None |
| Entry (Sass) | `bulma.scss` → `@use "sass"` |
| Compiled output | `css/bulma.css` (~785 KB), `css/bulma.min.css` (~678 KB) |
| Layout engines | Flexbox (`columns`), CSS Grid (`grid`/`cell`) |
| Theming | Light + dark via `prefers-color-scheme`, `[data-theme]`, `.theme-*` |
| Browser targets | Recent Chrome, Edge, Firefox, Opera, Safari; IE 10+ partial |

---

## 2. Architecture

### 2.1 Module graph

The compiled stylesheet is produced from a single root entry point that pulls in one aggregator:

```scss
// bulma.scss
@charset "utf-8";
/*! bulma.io v1.0.4 | MIT License | github.com/jgthms/bulma */
@use "sass";
```

`sass/_index.scss` forwards the layers in a deliberate cascade order:

```scss
@forward "utilities";   // variables, functions, controls (no output on their own)
@forward "themes";      // registers --bulma-* variables (light default + dark + setup)
@forward "base";        // minireset, generic element styles, keyframes
@forward "elements";    // button, tag, title, box, table, …
@forward "form";        // input, select, file, field, control, …
@forward "components";  // navbar, card, modal, dropdown, menu, …
@forward "grid";        // columns + smart grid
@forward "layout";      // container, hero, level, media, section, footer
@forward "base/skeleton";
@forward "helpers";      // utility classes (loaded last so !important wins)
```

> [!NOTE]
> Order matters. `utilities` and `themes` must come first because every later module reads the `--bulma-*` variables they define. `helpers` come last so their `!important` utility rules reliably override component defaults.

```
bulma.scss
└── sass/_index.scss
    ├── utilities/  initial-variables, functions, derived-variables, controls,
    │               css-variables, mixins, extends   (the engine — mostly no CSS output)
    ├── themes/      light.scss, dark.scss, setup.scss  (register --bulma-* values)
    ├── base/        minireset.scss, generic.scss, animations.scss, skeleton.scss
    ├── elements/    block, box, button, content, delete, icon, image, loader,
    │               notification, progress, table, tag, title
    ├── form/        shared, input-textarea, checkbox-radio, select, file, tools
    ├── components/  breadcrumb, card, dropdown, menu, message, modal, navbar,
    │               pagination, panel, tabs
    ├── grid/        columns.scss, grid.scss
    ├── layout/      container, footer, hero, level, media, section
    └── helpers/     aspect-ratio, border, color, flexbox, float, gap, overflow,
                    position, spacing, typography, visibility, other
```

### 2.2 The CSS custom-property engine (`utilities/css-variables.scss`)

This file is the heart of Bulma 1.0. It defines the helper API that every other file uses to register and read variables:

| Sass API | Purpose |
|----------|---------|
| `buildVarName($name, $prefix, $suffix)` | Builds `--bulma-<prefix><name><suffix>` |
| `getVar($name, $prefix, $suffix)` | Returns `var(--bulma-…)` for use in a property |
| `getVarWithBackup($name, $backup, …)` | `var(--a, var(--b))` fallback chain |
| `register-var($name, $value, …)` | Emits one custom property declaration |
| `register-vars($map, …)` | Emits a whole map of declarations |
| `register-hsl($name, $color)` | Splits a color into `-h`, `-s`, `-l` variables |
| `register-rgb($name, $color)` | Emits an `-rgb` channel triple |
| `generate-color-palette(...)` | Produces 20 shades + invert/light/dark/soft/bold for a color |
| `generate-on-scheme-colors(...)` | Computes an accessible "on scheme" lightness for a color |
| `bulma-theme($name)` / `system-theme($name)` | Wraps content in `[data-theme]`/`.theme-*` or a `prefers-color-scheme` query |

Components never hard-code colors. Instead each component file:

1. Declares Sass `$variables` with sensible defaults (overridable via `@use … with`).
2. Calls `register-vars(...)` on its own selector to publish those as `--bulma-<component>-*` custom properties.
3. Builds its rules with `getVar(...)`, so the same compiled CSS can be re-themed at runtime.

A representative excerpt (the box element):

```scss
$box-background-color: cv.getVar("scheme-main") !default;
$box-radius: cv.getVar("radius-large") !default;

.box {
  @include cv.register-vars((
    "box-background-color": #{$box-background-color},
    "box-radius": #{$box-radius},
  ));
  background-color: cv.getVar("box-background-color");
  border-radius: cv.getVar("box-radius");
}
```

### 2.3 Color system

Colors live as **HSL component variables**, not opaque hex values. For each color `name`, Bulma registers `--bulma-<name>-h`, `-s`, `-l` and then `generate-color-palette()` derives:

- 20 numbered lightness shades: `--bulma-<name>-00-l` through `--bulma-<name>-100-l` (steps of 5), each with a matching `--bulma-<name>-<digit>` color and an `-invert-l`.
- Semantic variants: `-invert`, `-light`, `-dark`, `-soft`, `-bold`, plus their inverts.
- `-on-scheme-l`: a lightness adjusted (via a luminance contrast loop, target ratio > 5) to remain readable on the current scheme background.

The contrast machinery uses `bulmaColorLuminance()` (WCAG relative luminance) and `bulmaColorBrightness()` in `utilities/functions.scss`. This is why a single `$primary: #6c5ce7` override cascades into dozens of accessible, theme-aware tints automatically.

### 2.4 Theming (`sass/themes/`)

| File | Role |
|------|------|
| `light.scss` | `light-theme` mixin: registers base hues, lightness scales, type/spacing/radius vars, and generates every color palette for a `100%` scheme-main lightness |
| `dark.scss` | `dark-theme` mixin: overrides only the lightness anchors (`scheme-main-l: 9%`, `background-l: 14%`, `text-l: 71%`, soft/bold swaps, larger hover deltas) and regenerates on-scheme colors |
| `setup.scss` | `setup-theme` mixin: computes derived semantic variables (`scheme-main`, `background`, `border`, `text`, `link`, `shadow`, `focus-*`, `code`, `pre`) from the anchors |

The themes index wires these to four targets:

```scss
:root { @include light.light-theme; @include setup.setup-theme; }            // default
@include cv.system-theme("light") { @include light.light-theme; }            // prefers-color-scheme: light
@include cv.system-theme("dark")  { @include dark.dark-theme; }              // prefers-color-scheme: dark
@include cv.bulma-theme("light")  { @include light.light-theme; @include setup.setup-theme; } // [data-theme=light], .theme-light
@include cv.bulma-theme("dark")   { @include dark.dark-theme;  @include setup.setup-theme; }  // [data-theme=dark],  .theme-dark
```

> [!IMPORTANT]
> A forced theme (`data-theme` / `.theme-*`) always re-runs `setup-theme`, so derived colors are recomputed for that subtree. Switching themes at runtime is therefore a single attribute change — no stylesheet swap required.

### 2.5 Base layer

- `minireset.scss` — a minimal reset (v0.0.6): zeroes margins/padding on block elements, normalizes box-sizing to `border-box`, strips list styles, collapses table borders.
- `generic.scss` — opinionated defaults for `html`, `body`, links, `code`, `pre`, `hr`, `strong`, tables, and focus-visible outlines, all sourced from `--bulma-*` variables.
- `animations.scss` — the `spinAround` and `pulsate` keyframes used by loaders and skeletons.

---

## 3. Requirements

| Concern | Requirement |
|---------|-------------|
| To use compiled CSS | Any modern browser; just link `css/bulma.min.css`. No tooling. |
| To customize via CSS variables | A browser supporting CSS custom properties (all current browsers). No build step. |
| To build from Sass | **Dart Sass** (`sass` npm package, tested against `^1.97`). Ruby Sass and Node Sass are **not** supported. |
| To minify | PostCSS + cssnano (the project uses `postcss-cli ^11`, `cssnano ^7`). |
| Node.js | Any current LTS for the npm scripts. |
| Browser support | Recent Chrome, Edge, Firefox, Opera, Safari; IE 10+ partial (Flexbox/Grid required). |

> [!WARNING]
> Compiling Bulma 1.0 with the deprecated `node-sass` or Ruby Sass engines will fail — the codebase relies on the Dart Sass module system (`@use`, `@forward`, `with`) and the modern `sass:color` / `sass:math` modules.

---

## 4. Customization Reference

There are two override surfaces: **Sass variables** (build time) and **CSS custom properties** (runtime).

### 4.1 Build-time: Sass `@use … with`

```scss
@use "bulma/sass" with (
  $primary: #6c5ce7,
  $link: #0a84ff,
  $family-primary: '"Nunito", sans-serif',
  $radius: 0.5rem,
  $control-border-width: 2px,
  $custom-colors: ("twitter": #1da1f2)
);
```

#### Initial variables (`utilities/initial-variables.scss`)

| Variable | Default | Notes |
|----------|---------|-------|
| `$scheme-h` / `$scheme-s` | `221` / `14%` | Base hue/saturation for greys & scheme |
| `$dark-l` / `$light-l` | `20%` / `90%` | Lightness anchors for soft/bold |
| `$black`…`$white` | HSL greys at `4%`→`100%` | Nine-step grey scale (`black`, `black-bis`, `black-ter`, `grey-darker`…`grey-lightest`, `white-ter`, `white-bis`, `white`) |
| `$orange` | `hsl(14,100%,53%)` | Palette color |
| `$yellow` | `hsl(42,100%,53%)` | |
| `$green` | `hsl(153,53%,53%)` | |
| `$turquoise` | `hsl(171,100%,41%)` | Default **primary** |
| `$cyan` | `hsl(198,100%,70%)` | Default **info** |
| `$blue` | `hsl(233,100%,63%)` | Default **link** |
| `$purple` | `hsl(271,100%,71%)` | |
| `$red` | `hsl(348,100%,70%)` | Default **danger** |
| `$family-sans-serif` | Inter-led stack | `"Inter","SF Pro","Segoe UI","Roboto",…` |
| `$family-monospace` | Inconsolata-led stack | `"Inconsolata","Hack","SF Mono",…` |
| `$size-1`…`$size-7` | `3rem,2.5rem,2rem,1.5rem,1.25rem,1rem,0.75rem` | Type scale |
| `$weight-light`…`$weight-extrabold` | `300,400,500,600,700,800` | Font weights |
| `$block-spacing` | `1.5rem` | Default gap below blocks |
| `$aspect-ratios` | 15 pairs | `(1,1),(4,3),(16,9),…` |
| `$gap` | `32px` | Container gutter & breakpoint offset |
| `$tablet` | `769px` | Breakpoint |
| `$desktop` | `960px + 2*$gap` = `1024px` | Breakpoint |
| `$widescreen` | `1152px + 2*$gap` = `1216px` | Breakpoint (`$widescreen-enabled`) |
| `$fullhd` | `1344px + 2*$gap` = `1408px` | Breakpoint (`$fullhd-enabled`) |
| `$duration` | `294ms` | Transition duration |
| `$easing` | `ease-out` | |
| `$radius-small`…`$radius-rounded` | `0.25rem,0.375rem,0.5em,0.75rem,9999px` | Corner radii |
| `$speed` | `86ms` | |
| `$variable-columns` | `true` | Enable variable column gaps |
| `$rtl` | `false` | Right-to-left flag (partial support) |
| `$class-prefix` | `""` | Prefix prepended to every class |
| `$cssvars-prefix` | `"bulma-"` | Prefix on every custom property |
| `$helpers-prefix` / `$helpers-has-prefix` | `"is-"` / `"has-"` | Helper class prefixes |
| `$variables-host` | `":root"` | Selector that hosts global variables |

#### Derived variables (`utilities/derived-variables.scss`)

Map raw palette colors to semantic roles, all overridable:

| Variable | Default source |
|----------|----------------|
| `$primary` | `$turquoise` |
| `$link` | `$blue` |
| `$info` | `$cyan` |
| `$success` | `$green` |
| `$warning` | `$yellow` |
| `$danger` | `$red` |
| `$light` / `$dark` | `$white-ter` / `$grey-darker` |
| `$text` / `$text-strong` / `$text-weak` | `$grey-dark` / `$grey-darker` / `$grey` |
| `$background` / `$border` / `$border-weak` | `$white-ter` / `$grey-lighter` / `$grey-lightest` |
| `$family-primary` / `$family-secondary` / `$family-code` | sans / sans / monospace |
| `$size-small`…`$size-large` | `$size-7,$size-6,$size-5,$size-4` |
| `$colors` (map) | `white,black,light,dark,text,primary,link,info,success,warning,danger` |
| `$shades` (map) | the nine grey steps |
| `$custom-colors` / `$custom-shades` | `null` (your extension points) |

> [!TIP]
> To add a brand color that flows into every `is-`/`has-` class, pass `$custom-colors: ("brand": #ff3860)`. `mergeColorMaps()` accepts either a single color (Bulma derives invert/light/dark) or a list `(base, invert, light, dark)` for full control.

### 4.2 Runtime: CSS custom properties

Every value above is also published as `--bulma-*` and can be overridden in plain CSS at any scope:

```css
:root {
  --bulma-primary-h: 270deg;
  --bulma-primary-s: 100%;
  --bulma-primary-l: 60%;
  --bulma-radius: 1rem;
  --bulma-link-h: 210deg;
}

/* Scoped override — only this subtree */
.promo {
  --bulma-body-background-color: #111;
}
```

Per-component variables follow the pattern `--bulma-<component>-<property>` (e.g. `--bulma-button-padding-horizontal`, `--bulma-card-radius`, `--bulma-navbar-height`). Component files register dozens each; inspect the relevant `sass/**/<name>.scss` `register-vars` block for the exhaustive list.

---

## 5. Build & Deployment Pipeline

All build logic lives in `package.json` scripts (the framework `package.json`, not the docs one):

| Script | Command | Purpose |
|--------|---------|---------|
| `build-bulma` | `sass --style=expanded --source-map bulma.scss css/bulma.css` | Compile the main stylesheet |
| `minify-bulma` | `postcss css/bulma.css --no-map --use cssnano --output css/bulma.min.css` | Minify |
| `version-no-dark-mode` | `sass … versions/bulma-no-dark-mode.scss …` | Compile the light-only variant |
| `version-no-helpers` | `sass … versions/bulma-no-helpers.scss …` | Compile without helpers |
| `version-no-helpers-prefixed` | `sass … versions/bulma-no-helpers-prefixed.scss …` | No helpers + class prefix |
| `version-prefixed` | `sass … versions/bulma-prefixed.scss …` | Class-prefixed variant |
| `build-versions` | runs all four `version-*` | Build every variant |
| `minify-versions` | `postcss css/versions/*.css … --use cssnano` | Minify all variants |
| `build-all` / `minify-all` | chains build + versions / minify + versions | Full build |
| `clean` | `rimraf css` | Remove generated CSS |
| `deploy` | `clean && build-all && minify-all` | Full reproducible build |
| `start` | `build-bulma -- --watch` | Watch mode for development |
| `test` | `sass --style=expanded --source-map --watch test.scss test.css` | Compile the Sass test fixture |

### 5.1 Prebuilt variants (`versions/`)

| File | Definition | When to ship it |
|------|-----------|-----------------|
| `bulma-prefixed.scss` | `@use "../sass" with ($class-prefix: "bulma-")` | Embedding Bulma alongside another framework — all classes become `.bulma-button`, etc. |
| `bulma-no-dark-mode.scss` | Forwards all modules but only the `light` theme | Apps that never use dark mode (smaller output) |
| `bulma-no-helpers.scss` | Forwards all modules except `helpers` | Trim the large helper surface |
| `bulma-no-helpers-prefixed.scss` | No helpers + prefix | Combination of the above |

> [!NOTE]
> The CSS-variable prefix (`--bulma-`) is fixed by `$cssvars-prefix` and is independent of `$class-prefix`. Prefixing classes does not rename the custom properties.

### 5.2 Reproducing the published artifacts

```bash
git clone https://github.com/jgthms/bulma
cd bulma
npm install          # installs Dart Sass, postcss-cli, cssnano, prettier, rimraf
npm run deploy       # clean → build-all → minify-all  ⇒ css/ + css/versions/
```

The `files` array in `package.json` defines what npm publishes: `css`, `sass`, `versions`, `bulma.scss`, `LICENSE`, `README.md`. Nothing else (no docs site, no tests) ships to consumers.

---

## 6. Security Analysis

Bulma's attack surface is exceptionally small because it is a static stylesheet.

| Vector | Assessment |
|--------|------------|
| JavaScript execution | **None.** No JS is shipped, so there is no script-injection or prototype-pollution surface from Bulma itself. |
| Runtime dependencies | **None.** The published package has zero `dependencies`; supply-chain exposure is limited to build-time devDependencies (`sass`, `postcss-cli`, `cssnano`, `prettier`, `rimraf`). |
| CSS injection | If you interpolate untrusted values into Bulma class names or into `--bulma-*` variable overrides, standard CSS-injection caution applies — never build class strings or inline `style` custom properties from unsanitized user input. |
| Content sourcing | Loading from a CDN introduces a third-party trust boundary; pin a version and add Subresource Integrity (SRI) if your threat model requires it. |
| Clickjacking / overlay | Components like `modal-background` and `is-overlay` create full-viewport layers; ensure your own JS enforces focus trapping and dismissal — Bulma only provides the styling. |

> [!CAUTION]
> Interactive components are styled, not behaviorally secured. Accessibility and security of modals, dropdowns, and menus (focus management, `aria-*`, escape handling, dismissal) are the integrator's responsibility because Bulma ships no JavaScript.

---

## 7. Operations

### 7.1 Integration patterns

- **Static / CDN:** link `bulma.min.css`. Zero build. Best for content sites.
- **Bundler (Vite/webpack/Rollup):** `import "bulma/css/bulma.min.css"` or import the Sass entry for customization.
- **Component frameworks (React/Vue/Svelte):** Bulma is class-only, so it composes cleanly. Toggle `is-active` etc. via your framework's state.
- **Design system:** compile from `sass/` with `@use … with (...)`, forwarding only the modules you use to control bundle size.

### 7.2 Reducing stylesheet size

Because Bulma 1.0 emits a comprehensive variable and helper surface, the compiled CSS is large (~678 KB minified). Strategies:

- [ ] Build from Sass and `@forward` only the modules you actually use (e.g. drop `grid` or `helpers`).
- [ ] Use the `bulma-no-helpers` prebuilt variant.
- [ ] Enable gzip/brotli on your server — the variable-heavy CSS compresses very well.
- [ ] Run a CSS tree-shaker (e.g. PurgeCSS) against your final markup as a build step.

### 7.3 Theming operations

- Default theme follows `prefers-color-scheme`.
- Force a theme by setting `data-theme="dark"` (or `theme-dark` class) on `<html>` or any subtree.
- Persist a user choice in `localStorage` and apply it on load: `document.documentElement.dataset.theme = saved`.

---

## 8. Code Quality & Conventions

- **Single source of truth per value.** Defaults are declared once as Sass `!default` variables, published once via `register-vars`, and consumed via `getVar`. Changing a default ripples everywhere consistently.
- **Strict module boundaries.** Files declare their dependencies explicitly with `@use` aliases (`cv` = css-variables, `iv` = initial-variables, `dv` = derived-variables, `mx` = mixins). No global leakage.
- **Logical properties throughout.** `margin-inline`, `inset-inline`, `border-start-*-radius`, etc., give partial RTL support and better internationalization than physical `left`/`right`.
- **Placeholders + mixins for shared behavior** (`%control`, `%block`, `%unselectable`, `%overlay`, `%loader`, `%arrow`, `%delete`) keep the output DRY via `@extend`.
- **Responsive mixins** (`mobile`, `tablet`, `desktop`, `widescreen`, `fullhd`, `touch`, `*-only`, plus container-query helpers `container-from`/`container-until`) centralize breakpoint logic.
- **Formatting** is enforced with Prettier (the docs site also uses a Liquid plugin).
- **Legacy test fixtures** in `test/dart-sass`, `test/node-sass`, `test/ruby-sass` remain in the tree for historical compilation checks; only Dart Sass is supported in 1.0.

---

## 9. Potential Improvements & Known Issues

Drawn from the source and the project's open community issues.

| Item | Detail | Source |
|------|--------|--------|
| **`is-offset-one-third` offset bug** | Emits `margin-inline-start: 0.3333%` instead of `33.3333%` for `is-offset-one-third` and its `-mobile`/`-tablet`/`-touch`/`-desktop`/`-widescreen` variants. Only `-fullhd` is correct. Workaround: use `is-offset-4`. | Issue #4044; `sass/grid/columns.scss` |
| **`--bulma-block-spacing` can be undefined** | Some components read it where it is not globally registered, collapsing block spacing. Mitigate by defining it on `:root`. | Issue #4037 |
| **Bundle size** | Comprehensive CSS-variable + helper surface makes even minified output large (~678 KB). A documented "lite" build or first-class tree-shaking guidance would help. | Issue #3761 |
| **Menu component RTL** | The `menu` component does not fully support right-to-left layouts. | Issue #4029 |
| **No `error` color** | No dedicated `is-error` semantic color (community request; `is-danger` is the current equivalent). | Issue #4027 |
| **`antialiased` smoothing** | `generic.scss` sets `-webkit-font-smoothing: antialiased`, which some consider degrades rendering. | Issue #4040 |
| **Removed `tile` component** | The `tile` layout was removed in 1.0; older tutorials referencing it no longer apply. Use the Smart Grid or columns. | `sass/` (no `tile.scss`); issue #4016 |
| **Release filename naming** | Community request to change the release archive filename convention. | Issue #4038 |

### Negative knowledge (what does NOT exist in `v1.0.4`)

- No JavaScript of any kind.
- No `.tile` / `tiles` component.
- No `is-error` color modifier.
- No support for Node Sass or Ruby Sass compilation.
- No runtime npm dependencies.

---

## 10. Contributing / Forking

The project is a single-package repository:

- **Framework source:** `sass/` (the product), `bulma.scss` (entry), `versions/` (prebuilt variants), `css/` (generated — do not edit by hand).
- **Documentation site:** `docs/` — a separate Jekyll (Ruby) site with its own `package.json`, plus a React-based "Bulma Customizer" under `docs/_react/bulma-customizer`. The docs build is independent of the framework build.

To work on the framework:

```bash
npm install
npm start            # watch-compile bulma.scss → css/bulma.css
```

To work on the docs site (per `docs/README.md`): install Ruby 2.x and Jekyll, copy `_config.yml` to `_config.local.yml`, point its `url:` at `http://localhost:4000`, then run `jekyll serve --incremental --config _config.local.yml`. A `docker-compose.yml` using the `jekyll/jekyll:pages` image is provided as an alternative. Note: changing the framework Sass requires `npm run start` to rebuild the docs' CSS; Jekyll then serves it.

> [!NOTE]
> Edits belong in `sass/` and `bulma.scss`. The contents of `css/` are build artifacts regenerated by `npm run deploy`; never patch them directly.

---

## 11. Quick Reference

### Build commands

```bash
npm run build-bulma     # compile main stylesheet
npm run minify-bulma    # minify with cssnano
npm run build-all       # main + all variants
npm run deploy          # clean + build-all + minify-all (full reproducible build)
npm start               # watch mode
```

### Customization cheat sheet

```scss
// Build-time
@use "bulma/sass" with (
  $primary: #6c5ce7,
  $radius: 0.5rem,
  $class-prefix: "bulma-",
  $custom-colors: ("brand": #ff3860)
);
```

```css
/* Runtime */
:root {
  --bulma-primary-h: 270deg;
  --bulma-radius: 1rem;
}
html[data-theme="dark"] { /* dark overrides applied automatically */ }
```

### Breakpoints

| Name | From | Until |
|------|------|-------|
| `mobile` | — | `768px` |
| `tablet` | `769px` | — |
| `tablet-only` | `769px` | `1023px` |
| `touch` | — | `1023px` |
| `desktop` | `1024px` | — |
| `desktop-only` | `1024px` | `1215px` |
| `widescreen` | `1216px` | — |
| `widescreen-only` | `1216px` | `1407px` |
| `fullhd` | `1408px` | — |

### Module layers (cascade order)

`utilities` → `themes` → `base` → `elements` → `form` → `components` → `grid` → `layout` → `skeleton` → `helpers`

### Key file map

| Path | Responsibility |
|------|----------------|
| `bulma.scss` | Root entry (`@use "sass"`) |
| `sass/_index.scss` | Layer aggregation order |
| `sass/utilities/initial-variables.scss` | Build-time Sass variables |
| `sass/utilities/derived-variables.scss` | Semantic color/type maps |
| `sass/utilities/css-variables.scss` | The `register-var`/`getVar` engine + palette generators |
| `sass/utilities/functions.scss` | Color/luminance/contrast math |
| `sass/utilities/mixins.scss` | Responsive + behavior mixins |
| `sass/themes/{light,dark,setup}.scss` | Theme variable registration |
| `sass/{elements,components,form,grid,layout,helpers}/` | The class library |
| `versions/*.scss` | Prebuilt distribution variants |

---

_Generated June 2026 from jgthms/bulma at 741da22. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
