Design Tokens

All tokens are CSS custom properties defined in @layer tokens on :root. Reference them with var(--token-name).

Color — Base Palette

--bg-base #080818
--bg-section #0e0e24 — alternating section bg
--bg-surface #121230 — card/panel surface
--bg-surface-active #14143a — active/open surface state
--border-subtle rgba(255,255,255,0.08) — default dividers & card borders

Color — Text

--text-primary #f0f0ff
--text-secondary #9090b8

Color — Accents

--accent-cyan #22d3ee — focus ring, overlines, chevrons
--accent-glow rgba(255,60,172,0.18) — btn hover glow

Color — Alpha / Surface Variants

--accent-cyan-subtle rgba(34,211,238,0.07) — hero bg glow
--accent-pink-subtle rgba(255,60,172,0.07) — hero bg glow
--bg-nav rgba(8,8,24,0.7) — nav desktop backdrop
--bg-nav-solid rgba(8,8,24,0.96) — nav mobile (no blur)
--surface-hover-md rgba(255,255,255,0.04) — subtle hover/tag bg
--border-hover rgba(255,255,255,0.2) — btn/input hover border

Color — Shadows

--shadow-sm nav scroll shadow
--shadow-lg card lift shadow

Spacing Scale

--space-xs 0.5rem — 8px
--space-sm 1rem — 16px
--space-sm-plus 1.5rem — 24px — component gaps
--space-md 2rem — 32px
--space-lg 4rem — 64px
--space-xl 8rem — 128px

Border Radius

--radius-sm 6px — buttons, inputs
--radius-md 12px — cards, panels
--radius-lg 20px — case studies wrapper
--radius-pill 100px — tags

Measure

--measure 60ch — max line length for text containers

This paragraph is constrained to max-width: var(--measure). Used on .section__header and .lets-talk__content to cap comfortable reading width.

Typography

Font Families

Exo --font-body "Exo" + system fallbacks — single token for all type: headings, body, UI

Font Size Scale

--font-size-sm 0.75rem / 12px Labels, badges, eyebrows, arrows, btn--sm
--font-size-base 0.9375rem / 15px Body text, UI chrome (footer copy, links, tagline)
--font-size-lg 1.125rem / 18px Component headings, section subtitle / lead text
--font-size-xl 1.375rem / 22px Nav wordmark, case study title
--font-size-2xl 1.75rem / 28px Footer name, card icon

Font Weight

--weight-normal 400 The quick brown fox
--weight-medium 500 The quick brown fox
--weight-semibold 600 The quick brown fox

Letter Spacing

--tracking-tighter -0.02em Display name
--tracking-tight -0.01em Section titles, wordmark
--tracking-normal 0.01em Default slight open
--tracking-wide 0.06em Hero title, uppercase tags
--tracking-wider 0.1em Org labels, col titles
--tracking-widest 0.12em Section eyebrow

Typography Utility Classes

Gradient Text
<span class="gradient-text">Gradient Text</span>

Applies --rainbow-gradient (7-stop spectrum) as a clipped background. Used on the hero name, nav wordmark, and footer name. The ✦ glyph sets background-image directly (not a .gradient-text element).

Overline Label
<p class="text--overline">Overline Label</p>

font-weight: --weight-semibold, uppercase. Used for section eyebrows and accordion org labels.

This is body text styled with the text--body utility. It sets font-size to --font-size-base and color to --text-secondary.

<p class="text--body">Body text here.</p>

--font-size-base (15px), --text-secondary. Used on card bodies and case study teasers.

  • First item in the list
  • Second item in the list
  • Third item in the list
<ul class="arrow-list">
  <li>First item</li>
  <li>Second item</li>
</ul>

Arrow-bulleted list. Each <li> gets a in --accent-cyan via ::before. Items are spaced with li + li { margin-top } — no flex wrapper needed. Used in case study columns for goals, outcomes, and learnings.

Category Tag
<span class="badge">Category Tag</span>

Pill-shaped label. --font-size-sm, --text-secondary, --surface-hover-md background, --border-subtle border, --radius-pill. Used on accordion items to label content type.

Column Label

<h4 class="text--col-label mb--xs">Column Label</h4>

