Colophon

A style guide and build notes for this site. Everything below is rendered from the site’s own CSS tokens and components, so it stays in sync when they change.

Color

Values are read from the live CSS variables with getComputedStyle, once for each theme.

--bg

Page background

Dark Light
--surface

Cards, menu panel

Dark Light
--ink

Primary text

Dark Light
--ink-2

Secondary text, labels

Dark Light
--line

Hairlines, dashed row borders

Dark Light
--line-strong

Control borders, rulers, crosshairs

Dark Light
--dot

Background dot grid

Dark Light
--grid

Hero grid lines

Dark Light
--accent

Links, focus ring, active marks, primary button

Dark Light
--ok

Success status

Dark Light
--err

Error status

Dark Light

Contrast

WCAG 2.x contrast ratio, computed from the values above. Body text needs 4.5:1 (AA); large text and UI parts need 3:1.

--ink / --bg

Primary text on page

Dark Light
--ink-2 / --bg

Secondary text on page

Dark Light
--ink-2 / --surface

Secondary text on card

Dark Light
--accent / --bg

Accent on page (links, marks)

Dark Light
--bg / --accent

Primary button text on accent

Dark Light
--ok / --bg

Success mark on page

Dark Light
--err / --bg

Error text on page

Dark Light

Typography

Headings and buttons use Hubot Sans, labels and paths use Martian Mono, body text uses the system font stack. Both web fonts are self-hosted and preloaded.

--display

Headings, brand, buttons

Dodi Sopandi, 0123456789

--mono

Paths, labels, nav, dates, code

Dodi Sopandi, 0123456789

--sans

Body text

Dodi Sopandi, 0123456789

Scale in use

Samples use the real classes; sizes are measured from the rendered element.

Section title

How I work

Row title
  • Transaction platform

Body

Build and maintain a transaction platform end to end.

Button
View my work
Path label
/process
Row label
  • Client project

The hero headline is fluid: clamp(2rem, 3.2vw, 2.625rem) on desktop, scaled per language with --fit (Indonesian is 0.78).

Spacing and grid

Layout comes from four tokens. Values are read live, so they show the current viewport (gutters disappear on small screens).

--frame

Maximum content width

--gutter

Dotted margin with the rulers, each side

--pad-x

Horizontal padding inside sections

--pad-y

Vertical padding inside sections

Breakpoints

767px
Rulers and gutters go away, split sections stack, rows become one column
879px
Header switches to the menu button
880–1023px
Tighter header spacing; hero stacks below 1024px
1024px
Desktop: two-column hero, hidden page scrollbar

Blueprint pattern

Dot grid
A radial-gradient dot pattern on the page background.
Rulers
Dashed vertical lines with ticks every 80px, in the gutters.
Crosshairs
A + mark on the corners where section lines meet.
Dashed lines
Dashed borders for rows and controls; solid lines only for section edges.

Live: a section with crosshair corners and dashed rows

Components

Live examples of what exists in the code. No variants are shown that the site does not use.

Primary button
Email me

The one main action in a group, such as Email me.

Secondary button
Copy email

Other actions next to a primary one, such as Copy email.

Rows
  • Label

    Row title

    A short line about the row.

  • Label

    Another row

    Rows are separated by dashed lines.

Lists of work, experience, and stack. The left label turns bright on hover.

Split section

Content sections: the label on the left, the content on the right.

Path label

Small label above a section title; it matches the anchor in the URL.

Card
A card with a dashed border.

A boxed block with a dashed border and the surface color.

Status

Not actively looking, but happy to chat.

A short state line; the green dot is only for “ok”.

The header controls (menu button, EN | ID switch, theme toggle) and the footer controls (Motion, Inspect) are live on this page too.

Motion

All motion is short and uses transform and opacity only, so layout never shifts.

--dur-fast

Opacity changes, small shifts

--dur

Transforms

--ease

Easing for all of the above

What moves

Intro loader
A boot-log line once per session; any key or click skips it.
Blur-in
Hero text fades in with a small blur.
Theme switch
The new theme grows as a circle from the toggle (450ms View Transition).
Theme icon
A shadow circle slides over the sun to make a crescent.
Language switch
A box slides to the chosen language before the page changes.
Nav links
Square brackets slide in on hover and keyboard focus.
Row hover
A thin accent line grows on the left of the row.
Arrow links
The arrow moves 3px toward its destination on hover.
Copy email
A green check draws itself and the frame turns green, then resets after 2 seconds.
Click feedback
Corner marks appear around buttons on hover and press.
Section arrival
The crosshairs light up after a menu link is used.
Menu panel
The mobile menu fades and slides in (150ms).

Turning it off

The Motion toggle in the footer sets data-motion="off" on <html> and remembers it. Durations become 0s, and the loader, blur-in, and theme reveal are skipped. prefers-reduced-motion does the same, and Motion starts off for those visitors. State changes still show, just without movement.

Accessibility

What the code does today.

Keyboard focus
Every interactive element gets a 2px accent outline with a 3px offset on :focus-visible.
Skip link
“Skip to content” is the first focusable element.
Structure
One h1 per page, header, nav, main, and footer landmarks, and sections named by their headings.
State in ARIA
aria-current for the active section and language, aria-pressed on toggles, aria-expanded and aria-controls on the menu button, and a live region for copy-email feedback.
Language
The html lang follows the page, and language links carry hreflang and lang.
Touch targets
Header controls are at least 40px tall, buttons 44px.
Contrast
Ratios for every text pair are listed in the Color section, computed from the live values.
Motion
Follows prefers-reduced-motion and the Motion toggle.

Built with

Only facts that can be checked in the repository.

Framework
Astro 7.4.1, static output
JavaScript
No client framework. A few small inline scripts handle theme, language, menu, copy email, and Inspect.
Hosting
Cloudflare Workers with static assets, on the custom domain stackfolio.web.id.
Deploy
Push to the main branch on GitHub; Cloudflare builds and deploys it.
Fonts
Hubot Sans and Martian Mono, self-hosted as variable fonts.
Languages
English and Indonesian from typed dictionaries, with hreflang and a sitemap.
Dependencies
4 packages: Astro, the sitemap integration, and the two fonts.
Trackers
None in the code: no analytics, no third-party scripts.
This page
…

Back to home