astro css-custom-properties brand-tokens tailwind code-review accessibility

Astro Pages Must Use Brand Tokens Consistently — Never Hardcode Values

Astro Pages Must Use Brand Tokens Consistently

Problem

When building new Astro pages (especially data-heavy landing pages), three categories of consistency errors recur:

  1. Hardcoded color values bypass the brand token system
  2. Tailwind utility classes used instead of brand CSS custom properties for layout
  3. Wrong semantic HTML elements (<p> instead of <h3>) in data-driven card grids

These are caught in code review but waste cycles. Better to prevent them.

Examples Found

1. Hardcoded RGBA in box-shadow

Wrong:

style={`box-shadow: 0 0 20px rgba(99, 102, 241, 0.3)`}

Right — either remove or use a token:

/* brand.css */
--brand-shadow-glow: 0 0 20px rgba(99, 102, 241, 0.3);
style={`box-shadow: var(--brand-shadow-glow)`}

The rgba(99, 102, 241, ...) is the raw value of --brand-color-primary (#6366f1). If the primary color ever changes, the shadow becomes stale.

2. Tailwind max-width instead of brand token

Wrong:

<div class="max-w-2xl mx-auto">  <!-- 672px, Tailwind default -->

Right:

<div class="max-w-[var(--brand-content-max)] mx-auto">  <!-- 720px, from brand.css -->

The brand system defines two width tokens:

  • --brand-container-max (1200px) — for wide grids (3-col cards)
  • --brand-content-max (720px) — for narrow prose sections (hero, FAQ, contact)

Using Tailwind’s max-w-2xl (672px) creates a subtle width inconsistency that’s hard to spot visually but breaks the design contract.

3. Styled <p> instead of semantic <h3> in card grids

Wrong:

<p class="text-lg font-semibold mb-2">{headline}</p>

Right:

<h3 class="text-lg font-semibold mb-2">{headline}</h3>

When using .map() to render card grids, it’s tempting to use <p> for everything. But card headlines should be <h3> for:

  • Screen reader navigation (users can jump between headings)
  • SEO (search engines use heading hierarchy)
  • Consistency with other card grids in the codebase

Prevention Checklist

When building a new Astro page, verify before committing:

  • No raw hex/rgba values in style={} attributes — all colors via var(--brand-color-*)
  • No Tailwind width utilities (max-w-2xl, max-w-4xl) — use max-w-[var(--brand-*-max)]
  • Card headlines use <h3>, not styled <p> tags
  • Sections use py-[var(--brand-section-padding)] px-4 — never hardcoded padding
  • Border separators use border-top: 1px solid var(--brand-color-border) — never Tailwind border classes with colors
  • Data arrays in frontmatter contain only rendered fields — remove unused properties

Container width decision tree

Is the section a card grid or wide layout?
  → Yes: max-w-[var(--brand-container-max)]
  → No (prose, FAQ, hero, contact): max-w-[var(--brand-content-max)]

Dead data in frontmatter arrays

If a data array (tiers, steps, etc.) has fields that aren’t referenced in the template, remove them. They add cognitive load and suggest missing features. Example: agents, delivery, support fields defined on pricing tiers but never rendered.

References

  • Brand CSS: apps/squamish-ai/src/styles/brand.css
  • Token defaults: packages/ui/src/styles/tokens.css
  • Example page: apps/squamish-ai/src/pages/agents.astro
  • Related: Tailwind v4 Astro Integration