--font-size-sm, --weight-semibold, uppercase, --tracking-wider, --rainbow-magenta. Used for accordion body column headings (Context, Goals, Results, etc.). Pair with .mb--xs for spacing below.

Buttons

All buttons share the .btn base class. Variants and size modifiers are additive. Hover states lift and brighten; :focus-visible shows a cyan outline ring.

Default Size

Primary Ghost
<a href="#" class="btn btn--primary">Primary</a>
<a href="#" class="btn btn--ghost">Ghost</a>
<button class="btn btn--sm btn--rainbow" aria-pressed="false">
  <span class="btn__icon" aria-hidden="true">🌈</span>
</button>

Small — .btn--sm

Primary Ghost
<a href="#" class="btn btn--sm btn--primary">Primary</a>
<a href="#" class="btn btn--sm btn--ghost">Ghost</a>
<button class="btn btn--sm btn--rainbow" aria-pressed="false">
  <span class="btn__icon" aria-hidden="true">🌈</span>
</button>

Rainbow — pressed state

<button class="btn btn--sm btn--rainbow" aria-pressed="true">
  <span class="btn__icon" aria-hidden="true">🌈</span>
</button>

Hover: All buttons lift (translateY -2px) via .btn:hover. btn--primary also gains a glow shadow and the gradient border brightens to full opacity. btn--ghost border brightens, text becomes primary. btn--rainbow border brightens, subtle background appears, icon rotates 20° and scales. Note: btn--rainbow uses aria-pressed to reflect toggle state — JS sets this on interaction.

Layout

Container

The global page column. Centers content and applies consistent horizontal padding.

max-width1100px padding-inlinevar(--space-md) — 32px margin-inlineauto — horizontally centered
<div class="container">
  <!-- page content -->
</div>

Section

Shared wrapper for every page section. Adds vertical rhythm and a top border separator between adjacent sections.

padding-blockvar(--space-xl) — 128px (var(--space-lg) on mobile) .section + .sectionborder-top: 1px solid var(--border-subtle)
<section class="section" id="my-section" aria-labelledby="my-heading">
  <div class="container">
    <header class="section__header">…</header>
    <!-- section content -->
  </div>
</section>

Section Header

The standard header block used at the top of every content section. Constrained to --measure (60ch). Children use margin-bottom for spacing — no flex/gap.

Eyebrow Label

Section Title

A subtitle or brief description that sits below the title and gives a little more context about what follows.

<header class="section__header">
  <p class="section__eyebrow">Eyebrow Label</p>
  <h2 class="section__title" id="section-heading">Section Title</h2>
  <p class="section__subtitle">Subtitle text here.</p>
</header>

Spacing: eyebrow margin-bottom: 0.75rem, title margin-bottom: 1rem, subtitle margin-bottom: var(--space-sm-plus). Header itself: margin-bottom: var(--space-lg).

Background Utilities

Semantic background color classes. Use these instead of inlining token values so section backgrounds stay in sync with the palette.

.bg--base var(--bg-base) — default page background
.bg--section var(--bg-section) — alternating section background
<section class="section bg--section">…</section>

Border Utilities

A pair of utilities for adding a 1px rainbow gradient border via pseudo-element. Opacity is controlled by --rainbow-border-opacity (default 0.35), making it overridable for animated reveal states.

Content below a rainbow border
<section class="section rainbow-border-top">…</section>

Renders via ::before at top: 0. Applied to all .section and .footer elements.

Content above a rainbow border
<nav class="nav rainbow-border-bottom">…</nav>

Renders via ::after at bottom: 0. Used on .nav — starts hidden (--rainbow-border-opacity: 0) and fades in on .nav.scrolled.

Grid — 3 Column

Responsive 3-column grid. 1-col on mobile, 2-col at 640px, 3-col at 960px. Used for cards, tech chips, and any uniform-item layouts.

<div class="grid--3col gap--sm-plus">
  <!-- items -->
</div>

Pair with a gap--* utility to control spacing. gap--sm-plus is the standard card grid gap.

Gap Utilities

Composable gap classes that map directly to the spacing scale. Apply to any flex or grid container.

