How this site is built.
The values, type, spacing, and voice. Maintained next to the code. If something on the site looks off, it probably broke one of these.
Foundations
Photo a Day is a single year of photographs, dated, captioned, and filed. One frame per day. The design exists to keep the photo as the loudest thing in the room. Everything else (type, color, spacing, motion) tries to step back.
The aesthetic is warm paper, dark ink, one accent color. No gradients. No drop shadows on cards. No icons in colored circles. The page should read like a printed quarterly that happens to live on the web, not like a SaaS product.
Color
Eight tokens. All values are OKLCH so dark mode flips automatically from a single set of overrides. The palette is warm: a cream paper, three ink grays for hierarchy, one rule color, one accent.
--paperoklch(0.965 0.008 75)--paper-2oklch(0.94 0.01 75)--paper-3oklch(0.91 0.012 75)--inkoklch(0.22 0.012 60)--ink-2oklch(0.42 0.012 60)--ink-3oklch(0.62 0.012 60)--ruleoklch(0.85 0.012 70)--accentoklch(0.55 0.13 25)
The accent is used once per page at most. If a second use feels warranted, the first one is probably wrong.
Typography
Two families. Inter Tight for everything except labels and numbers. JetBrains Mono for eyebrows, dates, EXIF, and any small caps.
- One frame, every day for a year.
- All volumes
- Foundations
- One photograph chosen each day, dated, captioned, and filed. Updated daily, archived forever.
- A photograph a day · 2026
- "Two dogs on a winter morning."
Layout and spacing
Everything sits on an 8px grid. Section gaps round to 24, 48, 80, 96. Page padding is 64 desktop, 32 tablet, 24 phone. The home hero is a 40 / 60 grid (text on the left, photo on the right) so the central rule lines up with the middle vertical rule of the four column stats grid below it.
--gutter-page64px (desktop) / 32 / 24--gutter-section96px between major sections--measure66ch for body copy (45 to 75 ideal)breakpoints1100px (tablet stack), 600px (phone)
Components and patterns
Components are kept few. Most of the site is plain HTML with the type and color tokens above. The components that exist:
- Hero
- Adaptive aspect from the photo's stored width and height. No fixed letterbox. The photo fills its column at its natural ratio.
- Lightbox
- Click any photo. Opens a centered frame with the full size image and a meta panel. Close button is anchored to the frame, not the viewport, so it never overlaps page chrome bleeding through.
- Stats grid
- Four columns in a 2 / 1 / 1 / 1 ratio so the first divider lands at 40%. Aligns with the home hero's central rule.
- Calendar tiles
- One tile per day. Color filled if the day has a color photo, ink filled if black and white, ghosted if no photo, ringed if today.
- Tag chips
- On the search page, each tag is sized by log of its count. The most used tags read larger at a glance.
Motion and accessibility
Motion is small. Most transitions are 120 to 180ms ease. Hover on photos lifts the image by 1.5%. The only longer animation is the empty hero placeholder on /today, where the developing-print breathes at about 4 seconds per cycle.
Every animation is suppressed under prefers-reduced-motion.
The placeholder still renders but stops breathing. Focus rings are
always visible. Touch targets are at least 44px on phone. Body text
sits at 16px or larger. Contrast ratio is 4.5:1 or higher on body,
3:1 on UI elements.
Voice
A handful of editorial rules. The aim is copy that sounds like one person at a desk.
- Sentence case headings.
- Plain punctuation. Commas, periods, parens, semicolons.
- Plain verbs. Is, has, does.
- Active over passive.
- Specific over generic. Name the camera, not "professional gear."
- One specific noun beats three vague ones.