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
DarkLight- --surface
Cards, menu panel
DarkLight- --ink
Primary text
DarkLight- --ink-2
Secondary text, labels
DarkLight- --line
Hairlines, dashed row borders
DarkLight- --line-strong
Control borders, rulers, crosshairs
DarkLight- --dot
Background dot grid
DarkLight- --grid
Hero grid lines
DarkLight- --accent
Links, focus ring, active marks, primary button
DarkLight- --ok
Success status
DarkLight- --err
Error status
DarkLight
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
DarkLight- --ink-2 / --bg
Secondary text on page
DarkLight- --ink-2 / --surface
Secondary text on card
DarkLight- --accent / --bg
Accent on page (links, marks)
DarkLight- --bg / --accent
Primary button text on accent
DarkLight- --ok / --bg
Success mark on page
DarkLight- --err / --bg
Error text on page
DarkLight
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
- …