diff --git a/.eleventy.js b/.eleventy.js index 5329b3a3..6eb41735 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -9,7 +9,8 @@ const pluginTOC = require('eleventy-plugin-toc'); const pluginDropcap = require('eleventy-plugin-dropcap'); const markdownIt = require("markdown-it"); const markdownItAnchor = require("markdown-it-anchor"); -const markdownItHighlightJS = require('markdown-it-highlightjs') +const markdownItHighlightJS = require('markdown-it-highlightjs'); +const markdownItContainer = require('markdown-it-container'); const emojiReadTime = require("@11tyrocks/eleventy-plugin-emoji-readtime"); const packageVersion = require("./package.json").version; const eleventySass = require("@11tyrocks/eleventy-plugin-sass-lightningcss"); @@ -118,6 +119,41 @@ module.exports = function (eleventyConfig) { markdownIt(mdOptions) .use(markdownItAnchor, mdAnchorOpts) .use(markdownItHighlightJS) + .use(markdownItContainer, 'card', { + render(tokens, idx) { + return tokens[idx].nesting === 1 + ? '
\n' + : '
\n'; + } + }) + .use(markdownItContainer, 'section', { + render(tokens, idx) { + return tokens[idx].nesting === 1 + ? '
\n' + : '
\n'; + } + }) + .use(markdownItContainer, 'cards', { + render(tokens, idx) { + return tokens[idx].nesting === 1 + ? '
\n' + : '
\n'; + } + }) + .use(markdownItContainer, 'card-basic', { + render(tokens, idx) { + return tokens[idx].nesting === 1 + ? '
\n' + : '
\n'; + } + }) + .use(markdownItContainer, 'card-shadow', { + render(tokens, idx) { + return tokens[idx].nesting === 1 + ? '
\n' + : '
\n'; + } + }) ); // Plugins diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..38408a06 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [Unreleased] + +### Added + +- 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) + +- Markdown containers system via `markdown-it-container` plugin + — `.eleventy.js`, `src/sass/containers.scss`, `src/_includes/markdown.njk` + (registers `:::card`, `:::section`, `:::cards`, `:::card-basic`, `:::card-shadow` fenced blocks; opt-in per page via `containers: true` in front matter) + +### Fixed + +- Production build now compiles all SCSS files to `docs/css/` (previously only `style.scss` was compiled, leaving `markdown.css`, `print.css`, etc. missing in production) + — `package.json` `build:sass-site` script changed from single-file to directory compilation (`src/sass:docs/css`) diff --git a/CLAUDE.md b/CLAUDE.md index 428c6ea7..4c30e67b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -104,6 +104,7 @@ scripts/ - `markdown-it-anchor`: Auto-heading anchors with `#` symbols - `markdown-it-highlightjs`: Syntax highlighting - `markdown-it-eleventy-img`: Image optimization + - `markdown-it-container`: Fenced container blocks (`:::card`, `:::section`, `:::cards`, `:::card-basic`, `:::card-shadow`) ### Eleventy Plugins Active 1. `@11ty/eleventy-plugin-syntaxhighlight` - Code block highlighting @@ -185,19 +186,41 @@ Edit `eleventyNavigation` in page front matter: - `title`: Display text in nav - `order`: Menu position (lower numbers first) +### Using Markdown Containers + +Pages using `layout: markdown.njk` can opt in to fenced container syntax by adding `containers: true` to front matter. This loads `containers.css` and enables all five container types: + +| Syntax | Output | Use case | +|--------|--------|----------| +| `:::card` | `
` | Bootstrap card component | +| `:::section` | `
` | Semantic section with spacing | +| `:::cards` | `
` | Flex row wrapper for adjacent cards | +| `:::card-basic` | `
` | Bordered card, earth-sand background | +| `:::card-shadow` | `
` | Cream background, box shadow | + +```yaml +--- +layout: markdown.njk +containers: true +--- +``` + +To add new container types: add `md.use(markdownItContainer, 'name', { render... })` in `.eleventy.js` and add styles in `src/sass/containers.scss`. + ## Working with Styles ### SCSS File Organization -- **Main**: `src/sass/style.scss` (imports Bootstrap + custom partials) +- **Main**: `src/sass/style.scss` (imports Bootstrap + custom partials, including containers) - **Colors**: `src/sass/_colors.scss` - **Typography**: `src/sass/_typography.scss` - **Layout**: `src/sass/_layout.scss` - **Components**: Individual `_component.scss` files (buttons, cards, gallery, etc.) +- **Containers**: `src/sass/containers.scss` (prose-section, card overrides for markdown context) ### CSS Build Process -- **Development**: Auto-compiles via `npm run start` watcher -- **Production**: `npm run build:sass` → PostCSS → minified output -- **Output**: `docs/css/style.css` (~98KB) +- **Development**: Auto-compiles entire `src/sass/` → `docs/css/` via `watch:sass` +- **Production**: `npm 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 diff --git a/README.md b/README.md index 917a2984..30daf85c 100755 --- a/README.md +++ b/README.md @@ -31,6 +31,60 @@ I'm a user experience designer with 15+ years of enterprise experience at compan ---- +## 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. + +```yaml +--- +layout: markdown.njk +containers: true +--- +``` + +```markdown +:::section +## Section Heading +Content here. +::: + +:::card +### Card Title +Card content here. +::: + +:::cards +:::card +Card one. +::: +:::card +Card two. +::: +::: + +:::card-basic +Basic styled card. +::: + +:::card-shadow +Elevated card with shadow. +::: +``` + +Available containers and their rendered output: + +| Syntax | Output | +|--------|--------| +| `:::card` | `
` | +| `:::section` | `
` | +| `:::cards` | `
` (flex row wrapper) | +| `:::card-basic` | `
` (bordered, earth-sand background) | +| `:::card-shadow` | `
` (cream background, box shadow) | + +Pages without `containers: true` are unaffected. To add new container types, register them in `.eleventy.js` and add styles in `src/sass/containers.scss`. + +---- + ## References and Resources **Libraries** diff --git a/docs/about/resume/index.html b/docs/about/resume/index.html index f7638073..0acf3ad9 100644 --- a/docs/about/resume/index.html +++ b/docs/about/resume/index.html @@ -75,12 +75,13 @@ +

Adam Jolicoeur

Lead Product Designer with 15+ years at AWS, Red Hat, and high-growth B2B companies

-
+

Adam Jolicoeur

contact@adamjolicoeur.com @@ -128,7 +129,7 @@

Also available

GitHub
-
+ diff --git a/docs/apps/taskstat-privacy.html b/docs/apps/taskstat-privacy.html index 2736943f..f1179750 100644 --- a/docs/apps/taskstat-privacy.html +++ b/docs/apps/taskstat-privacy.html @@ -75,12 +75,13 @@ +

TaskStat Privacy Policy

Privacy policy for TaskStat - a privacy-first task management app for iOS

-
+

Last Updated: January 5, 2026
Effective Date: January 5, 2026

@@ -328,7 +329,7 @@

Acknowledgment Simple tasks. Complete privacy.

-
+ diff --git a/docs/apps/taskstat.html b/docs/apps/taskstat.html index df303c2f..ef806e66 100644 --- a/docs/apps/taskstat.html +++ b/docs/apps/taskstat.html @@ -75,12 +75,13 @@ +

TaskStat

Privacy-first task management for iOS. Your tasks stay on your device—no accounts, no tracking, no cloud sync.

-
+

About TaskStat #

TaskStat is a native iOS task management app built with privacy as a core principle. Unlike cloud-based task managers, TaskStat stores all your data locally on your device using SwiftData—ensuring complete privacy and offline functionality.

@@ -176,7 +177,7 @@

Technical Details TaskStat: Simple tasks. Complete privacy.

-
+ diff --git a/docs/assets/img/TimeTrackerPro-1920x1080-thumb.jpg b/docs/assets/img/TimeTrackerPro-1920x1080-thumb.jpg new file mode 100644 index 00000000..c74fa3b2 Binary files /dev/null and b/docs/assets/img/TimeTrackerPro-1920x1080-thumb.jpg differ diff --git a/docs/assets/img/TimeTrackerPro-1920x1080-thumb.webp b/docs/assets/img/TimeTrackerPro-1920x1080-thumb.webp new file mode 100644 index 00000000..84883e18 Binary files /dev/null and b/docs/assets/img/TimeTrackerPro-1920x1080-thumb.webp differ diff --git a/docs/assets/img/TimeTrackerPro-1920x1080.jpg b/docs/assets/img/TimeTrackerPro-1920x1080.jpg new file mode 100644 index 00000000..3ed45406 Binary files /dev/null and b/docs/assets/img/TimeTrackerPro-1920x1080.jpg differ diff --git a/docs/assets/img/TimeTrackerPro-1920x1080.webp b/docs/assets/img/TimeTrackerPro-1920x1080.webp new file mode 100644 index 00000000..5ae20de5 Binary files /dev/null and b/docs/assets/img/TimeTrackerPro-1920x1080.webp differ diff --git a/docs/assets/img/timetracker-generated-summary-thumb.jpg b/docs/assets/img/timetracker-generated-summary-thumb.jpg new file mode 100644 index 00000000..c67a4fc9 Binary files /dev/null and b/docs/assets/img/timetracker-generated-summary-thumb.jpg differ diff --git a/docs/assets/img/timetracker-generated-summary-thumb.webp b/docs/assets/img/timetracker-generated-summary-thumb.webp new file mode 100644 index 00000000..de559568 Binary files /dev/null and b/docs/assets/img/timetracker-generated-summary-thumb.webp differ diff --git a/docs/assets/img/timetracker-generated-summary.jpg b/docs/assets/img/timetracker-generated-summary.jpg new file mode 100644 index 00000000..bb058161 Binary files /dev/null and b/docs/assets/img/timetracker-generated-summary.jpg differ diff --git a/docs/assets/img/timetracker-generated-summary.webp b/docs/assets/img/timetracker-generated-summary.webp new file mode 100644 index 00000000..e795062d Binary files /dev/null and b/docs/assets/img/timetracker-generated-summary.webp differ diff --git a/docs/assets/img/timetracker-loading-state-thumb.jpg b/docs/assets/img/timetracker-loading-state-thumb.jpg new file mode 100644 index 00000000..fb56fe83 Binary files /dev/null and b/docs/assets/img/timetracker-loading-state-thumb.jpg differ diff --git a/docs/assets/img/timetracker-loading-state-thumb.webp b/docs/assets/img/timetracker-loading-state-thumb.webp new file mode 100644 index 00000000..3256b1a1 Binary files /dev/null and b/docs/assets/img/timetracker-loading-state-thumb.webp differ diff --git a/docs/assets/img/timetracker-loading-state.jpg b/docs/assets/img/timetracker-loading-state.jpg new file mode 100644 index 00000000..2588ada7 Binary files /dev/null and b/docs/assets/img/timetracker-loading-state.jpg differ diff --git a/docs/assets/img/timetracker-loading-state.webp b/docs/assets/img/timetracker-loading-state.webp new file mode 100644 index 00000000..39acde92 Binary files /dev/null and b/docs/assets/img/timetracker-loading-state.webp differ diff --git a/docs/assets/img/timetracker-start-thumb.jpg b/docs/assets/img/timetracker-start-thumb.jpg new file mode 100644 index 00000000..335d082c Binary files /dev/null and b/docs/assets/img/timetracker-start-thumb.jpg differ diff --git a/docs/assets/img/timetracker-start-thumb.webp b/docs/assets/img/timetracker-start-thumb.webp new file mode 100644 index 00000000..8a586af6 Binary files /dev/null and b/docs/assets/img/timetracker-start-thumb.webp differ diff --git a/docs/assets/img/timetracker-start.jpg b/docs/assets/img/timetracker-start.jpg new file mode 100644 index 00000000..e9f97957 Binary files /dev/null and b/docs/assets/img/timetracker-start.jpg differ diff --git a/docs/assets/img/timetracker-start.webp b/docs/assets/img/timetracker-start.webp new file mode 100644 index 00000000..e202abf5 Binary files /dev/null and b/docs/assets/img/timetracker-start.webp differ diff --git a/docs/assets/img/timetracker-tone-client-thumb.jpg b/docs/assets/img/timetracker-tone-client-thumb.jpg new file mode 100644 index 00000000..69a8d93d Binary files /dev/null and b/docs/assets/img/timetracker-tone-client-thumb.jpg differ diff --git a/docs/assets/img/timetracker-tone-client-thumb.webp b/docs/assets/img/timetracker-tone-client-thumb.webp new file mode 100644 index 00000000..6e0c440c Binary files /dev/null and b/docs/assets/img/timetracker-tone-client-thumb.webp differ diff --git a/docs/assets/img/timetracker-tone-client.jpg b/docs/assets/img/timetracker-tone-client.jpg new file mode 100644 index 00000000..8f7990ff Binary files /dev/null and b/docs/assets/img/timetracker-tone-client.jpg differ diff --git a/docs/assets/img/timetracker-tone-client.webp b/docs/assets/img/timetracker-tone-client.webp new file mode 100644 index 00000000..38cb9f7d Binary files /dev/null and b/docs/assets/img/timetracker-tone-client.webp differ diff --git a/docs/assets/img/timetracker-tone-retro-thumb.jpg b/docs/assets/img/timetracker-tone-retro-thumb.jpg new file mode 100644 index 00000000..4c70ffa6 Binary files /dev/null and b/docs/assets/img/timetracker-tone-retro-thumb.jpg differ diff --git a/docs/assets/img/timetracker-tone-retro-thumb.webp b/docs/assets/img/timetracker-tone-retro-thumb.webp new file mode 100644 index 00000000..3bb0cd6e Binary files /dev/null and b/docs/assets/img/timetracker-tone-retro-thumb.webp differ diff --git a/docs/assets/img/timetracker-tone-retro.jpg b/docs/assets/img/timetracker-tone-retro.jpg new file mode 100644 index 00000000..cb3c1e1f Binary files /dev/null and b/docs/assets/img/timetracker-tone-retro.jpg differ diff --git a/docs/assets/img/timetracker-tone-retro.webp b/docs/assets/img/timetracker-tone-retro.webp new file mode 100644 index 00000000..9b337819 Binary files /dev/null and b/docs/assets/img/timetracker-tone-retro.webp differ diff --git a/docs/assets/img/timetracker-tone-standup-thumb.jpg b/docs/assets/img/timetracker-tone-standup-thumb.jpg new file mode 100644 index 00000000..9c03031b Binary files /dev/null and b/docs/assets/img/timetracker-tone-standup-thumb.jpg differ diff --git a/docs/assets/img/timetracker-tone-standup-thumb.webp b/docs/assets/img/timetracker-tone-standup-thumb.webp new file mode 100644 index 00000000..2b48a416 Binary files /dev/null and b/docs/assets/img/timetracker-tone-standup-thumb.webp differ diff --git a/docs/assets/img/timetracker-tone-standup.jpg b/docs/assets/img/timetracker-tone-standup.jpg new file mode 100644 index 00000000..77c61279 Binary files /dev/null and b/docs/assets/img/timetracker-tone-standup.jpg differ diff --git a/docs/assets/img/timetracker-tone-standup.webp b/docs/assets/img/timetracker-tone-standup.webp new file mode 100644 index 00000000..fb1e793b Binary files /dev/null and b/docs/assets/img/timetracker-tone-standup.webp differ diff --git a/docs/assets/img/timetracker-weekly-report-thumb.jpg b/docs/assets/img/timetracker-weekly-report-thumb.jpg new file mode 100644 index 00000000..833ea0ae Binary files /dev/null and b/docs/assets/img/timetracker-weekly-report-thumb.jpg differ diff --git a/docs/assets/img/timetracker-weekly-report-thumb.webp b/docs/assets/img/timetracker-weekly-report-thumb.webp new file mode 100644 index 00000000..92a6cc97 Binary files /dev/null and b/docs/assets/img/timetracker-weekly-report-thumb.webp differ diff --git a/docs/assets/img/timetracker-weekly-report.jpg b/docs/assets/img/timetracker-weekly-report.jpg new file mode 100644 index 00000000..acd0b966 Binary files /dev/null and b/docs/assets/img/timetracker-weekly-report.jpg differ diff --git a/docs/assets/img/timetracker-weekly-report.webp b/docs/assets/img/timetracker-weekly-report.webp new file mode 100644 index 00000000..03230f5d Binary files /dev/null and b/docs/assets/img/timetracker-weekly-report.webp differ diff --git a/docs/credits/index.html b/docs/credits/index.html index 9e77b5b5..76784b8c 100644 --- a/docs/credits/index.html +++ b/docs/credits/index.html @@ -75,6 +75,7 @@ +

Credits

diff --git a/docs/css/containers.css b/docs/css/containers.css new file mode 100644 index 00000000..2c9c593f --- /dev/null +++ b/docs/css/containers.css @@ -0,0 +1,82 @@ +@charset "UTF-8"; +/* Markdown container blocks — loaded only on pages with containers: true */ +/* Grid row for adjacent card blocks */ +.cards-row { + display: flex; + flex-wrap: wrap; + flex-direction: row; + gap: var(--space-lg, 1.5rem); +} + +/* Semantic prose section with spacing */ +.prose-section:nth-child(2) { + margin-top: 0; +} + +/* Card container in prose context — extends base .card with spacing for markdown content */ +.prose-section .card, +section .card { + margin-bottom: var(--space-lg, 1.5rem); +} + +/* Ensure headings inside cards have correct spacing */ +.card h2, +.card h3, +.card h4 { + margin-top: 0; + margin-bottom: var(--space-sm, 0.75rem); +} + +.card > h3 { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-sand); +} + +.card p:last-child, +.card ul:last-child, +.card ol:last-child { + margin-bottom: 0; +} + +.prose-section .card-shadow { + background: var(--earth-cream); + border: none; + border-radius: var(--radius-lg, 16px); + padding: var(--space-md, 1.5rem); + box-shadow: 10px 10px 0 var(--shadow-heavy); +} + +.prose-section .card-shadow > h3 { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-brown); +} + +.prose-section .card-basic { + background: var(--earth-sand); + border: 4px solid var(--earth-brown); + border-radius: var(--radius-lg, 16px); + padding: var(--space-md, 1.5rem); + box-shadow: 6px 6px 0 var(--shadow-heavy); + transition: transform 0.3s; +} + +.prose-section .card-basic > h3 { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-brown); +} + +blockquote { + font-size: clamp(1rem, 1.5vw, 1.1rem); + line-height: 1.6; + font-weight: 600; + color: var(--text-primary); + margin: var(--space-lg, 1.5rem); + padding: var(--space-lg, 1.5rem); + background: var(--earth-sand-light); + border-left: var(--border-medium) solid var(--accent-coral); +} + +/*# sourceMappingURL=containers.css.map */ diff --git a/docs/css/containers.css.map b/docs/css/containers.css.map new file mode 100644 index 00000000..5989a9a7 --- /dev/null +++ b/docs/css/containers.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../src/sass/containers.scss"],"names":[],"mappings":";AAAA;AAEA;AACA;EACE;EACA;EACA;EACA;;;AAGF;AAUA;EACE;;;AAGF;AACA;AAAA;EAEE;;;AAGF;AACA;AAAA;AAAA;EAGE;EACA;;;AAEF;EACE;EACA;EACA;;;AAGF;AAAA;AAAA;EAGE;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA","file":"containers.css"} \ No newline at end of file diff --git a/docs/css/markdown.css b/docs/css/markdown.css new file mode 100644 index 00000000..576fc100 --- /dev/null +++ b/docs/css/markdown.css @@ -0,0 +1,24 @@ +pre { + background-color: var(--earth-cream); + padding: var(--space-md, 1rem); + border-radius: var(--radius-md, 12px); +} + +section h2 { + margin-top: var(--space-lg, 2rem) !important; +} + +section h3 { + margin-bottom: var(--space-md, 1rem) !important; +} + +section ul, +section ol { + margin-bottom: var(--space-md, 1rem) !important; +} + +.card > h2::after { + display: none; +} + +/*# sourceMappingURL=markdown.css.map */ diff --git a/docs/css/markdown.css.map b/docs/css/markdown.css.map new file mode 100644 index 00000000..6a6f4967 --- /dev/null +++ b/docs/css/markdown.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../src/sass/markdown.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;;;AAEF;AAAA;EAEE;;;AAGA;EACE","file":"markdown.css"} \ No newline at end of file diff --git a/docs/css/print.css b/docs/css/print.css new file mode 100644 index 00000000..8822d634 --- /dev/null +++ b/docs/css/print.css @@ -0,0 +1,196 @@ +/** + ** Print stylesheet for Resume + ** Copyright 2008-2024 Adam J. Jolicoeur + ** https://www.adamjolicoeur.com +**/ +@media print { + body { + font: 12pt "Times New Roman", Times, serif; + line-height: 1.3; + background: #fff !important; + color: #000; + } + header, + #header, + footer, + #footer, + aside, + nav, + form, + iframe, + .menu, + .hero, + .adslot { + display: none; + } + #navigation, + #footer { + display: none !important; + } + main, + content { + display: block !important; + max-width: 8.5in !important; + width: 100%; + margin: 0; + float: none; + } + section, + .section-hero { + padding: 0 !important; + margin: 0 !important; + margin-top: 16px !important; + } + .row { + display: block !important; + } + .col-md-6 { + width: 100% !important; + } + .mt-4, .mt-3, .mt-2 { + margin-top: 2pt !important; + } + .mb-4, .mb-3, .mb-2 { + margin-bottom: 2pt !important; + } + .my-4, .my-3, .my-2 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .py-4, .py-3, .py-2 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .pb-4, .pb-3, .pb-2 { + padding-bottom: 2pt !important; + } + * { + background-image: none !important; + } + img, + svg { + display: none !important; + } + table, + img, + svg { + break-inside: avoid; + } + .text-bg-light { + background-color: transparent !important; + } + .row-badges { + display: none !important; + } + .hide-on-print { + display: none !important; + } + .print { + display: block !important; + } + h1, + .h1, + .text-h1 { + font-size: 22pt; + break-before: always; + text-shadow: none; + font-family: "Times New Roman", Times, serif; + } + h2, + .h2, + .text-h2 { + font-size: 19pt; + margin-top: 16px; + margin-bottom: 8px; + font-family: "Times New Roman", Times, serif !important; + } + h2::after, + .h2::after, + .text-h2::after { + display: none; + } + h3, + .h3, + .text-h3 { + font-size: 17pt; + margin-top: 16px; + margin-bottom: 8px; + font-family: "Times New Roman", Times, serif !important; + } + h4, + .h4, + .text-h4 { + font-size: 14pt; + margin-top: 16px; + margin-bottom: 8px; + font-family: "Times New Roman", Times, serif !important; + } + h5, + .h5, + .text-h5 { + font-size: 12pt; + margin-top: 16px; + margin-bottom: 8px; + font-family: "Times New Roman", Times, serif !important; + } + p, + .paragraph { + font-size: 12pt; + margin-bottom: 8px; + font-family: "Times New Roman", Times, serif !important; + } + /* Defining all page breaks */ + blockquote { + page-break-inside: avoid; + } + h1, + h2, + h3, + h4, + h5, + h6 { + page-break-after: avoid; + page-break-inside: avoid; + } + img { + page-break-inside: avoid; + page-break-after: avoid; + } + table, + pre { + page-break-inside: avoid; + } + ul, + ol, + dl { + page-break-before: avoid; + } + /* Displaying link color and link behavior */ + a { + page-break-inside: avoid; + } + a, + a:link, + a:visited { + background: transparent; + color: #520; + font-weight: bold; + text-decoration: underline; + text-align: left; + } + .badge { + border-color: #000 !important; + color: #000 !important; + background: transparent !important; + } + .card { + background: transparent !important; + border-color: transparent !important; + padding: 0 !important; + box-shadow: none !important; + transition: none !important; + transform: none !important; + } +} + +/*# sourceMappingURL=print.css.map */ diff --git a/docs/css/print.css.map b/docs/css/print.css.map new file mode 100644 index 00000000..ec3a23d4 --- /dev/null +++ b/docs/css/print.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../src/sass/print.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;EACE;IACE;IACA;IACA;IACA;;EAEF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IAWE;;EAEF;AAAA;IAEE;;EAEF;AAAA;IAEE;IACA;IACA;IACA;IACA;;EAEF;AAAA;IAEE;IACA;IACA;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;EAEF;IACE;;EAEF;IACE;;EAEF;AAAA;IAEE;;EAEF;AAAA;AAAA;IAGE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;IACA;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;IACA;;EAEF;AAAA;AAAA;IAGE;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;IACA;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;IACA;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;IACA;;EAEF;AAAA;IAEE;IACA;IACA;;AAGF;EACA;IACE;;EAEF;AAAA;AAAA;AAAA;AAAA;AAAA;IAME;IACA;;EAEF;IACE;IACA;;EAEF;AAAA;IAEE;;EAEF;AAAA;AAAA;IAGE;;AAGF;EACA;IACE;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;IACA;IACA;;EAeF;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;IACA;IACA","file":"print.css"} \ No newline at end of file diff --git a/docs/css/prism.css b/docs/css/prism.css new file mode 100644 index 00000000..0ace8b1d --- /dev/null +++ b/docs/css/prism.css @@ -0,0 +1,154 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+markdown+scss&plugins=show-language+toolbar */ +code[class*=language-], pre[class*=language-] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + tab-size: 4; + hyphens: none; +} + +code[class*=language-] ::selection, code[class*=language-]::selection, pre[class*=language-] ::selection, pre[class*=language-]::selection { + text-shadow: none; + background: #b3d4fc; +} + +code[class*=language-] ::selection, code[class*=language-]::selection, pre[class*=language-] ::selection, pre[class*=language-]::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*=language-], pre[class*=language-] { + text-shadow: none; + } +} +pre[class*=language-] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*=language-], pre[class*=language-] { + background: #f5f2f0; +} + +:not(pre) > code[class*=language-] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.cdata, .token.comment, .token.doctype, .token.prolog { + color: #708090; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.boolean, .token.constant, .token.deleted, .token.number, .token.property, .token.symbol, .token.tag { + color: #905; +} + +.token.attr-name, .token.builtin, .token.char, .token.inserted, .token.selector, .token.string { + color: #690; +} + +.language-css .token.string, .style .token.string, .token.entity, .token.operator, .token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, .token.attr-value, .token.keyword { + color: #07a; +} + +.token.class-name, .token.function { + color: #dd4a68; +} + +.token.important, .token.regex, .token.variable { + color: #e90; +} + +.token.bold, .token.important { + font-weight: 700; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +div.code-toolbar { + position: relative; +} + +div.code-toolbar > .toolbar { + position: absolute; + z-index: 10; + top: 0.3em; + right: 0.2em; + transition: opacity 0.3s ease-in-out; + opacity: 0; +} + +div.code-toolbar:hover > .toolbar { + opacity: 1; +} + +div.code-toolbar:focus-within > .toolbar { + opacity: 1; +} + +div.code-toolbar > .toolbar > .toolbar-item { + display: inline-block; +} + +div.code-toolbar > .toolbar > .toolbar-item > a { + cursor: pointer; +} + +div.code-toolbar > .toolbar > .toolbar-item > button { + background: 0 0; + border: 0; + color: inherit; + font: inherit; + line-height: normal; + overflow: visible; + padding: 0; + user-select: none; +} + +div.code-toolbar > .toolbar > .toolbar-item > a, div.code-toolbar > .toolbar > .toolbar-item > button, div.code-toolbar > .toolbar > .toolbar-item > span { + color: #bbb; + font-size: 0.8em; + padding: 0 0.5em; + background: #f5f2f0; + background: rgba(224, 224, 224, 0.2); + box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); + border-radius: 0.5em; +} + +div.code-toolbar > .toolbar > .toolbar-item > a:focus, div.code-toolbar > .toolbar > .toolbar-item > a:hover, div.code-toolbar > .toolbar > .toolbar-item > button:focus, div.code-toolbar > .toolbar > .toolbar-item > button:hover, div.code-toolbar > .toolbar > .toolbar-item > span:focus, div.code-toolbar > .toolbar > .toolbar-item > span:hover { + color: inherit; + text-decoration: none; +} + +/*# sourceMappingURL=prism.css.map */ diff --git a/docs/css/prism.css.map b/docs/css/prism.css.map new file mode 100644 index 00000000..87c11add --- /dev/null +++ b/docs/css/prism.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../src/sass/prism.scss"],"names":[],"mappings":"AAAA;AAAA;AAEA;EAAiD;EAAW;EAAe;EAAuB;EAAkE;EAAc;EAAgB;EAAgB;EAAoB;EAAkB;EAAiB;EAAgB;EAAW;;;AAAa;EAAgJ;EAAiB;;;AAAmB;EAAgJ;EAAiB;;;AAAmB;EAAa;IAAiD;;;AAAkB;EAAwB;EAAY;EAAc;;;AAAc;EAA2D;;;AAAmB;EAAmC;EAAa;EAAmB;;;AAAmB;EAAyD;;;AAAc;EAAmB;;;AAAW;EAAiB;;;AAAW;EAAqG;;;AAAW;EAA0F;;;AAAW;EAA0F;EAAc;;;AAAiC;EAA+C;;;AAAW;EAAkC;;;AAAc;EAA8C;;;AAAW;EAA6B;;;AAAgB;EAAc;;;AAAkB;EAAc;;;AAC1qD;EAAiB;;;AAAkB;EAA0B;EAAkB;EAAW;EAAS;EAAW;EAAmC;;;AAAU;EAAgC;;;AAAU;EAAuC;;;AAAU;EAAwC;;;AAAqB;EAA0C;;;AAAe;EAA+C;EAAe;EAAS;EAAc;EAAa;EAAmB;EAAiB;EAAU;;;AAAiB;EAAsI;EAAW;EAAe;EAAe;EAAmB;EAAgC;EAAoC;;;AAAmB;EAAgT;EAAc","file":"prism.css"} \ No newline at end of file diff --git a/docs/css/slides.css b/docs/css/slides.css new file mode 100644 index 00000000..5da54723 --- /dev/null +++ b/docs/css/slides.css @@ -0,0 +1,63 @@ +/* +** Based on the CodePen from Chirs Coyier +** https://codepen.io/chriscoyier/pen/XwbNwX +*/ +.slider { + text-align: center; + overflow: hidden; +} + +.slides { + display: flex; + overflow-x: auto; + scroll-snap-type: x mandatory; + scroll-behavior: smooth; + -webkit-overflow-scrolling: touch; +} + +.slides::-webkit-scrollbar { + width: 16px; +} + +.slides::-webkit-scrollbar-thumb { + background: var(--earth-sage); + border-radius: 2rem; + border: 2px solid transparent; + background-clip: content-box; +} + +.slides::-webkit-scrollbar-track { + background: transparent; + padding: 0 2px; + border-radius: 2rem; + border: 1px solid transparent; +} + +.slides > div { + scroll-snap-align: start; + flex-shrink: 0; + width: 300px; + height: 300px; + margin-right: 50px; + border-radius: 10px; + background: transparent; + transform-origin: center center; + transform: scale(1); + transition: transform 0.5s; + position: relative; + display: flex; + justify-content: center; + align-items: center; + font-size: 100px; +} + +.carousel img { + object-fit: cover; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +/*# sourceMappingURL=slides.css.map */ diff --git a/docs/css/slides.css.map b/docs/css/slides.css.map new file mode 100644 index 00000000..b157ea75 --- /dev/null +++ b/docs/css/slides.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../src/sass/slides.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAKA;EAEE;EACA;;;AAGF;EACE;EAEA;EACA;EAEA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA","file":"slides.css"} \ No newline at end of file diff --git a/docs/css/style.css b/docs/css/style.css index 2ad74832..b02231c0 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -1,2 +1,1740 @@ -:root{--font-family-sans:"Inter",system-ui,-apple-system,blinkmacsystemfont,"Segoe UI",roboto,"Helvetica Neue",arial,sans-serif;--font-family-serif:"Playfair Display",serif;--font-family-mono:"Fira Code","Courier New",courier,monospace;--font-family-heading:"Pirata One",cursive;--white:#f0f0f0;--black:#010101;--earth-dark:#2d1f12;--earth-brown:#4a3426;--earth-sage:#5a6b4f;--earth-sand:#c9b89a;--earth-cream:#f5f1e8;--accent-coral:#d35f3d;--accent-coral-dark:#b34a2d;--text-primary:#2d1f12;--text-secondary:#4a3426;--text-muted:#6b5d52;--shadow:rgba(45,31,18,.15);--shadow-heavy:rgba(45,31,18,.25);--shadow-light:rgba(45,31,18,.08);--font-size-xs:0.75rem;--font-size-sm:0.875rem;--font-size-md:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--font-size-2xl:1.5rem;--font-size-3xl:2rem;--font-size-4xl:2.5rem;--font-size-5xl:3rem;--font-size-6xl:4rem;--space-2xs:0.25rem;--space-xs:0.5rem;--space-sm:0.75rem;--space-md:1rem;--space-lg:1.5rem;--space-xl:2rem;--space-2xl:3rem;--space-3xl:6rem;--radius-sm:8px;--radius-md:12px;--radius-lg:16px;--radius-xl:20px;--radius-pill:50px;--border-thin:2px;--border-medium:4px;--border-thick:6px;--border-extra-thick:8px}*{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}:focus-visible{outline:var(--border-thin) solid var(--accent-coral);outline-offset:2px}html{scroll-behavior:smooth}body{background:linear-gradient(135deg,var(--earth-cream) 0,#e8dcc8 100%);color:var(--text-primary);font-family:var(--font-family-sans);line-height:1.6;min-height:100vh;position:relative}::-webkit-scrollbar,html::-webkit-scrollbar{width:16px}::-webkit-scrollbar-thumb,html::-webkit-scrollbar-thumb{background:-webkit-gradient(linear,left top,left bottom,from(var(--accent-coral-dark)),to(var(--accent-coral)));background:linear-gradient(var(--accent-coral-dark),var(--accent-coral));background-clip:content-box;border:2px solid transparent;border-radius:2rem}::-webkit-scrollbar-track,html::-webkit-scrollbar-track{background:transparent;border:1px solid var(--earth-sage);border-radius:2rem;padding:0 2px}@media (prefers-reduced-motion:reduce){.animated-element{-webkit-animation:none;animation:none;opacity:1;-webkit-transition:none;transition:none}body{scroll-behavior:auto}*,:after,:before{-webkit-animation-duration:.01ms!important;animation-duration:.01ms!important;-webkit-animation-iteration-count:1!important;animation-iteration-count:1!important;-webkit-transition-duration:.01ms!important;transition-duration:.01ms!important}}.d-none,.display-none{display:none!important}.hero{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin:0 auto;max-width:900px;padding:6rem 2rem;text-align:center}.rounded{border-radius:var(--radius-xl,20px)!important}.circle{border-radius:999px!important;padding:1rem!important}.fade-in{opacity:0;-webkit-transition:opacity .5s ease-in,visibility 0s linear .5s;transition:opacity .5s ease-in,visibility 0s linear .5s;visibility:hidden}.fade-in.show,.show{opacity:1;-webkit-transition-delay:0s;transition-delay:0s;visibility:visible}.hide{opacity:0;-webkit-transition:opacity .5s ease-in,visibility 0s linear .5s;transition:opacity .5s ease-in,visibility 0s linear .5s;visibility:hidden}.hide-on-screen{display:none!important}@media (width <= 768px){.hero h1{font-size:var(--font-size-5xl,3rem)}.no-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.hide-on-mobile{display:none!important}.callouts-grid,.work-grid{grid-template-columns:1fr}h2{font-size:var(--font-size-3xl,2rem)}}figcaption{color:var(--text-secondary);font-size:var(--font-size-sm,.875rem);font-style:italic;line-height:1.4;text-align:center}.arrows{bottom:20px;height:72px;left:50%;margin-left:-30px;position:absolute;width:60px}.arrows path{stroke:#bfe7fa;fill:transparent;stroke-width:1px;-webkit-animation:arrow 2s infinite;animation:arrow 2s infinite}@-webkit-keyframes arrow{0%{opacity:0}40%{opacity:1}80%{opacity:0}to{opacity:0}}@keyframes arrow{0%{opacity:0}40%{opacity:1}80%{opacity:0}to{opacity:0}}.arrows path.a1{-webkit-animation-delay:-1s;animation-delay:-1s}.arrows path.a2{-webkit-animation-delay:-.5s;animation-delay:-.5s}.arrows path.a3{-webkit-animation-delay:0s;animation-delay:0s}.pirata-one-regular{font-family:Pirata One,system-ui;font-style:normal;font-weight:400}.inter-400{font-optical-sizing:auto;font-style:normal;font-weight:400}.inter-400,.inter-500{font-family:Inter,sans-serif}.inter-500{font-optical-sizing:auto;font-style:normal;font-weight:500}.inter-600{font-optical-sizing:auto;font-style:normal;font-weight:600}.inter-600,.inter-700{font-family:Inter,sans-serif}.inter-700{font-optical-sizing:auto;font-style:normal;font-weight:700}.inter-800{font-optical-sizing:auto;font-style:normal;font-weight:800}.inter-800,.inter-900{font-family:Inter,sans-serif}.inter-900{font-optical-sizing:auto;font-style:normal;font-weight:900}.playfair-display-400{font-family:Playfair Display,serif;font-optical-sizing:auto;font-style:normal;font-weight:400}.playfair-display-500{font-family:Playfair Display,serif;font-optical-sizing:auto;font-style:normal;font-weight:500}.playfair-display-600{font-family:Playfair Display,serif;font-optical-sizing:auto;font-style:normal;font-weight:600}.playfair-display-700{font-family:Playfair Display,serif;font-optical-sizing:auto;font-style:normal;font-weight:700}.playfair-display-800{font-family:Playfair Display,serif;font-optical-sizing:auto;font-style:normal;font-weight:800}.playfair-display-900{font-family:Playfair Display,serif;font-optical-sizing:auto;font-style:normal;font-weight:900}.text-h1,h1{font-size:clamp(2.5rem,8vw,5rem);line-height:1.2}.text-display,.text-h1,h1{color:var(--text-primary);font-family:Pirata One,cursive;letter-spacing:2px;text-shadow:3px 3px 0 var(--accent-coral)}.text-display{font-size:clamp(3rem,10vw,6rem);line-height:1.1}.hero h1{font-family:var(--font-family-heading);font-size:6rem;letter-spacing:2px;line-height:1.2;margin-bottom:1rem;text-shadow:3px 3px 0 var(--accent-coral)}.hero h1,.text-h2,h2{color:var(--text-primary)}.text-h2,h2{font-family:Playfair Display,serif;font-size:clamp(2rem,5vw,3rem);font-weight:700;line-height:1.3;margin-bottom:var(--space-md,1.5rem)}.text-h2.no-underline:after{display:none;margin-bottom:var(--space-2xs,.25rem)}.text-h2:after,h2:after{background:var(--accent-coral);border:3px solid var(--earth-brown);content:"";display:block;height:5px;margin:1rem auto;width:100px}.text-h3,h3{font-size:clamp(1.5rem,3vw,2rem);line-height:1.3}.text-h3,.text-h4,h3,h4{color:var(--text-primary);font-family:Playfair Display,serif;font-weight:600}.text-h4,h4{font-size:clamp(1.25rem,2.5vw,1.5rem);line-height:1.4}.text-h5,h5{font-size:clamp(1.1rem,2vw,1.25rem)}.text-h5,.text-h6,h5,h6{color:var(--text-primary);font-family:Inter,sans-serif;font-weight:700;line-height:1.4}.text-h6,h6{font-size:1rem;letter-spacing:.5px;text-transform:uppercase}.text-body-lg{font-size:clamp(1.1rem,1.5vw,1.25rem)!important;line-height:1.7!important}.text-body,p{color:var(--text-primary);font-size:clamp(.95rem,1.5vw,1rem);line-height:1.7;padding-bottom:var(--space-xs,.5rem)}.text-body:last-child,p:last-child{margin-bottom:0}.hero p{color:var(--earth-brown);font-size:clamp(1.1rem,2vw,1.25rem);margin:0 auto;max-width:720px}.card-body .text-body:first-of-type,.card-body p:first-of-type{margin-top:var(--space-md,16px)}.text-body-sm{font-size:clamp(.85rem,1.2vw,.9rem);line-height:1.6}.text-caption{color:var(--text-muted);font-size:clamp(var(--space-sm),1vw,.85rem);line-height:1.5}.text-callout{background:var(--earth-sand-light);border-left:var(--border-medium) solid var(--accent-coral);color:var(--text-primary);font-size:clamp(1rem,1.5vw,1.1rem);font-weight:600;line-height:1.6;margin:var(--space-lg,1.5rem);padding:var(--space-lg,1.5rem)}.code,code{font-family:var(--font-family-mono);font-size:clamp(.85rem,1vw,.9rem)}.code.code-inline,code.code-inline{background:var(--earth-sand);border-radius:var(--radius-sm);padding:.1rem .3rem}.code-block{background:var(--earth-sand);border:var(--border-thin) solid var(--earth-sage);border-radius:var(--radius-md);display:block;font-size:clamp(.85rem,1vw,.9rem);overflow-x:auto;padding:1rem}.text-muted{color:var(--text-muted)}.text-secondary{color:var(--text-secondary)}.text-accent{color:var(--accent-coral)}.text-semibold{font-weight:600}.text-bold{font-weight:700}.text-center{text-align:center}.lead,.text-lead{color:var(--text-secondary);font-size:clamp(1.1rem,2vw,1.35rem);line-height:1.7}.link,a{border-bottom:1px solid var(--earth-sage);color:var(--earth-sage);font-weight:var(--font-weight-semibold,600);text-decoration:none;-webkit-transition:all .2s;transition:all .2s}.link:focus,.link:hover,a:focus,a:hover{border-bottom-color:var(--earth-brown);color:var(--earth-brown)}.link-brackets{margin-left:var(--space-md)!important}.link-brackets:after{content:"]";margin-left:.2rem}.link-brackets:after,.link-brackets:before{color:var(--earth-sage);position:absolute;-webkit-transition:all .2s;transition:all .2s}.link-brackets:before{content:"[";margin-left:-.8rem}.link-brackets:focus:after,.link-brackets:focus:before,.link-brackets:hover:after,.link-brackets:hover:before{color:var(--accent-coral)}.blockquote,blockquote{border-left:var(--border-thin) solid var(--earth-brown);color:var(--text-secondary);font-style:italic;margin:var(--space-lg,1.5rem) 0;padding-left:var(--space-md,1rem)}.mb-1{margin-bottom:var(--space-2xs)!important}.mb-2{margin-bottom:var(--space-xs)!important}.mb-3{margin-bottom:var(--space-sm)!important}.mb-4{margin-bottom:var(--space-md)!important}.mb-5{margin-bottom:var(--space-xl)!important}.mt-1{margin-top:var(--space-2xs)!important}.mt-2{margin-top:var(--space-xs)!important}.mt-3{margin-top:var(--space-sm)!important}.mt-4{margin-top:var(--space-md)!important}.mt-5{margin-top:var(--space-xl)!important}.ml-1{margin-left:var(--space-2xs)!important}.ml-2{margin-left:var(--space-xs)!important}.ml-3{margin-left:var(--space-sm)!important}.ml-4{margin-left:var(--space-md)!important}.ml-5{margin-left:var(--space-xl)!important}.mr-1{margin-right:var(--space-2xs)!important}.mr-2{margin-right:var(--space-xs)!important}.mr-3{margin-right:var(--space-sm)!important}.mr-4{margin-right:var(--space-md)!important}.mr-5{margin-right:var(--space-xl)!important}.p-1{padding:var(--space-2xs)!important}.p-2{padding:var(--space-xs)!important}.p-3{padding:var(--space-sm)!important}.p-4{padding:var(--space-md)!important}.p-5{padding:var(--space-xl)!important}.pt-1{padding-top:var(--space-2xs)!important}.pt-2{padding-top:var(--space-xs)!important}.pt-3{padding-top:var(--space-sm)!important}.pt-4{padding-top:var(--space-md)!important}.pt-5{padding-top:var(--space-xl)!important}.pb-1{padding-bottom:var(--space-2xs)!important}.pb-2{padding-bottom:var(--space-xs)!important}.pb-3{padding-bottom:var(--space-sm)!important}.pb-4{padding-bottom:var(--space-md)!important}.pb-5{padding-bottom:var(--space-xl)!important}.pl-1{padding-left:var(--space-2xs)!important}.pl-2{padding-left:var(--space-xs)!important}.pl-3{padding-left:var(--space-sm)!important}.pl-4{padding-left:var(--space-md)!important}.pl-5{padding-left:var(--space-xl)!important}.pr-1{padding-right:var(--space-2xs)!important}.pr-2{padding-right:var(--space-xs)!important}.pr-3{padding-right:var(--space-sm)!important}.pr-4{padding-right:var(--space-md)!important}.pr-5{padding-right:var(--space-xl)!important}section{margin:0 auto;max-width:1200px;padding:var(--space-3xl,6rem) var(--space-lg,2rem)}.justify-content-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:var(--space-lg,2rem)}@media (width >= 768px){.row{gap:var(--space-sm,.5rem)}.card-body .row{gap:0}}.button-row{gap:1rem}.no-wrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.d-flex{display:-webkit-box;display:-ms-flexbox;display:flex}.flex-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.align-items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.work-grid{display:grid;gap:var(--space-lg,2rem);grid-template-columns:repeat(auto-fit,minmax(300px,1fr));margin-bottom:var(--space-lg,2rem)}.divider{background:var(--accent-coral);border:var(--border-medium,4px) outset var(--earth-dark);display:block;height:var(--space-md,1.5rem);margin:0 auto;width:50%}.divider.vertical{background:var(--earth-dark);border:none!important;border-radius:var(--radius-sm);height:100%;margin:0;width:var(--space-2xs,.25rem)}.card-body ol,.card-body ul,ol,ol.list,ul,ul.list{margin-left:var(--space-lg)!important;padding-left:var(--space-md)!important}.highlight-block{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.header-highlight{margin:var(--space-md) auto;padding:var(--space-md);text-align:center;width:100%}nav{backdrop-filter:blur(24px);background:hsla(42,39%,94%,.5);border:var(--border-medium,4px) solid var(--earth-brown);border-radius:50px;-webkit-box-shadow:0 8px 24px var(--shadow-heavy);box-shadow:0 8px 24px var(--shadow-heavy);-webkit-filter:url(#lensFilter) saturate(120%) brightness(1.15);filter:url(#lensFilter) saturate(120%) brightness(1.15);left:50%;padding:var(--space-sm) 2rem;position:fixed;top:2rem;-webkit-transform:translateX(-50%);transform:translateX(-50%);z-index:1000}.main-nav{left:0;margin:0 auto;position:sticky;right:0;top:2rem;-webkit-transform:none!important;transform:none!important;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}nav ul{display:-webkit-box;display:-ms-flexbox;display:flex;list-style:none;-webkit-box-pack:center;-ms-flex-pack:center;gap:2rem;justify-content:center;margin-left:0!important;padding-left:0!important}nav a{border-bottom:none;color:var(--text-primary);font-size:.95rem;font-weight:500;padding:var(--space-2xs) var(--space-xs,.5rem);text-decoration:none;-webkit-transition:color .3s;transition:color .3s}nav a:focus,nav a:hover{outline:var(--border-thin) solid var(--accent-coral);outline-offset:2px}nav a.active,nav a:focus,nav a:hover{color:var(--accent-coral)}nav a.sub-page{outline:var(--border-thin) solid var(--text-secondary);outline-offset:2px}nav a.sub-page:hover{outline-color:var(--accent-coral)}@media (width <= 768px){nav{margin:0 auto!important;padding:var(--space-xs,.5rem) var(--space-sm,1rem)!important;top:var(--space-sm,1rem)!important}nav ul{gap:var(--space-sm,1rem)}}footer{background:var(--earth-dark);border-top:var(--border-extra-thick,8px) solid var(--earth-brown);-webkit-box-shadow:0 -10px 30px var(--shadow);box-shadow:0 -10px 30px var(--shadow);color:var(--earth-cream);margin-top:var(--space-3xl,6rem);padding:var(--space-2xl,3rem) var(--space-xl,2rem)}.footer-content{display:grid;gap:3rem;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));margin:0 auto;max-width:1200px}.footer-section h3{color:var(--accent-coral);font-size:clamp(1.2rem,2vw,1.5rem)}.footer-section h3,.footer-section h4{font-family:Playfair Display,serif;margin-bottom:var(--space-md,1rem)}.footer-section h4{color:hsla(0,0%,100%,.5)!important;font-size:clamp(1.1rem,1.25vw,1.125rem)}.footer-section li,.footer-section p{color:var(--earth-cream);line-height:1.6;margin-bottom:var(--space-xs,.5rem)}.footer-section ul{list-style:none;padding:0}.footer-section li{margin-bottom:var(--space-xs,.5rem)}.footer-bottom{border-top:var(--border-medium,4px) solid var(--earth-brown);color:var(--earth-sand);margin-top:var(--space-2xl,3rem);padding-top:var(--space-xl,2rem);text-align:center}.footer-bottom p{color:var(--earth-cream);font-size:var(--font-size-sm);margin:0}.footer-bottom a,.footer-section a{color:var(--earth-cream);text-decoration:underline}.footer-bottom a:hover,.footer-section a:hover{color:var(--accent-coral)}.badge{background:var(--earth-sage);border:var(--border-thin,2px) solid var(--earth-brown);border-radius:var(--radius-pill);color:var(--earth-cream);display:inline-block;font-size:.85rem;font-weight:600;padding:var(--space-2xs,.25rem) var(--space-sm,.75rem)}.badge-accent{background:var(--accent-coral-dark)}.badge-outline{background:transparent;color:inherit}.badges,.row-badges{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:var(--space-2xs,.25rem)}.btn{border:none;border-radius:var(--radius-md,12px);cursor:pointer;display:inline-block;font-family:var(--font-family-sans);font-size:var(--font-size-md,1rem);font-weight:600;padding:var(--space-sm,.75rem) var(--space-lg,1.5rem);text-align:center;text-decoration:none;-webkit-transition:all .2s;transition:all .2s}.btn:focus,.btn:hover{-webkit-box-shadow:2px 2px 0 var(--earth-brown);box-shadow:2px 2px 0 var(--earth-brown);-webkit-transform:translate(2px,2px);transform:translate(2px,2px)}.btn-primary{border:var(--border-medium,4px) solid var(--earth-brown);-webkit-box-shadow:4px 4px 0 var(--earth-brown);box-shadow:4px 4px 0 var(--earth-brown)}.btn-primary,.btn-primary:focus,.btn-primary:hover{background:var(--accent-coral-dark);color:var(--white)}.btn-secondary{background:var(--earth-cream);border:var(--border-medium,4px) solid var(--earth-brown);-webkit-box-shadow:4px 4px 0 var(--earth-sage);box-shadow:4px 4px 0 var(--earth-sage);color:var(--text-primary)}.btn-secondary:focus,.btn-secondary:hover{background:var(--earth-sand);-webkit-box-shadow:2px 2px 0 var(--earth-sage);box-shadow:2px 2px 0 var(--earth-sage);color:var(--text-primary);outline:var(--border-thin) solid var(--earth-dark);-webkit-transform:translate(2px,2px);transform:translate(2px,2px)}.btn-outline{backdrop-filter:blur(24px);background:hsla(0,0%,100%,.5)!important;border:var(--border-medium,4px) solid var(--earth-brown)!important;-webkit-box-shadow:none!important;box-shadow:none!important;color:var(--text-primary)!important;-webkit-filter:url(#lensFilter) saturate(120%) brightness(1.15);filter:url(#lensFilter) saturate(120%) brightness(1.15)}.btn-outline:focus,.btn-outline:hover{color:var(--earth-cream);text-decoration:underline}.btn-sm{border-width:var(--border-thin)!important;font-size:.9rem!important;padding:var(--space-xs,.5rem) var(--space-md,1rem)!important}.btn-lg{font-size:1.1rem!important;padding:var(--space-md,1rem) var(--space-xl,2rem)!important}.skip-link{background:var(--accent-coral);border:var(--border-medium,4px) solid var(--earth-brown);color:var(--white);font-weight:600;left:0;padding:var(--space-sm,.75rem) var(--space-lg,1.5rem);position:absolute;text-decoration:none;top:-100px;z-index:2000;clip:rect(0,0,0,0);overflow:hidden}.skip-link:focus{left:1rem;top:1rem;clip:auto;overflow:visible}.social-links{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:1rem}.social-link{background:var(--earth-sage);border:var(--border-medium,4px) solid var(--earth-sand);border-radius:8px;color:var(--white);display:inline-block;font-size:.95rem;font-weight:500;padding:var(--space-xs,.5rem) var(--space-md,1rem);text-decoration:none!important;-webkit-transition:all .3s;transition:all .3s}.social-link:focus,.social-link:hover{background:var(--accent-coral);color:var(--white)!important;-webkit-transform:translateY(-2px);transform:translateY(-2px)}.card{background:var(--earth-cream);border:var(--border-thick,6px) solid var(--earth-brown);border-radius:var(--radius-xl,20px);-webkit-box-shadow:8px 8px 0 var(--shadow-heavy);box-shadow:8px 8px 0 var(--shadow-heavy);padding:var(--space-lg,1.5rem);-webkit-transition:-webkit-transform .3s,-webkit-box-shadow .3s;transition:-webkit-transform .3s,-webkit-box-shadow .3s;transition:transform .3s,box-shadow .3s;transition:transform .3s,box-shadow .3s,-webkit-transform .3s,-webkit-box-shadow .3s}.card:focus-within,.card:hover{-webkit-box-shadow:12px 12px 0 var(--shadow-heavy);box-shadow:12px 12px 0 var(--shadow-heavy);-webkit-transform:translateY(-5px);transform:translateY(-5px)}.card-layered{border:var(--border-thick,6px) solid var(--earth-brown);border-radius:var(--radius-xl,20px);-webkit-box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown);box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown);padding:var(--space-xl,2rem)}.card-layered,.card-shadow{background:var(--earth-cream)}.card-shadow{border:none;border-radius:var(--radius-lg,16px);-webkit-box-shadow:10px 10px 0 var(--shadow-heavy);box-shadow:10px 10px 0 var(--shadow-heavy);padding:var(--space-md,1.5rem)}.card-accent{background:var(--earth-cream);border:var(--border-extra-thick,8px) solid var(--earth-brown);border-radius:var(--radius-xl,20px);-webkit-box-shadow:16px 16px 0 var(--accent-coral),16px 16px 0 6px var(--earth-brown);box-shadow:16px 16px 0 var(--accent-coral),16px 16px 0 6px var(--earth-brown);overflow:hidden}.card-flex{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-flex p{-webkit-box-flex:1;-ms-flex:1 0;flex:1 0}.card-with-columns .row{gap:var(--space-md,1rem);-ms-flex-item-align:stretch}.card-with-columns .column,.card-with-columns .row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;align-self:stretch}.card-with-columns .column{-webkit-box-flex:1;-ms-flex:1 0 0px;flex:1 0 0;-ms-flex-item-align:stretch}.card-header{border-bottom:var(--border-thin,2px) solid var(--earth-sand);margin-bottom:var(--space-md,1rem);padding-bottom:var(--space-md,1rem)}.card-body{margin-bottom:var(--space-md)}.card-body img{-o-object-fit:cover;object-fit:cover;width:100%}@media (width >= 768px){.img-thumbnail{max-width:50%}}.card-body:last-child{margin-bottom:0}.card-footer{border-top:var(--border-thin,2px) solid var(--earth-sand);margin-top:var(--space-md,1rem);padding-top:var(--space-md,1rem)}.showcase-content{padding:var(--space-lg,2rem)}.showcase-content h3{color:var(--text-primary);font-family:var(--font-family-serif);font-size:clamp(1.3rem,2.5vw,1.8rem);margin-bottom:var(--space-sm,1rem)}.showcase-content p{color:var(--text-secondary);font-size:clamp(.95rem,1.5vw,1rem);margin-bottom:var(--space-md,1.5rem)}.showcase-small{background:var(--earth-sand);border:4px solid var(--earth-brown);border-radius:var(--radius-lg,16px);-webkit-box-shadow:6px 6px 0 var(--shadow-heavy);box-shadow:6px 6px 0 var(--shadow-heavy);padding:var(--space-md,1.5rem);-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.showcase-small:focus-within,.showcase-small:hover{-webkit-transform:translateY(-4px);transform:translateY(-4px)}.showcase-small h4{color:var(--text-primary);font-family:var(--font-family-serif);font-size:clamp(1.1rem,2vw,1.3rem);margin-bottom:var(--space-xs,.5rem)}.showcase-small p{color:var(--text-secondary);font-size:clamp(.9rem,1.5vw,.95rem)}.about-card{background:var(--earth-cream);border:var(--border-thick,6px) solid var(--earth-brown);border-radius:var(--border-radius-xl,20px);-webkit-box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown);box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown);margin:0 auto;padding:var(--space-2xl,3rem)}@media (width <= 768px){.about-card{-webkit-box-shadow:6px 6px 0 var(--earth-sage),6px 6px 0 4px var(--earth-brown);box-shadow:6px 6px 0 var(--earth-sage),6px 6px 0 4px var(--earth-brown);padding:var(--space-md,1rem)}.about-grid{grid-template-columns:1fr!important}}.about-card p{color:var(--text-primary);font-size:clamp(1rem,1.5vw,1.1rem);line-height:1.8;margin-bottom:var(--space-lg,1.5rem)}.about-card p:last-child{margin-bottom:0}.about-grid{display:grid;gap:var(--space-xl,2rem);grid-template-columns:repeat(auto-fit,minmax(350px,1fr));margin-top:var(--space-xl,2rem)}.showcase-large{background:var(--earth-cream);border:var(--border-thick,6px) solid var(--earth-brown);border-radius:var(--radius-xl,20px);-webkit-box-shadow:12px 12px 0 var(--accent-coral),12px 12px 0 6px var(--earth-brown);box-shadow:12px 12px 0 var(--accent-coral),12px 12px 0 6px var(--earth-brown);overflow:hidden;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}@media (width <= 768px){.showcase-large{-webkit-box-shadow:6px 6px 0 var(--accent-coral),6px 6px 0 4px var(--earth-brown);box-shadow:6px 6px 0 var(--accent-coral),6px 6px 0 4px var(--earth-brown)}}.showcase-large:focus-within,.showcase-large:hover{-webkit-transform:translateY(-8px);transform:translateY(-8px)}.showcase-image{background:linear-gradient(135deg,var(--earth-sage) 0,var(--earth-sand) 100%);display:-webkit-box;display:-ms-flexbox;display:flex;height:300px;width:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;border-bottom:var(--border-thick,6px) solid var(--earth-brown);color:var(--earth-cream);font-size:var(--font-size-5xl,3rem);justify-content:center;-o-object-fit:contain;object-fit:contain;padding:var(--space-md,1rem)}.showcase-image-dark{background:linear-gradient(135deg,var(--black) 0,var(--earth-dark) 100%)}.small-showcase-cards{display:grid;gap:var(--space-md,1.5rem);grid-column:1/-1;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));margin-top:var(--space-sm,1rem)}.callouts-grid{display:grid;gap:2rem;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));margin-top:2rem}.callout{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end;-webkit-box-pack:justify;-ms-flex-pack:justify;background:var(--earth-cream);border:var(--border-thick,6px) solid var(--accent-coral-dark);border-radius:var(--radius-xl,20px);-webkit-box-shadow:8px 8px 0 var(--shadow-heavy);box-shadow:8px 8px 0 var(--shadow-heavy);justify-content:space-between;padding:2rem;position:relative;-webkit-transition:-webkit-transform .3s,-webkit-box-shadow .3s;transition:-webkit-transform .3s,-webkit-box-shadow .3s;transition:transform .3s,box-shadow .3s;transition:transform .3s,box-shadow .3s,-webkit-transform .3s,-webkit-box-shadow .3s}.callout:focus-within,.callout:hover{-webkit-box-shadow:12px 12px 0 var(--shadow-heavy);box-shadow:12px 12px 0 var(--shadow-heavy);-webkit-transform:translateY(-5px);transform:translateY(-5px)}.callout:before{color:var(--accent-coral);content:'"';font-family:var(--font-family-serif);font-size:var(--font-size-6xl,4rem);left:20px;line-height:1;position:absolute;top:10px}.callout-text{color:var(--text-primary);font-style:italic;margin-bottom:var(--space-md,1.5rem);padding-top:var(--space-sm,1rem)}.callout-author{color:var(--text-primary);display:block;font-weight:600}.callout-role{color:var(--text-secondary);font-size:var(--font-size-sm,.9rem)}.gallery{--size:100px;display:grid;gap:5px;grid-auto-rows:var(--size);grid-template-columns:repeat(6,var(--size));margin-bottom:var(--size);place-items:start center}.gallery:has(:focus) picture:not(:focus),.gallery:has(:hover) picture:not(:hover){-webkit-filter:brightness(.5) contrast(.5);filter:brightness(.5) contrast(.5)}.gallery picture{border-radius:5px;clip-path:path("M90,10 C100,0 100,0 110,10 190,90 190,90 190,90 200,100 200,100 190,110 190,110 110,190 110,190 100,200 100,200 90,190 90,190 10,110 10,110 0,100 0,100 10,90Z");grid-column:auto/span 2;height:calc(var(--size)*2);-o-object-fit:cover;object-fit:cover;-webkit-transition:clip-path .25s,-webkit-filter .75s;transition:clip-path .25s,-webkit-filter .75s;transition:clip-path .25s,filter .75s;transition:clip-path .25s,filter .75s,-webkit-filter .75s;width:calc(var(--size)*2)}.gallery picture:nth-child(5n-1){grid-column:2/span 2}.gallery picture:focus,.gallery picture:hover{clip-path:path("M0,0 C0,0 200,0 200,0 200,0 200,100 200,100 200,100 200,200 200,200 200,200 100,200 100,200 100,200 100,200 0,200 0,200 0,100 0,100 0,100 0,100 0,100Z");-webkit-transition:clip-path .25s,-webkit-filter .25s;transition:clip-path .25s,-webkit-filter .25s;transition:clip-path .25s,filter .25s;transition:clip-path .25s,filter .25s,-webkit-filter .25s;z-index:1}.gallery picture:focus{outline:1px dashed #000;outline-offset:-5px}.carousel>input{height:1px;width:1px;clip:rect(1px,1px,1px,1px);clip-path:inset(50%);margin:-1px;overflow:hidden;padding:0;position:absolute}.carousel>input:nth-of-type(15):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1400%}.carousel>input:nth-of-type(14):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1300%}.carousel>input:nth-of-type(13):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1200%}.carousel>input:nth-of-type(12):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1100%}.carousel>input:nth-of-type(11):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1000%}.carousel>input:nth-of-type(10):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-900%}.carousel>input:nth-of-type(9):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-800%}.carousel>input:nth-of-type(8):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-700%}.carousel>input:nth-of-type(7):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-600%}.carousel>input:nth-of-type(6):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-500%}.carousel>input:nth-of-type(5):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-400%}.carousel>input:nth-of-type(4):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-300%}.carousel>input:nth-of-type(3):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-200%}.carousel>input:nth-of-type(2):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-100%}.carousel>input:first-of-type:checked~.carousel__slides .carousel__slide:first-of-type{margin-left:0}.carousel>input:first-of-type:checked~.carousel__thumbnails li:first-of-type,.carousel>input:nth-of-type(10):checked~.carousel__thumbnails li:nth-of-type(10),.carousel>input:nth-of-type(11):checked~.carousel__thumbnails li:nth-of-type(11),.carousel>input:nth-of-type(12):checked~.carousel__thumbnails li:nth-of-type(12),.carousel>input:nth-of-type(13):checked~.carousel__thumbnails li:nth-of-type(13),.carousel>input:nth-of-type(14):checked~.carousel__thumbnails li:nth-of-type(14),.carousel>input:nth-of-type(15):checked~.carousel__thumbnails li:nth-of-type(15),.carousel>input:nth-of-type(2):checked~.carousel__thumbnails li:nth-of-type(2),.carousel>input:nth-of-type(3):checked~.carousel__thumbnails li:nth-of-type(3),.carousel>input:nth-of-type(4):checked~.carousel__thumbnails li:nth-of-type(4),.carousel>input:nth-of-type(5):checked~.carousel__thumbnails li:nth-of-type(5),.carousel>input:nth-of-type(6):checked~.carousel__thumbnails li:nth-of-type(6),.carousel>input:nth-of-type(7):checked~.carousel__thumbnails li:nth-of-type(7),.carousel>input:nth-of-type(8):checked~.carousel__thumbnails li:nth-of-type(8),.carousel>input:nth-of-type(9):checked~.carousel__thumbnails li:nth-of-type(9){-webkit-box-shadow:0 0 0 5px rgba(0,0,255,.5);box-shadow:0 0 0 5px rgba(0,0,255,.5)}.carousel__slides{display:-webkit-box;display:-ms-flexbox;display:flex;margin:0;padding:0;white-space:nowrap;z-index:1}.carousel__slide,.carousel__slides{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;position:relative}.carousel__slide{display:block;-webkit-box-flex:1;-ms-flex:1 0 100%;flex:1 0 100%;height:100%;-webkit-transition:all .3s ease-out;transition:all .3s ease-out;vertical-align:top;white-space:normal;width:100%}.carousel__slide figure{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0}.carousel__slide div{position:relative;width:100%}.carousel__slide div:before{content:"";display:block;padding-top:66.6666666667%;width:100%}.carousel__slide div>img{height:100%;inset:0;position:absolute;width:100%}.carousel__slide img{display:block;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;-o-object-fit:cover;object-fit:cover}.carousel__slide figcaption{-ms-flex-item-align:center;align-self:center;padding:20px 20px 0;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;min-width:150px;width:25%}.carousel__slide .credit{color:rgba(0,0,0,.5);display:block;margin-top:1rem}.carousel__slide.scrollable{overflow-y:scroll}.carousel__thumbnails{display:-webkit-box;display:-ms-flexbox;display:flex;list-style:none;margin:0 -10px;padding:0}.carousel__slides+.carousel__thumbnails{margin-top:20px}.carousel__thumbnails li{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;margin:0 10px;max-width:calc(16.66667% - 20px);-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.carousel__thumbnails label{display:block;position:relative}.carousel__thumbnails label:before{content:"";display:block;padding-top:100%;width:100%}.carousel__thumbnails label>img{height:100%;inset:0;position:absolute;width:100%}.carousel__thumbnails label:focus,.carousel__thumbnails label:hover{cursor:pointer}.carousel__thumbnails label:focus img,.carousel__thumbnails label:hover img{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.25);box-shadow:0 0 0 1px rgba(0,0,0,.25);-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.carousel__thumbnails img{display:block;height:100%;-o-object-fit:cover;object-fit:cover;width:100%} -/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zYXNzL192YXJpYWJsZXMuc2NzcyIsInN0eWxlLmNzcyIsIi4uLy4uL3NyYy9zYXNzL3N0eWxlLnNjc3MiLCIuLi8uLi9zcmMvc2Fzcy9fYW5pbWF0aW9ucy5zY3NzIiwiLi4vLi4vc3JjL3Nhc3MvX2ZvbnRzLnNjc3MiLCIuLi8uLi9zcmMvc2Fzcy9fdHlwb2dyYXBoeS5zY3NzIiwiLi4vLi4vc3JjL3Nhc3MvX3NwYWNpbmcuc2NzcyIsIi4uLy4uL3NyYy9zYXNzL19sYXlvdXQuc2NzcyIsIi4uLy4uL3NyYy9zYXNzL19saXN0cy5zY3NzIiwiLi4vLi4vc3JjL3Nhc3MvX2hpZ2hsaWdodC5zY3NzIiwiLi4vLi4vc3JjL3Nhc3MvX25hdmlnYXRpb24uc2NzcyIsIi4uLy4uL3NyYy9zYXNzL19mb290ZXIuc2NzcyIsIi4uLy4uL3NyYy9zYXNzL19iYWRnZS5zY3NzIiwiLi4vLi4vc3JjL3Nhc3MvX2J1dHRvbnMuc2NzcyIsIi4uLy4uL3NyYy9zYXNzL19jYXJkcy5zY3NzIiwiLi4vLi4vc3JjL3Nhc3MvX2dhbGxlcnkuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSxNQUVFLHlIQUFBLENBQ0EsNENBQUEsQ0FDQSw4REFBQSxDQUNBLDBDQUFBLENBR0EsZUFBQSxDQUNBLGVBQUEsQ0FDQSxvQkFBQSxDQUNBLHFCQUFBLENBQ0Esb0JBQUEsQ0FDQSxvQkFBQSxDQUNBLHFCQUFBLENBQ0Esc0JBQUEsQ0FDQSwyQkFBQSxDQUNBLHNCQUFBLENBQ0Esd0JBQUEsQ0FDQSxvQkFBQSxDQUNBLDJCQUFBLENBQ0EsaUNBQUEsQ0FDQSxpQ0FBQSxDQUdBLHNCQUFBLENBQ0EsdUJBQUEsQ0FDQSxtQkFBQSxDQUNBLHVCQUFBLENBQ0Esc0JBQUEsQ0FDQSxzQkFBQSxDQUNBLG9CQUFBLENBQ0Esc0JBQUEsQ0FDQSxvQkFBQSxDQUNBLG9CQUFBLENBR0EsbUJBQUEsQ0FDQSxpQkFBQSxDQUNBLGtCQUFBLENBQ0EsZUFBQSxDQUNBLGlCQUFB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a0JKNlhKLENJM1hFLHNCQUNFLFdBQUEsQ0FFQSxrQkp3WEosQ0lwWEUsOEdBRUUseUJKcVhKLENJaFhBLHVCQUNFLHVEQUFBLENBSUEsMkJBQUEsQ0FEQSxpQkFBQSxDQURBLCtCQUFBLENBREEsaUNKdVhGLENLMWxCQSxNQUNFLHdDTDZsQkYsQ0szbEJBLE1BQ0UsdUNMOGxCRixDSzVsQkEsTUFDRSx1Q0wrbEJGLENLN2xCQSxNQUNFLHVDTGdtQkYsQ0s5bEJBLE1BQ0UsdUNMaW1CRixDSy9sQkEsTUFDRSxxQ0xrbUJGLENLaG1CQSxNQUNFLG9DTG1tQkYsQ0tqbUJBLE1BQ0Usb0NMb21CRixDS2xtQkEsTUFDRSxvQ0xxbUJGLENLbm1CQSxNQUNFLG9DTHNtQkYsQ0twbUJBLE1BQ0Usc0NMdW1CRixDS3JtQkEsTUFDRSxxQ0x3bUJGLENLdG1CQSxNQUNFLHFDTHltQkYsQ0t2bUJBLE1BQ0UscUNMMG1CRixDS3htQkEsTUFDRSxxQ0wybUJGLENLem1CQSxNQUNFLHVDTDRtQkYsQ0sxbUJBLE1BQ0Usc0NMNm1CRixDSzNtQkEsTUFDRSxzQ0w4bUJGLENLNW1CQSxNQUNFLHNDTCttQkYsQ0s3bUJBLE1BQ0Usc0NMZ25CRixDSzltQkEsS0FDRSxrQ0xpbkJGLENLL21CQSxLQUNFLGlDTGtuQkYsQ0tobkJBLEtBQ0UsaUNMbW5CRixDS2puQkEsS0FDRSxpQ0xvbkJGLENLbG5CQSxLQUNFLGlDTHFuQkYsQ0tubkJBLE1BQ0Usc0NMc25CRixDS3BuQkEsTUFDRSxxQ0x1bkJGLENLcm5CQSxNQUNFLHFDTHduQkYsQ0t0bkJBLE1BQ0UscUNMeW5CRixDS3ZuQkEsTUFDRSxxQ0wwbkJGLENLeG5CQSxNQUNFLHlDTDJuQkYsQ0t6bkJBLE1BQ0Usd0NMNG5CRixDSzFuQkEsTUFDRSx3Q0w2bkJGLENLM25CQSxNQUNFLHdDTDhuQkYsQ0s1bkJBLE1BQ0Usd0NMK25CRixDSzduQkEsTUFDRSx1Q0xnb0JGLENLOW5CQSxNQUNFLHNDTGlvQkYsQ0svbkJBLE1BQ0Usc0NMa29CRixDS2hvQkEsTUFDRSxzQ0xtb0JGLENLam9CQSxNQUNFLHNDTG9vQkYsQ0tsb0JBLE1BQ0Usd0NMcW9CRixDS25vQkEsTUFDRSx1Q0xzb0JGLENLcG9CQSxNQUNFLHVDTHVvQkYsQ0tyb0JBLE1BQ0UsdUNMd29CRixDS3RvQkEsTUFDRSx1Q0x5b0JGLENNendCQSxRQUVFLGFBQUEsQ0FEQSxnQkFBQSxDQUVBLGtETjZ3QkYsQ00xd0JBLHdCQUNFLGlDQUFBLENBQUEsOEJBQUEsQ0FBQSxnQ042d0JGLENNM3dCQSx5QkFDRSxrQ0FBQSxDQUFBLCtCQUFBLENBQUEsdUNOOHdCRixDTTV3QkEscUJBQ0UsOEJBQUEsQ0FBQSwyQkFBQSxDQUFBLGtDTit3QkYsQ003d0JBLEtBQ0UsbUJBQUEsQ0FBQSxtQkFBQSxDQUFBLFlBQUEsQ0FDQSxrQkFBQSxDQUFBLGNBQUEsQ0FDQSx3Qk5neEJGLENNOXdCQSx3QkFDRSxLQUNFLHlCTml4QkYsQ003d0JBLGdCQUNFLEtOaXhCRixDQUpGLENNMXdCQSxZQUNFLFFOaXhCRixDTS93QkEsU0FDRSxvQkFBQSxDQUFBLGdCTmt4QkYsQ01oeEJBLFFBQ0UsbUJBMUNLLENBMENMLG1CQTFDSyxDQTBDTCxZTm14QkYsQ01qeEJBLGFBQ0UsMkJBNUNPLENBNENQLDRCQTVDTyxDQTRDUCx5QkE1Q08sQ0E0Q1AscUJOb3hCRixDTWx4QkEsb0JBQ0Usd0JBOUNPLENBOENQLHFCQTlDTyxDQThDUCxrQk5xeEJGLENNbnhCQSxXQUNFLFlBQUEsQ0FDQSx3QkFBQSxDQUNBLHdEQUFBLENBQ0Esa0NOc3hCRixDTXB4QkEsU0FJRSw4QkFBQSxDQUNBLHdEQUFBLENBSkEsYUFBQSxDQUVBLDZCQUFBLENBR0EsYUFBQSxDQUpBLFNOMnhCRixDTXJ4QkEsa0JBR0UsNEJBQUEsQ0FFQSxxQkFBQSxDQURBLDhCQUFBLENBRkEsV0FBQSxDQUlBLFFBQUEsQ0FMQSw2Qk42eEJGLENPOTFCQSxrREFLRSxxQ0FBQSxDQUNBLHNDUGkyQkYsQ1F2MkJBLGlCQUNFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBQ0EsNkJBQUEsQ0FBQSw0QkFBQSxDQUFBLHNCQUFBLENBQUEsa0JBQUEsQ0FDQSx3QkFBQSxDQUFBLHFCQUFBLENBQUEsa0JBQUEsQ0FDQSx1QkFBQSxDQUFBLG9CQUFBLENBQUEsc0JSMDJCRixDUXgyQkEsa0JBRUUsMkJBQUEsQ0FDQSx1QkFBQSxDQUZBLGlCQUFBLENBR0EsVVIyMkJGLENTcDNCQSxJQU9FLDBCQUFBLENBREEsOEJBQUEsQ0FHQSx3REFBQSxDQUNBLGtCQUFBLENBRUEsaURBQUEsQ0FBQSx5Q0FBQSxDQUpBLCtEQUFBLENBQUEsdURBQUEsQ0FMQSxRQUFBLENBUUEsNEJBQUEsQ0FWQSxjQUFBLENBQ0EsUUFBQSxDQUVBLGtDQUFBLENBQUEsMEJBQUEsQ0FDQSxZVCszQkYsQ1N0M0JBLFVBTUUsTUFBQSxDQUhBLGFBQUEsQ0FGQSxlQUFBLENBTUEsT0FBQSxDQUxBLFFBQUEsQ0FHQSxnQ0FBQSxDQUFBLHdCQUFBLENBREEseUJBQUEsQ0FBQSxzQkFBQSxDQUFBLGlCVDQzQkYsQ1N0M0JBLE9BRUUsbUJBQUEsQ0FBQSxtQkFBQSxDQUFBLFlBQUEsQ0FEQSxlQUFBLENBRUEsdUJBQUEsQ0FBQSxvQkFBQSxDQUNBLFFBQUEsQ0FEQSxzQkFBQSxDQUVBLHVCQUFBLENBQ0Esd0JUeTNCRixDU3QzQkEsTUFPRSxrQkFBQSxDQUxBLHlCQUFBLENBRUEsZ0JBQUEsQ0FEQSxlQUFBLENBR0EsOENBQUEsQ0FMQSxvQkFBQSxDQUlBLDRCQUFBLENBQUEsb0JUMjNCRixDU3QzQkEsd0JBR0Usb0RBQUEsQ0FDQSxrQlR5M0JGLENTdjNCQSxxQ0FKRSx5QlQrM0JGLENTeDNCQSxlQUNFLHNEQUFBLENBQ0Esa0JUMjNCRixDU3ozQkEscUJBQ0UsaUNUNDNCRixDU3ozQkEsd0JBQ0ksSUFHQSx1QkFBQSxDQURBLDREQUFBLENBREEsa0NUODNCRixDU3YzQkEsT0FDRSx3QlR5M0JGLENBQ0YsQ1VoOEJBLE9BQ0UsNEJBQUEsQ0FJQSxpRUFBQSxDQUNBLDZDQUFBLENBQUEscUNBQUEsQ0FKQSx3QkFBQSxDQUVBLGdDQUFBLENBREEsa0RWczhCRixDVWg4QkEsZ0JBR0UsWUFBQSxDQUVBLFFBQUEsQ0FEQSx3REFBQSxDQUZBLGFBQUEsQ0FEQSxnQlZ1OEJGLENVaDhCQSxtQkFFRSx5QkFBQSxDQUVBLGtDVm04QkYsQ1VqOEJBLHNDQUxFLGtDQUFBLENBRUEsa0NWMjhCRixDVXg4QkEsbUJBRUUsa0NBQUEsQ0FFQSx1Q1ZvOEJGLENVbDhCQSxxQ0FFRSx3QkFBQSxDQUNBLGVBQUEsQ0FDQSxtQ1ZxOEJGLENVbjhCQSxtQkFDRSxlQUFBLENBQ0EsU1ZzOEJGLENVcDhCQSxtQkFDRSxtQ1Z1OEJGLENVcjhCQSxlQUlFLDREQUFBLENBQ0EsdUJBQUEsQ0FIQSxnQ0FBQSxDQUNBLGdDQUFBLENBRkEsaUJWNDhCRixDVXQ4QkEsaUJBR0Usd0JBQUEsQ0FEQSw2QkFBQSxDQURBLFFWMjhCRixDVXY4QkEsbUNBRUUsd0JBQUEsQ0FDQSx5QlYwOEJGLENVeDhCQSwrQ0FFRSx5QlYyOEJGLENXeGdDQSxPQUtFLDRCQUFBLENBRUEsc0RBQUEsQ0FDQSxnQ0FBQSxDQUZBLHdCQUFBLENBTEEsb0JBQUEsQ0FFQSxnQkFBQSxDQUNBLGVBQUEsQ0FGQSxzRFhraENGLENXemdDQSxjQUNFLG1DWDRnQ0YsQ1d6Z0NBLGVBQ0Usc0JBQUEsQ0FDQSxhWDRnQ0YsQ1cxZ0NBLG9CQUNFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBRUEsa0JBQUEsQ0FBQSxjQUFBLENBREEsMkJYOGdDRixDWW5pQ0EsS0FVRSxXQUFBLENBSEEsbUNBQUEsQ0FFQSxjQUFBLENBUkEsb0JBQUEsQ0FFQSxtQ0FBQSxDQUNBLGtDQUFBLENBQ0EsZUFBQSxDQUhBLHFEQUFBLENBU0EsaUJBQUEsQ0FMQSxvQkFBQSxDQUVBLDBCQUFBLENBQUEsa0JaMGlDRixDWXJpQ0Esc0JBR0UsK0NBQUEsQ0FBQSx1Q0FBQSxDQURBLG9DQUFBLENBQUEsNEJaeWlDRixDWWppQ0EsYUFHRSx3REFBQSxDQUNBLCtDQUFBLENBQUEsdUNacWlDRixDWWxpQ0EsbURBTkUsbUNBQUEsQ0FDQSxrQlo2aUNGLENZOWhDQSxlQUNFLDZCQUFBLENBRUEsd0RBQUEsQ0FDQSw4Q0FBQSxDQUFBLHNDQUFBLENBRkEseUJab2lDRixDWS9oQ0EsMENBRUUsNEJBQUEsQ0FHQSw4Q0FBQSxDQUFBLHNDQUFBLENBRkEseUJBQUEsQ0FHQSxrREFBQSxDQUZBLG9DQUFBLENBQUEsNEJab2lDRixDWTVoQ0EsYUFFRSwwQkFBQSxDQURBLHVDQUFBLENBSUEsa0VBQUEsQ0FDQSxpQ0FBQSxDQUFBLHlCQUFBLENBRkEsbUNBQUEsQ0FEQSwrREFBQSxDQUFBLHVEWm1pQ0YsQ1k3aENBLHNDQUVFLHdCQUFBLENBQ0EseUJaZ2lDRixDWXpoQ0EsUUFHRSx5Q0FBQSxDQURBLHlCQUFBLENBREEsNERaK2hDRixDWTFoQ0EsUUFFRSwwQkFBQSxDQURBLDJEWjhoQ0YsQ1l6aENBLFdBSUUsOEJBQUEsQ0FLQSx3REFBQSxDQUpBLGtCQUFBLENBR0EsZUFBQSxDQUxBLE1BQUEsQ0FHQSxxREFBQSxDQUxBLGlCQUFBLENBTUEsb0JBQUEsQ0FMQSxVQUFBLENBUUEsWUFBQSxDQUNBLGtCQUFBLENBQ0EsZVo2aENGLENZMWhDQSxpQkFFRSxTQUFBLENBREEsUUFBQSxDQUVBLFNBQUEsQ0FDQSxnQlo2aENGLENZMWhDQSxjQUNFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBRUEsa0JBQUEsQ0FBQSxjQUFBLENBREEsUVo4aENGLENZMWhDQSxhQUdFLDRCQUFBLENBR0EsdURBQUEsQ0FDQSxpQkFBQSxDQUhBLGtCQUFBLENBSEEsb0JBQUEsQ0FTQSxnQkFBQSxDQUZBLGVBQUEsQ0FOQSxrREFBQSxDQUdBLDhCQUFBLENBSUEsMEJBQUEsQ0FBQSxrQlo4aENGLENZMWhDQSxzQ0FFRSw4QkFBQSxDQUtBLDRCQUFBLENBSkEsa0NBQUEsQ0FBQSwwQlo4aENGLENhcHFDQSxNQUNFLDZCQUFBLENBQ0EsdURBQUEsQ0FDQSxtQ0FBQSxDQUVBLGdEQUFBLENBQUEsd0NBQUEsQ0FEQSw4QkFBQSxDQUVBLCtEQUFBLENBQUEsdURBQUEsQ0FBQSx1Q0FBQSxDQUFBLG9GYndxQ0YsQ2FycUNBLCtCQUdFLGtEQUFBLENBQUEsMENBQUEsQ0FEQSxrQ0FBQSxDQUFBLDBCYnlxQ0YsQ2FwcUNBLGNBRUUsdURBQUEsQ0FDQSxtQ0FBQSxDQUVBLG1GQUFBLENBQUEsMkVBQUEsQ0FEQSw0QmJ5cUNGLENhbnFDQSwyQkFURSw2QmJxckNGLENhNXFDQSxhQUVFLFdBQUEsQ0FDQSxtQ0FBQSxDQUVBLGtEQUFBLENBQUEsMENBQUEsQ0FEQSw4QmJ3cUNGLENhbnFDQSxhQUNFLDZCQUFBLENBQ0EsNkRBQUEsQ0FDQSxtQ0FBQSxDQUVBLHFGQUFBLENBQUEsNkVBQUEsQ0FEQSxlYndxQ0YsQ2FscUNBLFdBQ0UsbUJBQUEsQ0FBQSxtQkFBQSxDQUFBLFlBQUEsQ0FDQSwyQkFBQSxDQUFBLDRCQUFBLENBQUEseUJBQUEsQ0FBQSxxQmJzcUNGLENhcHFDQSxhQUNFLGtCQUFBLENBQUEsWUFBQSxDQUFBLFFidXFDRixDYW5xQ0Usd0JBR0Usd0JBQUEsQ0FDQSwyQmJzcUNKLENhcHFDRSxtREFMRSxtQkFBQSxDQUFBLG1CQUFBLENBQUEsWUFBQSxDQUNBLHVCQUFBLENBQUEsb0JBQUEsQ0FBQSxzQkFBQSxDQUVBLGtCYjRxQ0osQ2ExcUNFLDJCQUdFLGtCQUFBLENBQUEsZ0JBQUEsQ0FBQSxVQUFBLENBQ0EsMkJic3FDSixDYWpxQ0EsYUFHRSw0REFBQSxDQUZBLGtDQUFBLENBQ0EsbUNic3FDRixDYWpxQ0EsV0FDRSw2QmJxcUNGLENhbnFDQSxlQUNFLG1CQUFBLENBQUEsZ0JBQUEsQ0FDQSxVYnNxQ0YsQ2FucUNBLHdCQUNFLGVBQ0UsYWJzcUNGLENBQ0YsQ2FucUNBLHNCQUNFLGVicXFDRixDYWpxQ0EsYUFHRSx5REFBQSxDQUZBLCtCQUFBLENBQ0EsZ0Nic3FDRixDYWxxQ0Esa0JBQ0UsNEJicXFDRixDYWxxQ0EscUJBR0UseUJBQUEsQ0FGQSxvQ0FBQSxDQUNBLG9DQUFBLENBRUEsa0NicXFDRixDYWxxQ0Esb0JBQ0UsMkJBQUEsQ0FFQSxrQ0FBQSxDQURBLG9DYnNxQ0YsQ2FucUNBLGdCQUNFLDRCQUFBLENBQ0EsbUNBQUEsQ0FDQSxtQ0FBQSxDQUVBLGdEQUFBLENBQUEsd0NBQUEsQ0FEQSw4QkFBQSxDQUVBLHdDQUFBLENBQUEsZ0NBQUEsQ0FBQSx3QkFBQSxDQUFBLDhDYnNxQ0YsQ2FucUNBLG1EQUVFLGtDQUFBLENBQUEsMEJic3FDRixDYW5xQ0EsbUJBR0UseUJBQUEsQ0FGQSxvQ0FBQSxDQUNBLGtDQUFBLENBRUEsbUNic3FDRixDYW5xQ0Esa0JBQ0UsMkJBQUEsQ0FDQSxtQ2JzcUNGLENhbHFDQSxZQUNFLDZCQUFBLENBQ0EsdURBQUEsQ0FFQSwwQ0FBQSxDQUNBLG1GQUFBLENBQUEsMkVBQUEsQ0FFQSxhQUFBLENBSkEsNkJieXFDRixDYW5xQ0Esd0JBQ0UsWUFDRSwrRUFBQSxDQUFBLHVFQUFBLENBRUEsNEJicXFDRixDYW5xQ0EsWUFDRSxtQ2JxcUNGLENBQ0YsQ2FscUNBLGNBR0UseUJBQUEsQ0FGQSxrQ0FBQSxDQUNBLGVBQUEsQ0FFQSxvQ2JvcUNGLENhanFDQSx5QkFDRSxlYm9xQ0YsQ2FscUNBLFlBQ0UsWUFBQSxDQUVBLHdCQUFBLENBREEsd0RBQUEsQ0FFQSwrQmJxcUNGLENhbHFDQSxnQkFDRSw2QkFBQSxDQUNBLHVEQUFBLENBQ0EsbUNBQUEsQ0FFQSxxRkFBQSxDQUFBLDZFQUFBLENBREEsZUFBQSxDQUdBLHdDQUFBLENBQUEsZ0NBQUEsQ0FBQSx3QkFBQSxDQUFBLDhDYm9xQ0YsQ2FscUNBLHdCQUNFLGdCQUNFLGlGQUFBLENBQUEseUVicXFDRixDQUNGLENhanFDQSxtREFFRSxrQ0FBQSxDQUFBLDBCYm1xQ0YsQ2FocUNBLGdCQUdFLDZFQUFBLENBQ0EsbUJBQUEsQ0FBQSxtQkFBQSxDQUFBLFlBQUEsQ0FGQSxZQUFBLENBREEsVUFBQSxDQUlBLHdCQUFBLENBQUEscUJBQUEsQ0FBQSxrQkFBQSxDQUNBLHVCQUFBLENBQUEsb0JBQUEsQ0FJQSw4REFBQSxDQURBLHdCQUFBLENBREEsbUNBQUEsQ0FGQSxzQkFBQSxDQUtBLHFCQUFBLENBQUEsa0JBQUEsQ0FKQSw0QmJ1cUNGLENhanFDQSxxQkFDRSx3RWJvcUNGLENhaHFDQSxzQkFFRSxZQUFBLENBRUEsMEJBQUEsQ0FIQSxnQkFBQSxDQUVBLHdEQUFBLENBRUEsK0Jib3FDRixDYWhxQ0EsZUFDRSxZQUFBLENBRUEsUUFBQSxDQURBLHdEQUFBLENBRUEsZWJvcUNGLENhanFDQSxTQUNFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBQ0EsMkJBQUEsQ0FBQSw0QkFBQSxDQUFBLHlCQUFBLENBQUEscUJBQUEsQ0FDQSxxQkFBQSxDQUFBLGtCQUFBLENBQUEsb0JBQUEsQ0FDQSx3QkFBQSxDQUFBLHFCQUFBLENBQ0EsNkJBQUEsQ0FDQSw2REFBQSxDQUVBLG1DQUFBLENBQ0EsZ0RBQUEsQ0FBQSx3Q0FBQSxDQUxBLDZCQUFBLENBR0EsWUFBQSxDQUdBLGlCQUFBLENBQ0EsK0RBQUEsQ0FBQSx1REFBQSxDQUFBLHVDQUFBLENBQUEsb0Zib3FDRixDYWpxQ0EscUNBR0Usa0RBQUEsQ0FBQSwwQ0FBQSxDQURBLGtDQUFBLENBQUEsMEJicXFDRixDYWpxQ0EsZ0JBSUUseUJBQUEsQ0FIQSxXQUFBLENBQ0Esb0NBQUEsQ0FDQSxtQ0FBQSxDQUlBLFNBQUEsQ0FDQSxhQUFBLENBSEEsaUJBQUEsQ0FDQSxRYnNxQ0YsQ2FqcUNBLGNBSUUseUJBQUEsQ0FIQSxpQkFBQSxDQUNBLG9DQUFBLENBQ0EsZ0NicXFDRixDYWpxQ0EsZ0JBRUUseUJBQUEsQ0FDQSxhQUFBLENBRkEsZWJzcUNGLENhanFDQSxjQUVFLDJCQUFBLENBREEsbUNicXFDRixDYzk3Q0EsU0FDRSxZQUFBLENBRUEsWUFBQSxDQUtBLE9BQUEsQ0FIQSwwQkFBQSxDQURBLDJDQUFBLENBRUEseUJBQUEsQ0FDQSx3QmRrOENGLENjLzdDRSxrRkFFRSwwQ0FBQSxDQUFBLGtDZGc4Q0osQ2M3N0NFLGlCQVdFLGlCQUFBLENBUEEsZ0xBQUEsQ0FNQSx1QkFBQSxDQVBBLDBCQUFBLENBRkEsbUJBQUEsQ0FBQSxnQkFBQSxDQU1BLHFEQUNFLENBREYsNkNBQ0UsQ0FERixxQ0FDRSxDQURGLHlEQUNFLENBTkYseUJkbzhDSixDY3o3Q0ksaUNBQ0Usb0JkMjdDTixDY3g3Q0ksOENBRUUsd0tBQUEsQ0FJQSxxREFDRSxDQURGLDZDQUNFLENBREYscUNBQ0UsQ0FERix5REFDRSxDQUZGLFNkdzdDTixDY2w3Q0ksdUJBQ0UsdUJBQUEsQ0FDQSxtQmRvN0NOLENjaDVDRSxnQkFFRSxVQUFBLENBREEsU0FBQSxDQUVBLDBCQUFBLENBQ0Esb0JBQUEsQ0FDQSxXQUFBLENBQ0EsZUFBQSxDQUNBLFNBQUEsQ0FDQSxpQmRvNUNKLENjbDVDSSx5RkFHRSxrQmRrNUNOLENjaDVDSSx5RkFHRSxrQmRnNUNOLENjOTRDSSx5RkFHRSxrQmQ4NENOLENjNTRDSSx5RkFHRSxrQmQ0NENOLENjMTRDSSx5RkFHRSxrQmQwNENOLENjeDRDSSx5RkFHRSxpQmR3NENOLENjdDRDSSx3RkFHRSxpQmRzNENOLENjcDRDSSx3RkFHRSxpQmRvNENOLENjbDRDSSx3RkFHRSxpQmRrNENOLENjaDRDSSx3RkFHRSxpQmRnNENOLENjOTNDSSx3RkFHRSxpQmQ4M0NOLENjNTNDSSx3RkFHRSxpQmQ0M0NOLENjMTNDSSx3RkFHRSxpQmQwM0NOLENjeDNDSSx3RkFHRSxpQmR3M0NOLENjdDNDSSx1RkFHRSxhZHMzQ04sQ2N6MENJLDJxQ0FDRSw2Q0FBQSxDQUFBLHFDZHEzQ04sQ2NoM0NBLGtCQVFFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBSkEsUUFBQSxDQURBLFNBQUEsQ0FHQSxrQkFBQSxDQUpBLFNkeTNDRixDY2gzQ0EsbUNBSkUsNkJBQUEsQ0FBQSxxQkFBQSxDQUZBLGVBQUEsQ0FKQSxpQmR1NENGLENjNzNDQSxpQkFFRSxhQUFBLENBQ0Esa0JBQUEsQ0FBQSxpQkFBQSxDQUFBLGFBQUEsQ0FFQSxXQUFBLENBRUEsbUNBQUEsQ0FBQSwyQkFBQSxDQUNBLGtCQUFBLENBRUEsa0JBQUEsQ0FOQSxVZHkzQ0YsQ2NqM0NFLHdCQUNFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBQ0EsMkJBQUEsQ0FBQSw0QkFBQSxDQUFBLHlCQUFBLENBQUEscUJBQUEsQ0FDQSxRZG0zQ0osQ2NoM0NFLHFCQWhNQSxpQkFBQSxDQW1NRSxVZGkzQ0osQ2NsakRFLDRCQUVFLFVBQUEsQ0FEQSxhQUFBLENBR0EsMEJBQUEsQ0FEQSxVZHFqREosQ2NqakRFLHlCQUlFLFdBQUEsQ0FGQSxPQUFBLENBREEsaUJBQUEsQ0FFQSxVZG9qREosQ2MxM0NFLHFCQUNFLGFBQUEsQ0FDQSxrQkFBQSxDQUFBLGlCQUFBLENBQUEsYUFBQSxDQUNBLG1CQUFBLENBQUEsZ0JkNDNDSixDY3ozQ0UsNEJBQ0UsMEJBQUEsQ0FBQSxpQkFBQSxDQUNBLG1CQUFBLENBQ0Esa0JBQUEsQ0FBQSxpQkFBQSxDQUFBLGFBQUEsQ0FFQSxlQUFBLENBREEsU2Q0M0NKLENjeDNDRSx5QkFFRSxvQkFBQSxDQUNBLGFBQUEsQ0FGQSxlZDQzQ0osQ2N2M0NFLDRCQUNFLGlCZHkzQ0osQ2NyM0NBLHNCQUdFLG1CQUFBLENBQUEsbUJBQUEsQ0FBQSxZQUFBLENBRkEsZUFBQSxDQUdBLGNBQUEsQ0FGQSxTZDAzQ0YsQ2N0M0NFLHdDQUNFLGVkdzNDSixDY3IzQ0UseUJBQ0Usa0JBQUEsQ0FBQSxpQkFBQSxDQUFBLGFBQUEsQ0FFQSxhQUFBLENBREEsZ0NBQUEsQ0FFQSxzQ0FBQSxDQUFBLDhCZHUzQ0osQ2NwM0NFLDRCQUNFLGFBQUEsQ0FqUEYsaUJkd21ERixDY3RtREUsbUNBRUUsVUFBQSxDQURBLGFBQUEsQ0FHQSxnQkFBQSxDQURBLFVkeW1ESixDY3JtREUsZ0NBSUUsV0FBQSxDQUZBLE9BQUEsQ0FEQSxpQkFBQSxDQUVBLFVkd21ESixDY2g0Q0ksb0VBRUUsY2RpNENOLENjLzNDTSw0RUFDRSw0Q0FBQSxDQUFBLG9DQUFBLENBQ0Esc0NBQUEsQ0FBQSw4QmRpNENSLENjNTNDRSwwQkFDRSxhQUFBLENBRUEsV0FBQSxDQUNBLG1CQUFBLENBQUEsZ0JBQUEsQ0FGQSxVZGc0Q0oiLCJmaWxlIjoic3R5bGUuY3NzIn0= */ \ No newline at end of file +@charset "UTF-8"; +/** + ** Copyright 2008-2025 Adam J. Jolicoeur + ** https://www.adamjolicoeur.com +**/ +:root { + /* Font Families */ + --font-family-sans: "Inter", system-ui, -apple-system, blinkmacsystemfont, "Segoe UI", roboto, "Helvetica Neue", arial, sans-serif; + --font-family-serif: "Playfair Display", serif; + --font-family-mono: "Fira Code", "Courier New", courier, monospace; + --font-family-heading: "Pirata One", cursive; + /* Colors */ + --white: #f0f0f0; + --black: #010101; + --earth-dark: #2d1f12; + --earth-brown: #4a3426; + --earth-sage: #5a6b4f; + --earth-sand: #c9b89a; + --earth-cream: #f5f1e8; + --accent-coral: #d35f3d; + --accent-coral-dark: #b34a2d; + --text-primary: #2d1f12; + --text-secondary: #4a3426; + --text-muted: #6b5d52; + --shadow: rgb(45, 31, 18, 15%); + --shadow-heavy: rgb(45, 31, 18, 25%); + --shadow-light: rgb(45, 31, 18, 8%); + /* Font Sizes */ + --font-size-xs: 0.75rem; + --font-size-sm: 0.875rem; + --font-size-md: 1rem; + --font-size-lg: 1.125rem; + --font-size-xl: 1.25rem; + --font-size-2xl: 1.5rem; + --font-size-3xl: 2rem; + --font-size-4xl: 2.5rem; + --font-size-5xl: 3rem; + --font-size-6xl: 4rem; + /* Spacing */ + --space-2xs: 0.25rem; + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2rem; + --space-2xl: 3rem; + --space-3xl: 6rem; + /* Border radius */ + --radius-sm: 8px; + --radius-md: 12px; + --radius-lg: 16px; + --radius-xl: 20px; + --radius-pill: 50px; + /* Borders */ + --border-thin: 2px; + --border-medium: 4px; + --border-thick: 6px; + --border-extra-thick: 8px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +/* Focus visible styles for keyboard navigation */ +*:focus-visible { + outline: var(--border-thin) solid var(--accent-coral); + outline-offset: 2px; +} + +html { + scroll-behavior: smooth; +} + +body { + font-family: var(--font-family-sans); + background: linear-gradient(135deg, var(--earth-cream) 0%, #e8dcc8 100%); + color: var(--text-primary); + line-height: 1.6; + min-height: 100vh; + position: relative; +} + +html::-webkit-scrollbar, +::-webkit-scrollbar { + width: 16px; +} + +html::-webkit-scrollbar-thumb, +::-webkit-scrollbar-thumb { + background: linear-gradient(var(--accent-coral-dark), var(--accent-coral)); + border-radius: 2rem; + border: 2px solid transparent; + background-clip: content-box; +} + +html::-webkit-scrollbar-track, +::-webkit-scrollbar-track { + background: transparent; + padding: 0 2px; + border-radius: 2rem; + border: 1px solid var(--earth-sage); +} + +/* Styles for users who prefer reduced motion */ +@media (prefers-reduced-motion: reduce) { + .animated-element { + animation: none; /* Disable animations */ + transition: none; /* Disable transitions */ + /* You can also provide alternative, less motion-intensive styles here */ + /* For example, for a hover effect, you might change opacity instead of scaling */ + opacity: 1; /* Ensure element is visible if animation was for visibility */ + } + /* You can also target specific elements or properties */ + body { + scroll-behavior: auto; /* Disable smooth scrolling if enabled */ + } + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} +.display-none, +.d-none { + display: none !important; +} + +/* Hero Section */ +.hero { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 6rem 2rem; + text-align: center; + max-width: 900px; + margin: 0 auto; +} + +.rounded { + border-radius: var(--radius-xl, 20px) !important; +} + +.circle { + border-radius: 999px !important; + padding: 1rem !important; +} + +/* Work Highlights */ +.fade-in { + opacity: 0; + visibility: hidden; + transition: opacity 0.5s ease-in, visibility 0s linear 0.5s; /* 0.5s for opacity transition, 0s visibility transition after 0.5s delay */ +} + +.fade-in.show { + opacity: 1; + visibility: visible; + transition-delay: 0s; /* Override the delay for fade-in */ +} + +.show { + opacity: 1; + visibility: visible; + transition-delay: 0s; +} + +.hide { + opacity: 0; + visibility: hidden; + transition: opacity 0.5s ease-in, visibility 0s linear 0.5s; /* 0.5s for opacity transition, 0s visibility transition after 0.5s delay */ +} + +.hide-on-screen { + display: none !important; +} + +/* Responsive */ +@media (width <= 768px) { + .hero h1 { + font-size: var(--font-size-5xl, 3rem); + } + .no-wrap { + flex-wrap: wrap !important; + } + .hide-on-mobile { + display: none !important; + } + .work-grid { + grid-template-columns: 1fr; + } + .callouts-grid { + grid-template-columns: 1fr; + } + h2 { + font-size: var(--font-size-3xl, 2rem); + } +} +figcaption { + font-size: var(--font-size-sm, 0.875rem); + line-height: 1.4; + color: var(--text-secondary); + text-align: center; + font-style: italic; +} + +/* stylint-disable */ +/* +** Arrow animations from https://codepen.io/postor/pen/vYpNYg +*/ +.arrows { + width: 60px; + height: 72px; + position: absolute; + left: 50%; + margin-left: -30px; + bottom: 20px; +} + +.arrows path { + stroke: #bfe7fa; + fill: transparent; + stroke-width: 1px; + animation: arrow 2s infinite; +} + +@keyframes arrow { + 0% { + opacity: 0; + } + 40% { + opacity: 1; + } + 80% { + opacity: 0; + } + 100% { + opacity: 0; + } +} +@keyframes arrow /*Safari and Chrome*/ { + 0% { + opacity: 0; + } + 40% { + opacity: 1; + } + 80% { + opacity: 0; + } + 100% { + opacity: 0; + } +} +.arrows path.a1 { + animation-delay: -1s; + /* Safari 和 Chrome */ +} + +.arrows path.a2 { + animation-delay: -0.5s; + /* Safari 和 Chrome */ +} + +.arrows path.a3 { + animation-delay: 0s; + /* Safari 和 Chrome */ +} + +.pirata-one-regular { + font-family: "Pirata One", system-ui; + font-weight: 400; + font-style: normal; +} + +.inter-400 { + font-family: Inter, sans-serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; +} + +.inter-500 { + font-family: Inter, sans-serif; + font-optical-sizing: auto; + font-weight: 500; + font-style: normal; +} + +.inter-600 { + font-family: Inter, sans-serif; + font-optical-sizing: auto; + font-weight: 600; + font-style: normal; +} + +.inter-700 { + font-family: Inter, sans-serif; + font-optical-sizing: auto; + font-weight: 700; + font-style: normal; +} + +.inter-800 { + font-family: Inter, sans-serif; + font-optical-sizing: auto; + font-weight: 800; + font-style: normal; +} + +.inter-900 { + font-family: Inter, sans-serif; + font-optical-sizing: auto; + font-weight: 900; + font-style: normal; +} + +.playfair-display-400 { + font-family: "Playfair Display", serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; +} + +.playfair-display-500 { + font-family: "Playfair Display", serif; + font-optical-sizing: auto; + font-weight: 500; + font-style: normal; +} + +.playfair-display-600 { + font-family: "Playfair Display", serif; + font-optical-sizing: auto; + font-weight: 600; + font-style: normal; +} + +.playfair-display-700 { + font-family: "Playfair Display", serif; + font-optical-sizing: auto; + font-weight: 700; + font-style: normal; +} + +.playfair-display-800 { + font-family: "Playfair Display", serif; + font-optical-sizing: auto; + font-weight: 800; + font-style: normal; +} + +.playfair-display-900 { + font-family: "Playfair Display", serif; + font-optical-sizing: auto; + font-weight: 900; + font-style: normal; +} + +/* Heading 1 */ +h1, +.text-h1 { + font-family: "Pirata One", cursive; + font-size: clamp(2.5rem, 8vw, 5rem); + color: var(--text-primary); + line-height: 1.2; + letter-spacing: 2px; + text-shadow: 3px 3px 0 var(--accent-coral); +} + +.text-display { + font-family: "Pirata One", cursive; + font-size: clamp(3rem, 10vw, 6rem); + color: var(--text-primary); + line-height: 1.1; + letter-spacing: 2px; + text-shadow: 3px 3px 0 var(--accent-coral); +} + +.hero h1 { + font-family: var(--font-family-heading); + color: var(--text-primary); + margin-bottom: 1rem; + text-shadow: 3px 3px 0 var(--accent-coral); + letter-spacing: 2px; + line-height: 1.2; +} + +/* Heading 2 */ +h2, +.text-h2 { + font-family: "Playfair Display", serif; + font-size: clamp(2rem, 5vw, 3rem); + color: var(--text-primary); + line-height: 1.3; + font-weight: 700; + margin-bottom: var(--space-md, 1.5rem); +} + +.text-h2.no-underline::after { + display: none; + margin-bottom: var(--space-2xs, 0.25rem); +} + +h2::after, +.text-h2::after { + content: ""; + display: block; + width: 100px; + height: 5px; + background: var(--accent-coral); + margin: 1rem auto; + border: 3px solid var(--earth-brown); +} + +/* Heading 3 */ +h3, +.text-h3 { + font-family: "Playfair Display", serif; + font-size: clamp(1.5rem, 3vw, 2rem); + color: var(--text-primary); + line-height: 1.3; + font-weight: 600; +} + +/* Heading 4 */ +h4, +.text-h4 { + font-family: "Playfair Display", serif; + font-size: clamp(1.25rem, 2.5vw, 1.5rem); + color: var(--text-primary); + line-height: 1.4; + font-weight: 600; +} + +/* Heading 5 */ +h5, +.text-h5 { + font-family: Inter, sans-serif; + font-size: clamp(1.1rem, 2vw, 1.25rem); + color: var(--text-primary); + line-height: 1.4; + font-weight: 700; +} + +/* Heading 6 */ +h6, +.text-h6 { + font-family: Inter, sans-serif; + font-size: 1rem; + color: var(--text-primary); + line-height: 1.4; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* Body text sizes */ +.text-body-lg { + font-size: clamp(1.1rem, 1.5vw, 1.25rem) !important; + line-height: 1.7 !important; +} + +p, +.text-body { + font-size: clamp(0.95rem, 1.5vw, 1rem); + line-height: 1.7; + color: var(--text-primary); + padding-bottom: var(--space-xs, 0.5rem); +} + +p:last-child, +.text-body:last-child { + margin-bottom: 0; +} + +.hero p { + font-size: clamp(1.1rem, 2vw, 1.25rem); + color: var(--earth-brown); + max-width: 720px; + margin: 0 auto; +} + +.card-body p:first-of-type, +.card-body .text-body:first-of-type { + margin-top: var(--space-md, 16px); +} + +.text-body-sm { + font-size: clamp(0.85rem, 1.2vw, 0.9rem); + line-height: 1.6; +} + +.text-caption { + font-size: clamp(var(--space-sm), 1vw, 0.85rem); + line-height: 1.5; + color: var(--text-muted); +} + +.text-callout { + font-size: clamp(1rem, 1.5vw, 1.1rem); + line-height: 1.6; + font-weight: 600; + color: var(--text-primary); + margin: var(--space-lg, 1.5rem); + padding: var(--space-lg, 1.5rem); + background: var(--earth-sand-light); + border-left: var(--border-medium) solid var(--accent-coral); +} + +code, +.code { + font-family: var(--font-family-mono); + font-size: clamp(0.85rem, 1vw, 0.9rem); +} + +code.code-inline, +.code.code-inline { + background: var(--earth-sand); + padding: 0.1rem 0.3rem; + border-radius: var(--radius-sm); +} + +.code-block { + display: block; + background: var(--earth-sand); + padding: 1rem; + border-radius: var(--radius-md); + font-size: clamp(0.85rem, 1vw, 0.9rem); + overflow-x: auto; + border: var(--border-thin) solid var(--earth-sage); +} + +/* Text utilities */ +.text-muted { + color: var(--text-muted); +} + +.text-secondary { + color: var(--text-secondary); +} + +.text-accent { + color: var(--accent-coral); +} + +.text-semibold { + font-weight: 600; +} + +.text-bold { + font-weight: 700; +} + +.text-center { + text-align: center; +} + +/* Lead paragraph */ +.lead, +.text-lead { + font-size: clamp(1.1rem, 2vw, 1.35rem); + line-height: 1.7; + color: var(--text-secondary); +} + +/* Links */ +a, +.link { + color: var(--earth-sage); + border-bottom: 1px solid var(--earth-sage); + text-decoration: none; + transition: all 0.2s; + font-weight: var(--font-weight-semibold, 600); +} + +a:hover, +a:focus, +.link:hover, +.link:focus { + color: var(--earth-brown); + border-bottom-color: var(--earth-brown); +} + +.link-brackets { + margin-left: var(--space-md) !important; +} +.link-brackets::after { + content: "]"; + position: absolute; + margin-left: 0.2rem; + color: var(--earth-sage); + transition: all 0.2s; +} +.link-brackets::before { + content: "["; + position: absolute; + margin-left: -0.8rem; + color: var(--earth-sage); + transition: all 0.2s; +} +.link-brackets:hover::after, .link-brackets:hover::before, .link-brackets:focus::after, .link-brackets:focus::before { + color: var(--accent-coral); +} + +/* Blockquote */ +blockquote, +.blockquote { + border-left: var(--border-thin) solid var(--earth-brown); + padding-left: var(--space-md, 1rem); + margin: var(--space-lg, 1.5rem) 0; + font-style: italic; + color: var(--text-secondary); +} + +.mb-1 { + margin-bottom: var(--space-2xs) !important; +} + +.mb-2 { + margin-bottom: var(--space-xs) !important; +} + +.mb-3 { + margin-bottom: var(--space-sm) !important; +} + +.mb-4 { + margin-bottom: var(--space-md) !important; +} + +.mb-5 { + margin-bottom: var(--space-xl) !important; +} + +.mt-1 { + margin-top: var(--space-2xs) !important; +} + +.mt-2 { + margin-top: var(--space-xs) !important; +} + +.mt-3 { + margin-top: var(--space-sm) !important; +} + +.mt-4 { + margin-top: var(--space-md) !important; +} + +.mt-5 { + margin-top: var(--space-xl) !important; +} + +.ml-1 { + margin-left: var(--space-2xs) !important; +} + +.ml-2 { + margin-left: var(--space-xs) !important; +} + +.ml-3 { + margin-left: var(--space-sm) !important; +} + +.ml-4 { + margin-left: var(--space-md) !important; +} + +.ml-5 { + margin-left: var(--space-xl) !important; +} + +.mr-1 { + margin-right: var(--space-2xs) !important; +} + +.mr-2 { + margin-right: var(--space-xs) !important; +} + +.mr-3 { + margin-right: var(--space-sm) !important; +} + +.mr-4 { + margin-right: var(--space-md) !important; +} + +.mr-5 { + margin-right: var(--space-xl) !important; +} + +.p-1 { + padding: var(--space-2xs) !important; +} + +.p-2 { + padding: var(--space-xs) !important; +} + +.p-3 { + padding: var(--space-sm) !important; +} + +.p-4 { + padding: var(--space-md) !important; +} + +.p-5 { + padding: var(--space-xl) !important; +} + +.pt-1 { + padding-top: var(--space-2xs) !important; +} + +.pt-2 { + padding-top: var(--space-xs) !important; +} + +.pt-3 { + padding-top: var(--space-sm) !important; +} + +.pt-4 { + padding-top: var(--space-md) !important; +} + +.pt-5 { + padding-top: var(--space-xl) !important; +} + +.pb-1 { + padding-bottom: var(--space-2xs) !important; +} + +.pb-2 { + padding-bottom: var(--space-xs) !important; +} + +.pb-3 { + padding-bottom: var(--space-sm) !important; +} + +.pb-4 { + padding-bottom: var(--space-md) !important; +} + +.pb-5 { + padding-bottom: var(--space-xl) !important; +} + +.pl-1 { + padding-left: var(--space-2xs) !important; +} + +.pl-2 { + padding-left: var(--space-xs) !important; +} + +.pl-3 { + padding-left: var(--space-sm) !important; +} + +.pl-4 { + padding-left: var(--space-md) !important; +} + +.pl-5 { + padding-left: var(--space-xl) !important; +} + +.pr-1 { + padding-right: var(--space-2xs) !important; +} + +.pr-2 { + padding-right: var(--space-xs) !important; +} + +.pr-3 { + padding-right: var(--space-sm) !important; +} + +.pr-4 { + padding-right: var(--space-md) !important; +} + +.pr-5 { + padding-right: var(--space-xl) !important; +} + +/* Section Styles */ +section { + max-width: 1200px; + margin: 0 auto; + padding: var(--space-3xl, 6rem) var(--space-lg, 2rem); +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.row { + display: flex; + flex-wrap: wrap; + gap: var(--space-lg, 2rem); +} + +@media (width >= 768px) { + .row { + gap: var(--space-sm, 0.5rem); + } +} +@media (width >= 768px) { + .card-body .row { + gap: 0; + } +} +.button-row { + gap: 1rem; +} + +.no-wrap { + flex-wrap: nowrap; +} + +.d-flex { + display: flex; +} + +.flex-column { + flex-direction: column; +} + +.align-items-center { + align-items: center; +} + +.work-grid { + display: grid; + gap: var(--space-lg, 2rem); + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + margin-bottom: var(--space-lg, 2rem); +} + +.divider { + display: block; + width: 50%; + height: var(--space-md, 1.5rem); + background: var(--accent-coral); + border: var(--border-medium, 4px) outset var(--earth-dark); + margin: 0 auto; +} + +.divider.vertical { + width: var(--space-2xs, 0.25rem); + height: 100%; + background: var(--earth-dark); + border-radius: var(--radius-sm); + border: none !important; + margin: 0; +} + +ul, +ol, +.card-body ul, +.card-body ol, +ul.list, ol.list { + margin-left: var(--space-lg) !important; + padding-left: var(--space-md) !important; +} + +.highlight-block { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; +} + +.header-highlight { + text-align: center; + margin: var(--space-md) auto; + padding: var(--space-md); + width: 100%; +} + +/* Navigation */ +nav { + position: fixed; + top: 2rem; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + background: rgba(245, 241, 232, 0.5); + backdrop-filter: blur(24px); + filter: url("#lensFilter") saturate(120%) brightness(1.15); + border: var(--border-medium, 4px) solid var(--earth-brown); + border-radius: 50px; + padding: var(--space-sm) 2rem; + box-shadow: 0 8px 24px var(--shadow-heavy); +} + +.main-nav { + position: sticky; + top: 2rem; + margin: 0 auto; + width: fit-content; + transform: none !important; + left: 0; + right: 0; +} + +nav ul { + list-style: none; + display: flex; + justify-content: center; + gap: 2rem; + margin-left: 0 !important; + padding-left: 0 !important; +} + +nav a { + text-decoration: none; + color: var(--text-primary); + font-weight: 500; + font-size: 0.95rem; + transition: color 0.3s; + padding: var(--space-2xs) var(--space-xs, 0.5rem); + border-bottom: none; +} + +nav a:hover, +nav a:focus { + color: var(--accent-coral); + outline: var(--border-thin) solid var(--accent-coral); + outline-offset: 2px; +} + +nav a.active { + color: var(--accent-coral); +} + +nav a.sub-page { + outline: var(--border-thin) solid var(--text-secondary); + outline-offset: 2px; +} + +nav a.sub-page:hover { + outline-color: var(--accent-coral); +} + +@media (width <= 768px) { + nav { + top: var(--space-sm, 1rem) !important; + padding: var(--space-xs, 0.5rem) var(--space-sm, 1rem) !important; + margin: 0 auto !important; + } + nav ul { + gap: var(--space-sm, 1rem); + } +} +/* Footer */ +footer { + background: var(--earth-dark); + color: var(--earth-cream); + padding: var(--space-2xl, 3rem) var(--space-xl, 2rem); + margin-top: var(--space-3xl, 6rem); + border-top: var(--border-extra-thick, 8px) solid var(--earth-brown); + box-shadow: 0 -10px 30px var(--shadow); +} + +.footer-content { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 3rem; +} + +.footer-section h3 { + font-family: "Playfair Display", serif; + color: var(--accent-coral); + margin-bottom: var(--space-md, 1rem); + font-size: clamp(1.2rem, 2vw, 1.5rem); +} + +.footer-section h4 { + font-family: "Playfair Display", serif; + color: rgba(255, 255, 255, 0.5) !important; + margin-bottom: var(--space-md, 1rem); + font-size: clamp(1.1rem, 1.25vw, 1.125rem); +} + +.footer-section p, +.footer-section li { + color: var(--earth-cream); + line-height: 1.6; + margin-bottom: var(--space-xs, 0.5rem); +} + +.footer-section ul { + list-style: none; + padding: 0; +} + +.footer-section li { + margin-bottom: var(--space-xs, 0.5rem); +} + +.footer-bottom { + text-align: center; + margin-top: var(--space-2xl, 3rem); + padding-top: var(--space-xl, 2rem); + border-top: var(--border-medium, 4px) solid var(--earth-brown); + color: var(--earth-sand); +} + +.footer-bottom p { + margin: 0; + font-size: var(--font-size-sm); + color: var(--earth-cream); +} + +.footer-section a, +.footer-bottom a { + color: var(--earth-cream); + text-decoration: underline; +} + +.footer-section a:hover, +.footer-bottom a:hover { + color: var(--accent-coral); +} + +/* Badge */ +.badge { + display: inline-block; + padding: var(--space-2xs, 0.25rem) var(--space-sm, 0.75rem); + font-size: 0.85rem; + font-weight: 600; + background: var(--earth-sage); + color: var(--earth-cream); + border: var(--border-thin, 2px) solid var(--earth-brown); + border-radius: var(--radius-pill); +} + +.badge-accent { + background: var(--accent-coral-dark); +} + +.badge-outline { + background: transparent; + color: inherit; +} + +.badges, .row-badges { + display: flex; + gap: var(--space-2xs, 0.25rem); + flex-wrap: wrap; +} + +/* Base button styles */ +.btn { + display: inline-block; + padding: var(--space-sm, 0.75rem) var(--space-lg, 1.5rem); + font-family: var(--font-family-sans); + font-size: var(--font-size-md, 1rem); + font-weight: 600; + text-decoration: none; + border-radius: var(--radius-md, 12px); + transition: all 0.2s; + cursor: pointer; + border: none; + text-align: center; +} + +.btn:hover, +.btn:focus { + transform: translate(2px, 2px); + box-shadow: 2px 2px 0 var(--earth-brown); +} + +/* Primary button */ +.btn-primary { + background: var(--accent-coral-dark); + color: var(--white); + border: var(--border-medium, 4px) solid var(--earth-brown); + box-shadow: 4px 4px 0 var(--earth-brown); +} + +.btn-primary:hover, +.btn-primary:focus { + background: var(--accent-coral-dark); + color: var(--white); +} + +/* Secondary button */ +.btn-secondary { + background: var(--earth-cream); + color: var(--text-primary); + border: var(--border-medium, 4px) solid var(--earth-brown); + box-shadow: 4px 4px 0 var(--earth-sage); +} + +.btn-secondary:hover, +.btn-secondary:focus { + background: var(--earth-sand); + color: var(--text-primary); + transform: translate(2px, 2px); + box-shadow: 2px 2px 0 var(--earth-sage); + outline: var(--border-thin) solid var(--earth-dark); +} + +/* Outline button */ +.btn-outline { + background: rgba(255, 255, 255, 0.5) !important; + backdrop-filter: blur(24px); + filter: url("#lensFilter") saturate(120%) brightness(1.15); + color: var(--text-primary) !important; + border: var(--border-medium, 4px) solid var(--earth-brown) !important; + box-shadow: none !important; +} + +.btn-outline:hover, +.btn-outline:focus { + color: var(--earth-cream); + text-decoration: underline; +} + +/* Button sizes */ +.btn-sm { + padding: var(--space-xs, 0.5rem) var(--space-md, 1rem) !important; + font-size: 0.9rem !important; + border-width: var(--border-thin) !important; +} + +.btn-lg { + padding: var(--space-md, 1rem) var(--space-xl, 2rem) !important; + font-size: 1.1rem !important; +} + +/* Skip to main content link */ +.skip-link { + position: absolute; + top: -100px; + left: 0; + background: var(--accent-coral); + color: var(--white); + padding: var(--space-sm, 0.75rem) var(--space-lg, 1.5rem); + text-decoration: none; + font-weight: 600; + border: var(--border-medium, 4px) solid var(--earth-brown); + z-index: 2000; + clip: rect(0, 0, 0, 0); + overflow: hidden; +} + +.skip-link:focus { + top: 1rem; + left: 1rem; + clip: auto; + overflow: visible; +} + +.social-links { + display: flex; + gap: 1rem; + flex-wrap: wrap; +} + +.social-link { + display: inline-block; + padding: var(--space-xs, 0.5rem) var(--space-md, 1rem); + background: var(--earth-sage); + color: var(--white); + text-decoration: none !important; + border: var(--border-medium, 4px) solid var(--earth-sand); + border-radius: 8px; + font-weight: 500; + transition: all 0.3s; + font-size: 0.95rem; +} + +.social-link:hover, +.social-link:focus { + background: var(--accent-coral); + transform: translateY(-2px); + color: var(--white) !important; +} + +/* Base card */ +.card { + background: var(--earth-cream); + border: var(--border-thick, 6px) solid var(--earth-brown); + border-radius: var(--radius-xl, 20px); + padding: var(--space-lg, 1.5rem); + box-shadow: 8px 8px 0 var(--shadow-heavy); + transition: transform 0.3s, box-shadow 0.3s; +} + +.card:hover, +.card:focus-within { + transform: translateY(-5px); + box-shadow: 12px 12px 0 var(--shadow-heavy); +} + +/* Card with layered shadow */ +.card-layered { + background: var(--earth-cream); + border: var(--border-thick, 6px) solid var(--earth-brown); + border-radius: var(--radius-xl, 20px); + padding: var(--space-xl, 2rem); + box-shadow: 12px 12px 0 var(--earth-sage), 12px 12px 0 5px var(--earth-brown); +} + +/* Card with only shadow */ +.card-shadow { + background: var(--earth-cream); + border: none; + border-radius: var(--radius-lg, 16px); + padding: var(--space-md, 1.5rem); + box-shadow: 10px 10px 0 var(--shadow-heavy); +} + +/* Card with accent shadow */ +.card-accent { + background: var(--earth-cream); + border: var(--border-extra-thick, 8px) solid var(--earth-brown); + border-radius: var(--radius-xl, 20px); + overflow: hidden; + box-shadow: 16px 16px 0 var(--accent-coral), 16px 16px 0 6px var(--earth-brown); +} + +/* Simple card (minimal shadow) */ +.card-flex { + display: flex; + flex-direction: column; +} + +.card-flex p { + flex: 1 0; +} + +.card-with-columns .row { + display: flex; + align-items: flex-start; + gap: var(--space-md, 1rem); + align-self: stretch; +} +.card-with-columns .column { + display: flex; + align-items: flex-start; + flex: 1 0 0; + align-self: stretch; +} + +/* Card header */ +.card-header { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-sand); +} + +/* Card body */ +.card-body { + margin-bottom: var(--space-md); +} + +.card-body img { + object-fit: cover; + width: 100%; +} + +@media (width >= 768px) { + .img-thumbnail { + max-width: 50%; + } +} +.card-body:last-child { + margin-bottom: 0; +} + +/* Card footer */ +.card-footer { + margin-top: var(--space-md, 1rem); + padding-top: var(--space-md, 1rem); + border-top: var(--border-thin, 2px) solid var(--earth-sand); +} + +.showcase-content { + padding: var(--space-lg, 2rem); +} + +.showcase-content h3 { + font-family: var(--font-family-serif); + font-size: clamp(1.3rem, 2.5vw, 1.8rem); + color: var(--text-primary); + margin-bottom: var(--space-sm, 1rem); +} + +.showcase-content p { + color: var(--text-secondary); + margin-bottom: var(--space-md, 1.5rem); + font-size: clamp(0.95rem, 1.5vw, 1rem); +} + +.showcase-small { + background: var(--earth-sand); + border: 4px solid var(--earth-brown); + border-radius: var(--radius-lg, 16px); + padding: var(--space-md, 1.5rem); + box-shadow: 6px 6px 0 var(--shadow-heavy); + transition: transform 0.3s; +} + +.showcase-small:hover, +.showcase-small:focus-within { + transform: translateY(-4px); +} + +.showcase-small h4 { + font-family: var(--font-family-serif); + font-size: clamp(1.1rem, 2vw, 1.3rem); + color: var(--text-primary); + margin-bottom: var(--space-xs, 0.5rem); +} + +.showcase-small p { + color: var(--text-secondary); + font-size: clamp(0.9rem, 1.5vw, 0.95rem); +} + +/* About Section */ +.about-card { + 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); + box-shadow: 12px 12px 0 var(--earth-sage), 12px 12px 0 5px var(--earth-brown); + margin: 0 auto; +} + +@media (width <= 768px) { + .about-card { + box-shadow: 6px 6px 0 var(--earth-sage), 6px 6px 0 4px var(--earth-brown); + padding: var(--space-md, 1rem); + } + .about-grid { + grid-template-columns: 1fr !important; + } +} +.about-card p { + font-size: clamp(1rem, 1.5vw, 1.1rem); + line-height: 1.8; + color: var(--text-primary); + margin-bottom: var(--space-lg, 1.5rem); +} + +.about-card p:last-child { + margin-bottom: 0; +} + +.about-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: var(--space-xl, 2rem); + margin-top: var(--space-xl, 2rem); +} + +.showcase-large { + background: var(--earth-cream); + border: var(--border-thick, 6px) solid var(--earth-brown); + border-radius: var(--radius-xl, 20px); + overflow: hidden; + box-shadow: 12px 12px 0 var(--accent-coral), 12px 12px 0 6px var(--earth-brown); + transition: transform 0.3s; +} + +@media (width <= 768px) { + .showcase-large { + box-shadow: 6px 6px 0 var(--accent-coral), 6px 6px 0 4px var(--earth-brown); + } +} +.showcase-large:hover, +.showcase-large:focus-within { + transform: translateY(-8px); +} + +.showcase-image { + width: 100%; + height: 300px; + background: linear-gradient(135deg, var(--earth-sage) 0%, var(--earth-sand) 100%); + display: flex; + align-items: center; + justify-content: center; + padding: var(--space-md, 1rem); + font-size: var(--font-size-5xl, 3rem); + color: var(--earth-cream); + border-bottom: var(--border-thick, 6px) solid var(--earth-brown); + object-fit: contain; +} + +.showcase-image-dark { + background: linear-gradient(135deg, var(--black) 0%, var(--earth-dark) 100%); +} + +/* Small Projects */ +.small-showcase-cards { + grid-column: 1/-1; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--space-md, 1.5rem); + margin-top: var(--space-sm, 1rem); +} + +/* Callouts */ +.callouts-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin-top: 2rem; +} + +.callout { + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: space-between; + background: var(--earth-cream); + border: var(--border-thick, 6px) solid var(--accent-coral-dark); + padding: 2rem; + border-radius: var(--radius-xl, 20px); + box-shadow: 8px 8px 0 var(--shadow-heavy); + position: relative; + transition: transform 0.3s, box-shadow 0.3s; +} + +.callout:hover, +.callout:focus-within { + transform: translateY(-5px); + box-shadow: 12px 12px 0 var(--shadow-heavy); +} + +.callout::before { + content: '"'; + font-family: var(--font-family-serif); + font-size: var(--font-size-6xl, 4rem); + color: var(--accent-coral); + position: absolute; + top: 10px; + left: 20px; + line-height: 1; +} + +.callout-text { + font-style: italic; + margin-bottom: var(--space-md, 1.5rem); + padding-top: var(--space-sm, 1rem); + color: var(--text-primary); +} + +.callout-author { + font-weight: 600; + color: var(--text-primary); + display: block; +} + +.callout-role { + font-size: var(--font-size-sm, 0.9rem); + color: var(--text-secondary); +} + +/* stylelint-disable */ +.gallery { + --size: 100px; + display: grid; + grid-template-columns: repeat(6, var(--size)); + grid-auto-rows: var(--size); + margin-bottom: var(--size); + place-items: start center; + gap: 5px; +} +.gallery:has(:hover) picture:not(:hover), .gallery:has(:focus) picture:not(:focus) { + filter: brightness(0.5) contrast(0.5); +} +.gallery picture { + object-fit: cover; + width: calc(var(--size) * 2); + height: calc(var(--size) * 2); + clip-path: path("M90,10 C100,0 100,0 110,10 190,90 190,90 190,90 200,100 200,100 190,110 190,110 110,190 110,190 100,200 100,200 90,190 90,190 10,110 10,110 0,100 0,100 10,90Z"); + transition: clip-path 0.25s, filter 0.75s; + grid-column: auto/span 2; + border-radius: 5px; +} +.gallery picture:nth-child(5n-1) { + grid-column: 2/span 2; +} +.gallery picture:hover, .gallery picture:focus { + clip-path: path("M0,0 C0,0 200,0 200,0 200,0 200,100 200,100 200,100 200,200 200,200 200,200 100,200 100,200 100,200 100,200 0,200 0,200 0,100 0,100 0,100 0,100 0,100Z"); + z-index: 1; + transition: clip-path 0.25s, filter 0.25s; +} +.gallery picture:focus { + outline: 1px dashed black; + outline-offset: -5px; +} + +/* Carousel */ +.carousel > input { + width: 1px; + height: 1px; + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(50%); + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; +} +.carousel > input:nth-of-type(15):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -1400%; +} +.carousel > input:nth-of-type(14):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -1300%; +} +.carousel > input:nth-of-type(13):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -1200%; +} +.carousel > input:nth-of-type(12):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -1100%; +} +.carousel > input:nth-of-type(11):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -1000%; +} +.carousel > input:nth-of-type(10):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -900%; +} +.carousel > input:nth-of-type(9):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -800%; +} +.carousel > input:nth-of-type(8):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -700%; +} +.carousel > input:nth-of-type(7):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -600%; +} +.carousel > input:nth-of-type(6):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -500%; +} +.carousel > input:nth-of-type(5):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -400%; +} +.carousel > input:nth-of-type(4):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -300%; +} +.carousel > input:nth-of-type(3):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -200%; +} +.carousel > input:nth-of-type(2):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: -100%; +} +.carousel > input:nth-of-type(1):checked ~ .carousel__slides .carousel__slide:first-of-type { + margin-left: 0%; +} +.carousel > input:nth-of-type(1):checked ~ .carousel__thumbnails li:nth-of-type(1) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(2):checked ~ .carousel__thumbnails li:nth-of-type(2) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(3):checked ~ .carousel__thumbnails li:nth-of-type(3) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(4):checked ~ .carousel__thumbnails li:nth-of-type(4) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(5):checked ~ .carousel__thumbnails li:nth-of-type(5) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(6):checked ~ .carousel__thumbnails li:nth-of-type(6) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(7):checked ~ .carousel__thumbnails li:nth-of-type(7) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(8):checked ~ .carousel__thumbnails li:nth-of-type(8) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(9):checked ~ .carousel__thumbnails li:nth-of-type(9) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(10):checked ~ .carousel__thumbnails li:nth-of-type(10) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(11):checked ~ .carousel__thumbnails li:nth-of-type(11) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(12):checked ~ .carousel__thumbnails li:nth-of-type(12) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(13):checked ~ .carousel__thumbnails li:nth-of-type(13) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(14):checked ~ .carousel__thumbnails li:nth-of-type(14) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} +.carousel > input:nth-of-type(15):checked ~ .carousel__thumbnails li:nth-of-type(15) { + box-shadow: 0 0 0 5px rgba(0, 0, 255, 0.5); +} + +.carousel__slides { + position: relative; + z-index: 1; + padding: 0; + margin: 0; + overflow: hidden; + white-space: nowrap; + box-sizing: border-box; + display: flex; +} + +.carousel__slide { + position: relative; + display: block; + flex: 1 0 100%; + width: 100%; + height: 100%; + overflow: hidden; + transition: all 300ms ease-out; + vertical-align: top; + box-sizing: border-box; + white-space: normal; +} +.carousel__slide figure { + display: flex; + flex-direction: column; + margin: 0; +} +.carousel__slide div { + position: relative; + width: 100%; +} +.carousel__slide div::before { + display: block; + content: ""; + width: 100%; + padding-top: 66.6666666667%; +} +.carousel__slide div > img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} +.carousel__slide img { + display: block; + flex: 1 1 auto; + object-fit: cover; +} +.carousel__slide figcaption { + align-self: center; + padding: 20px 20px 0; + flex: 0 0 auto; + width: 25%; + min-width: 150px; +} +.carousel__slide .credit { + margin-top: 1rem; + color: rgba(0, 0, 0, 0.5); + display: block; +} +.carousel__slide.scrollable { + overflow-y: scroll; +} + +.carousel__thumbnails { + list-style: none; + padding: 0; + display: flex; + margin: 0 -10px; +} +.carousel__slides + .carousel__thumbnails { + margin-top: 20px; +} +.carousel__thumbnails li { + flex: 1 1 auto; + max-width: calc(16.6666666667% - 20px); + margin: 0 10px; + transition: all 300ms ease-in-out; +} +.carousel__thumbnails label { + display: block; + position: relative; +} +.carousel__thumbnails label::before { + display: block; + content: ""; + width: 100%; + padding-top: 100%; +} +.carousel__thumbnails label > img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} +.carousel__thumbnails label:hover, .carousel__thumbnails label:focus { + cursor: pointer; +} +.carousel__thumbnails label:hover img, .carousel__thumbnails label:focus img { + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25); + transition: all 300ms ease-in-out; +} +.carousel__thumbnails img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; +} + +/* stylelint-enable */ +/* stylint-enable */ + +/*# sourceMappingURL=style.css.map */ diff --git a/docs/css/style.css.map b/docs/css/style.css.map index 466418ea..8a674f8e 100644 --- a/docs/css/style.css.map +++ b/docs/css/style.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../src/sass/style.scss","../../src/sass/_variables.scss","../../src/sass/_animations.scss","../../src/sass/_fonts.scss","../../src/sass/_typography.scss","../../src/sass/_spacing.scss","../../src/sass/_layout.scss","../../src/sass/_lists.scss","../../src/sass/_highlight.scss","../../src/sass/_navigation.scss","../../src/sass/_footer.scss","../../src/sass/_badge.scss","../../src/sass/_buttons.scss","../../src/sass/_cards.scss","../../src/sass/_gallery.scss"],"names":[],"mappings":";AAAA;AAAA;AAAA;AAAA;ACSA;AACE;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;;;AD3DF;EACE;EACA;EACA;;;AAGF;AACA;EACE;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;;;AAEF;AAAA;EAEE;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;EACA;;;AAGF;AACA;EACE;IACE;IACA;AAEA;AAEA;IACA;;AAGF;EACA;IACE;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;;;AAGJ;AAAA;EAEE;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;EACA;;;AAGF;AACA;EACE;EACA;EACA,YACE,iDAC2B;;;AAE/B;EACE;EACA;EACA;;;AAGF;EAEE;EACA;EACA;;;AAEF;EACE;EACA;EACA,YACE,iDAC2B;;;AAE/B;EACE;;;AAGF;AACA;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;AEpKA;AAAA;AAAA;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;IAAI;;EACJ;IAAK;;EACL;IAAK;;EACL;IAAM;;;AAGR;EACE;IAAI;;EACJ;IAAK;;EACL;IAAK;;EACL;IAAM;;;AAGR;EACE;AAED;;;AAGD;EACE;AAED;;;AAGD;EACE;AAED;;;AC/CD;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AC7EF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EAEE;;;AAIJ;AACA;EACE;EACA;EACA;EACA;EACA;;;ACtOF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;ACjIF;AACA;EACE;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;IACE;;;AAGJ;EACE;IACE;;;AAGJ;EACE;;;AAEF;EACE;;;AAEF;EACE,SA1CK;;;AA4CP;EACE,gBA5CO;;;AA8CT;EACE,aA9CO;;;AAgDT;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;ACtEF;AAAA;AAAA;AAAA;AAAA;EAKE;EACA;;;ACNF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;ACVF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;;;AAGF;EACI;IACA;IACA;IACA;;EAKF;IACE;;;ACvEJ;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;;;AAEF;AAAA;EAEE;;;AC9DF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAEF;EACE;EACA;EACA;;;ACvBF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;;;AAMF;AACA;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAMF;AACA;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAKF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAMF;AACA;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EAIA;;;AC3IF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAIF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAIF;AACA;EACE;EACA;;;AAEF;EACE;;;AAIA;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;;;AAGF;AACA;EACE;;;AAEF;EACE;EACA;;;AAGF;EACE;IACE;;;AAIJ;EACE;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EAEA;;;AAEF;EACE;IACE;IAEA;;EAEF;IACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EAEA;;;AAEF;EACE;IACE;;;AAKJ;AAAA;EAEE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AC3RF;AACA;EACE;EAEA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;EACA;EACA;EACA;EAGA,YACE;EAEF;EACA;;AAEA;EACE;;AAGF;EAEE;EAGA;EACA,YACE;;AAIJ;EACE;EACA;;;AAKN;AA+BE;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAGF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EAhMA;EAmME;;AAjMF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAyLF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EAjPF;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAuOA;EAEE;;AAEA;EACE;EACA;;AAKN;EACE;EACA;EACA;EACA;;;AAGJ;AdxIA","file":"style.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../../src/sass/style.scss","../../src/sass/_variables.scss","../../src/sass/_animations.scss","../../src/sass/_fonts.scss","../../src/sass/_typography.scss","../../src/sass/_spacing.scss","../../src/sass/_layout.scss","../../src/sass/_lists.scss","../../src/sass/_highlight.scss","../../src/sass/_navigation.scss","../../src/sass/_footer.scss","../../src/sass/_badge.scss","../../src/sass/_buttons.scss","../../src/sass/_cards.scss","../../src/sass/_gallery.scss"],"names":[],"mappings":";AAAA;AAAA;AAAA;AAAA;ACSA;AACE;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;;;AD3DF;EACE;EACA;EACA;;;AAGF;AACA;EACE;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;;;AAEF;AAAA;EAEE;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;EACA;;;AAGF;AACA;EACE;IACE;IACA;AAEA;AAEA;IACA;;AAGF;EACA;IACE;;EAEF;AAAA;AAAA;IAGE;IACA;IACA;;;AAGJ;AAAA;EAEE;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;EACA;;;AAGF;AACA;EACE;EACA;EACA,YACE,iDAC2B;;;AAE/B;EACE;EACA;EACA;;;AAGF;EAEE;EACA;EACA;;;AAEF;EACE;EACA;EACA,YACE,iDAC2B;;;AAE/B;EACE;;;AAGF;AACA;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;AEpKA;AAAA;AAAA;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;IAAI;;EACJ;IAAK;;EACL;IAAK;;EACL;IAAM;;;AAGR;EACE;IAAI;;EACJ;IAAK;;EACL;IAAK;;EACL;IAAM;;;AAGR;EACE;AAED;;;AAGD;EACE;AAED;;;AAGD;EACE;AAED;;;AC/CD;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AC7EF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EAEA;EACA;EACA;EACA;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;;;AAGF;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAEF;AAAA;AAAA;AAAA;EAIE;EACA;;;AAEF;EACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EAIE;;;AAIJ;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;;;ACzPF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;ACjIF;AACA;EACE;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;IACE;;;AAGJ;EACE;IACE;;;AAGJ;EACE;;;AAEF;EACE;;;AAEF;EACE,SA1CK;;;AA4CP;EACE,gBA5CO;;;AA8CT;EACE,aA9CO;;;AAgDT;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;ACtEF;AAAA;AAAA;AAAA;AAAA;EAKE;EACA;;;ACNF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;ACVF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;;;AAGF;EACI;IACA;IACA;IACA;;EAKF;IACE;;;ACvEJ;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;;;AAEF;AAAA;EAEE;;;AC9DF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAEF;EACE;EACA;EACA;;;ACvBF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;AAAA;EAEE;EACA;;;AAMF;AACA;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAMF;AACA;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAKF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAMF;AACA;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EAIA;;;AC3IF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAIF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAIF;AACA;EACE;EACA;;;AAEF;EACE;;;AAIA;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;;;AAGF;AACA;EACE;;;AAEF;EACE;EACA;;;AAGF;EACE;IACE;;;AAIJ;EACE;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EAEA;;;AAEF;EACE;IACE;IAEA;;EAEF;IACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EAEA;;;AAEF;EACE;IACE;;;AAKJ;AAAA;EAEE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AC3RF;AACA;EACE;EAEA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;EACA;EACA;EACA;EAGA,YACE;EAEF;EACA;;AAEA;EACE;;AAGF;EAEE;EAGA;EACA,YACE;;AAIJ;EACE;EACA;;;AAKN;AA+BE;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAEF;EAGE;;AAGF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EAhMA;EAmME;;AAjMF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAyLF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EAjPF;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAuOA;EAEE;;AAEA;EACE;EACA;;AAKN;EACE;EACA;EACA;EACA;;;AAGJ;AdvIA","file":"style.css"} \ No newline at end of file diff --git a/docs/development/timetracker/index.html b/docs/development/timetracker/index.html new file mode 100644 index 00000000..d188affa --- /dev/null +++ b/docs/development/timetracker/index.html @@ -0,0 +1,368 @@ + + + + + + Weekly Report: AI-Powered Work Summary | Adam Jolicoeur + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + +
+

Weekly Report: AI-Powered Work Summary

+

Start the day, capture tasks, review, and archive - then summarize using AI

+ + + +
+

Project Overview #

+
+

ROLE: Lead Product Designer & Product Manager

+

TYPE: Feature extension - personal productivity tool

+

STACK: React, TypeScript, Tailwind CSS, Google Gemini API

+

STATUS: Shipped - in daily use

+
+
+
+

About TimeTracker Pro #

+

TimeTracker Pro is a Progressive Web App (PWA) I designed, built, and use every day to track how I spend my work hours. It runs in the browser, installs as a native-like application on desktop and mobile, and stores data locally by default - no account required. Through the day I create tasks, assign them to projects and categories, and archive each completed day. Over time, it builds a personal record of where my time actually goes.

+

I built it because every time tracking tool that I tried was either too complex for my personal use, or too simple to be useful. TimeTracker Pro is purpose-built for the way I work: start the day, capture tasks as they happen, and review and archive at the end. It has been in daily use since early 2025 and has grown into a small, but complete, product - export formats, project management, offline support, and invoicing. The Weekly Report feature is the most recent addition, and the one that most clearly shows how the product has evolved from a personal utility into a considered system.

+
+
+ Start screen for TimeTracker Pro +
+
+
+
+

The Weekly Report Feature #

+
+

After archiving each week, I found myself running a second, separate tool to generate a weekly summary. That tool only worked with PDFs directly exported from the time tracker, only ran on a local development server, and product output that always needed manual cleanup before it was shareable. It was a workaround, not a product.

+

The Weekly Report feature replaces that entire workflow. It lives inside TimeTracker Pro as a dedicated route, directly reading the same data the rest of the app uses, and generates a coherent weekly narrative using an AI model (Gemini). The output can be tuned for different audiences - a team’s standup, a client update, or a personal retrospective - and is editable before copying to a separate document. No export step, no separate server, no manual cleanup.

+
+
+
+
+ Weekly Report Screen +
review the time period to summarize and select a tone before generation
+
+
+
+
+

The right tool for summarizing my work week is the tool that already knows my work week.

+
+
+
+

The Problem #

+
+

The original two-tool setup had three specific friction points:

+
    +
  1. No real integration
  2. +
  3. Availability
  4. +
  5. Output always requiring editing
  6. +
+
    +
  • +

    The generator only accepted PDFs from the time tracker, creating a dependency without any actual data sharing. The export was the only bridge between them.

    +
  • +
  • +

    The generator ran on a local Vite server, which meant it was only accessible from my machine and only in a single context. Any time I needed a summary on a different device, I was out of luck.

    +
  • +
  • +

    Because the generator had no understanding of who I was writing for, every summary came out generic and required manual work to make it usable. The generator sounded too similar from week-to-week, diminishing the quality of the reports.

    +
  • +
+
+
+

The deeper problem was that the tooling made a simple, recurring task feel like a project in itself. I needed a paragraph that I could drop into a standup or send to a client. What I had was a process.

+
+
+
+

Extend, Not Replace #

+
+

The obvious move might have been to build a better standalone summary tool, but I chose not to - and the reasoning matters.

+

A standalone tool would still need an export step, a file upload, or an API connection to access my time data. It would have to be general enough to work with any input, which means losing all the context that makes a summary actually useful - what categories mean, which projects are billable, and what a typical week looks like - specifically for me.

+

Extending TimeTracker Pro meant the summary feature could read directly from the same local data store the rest of the app uses. No synchronization problem. No format negotiation. The data is already structured exactly the way the feature needs it to be - tasks with descriptions, projects, categories, and duration - grouped by day.

+

It also meant the feature could be opinionated in ways that a generic tool cannot. It knows to exclude break-time and lunch categories automatically. It understands the project and client structure. It has enough context to group a week of task descriptions into a meaningful narrative rather than a list.

+
+
+
+

Design Decisions #

+
+

The goal was to make the AI feel like a step in a workflow, not a magic trick.

+
+

Two-panel Layout #

+

At wider view-ports, and the report page uses a two-column layout: controls on the left, output on the right. This came from recognizing that the interaction has two distinct modes - configuring the request and reviewing the result - and that collapsing them into a single scrolling column would blur that separation.

+

The left column handles week navigation, the data breakdown, and tone selection. it is the setup side. The right column is purely reactive - it shows whatever state the output is in: idle, generating, error, or a draft summary ready to edit and copy. Nothing in the right column requires user input; it only responds to decisions made on the left.

+

This separation also meant each column could be designed for its specific job. The left column is dense and interactive. The right column has more breathing room because reading and editing require it.

+
+
+
+
+ Report generation preview +
select what to include in the report and the desired tone
+
+
+
+
+
+
+ Client Summary +
the report summary, ready to copy into any document
+
+
+
+
+

The generation flow as a design experience #

+

The most deliberate UX decision was treating the AI generation as a visible, legible transition rather than a black-box button press. When generation is in progress, the right panel names the week being summarized and shows staggered skeleton lines that suggest an output is forthcoming.

+

The idle state - before anything has been generated - uses a dashed border container with a short explanation of what will appear there. This keeps the two-column layout from reading as broken or incomplete on first load, and gives the right panel a purpose even before it has content.

+

Error states are structured and recoverable: a header that names the failure, a plain-language description, and a “Try again” action inline. The error is informative without being alarming.

+
+
+
+ Report generation preview +
feedback showing the generation of the report
+
+
+
+
+
+

Tone as a product decision #

+

The tone selector - Standup, Client, Retrospective - reflects a real choice I make every week about who I’m writing for. These are not cosmetic variations. Each tone maps to a different set of system prompt instructions sent to the model, producing meaningfully different outputs.

+
+
+
Standup
+
+
+ Standup Summary +
terse, first-person, and focused on what moved and what is in progress
+
+
+
+
+
Client
+
+
+ Client Summary +
outcome-oriented, professional, and suitable for sharing progress on deliverables
+
+
+
+
+
Retrospective
+
+
+ Retrospective Summary +
more reflective, noting themes and shift across the week rather than just outputs
+
+
+
+
+
+

Having tone as an explicit control also solves a subtle UX problem: when you change the tone, the existing summary resets so you never mistake a standup summary for a client-ready output. The control communicates its own consequences.

+
+

Editable output by default #

+
+

The generated summary appears in an editable text area, rather than a read-only display. This frames the AI’s role correctly: it drafts, the human approves. The copy button and a brief ‘changes are not saved’ note completes the mental model - this is a staging area, not a final product.

+

A “regenerate” button sites alongside the copy button, so it is easy to get a different draft without scrolling back to the controls. The two actions - regenerate and copy - represent the two things a person actually wants to do with a draft: try again or take it.

+
+
+

AI prompt architecture #

+
+

The prompt that drives the summary is split into two parts. The system instruction establishes the persona, length constraints (3 to 5 sentences), voice (first-person, no filler phrases), and the specific tone instructions for whichever mode is selected. The user message contains the serialized week data - a lean, human-readable representation of each workday with task titles, descriptions, project names, and durations.

+

Before sending, the serialization step strips timestamps, IDs, and non-work categories. What reaches the model is only what a human would include if they were writing the summary prompt by hand. This matters because model output quality is directly proportional to input clarity - sending structured noise produces structured noise back.

+

The prompt architecture is designed to evolve. As I use the feature and notice patterns in what I edit or regenerate, the system instructions cane be turned to match how I actually write and what different audiences respond to. The tone categories themselves may expand - a spring summary or executive update tone would be natural additions as the use cases grow.

+
+
+
+
+
+

Outcome #

+

Every week I use the standup tone on Monday morning to orient myself before the week’s work begins, with the retrospective tone on Friday to close out the week. Before this feature existed, I skipped that ritual more often than not due to the fact that the tooling made it feel like work. Now it takes less than a minute. The summary is available wherever TimeTracker Pro is available, and the tone control means the output is usually usable with one or two edits rather than a full rewrite.

+

From a portfolio standpoint the project demonstrates a specific combination of skills: identifying friction in a real workflow, making a considered architectural decision about where a feature belongs, designing the interactions states that make AI output feel trustworthy, and shipping something that has been in daily use since it launched.

+
+
+
+ +
+ +
+ + +
+ + + + + + + + + diff --git a/docs/feed.json b/docs/feed.json index 18991995..c9e8ab1b 100644 --- a/docs/feed.json +++ b/docs/feed.json @@ -26,6 +26,14 @@ "url": "" }, "items": [ + { + "id": "/development/timetracker/", + "url": "/development/timetracker/", + "title": "Weekly Report: AI-Powered Work Summary", + "date_published": "2026-03-10T18:18:24Z", + "date": "2026-03-10T18:18:24Z" + } + , { "id": "/year-in-review/2025/", "url": "/year-in-review/2025/", diff --git a/docs/sass/containers.css b/docs/sass/containers.css new file mode 100644 index 00000000..92c815ee --- /dev/null +++ b/docs/sass/containers.css @@ -0,0 +1 @@ +.cards-row{gap:var(--space-lg,1.5rem);-ms-flex-flow:wrap;flex-flow:wrap;display:-ms-flexbox;display:flex}.prose-section:nth-child(2){margin-top:0}.prose-section .card,section .card{margin-bottom:var(--space-lg,1.5rem)}.card h2,.card h3,.card h4{margin-top:0;margin-bottom:var(--space-sm,.75rem)}.card>h3{margin-bottom:var(--space-md,1rem);padding-bottom:var(--space-md,1rem);border-bottom:var(--border-thin,2px)solid var(--earth-sand)}.card p:last-child,.card ul:last-child,.card ol:last-child{margin-bottom:0}.prose-section .card-shadow{background:var(--earth-cream);border-radius:var(--radius-lg,16px);padding:var(--space-md,1.5rem);box-shadow:10px 10px 0 var(--shadow-heavy);border:none}.prose-section .card-shadow>h3{margin-bottom:var(--space-md,1rem);padding-bottom:var(--space-md,1rem);border-bottom:var(--border-thin,2px)solid var(--earth-brown)}.prose-section .card-basic{background:var(--earth-sand);border:4px solid var(--earth-brown);border-radius:var(--radius-lg,16px);padding:var(--space-md,1.5rem);box-shadow:6px 6px 0 var(--shadow-heavy);transition:transform .3s}.prose-section .card-basic>h3{margin-bottom:var(--space-md,1rem);padding-bottom:var(--space-md,1rem);border-bottom:var(--border-thin,2px)solid var(--earth-brown)}blockquote{color:var(--text-primary);margin:var(--space-lg,1.5rem);padding:var(--space-lg,1.5rem);background:var(--earth-sand-light);border-left:var(--border-medium)solid var(--accent-coral);font-size:max(1rem,min(1.5vw,1.1rem));font-weight:600;line-height:1.6} \ No newline at end of file diff --git a/docs/sass/markdown.css b/docs/sass/markdown.css index aa10a161..76607185 100644 --- a/docs/sass/markdown.css +++ b/docs/sass/markdown.css @@ -1 +1 @@ -pre{background-color:var(--earth-cream);padding:var(--space-md,1rem);border-radius:var(--radius-md,12px)}section h2{margin-top:var(--space-lg,2rem)!important}section h3,section ul,section ol{margin-bottom:var(--space-md,1rem)!important} \ No newline at end of file +pre{background-color:var(--earth-cream);padding:var(--space-md,1rem);border-radius:var(--radius-md,12px)}section h2{margin-top:var(--space-lg,2rem)!important}section h3,section ul,section ol{margin-bottom:var(--space-md,1rem)!important}.card>h2:after{display:none} \ No newline at end of file diff --git a/docs/sass/style.css b/docs/sass/style.css index 9e11ad8d..21c9b8b0 100644 --- a/docs/sass/style.css +++ b/docs/sass/style.css @@ -1 +1 @@ -:root{--font-family-sans:"Inter",system-ui,-apple-system,blinkmacsystemfont,"Segoe UI",roboto,"Helvetica Neue",arial,sans-serif;--font-family-serif:"Playfair Display",serif;--font-family-mono:"Fira Code","Courier New",courier,monospace;--font-family-heading:"Pirata One",cursive;--white:#f0f0f0;--black:#010101;--earth-dark:#2d1f12;--earth-brown:#4a3426;--earth-sage:#5a6b4f;--earth-sand:#c9b89a;--earth-cream:#f5f1e8;--accent-coral:#d35f3d;--accent-coral-dark:#b34a2d;--text-primary:#2d1f12;--text-secondary:#4a3426;--text-muted:#6b5d52;--shadow:rgba(45,31,18,.15);--shadow-heavy:rgba(45,31,18,.25);--shadow-light:rgba(45,31,18,.08);--font-size-xs:.75rem;--font-size-sm:.875rem;--font-size-md:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--font-size-2xl:1.5rem;--font-size-3xl:2rem;--font-size-4xl:2.5rem;--font-size-5xl:3rem;--font-size-6xl:4rem;--space-2xs:.25rem;--space-xs:.5rem;--space-sm:.75rem;--space-md:1rem;--space-lg:1.5rem;--space-xl:2rem;--space-2xl:3rem;--space-3xl:6rem;--radius-sm:8px;--radius-md:12px;--radius-lg:16px;--radius-xl:20px;--radius-pill:50px;--border-thin:2px;--border-medium:4px;--border-thick:6px;--border-extra-thick:8px}*{box-sizing:border-box;margin:0;padding:0}:focus-visible{outline:var(--border-thin)solid var(--accent-coral);outline-offset:2px}html{scroll-behavior:smooth}body{font-family:var(--font-family-sans);background:linear-gradient(135deg,var(--earth-cream)0%,#e8dcc8 100%);color:var(--text-primary);min-height:100vh;line-height:1.6;position:relative}html::-webkit-scrollbar{width:16px}::-webkit-scrollbar{width:16px}html::-webkit-scrollbar-thumb{background:linear-gradient(var(--accent-coral-dark),var(--accent-coral));background-clip:content-box;border:2px solid transparent;border-radius:2rem}::-webkit-scrollbar-thumb{background:linear-gradient(var(--accent-coral-dark),var(--accent-coral));background-clip:content-box;border:2px solid transparent;border-radius:2rem}html::-webkit-scrollbar-track{border:1px solid var(--earth-sage);background:0 0;border-radius:2rem;padding:0 2px}::-webkit-scrollbar-track{border:1px solid var(--earth-sage);background:0 0;border-radius:2rem;padding:0 2px}@media (prefers-reduced-motion:reduce){.animated-element{opacity:1;transition:none;animation:none}body{scroll-behavior:auto}*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}.display-none,.d-none{display:none!important}.hero{text-align:center;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;max-width:900px;margin:0 auto;padding:6rem 2rem;display:-ms-flexbox;display:flex}.rounded{border-radius:var(--radius-xl,20px)!important}.circle{border-radius:999px!important;padding:1rem!important}.fade-in{opacity:0;visibility:hidden;transition:opacity .5s ease-in,visibility 0s linear .5s}.fade-in.show,.show{opacity:1;visibility:visible;transition-delay:0s}.hide{opacity:0;visibility:hidden;transition:opacity .5s ease-in,visibility 0s linear .5s}.hide-on-screen{display:none!important}@media (max-width:768px){.hero h1{font-size:var(--font-size-5xl,3rem)}.no-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.hide-on-mobile{display:none!important}.work-grid,.callouts-grid{grid-template-columns:1fr}h2{font-size:var(--font-size-3xl,2rem)}}figcaption{font-size:var(--font-size-sm,.875rem);color:var(--text-secondary);text-align:center;font-style:italic;line-height:1.4}.arrows{width:60px;height:72px;margin-left:-30px;position:absolute;bottom:20px;left:50%}.arrows path{stroke:#bfe7fa;fill:transparent;stroke-width:1px;animation:2s infinite arrow}@keyframes arrow{0%{opacity:0}40%{opacity:1}80%{opacity:0}to{opacity:0}}.arrows path.a1{animation-delay:-1s}.arrows path.a2{animation-delay:-.5s}.arrows path.a3{animation-delay:0s}.pirata-one-regular{font-family:Pirata One,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue;font-style:normal;font-weight:400}.inter-400{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:400}.inter-500{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:500}.inter-600{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:600}.inter-700{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:700}.inter-800{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:800}.inter-900{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:900}.playfair-display-400{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:400}.playfair-display-500{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:500}.playfair-display-600{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:600}.playfair-display-700{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:700}.playfair-display-800{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:800}.playfair-display-900{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:900}h1,.text-h1{color:var(--text-primary);letter-spacing:2px;text-shadow:3px 3px 0 var(--accent-coral);font-family:Pirata One,cursive;font-size:max(2.5rem,min(8vw,5rem));line-height:1.2}.text-display{color:var(--text-primary);letter-spacing:2px;text-shadow:3px 3px 0 var(--accent-coral);font-family:Pirata One,cursive;font-size:max(3rem,min(10vw,6rem));line-height:1.1}.hero h1{font-family:var(--font-family-heading);color:var(--text-primary);text-shadow:3px 3px 0 var(--accent-coral);letter-spacing:2px;margin-bottom:1rem;font-size:6rem;line-height:1.2}h2,.text-h2{color:var(--text-primary);margin-bottom:var(--space-md,1.5rem);font-family:Playfair Display,serif;font-size:max(2rem,min(5vw,3rem));font-weight:700;line-height:1.3}.text-h2.no-underline:after{margin-bottom:var(--space-2xs,.25rem);display:none}h2:after,.text-h2:after{content:"";background:var(--accent-coral);border:3px solid var(--earth-brown);width:100px;height:5px;margin:1rem auto;display:block}h3,.text-h3{color:var(--text-primary);font-family:Playfair Display,serif;font-size:max(1.5rem,min(3vw,2rem));font-weight:600;line-height:1.3}h4,.text-h4{color:var(--text-primary);font-family:Playfair Display,serif;font-size:max(1.25rem,min(2.5vw,1.5rem));font-weight:600;line-height:1.4}h5,.text-h5{color:var(--text-primary);font-family:Inter,sans-serif;font-size:max(1.1rem,min(2vw,1.25rem));font-weight:700;line-height:1.4}h6,.text-h6{color:var(--text-primary);text-transform:uppercase;letter-spacing:.5px;font-family:Inter,sans-serif;font-size:1rem;font-weight:700;line-height:1.4}.text-body-lg{font-size:max(1.1rem,min(1.5vw,1.25rem))!important;line-height:1.7!important}p,.text-body{color:var(--text-primary);padding-bottom:var(--space-xs,.5rem);font-size:max(.95rem,min(1.5vw,1rem));line-height:1.7}p:last-child,.text-body:last-child{margin-bottom:0}.hero p{color:var(--earth-brown);max-width:720px;margin:0 auto;font-size:max(1.1rem,min(2vw,1.25rem))}.card-body p:first-of-type,.card-body .text-body:first-of-type{margin-top:var(--space-md,16px)}.text-body-sm{font-size:max(.85rem,min(1.2vw,.9rem));line-height:1.6}.text-caption{font-size:clamp(var(--space-sm),1vw,.85rem);color:var(--text-muted);line-height:1.5}.text-callout{color:var(--text-primary);margin:var(--space-lg,1.5rem);padding:var(--space-lg,1.5rem);background:var(--earth-sand-light);border-left:var(--border-medium)solid var(--accent-coral);font-size:max(1rem,min(1.5vw,1.1rem));font-weight:600;line-height:1.6}code,.code{font-family:var(--font-family-mono);font-size:max(.85rem,min(1vw,.9rem))}code.code-inline,.code.code-inline{background:var(--earth-sand);border-radius:var(--radius-sm);padding:.1rem .3rem}.code-block{background:var(--earth-sand);border-radius:var(--radius-md);border:var(--border-thin)solid var(--earth-sage);padding:1rem;font-size:max(.85rem,min(1vw,.9rem));display:block;overflow-x:auto}.text-muted{color:var(--text-muted)}.text-secondary{color:var(--text-secondary)}.text-accent{color:var(--accent-coral)}.text-semibold{font-weight:600}.text-bold{font-weight:700}.text-center{text-align:center}.lead,.text-lead{color:var(--text-secondary);font-size:max(1.1rem,min(2vw,1.35rem));line-height:1.7}a,.link{color:var(--earth-sage);border-bottom:1px solid var(--earth-sage);font-weight:var(--font-weight-semibold,600);text-decoration:none;transition:all .2s}a:hover,a:focus,.link:hover,.link:focus{color:var(--earth-brown);border-bottom-color:var(--earth-brown)}.link-brackets{margin-left:var(--space-md)!important}.link-brackets:after{content:"]";color:var(--earth-sage);margin-left:.2rem;transition:all .2s;position:absolute}.link-brackets:before{content:"[";color:var(--earth-sage);margin-left:-.8rem;transition:all .2s;position:absolute}.link-brackets:hover:after,.link-brackets:hover:before,.link-brackets:focus:after,.link-brackets:focus:before{color:var(--accent-coral)}blockquote,.blockquote{border-left:var(--border-thin)solid var(--earth-brown);padding-left:var(--space-md,1rem);margin:var(--space-lg,1.5rem)0;color:var(--text-secondary);font-style:italic}.mb-1{margin-bottom:var(--space-2xs)!important}.mb-2{margin-bottom:var(--space-xs)!important}.mb-3{margin-bottom:var(--space-sm)!important}.mb-4{margin-bottom:var(--space-md)!important}.mb-5{margin-bottom:var(--space-xl)!important}.mt-1{margin-top:var(--space-2xs)!important}.mt-2{margin-top:var(--space-xs)!important}.mt-3{margin-top:var(--space-sm)!important}.mt-4{margin-top:var(--space-md)!important}.mt-5{margin-top:var(--space-xl)!important}.ml-1{margin-left:var(--space-2xs)!important}.ml-2{margin-left:var(--space-xs)!important}.ml-3{margin-left:var(--space-sm)!important}.ml-4{margin-left:var(--space-md)!important}.ml-5{margin-left:var(--space-xl)!important}.mr-1{margin-right:var(--space-2xs)!important}.mr-2{margin-right:var(--space-xs)!important}.mr-3{margin-right:var(--space-sm)!important}.mr-4{margin-right:var(--space-md)!important}.mr-5{margin-right:var(--space-xl)!important}.p-1{padding:var(--space-2xs)!important}.p-2{padding:var(--space-xs)!important}.p-3{padding:var(--space-sm)!important}.p-4{padding:var(--space-md)!important}.p-5{padding:var(--space-xl)!important}.pt-1{padding-top:var(--space-2xs)!important}.pt-2{padding-top:var(--space-xs)!important}.pt-3{padding-top:var(--space-sm)!important}.pt-4{padding-top:var(--space-md)!important}.pt-5{padding-top:var(--space-xl)!important}.pb-1{padding-bottom:var(--space-2xs)!important}.pb-2{padding-bottom:var(--space-xs)!important}.pb-3{padding-bottom:var(--space-sm)!important}.pb-4{padding-bottom:var(--space-md)!important}.pb-5{padding-bottom:var(--space-xl)!important}.pl-1{padding-left:var(--space-2xs)!important}.pl-2{padding-left:var(--space-xs)!important}.pl-3{padding-left:var(--space-sm)!important}.pl-4{padding-left:var(--space-md)!important}.pl-5{padding-left:var(--space-xl)!important}.pr-1{padding-right:var(--space-2xs)!important}.pr-2{padding-right:var(--space-xs)!important}.pr-3{padding-right:var(--space-sm)!important}.pr-4{padding-right:var(--space-md)!important}.pr-5{padding-right:var(--space-xl)!important}section{max-width:1200px;padding:var(--space-3xl,6rem)var(--space-lg,2rem);margin:0 auto}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.row{gap:var(--space-lg,2rem);-ms-flex-wrap:wrap;flex-wrap:wrap;display:-ms-flexbox;display:flex}@media (min-width:768px){.row{gap:var(--space-sm,.5rem)}.card-body .row{gap:0}}.button-row{gap:1rem}.no-wrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.d-flex{display:-ms-flexbox;display:flex}.flex-column{-ms-flex-direction:column;flex-direction:column}.align-items-center{-ms-flex-align:center;align-items:center}.work-grid{gap:var(--space-lg,2rem);margin-bottom:var(--space-lg,2rem);grid-template-columns:repeat(auto-fit,minmax(300px,1fr));display:grid}.divider{width:50%;height:var(--space-md,1.5rem);background:var(--accent-coral);border:var(--border-medium,4px)outset var(--earth-dark);margin:0 auto;display:block}.divider.vertical{width:var(--space-2xs,.25rem);background:var(--earth-dark);border-radius:var(--radius-sm);height:100%;margin:0;border:none!important}ul,ol,.card-body ul,.card-body ol,ul.list,ol.list{margin-left:var(--space-lg)!important;padding-left:var(--space-md)!important}.highlight-block{-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.header-highlight{text-align:center;margin:var(--space-md)auto;padding:var(--space-md);width:100%}nav{z-index:1000;backdrop-filter:blur(24px);filter:url(#lensFilter)saturate(120%)brightness(1.15);border:var(--border-medium,4px)solid var(--earth-brown);padding:var(--space-sm)2rem;box-shadow:0 8px 24px var(--shadow-heavy);background:rgba(245,241,232,.5);border-radius:50px;position:fixed;top:2rem;left:50%;transform:translate(-50%)}.main-nav{width:fit-content;margin:0 auto;position:sticky;top:2rem;left:0;right:0;transform:none!important}nav ul{-ms-flex-pack:center;justify-content:center;gap:2rem;list-style:none;display:-ms-flexbox;display:flex;margin-left:0!important;padding-left:0!important}nav a{color:var(--text-primary);padding:var(--space-2xs)var(--space-xs,.5rem);border-bottom:none;font-size:.95rem;font-weight:500;text-decoration:none;transition:color .3s}nav a:hover,nav a:focus{color:var(--accent-coral);outline:var(--border-thin)solid var(--accent-coral);outline-offset:2px}nav a.active{color:var(--accent-coral)}nav a.sub-page{outline:var(--border-thin)solid var(--text-secondary);outline-offset:2px}nav a.sub-page:hover{outline-color:var(--accent-coral)}@media (max-width:768px){nav{top:var(--space-sm,1rem)!important;padding:var(--space-xs,.5rem)var(--space-sm,1rem)!important;margin:0 auto!important}nav ul{gap:var(--space-sm,1rem)}}footer{background:var(--earth-dark);color:var(--earth-cream);padding:var(--space-2xl,3rem)var(--space-xl,2rem);margin-top:var(--space-3xl,6rem);border-top:var(--border-extra-thick,8px)solid var(--earth-brown);box-shadow:0 -10px 30px var(--shadow)}.footer-content{grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:3rem;max-width:1200px;margin:0 auto;display:grid}.footer-section h3{color:var(--accent-coral);margin-bottom:var(--space-md,1rem);font-family:Playfair Display,serif;font-size:max(1.2rem,min(2vw,1.5rem))}.footer-section h4{margin-bottom:var(--space-md,1rem);font-family:Playfair Display,serif;font-size:max(1.1rem,min(1.25vw,1.125rem));color:rgba(255,255,255,.5)!important}.footer-section p,.footer-section li{color:var(--earth-cream);margin-bottom:var(--space-xs,.5rem);line-height:1.6}.footer-section ul{padding:0;list-style:none}.footer-section li{margin-bottom:var(--space-xs,.5rem)}.footer-bottom{text-align:center;margin-top:var(--space-2xl,3rem);padding-top:var(--space-xl,2rem);border-top:var(--border-medium,4px)solid var(--earth-brown);color:var(--earth-sand)}.footer-bottom p{font-size:var(--font-size-sm);color:var(--earth-cream);margin:0}.footer-section a,.footer-bottom a{color:var(--earth-cream);text-decoration:underline}.footer-section a:hover,.footer-bottom a:hover{color:var(--accent-coral)}.badge{padding:var(--space-2xs,.25rem)var(--space-sm,.75rem);background:var(--earth-sage);color:var(--earth-cream);border:var(--border-thin,2px)solid var(--earth-brown);border-radius:var(--radius-pill);font-size:.85rem;font-weight:600;display:inline-block}.badge-accent{background:var(--accent-coral-dark)}.badge-outline{color:inherit;background:0 0}.badges,.row-badges{gap:var(--space-2xs,.25rem);-ms-flex-wrap:wrap;flex-wrap:wrap;display:-ms-flexbox;display:flex}.btn{padding:var(--space-sm,.75rem)var(--space-lg,1.5rem);font-family:var(--font-family-sans);font-size:var(--font-size-md,1rem);border-radius:var(--radius-md,12px);cursor:pointer;text-align:center;border:none;font-weight:600;text-decoration:none;transition:all .2s;display:inline-block}.btn:hover,.btn:focus{box-shadow:2px 2px 0 var(--earth-brown);transform:translate(2px,2px)}.btn-primary{background:var(--accent-coral-dark);color:var(--white);border:var(--border-medium,4px)solid var(--earth-brown);box-shadow:4px 4px 0 var(--earth-brown)}.btn-primary:hover,.btn-primary:focus{background:var(--accent-coral-dark);color:var(--white)}.btn-secondary{background:var(--earth-cream);color:var(--text-primary);border:var(--border-medium,4px)solid var(--earth-brown);box-shadow:4px 4px 0 var(--earth-sage)}.btn-secondary:hover,.btn-secondary:focus{background:var(--earth-sand);color:var(--text-primary);box-shadow:2px 2px 0 var(--earth-sage);outline:var(--border-thin)solid var(--earth-dark);transform:translate(2px,2px)}.btn-outline{backdrop-filter:blur(24px);filter:url(#lensFilter)saturate(120%)brightness(1.15);color:var(--text-primary)!important;border:var(--border-medium,4px)solid var(--earth-brown)!important;box-shadow:none!important;background:rgba(255,255,255,.5)!important}.btn-outline:hover,.btn-outline:focus{color:var(--earth-cream);text-decoration:underline}.btn-sm{padding:var(--space-xs,.5rem)var(--space-md,1rem)!important;border-width:var(--border-thin)!important;font-size:.9rem!important}.btn-lg{padding:var(--space-md,1rem)var(--space-xl,2rem)!important;font-size:1.1rem!important}.skip-link{background:var(--accent-coral);color:var(--white);padding:var(--space-sm,.75rem)var(--space-lg,1.5rem);border:var(--border-medium,4px)solid var(--earth-brown);z-index:2000;clip:rect(0,0,0,0);font-weight:600;text-decoration:none;position:absolute;top:-100px;left:0;overflow:hidden}.skip-link:focus{clip:auto;top:1rem;left:1rem;overflow:visible}.social-links{-ms-flex-wrap:wrap;flex-wrap:wrap;gap:1rem;display:-ms-flexbox;display:flex}.social-link{padding:var(--space-xs,.5rem)var(--space-md,1rem);background:var(--earth-sage);color:var(--white);border:var(--border-medium,4px)solid var(--earth-sand);border-radius:8px;font-size:.95rem;font-weight:500;transition:all .3s;display:inline-block;text-decoration:none!important}.social-link:hover,.social-link:focus{background:var(--accent-coral);transform:translateY(-2px);color:var(--white)!important}.card{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);padding:var(--space-lg,1.5rem);box-shadow:8px 8px 0 var(--shadow-heavy);transition:transform .3s,box-shadow .3s}.card:hover{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.card:focus-within{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.card-layered{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);padding:var(--space-xl,2rem);box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown)}.card-shadow{background:var(--earth-cream);border-radius:var(--radius-lg,16px);padding:var(--space-md,1.5rem);box-shadow:10px 10px 0 var(--shadow-heavy);border:none}.card-accent{background:var(--earth-cream);border:var(--border-extra-thick,8px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);box-shadow:16px 16px 0 var(--accent-coral),16px 16px 0 6px var(--earth-brown);overflow:hidden}.card-flex{-ms-flex-direction:column;flex-direction:column;display:-ms-flexbox;display:flex}.card-flex p{-ms-flex:1 0;flex:1 0}.card-with-columns .row{-ms-flex-align:start;align-items:flex-start;gap:var(--space-md,1rem);-ms-flex-item-align:stretch;align-self:stretch;display:-ms-flexbox;display:flex}.card-with-columns .column{-ms-flex:1 0 0;flex:1 0 0;-ms-flex-item-align:stretch;align-self:stretch;-ms-flex-align:start;align-items:flex-start;display:-ms-flexbox;display:flex}.card-header{margin-bottom:var(--space-md,1rem);padding-bottom:var(--space-md,1rem);border-bottom:var(--border-thin,2px)solid var(--earth-sand)}.card-body{margin-bottom:var(--space-md)}.card-body img{object-fit:cover;width:100%}@media (min-width:768px){.img-thumbnail{max-width:50%}}.card-body:last-child{margin-bottom:0}.card-footer{margin-top:var(--space-md,1rem);padding-top:var(--space-md,1rem);border-top:var(--border-thin,2px)solid var(--earth-sand)}.showcase-content{padding:var(--space-lg,2rem)}.showcase-content h3{font-family:var(--font-family-serif);color:var(--text-primary);margin-bottom:var(--space-sm,1rem);font-size:max(1.3rem,min(2.5vw,1.8rem))}.showcase-content p{color:var(--text-secondary);margin-bottom:var(--space-md,1.5rem);font-size:max(.95rem,min(1.5vw,1rem))}.showcase-small{background:var(--earth-sand);border:4px solid var(--earth-brown);border-radius:var(--radius-lg,16px);padding:var(--space-md,1.5rem);box-shadow:6px 6px 0 var(--shadow-heavy);transition:transform .3s}.showcase-small:hover{transform:translateY(-4px)}.showcase-small:focus-within{transform:translateY(-4px)}.showcase-small h4{font-family:var(--font-family-serif);color:var(--text-primary);margin-bottom:var(--space-xs,.5rem);font-size:max(1.1rem,min(2vw,1.3rem))}.showcase-small p{color:var(--text-secondary);font-size:max(.9rem,min(1.5vw,.95rem))}.about-card{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);box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown);margin:0 auto}@media (max-width:768px){.about-card{box-shadow:6px 6px 0 var(--earth-sage),6px 6px 0 4px var(--earth-brown);padding:var(--space-md,1rem)}.about-grid{grid-template-columns:1fr!important}}.about-card p{color:var(--text-primary);margin-bottom:var(--space-lg,1.5rem);font-size:max(1rem,min(1.5vw,1.1rem));line-height:1.8}.about-card p:last-child{margin-bottom:0}.about-grid{gap:var(--space-xl,2rem);margin-top:var(--space-xl,2rem);grid-template-columns:repeat(auto-fit,minmax(350px,1fr));display:grid}.showcase-large{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);box-shadow:12px 12px 0 var(--accent-coral),12px 12px 0 6px var(--earth-brown);transition:transform .3s;overflow:hidden}@media (max-width:768px){.showcase-large{box-shadow:6px 6px 0 var(--accent-coral),6px 6px 0 4px var(--earth-brown)}}.showcase-large:hover{transform:translateY(-8px)}.showcase-large:focus-within{transform:translateY(-8px)}.showcase-image{background:linear-gradient(135deg,var(--earth-sage)0%,var(--earth-sand)100%);width:100%;height:300px;padding:var(--space-md,1rem);font-size:var(--font-size-5xl,3rem);color:var(--earth-cream);border-bottom:var(--border-thick,6px)solid var(--earth-brown);object-fit:contain;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.showcase-image-dark{background:linear-gradient(135deg,var(--black)0%,var(--earth-dark)100%)}.small-showcase-cards{gap:var(--space-md,1.5rem);margin-top:var(--space-sm,1rem);grid-column:1/-1;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));display:grid}.callouts-grid{grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:2rem;margin-top:2rem;display:grid}.callout{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--accent-coral-dark);border-radius:var(--radius-xl,20px);box-shadow:8px 8px 0 var(--shadow-heavy);-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:end;align-items:flex-end;padding:2rem;transition:transform .3s,box-shadow .3s;display:-ms-flexbox;display:flex;position:relative}.callout:hover{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.callout:focus-within{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.callout:before{content:"\"";font-family:var(--font-family-serif);font-size:var(--font-size-6xl,4rem);color:var(--accent-coral);line-height:1;position:absolute;top:10px;left:20px}.callout-text{margin-bottom:var(--space-md,1.5rem);padding-top:var(--space-sm,1rem);color:var(--text-primary);font-style:italic}.callout-author{color:var(--text-primary);font-weight:600;display:block}.callout-role{font-size:var(--font-size-sm,.9rem);color:var(--text-secondary)}.gallery{--size:100px;grid-template-columns:repeat(6,var(--size));grid-auto-rows:var(--size);margin-bottom:var(--size);-ms-flex-align:start;align-items:start;justify-items:center;gap:5px;display:grid}.gallery:has(:hover) picture:not(:hover){filter:brightness(.5)contrast(.5)}.gallery:has(:focus) picture:not(:focus){filter:brightness(.5)contrast(.5)}.gallery picture{object-fit:cover;width:calc(var(--size)*2);height:calc(var(--size)*2);clip-path:path("M90,10 C100,0 100,0 110,10 190,90 190,90 190,90 200,100 200,100 190,110 190,110 110,190 110,190 100,200 100,200 90,190 90,190 10,110 10,110 0,100 0,100 10,90Z");border-radius:5px;grid-column:auto/span 2;transition:clip-path .25s,filter .75s}.gallery picture:nth-child(5n-1){grid-column:2/span 2}.gallery picture:hover,.gallery picture:focus{clip-path:path("M0,0 C0,0 200,0 200,0 200,0 200,100 200,100 200,100 200,200 200,200 200,200 100,200 100,200 100,200 100,200 0,200 0,200 0,100 0,100 0,100 0,100 0,100Z");z-index:1;transition:clip-path .25s,filter .25s}.gallery picture:focus{outline-offset:-5px;outline:1px dashed #000}.carousel>input{clip:rect(1px,1px,1px,1px);clip-path:inset(50%);width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.carousel>input:nth-of-type(15):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1400%}.carousel>input:nth-of-type(14):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1300%}.carousel>input:nth-of-type(13):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1200%}.carousel>input:nth-of-type(12):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1100%}.carousel>input:nth-of-type(11):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1000%}.carousel>input:nth-of-type(10):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-900%}.carousel>input:nth-of-type(9):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-800%}.carousel>input:nth-of-type(8):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-700%}.carousel>input:nth-of-type(7):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-600%}.carousel>input:nth-of-type(6):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-500%}.carousel>input:nth-of-type(5):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-400%}.carousel>input:nth-of-type(4):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-300%}.carousel>input:nth-of-type(3):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-200%}.carousel>input:nth-of-type(2):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-100%}.carousel>input:first-of-type:checked~.carousel__slides .carousel__slide:first-of-type{margin-left:0%}.carousel>input:first-of-type:checked~.carousel__thumbnails li:first-of-type,.carousel>input:nth-of-type(2):checked~.carousel__thumbnails li:nth-of-type(2),.carousel>input:nth-of-type(3):checked~.carousel__thumbnails li:nth-of-type(3),.carousel>input:nth-of-type(4):checked~.carousel__thumbnails li:nth-of-type(4),.carousel>input:nth-of-type(5):checked~.carousel__thumbnails li:nth-of-type(5),.carousel>input:nth-of-type(6):checked~.carousel__thumbnails li:nth-of-type(6),.carousel>input:nth-of-type(7):checked~.carousel__thumbnails li:nth-of-type(7),.carousel>input:nth-of-type(8):checked~.carousel__thumbnails li:nth-of-type(8),.carousel>input:nth-of-type(9):checked~.carousel__thumbnails li:nth-of-type(9),.carousel>input:nth-of-type(10):checked~.carousel__thumbnails li:nth-of-type(10),.carousel>input:nth-of-type(11):checked~.carousel__thumbnails li:nth-of-type(11),.carousel>input:nth-of-type(12):checked~.carousel__thumbnails li:nth-of-type(12),.carousel>input:nth-of-type(13):checked~.carousel__thumbnails li:nth-of-type(13),.carousel>input:nth-of-type(14):checked~.carousel__thumbnails li:nth-of-type(14),.carousel>input:nth-of-type(15):checked~.carousel__thumbnails li:nth-of-type(15){box-shadow:0 0 0 5px rgba(0,0,255,.5)}.carousel__slides{z-index:1;white-space:nowrap;box-sizing:border-box;margin:0;padding:0;display:-ms-flexbox;display:flex;position:relative;overflow:hidden}.carousel__slide{vertical-align:top;box-sizing:border-box;white-space:normal;-ms-flex:1 0 100%;flex:1 0 100%;width:100%;height:100%;transition:all .3s ease-out;display:block;position:relative;overflow:hidden}.carousel__slide figure{-ms-flex-direction:column;flex-direction:column;margin:0;display:-ms-flexbox;display:flex}.carousel__slide div{width:100%;position:relative}.carousel__slide div:before{content:"";width:100%;padding-top:66.6667%;display:block}.carousel__slide div>img{width:100%;height:100%;position:absolute;top:0;bottom:0;left:0;right:0}.carousel__slide img{object-fit:cover;-ms-flex:auto;flex:auto;display:block}.carousel__slide figcaption{-ms-flex:none;flex:none;-ms-flex-item-align:center;align-self:center;width:25%;min-width:150px;padding:20px 20px 0}.carousel__slide .credit{color:rgba(0,0,0,.5);margin-top:1rem;display:block}.carousel__slide.scrollable{overflow-y:scroll}.carousel__thumbnails{margin:0 -10px;padding:0;list-style:none;display:-ms-flexbox;display:flex}.carousel__slides+.carousel__thumbnails{margin-top:20px}.carousel__thumbnails li{-ms-flex:auto;flex:auto;max-width:calc(16.6667% - 20px);margin:0 10px;transition:all .3s ease-in-out}.carousel__thumbnails label{display:block;position:relative}.carousel__thumbnails label:before{content:"";width:100%;padding-top:100%;display:block}.carousel__thumbnails label>img{width:100%;height:100%;position:absolute;top:0;bottom:0;left:0;right:0}.carousel__thumbnails label:hover,.carousel__thumbnails label:focus{cursor:pointer}.carousel__thumbnails label:hover img,.carousel__thumbnails label:focus img{transition:all .3s ease-in-out;box-shadow:0 0 0 1px rgba(0,0,0,.25)}.carousel__thumbnails img{object-fit:cover;width:100%;height:100%;display:block} \ No newline at end of file +:root{--font-family-sans:"Inter",system-ui,-apple-system,blinkmacsystemfont,"Segoe UI",roboto,"Helvetica Neue",arial,sans-serif;--font-family-serif:"Playfair Display",serif;--font-family-mono:"Fira Code","Courier New",courier,monospace;--font-family-heading:"Pirata One",cursive;--white:#f0f0f0;--black:#010101;--earth-dark:#2d1f12;--earth-brown:#4a3426;--earth-sage:#5a6b4f;--earth-sand:#c9b89a;--earth-cream:#f5f1e8;--accent-coral:#d35f3d;--accent-coral-dark:#b34a2d;--text-primary:#2d1f12;--text-secondary:#4a3426;--text-muted:#6b5d52;--shadow:rgba(45,31,18,.15);--shadow-heavy:rgba(45,31,18,.25);--shadow-light:rgba(45,31,18,.08);--font-size-xs:.75rem;--font-size-sm:.875rem;--font-size-md:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--font-size-2xl:1.5rem;--font-size-3xl:2rem;--font-size-4xl:2.5rem;--font-size-5xl:3rem;--font-size-6xl:4rem;--space-2xs:.25rem;--space-xs:.5rem;--space-sm:.75rem;--space-md:1rem;--space-lg:1.5rem;--space-xl:2rem;--space-2xl:3rem;--space-3xl:6rem;--radius-sm:8px;--radius-md:12px;--radius-lg:16px;--radius-xl:20px;--radius-pill:50px;--border-thin:2px;--border-medium:4px;--border-thick:6px;--border-extra-thick:8px}*{box-sizing:border-box;margin:0;padding:0}:focus-visible{outline:var(--border-thin)solid var(--accent-coral);outline-offset:2px}html{scroll-behavior:smooth}body{font-family:var(--font-family-sans);background:linear-gradient(135deg,var(--earth-cream)0%,#e8dcc8 100%);color:var(--text-primary);min-height:100vh;line-height:1.6;position:relative}html::-webkit-scrollbar{width:16px}::-webkit-scrollbar{width:16px}html::-webkit-scrollbar-thumb{background:linear-gradient(var(--accent-coral-dark),var(--accent-coral));background-clip:content-box;border:2px solid transparent;border-radius:2rem}::-webkit-scrollbar-thumb{background:linear-gradient(var(--accent-coral-dark),var(--accent-coral));background-clip:content-box;border:2px solid transparent;border-radius:2rem}html::-webkit-scrollbar-track{border:1px solid var(--earth-sage);background:0 0;border-radius:2rem;padding:0 2px}::-webkit-scrollbar-track{border:1px solid var(--earth-sage);background:0 0;border-radius:2rem;padding:0 2px}@media (prefers-reduced-motion:reduce){.animated-element{opacity:1;transition:none;animation:none}body{scroll-behavior:auto}*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}.display-none,.d-none{display:none!important}.hero{text-align:center;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;max-width:900px;margin:0 auto;padding:6rem 2rem;display:-ms-flexbox;display:flex}.rounded{border-radius:var(--radius-xl,20px)!important}.circle{border-radius:999px!important;padding:1rem!important}.fade-in{opacity:0;visibility:hidden;transition:opacity .5s ease-in,visibility 0s linear .5s}.fade-in.show,.show{opacity:1;visibility:visible;transition-delay:0s}.hide{opacity:0;visibility:hidden;transition:opacity .5s ease-in,visibility 0s linear .5s}.hide-on-screen{display:none!important}@media (max-width:768px){.hero h1{font-size:var(--font-size-5xl,3rem)}.no-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.hide-on-mobile{display:none!important}.work-grid,.callouts-grid{grid-template-columns:1fr}h2{font-size:var(--font-size-3xl,2rem)}}figcaption{font-size:var(--font-size-sm,.875rem);color:var(--text-secondary);text-align:center;font-style:italic;line-height:1.4}.arrows{width:60px;height:72px;margin-left:-30px;position:absolute;bottom:20px;left:50%}.arrows path{stroke:#bfe7fa;fill:transparent;stroke-width:1px;animation:2s infinite arrow}@keyframes arrow{0%{opacity:0}40%{opacity:1}80%{opacity:0}to{opacity:0}}.arrows path.a1{animation-delay:-1s}.arrows path.a2{animation-delay:-.5s}.arrows path.a3{animation-delay:0s}.pirata-one-regular{font-family:Pirata One,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue;font-style:normal;font-weight:400}.inter-400{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:400}.inter-500{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:500}.inter-600{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:600}.inter-700{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:700}.inter-800{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:800}.inter-900{font-optical-sizing:auto;font-family:Inter,sans-serif;font-style:normal;font-weight:900}.playfair-display-400{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:400}.playfair-display-500{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:500}.playfair-display-600{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:600}.playfair-display-700{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:700}.playfair-display-800{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:800}.playfair-display-900{font-optical-sizing:auto;font-family:Playfair Display,serif;font-style:normal;font-weight:900}h1,.text-h1{color:var(--text-primary);letter-spacing:2px;text-shadow:3px 3px 0 var(--accent-coral);font-family:Pirata One,cursive;font-size:max(2.5rem,min(8vw,5rem));line-height:1.2}.text-display{color:var(--text-primary);letter-spacing:2px;text-shadow:3px 3px 0 var(--accent-coral);font-family:Pirata One,cursive;font-size:max(3rem,min(10vw,6rem));line-height:1.1}.hero h1{font-family:var(--font-family-heading);color:var(--text-primary);text-shadow:3px 3px 0 var(--accent-coral);letter-spacing:2px;margin-bottom:1rem;line-height:1.2}h2,.text-h2{color:var(--text-primary);margin-bottom:var(--space-md,1.5rem);font-family:Playfair Display,serif;font-size:max(2rem,min(5vw,3rem));font-weight:700;line-height:1.3}.text-h2.no-underline:after{margin-bottom:var(--space-2xs,.25rem);display:none}h2:after,.text-h2:after{content:"";background:var(--accent-coral);border:3px solid var(--earth-brown);width:100px;height:5px;margin:1rem auto;display:block}h3,.text-h3{color:var(--text-primary);font-family:Playfair Display,serif;font-size:max(1.5rem,min(3vw,2rem));font-weight:600;line-height:1.3}h4,.text-h4{color:var(--text-primary);font-family:Playfair Display,serif;font-size:max(1.25rem,min(2.5vw,1.5rem));font-weight:600;line-height:1.4}h5,.text-h5{color:var(--text-primary);font-family:Inter,sans-serif;font-size:max(1.1rem,min(2vw,1.25rem));font-weight:700;line-height:1.4}h6,.text-h6{color:var(--text-primary);text-transform:uppercase;letter-spacing:.5px;font-family:Inter,sans-serif;font-size:1rem;font-weight:700;line-height:1.4}.text-body-lg{font-size:max(1.1rem,min(1.5vw,1.25rem))!important;line-height:1.7!important}p,.text-body{color:var(--text-primary);padding-bottom:var(--space-xs,.5rem);font-size:max(.95rem,min(1.5vw,1rem));line-height:1.7}p:last-child,.text-body:last-child{margin-bottom:0}.hero p{color:var(--earth-brown);max-width:720px;margin:0 auto;font-size:max(1.1rem,min(2vw,1.25rem))}.card-body p:first-of-type,.card-body .text-body:first-of-type{margin-top:var(--space-md,16px)}.text-body-sm{font-size:max(.85rem,min(1.2vw,.9rem));line-height:1.6}.text-caption{font-size:clamp(var(--space-sm),1vw,.85rem);color:var(--text-muted);line-height:1.5}.text-callout{color:var(--text-primary);margin:var(--space-lg,1.5rem);padding:var(--space-lg,1.5rem);background:var(--earth-sand-light);border-left:var(--border-medium)solid var(--accent-coral);font-size:max(1rem,min(1.5vw,1.1rem));font-weight:600;line-height:1.6}code,.code{font-family:var(--font-family-mono);font-size:max(.85rem,min(1vw,.9rem))}code.code-inline,.code.code-inline{background:var(--earth-sand);border-radius:var(--radius-sm);padding:.1rem .3rem}.code-block{background:var(--earth-sand);border-radius:var(--radius-md);border:var(--border-thin)solid var(--earth-sage);padding:1rem;font-size:max(.85rem,min(1vw,.9rem));display:block;overflow-x:auto}.text-muted{color:var(--text-muted)}.text-secondary{color:var(--text-secondary)}.text-accent{color:var(--accent-coral)}.text-semibold{font-weight:600}.text-bold{font-weight:700}.text-center{text-align:center}.lead,.text-lead{color:var(--text-secondary);font-size:max(1.1rem,min(2vw,1.35rem));line-height:1.7}a,.link{color:var(--earth-sage);border-bottom:1px solid var(--earth-sage);font-weight:var(--font-weight-semibold,600);text-decoration:none;transition:all .2s}a:hover,a:focus,.link:hover,.link:focus{color:var(--earth-brown);border-bottom-color:var(--earth-brown)}.link-brackets{margin-left:var(--space-md)!important}.link-brackets:after{content:"]";color:var(--earth-sage);margin-left:.2rem;transition:all .2s;position:absolute}.link-brackets:before{content:"[";color:var(--earth-sage);margin-left:-.8rem;transition:all .2s;position:absolute}.link-brackets:hover:after,.link-brackets:hover:before,.link-brackets:focus:after,.link-brackets:focus:before{color:var(--accent-coral)}blockquote,.blockquote{border-left:var(--border-thin)solid var(--earth-brown);padding-left:var(--space-md,1rem);margin:var(--space-lg,1.5rem)0;color:var(--text-secondary);font-style:italic}.mb-1{margin-bottom:var(--space-2xs)!important}.mb-2{margin-bottom:var(--space-xs)!important}.mb-3{margin-bottom:var(--space-sm)!important}.mb-4{margin-bottom:var(--space-md)!important}.mb-5{margin-bottom:var(--space-xl)!important}.mt-1{margin-top:var(--space-2xs)!important}.mt-2{margin-top:var(--space-xs)!important}.mt-3{margin-top:var(--space-sm)!important}.mt-4{margin-top:var(--space-md)!important}.mt-5{margin-top:var(--space-xl)!important}.ml-1{margin-left:var(--space-2xs)!important}.ml-2{margin-left:var(--space-xs)!important}.ml-3{margin-left:var(--space-sm)!important}.ml-4{margin-left:var(--space-md)!important}.ml-5{margin-left:var(--space-xl)!important}.mr-1{margin-right:var(--space-2xs)!important}.mr-2{margin-right:var(--space-xs)!important}.mr-3{margin-right:var(--space-sm)!important}.mr-4{margin-right:var(--space-md)!important}.mr-5{margin-right:var(--space-xl)!important}.p-1{padding:var(--space-2xs)!important}.p-2{padding:var(--space-xs)!important}.p-3{padding:var(--space-sm)!important}.p-4{padding:var(--space-md)!important}.p-5{padding:var(--space-xl)!important}.pt-1{padding-top:var(--space-2xs)!important}.pt-2{padding-top:var(--space-xs)!important}.pt-3{padding-top:var(--space-sm)!important}.pt-4{padding-top:var(--space-md)!important}.pt-5{padding-top:var(--space-xl)!important}.pb-1{padding-bottom:var(--space-2xs)!important}.pb-2{padding-bottom:var(--space-xs)!important}.pb-3{padding-bottom:var(--space-sm)!important}.pb-4{padding-bottom:var(--space-md)!important}.pb-5{padding-bottom:var(--space-xl)!important}.pl-1{padding-left:var(--space-2xs)!important}.pl-2{padding-left:var(--space-xs)!important}.pl-3{padding-left:var(--space-sm)!important}.pl-4{padding-left:var(--space-md)!important}.pl-5{padding-left:var(--space-xl)!important}.pr-1{padding-right:var(--space-2xs)!important}.pr-2{padding-right:var(--space-xs)!important}.pr-3{padding-right:var(--space-sm)!important}.pr-4{padding-right:var(--space-md)!important}.pr-5{padding-right:var(--space-xl)!important}section{max-width:1200px;padding:var(--space-3xl,6rem)var(--space-lg,2rem);margin:0 auto}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.row{gap:var(--space-lg,2rem);-ms-flex-wrap:wrap;flex-wrap:wrap;display:-ms-flexbox;display:flex}@media (min-width:768px){.row{gap:var(--space-sm,.5rem)}.card-body .row{gap:0}}.button-row{gap:1rem}.no-wrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.d-flex{display:-ms-flexbox;display:flex}.flex-column{-ms-flex-direction:column;flex-direction:column}.align-items-center{-ms-flex-align:center;align-items:center}.work-grid{gap:var(--space-lg,2rem);margin-bottom:var(--space-lg,2rem);grid-template-columns:repeat(auto-fit,minmax(300px,1fr));display:grid}.divider{width:50%;height:var(--space-md,1.5rem);background:var(--accent-coral);border:var(--border-medium,4px)outset var(--earth-dark);margin:0 auto;display:block}.divider.vertical{width:var(--space-2xs,.25rem);background:var(--earth-dark);border-radius:var(--radius-sm);height:100%;margin:0;border:none!important}ul,ol,.card-body ul,.card-body ol,ul.list,ol.list{margin-left:var(--space-lg)!important;padding-left:var(--space-md)!important}.highlight-block{-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.header-highlight{text-align:center;margin:var(--space-md)auto;padding:var(--space-md);width:100%}nav{z-index:1000;backdrop-filter:blur(24px);filter:url(#lensFilter)saturate(120%)brightness(1.15);border:var(--border-medium,4px)solid var(--earth-brown);padding:var(--space-sm)2rem;box-shadow:0 8px 24px var(--shadow-heavy);background:rgba(245,241,232,.5);border-radius:50px;position:fixed;top:2rem;left:50%;transform:translate(-50%)}.main-nav{width:fit-content;margin:0 auto;position:sticky;top:2rem;left:0;right:0;transform:none!important}nav ul{-ms-flex-pack:center;justify-content:center;gap:2rem;list-style:none;display:-ms-flexbox;display:flex;margin-left:0!important;padding-left:0!important}nav a{color:var(--text-primary);padding:var(--space-2xs)var(--space-xs,.5rem);border-bottom:none;font-size:.95rem;font-weight:500;text-decoration:none;transition:color .3s}nav a:hover,nav a:focus{color:var(--accent-coral);outline:var(--border-thin)solid var(--accent-coral);outline-offset:2px}nav a.active{color:var(--accent-coral)}nav a.sub-page{outline:var(--border-thin)solid var(--text-secondary);outline-offset:2px}nav a.sub-page:hover{outline-color:var(--accent-coral)}@media (max-width:768px){nav{top:var(--space-sm,1rem)!important;padding:var(--space-xs,.5rem)var(--space-sm,1rem)!important;margin:0 auto!important}nav ul{gap:var(--space-sm,1rem)}}footer{background:var(--earth-dark);color:var(--earth-cream);padding:var(--space-2xl,3rem)var(--space-xl,2rem);margin-top:var(--space-3xl,6rem);border-top:var(--border-extra-thick,8px)solid var(--earth-brown);box-shadow:0 -10px 30px var(--shadow)}.footer-content{grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:3rem;max-width:1200px;margin:0 auto;display:grid}.footer-section h3{color:var(--accent-coral);margin-bottom:var(--space-md,1rem);font-family:Playfair Display,serif;font-size:max(1.2rem,min(2vw,1.5rem))}.footer-section h4{margin-bottom:var(--space-md,1rem);font-family:Playfair Display,serif;font-size:max(1.1rem,min(1.25vw,1.125rem));color:rgba(255,255,255,.5)!important}.footer-section p,.footer-section li{color:var(--earth-cream);margin-bottom:var(--space-xs,.5rem);line-height:1.6}.footer-section ul{padding:0;list-style:none}.footer-section li{margin-bottom:var(--space-xs,.5rem)}.footer-bottom{text-align:center;margin-top:var(--space-2xl,3rem);padding-top:var(--space-xl,2rem);border-top:var(--border-medium,4px)solid var(--earth-brown);color:var(--earth-sand)}.footer-bottom p{font-size:var(--font-size-sm);color:var(--earth-cream);margin:0}.footer-section a,.footer-bottom a{color:var(--earth-cream);text-decoration:underline}.footer-section a:hover,.footer-bottom a:hover{color:var(--accent-coral)}.badge{padding:var(--space-2xs,.25rem)var(--space-sm,.75rem);background:var(--earth-sage);color:var(--earth-cream);border:var(--border-thin,2px)solid var(--earth-brown);border-radius:var(--radius-pill);font-size:.85rem;font-weight:600;display:inline-block}.badge-accent{background:var(--accent-coral-dark)}.badge-outline{color:inherit;background:0 0}.badges,.row-badges{gap:var(--space-2xs,.25rem);-ms-flex-wrap:wrap;flex-wrap:wrap;display:-ms-flexbox;display:flex}.btn{padding:var(--space-sm,.75rem)var(--space-lg,1.5rem);font-family:var(--font-family-sans);font-size:var(--font-size-md,1rem);border-radius:var(--radius-md,12px);cursor:pointer;text-align:center;border:none;font-weight:600;text-decoration:none;transition:all .2s;display:inline-block}.btn:hover,.btn:focus{box-shadow:2px 2px 0 var(--earth-brown);transform:translate(2px,2px)}.btn-primary{background:var(--accent-coral-dark);color:var(--white);border:var(--border-medium,4px)solid var(--earth-brown);box-shadow:4px 4px 0 var(--earth-brown)}.btn-primary:hover,.btn-primary:focus{background:var(--accent-coral-dark);color:var(--white)}.btn-secondary{background:var(--earth-cream);color:var(--text-primary);border:var(--border-medium,4px)solid var(--earth-brown);box-shadow:4px 4px 0 var(--earth-sage)}.btn-secondary:hover,.btn-secondary:focus{background:var(--earth-sand);color:var(--text-primary);box-shadow:2px 2px 0 var(--earth-sage);outline:var(--border-thin)solid var(--earth-dark);transform:translate(2px,2px)}.btn-outline{backdrop-filter:blur(24px);filter:url(#lensFilter)saturate(120%)brightness(1.15);color:var(--text-primary)!important;border:var(--border-medium,4px)solid var(--earth-brown)!important;box-shadow:none!important;background:rgba(255,255,255,.5)!important}.btn-outline:hover,.btn-outline:focus{color:var(--earth-cream);text-decoration:underline}.btn-sm{padding:var(--space-xs,.5rem)var(--space-md,1rem)!important;border-width:var(--border-thin)!important;font-size:.9rem!important}.btn-lg{padding:var(--space-md,1rem)var(--space-xl,2rem)!important;font-size:1.1rem!important}.skip-link{background:var(--accent-coral);color:var(--white);padding:var(--space-sm,.75rem)var(--space-lg,1.5rem);border:var(--border-medium,4px)solid var(--earth-brown);z-index:2000;clip:rect(0,0,0,0);font-weight:600;text-decoration:none;position:absolute;top:-100px;left:0;overflow:hidden}.skip-link:focus{clip:auto;top:1rem;left:1rem;overflow:visible}.social-links{-ms-flex-wrap:wrap;flex-wrap:wrap;gap:1rem;display:-ms-flexbox;display:flex}.social-link{padding:var(--space-xs,.5rem)var(--space-md,1rem);background:var(--earth-sage);color:var(--white);border:var(--border-medium,4px)solid var(--earth-sand);border-radius:8px;font-size:.95rem;font-weight:500;transition:all .3s;display:inline-block;text-decoration:none!important}.social-link:hover,.social-link:focus{background:var(--accent-coral);transform:translateY(-2px);color:var(--white)!important}.card{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);padding:var(--space-lg,1.5rem);box-shadow:8px 8px 0 var(--shadow-heavy);transition:transform .3s,box-shadow .3s}.card:hover{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.card:focus-within{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.card-layered{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);padding:var(--space-xl,2rem);box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown)}.card-shadow{background:var(--earth-cream);border-radius:var(--radius-lg,16px);padding:var(--space-md,1.5rem);box-shadow:10px 10px 0 var(--shadow-heavy);border:none}.card-accent{background:var(--earth-cream);border:var(--border-extra-thick,8px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);box-shadow:16px 16px 0 var(--accent-coral),16px 16px 0 6px var(--earth-brown);overflow:hidden}.card-flex{-ms-flex-direction:column;flex-direction:column;display:-ms-flexbox;display:flex}.card-flex p{-ms-flex:1 0;flex:1 0}.card-with-columns .row{-ms-flex-align:start;align-items:flex-start;gap:var(--space-md,1rem);-ms-flex-item-align:stretch;align-self:stretch;display:-ms-flexbox;display:flex}.card-with-columns .column{-ms-flex:1 0 0;flex:1 0 0;-ms-flex-item-align:stretch;align-self:stretch;-ms-flex-align:start;align-items:flex-start;display:-ms-flexbox;display:flex}.card-header{margin-bottom:var(--space-md,1rem);padding-bottom:var(--space-md,1rem);border-bottom:var(--border-thin,2px)solid var(--earth-sand)}.card-body{margin-bottom:var(--space-md)}.card-body img{object-fit:cover;width:100%}@media (min-width:768px){.img-thumbnail{max-width:50%}}.card-body:last-child{margin-bottom:0}.card-footer{margin-top:var(--space-md,1rem);padding-top:var(--space-md,1rem);border-top:var(--border-thin,2px)solid var(--earth-sand)}.showcase-content{padding:var(--space-lg,2rem)}.showcase-content h3{font-family:var(--font-family-serif);color:var(--text-primary);margin-bottom:var(--space-sm,1rem);font-size:max(1.3rem,min(2.5vw,1.8rem))}.showcase-content p{color:var(--text-secondary);margin-bottom:var(--space-md,1.5rem);font-size:max(.95rem,min(1.5vw,1rem))}.showcase-small{background:var(--earth-sand);border:4px solid var(--earth-brown);border-radius:var(--radius-lg,16px);padding:var(--space-md,1.5rem);box-shadow:6px 6px 0 var(--shadow-heavy);transition:transform .3s}.showcase-small:hover{transform:translateY(-4px)}.showcase-small:focus-within{transform:translateY(-4px)}.showcase-small h4{font-family:var(--font-family-serif);color:var(--text-primary);margin-bottom:var(--space-xs,.5rem);font-size:max(1.1rem,min(2vw,1.3rem))}.showcase-small p{color:var(--text-secondary);font-size:max(.9rem,min(1.5vw,.95rem))}.about-card{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);box-shadow:12px 12px 0 var(--earth-sage),12px 12px 0 5px var(--earth-brown);margin:0 auto}@media (max-width:768px){.about-card{box-shadow:6px 6px 0 var(--earth-sage),6px 6px 0 4px var(--earth-brown);padding:var(--space-md,1rem)}.about-grid{grid-template-columns:1fr!important}}.about-card p{color:var(--text-primary);margin-bottom:var(--space-lg,1.5rem);font-size:max(1rem,min(1.5vw,1.1rem));line-height:1.8}.about-card p:last-child{margin-bottom:0}.about-grid{gap:var(--space-xl,2rem);margin-top:var(--space-xl,2rem);grid-template-columns:repeat(auto-fit,minmax(350px,1fr));display:grid}.showcase-large{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--earth-brown);border-radius:var(--radius-xl,20px);box-shadow:12px 12px 0 var(--accent-coral),12px 12px 0 6px var(--earth-brown);transition:transform .3s;overflow:hidden}@media (max-width:768px){.showcase-large{box-shadow:6px 6px 0 var(--accent-coral),6px 6px 0 4px var(--earth-brown)}}.showcase-large:hover{transform:translateY(-8px)}.showcase-large:focus-within{transform:translateY(-8px)}.showcase-image{background:linear-gradient(135deg,var(--earth-sage)0%,var(--earth-sand)100%);width:100%;height:300px;padding:var(--space-md,1rem);font-size:var(--font-size-5xl,3rem);color:var(--earth-cream);border-bottom:var(--border-thick,6px)solid var(--earth-brown);object-fit:contain;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.showcase-image-dark{background:linear-gradient(135deg,var(--black)0%,var(--earth-dark)100%)}.small-showcase-cards{gap:var(--space-md,1.5rem);margin-top:var(--space-sm,1rem);grid-column:1/-1;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));display:grid}.callouts-grid{grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:2rem;margin-top:2rem;display:grid}.callout{background:var(--earth-cream);border:var(--border-thick,6px)solid var(--accent-coral-dark);border-radius:var(--radius-xl,20px);box-shadow:8px 8px 0 var(--shadow-heavy);-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:end;align-items:flex-end;padding:2rem;transition:transform .3s,box-shadow .3s;display:-ms-flexbox;display:flex;position:relative}.callout:hover{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.callout:focus-within{box-shadow:12px 12px 0 var(--shadow-heavy);transform:translateY(-5px)}.callout:before{content:"\"";font-family:var(--font-family-serif);font-size:var(--font-size-6xl,4rem);color:var(--accent-coral);line-height:1;position:absolute;top:10px;left:20px}.callout-text{margin-bottom:var(--space-md,1.5rem);padding-top:var(--space-sm,1rem);color:var(--text-primary);font-style:italic}.callout-author{color:var(--text-primary);font-weight:600;display:block}.callout-role{font-size:var(--font-size-sm,.9rem);color:var(--text-secondary)}.gallery{--size:100px;grid-template-columns:repeat(6,var(--size));grid-auto-rows:var(--size);margin-bottom:var(--size);-ms-flex-align:start;align-items:start;justify-items:center;gap:5px;display:grid}.gallery:has(:hover) picture:not(:hover){filter:brightness(.5)contrast(.5)}.gallery:has(:focus) picture:not(:focus){filter:brightness(.5)contrast(.5)}.gallery picture{object-fit:cover;width:calc(var(--size)*2);height:calc(var(--size)*2);clip-path:path("M90,10 C100,0 100,0 110,10 190,90 190,90 190,90 200,100 200,100 190,110 190,110 110,190 110,190 100,200 100,200 90,190 90,190 10,110 10,110 0,100 0,100 10,90Z");border-radius:5px;grid-column:auto/span 2;transition:clip-path .25s,filter .75s}.gallery picture:nth-child(5n-1){grid-column:2/span 2}.gallery picture:hover,.gallery picture:focus{clip-path:path("M0,0 C0,0 200,0 200,0 200,0 200,100 200,100 200,100 200,200 200,200 200,200 100,200 100,200 100,200 100,200 0,200 0,200 0,100 0,100 0,100 0,100 0,100Z");z-index:1;transition:clip-path .25s,filter .25s}.gallery picture:focus{outline-offset:-5px;outline:1px dashed #000}.carousel>input{clip:rect(1px,1px,1px,1px);clip-path:inset(50%);width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.carousel>input:nth-of-type(15):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1400%}.carousel>input:nth-of-type(14):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1300%}.carousel>input:nth-of-type(13):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1200%}.carousel>input:nth-of-type(12):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1100%}.carousel>input:nth-of-type(11):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-1000%}.carousel>input:nth-of-type(10):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-900%}.carousel>input:nth-of-type(9):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-800%}.carousel>input:nth-of-type(8):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-700%}.carousel>input:nth-of-type(7):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-600%}.carousel>input:nth-of-type(6):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-500%}.carousel>input:nth-of-type(5):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-400%}.carousel>input:nth-of-type(4):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-300%}.carousel>input:nth-of-type(3):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-200%}.carousel>input:nth-of-type(2):checked~.carousel__slides .carousel__slide:first-of-type{margin-left:-100%}.carousel>input:first-of-type:checked~.carousel__slides .carousel__slide:first-of-type{margin-left:0%}.carousel>input:first-of-type:checked~.carousel__thumbnails li:first-of-type,.carousel>input:nth-of-type(2):checked~.carousel__thumbnails li:nth-of-type(2),.carousel>input:nth-of-type(3):checked~.carousel__thumbnails li:nth-of-type(3),.carousel>input:nth-of-type(4):checked~.carousel__thumbnails li:nth-of-type(4),.carousel>input:nth-of-type(5):checked~.carousel__thumbnails li:nth-of-type(5),.carousel>input:nth-of-type(6):checked~.carousel__thumbnails li:nth-of-type(6),.carousel>input:nth-of-type(7):checked~.carousel__thumbnails li:nth-of-type(7),.carousel>input:nth-of-type(8):checked~.carousel__thumbnails li:nth-of-type(8),.carousel>input:nth-of-type(9):checked~.carousel__thumbnails li:nth-of-type(9),.carousel>input:nth-of-type(10):checked~.carousel__thumbnails li:nth-of-type(10),.carousel>input:nth-of-type(11):checked~.carousel__thumbnails li:nth-of-type(11),.carousel>input:nth-of-type(12):checked~.carousel__thumbnails li:nth-of-type(12),.carousel>input:nth-of-type(13):checked~.carousel__thumbnails li:nth-of-type(13),.carousel>input:nth-of-type(14):checked~.carousel__thumbnails li:nth-of-type(14),.carousel>input:nth-of-type(15):checked~.carousel__thumbnails li:nth-of-type(15){box-shadow:0 0 0 5px rgba(0,0,255,.5)}.carousel__slides{z-index:1;white-space:nowrap;box-sizing:border-box;margin:0;padding:0;display:-ms-flexbox;display:flex;position:relative;overflow:hidden}.carousel__slide{vertical-align:top;box-sizing:border-box;white-space:normal;-ms-flex:1 0 100%;flex:1 0 100%;width:100%;height:100%;transition:all .3s ease-out;display:block;position:relative;overflow:hidden}.carousel__slide figure{-ms-flex-direction:column;flex-direction:column;margin:0;display:-ms-flexbox;display:flex}.carousel__slide div{width:100%;position:relative}.carousel__slide div:before{content:"";width:100%;padding-top:66.6667%;display:block}.carousel__slide div>img{width:100%;height:100%;position:absolute;top:0;bottom:0;left:0;right:0}.carousel__slide img{object-fit:cover;-ms-flex:auto;flex:auto;display:block}.carousel__slide figcaption{-ms-flex:none;flex:none;-ms-flex-item-align:center;align-self:center;width:25%;min-width:150px;padding:20px 20px 0}.carousel__slide .credit{color:rgba(0,0,0,.5);margin-top:1rem;display:block}.carousel__slide.scrollable{overflow-y:scroll}.carousel__thumbnails{margin:0 -10px;padding:0;list-style:none;display:-ms-flexbox;display:flex}.carousel__slides+.carousel__thumbnails{margin-top:20px}.carousel__thumbnails li{-ms-flex:auto;flex:auto;max-width:calc(16.6667% - 20px);margin:0 10px;transition:all .3s ease-in-out}.carousel__thumbnails label{display:block;position:relative}.carousel__thumbnails label:before{content:"";width:100%;padding-top:100%;display:block}.carousel__thumbnails label>img{width:100%;height:100%;position:absolute;top:0;bottom:0;left:0;right:0}.carousel__thumbnails label:hover,.carousel__thumbnails label:focus{cursor:pointer}.carousel__thumbnails label:hover img,.carousel__thumbnails label:focus img{transition:all .3s ease-in-out;box-shadow:0 0 0 1px rgba(0,0,0,.25)}.carousel__thumbnails img{object-fit:cover;width:100%;height:100%;display:block} \ No newline at end of file diff --git a/docs/sitemap.xml b/docs/sitemap.xml index a5c92c28..ce58258b 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -171,4 +171,9 @@ 2026-01-19T16:58:02.000Z + + https://www.adamjolicoeur.com/development/timetracker/ + 2026-03-10T18:18:24.000Z + + diff --git a/package-lock.json b/package-lock.json index d603406f..5ab081d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "jolicoeur", - "version": "9.26.0", + "version": "10.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jolicoeur", - "version": "9.26.0", + "version": "10.0.2", "license": "Apache-2.0", "dependencies": { "@11tyrocks/eleventy-plugin-emoji-readtime": "^1.0.1", "@11tyrocks/eleventy-plugin-sass-lightningcss": "^1.3.0", - "bootstrap": "^5.3.8" + "bootstrap": "^5.3.8", + "markdown-it-container": "^4.0.0" }, "devDependencies": { "@11ty/eleventy": "^3.1.2", @@ -717,7 +718,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -741,7 +741,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1840,6 +1839,40 @@ "hint": "^7.0.0" } }, + "node_modules/@hint/parser-babel-config": { + "version": "2.1.43", + "resolved": "https://registry.npmjs.org/@hint/parser-babel-config/-/parser-babel-config-2.1.43.tgz", + "integrity": "sha512-+tioyerTq7Zu54Q6WKsBgmvAee3ACKEpYPkSb23BLeNuRThguN1c9dhoJHnwUXiSZAGpfcqyVMSjjGhXK/rYgA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@hint/utils-fs": "^1.0.16", + "@hint/utils-json": "^1.0.28", + "@hint/utils-network": "^1.0.27", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "hint": "^7.0.0" + } + }, + "node_modules/@hint/parser-css": { + "version": "3.0.39", + "resolved": "https://registry.npmjs.org/@hint/parser-css/-/parser-css-3.0.39.tgz", + "integrity": "sha512-mUwYltAGbCQ7Aoyk0ySaSEdGJeCFioPSeePz1mXYgACzigtlJ6x1Q10ozQYG3WFgXizwpberuGHnJJ/fM6he0Q==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@hint/utils-debug": "^1.0.11", + "@hint/utils-string": "^1.0.14", + "postcss": "^8.4.23", + "postcss-safe-parser": "^6.0.0" + }, + "peerDependencies": { + "hint": "^7.0.0" + } + }, "node_modules/@hint/parser-html": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@hint/parser-html/-/parser-html-3.1.4.tgz", @@ -1854,6 +1887,26 @@ "hint": "^7.0.0" } }, + "node_modules/@hint/parser-javascript": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/@hint/parser-javascript/-/parser-javascript-3.1.25.tgz", + "integrity": "sha512-XKH0urYBPD3PiHBipDtSpGt8qNvgFuPKaXl/YqQK5fehykr/KmFblCs3JpHxa7fG86QIS544OEm5dTm6uspH5A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@hint/utils": "^7.0.24", + "@hint/utils-debug": "^1.0.11", + "@types/estree-jsx": "^0.0.1", + "acorn": "^8.8.2", + "acorn-jsx": "^5.3.2", + "acorn-jsx-walk": "^2.0.0", + "acorn-walk": "^8.2.0" + }, + "peerDependencies": { + "hint": "^7.0.0" + } + }, "node_modules/@hint/parser-jsx": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@hint/parser-jsx/-/parser-jsx-1.1.6.tgz", @@ -1908,6 +1961,23 @@ "hint": "^7.0.0" } }, + "node_modules/@hint/parser-manifest": { + "version": "2.3.20", + "resolved": "https://registry.npmjs.org/@hint/parser-manifest/-/parser-manifest-2.3.20.tgz", + "integrity": "sha512-Wv26kCLlRidoi8D/jJV63o6rznv7r5R8ofNdmhbKRzR7KwSgjoIrQnal3JrCXPmMvIeKf5AkNKWKhWLSKYtk2A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@hint/utils-json": "^1.0.28", + "@hint/utils-network": "^1.0.27", + "@hint/utils-string": "^1.0.14", + "@hint/utils-types": "^1.2.1" + }, + "peerDependencies": { + "hint": "^7.0.0" + } + }, "node_modules/@hint/parser-sass": { "version": "1.0.31", "resolved": "https://registry.npmjs.org/@hint/parser-sass/-/parser-sass-1.0.31.tgz", @@ -1943,6 +2013,38 @@ "hint": "^7.0.0" } }, + "node_modules/@hint/parser-typescript-config": { + "version": "2.4.31", + "resolved": "https://registry.npmjs.org/@hint/parser-typescript-config/-/parser-typescript-config-2.4.31.tgz", + "integrity": "sha512-X5yk6rwCz3mugca0tTI9wNb4dc/Ge/N3h4GH+qjGR5hoBqKvlWmI5/hMBkmaNrIYC2JTp6If9DV3lZxH0d2qGQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@hint/utils-fs": "^1.0.16", + "@hint/utils-json": "^1.0.28", + "@hint/utils-network": "^1.0.27", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "hint": "^7.0.0" + } + }, + "node_modules/@hint/parser-webpack-config": { + "version": "2.1.42", + "resolved": "https://registry.npmjs.org/@hint/parser-webpack-config/-/parser-webpack-config-2.1.42.tgz", + "integrity": "sha512-U4UoICVjkZHbP2vLv0c4IKQ6DZZmldcNd2KX4N0og1dEDVWOsI1Tj7Vsr1RCn8WAyYAKKoGMAb6O0Le48JGoqg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@hint/utils": "^7.0.24", + "@hint/utils-network": "^1.0.27" + }, + "peerDependencies": { + "hint": "^7.0.0" + } + }, "node_modules/@hint/utils": { "version": "7.0.24", "resolved": "https://registry.npmjs.org/@hint/utils/-/utils-7.0.24.tgz", @@ -3330,7 +3432,8 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/markdown-it": { "version": "14.1.1", @@ -3347,7 +3450,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/node": { "version": "20.14.9", @@ -3526,7 +3630,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4137,7 +4240,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -5741,6 +5843,17 @@ "dev": true, "license": "MIT" }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/encoding-sniffer": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", @@ -8770,7 +8883,6 @@ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -8794,6 +8906,12 @@ "markdown-it": "*" } }, + "node_modules/markdown-it-container": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-4.0.0.tgz", + "integrity": "sha512-HaNccxUH0l7BNGYbFbjmGpf5aLHAMTinqRZQAEQbMr2cdD3z91Q6kIo1oUn1CQndkT03jat6ckrdRYuwwqLlQw==", + "license": "MIT" + }, "node_modules/markdown-it-eleventy-img": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/markdown-it-eleventy-img/-/markdown-it-eleventy-img-0.10.2.tgz", @@ -10488,7 +10606,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -11219,7 +11336,6 @@ "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", "dev": true, - "peer": true, "dependencies": { "posthtml-parser": "^0.11.0", "posthtml-render": "^3.0.0" @@ -11291,7 +11407,6 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -12747,7 +12862,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", @@ -13054,7 +13168,6 @@ "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -13392,7 +13505,6 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13611,6 +13723,22 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", diff --git a/package.json b/package.json index 142c2bd5..90aeab3a 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "watch:sass": "sass --no-source-map --watch src/sass:docs/css", "watch:eleventy": "eleventy --serve --port=8081", "build:sass-nomap": "sass --no-source-map src/sass/style.scss docs/css/style.css", - "build:sass-site": "sass src/sass/style.scss docs/css/style.css", + "build:sass-site": "sass src/sass:docs/css", "build:sass": "npm-run-all --parallel build:sass-site", "build:eleventy": "eleventy", "postbuild": "postcss docs/css/*.css -u autoprefixer cssnano -r", @@ -75,6 +75,7 @@ "dependencies": { "@11tyrocks/eleventy-plugin-emoji-readtime": "^1.0.1", "@11tyrocks/eleventy-plugin-sass-lightningcss": "^1.3.0", - "bootstrap": "^5.3.8" + "bootstrap": "^5.3.8", + "markdown-it-container": "^4.0.0" } } diff --git a/src/_includes/markdown.njk b/src/_includes/markdown.njk index f62a50c8..96cfc42b 100644 --- a/src/_includes/markdown.njk +++ b/src/_includes/markdown.njk @@ -4,6 +4,9 @@ layout: base.njk +{% if containers %} + +{% endif %}

{{ title }}

@@ -18,7 +21,7 @@ layout: base.njk {{ content | safe }}
{% else %} -
+ {{ content | safe }} -
+ {% endif %} diff --git a/src/assets/img-raw/TimeTrackerPro-1920x1080.png b/src/assets/img-raw/TimeTrackerPro-1920x1080.png new file mode 100644 index 00000000..2ea85c39 Binary files /dev/null and b/src/assets/img-raw/TimeTrackerPro-1920x1080.png differ diff --git a/src/assets/img-raw/timetracker-generated-summary.png b/src/assets/img-raw/timetracker-generated-summary.png new file mode 100644 index 00000000..032f9506 Binary files /dev/null and b/src/assets/img-raw/timetracker-generated-summary.png differ diff --git a/src/assets/img-raw/timetracker-loading-state.png b/src/assets/img-raw/timetracker-loading-state.png new file mode 100644 index 00000000..d8f9b213 Binary files /dev/null and b/src/assets/img-raw/timetracker-loading-state.png differ diff --git a/src/assets/img-raw/timetracker-start.png b/src/assets/img-raw/timetracker-start.png new file mode 100644 index 00000000..efeb4f96 Binary files /dev/null and b/src/assets/img-raw/timetracker-start.png differ diff --git a/src/assets/img-raw/timetracker-tone-client.png b/src/assets/img-raw/timetracker-tone-client.png new file mode 100644 index 00000000..61e47c01 Binary files /dev/null and b/src/assets/img-raw/timetracker-tone-client.png differ diff --git a/src/assets/img-raw/timetracker-tone-retro.png b/src/assets/img-raw/timetracker-tone-retro.png new file mode 100644 index 00000000..a05a1ec8 Binary files /dev/null and b/src/assets/img-raw/timetracker-tone-retro.png differ diff --git a/src/assets/img-raw/timetracker-tone-standup.png b/src/assets/img-raw/timetracker-tone-standup.png new file mode 100644 index 00000000..78e21582 Binary files /dev/null and b/src/assets/img-raw/timetracker-tone-standup.png differ diff --git a/src/assets/img-raw/timetracker-weekly-report.png b/src/assets/img-raw/timetracker-weekly-report.png new file mode 100644 index 00000000..504212ea Binary files /dev/null and b/src/assets/img-raw/timetracker-weekly-report.png differ diff --git a/src/assets/img/TimeTrackerPro-1920x1080-thumb.jpg b/src/assets/img/TimeTrackerPro-1920x1080-thumb.jpg new file mode 100644 index 00000000..c74fa3b2 Binary files /dev/null and b/src/assets/img/TimeTrackerPro-1920x1080-thumb.jpg differ diff --git a/src/assets/img/TimeTrackerPro-1920x1080-thumb.webp b/src/assets/img/TimeTrackerPro-1920x1080-thumb.webp new file mode 100644 index 00000000..84883e18 Binary files /dev/null and b/src/assets/img/TimeTrackerPro-1920x1080-thumb.webp differ diff --git a/src/assets/img/TimeTrackerPro-1920x1080.jpg b/src/assets/img/TimeTrackerPro-1920x1080.jpg new file mode 100644 index 00000000..3ed45406 Binary files /dev/null and b/src/assets/img/TimeTrackerPro-1920x1080.jpg differ diff --git a/src/assets/img/TimeTrackerPro-1920x1080.webp b/src/assets/img/TimeTrackerPro-1920x1080.webp new file mode 100644 index 00000000..5ae20de5 Binary files /dev/null and b/src/assets/img/TimeTrackerPro-1920x1080.webp differ diff --git a/src/assets/img/timetracker-generated-summary-thumb.jpg b/src/assets/img/timetracker-generated-summary-thumb.jpg new file mode 100644 index 00000000..c67a4fc9 Binary files /dev/null and b/src/assets/img/timetracker-generated-summary-thumb.jpg differ diff --git a/src/assets/img/timetracker-generated-summary-thumb.webp b/src/assets/img/timetracker-generated-summary-thumb.webp new file mode 100644 index 00000000..de559568 Binary files /dev/null and b/src/assets/img/timetracker-generated-summary-thumb.webp differ diff --git a/src/assets/img/timetracker-generated-summary.jpg b/src/assets/img/timetracker-generated-summary.jpg new file mode 100644 index 00000000..bb058161 Binary files /dev/null and b/src/assets/img/timetracker-generated-summary.jpg differ diff --git a/src/assets/img/timetracker-generated-summary.webp b/src/assets/img/timetracker-generated-summary.webp new file mode 100644 index 00000000..e795062d Binary files /dev/null and b/src/assets/img/timetracker-generated-summary.webp differ diff --git a/src/assets/img/timetracker-loading-state-thumb.jpg b/src/assets/img/timetracker-loading-state-thumb.jpg new file mode 100644 index 00000000..fb56fe83 Binary files /dev/null and b/src/assets/img/timetracker-loading-state-thumb.jpg differ diff --git a/src/assets/img/timetracker-loading-state-thumb.webp b/src/assets/img/timetracker-loading-state-thumb.webp new file mode 100644 index 00000000..3256b1a1 Binary files /dev/null and b/src/assets/img/timetracker-loading-state-thumb.webp differ diff --git a/src/assets/img/timetracker-loading-state.jpg b/src/assets/img/timetracker-loading-state.jpg new file mode 100644 index 00000000..2588ada7 Binary files /dev/null and b/src/assets/img/timetracker-loading-state.jpg differ diff --git a/src/assets/img/timetracker-loading-state.webp b/src/assets/img/timetracker-loading-state.webp new file mode 100644 index 00000000..39acde92 Binary files /dev/null and b/src/assets/img/timetracker-loading-state.webp differ diff --git a/src/assets/img/timetracker-start-thumb.jpg b/src/assets/img/timetracker-start-thumb.jpg new file mode 100644 index 00000000..335d082c Binary files /dev/null and b/src/assets/img/timetracker-start-thumb.jpg differ diff --git a/src/assets/img/timetracker-start-thumb.webp b/src/assets/img/timetracker-start-thumb.webp new file mode 100644 index 00000000..8a586af6 Binary files /dev/null and b/src/assets/img/timetracker-start-thumb.webp differ diff --git a/src/assets/img/timetracker-start.jpg b/src/assets/img/timetracker-start.jpg new file mode 100644 index 00000000..e9f97957 Binary files /dev/null and b/src/assets/img/timetracker-start.jpg differ diff --git a/src/assets/img/timetracker-start.webp b/src/assets/img/timetracker-start.webp new file mode 100644 index 00000000..e202abf5 Binary files /dev/null and b/src/assets/img/timetracker-start.webp differ diff --git a/src/assets/img/timetracker-tone-client-thumb.jpg b/src/assets/img/timetracker-tone-client-thumb.jpg new file mode 100644 index 00000000..69a8d93d Binary files /dev/null and b/src/assets/img/timetracker-tone-client-thumb.jpg differ diff --git a/src/assets/img/timetracker-tone-client-thumb.webp b/src/assets/img/timetracker-tone-client-thumb.webp new file mode 100644 index 00000000..6e0c440c Binary files /dev/null and b/src/assets/img/timetracker-tone-client-thumb.webp differ diff --git a/src/assets/img/timetracker-tone-client.jpg b/src/assets/img/timetracker-tone-client.jpg new file mode 100644 index 00000000..8f7990ff Binary files /dev/null and b/src/assets/img/timetracker-tone-client.jpg differ diff --git a/src/assets/img/timetracker-tone-client.webp b/src/assets/img/timetracker-tone-client.webp new file mode 100644 index 00000000..38cb9f7d Binary files /dev/null and b/src/assets/img/timetracker-tone-client.webp differ diff --git a/src/assets/img/timetracker-tone-retro-thumb.jpg b/src/assets/img/timetracker-tone-retro-thumb.jpg new file mode 100644 index 00000000..4c70ffa6 Binary files /dev/null and b/src/assets/img/timetracker-tone-retro-thumb.jpg differ diff --git a/src/assets/img/timetracker-tone-retro-thumb.webp b/src/assets/img/timetracker-tone-retro-thumb.webp new file mode 100644 index 00000000..3bb0cd6e Binary files /dev/null and b/src/assets/img/timetracker-tone-retro-thumb.webp differ diff --git a/src/assets/img/timetracker-tone-retro.jpg b/src/assets/img/timetracker-tone-retro.jpg new file mode 100644 index 00000000..cb3c1e1f Binary files /dev/null and b/src/assets/img/timetracker-tone-retro.jpg differ diff --git a/src/assets/img/timetracker-tone-retro.webp b/src/assets/img/timetracker-tone-retro.webp new file mode 100644 index 00000000..9b337819 Binary files /dev/null and b/src/assets/img/timetracker-tone-retro.webp differ diff --git a/src/assets/img/timetracker-tone-standup-thumb.jpg b/src/assets/img/timetracker-tone-standup-thumb.jpg new file mode 100644 index 00000000..9c03031b Binary files /dev/null and b/src/assets/img/timetracker-tone-standup-thumb.jpg differ diff --git a/src/assets/img/timetracker-tone-standup-thumb.webp b/src/assets/img/timetracker-tone-standup-thumb.webp new file mode 100644 index 00000000..2b48a416 Binary files /dev/null and b/src/assets/img/timetracker-tone-standup-thumb.webp differ diff --git a/src/assets/img/timetracker-tone-standup.jpg b/src/assets/img/timetracker-tone-standup.jpg new file mode 100644 index 00000000..77c61279 Binary files /dev/null and b/src/assets/img/timetracker-tone-standup.jpg differ diff --git a/src/assets/img/timetracker-tone-standup.webp b/src/assets/img/timetracker-tone-standup.webp new file mode 100644 index 00000000..fb1e793b Binary files /dev/null and b/src/assets/img/timetracker-tone-standup.webp differ diff --git a/src/assets/img/timetracker-weekly-report-thumb.jpg b/src/assets/img/timetracker-weekly-report-thumb.jpg new file mode 100644 index 00000000..833ea0ae Binary files /dev/null and b/src/assets/img/timetracker-weekly-report-thumb.jpg differ diff --git a/src/assets/img/timetracker-weekly-report-thumb.webp b/src/assets/img/timetracker-weekly-report-thumb.webp new file mode 100644 index 00000000..92a6cc97 Binary files /dev/null and b/src/assets/img/timetracker-weekly-report-thumb.webp differ diff --git a/src/assets/img/timetracker-weekly-report.jpg b/src/assets/img/timetracker-weekly-report.jpg new file mode 100644 index 00000000..acd0b966 Binary files /dev/null and b/src/assets/img/timetracker-weekly-report.jpg differ diff --git a/src/assets/img/timetracker-weekly-report.webp b/src/assets/img/timetracker-weekly-report.webp new file mode 100644 index 00000000..03230f5d Binary files /dev/null and b/src/assets/img/timetracker-weekly-report.webp differ diff --git a/src/pages/development/timetracker.md b/src/pages/development/timetracker.md new file mode 100644 index 00000000..fa47f404 --- /dev/null +++ b/src/pages/development/timetracker.md @@ -0,0 +1,253 @@ +--- +layout: markdown.njk +title: 'Weekly Report: AI-Powered Work Summary' +date: git Last Modified +abbreviation: 'worksummary' +description: 'Start the day, capture tasks, review, and archive - then summarize using AI' +eleventyNavigation: + key: Development + parent: Development + order: 2 +containers: true +--- + +:::section + +## Project Overview + + :::card + + **ROLE**: Lead Product Designer & Product Manager + + **TYPE**: Feature extension - personal productivity tool + + **STACK**: React, TypeScript, Tailwind CSS, Google Gemini API + + **STATUS**: Shipped - in daily use + +::: + +::::section + +## About TimeTracker Pro + + TimeTracker Pro is a Progressive Web App (PWA) I designed, built, and use every day to track how I spend my work hours. It runs in the browser, installs as a native-like application on desktop and mobile, and stores data locally by default - no account required. Through the day I create tasks, assign them to projects and categories, and archive each completed day. Over time, it builds a personal record of where my time actually goes. + + I built it because every time tracking tool that I tried was either too complex for my personal use, or too simple to be useful. TimeTracker Pro is purpose-built for the way I work: start the day, capture tasks as they happen, and review and archive at the end. It has been in daily use since early 2025 and has grown into a small, but complete, product - export formats, project management, offline support, and invoicing. The Weekly Report feature is the most recent addition, and the one that most clearly shows how the product has evolved from a personal utility into a considered system. + +
+
+ Start screen for TimeTracker Pro +
+
+:::: + +::::section +## The Weekly Report Feature + + :::card + After archiving each week, I found myself running a second, separate tool to generate a weekly summary. That tool only worked with PDFs directly exported from the time tracker, only ran on a local development server, and product output that always needed manual cleanup before it was shareable. It was a workaround, not a product. + + The Weekly Report feature replaces that entire workflow. It lives inside TimeTracker Pro as a dedicated route, directly reading the same data the rest of the app uses, and generates a coherent weekly narrative using an AI model (Gemini). The output can be tuned for different audiences - a team's standup, a client update, or a personal retrospective - and is editable before copying to a separate document. No export step, no separate server, no manual cleanup. + ::: + +
+
+
+ Weekly Report Screen +
review the time period to summarize and select a tone before generation
+
+
+
+ + > The right tool for summarizing my work week is the tool that already knows my work week. +:::: + +::::section +## The Problem + + :::card + The original two-tool setup had three specific friction points: + + 1. No real integration + 2. Availability + 3. Output always requiring editing + + - The generator only accepted PDFs from the time tracker, creating a dependency without any actual data sharing. The export was the only bridge between them. + + - The generator ran on a local Vite server, which meant it was only accessible from my machine and only in a single context. Any time I needed a summary on a different device, I was out of luck. + + - Because the generator had no understanding of who I was writing for, every summary came out generic and required manual work to make it usable. The generator sounded too similar from week-to-week, diminishing the quality of the reports. + ::: + +> The deeper problem was that the tooling made a simple, recurring task feel like a project in itself. I needed a paragraph that I could drop into a standup or send to a client. _What I had was a process_. +:::: + +::::section +## Extend, Not Replace + + :::card + The obvious move might have been to build a better standalone summary tool, but I chose not to - and the reasoning matters. + + A standalone tool would still need an export step, a file upload, or an API connection to access my time data. It would have to be general enough to work with any input, which means losing all the context that makes a summary actually useful - what categories mean, which projects are billable, and what a typical week looks like - specifically for me. + + Extending TimeTracker Pro meant the summary feature could read directly from the same local data store the rest of the app uses. No synchronization problem. No format negotiation. The data is already structured exactly the way the feature needs it to be - tasks with descriptions, projects, categories, and duration - grouped by day. + + It also meant the feature could be opinionated in ways that a generic tool cannot. It knows to exclude break-time and lunch categories automatically. It understands the project and client structure. It has enough context to group a week of task descriptions into a meaningful narrative rather than a list. +:::: + +::::section +## Design Decisions + + > The goal was to make the AI feel like a step in a workflow, not a magic trick. + + ### Two-panel Layout + + At wider view-ports, and the report page uses a two-column layout: controls on the left, output on the right. This came from recognizing that the interaction has two distinct modes - configuring the request and reviewing the result - and that collapsing them into a single scrolling column would blur that separation. + + The left column handles week navigation, the data breakdown, and tone selection. it is the setup side. The right column is purely reactive - it shows whatever state the output is in: **idle**, **generating**, **error**, or a **draft summary ready** to edit and copy. Nothing in the right column requires user input; it only responds to decisions made on the left. + + This separation also meant each column could be designed for its specific job. The left column is dense and interactive. The right column has more breathing room because reading and editing require it. + +
+
+
+
+ Report generation preview +
select what to include in the report and the desired tone
+
+
+
+
+
+
+ Client Summary +
the report summary, ready to copy into any document
+
+
+
+
+ + ### The generation flow as a design experience + + The most deliberate UX decision was treating the AI generation as a visible, legible transition rather than a black-box button press. When generation is in progress, the right panel names the week being summarized and shows staggered skeleton lines that suggest an output is forthcoming. + + The idle state - before anything has been generated - uses a dashed border container with a short explanation of what will appear there. This keeps the two-column layout from reading as broken or incomplete on first load, and gives the right panel a purpose even before it has content. + + Error states are structured and recoverable: a header that names the failure, a plain-language description, and a "Try again" action inline. The error is informative without being alarming. + +
+
+
+ Report generation preview +
feedback showing the generation of the report
+
+
+
+ +:::: + +::::section + ## Tone as a product decision + + The tone selector - **Standup**, **Client**, **Retrospective** - reflects a real choice I make every week about who I'm writing for. These are not cosmetic variations. Each tone maps to a different set of system prompt instructions sent to the model, producing meaningfully different outputs. + +
+
+
Standup
+
+
+ Standup Summary +
terse, first-person, and focused on what moved and what is in progress
+
+
+
+
+
Client
+
+
+ Client Summary +
outcome-oriented, professional, and suitable for sharing progress on deliverables
+
+
+
+
+
Retrospective
+
+
+ Retrospective Summary +
more reflective, noting themes and shift across the week rather than just outputs
+
+
+
+
+ + > Having tone as an explicit control also solves a subtle UX problem: when you change the tone, the existing summary resets so you never mistake a standup summary for a client-ready output. The control communicates its own consequences. + + ### Editable output by default + + :::card-shadow + The generated summary appears in an editable text area, rather than a read-only display. This frames the AI's role correctly: it drafts, the human approves. The copy button and a brief 'changes are not saved' note completes the mental model - this is a staging area, not a final product. + + A "regenerate" button sites alongside the copy button, so it is easy to get a different draft without scrolling back to the controls. The two actions - regenerate and copy - represent the two things a person actually wants to do with a draft: try again or take it. + ::: + +
+ + ### AI prompt architecture + + :::card-shadow + The prompt that drives the summary is split into two parts. The system instruction establishes the persona, length constraints (3 to 5 sentences), voice (first-person, no filler phrases), and the specific tone instructions for whichever mode is selected. The user message contains the serialized week data - a lean, human-readable representation of each workday with task titles, descriptions, project names, and durations. + + Before sending, the serialization step strips timestamps, IDs, and non-work categories. What reaches the model is only what a human would include if they were writing the summary prompt by hand. This matters because model output quality is directly proportional to input clarity - sending structured noise produces structured noise back. + + The prompt architecture is designed to evolve. As I use the feature and notice patterns in what I edit or regenerate, the system instructions cane be turned to match how I actually write and what different audiences respond to. The tone categories themselves may expand - a spring summary or executive update tone would be natural additions as the use cases grow. + ::: +:::: + +
+ +::::section + :::card + ### Outcome + + Every week I use the standup tone on Monday morning to orient myself before the week's work begins, with the retrospective tone on Friday to close out the week. Before this feature existed, I skipped that ritual more often than not due to the fact that the tooling made it feel like work. *Now it takes less than a minute*. The summary is available wherever TimeTracker Pro is available, and the tone control means the output is usually usable with one or two edits rather than a full rewrite. + + From a portfolio standpoint the project demonstrates a specific combination of skills: identifying friction in a real workflow, making a considered architectural decision about where a feature belongs, designing the interactions states that make AI output feel trustworthy, and shipping something that has been in daily use since it launched. +:::: + +::::section +
+ Previous Case Study + Next Case Study +
+:::: diff --git a/src/sass/_typography.scss b/src/sass/_typography.scss index 672e4828..f8b08878 100644 --- a/src/sass/_typography.scss +++ b/src/sass/_typography.scss @@ -1,5 +1,6 @@ /* Heading 1 */ -h1, .text-h1 { +h1, +.text-h1 { font-family: 'Pirata One', cursive; font-size: clamp(2.5rem, 8vw, 5rem); color: var(--text-primary); @@ -19,7 +20,7 @@ h1, .text-h1 { .hero h1 { font-family: var(--font-family-heading); - font-size: 6rem; + // font-size: 6rem; color: var(--text-primary); margin-bottom: 1rem; text-shadow: 3px 3px 0 var(--accent-coral); @@ -28,7 +29,8 @@ h1, .text-h1 { } /* Heading 2 */ -h2, .text-h2 { +h2, +.text-h2 { font-family: 'Playfair Display', serif; font-size: clamp(2rem, 5vw, 3rem); color: var(--text-primary); @@ -40,7 +42,8 @@ h2, .text-h2 { display: none; margin-bottom: var(--space-2xs, 0.25rem); } -h2::after, .text-h2::after { +h2::after, +.text-h2::after { content: ''; display: block; width: 100px; @@ -51,7 +54,8 @@ h2::after, .text-h2::after { } /* Heading 3 */ -h3, .text-h3 { +h3, +.text-h3 { font-family: 'Playfair Display', serif; font-size: clamp(1.5rem, 3vw, 2rem); color: var(--text-primary); @@ -60,7 +64,8 @@ h3, .text-h3 { } /* Heading 4 */ -h4, .text-h4 { +h4, +.text-h4 { font-family: 'Playfair Display', serif; font-size: clamp(1.25rem, 2.5vw, 1.5rem); color: var(--text-primary); @@ -69,7 +74,8 @@ h4, .text-h4 { } /* Heading 5 */ -h5, .text-h5 { +h5, +.text-h5 { font-family: Inter, sans-serif; font-size: clamp(1.1rem, 2vw, 1.25rem); color: var(--text-primary); @@ -78,7 +84,8 @@ h5, .text-h5 { } /* Heading 6 */ -h6, .text-h6 { +h6, +.text-h6 { font-family: Inter, sans-serif; font-size: 1rem; color: var(--text-primary); @@ -94,23 +101,26 @@ h6, .text-h6 { line-height: 1.7 !important; } -p, .text-body { +p, +.text-body { font-size: clamp(0.95rem, 1.5vw, 1rem); line-height: 1.7; color: var(--text-primary); padding-bottom: var(--space-xs, 0.5rem); } -p:last-child, .text-body:last-child { +p:last-child, +.text-body:last-child { margin-bottom: 0; } .hero p { - font-size: clamp(1.1rem, 2vw, 1.25rem);; + font-size: clamp(1.1rem, 2vw, 1.25rem); color: var(--earth-brown); max-width: 720px; margin: 0 auto; } -.card-body p:first-of-type, .card-body .text-body:first-of-type { +.card-body p:first-of-type, +.card-body .text-body:first-of-type { margin-top: var(--space-md, 16px); } @@ -136,7 +146,8 @@ p:last-child, .text-body:last-child { border-left: var(--border-medium) solid var(--accent-coral); } -code, .code { +code, +.code { font-family: var(--font-family-mono); font-size: clamp(0.85rem, 1vw, 0.9rem); } @@ -182,21 +193,26 @@ code.code-inline, } /* Lead paragraph */ -.lead, .text-lead { +.lead, +.text-lead { font-size: clamp(1.1rem, 2vw, 1.35rem); line-height: 1.7; color: var(--text-secondary); } /* Links */ -a, .link { +a, +.link { color: var(--earth-sage); border-bottom: 1px solid var(--earth-sage); text-decoration: none; transition: all 0.2s; font-weight: var(--font-weight-semibold, 600); } -a:hover, a:focus, .link:hover, .link:focus { +a:hover, +a:focus, +.link:hover, +.link:focus { color: var(--earth-brown); border-bottom-color: var(--earth-brown); } @@ -216,14 +232,17 @@ a:hover, a:focus, .link:hover, .link:focus { color: var(--earth-sage); transition: all 0.2s; } - &:hover::after, &:hover::before, - &:focus::after, &:focus::before { + &:hover::after, + &:hover::before, + &:focus::after, + &:focus::before { color: var(--accent-coral); } } /* Blockquote */ -blockquote, .blockquote { +blockquote, +.blockquote { border-left: var(--border-thin) solid var(--earth-brown); padding-left: var(--space-md, 1rem); margin: var(--space-lg, 1.5rem) 0; diff --git a/src/sass/containers.scss b/src/sass/containers.scss new file mode 100644 index 00000000..2f138a23 --- /dev/null +++ b/src/sass/containers.scss @@ -0,0 +1,84 @@ +/* Markdown container blocks — loaded only on pages with containers: true */ + +/* Grid row for adjacent card blocks */ +.cards-row { + display: flex; + flex-wrap: wrap; + flex-direction: row; + gap: var(--space-lg, 1.5rem); +} + +/* Semantic prose section with spacing */ +// .prose-section { +// max-width: 1200px; +// margin: 0 auto; +// padding: var(--space-3xl, 6rem) var(--space-lg, 2rem); + +// & + .prose-section { +// border-top: var(--border-thin, 2px) solid var(--earth-sand); +// } +// } +.prose-section:nth-child(2) { + margin-top: 0; +} + +/* Card container in prose context — extends base .card with spacing for markdown content */ +.prose-section .card, +section .card { + margin-bottom: var(--space-lg, 1.5rem); +} + +/* Ensure headings inside cards have correct spacing */ +.card h2, +.card h3, +.card h4 { + margin-top: 0; + margin-bottom: var(--space-sm, 0.75rem); +} +.card > h3 { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-sand); +} + +.card p:last-child, +.card ul:last-child, +.card ol:last-child { + margin-bottom: 0; +} +.prose-section .card-shadow { + background: var(--earth-cream); + border: none; + border-radius: var(--radius-lg, 16px); + padding: var(--space-md, 1.5rem); + box-shadow: 10px 10px 0 var(--shadow-heavy); +} +.prose-section .card-shadow > h3 { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-brown); +} +.prose-section .card-basic { + background: var(--earth-sand); + border: 4px solid var(--earth-brown); + border-radius: var(--radius-lg, 16px); + padding: var(--space-md, 1.5rem); + box-shadow: 6px 6px 0 var(--shadow-heavy); + transition: transform 0.3s; +} +.prose-section .card-basic > h3 { + margin-bottom: var(--space-md, 1rem); + padding-bottom: var(--space-md, 1rem); + border-bottom: var(--border-thin, 2px) solid var(--earth-brown); +} + +blockquote { + font-size: clamp(1rem, 1.5vw, 1.1rem); + line-height: 1.6; + font-weight: 600; + color: var(--text-primary); + margin: var(--space-lg, 1.5rem); + padding: var(--space-lg, 1.5rem); + background: var(--earth-sand-light); + border-left: var(--border-medium) solid var(--accent-coral); +} diff --git a/src/sass/markdown.scss b/src/sass/markdown.scss index e0432c01..f4c8f6d7 100644 --- a/src/sass/markdown.scss +++ b/src/sass/markdown.scss @@ -14,3 +14,8 @@ section ul, section ol { margin-bottom: var(--space-md, 1rem) !important; } +.card > h2 { + &::after { + display: none; + } +} diff --git a/src/sass/style.scss b/src/sass/style.scss index 6494317a..823f29f9 100644 --- a/src/sass/style.scss +++ b/src/sass/style.scss @@ -176,5 +176,6 @@ figcaption { @import 'buttons'; @import 'cards'; @import 'gallery'; +// @import 'containers'; /* stylint-enable */