Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions .claude/skills/slashed-build/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
name: slashed-build
description: >-
Use when building or styling a UI, website, page, or component with the
SLASHED CSS framework (the `--sf-*` token API and `.sf-*` classes) — writing
the HTML/CSS, choosing tokens over hardcoded values, laying out with
primitives, rebranding, or wiring dark mode. Routes to the framework's
authoritative, CI-gated docs; does not duplicate token or class lists.
---

# Building with SLASHED

SLASHED is a token-first, BEM-first CSS framework: the `--sf-*` design-token API
is the product, and you compose components on top of it. This skill is the
entry point — it teaches the mental model and the build workflow, then routes
you to the authoritative reference docs for the exhaustive lists. **Do not
memorise or reproduce token/class inventories from here; look them up in the
linked docs, which CI keeps in sync with the source.**

## When to use

Use this whenever the task involves writing or styling markup that should look
like SLASHED: new pages, components, layouts, rebrands, theming, or dark mode.
If the user's project loads a `slashed*.css` bundle or uses `--sf-*` / `.sf-*`
names, you are in scope.

## The five principles (in priority order)

1. **Never hardcode a visual value.** Every colour, space, radius, shadow,
font, z-index, and duration is a token. `padding: 24px` is a bug; write
`padding: var(--sf-space-m)`. Hardcoded numbers break consistency and dark
mode.
2. **BEM-first, classes where they count.** Base elements are styled classless.
Use `.sf-*` classes for layout primitives, macros, and states; build your
own BEM components on the token API for everything else.
3. **Prefer semantic tokens over primitive ones.** Reach for `var(--sf-gap)`
over `var(--sf-space-m)` in a grid — the semantic token lets one change
ripple everywhere without touching components.
4. **Dark mode is free — don't fight it.** Never write dark-mode colour CSS or
toggle CSS variables in JS. Set `data-theme` and let the framework recompute
the palette from the source tokens.
5. **Tweak by knob or `calc()`, never a new token.** For a one-off variation,
override an existing knob (`--sf-grid-gap: var(--sf-space-s)`) or compose
with `calc()`. Inventing `--my-*` tokens fragments the system and skips
dark-mode derivation.

> **Advanced escape hatch (not the default workflow):** because everything
> flows from tokens, global multipliers such as `--sf-radius-scale: 0` or
> `--sf-motion-scale: 0` can restyle an entire site in one line. Treat these as
> a deliberate power-user switch, hidden by default — do not introduce them
> into ordinary component work.

## Build workflow

1. **Load the framework.** Confirm a bundle is present (or add one). Optimal is
the default; the full bundle adds `.sf-btn` / `.sf-card` + utilities. See
[getting-started.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/getting-started.md).
2. **Lay out with primitives, not custom CSS.** Reach for `.sf-container`,
`.sf-stack`, `.sf-grid`, `.sf-cluster`, `.sf-sidebar`, `.sf-cover`, and
friends before writing flexbox/grid by hand. → [layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md)
3. **Style with macros + tokens.** Panels → `.sf-surface`; articles →
`.sf-prose`; spacing/typography → tokens. → [macros.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/macros.md)
4. **Wire state through `.sf-is-*` classes + ARIA**, toggled from JS — not
inline styles. → [states.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/states.md)
5. **Brand via the six source colours** in the overrides space; add
`data-theme` for forced modes. → [theming.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/theming.md)
6. **Verify token-first.** Before finishing, scan your CSS for hardcoded
colours/px/rem and replace them with tokens.

## Decision tree — "I want to…"

