Style guide

The live type scale, color tokens, and spacing system pulled from globals.css — how the site looks. The editorial guide at the end documents how it reads. This page is the system's self-documentation and a visual-regression reference.

Headings

.h1IBM Plex Sansclamp(32px, base×7, 84px)
Design that ships
.h2IBM Plex Sansclamp(24px, base×4, 48px)
Design that ships
.h3IBM Plex Sansclamp(20px, base×3, 36px)
Design that ships
.h4IBM Plex Sans — large labelclamp(18px, base×8/3, 36px)
Design that ships
.h5IBM Plex Sans — labelclamp(15px, base×2, 32px)
Design that ships
.h6IBM Plex Sans — small labelclamp(13px, base×1.5, 24px)
Design that ships

Display emphasis

One family ships: IBM Plex Sans for display, standfirst, labels, and body. Inside .h1–.h3 the one emphasis available is strong (bold). A headline gets at most one bold emphasis.

.h1base / strong
IBM Plex Sans Bold
.h2base / strong
IBM Plex Sans Bold
.h3base / strong
IBM Plex Sans Bold

Subheads

.subhead--largePlex, gray
Section label, larger
.subheadPlex, gray
Section label

Body copy

.content pclamp(16px, base×2.25, 36px)

Body copy is IBM Plex Sans at a fluid size. Inline strong, emphasis, and links inherit the running color with an underline-color shift on hover.

p.smallclamp(13px, base×1.5, 24px)

Small print — captions, footnotes, secondary detail.

Spacing scale

All spacing derives from --base: clamp(4px, 0.5vw, 16px). Multiply by a fixed factor. At 1440px viewport, base ≈ 7.2px.

×0.5
×1
×2
×3
×5
×8
×10

Class naming: .padding--80 = base×10, .margin-top--24 = base×3. The number reflects an 8px reference unit. Actual spacing scales with the viewport.

Color tokens

Every value below is read out of the :root block in globals.css when the page builds, so this table cannot drift from the stylesheet it documents. Click any swatch to copy the variable. Contrast ratios are measured against --white (#fefefe).

Palette — what the value is

Five base colors supply the role tokens used by components.

--white#fefefePage background
--lightest#eeeeeeSubtle fills, image placeholders1.36:1
--light#c0c0c0Hairline borders, input placeholders, muted arrows1.80:1
--gray#707070Secondary text, subhead labels4.91:1 ✓ AA
--black#060606Primary text20.09:1 ✓ AAA

Functional

Already role-named, and outside both tiers. Accent and selection colors can change on :root at runtime per case study.

--accent#1E40AFLinks, focus ring, brand wordmark. Rewritten per case study8.65:1 ✓ AAA
--accent-text#1E40AF→ --accentNav/footer wordmark — tracks the accent unless a page darkens it
--focus-halo#060606Focus-ring halo. Fixed near-black so the ring stays legible on every accent
--selection#BFDBFEText-highlight tint. Read by JS only — WebKit drops a ::selection rule that uses var()
--error#b42318Contact-form validation feedback. Scoped to .form*

Role — what the value is for

The tokens components use. A plain alias points at a palette value; an -rgb orphan is an off-palette ink that only ever appears at partial alpha, so it's stored as a channel triple and used as rgb(var(--token) / N%). Orphans are named, never snapped onto the nearest palette value — merging them would change pixels.

Surfaces
--surface-page#fefefe→ --whitepage + card + popover backgrounds
--surface-subtle#eeeeee→ --lightestfills, image placeholders, code, arrows
--surface-inverse#060606→ --blackskip link, button hover
--surface-plate-dark-rgbrgb(16 16 16)orphan — the media-stage "black-950" plate
Ink
--ink-primary#060606→ --blackbody copy
--ink-muted#707070→ --graysubheads, captions, secondary nav
--ink-faint#c0c0c0→ --lightplaceholders, muted ::after arrows, underlines
--ink-inverse#fefefe→ --whitecopy + icons on a dark surface
--ink-nav-active#282828orphan — table-of-contents hover/active
--ink-exhibit-rgbrgb(255 255 255)orphan — chrome over a live exhibit
--ink-exhibit-muted#767676orphan — the same chrome on a light plate
Rules (hairlines)
--rule-subtle#eeeeee→ --lightestrow dividers, popover + swatch borders
--rule-strong#c0c0c0→ --lightinput borders, toc rail, link underlines
--rule-on-dark-rgbrgb(242 242 242)orphan — hairline over a dark plate
Elevation inks
--shadow-ink#060606→ --blackthe color-mix elevation shadows
--shadow-ink-paper-rgbrgb(16 24 40)orphan — .paper's Figma-derived ink
--shadow-ink-neutral-rgbrgb(0 0 0)orphan — pure-black washes over media
--shadow-ink-stage-rgbrgb(12 10 8)orphan — media-stage inset shadow
--shadow-ink-cursor-rgbrgb(15 17 21)orphan — the material-cursor pill's own ink

Interaction states

Global transition timing: --transition: 0.15s. All interactive elements carry cursor: pointer and a color/opacity shift on hover.

Linksunderline-color shift

Default link — resting underline uses --light; hover and focus deepen it to --gray. Text color stays inherited; only the underline shifts.

Focus ring2px accent, 2px offset
Simulated focusTab through this page to see live focus rings.
Button.button

Editorial guide

The writing aims to make my experience easy to understand: specific work, accurate attribution, and clear descriptions of my contribution.

Philosophyvoice, ranked

Lead with the work. Describe what I contributed, the tools I used, and the context a reader needs. Keep claims tied to experience I can support.

Make the page easy to read. Use descriptive headings, short paragraphs, and natural technical language. Keep employment, education, and creative credits consistent across the site.

The auditbefore every piece ships
  1. No wall paragraphs. Target two to four sentences, one idea each. Five or more is a wall — split it at its natural beat.
  2. Section on real turns. A header marks a shift in phase, question, or time — not decoration. A short essay wants three to six, not ten.
  3. One emphasis per section. A single bold line on the thesis stays scannable; bolding everything makes nothing stand out.
  4. Assets earn their place. A figure goes in when it shows what prose can't. Two or three strong visuals beat six decorative ones.
  5. Lists over inline runs. Three or more parallel items become a list, not a buried sentence.

The test: skim at reading speed. If your eye slides off a gray block, split it; if a header or image hits every screen, pull some back.

In practicethe same words, audited
Before — one wall

I develop full-stack features for an internal technology governance platform, and my work also includes Java services and SQL data workflows, along with tracing data issues across the application and helping validate production releases, so the role spans both feature development and the support work that follows a release.

After — audited

I develop full-stack features, Java services, and SQL data workflows for an internal technology governance platform.

I also trace data issues across the application and help validate production releases. My role spans feature development and production support.