DESIGN.md

Personal site — Astro, Tailwind CSS 4, Inter + monospace accents. Light, editorial cards on a neutral canvas.

Design Tokens (YAML)

Colors

Token PathValuePreview
colors.primary#1a1a1a
#1a1a1a
colors.secondary#6b7280
#6b7280
colors.tertiary#3b82f6
#3b82f6
colors.neutral#f5f5f5
#f5f5f5
colors.surface#ffffff
#ffffff
colors.border#e5e7eb
#e5e7eb
colors.border-muted#f3f4f6
#f3f4f6
colors.muted-ui#9ca3af
#9ca3af
colors.heatmap-low#f3f4f6
#f3f4f6
colors.heatmap-mid#d1d5db
#d1d5db
colors.heatmap-high#4b5563
#4b5563
colors.heatmap-max#000000
#000000

Typography

Token PathValuePreview
typography.body.fontFamilyInter
Aa
Inter
typography.body.fontSize1rem
1rem
1rem
typography.body.fontWeight400
Aa
400
typography.body.lineHeight1.6
A
a
1.6
typography.mono-label.fontFamilyui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
Aa
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
typography.mono-label.fontSize0.75rem
0.75rem
0.75rem
typography.mono-label.fontWeight500
Aa
500
typography.mono-label.lineHeight1.25
A
a
1.25
typography.card-title.fontFamilyui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
Aa
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
typography.card-title.fontSize1.125rem
1.125rem
1.125rem
typography.card-title.fontWeight600
Aa
600
typography.card-title.lineHeight1.375
A
a
1.375
typography.profile-name.fontFamilyui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
Aa
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
typography.profile-name.fontSize1.5rem
1.5rem
1.5rem
typography.profile-name.fontWeight700
Aa
700
typography.profile-name.lineHeight1.2
A
a
1.2
typography.post-title.fontFamilyui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
Aa
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
typography.post-title.fontSize1.875rem
1.875rem
1.875rem
typography.post-title.fontWeight700
Aa
700
typography.post-title.lineHeight1.2
A
a
1.2
typography.prose-body.fontFamilyInter
Aa
Inter
typography.prose-body.fontSize1rem
1rem
1rem
typography.prose-body.fontWeight400
Aa
400
typography.prose-body.lineHeight1.625
A
a
1.625

Rounded

Token PathValuePreview
rounded.none0px
0px
rounded.hairline2px
2px

Spacing

Token PathValuePreview
spacing.xs4px
4px
spacing.sm8px
8px
spacing.md16px
16px
spacing.lg24px
24px
spacing.xl32px
32px
spacing.section48px
48px

Components

Token PathValuePreview
components.card.backgroundColor{colors.surface}
= #ffffff
#ffffff
components.card.textColor{colors.primary}
= #1a1a1a
#1a1a1a
components.card.rounded{rounded.none}
= 0px
0px
components.card.padding24px
24px
components.list-row-interactive.backgroundColor{colors.surface}
= #ffffff
#ffffff
components.list-row-interactive.textColor{colors.primary}
= #1a1a1a
#1a1a1a
components.list-row-interactive.padding12px
12px
components.secondary-button.backgroundColor{colors.border-muted}
= #f3f4f6
#f3f4f6
components.secondary-button.textColor#374151
#374151
components.secondary-button.typography{typography.mono-label}
-
components.secondary-button.padding12px 16px
12px
16px
components.caption-text.backgroundColor{colors.surface}
= #ffffff
#ffffff
components.caption-text.textColor{colors.secondary}
= #6b7280
#6b7280
components.caption-text.typography{typography.body}
-
components.caption-text.padding0px
0px
components.divider-rule.backgroundColor{colors.border}
= #e5e7eb
#e5e7eb
components.divider-rule.textColor{colors.primary}
= #1a1a1a
#1a1a1a
components.divider-rule.height1px
1px
components.divider-rule.padding0px
0px
components.page-canvas.backgroundColor{colors.neutral}
= #f5f5f5
#f5f5f5
components.page-canvas.textColor{colors.primary}
= #1a1a1a
#1a1a1a
components.page-canvas.padding0px
0px
components.meta-muted.backgroundColor{colors.surface}
= #ffffff
#ffffff
components.meta-muted.textColor{colors.secondary}
= #6b7280
#6b7280
components.meta-muted.typography{typography.mono-label}
-
components.meta-muted.padding0px
0px
components.heatmap-empty.backgroundColor{colors.heatmap-low}
= #f3f4f6
#f3f4f6
components.heatmap-empty.padding0px
0px
components.heatmap-light.backgroundColor{colors.heatmap-mid}
= #d1d5db
#d1d5db
components.heatmap-light.padding0px
0px
components.heatmap-dark.backgroundColor{colors.heatmap-high}
= #4b5563
#4b5563
components.heatmap-dark.padding0px
0px
components.heatmap-full.backgroundColor{colors.heatmap-max}
= #000000
#000000
components.heatmap-full.padding0px
0px
components.focus-accent.backgroundColortransparent
-
components.focus-accent.textColor{colors.tertiary}
= #3b82f6
#3b82f6
components.focus-accent.padding0px
0px

Overview