| Goal | Reach for | Reference |
| --- | --- | --- |
| Constrain / centre page content | `.sf-container`, `.sf-container--narrow`, `.sf-container--wide`, `.sf-container--prose` | [layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md) |
| Space stacked children | `.sf-stack` | [layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md) |
| Responsive card grid (no media queries) | `.sf-grid .sf-grid--fit` + `--sf-grid-min` | [layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md) |
| Row that wraps (buttons, tags) | `.sf-cluster` | [layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md) |
| Content + collapsing sidebar | `.sf-sidebar` | [layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md) |
| A padded, elevated panel | `.sf-surface` (any bundle) / `.sf-card` (full) | [macros.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/macros.md) |
| Rich article typography | `.sf-prose` | [macros.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/macros.md) |
| Buttons | `.sf-btn` + variant (full bundle) | [classes.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/classes.md) |
| Loading / selected / disabled state | `.sf-is-*` + matching ARIA | [states.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/states.md) |
| A specific spacing / colour / radius value | a `--sf-*` token | [llm-guide.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/llm-guide.md) · [tokens.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/tokens.md) |
| Rebrand the whole site | six `--sf-color-*-source-light` tokens | [theming.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/theming.md) |
| Dark mode | `data-theme="dark"` on `<html>` or a section | [theming.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/theming.md) |
| Look a name up programmatically | `api-index.json` / `token-index.json` | [docs/](https://github.com/codeslash-dev/SLASHED/tree/main/docs) |

## Reference map (authoritative, CI-gated)

Links point at GitHub so this skill works when copied into any project. Inside
the SLASHED repo itself, the same files live under `docs/` — read them locally.

- **[getting-started.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/getting-started.md)** — install, bundle
choice, boilerplate, first rebrand.
- **[cookbook.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/cookbook.md)** — copy-paste recipes for common
builds (page shell, card grid, hero, sidebar, form states, rebrand).
- **[llm-guide.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/llm-guide.md)** — the deep token reference:
colour/type/space/layout/motion systems, tiers, best practices.
- **[layout.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/layout.md)** / **[macros.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/macros.md)**
/ **[states.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/states.md)** — every layout primitive, macro,
and state class.
- **[theming.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/theming.md)** — rebrand, dark mode, multi-brand,
contrast.
- **[classes.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/classes.md)** / **[tokens.md](https://github.com/codeslash-dev/SLASHED/blob/main/docs/tokens.md)**
— the complete generated inventories.
- **`api-index.json`** / **`token-index.json`** — machine-readable indexes for
programmatic lookup.

## Guardrails

- Only reference `--sf-*` tokens and `.sf-*` classes that actually exist — check
the reference docs or the JSON indexes rather than guessing a name.
- Do not edit `INTERNAL` tokens (e.g. `--sf-is-dark`); they are framework-managed.
- Put your overrides in plain `:root` / your own selectors — the
`slashed.overrides` layer sits last, so you never need `!important`.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ Pre-built bundles ship with every [release](https://github.com/codeslash-dev/SLA

| Guide | What's inside |
| --- | --- |
| [Getting started](docs/getting-started.md) | install, bundle choice, boilerplate, first rebrand — start here |
| [Cookbook](docs/cookbook.md) | copy-paste recipes for common builds (page shell, card grid, hero, sidebar, states) |
| [Architecture](docs/architecture.md) | layers, file structure, class taxonomy, bundles, token contract, performance |
| [Theming](docs/theming.md) | rebrand in 6 tokens, dark mode, multi-brand, contrast |
| [Layout primitives](docs/layout.md) | every `.sf-*` layout class + tokens |
Expand All @@ -168,6 +170,10 @@ Pre-built bundles ship with every [release](https://github.com/codeslash-dev/SLA
| [LLM guide](docs/llm-guide.md) | compact API reference for AI-assisted development |
| [Migration](docs/migration.md) | upgrading SLASHED + migrating from other frameworks |

Building with an AI assistant? The **`slashed-build` skill**
(`.claude/skills/slashed-build/`) turns this documentation set into a guided
build workflow — mental model, decision tree, and routing into the docs above.

## Editor integration

A generated [VS Code CSS Custom Data](https://github.com/microsoft/vscode-css-languageservice/blob/main/docs/customData.md)
Expand Down
255 changes: 255 additions & 0 deletions docs/cookbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
# SLASHED Cookbook

Task-oriented recipes: *"I want to build X"* → the markup and the tokens that
get you there. Every recipe is copy-paste ready and works in light and dark
mode with no extra CSS. For the reasoning behind each choice, follow the links
into the [LLM guide](llm-guide.md).

These recipes lean on the **optimal** bundle. Recipes that use `.sf-btn` or
`.sf-card` note that they need the **full** bundle.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- [Page shell](#page-shell)
- [Vertical rhythm (stack)](#vertical-rhythm-stack)
- [Card grid](#card-grid)
- [Hero / landing section](#hero--landing-section)
- [Sidebar layout](#sidebar-layout)
- [Long-form article (prose)](#long-form-article-prose)
- [A surface / panel](#a-surface--panel)
- [Buttons and actions](#buttons-and-actions)
- [Interactive states](#interactive-states)
- [Rebrand + dark-mode toggle](#rebrand--dark-mode-toggle)
- [Local tweaks without new tokens](#local-tweaks-without-new-tokens)

---

## Page shell

Centre and constrain content with `.sf-container`; it caps line length and adds
responsive side padding.

```html
<header class="sf-container"> … </header>
<main class="sf-container"> … </main>
<footer class="sf-container"> … </footer>
```

Width variants: `.sf-container--narrow`, `.sf-container--wide`,
`.sf-container--full`, `.sf-container--prose` (ideal reading measure).

---

## Vertical rhythm (stack)

`.sf-stack` puts consistent space **between** children — never margins on the
children themselves.

```html
<div class="sf-stack">
<h2>Section title</h2>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</div>
```

Tune the gap per-instance with a size modifier (`.sf-stack--s` …
`.sf-stack--2xl`) or globally with the `--sf-stack-gap` knob. See
[layout.md](layout.md).

---

## Card grid

A responsive grid that fits as many columns as will fit — no media queries.

```html
<ul class="sf-grid sf-grid--fit">
<li class="sf-card">Card one</li>
<li class="sf-card">Card two</li>
<li class="sf-card">Card three</li>
</ul>
```

- `.sf-grid--fit` auto-fits columns based on `--sf-grid-min` (the minimum
column width). Set `--sf-grid-min` to change the breakpoint density.
- `.sf-card` needs the **full** bundle. On the optimal bundle, use
`.sf-surface` for the same panel look.
- Want a tighter grid? Set `--sf-grid-gap: var(--sf-space-s)` on the `<ul>`
instead of writing a new class.

---

## Hero / landing section

`.sf-cover` vertically centres a headline block within a minimum-height region;
`.sf-section` adds generous top/bottom padding.

*(The `.sf-btn` buttons below need the **full** bundle; the layout itself works
on optimal.)*

```html
<section class="sf-section sf-cover">
<div class="sf-container sf-stack">
<h1>Ship your design system, not a build step.</h1>
<p class="sf-text-l">One stylesheet. Six tokens to rebrand. Dark mode free.</p>
<div class="sf-cluster">
<a class="sf-btn sf-btn--primary" href="#">Get started</a>
<a class="sf-btn sf-btn--outline" href="#">Read the docs</a>
</div>
</div>
</section>
```

`.sf-cluster` lays out the buttons in a row that wraps gracefully on small
screens. Section padding scales with `--sf-section-pad`.

---

## Sidebar layout

A content area with a sidebar that collapses below a threshold — again, no
breakpoints.

```html
<div class="sf-sidebar">
<aside> … navigation … </aside>
<main> … content … </main>
</div>
```

`.sf-sidebar--right` flips the side; `.sf-sidebar--wide` /
`.sf-sidebar--narrow` change the sidebar's target width, tuned by
`--sf-sidebar-width`. The pair wraps to a single column automatically when the
main content can no longer fit alongside — no breakpoints. See
[layout.md](layout.md).

---

## Long-form article (prose)

`.sf-prose` styles a block of raw HTML (headings, lists, blockquotes, code)
into a readable article — the one place you *want* rich classless typography.

```html
<article class="sf-container--prose sf-prose">
<h1>Title</h1>
<p>Body copy with <a href="#">links</a>, <code>inline code</code>, lists…</p>
<blockquote>Pull quote.</blockquote>
</article>
```

Wrap anything you must exclude from prose styling in `.sf-not-prose`.

---

## A surface / panel

`.sf-surface` is the classless-friendly card look available in **every**
bundle: padded, rounded, elevated, theme-aware.

```html
<div class="sf-surface sf-stack">
<h3>Panel title</h3>
<p>Content on a raised surface.</p>
</div>
```

Semantic variants tint the surface: `.sf-surface--neutral`,
`.sf-surface--secondary`, `.sf-surface--success`, `.sf-surface--danger`,
`.sf-surface--info`, `.sf-surface--warning`, `.sf-surface--inverse`.

---

## Buttons and actions

*(Requires the **full** bundle.)*

```html
<button class="sf-btn sf-btn--primary">Primary</button>
<button class="sf-btn sf-btn--secondary">Secondary</button>
<button class="sf-btn sf-btn--outline">Outline</button>
<button class="sf-btn sf-btn--danger">Delete</button>
```

Sizes: `.sf-btn--xs` … `.sf-btn--xl`. Full-width: `.sf-btn--block`. Text
colour on coloured buttons uses the `--sf-color-text--on-*` auto-contrast
tokens, so it stays legible in both themes for free.

---

## Interactive states

State classes map to ARIA and drive visuals — toggle them from your JS instead
of editing inline styles. *(The `.sf-btn` / `.sf-card` examples need the
**full** bundle.)*

Pair each state class with the matching semantics: `aria-selected` needs a
`role="option"` inside a `role="listbox"` (a bare `<li>` does not support it),
and a disabled `<button>` needs the native `disabled` attribute — `aria-disabled`
only exposes the state, it does not block activation.

```html
<button class="sf-btn sf-btn--primary sf-is-loading" aria-busy="true">Saving…</button>

<ul role="listbox" aria-label="Choices">
<li role="option" class="sf-card sf-is-selected" aria-selected="true">Chosen</li>
</ul>

<button class="sf-btn sf-is-disabled" disabled>Unavailable</button>
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

The full catalogue and its ARIA mapping is in [states.md](states.md). Prefer a
shimmer placeholder while loading? Use `.sf-is-shimmer`.

---

## Rebrand + dark-mode toggle

```css
/* your overrides — no !important needed */
:root {
--sf-color-primary-source-light: #7048e8;
--sf-color-base-source-light: #f8f9fa;
}
```

```html
<button id="theme" type="button">Toggle theme</button>
<script>
const root = document.documentElement;
document.getElementById('theme').addEventListener('click', () => {
root.dataset.theme = root.dataset.theme === 'dark' ? 'light' : 'dark';
});
</script>
```

Toggle the **attribute**, never the CSS variables — the framework recomputes the
whole palette from `data-theme`. Add `class="sf-theme-transition"` on `<html>`
for a smooth cross-fade.

---

## Local tweaks without new tokens

When you need a one-off variation, compose with `calc()` or override an existing
knob — do **not** invent a new token.

```css
/* ✓ a roomier hero — compose from the existing token */
.hero { padding-block: calc(var(--sf-section-pad) * 1.5); }

/* ✓ a tighter grid — set the knob, don't write .sf-grid--tight */
.compact-grid { --sf-grid-gap: var(--sf-space-s); }
```

Why: new tokens fragment the system and skip dark-mode derivation. The full set
of anti-patterns is in [Best Practices](llm-guide.md#14-best-practices).

---

## More building blocks

This cookbook covers the common cases. The complete class inventory —
`.sf-switcher`, `.sf-reel`, `.sf-frame`, `.sf-bento`, `.sf-center`,
`.sf-imposter`, overflow-fade, scroll-snap, and the rest — is in
[layout.md](layout.md), [macros.md](macros.md), and the generated
[classes.md](classes.md).
Loading