.gap--xsvar(--space-xs) — 8px
.gap--smvar(--space-sm) — 16px
.gap--sm-plusvar(--space-sm-plus) — 24px — standard card/chip gap
.gap--mdvar(--space-md) — 32px
.gap--lgvar(--space-lg) — 64px
.gap--xlvar(--space-xl) — 128px

Margin-Bottom Utilities

Composable margin-bottom classes for spacing typography elements without nested CSS. Prefer these over component-specific descendant selectors.

.mb--xsvar(--space-xs) — 8px — col label → list spacing
.mb--smvar(--space-sm) — 16px — eyebrow → title, badge-group label → chips
.mb--sm-plusvar(--space-sm-plus) — 24px
.mb--mdvar(--space-md) — 32px

Components

Card

Used in the Philosophy section inside a .grid--3col wrapper. 3-col on desktop, 2-col on tablet, 1-col on mobile. Cards lift on hover with a pink glow.

Systems Over Heroics

Sustainable delivery comes from strong planning rituals, not individual heroics. Build the system, not the hero.

Safety With Accountability

Psychological safety isn't softness — it's the foundation that lets people do their best work without fear.

<article class="card">
  <div class="card__icon" aria-hidden="true">⚙️</div>
  <h3 class="card__title">Title</h3>
  <p class="card__body text--body">Body text.</p>
</article>

In rainbow mode, card borders become a full-spectrum gradient via background-clip: border-box.

Accordion

An accessible accordion. Each item is a <button> trigger with aria-expanded and aria-controls. The body uses the hidden attribute; JS toggles is-open on the wrapper and removes hidden. The title gets a gradient on hover/open. The chevron rotates on open.

Context

Background prose about the problem space and situation.

Goals

  • Deliver the feature on schedule
  • Improve team collaboration rituals
  • Increase engagement metrics

What I Learned

Reflective prose about key takeaways from the engagement.

<div class="accordion">
  <article class="accordion__item" id="cs-id">
    <button class="accordion__trigger" aria-expanded="false" aria-controls="cs-id-body">
      <div class="accordion__meta">
        <span class="section__eyebrow">Org</span>
        <span class="badge">Category</span>
      </div>
      <h3 class="accordion__title">Title</h3>
      <p class="accordion__teaser text--body">Teaser.</p>
      <span class="accordion__chevron" aria-hidden="true"></span>
    </button>
    <div class="accordion__body" id="cs-id-body" hidden>
      <div class="accordion__grid">
        <div class="accordion__col">
          <h4 class="text--col-label mb--xs">Context</h4>
          <p>Prose.</p>
        </div>
        <div class="accordion__col">
          <h4 class="text--col-label mb--xs">Goals</h4>
          <ul class="arrow-list">
            <li>Goal one</li>
          </ul>
        </div>
      </div>
    </div>
  </article>
</div>

The gap: 1px between case study items is achieved by the flex container exposing its background through a 1px gap — not borders. JS toggles .is-open on the article and flips aria-expanded. The expandIn animation plays when the body is revealed.

Nav

Fixed to the top. Glassmorphism backdrop blur on desktop (removed on mobile for performance). The wordmark fades in via JS once the hero name scrolls out of view. The rainbow toggle lives here.

<nav class="nav" aria-label="Main navigation">
  <a href="/" class="nav__wordmark">
    <span class="gradient-text">Aly Fluckey</span>
  </a>
  <div>
    <button class="btn btn--sm btn--rainbow" id="rainbowToggle"
            aria-pressed="false" aria-label="Toggle Rainbow Time mode">
      <span class="btn__icon" aria-hidden="true">🌈</span>
    </button>
  </div>
</nav>

.nav.scrolled reveals the .rainbow-border-bottom gradient (sets --rainbow-border-opacity to 0.35) and adds a drop shadow — applied by JS on scroll. .nav.name-visible fades the wordmark in — applied by JS via IntersectionObserver on the hero name.

Badge Group

A labeled cluster of pill badges. Each group has an overline heading and a flex-wrapped chip row using .badge elements. Named by pattern, not content — reusable anywhere badges need a labeled grouping.

Frontend