yuler.dev is a light, content-first personal site: soft neutral canvas, white surfaces with hairline borders, and monospace for navigation, section titles, and article headings so the UI reads like a clean terminal or README. Body copy stays in Inter for readability. Motion is subtle (border darkens on hover, short transitions). There are almost no rounded “app” cards—corners stay square; optional corner bracket markers reinforce a drafted, editorial frame. Use this file when adding pages or components so new UI matches existing Tailwind usage and global styles in src/styles/global.css.

Colors

  • Primary (#1a1a1a): Default text on the canvas and on white surfaces; matches body in global.css.
  • Secondary (#6b7280): Metadata, footer, timestamps, and de-emphasized labels (Tailwind text-gray-500 class family).
  • Tertiary (#3b82f6): Focus and selection affordances only—::selection and :focus-visible use this hue at partial opacity; do not flood large areas with blue.
  • Neutral (#f5f5f5): Page background for home, posts, and workouts (bg-[#f5f5f5] / same as body background).
  • Surface (#ffffff): All primary cards and article shells.
  • Border (#e5e7eb) / border-muted (#f3f4f6): Default card and list borders; lighter rules for section dividers (border-gray-100).
  • Muted UI (#9ca3af, Tailwind gray-400): Chevron icons, corner markers, decorative separators, and inactive controls. Use for short UI chrome only, not long text on white (contrast).
  • Heatmap scale (heatmap-*): Workout contribution cells only—from empty light gray through black for intensity; today’s cell may use an inset ring, not a fifth fill color.

Typography

  • Body: Inter, 400, comfortable line height (1.6 globally). This is the default for paragraphs, descriptions, and long-form prose.
  • Monospace stack (font-mono): Section titles (“Posts”, “Workouts”), profile name, post H1, breadcrumbs, meta lines (date:, read:), and small UI labels. Keeps the site feeling like structured logs or docs.
  • Weights: Semibold for card section titles and post H2 in prose; bold for profile name and post title; medium for list item titles.
  • Article prose: Use @tailwindcss/typography with the existing prose-gray overrides in src/pages/posts/[...slug].astro: headings monospace and gray-900, links underlined with gray decoration, blockquotes left border + gray-50 fill, tables with gray borders and mono table headers.

Layout

  • Canvas: Full-width neutral background; content centered with horizontal padding (px-4), vertical rhythm py-8 / md:py-12.
  • Home: max-w-7xl container; 3-column grid on large screens (profile column + two-column main), single column on small screens; consistent gap-4 between cards.
  • Posts list / post detail / workouts: max-w-4xl for reading width on article flows; breadcrumbs above the first card.
  • Cards: Prefer single white panel with p-6 (or md:p-8 / lg:p-12 for long article bodies). Headers often include a bottom rule (border-b border-gray-100 pb-4).
  • Spacing scale: Use Tailwind’s 4-based rhythm aligned to tokens: gap-4, p-6, mb-8, etc.; avoid arbitrary large gaps unless matching an existing page.

Elevation & Depth

  • No drop shadows on standard cards; depth comes from 1px borders and hover state (hover:border-gray-400).
  • Corner markers: Optional CornerMarkers—small L-shaped borders at card corners; use together with cards, not on plain divs.
  • Lightbox / overlays: Follow existing LightBox behavior; keep backdrop consistent with rest of site (do not introduce new blur tints without updating this doc).

Shapes

  • Corners: Default square (rounded-none) for cards, code blocks, and primary panels. Small rounded corners are acceptable only where already used (e.g. tiny badges, thought tags).
  • Borders: 1px solid gray-200 default; lighten to gray-100 for internal dividers; interactive rows use transparent border then hover:border-gray-200.

Components

  • Card (default): White background, border border-gray-200, p-6, relative, transition on border color; include CornerMarkers when the pattern matches profile/posts/workouts cards.
  • Card header: Flex row, space-between; title uses card-title token (mono, semibold); optional count badge text-sm bg-gray-100 text-gray-600 font-mono px-2 py-0.5.
  • List row (link): p-3, min-h-[3.25rem], hover bg-gray-50, optional border on hover; trailing chevron text-gray-400 with slight translate on hover.
  • Secondary button / footer link: bg-gray-100 text-gray-600, hover bg-gray-200 text-gray-900, font-mono, inline-flex with icon gap (see “View more” on posts).
  • Text link (muted): text-xs text-gray-400, underline with decoration-gray-200, hover to gray-600 and stronger decoration (workouts “View all”).
  • Tags: border border-gray-300 text-gray-600, hover darkens border and text to gray-900.
  • Status chips: Draft = gray-200/gray-600; WIP = amber-100/amber-700; align padding text-xs.
  • Heatmap cells: Four gray/black steps only; “today” uses inset ring; future days muted empty state.
  • Icons: Implement as small Astro components under src/components/icons/; stroke/fill colors follow muted / secondary, inheriting currentColor where possible.

Do’s and Don’ts

Do

  • Keep Inter + monospace split: prose body in Inter; UI chrome and headings in mono where the codebase already does.
  • Reuse gray border vocabulary (200 default, 100 dividers, 400 on card hover).
  • Match focus-visible to global outline (blue tint, 2px-equivalent offset).
  • Add new icons as dedicated Astro components in src/components/icons/.

Don’t

  • Don’t introduce dark mode or new primary hues in one-off components without updating tokens and this file.
  • Don’t default to heavy rounding or shadow-heavy cards; they conflict with the current editorial flat look.
  • Don’t use tertiary blue as large fills; it’s for focus/selection semantics.
  • Don’t paste inline SVG in random pages when an icon component pattern exists.