Navigation2
Sections7

Section

The page building block. Full-bleed outer owns gutter + rhythm, inner wrapper owns the width. Props: eyebrow?, title?, sub?, level: 2 | 3,width: "site" | "wide" | "content" | "narrow" | "prose", align: "start" | "center",tone: "plain" | "raised" | "brand" | "inverse", space: "default" | "tight" | "none",id?, plus any <section> attribute. Slots: default, aside. Renders a <section> when a title is present, otherwise a <div>.

tone="plain" · eyebrow + title + sub

Eyebrow

A plain section

No background. Width defaults to site (--site-width, the header pill's column); rhythm is --section-space-md top and bottom.

Default-slot content follows the head. Unclassed lists, paragraphs and tables pick up the base defaults.

tone="raised" · width="narrow" · space="tight"

Raised, narrow, tight

Background --surface-raised (the body already sits on --neutral-ultra-light, so that shade would be invisible). Inner width --content-width-sm.

Use space="tight" when two sections of the same tone sit next to each other.

tone="brand" · aside slot

Brand tone

Head with an aside

The aside sits beside the copy from the medium breakpoint up, bottom-aligned; below that it stacks under the sub.

Typical use: a section title on the left, a "See all" link or a filter on the right.

Hero

Props: eyebrow?, title, lede?,align: "start" | "center", tone: "default" | "dark" | "brand",level?: 1 | 2. Slot: actions. Full-bleed band; as the first block in main it clears the fixed header by itself.

tone="default" · align="start"

Default hero

A starter you can actually launch from.

Opinionated defaults, OKLCH color engine, fluid type. Edit override.scss, you're done.

Learn more

tone="brand" · align="center"

Brand tone

Build something worth shipping.

Primary ultra-light background, full-bleed band, generous padding.

tone="dark" · align="center"

Dark tone

For high-contrast moments.

Neutral ultra-dark background, primary-light eyebrow, inverted text.

Secondary

CTA

The closing call-to-action on every page is the layout's SiteCta — aSection with align="center" and width="narrow", rendered after<main>. Pages do not compose it; they pass cta to Base(hide, or title / body / primary / secondary overrides).SiteCta props: title, body, primary, secondary({label, href}), tone: "brand" | "inverse".

CTA below is the in-page block for mid-page prompts. Props: title, body?,tone: "default" | "brand" | "dark" | "accent",align: "start" | "center". Slot: actions.

SiteCta · tone="inverse" (layout-owned; shown here with overrides)

Closing call-to-action

Rendered by Base.astro after main on every page unless cta.hide is set.

CTA · tone="default"

Ready to build?

Clone the starter, tune one file, push.

View style guide

tone="brand"

Make it yours in minutes.

Tune brand colors in override.scss — the whole palette rebuilds via OKLCH.

tone="accent"

Got feedback?

Tell us what's missing — astrobase grows from real project feedback.

tone="dark"

Still reading?

Clone the repo and see how little configuration it takes to ship something clean.

Feature grid

Props: features (array of {icon?, title, body}),columns: 2 | 3 | 4, align: "start" | "center",tone: "default" | "muted".

columns=3 · align="start"

OKLCH palette

10 families × 8 shades, generated perceptually uniform from hue alone.

Fluid scale

Spacing + type interpolate between mobile and desktop via clamp().

One file tuning

Edit override.scss, the whole system rebuilds. Framework file stays untouched.

columns=3 · align="center" · tone="muted"

OKLCH palette

10 families × 8 shades, generated perceptually uniform from hue alone.

Fluid scale

Spacing + type interpolate between mobile and desktop via clamp().

One file tuning

Edit override.scss, the whole system rebuilds. Framework file stays untouched.

Astro native

SCSS compiled by Astro — no extra build step, no runtime CSS-in-JS.

Dark mode

Flip the palette via [data-theme='dark']. All components follow automatically.

Three layers

framework.scss upstream; override.scss is your tuning surface; base.scss is opt-in reset.

columns=4

OKLCH palette

10 families × 8 shades, generated perceptually uniform from hue alone.

Fluid scale

Spacing + type interpolate between mobile and desktop via clamp().

One file tuning

Edit override.scss, the whole system rebuilds. Framework file stays untouched.

Astro native

SCSS compiled by Astro — no extra build step, no runtime CSS-in-JS.

Stats

Props: stats (array of {value, label, hint?}),columns: 2 | 3 | 4, align: "start" | "center",tone: "default" | "muted". Uses <dl>/<dt>/<dd> + tabular-nums for aligned values.

columns=4 · align="start"

Color tokens
10×8
Families × shades generated from hue + lightness + chroma.
Body baseline
18px
Fluid to 16px on mobile. Type scale 1.25 / 1.2.
Versioned
SemVer
Every framework.scss change bumps the version; history in css-framework/CHANGELOG.md.
Runtime CSS
0ms
Static SCSS → plain CSS. Zero CSS-in-JS overhead.

columns=4 · align="center" · tone="muted"

Color tokens
10×8
Families × shades generated from hue + lightness + chroma.
Body baseline
18px
Fluid to 16px on mobile. Type scale 1.25 / 1.2.
Versioned
SemVer
Every framework.scss change bumps the version; history in css-framework/CHANGELOG.md.
Runtime CSS
0ms
Static SCSS → plain CSS. Zero CSS-in-JS overhead.

Testimonial

Props: quote, author, role?,avatar?, tone: "default" | "muted" | "brand" | "dark".

tone="default"

The OKLCH palette is the cleanest color system I've shipped against. Edit one hue, the whole palette re-derives.

Jamie ChenDesign engineer, Relay

tone="brand"

Fluid type and spacing out of the box. I stopped writing media queries and started writing features.

Priya ShahFounder, Nimbus

tone="dark"

Clone, tune override.scss, push. First marketing site of the year that didn't turn into a config swamp.

Marco AlvaresCTO, Folio

Logo cloud

Props: title?, logos (array of {name, src?, href?}),align: "start" | "center", tone: "default" | "muted". Text fallback when src omitted.

align="center"

Trusted by teams at

  • Acme
  • Corta
  • Nimbus
  • Folio
  • Relay
  • Pilot

align="start" · tone="muted"

Powering product launches

  • Acme
  • Corta
  • Nimbus
  • Folio
  • Relay
  • Pilot
Content3

Card

Props: eyebrow?, title?, href?,tone: "default" | "muted" | "brand",padding: "md" | "lg". Slots: default (body), media.

Default trio

Guide

Getting started

Clone astrobase, run npm install, tune override.scss, and you're shipping.

Reference

Style guide

Every token live-rendered — colors, spacing, type, radius, and primitives.

Framework

Three layers

framework.scss is upstream. override.scss is yours. base.scss is opt-in.

tone="brand" · pad-lg

Launch

Ready when you are

Primary-tinted card for emphasis. Use sparingly — hero piece of a grid.

Accordion

Props: items (array of {question, answer}),exclusive? (only one item open at a time — native <details name> group, Chromium 120+/Safari 17+). Uses native <details> so it works without JS.

default (independent)

Can I use a different font?
Yes — swap the @font-face block in main.scss and update the $font-family-* tokens. The framework itself is font-agnostic.
How do I customize the palette?
Set your brand hues in the $color-bases map in override.scss. Each family generates a full 8-shade scale from a single hue, lightness, and chroma in OKLCH.
Do I style each component twice for dark mode?
No. [data-theme="dark"] flips the whole shade palette; any component that uses palette tokens follows automatically — no per-component overrides required.
What do I change when cloning astrobase?
Rename the Astro package, edit override.scss for your brand, build pages under src/pages, and point a deploy webhook at main. That's the whole setup.

exclusive=true

Can I use a different font?
Yes — swap the @font-face block in main.scss and update the $font-family-* tokens. The framework itself is font-agnostic.
How do I customize the palette?
Set your brand hues in the $color-bases map in override.scss. Each family generates a full 8-shade scale from a single hue, lightness, and chroma in OKLCH.
Do I style each component twice for dark mode?
No. [data-theme="dark"] flips the whole shade palette; any component that uses palette tokens follows automatically — no per-component overrides required.
What do I change when cloning astrobase?
Rename the Astro package, edit override.scss for your brand, build pages under src/pages, and point a deploy webhook at main. That's the whole setup.

Alert

Props: variant: "info" | "success" | "warning" | "danger",title?, icon? (overrides default glyph). Static content, so no live-region role is set; pass role="alert" orrole="status" through when you inject one after load.

All four variants

Heads up

This is an info alert. Rendered statically, so it carries no live-region role.

Deploy complete

Your site is live at astrobase.florianstangl.com.

Pending action

The latest framework minor changed the default palette. Review your override.scss.

Build failed

SCSS compilation errored at framework.scss:352. Check the CI logs.

Title only (no body)

A new framework version is live.

All systems operational.

Primitives2

Button

Props: href? (renders <a> when set, otherwise <button>),variant, size, disabled.

Variants

Sizes

Links vs. buttons

As a link

Badge

Props: variant (9 families, all soft by default),size: "sm" | "md", solid?.

Soft (default) — 9 variants

NeutralPrimarySecondaryTertiaryAccentSuccessWarningInfoDanger

Solid

NeutralPrimarySuccessWarningInfoDanger

Sizes

SmallMedium

Ready to build?

Clone the starter and see how little configuration it takes to ship something clean.