From 22e904a855817f419924a832b2b2e7b94fd41036 Mon Sep 17 00:00:00 2001 From: Adam Jolicoeur Date: Fri, 5 Jun 2026 14:56:57 -0400 Subject: [PATCH 1/2] chore: fix design system conflicts and add DESIGN.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing --earth-sand-light token to _variables.scss - Fix --border-radius-xl typo → --radius-xl in _cards.scss - Scope containers.scss blockquote under .prose-section to prevent global override - Remove dead .badge, .badge-accent, .divider from _components.scss (not imported) - Add DESIGN.md documenting all tokens, components, and layout patterns --- DESIGN.md | 292 ++++++++++++++++++++++++++++++++++++++ src/sass/_cards.scss | 2 +- src/sass/_components.scss | 25 ---- src/sass/_variables.scss | 1 + src/sass/containers.scss | 2 +- 5 files changed, 295 insertions(+), 27 deletions(-) create mode 100644 DESIGN.md diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 00000000..92196dfc --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,292 @@ +# Design System — Adam Jolicoeur Portfolio + +Source of truth for visual identity, tokens, and component patterns at adamjolicoeur.com. + +--- + +## Brand Identity + +**Site:** adamjolicoeur.com +**Owner:** Adam Jolicoeur — Lead Product Designer +**Tone:** Earth-toned, high-contrast, editorial. Brutal neo-craft aesthetic — thick borders, hard offset shadows, mixed serif/sans hierarchy. + +**Content pillars:** +- Design case studies (AWS, Red Hat, Component Assembly Systems) +- Development projects (open source tools, code examples) +- Professional content (resume, presentations, articles) +- App showcases (iOS/web applications) + +--- + +## Color Tokens + +Defined in `src/sass/_variables.scss`. + +| Token | Value | Role | +|-------|-------|------| +| `--white` | `#f0f0f0` | High-contrast white | +| `--black` | `#010101` | High-contrast black | +| `--earth-dark` | `#2d1f12` | Footer bg, deep shadow base | +| `--earth-brown` | `#4a3426` | Primary border color, text-secondary | +| `--earth-sage` | `#5a6b4f` | Badges, social links, secondary card shadow | +| `--earth-sand` | `#c9b89a` | Code bg, card section dividers | +| `--earth-sand-light` | `#e2d8c8` | Callout bg, prose blockquote bg | +| `--earth-cream` | `#f5f1e8` | Canvas bg, card bg | +| `--accent-coral` | `#d35f3d` | H2 underline bars, CTA highlights, skip-link | +| `--accent-coral-dark` | `#b34a2d` | Primary button bg | +| `--text-primary` | `#2d1f12` | All body and heading text | +| `--text-secondary` | `#4a3426` | Subtitles, lead paragraphs | +| `--text-muted` | `#6b5d52` | Captions, metadata | +| `--shadow` | `rgb(45,31,18,15%)` | Standard shadow | +| `--shadow-heavy` | `rgb(45,31,18,25%)` | Card offset shadows | +| `--shadow-light` | `rgb(45,31,18,8%)` | Subtle elevation | +| `--bg-canvas` | `var(--earth-cream)` | Alias for page background | +| `--border-brown` | `var(--earth-brown)` | Alias for primary border | + +--- + +## Typography + +Fonts loaded via Google Fonts. Defined in `src/sass/_variables.scss` and `src/sass/_typography.scss`. + +| Variable | Family | Use | +|----------|--------|-----| +| `--font-family-heading` | Pirata One | H1, `.text-display` — display/hero only | +| `--font-family-serif` | Playfair Display | H2–H4 — section headings | +| `--font-family-sans` | Inter | H5–H6, body, UI | +| `--font-family-mono` | Fira Code | `code`, `.code-block` | + +### Type Scale + +| Token | Value | px equiv | +|-------|-------|----------| +| `--font-size-xs` | `0.75rem` | 12px | +| `--font-size-sm` | `0.875rem` | 14px | +| `--font-size-md` | `1rem` | 16px | +| `--font-size-lg` | `1.125rem` | 18px | +| `--font-size-xl` | `1.25rem` | 20px | +| `--font-size-2xl` | `1.5rem` | 24px | +| `--font-size-3xl` | `2rem` | 32px | +| `--font-size-4xl` | `2.5rem` | 40px | +| `--font-size-5xl` | `3rem` | 48px | +| `--font-size-6xl` | `4rem` | 64px | + +### Heading Styles + +| Element | Font | Size | Notes | +|---------|------|------|-------| +| `h1` / `.text-display` | Pirata One | `clamp(2.5rem, 8vw, 5rem)` | `text-shadow: 3px 3px 0 coral` | +| `h2` | Playfair Display | `clamp(2rem, 5vw, 3rem)` | Coral underline bar (100px×5px) after element | +| `h3` | Playfair Display | `clamp(1.5rem, 3vw, 2rem)` | weight 600 | +| `h4` | Playfair Display | `clamp(1.25rem, 2.5vw, 1.5rem)` | weight 600 | +| `h5` | Inter | `clamp(1.1rem, 2vw, 1.25rem)` | weight 700 | +| `h6` | Inter | `1rem` | weight 700, uppercase, letter-spacing 0.5px | + +### Body & Utility Classes + +| Class | Size | Notes | +|-------|------|-------| +| `p` / `.text-body` | `clamp(0.95rem, 1.5vw, 1rem)` | line-height 1.7 | +| `.text-body-lg` | `clamp(1.1rem, 1.5vw, 1.25rem)` | line-height 1.7 | +| `.text-body-sm` | `clamp(0.85rem, 1.2vw, 0.9rem)` | line-height 1.6 | +| `.lead` / `.text-lead` | `clamp(1.1rem, 2vw, 1.35rem)` | color `--text-secondary` | +| `.text-caption` | `clamp(0.75rem, 1vw, 0.85rem)` | color `--text-muted` | +| `.text-callout` | `clamp(1rem, 1.5vw, 1.1rem)` | bg `--earth-sand-light`, left border coral | +| `.text-muted` | — | color `--text-muted` | +| `.text-secondary` | — | color `--text-secondary` | +| `.text-accent` | — | color `--accent-coral` | +| `.text-semibold` | — | weight 600 | +| `.text-bold` | — | weight 700 | +| `.text-center` | — | `text-align: center` | + +### Links + +Default: `--earth-sage`, 1px solid underline, weight 600. Hover: `--earth-brown`. +`.link-brackets` — decorative `[` `]` pseudo-elements that shift to coral on hover. + +--- + +## Spacing Tokens + +Defined in `src/sass/_variables.scss`. + +| Token | Value | px equiv | +|-------|-------|----------| +| `--space-2xs` | `0.25rem` | 4px | +| `--space-xs` | `0.5rem` | 8px | +| `--space-sm` | `0.75rem` | 12px | +| `--space-md` | `1rem` | 16px | +| `--space-lg` | `1.5rem` | 24px | +| `--space-xl` | `2rem` | 32px | +| `--space-2xl` | `3rem` | 48px | +| `--space-3xl` | `6rem` | 96px | + +Spacing utility classes (`.mb-1`–`.mb-5`, `.mt-`, `.ml-`, `.mr-`, `.p-`, `.pt-`, `.pb-`, `.pl-`, `.pr-`) map 1→`2xs`, 2→`xs`, 3→`sm`, 4→`md`, 5→`xl`. Defined in `src/sass/_spacing.scss`. + +--- + +## Shape Tokens + +Defined in `src/sass/_variables.scss`. + +### Border Radius + +| Token | Value | +|-------|-------| +| `--radius-sm` | `8px` | +| `--radius-md` | `12px` | +| `--radius-lg` | `16px` | +| `--radius-xl` | `20px` | +| `--radius-pill` | `50px` | + +### Border Widths + +| Token | Value | +|-------|-------| +| `--border-thin` | `2px` | +| `--border-medium` | `4px` | +| `--border-thick` | `6px` | +| `--border-extra-thick` | `8px` | + +--- + +## Components + +### Cards + +Defined in `src/sass/_cards.scss`. + +| Class | Border | Shadow | Radius | Use | +|-------|--------|--------|--------|-----| +| `.card` | `thick` `--earth-brown` | `8px 8px 0 shadow-heavy` (hover: 12px) | `radius-xl` | General content card | +| `.card-layered` | `thick` `--earth-brown` | sage+brown stacked offset | `radius-xl` | About section card | +| `.card-shadow` | none | `10px 10px 0 shadow-heavy` | `radius-lg` | Borderless elevated card | +| `.card-accent` | `extra-thick` `--earth-brown` | coral+brown stacked offset | `radius-xl` | High-emphasis card | +| `.card-image` | `medium` `--earth-brown` | `6px 6px 0 shadow-light` | `radius-xl` | Card with image top | +| `.showcase-large` | `thick` `--earth-brown` | coral+brown stacked offset | `radius-xl` | Featured work items | +| `.showcase-small` | `4px` `--earth-brown` | `6px 6px 0 shadow-heavy` | `radius-lg` | Small project cards | +| `.about-card` | `thick` `--earth-brown` | sage+brown stacked offset | `radius-xl` | About section wrapper | + +**Card anatomy classes:** `.card-header`, `.card-body`, `.card-footer` — each with `--space-md` padding/margin and `--earth-sand` border separator. + +**Layout helpers:** `.card-flex` (column flex, `p:flex 1 0`) for equal-height cards. `.card-with-columns` for multi-column card interior. + +### Buttons + +Defined in `src/sass/_buttons.scss`. + +| Class | Bg | Border | Shadow | Use | +|-------|----|--------|--------|-----| +| `.btn-primary` | `--accent-coral-dark` | `medium` `--earth-brown` | `4px 4px 0 earth-brown` | Primary CTA | +| `.btn-secondary` | `--earth-cream` | `medium` `--earth-brown` | `4px 4px 0 earth-sage` | Secondary action | +| `.btn-outline` | `white 50% / blur` | `medium` `--earth-brown` | none | Tertiary / on-image | + +All buttons: hover translates `(2px, 2px)` and collapses shadow to `2px`. +Size modifiers: `.btn-sm` (thin border, 0.9rem), `.btn-lg` (1.1rem, xl padding). + +### Badges + +Defined in `src/sass/_badge.scss`. + +| Class | Bg | Use | +|-------|----|-----| +| `.badge` | `--earth-sage` | Default tag/label | +| `.badge-accent` | `--accent-coral-dark` | Highlighted tag | +| `.badge-outline` | transparent | Inline label variant | + +`.badges` / `.row-badges` — flex row with `2xs` gap for badge groups. + +### Navigation + +Defined in `src/sass/_navigation.scss`. Floating pill nav: `position: fixed`, `top: 2rem`, centered via `left: 50% + translateX(-50%)`. Frosted glass bg (`earth-cream 50% / blur(24px)`), `medium` brown border, `radius-pill` shape. Active links: `--accent-coral`. Mobile (`≤768px`): reduced padding and gap. + +### Divider + +Defined in `src/sass/_layout.scss`. + +| Class | Shape | Use | +|-------|-------|-----| +| `.divider` | `50% wide × space-md tall`, coral bg, `medium outset earth-dark` border | Horizontal section break | +| `.divider.vertical` | `space-2xs wide × 100% tall`, earth-dark bg, no border | Vertical content separator | + +### Callouts (Testimonials) + +`.callout` — cream card, `thick` coral-dark border, `8px 8px 0 shadow-heavy`, `radius-xl`. Decorative `"` pseudo-element (Playfair Display, 4rem, coral). `.callout-text` italic body. `.callout-author` weight 600. `.callout-role` sm muted. + +### Badges & Tags + +`.badge` — pill shape (`radius-pill`), sage bg, cream text, `thin` brown border. + +--- + +## Layout + +Defined in `src/sass/_layout.scss` and `src/sass/_components.scss`. + +| Class | Pattern | +|-------|---------| +| `section` | `max-width: 1200px`, `margin: 0 auto`, `padding: space-3xl space-lg` | +| `.container` | `max-width: 1200px`, `padding: 0 space-lg` | +| `.container-narrow` | `max-width: 800px`, `padding: 0 space-lg` | +| `.work-grid` | CSS Grid, `auto-fit minmax(300px, 1fr)`, `space-lg` gap | +| `.about-grid` | CSS Grid, `auto-fit minmax(350px, 1fr)`, `space-xl` gap | +| `.callouts-grid` | CSS Grid, `auto-fit minmax(300px, 1fr)`, `2rem` gap | +| `.small-showcase-cards` | CSS Grid, `auto-fit minmax(250px, 1fr)`, `space-md` gap | +| `.row` | Flexbox wrap, `space-lg` gap (collapses to `space-sm` at 768px+) | +| `.cards-row` | Flex row wrap, `space-lg` gap (containers only) | +| `.section` | `padding: space-2xl space-lg` | +| `.section-lg` | `padding: space-3xl space-lg` | + +--- + +## Markdown Containers + +Opt-in via `containers: true` in page front matter. Loads `docs/css/containers.css`. Defined in `src/sass/containers.scss`. + +| Syntax | Class | Style | +|--------|-------|-------| +| `:::card` | `.card` | Standard card (see Cards) | +| `:::section` | `.prose-section` | Semantic section with spacing | +| `:::cards` | `.cards-row` | Flex row wrapper | +| `:::card-basic` | `.card-basic` | `--earth-sand` bg, 4px brown border, `radius-lg`, hard shadow | +| `:::card-shadow` | `.card-shadow` | Cream bg, borderless, `10px 10px 0 shadow-heavy` | + +Prose-scoped `blockquote` (within `.prose-section`): cream-sand bg, coral left border (`medium`), weight 600, full padding — overrides the global base style. + +--- + +## Footer + +Defined in `src/sass/_footer.scss`. Dark bg (`--earth-dark`), `extra-thick` brown top border. Grid layout (`auto-fit minmax(250px, 1fr)`). Section headings: Playfair Display, coral. Links: cream, underline, hover → coral. + +--- + +## Animation + +Defined in `src/sass/_animations.scss`. Arrow scroll indicator (`@keyframes arrow`, opacity pulse, 2s infinite). Card hover: `translateY(-5px)` with shadow expansion. Button hover: `translate(2px, 2px)` with shadow collapse. All animations disabled under `prefers-reduced-motion: reduce`. + +--- + +## Image Conventions + +- Source: `src/assets/img-raw/` (high-res originals) +- Output: `src/assets/img/` (Sharp-processed) +- Full-size: 1200px wide, WebP (80%) + JPEG (85%) +- Thumbnail: 300px wide, WebP (70%) + JPEG (75%) +- `.showcase-image` placeholder: `300px` tall, `135deg` gradient sage→sand, centers emoji/icon fallback +- `.showcase-image-dark`: black→earth-dark gradient variant + +--- + +## CSS Build + +| File | Output | Loaded | +|------|--------|--------| +| `src/sass/style.scss` | `docs/css/style.css` | All pages | +| `src/sass/containers.scss` | `docs/css/containers.css` | Pages with `containers: true` | +| `src/sass/markdown.scss` | `docs/css/markdown.css` | Markdown layout pages | +| `src/sass/print.scss` | `docs/css/print.css` | Print media | +| `src/sass/prism.scss` | `docs/css/prism.css` | Code syntax highlighting | +| `src/sass/slides.scss` | `docs/css/slides.css` | Presentation pages | + +Import order in `style.scss`: `variables` → `animations` → `fonts` → `typography` → `spacing` → `layout` → `lists` → `highlight` → `navigation` → `footer` → `badge` → `buttons` → `cards` → `gallery`. diff --git a/src/sass/_cards.scss b/src/sass/_cards.scss index 47032ab8..2bb40f96 100644 --- a/src/sass/_cards.scss +++ b/src/sass/_cards.scss @@ -151,7 +151,7 @@ background: var(--earth-cream); border: var(--border-thick, 6px) solid var(--earth-brown); padding: var(--space-2xl, 3rem); - border-radius: var(--border-radius-xl, 20px); + border-radius: var(--radius-xl, 20px); box-shadow: 12px 12px 0 var(--earth-sage), 12px 12px 0 5px var(--earth-brown); diff --git a/src/sass/_components.scss b/src/sass/_components.scss index 3f3e7280..210f94e7 100644 --- a/src/sass/_components.scss +++ b/src/sass/_components.scss @@ -1,28 +1,3 @@ -/* Badge */ -.badge { - display: inline-block; - padding: var(--space-2xs) var(--space-sm); - font-size: 0.85rem; - font-weight: 600; - background: var(--earth-sage); - color: var(--earth-cream); - border: var(--border-thin) solid var(--earth-brown); - border-radius: var(--radius-pill); -} - -.badge-accent { - background: var(--accent-coral); -} - -/* Divider */ -.divider { - width: 100px; - height: 5px; - background: var(--accent-coral); - border: var(--border-thin) solid var(--earth-brown); - margin: var(--space-lg) auto; -} - /* Container */ .container { max-width: 1200px; diff --git a/src/sass/_variables.scss b/src/sass/_variables.scss index 7e6fe02c..b419fe79 100644 --- a/src/sass/_variables.scss +++ b/src/sass/_variables.scss @@ -23,6 +23,7 @@ --earth-brown: #4a3426; --earth-sage: #5a6b4f; --earth-sand: #c9b89a; + --earth-sand-light: #e2d8c8; --earth-cream: #f5f1e8; --accent-coral: #d35f3d; --accent-coral-dark: #b34a2d; diff --git a/src/sass/containers.scss b/src/sass/containers.scss index 2f138a23..e2e924eb 100644 --- a/src/sass/containers.scss +++ b/src/sass/containers.scss @@ -72,7 +72,7 @@ section .card { border-bottom: var(--border-thin, 2px) solid var(--earth-brown); } -blockquote { +.prose-section blockquote { font-size: clamp(1rem, 1.5vw, 1.1rem); line-height: 1.6; font-weight: 600; From 0c70723dc6dfc69ecb00d4a5890fc68b85dae92a Mon Sep 17 00:00:00 2001 From: Adam Jolicoeur Date: Fri, 5 Jun 2026 18:45:47 -0400 Subject: [PATCH 2/2] docs: rewrite DESIGN.md for Stitch compatibility Convert DESIGN.md from table-based reference to Stitch-compatible YAML frontmatter + narrative design system document. Add .stitch/DESIGN.md with full color role mappings and component generation prompts. - Add lint:design script (design.md lint) - Update CLAUDE.md and README for pnpm migration - Update CHANGELOG with design system and open source page entries - Add git add/commit permissions to .claude/settings.local.json --- .claude/settings.local.json | 4 +- .stitch/DESIGN.md | 268 ++++++++++++++++++ CHANGELOG.md | 23 ++ CLAUDE.md | 54 ++-- DESIGN.md | 540 +++++++++++++++++------------------- README.md | 12 + package.json | 3 +- 7 files changed, 594 insertions(+), 310 deletions(-) create mode 100644 .stitch/DESIGN.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 6705be06..e07b9466 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,9 @@ "permissions": { "allow": [ "Bash(pnpm add *)", - "Bash(gh pr *)" + "Bash(gh pr *)", + "Bash(git add *)", + "Bash(git commit -m ' *)" ] } } diff --git a/.stitch/DESIGN.md b/.stitch/DESIGN.md new file mode 100644 index 00000000..c3e41109 --- /dev/null +++ b/.stitch/DESIGN.md @@ -0,0 +1,268 @@ +--- +name: Adam Jolicoeur Portfolio +colors: + surface: '#f5f1e8' + surface-dim: '#e2d8c8' + surface-bright: '#f5f1e8' + surface-container-lowest: '#f5f1e8' + surface-container-low: '#e2d8c8' + surface-container: '#c9b89a' + surface-container-high: '#4a3426' + surface-container-highest: '#2d1f12' + on-surface: '#2d1f12' + on-surface-variant: '#4a3426' + inverse-surface: '#2d1f12' + inverse-on-surface: '#f5f1e8' + outline: '#4a3426' + outline-variant: '#c9b89a' + surface-tint: '#5a6b4f' + primary: '#b34a2d' + on-primary: '#f0f0f0' + primary-container: '#d35f3d' + on-primary-container: '#f5f1e8' + inverse-primary: '#d35f3d' + secondary: '#5a6b4f' + on-secondary: '#f0f0f0' + secondary-container: '#e2d8c8' + on-secondary-container: '#2d1f12' + tertiary: '#4a3426' + on-tertiary: '#f5f1e8' + tertiary-container: '#c9b89a' + on-tertiary-container: '#2d1f12' + error: '#b34a2d' + on-error: '#f0f0f0' + error-container: '#e2d8c8' + on-error-container: '#2d1f12' + background: '#f5f1e8' + on-background: '#2d1f12' + surface-variant: '#e2d8c8' +typography: + display-lg: + fontFamily: Pirata One + fontSize: 80px + fontWeight: '400' + lineHeight: 88px + letterSpacing: 2px + headline-lg: + fontFamily: Pirata One + fontSize: 48px + fontWeight: '400' + lineHeight: 57px + letterSpacing: 2px + headline-md: + fontFamily: Playfair Display + fontSize: 36px + fontWeight: '700' + lineHeight: 47px + letterSpacing: 0 + headline-sm: + fontFamily: Playfair Display + fontSize: 28px + fontWeight: '600' + lineHeight: 36px + letterSpacing: 0 + title-lg: + fontFamily: Playfair Display + fontSize: 22px + fontWeight: '600' + lineHeight: 30px + letterSpacing: 0 + title-md: + fontFamily: Inter + fontSize: 18px + fontWeight: '700' + lineHeight: 25px + letterSpacing: 0 + title-sm: + fontFamily: Inter + fontSize: 16px + fontWeight: '700' + lineHeight: 22px + letterSpacing: 0.5px + body-lg: + fontFamily: Inter + fontSize: 18px + fontWeight: '400' + lineHeight: 30px + letterSpacing: 0 + body-md: + fontFamily: Inter + fontSize: 16px + fontWeight: '400' + lineHeight: 27px + letterSpacing: 0 + body-sm: + fontFamily: Inter + fontSize: 14px + fontWeight: '400' + lineHeight: 22px + letterSpacing: 0 + label-lg: + fontFamily: Inter + fontSize: 14px + fontWeight: '600' + lineHeight: 20px + letterSpacing: 0.5px + label-sm: + fontFamily: Inter + fontSize: 12px + fontWeight: '500' + lineHeight: 16px + letterSpacing: 0.5px +--- + +# Design System: Adam Jolicoeur Portfolio + +## 1. Visual Theme & Atmosphere + +This portfolio lives in the territory between artisan craft and digital precision. The palette is built entirely from warm earth tones — deep espresso browns, aged-parchment creams, muted olive sage, and terracotta coral — creating the feel of a hand-bound sketchbook or a well-worn design studio. Nothing is clinical or cold; every surface carries warmth. The overall mood is confident and distinctive: a designer who has a clear point of view and isn't afraid to show it. + +The aesthetic is deliberately neo-brutalist: thick 4–8px solid borders, hard-offset box shadows with no blur radius, and interactive elements that physically shift on hover (translateY). This isn't decoration — it communicates craft and intentionality. Sections breathe generously with 96px vertical padding, while cards cluster tightly within their grids. The floating pill-shaped navigation with a frosted-glass backdrop blur adds a single modern counterpoint to the otherwise tactile, grounded visual language. + +## 2. Color Palette & Roles + +### Primary Foundation +- **Aged Parchment** `#f5f1e8` — Main surface/background; the primary canvas for all content +- **Warm Linen** `#e2d8c8` — Secondary surface; section backgrounds, callout fills, card-basic +- **Desert Sand** `#c9b89a` — Tertiary surface; code backgrounds, showcase-small cards, muted fills +- **Near-Black** `#010101` — Absolute black; used sparingly for maximum contrast +- **Off-White** `#f0f0f0` — Text on dark surfaces; button labels on coral/dark backgrounds + +### Accent & Interactive +- **Terracotta** `#d35f3d` — Primary accent; H1 text-shadows, H2 underline decorators, hover states, skip-link +- **Deep Terracotta** `#b34a2d` — Primary CTA buttons; darker accent for increased contrast +- **Olive Sage** `#5a6b4f` — Social links, secondary shadows on card hover states, links/anchor colors + +### Typography & Text Hierarchy +- **Espresso** `#2d1f12` — Primary text color; same as `earth-dark`; all headings and body copy +- **Rich Brown** `#4a3426` — Secondary text; hero subtext, card secondary content; same as `earth-brown` +- **Warm Taupe** `#6b5d52` — Muted/caption text; metadata, captions, supplementary labels + +### Functional States +- **Dark Espresso** `#2d1f12` — Footer background (inverted surface) +- Shadows use `rgba(45, 31, 18, 0.25)` — heavy shadow for depth +- Shadows use `rgba(45, 31, 18, 0.15)` — standard shadow +- Shadows use `rgba(45, 31, 18, 0.08)` — light shadow + +## 3. Typography Rules + +### Font Families +- **Pirata One** (cursive/display) — Dramatic medieval-style display font used exclusively for H1 and `.text-display`. Evokes craft, personality, and a sense of history. The designer's signature typographic choice. +- **Playfair Display** (serif) — Editorial high-contrast serif for H2, H3, H4, footer section headings, and showcase card titles. Communicates authority and refinement. +- **Inter** (geometric sans-serif) — Workhorse for all body copy, H5, H6, navigation links, buttons, and UI labels. Optically sized, covers weights 400–900. +- **Fira Code** (monospace) — Code blocks and inline code only. + +### Hierarchy & Weights +| Level | Font | Size (clamp) | Weight | Special | +|-------|------|-------------|--------|---------| +| Display | Pirata One | 3–6rem | 400 | `text-shadow: 3px 3px 0 #d35f3d`, letter-spacing: 2px | +| H1 | Pirata One | 2.5–5rem | 400 | Same text-shadow treatment | +| H2 | Playfair Display | 2–3rem | 700 | Decorative 100×5px coral block underline with brown border | +| H3 | Playfair Display | 1.5–2rem | 600 | No underline decorator | +| H4 | Playfair Display | 1.25–1.5rem | 600 | No underline decorator | +| H5 | Inter | 1.1–1.25rem | 700 | No special treatment | +| H6 | Inter | 1rem | 700 | `text-transform: uppercase`, letter-spacing: 0.5px | +| Body | Inter | 0.95–1rem | 400 | line-height: 1.7 | +| Lead | Inter | 1.1–1.35rem | 400 | `color: text-secondary` | +| Caption | Inter | ~0.85rem | 400 | `color: text-muted` | + +### Spacing Principles +- Line-heights are generous on body text (1.7) for readability, tighter on display/headings (1.1–1.3) +- 2px letter-spacing on display type for dramatic theatrical effect +- 0.5px letter-spacing on H6 and uppercase labels for legibility +- Links use semibold (600) weight with bottom-border underline instead of text-decoration + +## 4. Component Stylings + +### Buttons +Buttons have 12px border-radius (radius-md), Inter font, semibold weight, and a signature hard-offset shadow system that shifts on interaction. + +- **Primary** — `#b34a2d` background, `#f0f0f0` text, 4px solid `#4a3426` border, `4px 4px 0 #4a3426` box-shadow. On hover: translates `(2px, 2px)` and shadow reduces to `2px 2px 0`. +- **Secondary** — Aged parchment `#f5f1e8` background, espresso text, 4px brown border, `4px 4px 0 #5a6b4f` shadow (sage). Hover darkens to sand and adds outline. +- **Outline** — 50% white with `backdrop-filter: blur(24px)` frosted glass, 4px brown border, no shadow. Hover: underline + cream text. +- **Social links** — `#5a6b4f` olive sage background, off-white text, 4px sand border, 8px radius. Hover: becomes terracotta, translates up 2px. +- **Sizes**: sm (padding 8px/16px, 0.9rem), default (12px/24px, 1rem), lg (16px/32px, 1.1rem) + +### Cards +Cards are the primary content vehicle — bold borders, hard shadows, generous rounding. + +- **Base Card** `.card` — Parchment bg, 6px solid brown border, 20px radius (radius-xl), 24px padding, `8px 8px 0 rgba(45,31,18,0.25)` shadow. Hover: `translateY(-5px)`, shadow extends to 12px. +- **Layered Card** `.card-layered` — Like base but with dual-layer shadow: `12px 12px 0 sage, 12px 12px 0 5px brown`. +- **Accent Card** `.card-accent` — 8px border, coral+brown dual shadow at 16px offset. Most dramatic variant. +- **Shadow Card** `.card-shadow` — No border, `10px 10px 0` shadow only. Softer option. +- **Showcase Large** `.showcase-large` — Full-width card with image well (300px height, sage→sand gradient), 6px border, coral+brown dual shadow, `translateY(-8px)` on hover. +- Card headers/footers use 2px sand border-top/bottom separators. + +### Navigation +Floating pill nav: `position: fixed/sticky`, centered, `background: rgba(245,241,232,0.5)` with `backdrop-filter: blur(24px)`. 4px brown border, 50px border-radius (true pill shape). Items spaced 2rem apart, Inter 0.95rem medium weight. Active state and hover both use terracotta color + outline. + +### Inputs & Forms +No dedicated form component file found. Code blocks use sand background `#c9b89a`, 12px radius (radius-md), 2px sage border. Inline code uses sand bg with 8px radius (radius-sm). + +### Portfolio/Case Study Components +- **Callout Card** `.callout` — Parchment bg, 6px deep-terracotta border, 20px radius, `8px 8px 0` shadow. Oversized Playfair Display `"` quote mark in coral positioned top-left. Right-aligned content. +- **Work Grid** `.work-grid` — CSS Grid, `auto-fit minmax(300px, 1fr)`, 2rem gap. +- **Divider** `.divider` — 50% width, terracotta fill, 4px outset dark-brown border. Horizontal rule as decorative element. +- **Callout Text Block** `.text-callout` — Sand-light background, 4px left coral border, semibold, generous margins/padding. + +## 5. Layout Principles + +### Grid & Structure +- **Max content width**: 1200px (`section`, `.container`, `.footer-content`) +- **Narrow content**: 800px (`.container-narrow`) for prose/article pages +- **Grid system**: CSS Grid with `auto-fit / minmax()` patterns — not fixed columns + - Work grid: `minmax(300px, 1fr)` + - About grid: `minmax(350px, 1fr)` + - Small showcase: `minmax(250px, 1fr)` + - Footer: `minmax(250px, 1fr)` +- **Flex rows**: `display: flex; flex-wrap: wrap; gap: 2rem` + +### Whitespace Strategy +- Base unit: 4px (`--space-2xs`) +- Section vertical padding: **96px** (`--space-3xl`) — extremely generous +- Section lateral padding: 24px (`--space-lg`) +- Card internal padding: 24px default, 32px for larger variants +- Spacing scale: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 96px + +### Alignment & Visual Balance +- Section content centered with `max-width + margin: 0 auto` +- H2 decorative underline centered with `margin: 1rem auto` +- Hero text centered; body content left-aligned +- Footer uses CSS Grid for balanced multi-column layout + +### Responsive Behavior & Touch +- Breakpoint: 768px (mobile/desktop boundary) +- Mobile nav: reduces padding, compresses to tighter horizontal fit +- Cards: grids collapse naturally via `auto-fit/minmax` +- About card: switches to single column, reduces shadow and padding +- Showcase large: reduces shadow offset on mobile +- Font sizes: all use `clamp()` for fluid scaling — no hard breakpoints in typography + +## 6. Design System Notes for Stitch Generation + +### Language to Use +Describe screens as: *warm, earthy, crafted, neo-brutalist, artisanal, portfolio-grade, high-contrast, parchment-toned, bold-bordered, tactile*. Avoid clinical or sterile descriptors. Think: "a designer's sketchbook brought to the web." + +### Color References +- Canvas/background: Aged Parchment `#f5f1e8` +- Primary CTA: Deep Terracotta `#b34a2d` +- Accent/highlight: Terracotta `#d35f3d` +- Borders & outlines: Rich Brown `#4a3426` +- Secondary/links: Olive Sage `#5a6b4f` +- Body text: Espresso `#2d1f12` +- Secondary text: Rich Brown `#4a3426` +- Dark surface (footer): Dark Espresso `#2d1f12` + +### Component Prompts +- *"Portfolio card with thick brown border, terracotta drop shadow, parchment background, Playfair Display heading, and hover lift effect"* +- *"CTA button in deep terracotta with 4px brown border, hard offset shadow, semi-bold Inter text, 12px radius"* +- *"Floating pill navigation bar with frosted glass backdrop blur, parchment tint, brown border, centered links in Inter medium"* +- *"Case study hero with Pirata One display heading, terracotta text-shadow, centered on parchment, with a Playfair Display subtitle in secondary brown"* +- *"Dark footer with espresso background, coral section headings, cream body text, multi-column grid layout"* + +### Incremental Iteration +- Start screens on parchment `#f5f1e8` — never white or gray +- Apply borders before shadows — the border defines the component shape +- Use `translateY(-5px)` lift on card hover, never scale transforms +- H2 always needs its coral underline block — it's a signature element +- Shadow style is always flat/hard-offset (no blur radius), not soft/diffuse diff --git a/CHANGELOG.md b/CHANGELOG.md index 38408a06..30fede9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,29 @@ All notable changes to this project will be documented in this file. ### Added +- Design system document (`.stitch/DESIGN.md`) extracted from source SCSS + — `.stitch/DESIGN.md` + (Stitch-compatible design system with YAML frontmatter color/typography tokens; covers earth-tone palette, neo-brutalist component patterns, layout principles, and Stitch generation prompts) + +- Design system overview (`DESIGN.md`) at project root + — `DESIGN.md`, `src/sass/_variables.scss`, `src/sass/_typography.scss`, `src/sass/_cards.scss`, `src/sass/_buttons.scss`, `src/sass/_navigation.scss` + (warm earth-tone palette with CSS custom properties; Pirata One/Playfair Display/Inter type hierarchy; neo-brutalist borders/hard-offset shadows) + +- Open Source page + — `src/pages/open-source/index.md` + (dedicated page for open source contributions and projects) + +### Changed + +- Package manager migrated from NPM to PNPM + — `package.json`, `pnpm-lock.yaml` (replaces `package-lock.json`) + (`preinstall` guard enforces pnpm via `only-allow`; all install/run commands now use `pnpm`) + +- Version bumped to 11.4.1 (was 10.0.2 per prior docs) + — `package.json` + +### Added (prior) + - TimeTracker Pro case study page for the Weekly Report AI feature — `src/pages/development/timetracker.md`, `src/assets/img/timetracker-*.{webp,jpg}`, `src/assets/img-raw/timetracker-*.png` (full case study covering design decisions, two-panel layout, tone selection, and AI prompt architecture; 8 screenshots with full-size + thumbnail variants) diff --git a/CLAUDE.md b/CLAUDE.md index 4c30e67b..4c3ae099 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,10 +6,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Portfolio website for Adam Jolicoeur (adamjolicoeur.com) built with Eleventy (11ty) static site generator. The site showcases UX/UI design work, development projects, and professional content. Deployed to GitHub Pages from the `docs/` directory. -**Current Version**: 10.0.2 +**Current Version**: 11.4.1 **Repository**: https://github.com/AdamJ/adamj.github.io **Live Site**: https://adamjolicoeur.com -**Node.js**: v25.2.1 required (runs on 20+, see `.nvmrc`) +**Node.js**: v25.9.0 required (runs on 20+, see `.nvmrc`) +**Package Manager**: pnpm (enforced — `npm install` is blocked by `preinstall` guard) ## Critical Build Commands @@ -18,30 +19,30 @@ All commands include expected timings. **NEVER CANCEL** builds—they complete w ### Development Workflow ```bash # Initial setup (first time only) -npm install # 60 seconds - installs dependencies +pnpm install # 60 seconds - installs dependencies # Start development server -npm run start # Starts watchers + BrowserSync on http://localhost:8081 +pnpm run start # Starts watchers + BrowserSync on http://localhost:8081 # NOT port 8080 - this is hardcoded # Full production build -npm run build # 20 seconds - runs all build steps in sequence +pnpm run build # 20 seconds - runs all build steps in sequence ``` ### Individual Build Steps ```bash -npm run clean # 1 second - removes docs/ directory -npm run images:optimize # 14 seconds - processes images with Sharp -npm run build:sass # 2 seconds - compiles SCSS to CSS -npm run build:eleventy # 2 seconds - static site generation -npm run postbuild # Auto-runs after build (Autoprefixer + CSSNano) +pnpm run clean # 1 second - removes docs/ directory +pnpm run images:optimize # 14 seconds - processes images with Sharp +pnpm run build:sass # 2 seconds - compiles SCSS to CSS +pnpm run build:eleventy # 2 seconds - static site generation +pnpm run postbuild # Auto-runs after build (Autoprefixer + CSSNano) ``` ### Linting & Validation ```bash -npm run lint # 5 seconds - Stylelint check (expect 176+ legacy errors) -npm run lint:fix # Auto-fix Stylelint issues -npm run webhint # 30 seconds - accessibility/performance audit +pnpm run lint # 5 seconds - Stylelint check (expect 176+ legacy errors) +pnpm run lint:fix # Auto-fix Stylelint issues +pnpm run webhint # 30 seconds - accessibility/performance audit ``` **Expected Build Warnings (Safe to Ignore)**: @@ -128,7 +129,7 @@ scripts/ ### Image Processing Pipeline 1. Place originals in `src/assets/img-raw/` (high-res source) -2. Run `npm run images:optimize` (14 seconds) +2. Run `pnpm run images:optimize` (14 seconds) 3. Sharp generates: - Full-size: 1200px width, WebP (80%) + JPEG (85%) - Thumbnail: 300px width, WebP (70%) + JPEG (75%) @@ -178,7 +179,7 @@ categories: [development, design] 1. Create subfolder in `src/pages/designs/` 2. Add `index.md` with front matter 3. Place images in `src/assets/img-raw/[project-name]/` -4. Run `npm run images:optimize` +4. Run `pnpm run images:optimize` ### Modify Site Navigation Edit `eleventyNavigation` in page front matter: @@ -219,7 +220,7 @@ To add new container types: add `md.use(markdownItContainer, 'name', { render... ### CSS Build Process - **Development**: Auto-compiles entire `src/sass/` → `docs/css/` via `watch:sass` -- **Production**: `npm run build:sass` compiles entire `src/sass/` → `docs/css/` → PostCSS → minified +- **Production**: `pnpm run build:sass` compiles entire `src/sass/` → `docs/css/` → PostCSS → minified - **Output**: `docs/css/style.css` (main bundle), `docs/css/containers.css`, `docs/css/markdown.css`, etc. ## Environment Variables @@ -234,8 +235,8 @@ To add new container types: add `md.use(markdownItContainer, 'name', { render... 2. **Node.js**: v25.x 3. **Steps**: - Checkout code - - `npm ci` (with Font Awesome token) - - `npm run build` + - `pnpm install` (with Font Awesome token) + - `pnpm run build` - Deploy `docs/` to `gh-pages` branch 4. **Live Site**: Auto-deploys to GitHub Pages @@ -269,7 +270,7 @@ To add new container types: add `md.use(markdownItContainer, 'name', { render... ```bash # 1. Place original files in src/assets/img-raw/ # 2. Process with Sharp -npm run images:optimize # 14 seconds +pnpm run images:optimize # 14 seconds # 3. Reference in templates with Eleventy Image filter # Generated files appear in src/assets/img/ @@ -286,7 +287,7 @@ Edit `eleventyNavigation` in page front matter (see "Adding Content" above) ### Test Responsive Design ```bash -npm run start # Opens BrowserSync on :8081 +pnpm run start # Opens BrowserSync on :8081 # Resize browser window or use DevTools device emulation ``` @@ -304,7 +305,7 @@ After changes, ALWAYS test: ### Quick Validation Commands ```bash # Verify site builds and serves -npm run build && npm run start & +pnpm run build && pnpm run start & # Check key files exist ls -la docs/css/style.css # Main CSS (~98KB) @@ -320,17 +321,17 @@ curl -I http://localhost:8081/designs/ # Should return 200 OK ### Common Issues - **Build hangs during image optimization**: Check `src/assets/img-raw/` for valid images - **Port 8081 in use**: Kill existing process or change port in `package.json` -- **Missing Sharp module**: Run `npm install` again (CPU architecture specific) +- **Missing Sharp module**: Run `pnpm install` again (CPU architecture specific) - **CSS not updating**: Clear browser cache, check Sass compilation warnings - **404 on navigation**: Verify Eleventy generated HTML in `docs/` ### Recovery Commands ```bash # Nuclear option - clean restart -npm run clean +pnpm run clean rm -rf node_modules -npm install -npm run build +pnpm install +pnpm run build # Verify build output ls -la docs/ @@ -342,7 +343,8 @@ ls -la docs/assets/img/ **Core**: - Eleventy (11ty) v3.1.2 - Static site generator -- Node.js v25.2.1 (runs on 20+) +- Node.js v25.9.0 (runs on 20+) +- pnpm - Package manager (enforced; npm blocked by preinstall guard) - Nunjucks + Liquid - Templating - Markdown + YAML - Content format diff --git a/DESIGN.md b/DESIGN.md index 92196dfc..c3e41109 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,292 +1,268 @@ -# Design System — Adam Jolicoeur Portfolio - -Source of truth for visual identity, tokens, and component patterns at adamjolicoeur.com. - --- - -## Brand Identity - -**Site:** adamjolicoeur.com -**Owner:** Adam Jolicoeur — Lead Product Designer -**Tone:** Earth-toned, high-contrast, editorial. Brutal neo-craft aesthetic — thick borders, hard offset shadows, mixed serif/sans hierarchy. - -**Content pillars:** -- Design case studies (AWS, Red Hat, Component Assembly Systems) -- Development projects (open source tools, code examples) -- Professional content (resume, presentations, articles) -- App showcases (iOS/web applications) - ---- - -## Color Tokens - -Defined in `src/sass/_variables.scss`. - -| Token | Value | Role | -|-------|-------|------| -| `--white` | `#f0f0f0` | High-contrast white | -| `--black` | `#010101` | High-contrast black | -| `--earth-dark` | `#2d1f12` | Footer bg, deep shadow base | -| `--earth-brown` | `#4a3426` | Primary border color, text-secondary | -| `--earth-sage` | `#5a6b4f` | Badges, social links, secondary card shadow | -| `--earth-sand` | `#c9b89a` | Code bg, card section dividers | -| `--earth-sand-light` | `#e2d8c8` | Callout bg, prose blockquote bg | -| `--earth-cream` | `#f5f1e8` | Canvas bg, card bg | -| `--accent-coral` | `#d35f3d` | H2 underline bars, CTA highlights, skip-link | -| `--accent-coral-dark` | `#b34a2d` | Primary button bg | -| `--text-primary` | `#2d1f12` | All body and heading text | -| `--text-secondary` | `#4a3426` | Subtitles, lead paragraphs | -| `--text-muted` | `#6b5d52` | Captions, metadata | -| `--shadow` | `rgb(45,31,18,15%)` | Standard shadow | -| `--shadow-heavy` | `rgb(45,31,18,25%)` | Card offset shadows | -| `--shadow-light` | `rgb(45,31,18,8%)` | Subtle elevation | -| `--bg-canvas` | `var(--earth-cream)` | Alias for page background | -| `--border-brown` | `var(--earth-brown)` | Alias for primary border | - +name: Adam Jolicoeur Portfolio +colors: + surface: '#f5f1e8' + surface-dim: '#e2d8c8' + surface-bright: '#f5f1e8' + surface-container-lowest: '#f5f1e8' + surface-container-low: '#e2d8c8' + surface-container: '#c9b89a' + surface-container-high: '#4a3426' + surface-container-highest: '#2d1f12' + on-surface: '#2d1f12' + on-surface-variant: '#4a3426' + inverse-surface: '#2d1f12' + inverse-on-surface: '#f5f1e8' + outline: '#4a3426' + outline-variant: '#c9b89a' + surface-tint: '#5a6b4f' + primary: '#b34a2d' + on-primary: '#f0f0f0' + primary-container: '#d35f3d' + on-primary-container: '#f5f1e8' + inverse-primary: '#d35f3d' + secondary: '#5a6b4f' + on-secondary: '#f0f0f0' + secondary-container: '#e2d8c8' + on-secondary-container: '#2d1f12' + tertiary: '#4a3426' + on-tertiary: '#f5f1e8' + tertiary-container: '#c9b89a' + on-tertiary-container: '#2d1f12' + error: '#b34a2d' + on-error: '#f0f0f0' + error-container: '#e2d8c8' + on-error-container: '#2d1f12' + background: '#f5f1e8' + on-background: '#2d1f12' + surface-variant: '#e2d8c8' +typography: + display-lg: + fontFamily: Pirata One + fontSize: 80px + fontWeight: '400' + lineHeight: 88px + letterSpacing: 2px + headline-lg: + fontFamily: Pirata One + fontSize: 48px + fontWeight: '400' + lineHeight: 57px + letterSpacing: 2px + headline-md: + fontFamily: Playfair Display + fontSize: 36px + fontWeight: '700' + lineHeight: 47px + letterSpacing: 0 + headline-sm: + fontFamily: Playfair Display + fontSize: 28px + fontWeight: '600' + lineHeight: 36px + letterSpacing: 0 + title-lg: + fontFamily: Playfair Display + fontSize: 22px + fontWeight: '600' + lineHeight: 30px + letterSpacing: 0 + title-md: + fontFamily: Inter + fontSize: 18px + fontWeight: '700' + lineHeight: 25px + letterSpacing: 0 + title-sm: + fontFamily: Inter + fontSize: 16px + fontWeight: '700' + lineHeight: 22px + letterSpacing: 0.5px + body-lg: + fontFamily: Inter + fontSize: 18px + fontWeight: '400' + lineHeight: 30px + letterSpacing: 0 + body-md: + fontFamily: Inter + fontSize: 16px + fontWeight: '400' + lineHeight: 27px + letterSpacing: 0 + body-sm: + fontFamily: Inter + fontSize: 14px + fontWeight: '400' + lineHeight: 22px + letterSpacing: 0 + label-lg: + fontFamily: Inter + fontSize: 14px + fontWeight: '600' + lineHeight: 20px + letterSpacing: 0.5px + label-sm: + fontFamily: Inter + fontSize: 12px + fontWeight: '500' + lineHeight: 16px + letterSpacing: 0.5px --- -## Typography - -Fonts loaded via Google Fonts. Defined in `src/sass/_variables.scss` and `src/sass/_typography.scss`. - -| Variable | Family | Use | -|----------|--------|-----| -| `--font-family-heading` | Pirata One | H1, `.text-display` — display/hero only | -| `--font-family-serif` | Playfair Display | H2–H4 — section headings | -| `--font-family-sans` | Inter | H5–H6, body, UI | -| `--font-family-mono` | Fira Code | `code`, `.code-block` | - -### Type Scale - -| Token | Value | px equiv | -|-------|-------|----------| -| `--font-size-xs` | `0.75rem` | 12px | -| `--font-size-sm` | `0.875rem` | 14px | -| `--font-size-md` | `1rem` | 16px | -| `--font-size-lg` | `1.125rem` | 18px | -| `--font-size-xl` | `1.25rem` | 20px | -| `--font-size-2xl` | `1.5rem` | 24px | -| `--font-size-3xl` | `2rem` | 32px | -| `--font-size-4xl` | `2.5rem` | 40px | -| `--font-size-5xl` | `3rem` | 48px | -| `--font-size-6xl` | `4rem` | 64px | - -### Heading Styles - -| Element | Font | Size | Notes | -|---------|------|------|-------| -| `h1` / `.text-display` | Pirata One | `clamp(2.5rem, 8vw, 5rem)` | `text-shadow: 3px 3px 0 coral` | -| `h2` | Playfair Display | `clamp(2rem, 5vw, 3rem)` | Coral underline bar (100px×5px) after element | -| `h3` | Playfair Display | `clamp(1.5rem, 3vw, 2rem)` | weight 600 | -| `h4` | Playfair Display | `clamp(1.25rem, 2.5vw, 1.5rem)` | weight 600 | -| `h5` | Inter | `clamp(1.1rem, 2vw, 1.25rem)` | weight 700 | -| `h6` | Inter | `1rem` | weight 700, uppercase, letter-spacing 0.5px | - -### Body & Utility Classes - -| Class | Size | Notes | -|-------|------|-------| -| `p` / `.text-body` | `clamp(0.95rem, 1.5vw, 1rem)` | line-height 1.7 | -| `.text-body-lg` | `clamp(1.1rem, 1.5vw, 1.25rem)` | line-height 1.7 | -| `.text-body-sm` | `clamp(0.85rem, 1.2vw, 0.9rem)` | line-height 1.6 | -| `.lead` / `.text-lead` | `clamp(1.1rem, 2vw, 1.35rem)` | color `--text-secondary` | -| `.text-caption` | `clamp(0.75rem, 1vw, 0.85rem)` | color `--text-muted` | -| `.text-callout` | `clamp(1rem, 1.5vw, 1.1rem)` | bg `--earth-sand-light`, left border coral | -| `.text-muted` | — | color `--text-muted` | -| `.text-secondary` | — | color `--text-secondary` | -| `.text-accent` | — | color `--accent-coral` | -| `.text-semibold` | — | weight 600 | -| `.text-bold` | — | weight 700 | -| `.text-center` | — | `text-align: center` | - -### Links - -Default: `--earth-sage`, 1px solid underline, weight 600. Hover: `--earth-brown`. -`.link-brackets` — decorative `[` `]` pseudo-elements that shift to coral on hover. - ---- - -## Spacing Tokens - -Defined in `src/sass/_variables.scss`. - -| Token | Value | px equiv | -|-------|-------|----------| -| `--space-2xs` | `0.25rem` | 4px | -| `--space-xs` | `0.5rem` | 8px | -| `--space-sm` | `0.75rem` | 12px | -| `--space-md` | `1rem` | 16px | -| `--space-lg` | `1.5rem` | 24px | -| `--space-xl` | `2rem` | 32px | -| `--space-2xl` | `3rem` | 48px | -| `--space-3xl` | `6rem` | 96px | - -Spacing utility classes (`.mb-1`–`.mb-5`, `.mt-`, `.ml-`, `.mr-`, `.p-`, `.pt-`, `.pb-`, `.pl-`, `.pr-`) map 1→`2xs`, 2→`xs`, 3→`sm`, 4→`md`, 5→`xl`. Defined in `src/sass/_spacing.scss`. - ---- - -## Shape Tokens - -Defined in `src/sass/_variables.scss`. - -### Border Radius - -| Token | Value | -|-------|-------| -| `--radius-sm` | `8px` | -| `--radius-md` | `12px` | -| `--radius-lg` | `16px` | -| `--radius-xl` | `20px` | -| `--radius-pill` | `50px` | - -### Border Widths - -| Token | Value | -|-------|-------| -| `--border-thin` | `2px` | -| `--border-medium` | `4px` | -| `--border-thick` | `6px` | -| `--border-extra-thick` | `8px` | - ---- - -## Components - -### Cards - -Defined in `src/sass/_cards.scss`. - -| Class | Border | Shadow | Radius | Use | -|-------|--------|--------|--------|-----| -| `.card` | `thick` `--earth-brown` | `8px 8px 0 shadow-heavy` (hover: 12px) | `radius-xl` | General content card | -| `.card-layered` | `thick` `--earth-brown` | sage+brown stacked offset | `radius-xl` | About section card | -| `.card-shadow` | none | `10px 10px 0 shadow-heavy` | `radius-lg` | Borderless elevated card | -| `.card-accent` | `extra-thick` `--earth-brown` | coral+brown stacked offset | `radius-xl` | High-emphasis card | -| `.card-image` | `medium` `--earth-brown` | `6px 6px 0 shadow-light` | `radius-xl` | Card with image top | -| `.showcase-large` | `thick` `--earth-brown` | coral+brown stacked offset | `radius-xl` | Featured work items | -| `.showcase-small` | `4px` `--earth-brown` | `6px 6px 0 shadow-heavy` | `radius-lg` | Small project cards | -| `.about-card` | `thick` `--earth-brown` | sage+brown stacked offset | `radius-xl` | About section wrapper | - -**Card anatomy classes:** `.card-header`, `.card-body`, `.card-footer` — each with `--space-md` padding/margin and `--earth-sand` border separator. - -**Layout helpers:** `.card-flex` (column flex, `p:flex 1 0`) for equal-height cards. `.card-with-columns` for multi-column card interior. +# Design System: Adam Jolicoeur Portfolio + +## 1. Visual Theme & Atmosphere + +This portfolio lives in the territory between artisan craft and digital precision. The palette is built entirely from warm earth tones — deep espresso browns, aged-parchment creams, muted olive sage, and terracotta coral — creating the feel of a hand-bound sketchbook or a well-worn design studio. Nothing is clinical or cold; every surface carries warmth. The overall mood is confident and distinctive: a designer who has a clear point of view and isn't afraid to show it. + +The aesthetic is deliberately neo-brutalist: thick 4–8px solid borders, hard-offset box shadows with no blur radius, and interactive elements that physically shift on hover (translateY). This isn't decoration — it communicates craft and intentionality. Sections breathe generously with 96px vertical padding, while cards cluster tightly within their grids. The floating pill-shaped navigation with a frosted-glass backdrop blur adds a single modern counterpoint to the otherwise tactile, grounded visual language. + +## 2. Color Palette & Roles + +### Primary Foundation +- **Aged Parchment** `#f5f1e8` — Main surface/background; the primary canvas for all content +- **Warm Linen** `#e2d8c8` — Secondary surface; section backgrounds, callout fills, card-basic +- **Desert Sand** `#c9b89a` — Tertiary surface; code backgrounds, showcase-small cards, muted fills +- **Near-Black** `#010101` — Absolute black; used sparingly for maximum contrast +- **Off-White** `#f0f0f0` — Text on dark surfaces; button labels on coral/dark backgrounds + +### Accent & Interactive +- **Terracotta** `#d35f3d` — Primary accent; H1 text-shadows, H2 underline decorators, hover states, skip-link +- **Deep Terracotta** `#b34a2d` — Primary CTA buttons; darker accent for increased contrast +- **Olive Sage** `#5a6b4f` — Social links, secondary shadows on card hover states, links/anchor colors + +### Typography & Text Hierarchy +- **Espresso** `#2d1f12` — Primary text color; same as `earth-dark`; all headings and body copy +- **Rich Brown** `#4a3426` — Secondary text; hero subtext, card secondary content; same as `earth-brown` +- **Warm Taupe** `#6b5d52` — Muted/caption text; metadata, captions, supplementary labels + +### Functional States +- **Dark Espresso** `#2d1f12` — Footer background (inverted surface) +- Shadows use `rgba(45, 31, 18, 0.25)` — heavy shadow for depth +- Shadows use `rgba(45, 31, 18, 0.15)` — standard shadow +- Shadows use `rgba(45, 31, 18, 0.08)` — light shadow + +## 3. Typography Rules + +### Font Families +- **Pirata One** (cursive/display) — Dramatic medieval-style display font used exclusively for H1 and `.text-display`. Evokes craft, personality, and a sense of history. The designer's signature typographic choice. +- **Playfair Display** (serif) — Editorial high-contrast serif for H2, H3, H4, footer section headings, and showcase card titles. Communicates authority and refinement. +- **Inter** (geometric sans-serif) — Workhorse for all body copy, H5, H6, navigation links, buttons, and UI labels. Optically sized, covers weights 400–900. +- **Fira Code** (monospace) — Code blocks and inline code only. + +### Hierarchy & Weights +| Level | Font | Size (clamp) | Weight | Special | +|-------|------|-------------|--------|---------| +| Display | Pirata One | 3–6rem | 400 | `text-shadow: 3px 3px 0 #d35f3d`, letter-spacing: 2px | +| H1 | Pirata One | 2.5–5rem | 400 | Same text-shadow treatment | +| H2 | Playfair Display | 2–3rem | 700 | Decorative 100×5px coral block underline with brown border | +| H3 | Playfair Display | 1.5–2rem | 600 | No underline decorator | +| H4 | Playfair Display | 1.25–1.5rem | 600 | No underline decorator | +| H5 | Inter | 1.1–1.25rem | 700 | No special treatment | +| H6 | Inter | 1rem | 700 | `text-transform: uppercase`, letter-spacing: 0.5px | +| Body | Inter | 0.95–1rem | 400 | line-height: 1.7 | +| Lead | Inter | 1.1–1.35rem | 400 | `color: text-secondary` | +| Caption | Inter | ~0.85rem | 400 | `color: text-muted` | + +### Spacing Principles +- Line-heights are generous on body text (1.7) for readability, tighter on display/headings (1.1–1.3) +- 2px letter-spacing on display type for dramatic theatrical effect +- 0.5px letter-spacing on H6 and uppercase labels for legibility +- Links use semibold (600) weight with bottom-border underline instead of text-decoration + +## 4. Component Stylings ### Buttons +Buttons have 12px border-radius (radius-md), Inter font, semibold weight, and a signature hard-offset shadow system that shifts on interaction. -Defined in `src/sass/_buttons.scss`. - -| Class | Bg | Border | Shadow | Use | -|-------|----|--------|--------|-----| -| `.btn-primary` | `--accent-coral-dark` | `medium` `--earth-brown` | `4px 4px 0 earth-brown` | Primary CTA | -| `.btn-secondary` | `--earth-cream` | `medium` `--earth-brown` | `4px 4px 0 earth-sage` | Secondary action | -| `.btn-outline` | `white 50% / blur` | `medium` `--earth-brown` | none | Tertiary / on-image | - -All buttons: hover translates `(2px, 2px)` and collapses shadow to `2px`. -Size modifiers: `.btn-sm` (thin border, 0.9rem), `.btn-lg` (1.1rem, xl padding). +- **Primary** — `#b34a2d` background, `#f0f0f0` text, 4px solid `#4a3426` border, `4px 4px 0 #4a3426` box-shadow. On hover: translates `(2px, 2px)` and shadow reduces to `2px 2px 0`. +- **Secondary** — Aged parchment `#f5f1e8` background, espresso text, 4px brown border, `4px 4px 0 #5a6b4f` shadow (sage). Hover darkens to sand and adds outline. +- **Outline** — 50% white with `backdrop-filter: blur(24px)` frosted glass, 4px brown border, no shadow. Hover: underline + cream text. +- **Social links** — `#5a6b4f` olive sage background, off-white text, 4px sand border, 8px radius. Hover: becomes terracotta, translates up 2px. +- **Sizes**: sm (padding 8px/16px, 0.9rem), default (12px/24px, 1rem), lg (16px/32px, 1.1rem) -### Badges - -Defined in `src/sass/_badge.scss`. - -| Class | Bg | Use | -|-------|----|-----| -| `.badge` | `--earth-sage` | Default tag/label | -| `.badge-accent` | `--accent-coral-dark` | Highlighted tag | -| `.badge-outline` | transparent | Inline label variant | +### Cards +Cards are the primary content vehicle — bold borders, hard shadows, generous rounding. -`.badges` / `.row-badges` — flex row with `2xs` gap for badge groups. +- **Base Card** `.card` — Parchment bg, 6px solid brown border, 20px radius (radius-xl), 24px padding, `8px 8px 0 rgba(45,31,18,0.25)` shadow. Hover: `translateY(-5px)`, shadow extends to 12px. +- **Layered Card** `.card-layered` — Like base but with dual-layer shadow: `12px 12px 0 sage, 12px 12px 0 5px brown`. +- **Accent Card** `.card-accent` — 8px border, coral+brown dual shadow at 16px offset. Most dramatic variant. +- **Shadow Card** `.card-shadow` — No border, `10px 10px 0` shadow only. Softer option. +- **Showcase Large** `.showcase-large` — Full-width card with image well (300px height, sage→sand gradient), 6px border, coral+brown dual shadow, `translateY(-8px)` on hover. +- Card headers/footers use 2px sand border-top/bottom separators. ### Navigation - -Defined in `src/sass/_navigation.scss`. Floating pill nav: `position: fixed`, `top: 2rem`, centered via `left: 50% + translateX(-50%)`. Frosted glass bg (`earth-cream 50% / blur(24px)`), `medium` brown border, `radius-pill` shape. Active links: `--accent-coral`. Mobile (`≤768px`): reduced padding and gap. - -### Divider - -Defined in `src/sass/_layout.scss`. - -| Class | Shape | Use | -|-------|-------|-----| -| `.divider` | `50% wide × space-md tall`, coral bg, `medium outset earth-dark` border | Horizontal section break | -| `.divider.vertical` | `space-2xs wide × 100% tall`, earth-dark bg, no border | Vertical content separator | - -### Callouts (Testimonials) - -`.callout` — cream card, `thick` coral-dark border, `8px 8px 0 shadow-heavy`, `radius-xl`. Decorative `"` pseudo-element (Playfair Display, 4rem, coral). `.callout-text` italic body. `.callout-author` weight 600. `.callout-role` sm muted. - -### Badges & Tags - -`.badge` — pill shape (`radius-pill`), sage bg, cream text, `thin` brown border. - ---- - -## Layout - -Defined in `src/sass/_layout.scss` and `src/sass/_components.scss`. - -| Class | Pattern | -|-------|---------| -| `section` | `max-width: 1200px`, `margin: 0 auto`, `padding: space-3xl space-lg` | -| `.container` | `max-width: 1200px`, `padding: 0 space-lg` | -| `.container-narrow` | `max-width: 800px`, `padding: 0 space-lg` | -| `.work-grid` | CSS Grid, `auto-fit minmax(300px, 1fr)`, `space-lg` gap | -| `.about-grid` | CSS Grid, `auto-fit minmax(350px, 1fr)`, `space-xl` gap | -| `.callouts-grid` | CSS Grid, `auto-fit minmax(300px, 1fr)`, `2rem` gap | -| `.small-showcase-cards` | CSS Grid, `auto-fit minmax(250px, 1fr)`, `space-md` gap | -| `.row` | Flexbox wrap, `space-lg` gap (collapses to `space-sm` at 768px+) | -| `.cards-row` | Flex row wrap, `space-lg` gap (containers only) | -| `.section` | `padding: space-2xl space-lg` | -| `.section-lg` | `padding: space-3xl space-lg` | - ---- - -## Markdown Containers - -Opt-in via `containers: true` in page front matter. Loads `docs/css/containers.css`. Defined in `src/sass/containers.scss`. - -| Syntax | Class | Style | -|--------|-------|-------| -| `:::card` | `.card` | Standard card (see Cards) | -| `:::section` | `.prose-section` | Semantic section with spacing | -| `:::cards` | `.cards-row` | Flex row wrapper | -| `:::card-basic` | `.card-basic` | `--earth-sand` bg, 4px brown border, `radius-lg`, hard shadow | -| `:::card-shadow` | `.card-shadow` | Cream bg, borderless, `10px 10px 0 shadow-heavy` | - -Prose-scoped `blockquote` (within `.prose-section`): cream-sand bg, coral left border (`medium`), weight 600, full padding — overrides the global base style. - ---- - -## Footer - -Defined in `src/sass/_footer.scss`. Dark bg (`--earth-dark`), `extra-thick` brown top border. Grid layout (`auto-fit minmax(250px, 1fr)`). Section headings: Playfair Display, coral. Links: cream, underline, hover → coral. - ---- - -## Animation - -Defined in `src/sass/_animations.scss`. Arrow scroll indicator (`@keyframes arrow`, opacity pulse, 2s infinite). Card hover: `translateY(-5px)` with shadow expansion. Button hover: `translate(2px, 2px)` with shadow collapse. All animations disabled under `prefers-reduced-motion: reduce`. - ---- - -## Image Conventions - -- Source: `src/assets/img-raw/` (high-res originals) -- Output: `src/assets/img/` (Sharp-processed) -- Full-size: 1200px wide, WebP (80%) + JPEG (85%) -- Thumbnail: 300px wide, WebP (70%) + JPEG (75%) -- `.showcase-image` placeholder: `300px` tall, `135deg` gradient sage→sand, centers emoji/icon fallback -- `.showcase-image-dark`: black→earth-dark gradient variant - ---- - -## CSS Build - -| File | Output | Loaded | -|------|--------|--------| -| `src/sass/style.scss` | `docs/css/style.css` | All pages | -| `src/sass/containers.scss` | `docs/css/containers.css` | Pages with `containers: true` | -| `src/sass/markdown.scss` | `docs/css/markdown.css` | Markdown layout pages | -| `src/sass/print.scss` | `docs/css/print.css` | Print media | -| `src/sass/prism.scss` | `docs/css/prism.css` | Code syntax highlighting | -| `src/sass/slides.scss` | `docs/css/slides.css` | Presentation pages | - -Import order in `style.scss`: `variables` → `animations` → `fonts` → `typography` → `spacing` → `layout` → `lists` → `highlight` → `navigation` → `footer` → `badge` → `buttons` → `cards` → `gallery`. +Floating pill nav: `position: fixed/sticky`, centered, `background: rgba(245,241,232,0.5)` with `backdrop-filter: blur(24px)`. 4px brown border, 50px border-radius (true pill shape). Items spaced 2rem apart, Inter 0.95rem medium weight. Active state and hover both use terracotta color + outline. + +### Inputs & Forms +No dedicated form component file found. Code blocks use sand background `#c9b89a`, 12px radius (radius-md), 2px sage border. Inline code uses sand bg with 8px radius (radius-sm). + +### Portfolio/Case Study Components +- **Callout Card** `.callout` — Parchment bg, 6px deep-terracotta border, 20px radius, `8px 8px 0` shadow. Oversized Playfair Display `"` quote mark in coral positioned top-left. Right-aligned content. +- **Work Grid** `.work-grid` — CSS Grid, `auto-fit minmax(300px, 1fr)`, 2rem gap. +- **Divider** `.divider` — 50% width, terracotta fill, 4px outset dark-brown border. Horizontal rule as decorative element. +- **Callout Text Block** `.text-callout` — Sand-light background, 4px left coral border, semibold, generous margins/padding. + +## 5. Layout Principles + +### Grid & Structure +- **Max content width**: 1200px (`section`, `.container`, `.footer-content`) +- **Narrow content**: 800px (`.container-narrow`) for prose/article pages +- **Grid system**: CSS Grid with `auto-fit / minmax()` patterns — not fixed columns + - Work grid: `minmax(300px, 1fr)` + - About grid: `minmax(350px, 1fr)` + - Small showcase: `minmax(250px, 1fr)` + - Footer: `minmax(250px, 1fr)` +- **Flex rows**: `display: flex; flex-wrap: wrap; gap: 2rem` + +### Whitespace Strategy +- Base unit: 4px (`--space-2xs`) +- Section vertical padding: **96px** (`--space-3xl`) — extremely generous +- Section lateral padding: 24px (`--space-lg`) +- Card internal padding: 24px default, 32px for larger variants +- Spacing scale: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 96px + +### Alignment & Visual Balance +- Section content centered with `max-width + margin: 0 auto` +- H2 decorative underline centered with `margin: 1rem auto` +- Hero text centered; body content left-aligned +- Footer uses CSS Grid for balanced multi-column layout + +### Responsive Behavior & Touch +- Breakpoint: 768px (mobile/desktop boundary) +- Mobile nav: reduces padding, compresses to tighter horizontal fit +- Cards: grids collapse naturally via `auto-fit/minmax` +- About card: switches to single column, reduces shadow and padding +- Showcase large: reduces shadow offset on mobile +- Font sizes: all use `clamp()` for fluid scaling — no hard breakpoints in typography + +## 6. Design System Notes for Stitch Generation + +### Language to Use +Describe screens as: *warm, earthy, crafted, neo-brutalist, artisanal, portfolio-grade, high-contrast, parchment-toned, bold-bordered, tactile*. Avoid clinical or sterile descriptors. Think: "a designer's sketchbook brought to the web." + +### Color References +- Canvas/background: Aged Parchment `#f5f1e8` +- Primary CTA: Deep Terracotta `#b34a2d` +- Accent/highlight: Terracotta `#d35f3d` +- Borders & outlines: Rich Brown `#4a3426` +- Secondary/links: Olive Sage `#5a6b4f` +- Body text: Espresso `#2d1f12` +- Secondary text: Rich Brown `#4a3426` +- Dark surface (footer): Dark Espresso `#2d1f12` + +### Component Prompts +- *"Portfolio card with thick brown border, terracotta drop shadow, parchment background, Playfair Display heading, and hover lift effect"* +- *"CTA button in deep terracotta with 4px brown border, hard offset shadow, semi-bold Inter text, 12px radius"* +- *"Floating pill navigation bar with frosted glass backdrop blur, parchment tint, brown border, centered links in Inter medium"* +- *"Case study hero with Pirata One display heading, terracotta text-shadow, centered on parchment, with a Playfair Display subtitle in secondary brown"* +- *"Dark footer with espresso background, coral section headings, cream body text, multi-column grid layout"* + +### Incremental Iteration +- Start screens on parchment `#f5f1e8` — never white or gray +- Apply borders before shadows — the border defines the component shape +- Use `translateY(-5px)` lift on card hover, never scale transforms +- H2 always needs its coral underline block — it's a signature element +- Shadow style is always flat/hard-offset (no blur radius), not soft/diffuse diff --git a/README.md b/README.md index 70f5fc01..849f470c 100755 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This is a **personal portfolio site** showcasing my work as a Lead Product Desig - **Development Projects** - Open source contributions, tools, and code examples - **Professional Content** - Resume, presentations, and technical articles - **App Showcases** - iOS/iPadOS apps and web applications +- **Open Source** - Open source project contributions and tooling ## Usage & Ownership @@ -31,6 +32,17 @@ I'm a user experience designer with 15+ years of enterprise experience at compan --- +## Design System + +The visual language is documented in two places: + +- **`DESIGN.md`** — Source-code-derived design system with YAML frontmatter color/typography tokens compatible with [Stitch](https://stitch.withgoogle.com). Documents the warm earth-tone palette, neo-brutalist component patterns, and layout principles. +- **`.stitch/DESIGN.md`** — Stitch-specific copy with full color role mappings and component generation prompts. + +Key design tokens live in `src/sass/_variables.scss` as CSS custom properties. The palette is built entirely from warm earth tones (parchment, espresso, terracotta, olive sage). Style aesthetic: thick borders (4–8px), hard-offset box shadows (no blur), and physical hover translations. + +--- + ## Markdown Containers Pages using `layout: markdown.njk` can opt in to fenced container blocks by adding `containers: true` to front matter. This enables container syntax without writing raw HTML. diff --git a/package.json b/package.json index b86aa56a..52d8bff7 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "lint": "stylelint 'src/sass/*.scss'", "lint:fix": "stylelint --fix 'src/sass/*.scss'", "images:optimize": "node scripts/image-optimizer.js", - "bump": "npm --no-git-tag-version version" + "bump": "npm --no-git-tag-version version", + "lint:design": "npx @google/design.md lint DESIGN.md" }, "repository": { "type": "git",