React TypeScript CSS Next.js
<div class="badge-group">
  <p class="text--overline mb--sm">Group Label</p>
  <div class="badge-group__chips">
    <span class="badge">Chip</span>
    <span class="badge">Chip</span>
  </div>
</div>

.badge-group__chips is display: flex; flex-wrap: wrap; gap: var(--space-xs). Uses .badge for the individual chips. Groups are placed inside a .grid--3col wrapper. The .mb--sm on the label drives spacing without nested CSS.

2-column grid on desktop (brand left, links right), stacked on mobile. The bottom bar spans full width and holds copyright copy and a second rainbow toggle.

<footer class="footer">
  <div class="container footer__inner">
    <div>
      <span class="footer__name gradient-text">Name</span>
      <p class="footer__tagline">Tagline.</p>
    </div>
    <nav class="footer__links" aria-label="...">
      <a href="#" class="footer__link">Link</a>
    </nav>
    <div class="footer__bottom">
      <span class="footer__copy">Copy text.</span>
      <button class="btn btn--sm btn--rainbow" aria-pressed="false">
        <span class="btn__icon" aria-hidden="true">🌈</span>
      </button>
    </div>
  </div>
</footer>

Animations & Motion

All animations respect prefers-reduced-motion: reduce — durations are collapsed to 0.01ms and iteration counts to 1.

Motion Tokens

--ease-out cubic-bezier(0.22, 1, 0.36, 1) — snappy deceleration
--duration 0.3s — default: buttons, borders, colours
--duration-medium 0.4s — nav wordmark, toggle icon
--duration-slow 0.5s — body bg transition

Keyframe Animations

glyphSpin 18s linear infinite Rotates the ✦ glyph in the Let's Talk section. Paused by default, runs only when the element is visible in the viewport (IntersectionObserver sets .playing class).
expandIn var(--duration-medium) var(--ease-out) Fades in and lifts up (translateY -8px → 0) the case study body panel when an accordion item is opened.

Transition Patterns

btn--primary hover Gradient border ::before opacity 0.7 → 1, plus box-shadow glow. Lift (translateY -2px) is inherited from .btn:hover.
btn--ghost hover Border brightens to --border-hover, text becomes --text-primary. Lift inherited from .btn:hover.
btn--rainbow hover / pressed Border brightens, subtle background appears, .btn__icon rotates 20° and scales 1.15×.
card hover translateY(-2px) + --shadow-lg lift shadow.
nav wordmark opacity 0 → 1 + translateY(-6px → 0) over --duration-medium. Triggered by IntersectionObserver when hero name leaves viewport.
body background background-color transitions over --duration-slow on load.

Rainbow Time

Rainbow Time is the default color scheme. The rainbow spectrum tokens live in :root and are applied directly to key components — no mode class required. The 🌈 toggle button (#rainbowToggle, #rainbowToggleFooter) is preserved for future use.

Spectrum Tokens

--rainbow-orange #ff7a18 — spectrum stop
--rainbow-pink #ff3cac — spectrum stop
--rainbow-magenta #ff00cc — spectrum stop, .text--col-label
--rainbow-purple #9333ea — spectrum stop
--rainbow-indigo #6366f1 — spectrum stop
--rainbow-blue #3b82f6 — spectrum stop
--rainbow-gradient orange → pink → magenta → purple → indigo → blue → cyan (horizontal)
--rainbow-gradient-diagonal same spectrum at 135° — odd card borders and btn--primary border
--rainbow-gradient-diagonal-reverse reversed spectrum at -135° — even card borders

Components Using Rainbow Spectrum

.gradient-text background-image: --rainbow-gradient via base class — used on hero name, nav wordmark, footer name
.lets-talk__glyph background-image: --rainbow-gradient (not a .gradient-text; has its own rule)
.card Rainbow border via background-clip: border-box. Odd cards: --rainbow-gradient-diagonal; even cards: --rainbow-gradient-diagonal-reverse
.btn--primary::before Gradient border uses --rainbow-gradient-diagonal
.rainbow-border-top 1px gradient top border via ::before. Applied to all .section and .footer elements.
.rainbow-border-bottom 1px gradient bottom border via ::after. Applied to .nav — fades in on scroll via --rainbow-border-opacity custom property.