Conventions
CSS architecture
File structure
All CSS lives in assets/css/. The entry point is main.css: it contains no rules, only a list of @import statements in load order. Adding a new file requires adding it to main.css and to the resources.Concat call in layouts/_default/baseof.html.
├── main.css # entry point: imports only, no rules
├── tokens.css # all custom properties (:root)
├── base.css # reset, typography, global elements
├── components/ # one file per BEM block
│ ├── docs.css
│ ├── buttons.css
│ ├── hero.css
│ └── … (24 more)
└── responsive.css # ALL @media queries, grouped by breakpoint
Key rules:
tokens.cssis the only file allowed to define custom propertiesresponsive.cssis the only file allowed to contain@mediaqueries- Each file in
components/covers one BEM block; no cross-block rules main.csscontains no rules: only imports in layer order
responsive.css means one place to check, one place to add breakpoints, and one obvious location to spot mobile regressions.Hugo Pipes bundle
All CSS is concatenated and fingerprinted in baseof.html:
{{ $css := slice
"css/tokens.css"
"css/base.css"
"css/components/buttons.css"
...
"css/responsive.css"
| resources.Concat "css/main.css"
| minify | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}"
integrity="{{ $css.Data.Integrity }}">
Adding a new CSS file:
- Create
assets/css/components/your-block.css - Add it to the
sliceinbaseof.htmlin the correct position (beforeresponsive.css) - The file is not auto-discovered — it will be silently ignored if omitted from the slice
BEM naming
.block { }
.block__element { }
.block--modifier { }
.block__element--modifier { }
- Block = one CSS file (e.g.
docs.css→.docs,.docs__sidebar,.docs__content) - Element separator:
__(double underscore) - Modifier separator:
--(double dash) - No nesting in CSS (even with SCSS-style nesting); flat selectors only
- JavaScript hooks:
js-prefix on classes used only in JS; never stylejs-classes
Specificity rules
- Match the existing selector depth for the context you’re working in
- Use deep descendant chains when you need to win a specificity battle; the chain should reflect real DOM ancestry
- Never pad specificity with fake
:not(.x)selectors or repeated class names - Never use
!important; if you feel you need it, the problem is architecture, not specificity
Tokens only: no raw values
No raw px, em, rem, or hex color values in component files. All values come from tokens.css. If a needed value has no token, add the token first.
The only exceptions: border-radius values (0.25rem, 0.375rem, 0.5rem) and stroke-width on SVGs; these are structural and don’t benefit from tokenization.
JS conventions
File locations
| Location | Purpose | Loaded by |
|---|---|---|
assets/js/global.js | Site-wide: nav toggle, dropdowns, banner icons, model nav persistence | baseof.html via Hugo Pipes, defer |
assets/js/<name>.js | Page-specific behavior | Template’s {{ define "scripts" }} block |
static/js/cookie-consent.js | Cookie consent (hand-managed, specific load timing) | baseof.html directly; not Hugo Pipes |
Hugo Pipes loading (page-specific)
{{ define "scripts" }}
{{ $js := resources.Get "js/docs-sidebar.js" | minify | fingerprint }}
<script src="{{ $js.RelPermalink }}"
integrity="{{ $js.Data.Integrity }}" defer></script>
{{ end }}
Shared scripts used by multiple templates (e.g. docs-sidebar.js) live in their own file and are included by each template that needs them; not duplicated.
Style rules
- No bundler, no transpiler, no framework: plain ES5-compatible JS
- Each file wraps its body in
document.addEventListener('DOMContentLoaded', …)for safety (even thoughdefermakes it nearly redundant) - No
import/export; each file is self-contained - No jQuery; native DOM APIs only
External links
Links to external sites use target="_blank" rel="noopener noreferrer" and an inline SVG icon with class .external-link-icon. This pattern should be applied consistently in templates; not in content markdown.
<a href="https://example.com"
target="_blank"
rel="noopener noreferrer">
Link text
<svg class="external-link-icon" …>…</svg>
</a>
rel="noopener noreferrer" is required for all target="_blank" links: noopener prevents the opened page from accessing window.opener; noreferrer additionally suppresses the Referer header for privacy.
Content authoring conventions
Markdown in content files
- Use
**bold**for UI labels, field names, and key terms; not for general emphasis - Use
_italic_for genuine emphasis or book/article titles - Use backtick code spans for: file paths, class names, token names, terminal commands, and any literal string a reader would type or copy
- Shortcodes for reusable content blocks (sponsor rows, agenda tables); never duplicate the HTML in markdown directly
- Raw HTML in markdown is allowed (
unsafe = truein config) but use sparingly and document why
Frontmatter conventions
Every content file needs:
---
title: "Page title"
description: "One sentence, no period, for meta tags and card excerpts."
layout: "single" # or section-specific layout
type: "page" # or section type (internal, samm-identity, etc.)
---
Internal pages additionally require:
sitemap:
disable: true
robots: "noindex, nofollow"