How this site is built

Built to the standard we sell.

This site runs behind the same budgets, gates and accessibility checks we put on client work. Every figure here says what it is: Measured, with its source and date, or Target, a limit the build holds us to.

Framework
Astro, prerendered
Host
Cloudflare Workers
Design system
FIRN
Cookies
None of our own
Measured
2026-10-13

Measured, not claimed

The numbers this site can prove about itself. The JavaScript figure is read from the build and checked by it, so it can’t drift from the truth.

Lighthouse: Lighthouse 13, median of 3, on a local production build of the home page, ; layout shift and blocking time from the same runs. JavaScript: gzip size of the one script this page runs at load.

Limits the build enforces

A check after every build fails it if any page goes over, and axe holds every template to WCAG 2.2 AA in both themes. These are limits, not readings, so they carry the Target label.

Gzip sizes. One documented exception: the home page may inline a little more CSS for its CSS-only chapters. No page loads a stylesheet or a font from another domain. The theme’s text and surface color pairs are checked for contrast in the unit tests.

Open Machine view to check these numbers on any page. It outlines the page’s sections, reads load timings, bytes and requests from your own browser, and sets them beside these budgets. Every page’s footer has it as “Measure this page”. It needs JavaScript, and nothing it reads is sent anywhere.

Five checks. Try to break the build.

Every pull request to this site runs the same five steps, in order, and a failure stops the line. Pick a change below to see which check stops it, and what it printed.

Pick a change to merge:
  1. Types

    Strict TypeScript across pages, components and server code.

  2. Unit tests

    Lead pipeline, structured data, the contrast of the theme’s color pairs, content rules.

  3. Build

    Pages prerendered to static HTML with their CSS inlined, and the Worker bundled.

  4. Verify

    Content in the HTML, one H1, valid structured data, no prices, every budget held.

  5. Accessibility and journeys

    axe against WCAG 2.2 AA in light, dark and mobile, plus the real journeys in a browser.

  1. A clean change: All 5 passed. Merged. Passed: Types, Unit tests, Build, Verify, Accessibility and journeys.

    $ pnpm check · test · build · verify · test:e2e
    Result (196 files):
    - 0 errors
    Tests  274 passed | 16 skipped (290)
    [build] Complete!
    ✓ 29 pages checked · JS at load: entry 1502 B gz
    196 skipped
    463 passed (8.2m)

    The rule All five steps pass, in order, so the change can merge.

    Now try to break it.

  2. Rename a prop, miss one page: Stopped at Types. Not merged. Stopped it: Types. Not run: Unit tests, Build, Verify, Accessibility and journeys.

    $ pnpm check
    src/pages/approach/how-this-site-is-built.astro:94:26 - error ts(2322):
      Property 'label' does not exist on type 'IntrinsicAttributes & Props'.
    Result (196 files):
    - 1 error

    The rule astro check runs strict TypeScript over every page, component and server file. One error fails the step.

    The page that still used the old name would have shipped broken.

  3. Lighten the grey text a touch: Stopped at Unit tests. Not merged. Passed: Types. Stopped it: Unit tests. Not run: Build, Verify, Accessibility and journeys.

    $ pnpm test
    ❯ tests/unit/tokens.test.ts (92 tests | 4 failed)
        × moraine on snow-25 >= 4.5:1
        × moraine on snow-0 >= 4.5:1
        × moraine on rime >= 4.5:1
        × moraine on firn-deep >= 4.5:1
    AssertionError: expected 3.9654034385519052 to be greater than or equal to 4.5

    The rule The unit tests hold every text and surface pair in the palette to WCAG: 4.5:1 for body text, 3:1 for large text and controls.

    #56606B to #737D88 looks subtle on a good monitor and is hard to read on a phone in daylight.

  4. Type “<2 seconds” in a page: Stopped at Build. Not merged. Passed: Types, Unit tests. Stopped it: Build. Not run: Verify, Accessibility and journeys.

    $ pnpm build
    [ERROR] [vite] ✗ Build failed in 1.96s
    55:22: Unexpected character after `<`, expected a valid JSX tag
      (note: to create a link in MDX, use `[text](url)`) (mdx-jsx:unexpected-character)
      src/content/services/modernization.mdx:55:22

    The rule Every page compiles to static HTML before anything is checked; content that won’t compile stops the line, with the file and line. Type check passed this one. Only the build caught it.

    A slip in the copy can’t take a page down, because it can’t get there.

  5. Add an analytics snippet: Stopped at Verify. Not merged. Passed: Types, Unit tests, Build. Stopped it: Verify. Not run: Accessibility and journeys.

    $ pnpm verify
    ✗ 2 problem(s):
      about/index.html: script not allowed (only ld+json, speculationrules and the /_astro/ entry module):
        <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX">
      about/index.html: references third-party script origin https://www.googletagmanager.com

    The rule A page may run one script: the site’s own entry module. No third-party script origins, except the anti-spam check on the contact page.

    “No tracking” is a rule the build enforces, not a promise.

  6. Add a 3 KB library to every page: Stopped at Verify. Not merged. Passed: Types, Unit tests, Build. Stopped it: Verify. Not run: Accessibility and journeys.

    $ pnpm verify
    ✗ 1 problem(s):
      entry /_astro/Enhance…js + static imports is 4463 B gzip, over the 2048 B budget

    The rule The one script a page runs at load stays within 2,048 bytes gzip, imports included. Anything bigger loads later, on intent.

    Pages stay quick on a mid-range phone because the build refuses the bytes.

  7. Drop an image’s alt text: Stopped at Accessibility and journeys. Not merged. Passed: Types, Unit tests, Build, Verify. Stopped it: Accessibility and journeys.

    $ pnpm test:e2e
    ✘ [desktop-light] › tests/e2e/a11y.spec.ts:29:3 › axe: /about/
    ✘ [desktop-dark] › tests/e2e/a11y.spec.ts:29:3 › axe: /about/
    ✘ [mobile-reduced-motion] › tests/e2e/a11y.spec.ts:29:3 › axe: /about/
    +   "image-alt: 1 node(s) · Images must have alternative text",

    The rule A real browser opens every template in light, dark and on a phone with reduced motion, and runs axe’s WCAG A and AA rules. Verify passed this one; axe did not.

    Nobody using a screen reader meets an unlabelled image.

