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:
- Hardcoded color values bypass the brand token system
- Tailwind utility classes used instead of brand CSS custom properties for layout
- 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 viavar(--brand-color-*) - No Tailwind width utilities (
max-w-2xl,max-w-4xl) — usemax-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
Related Patterns
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