ExampleEach log is real output, trimmed: we made the change to a copy of this site and ran the checks on .

Islands, loaded on intent

Rich interaction without the usual cost: one small script runs at load, and nothing more is fetched until someone reaches for it or scrolls to it.

  1. HTML and CSS first

    Every feature works as native HTML and CSS: links, forms, details, popover. Motion is CSS, off under reduced motion.

  2. One small entry

    A single module at load, held to 2,048 bytes. It waits for a reason to load anything more.

  3. Loaded on intent

    Islands are fetched on the first hover, focus, press or key, or as they scroll near. Until then they cost nothing.

  4. Heavy work off the main thread

    Per-frame drawing runs in a Web Worker on an OffscreenCanvas, so scrolling and typing stay free.

No framework runtime and no single-page router. The terrain lab shows the off-main-thread renderer on its own.

Static at the edge

Pages are files, served close to the reader. Of the few parts that have to be live, the quote form works without JavaScript and stores every request before it is delivered.

  1. Static pages

    Most pages are prerendered at build time and served as static files by Cloudflare Workers.

  2. A few live routes

    The contact form, the privacy choices page and the WordPress tracker with its data files render per request; everything else is a static file.

  3. Stored first

    A quote request is validated, then saved to a Cloudflare D1 database before it goes anywhere else.

  4. Then delivered

    The CRM and the studio inbox are updated once the page has answered you; a daily job retries anything that failed.

Private by default

Read the privacy policy

FIRN, one set of tokens

Color, type, spacing, radius and motion live in one token file. Light and dark are the same names with different values, and every page inherits them.

Start a project

Hold your build to the same standard.

We reply within one business day, with questions or a time to talk.

Pittsburgh, PA · Since 2015 · First step: a 30-minute call