diff --git a/public/css/workflow.css b/public/css/workflow.css index 55da43f0f..cbdf3c5cf 100644 --- a/public/css/workflow.css +++ b/public/css/workflow.css @@ -1247,12 +1247,10 @@ font-size: 1.125rem; font-weight: 500; color: var(--color-ink); - padding: var(--spacing-md) 0; + padding: var(--spacing-md) calc(var(--spacing-md) + 1.5rem) var(--spacing-md) 0; cursor: pointer; list-style: none; - display: flex; - align-items: center; - justify-content: space-between; + position: relative; transition: color 0.2s ease; } @@ -1267,10 +1265,14 @@ font-weight: 300; color: var(--color-accent); transition: transform 0.3s var(--ease-out); + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); } .faq-item[open] .faq-question::after { - transform: rotate(45deg); + transform: translateY(-50%) rotate(45deg); } .faq-question:hover { diff --git a/scripts/lib/utils.js b/scripts/lib/utils.js index 9f1c1d764..9c060894a 100644 --- a/scripts/lib/utils.js +++ b/scripts/lib/utils.js @@ -226,7 +226,102 @@ export function writeFile(filePath, content) { * * Returns { patterns: [...], antipatterns: [...] } */ -export function readPatterns(rootDir, relativePath = 'source/skills/impeccable/SKILL.md') { +// Curated short-list for the homepage Antidote section. Intentionally +// hand-written (not auto-extracted) so the copy stays tight and +// editorial. The long-form catalog lives on /anti-patterns — this is +// the teaser. +const CURATED_CATEGORIES = [ + { + name: 'Typography', + do: [ + 'Pair a distinctive display face with a restrained body face; vary across projects.', + 'Use a ≥1.25 scale ratio between hierarchy steps. Flat scales read as bland.', + 'Cap body line length at 65–75ch. Wider is fatiguing.', + ], + dont: [ + 'Inter, Roboto, Plex, Fraunces, or any other reflex default. Look further.', + 'Monospace as lazy shorthand for "technical."', + 'Long passages in uppercase. Reserve all-caps for short labels.', + ], + }, + { + name: 'Color & Contrast', + do: [ + 'Use OKLCH. Reduce chroma near lightness extremes.', + 'Tint neutrals toward the brand hue. Chroma 0.005–0.01 is enough.', + 'Pick a color strategy before picking colors (Restrained, Committed, Full, Drenched).', + ], + dont: [ + 'Pure #000 or #fff. Always tint.', + 'Dark mode + purple-to-cyan gradients. The AI tell.', + 'Gradient text via background-clip. Use weight or size for emphasis.', + ], + }, + { + name: 'Layout & Space', + do: [ + 'Vary spacing for rhythm. Tight groupings, generous separations.', + 'Use the simplest tool: Flexbox for 1D, Grid for 2D, plain flow often enough.', + 'Let whitespace carry hierarchy before reaching for color or scale.', + ], + dont: [ + 'Wrap everything in cards. Nested cards are always wrong.', + 'Identical card grids of icon + heading + text, repeated endlessly.', + 'The hero-metric template: big number, small label, supporting stats, gradient accent.', + ], + }, + { + name: 'Visual Details', + do: [ + 'Commit to an aesthetic direction and execute it with precision.', + 'Use ornament only where it earns its place.', + ], + dont: [ + 'Side-stripe borders (border-left/-right > 1px). The dashboard tell.', + 'Glassmorphism everywhere. Rare and purposeful or nothing.', + 'Rounded rectangles with generic drop shadows. "Could be any AI output."', + ], + }, + { + name: 'Motion', + do: [ + 'Use transform and opacity. Animate the composited properties only.', + 'Ease out with exponential curves (quart / quint / expo).', + 'Respect prefers-reduced-motion on every transition.', + ], + dont: [ + 'Animate layout (width, height, padding, margin).', + 'Bounce or elastic easing. Feels dated and tacky.', + 'Decorative motion for its own sake. Motion should signal state.', + ], + }, + { + name: 'Interaction', + do: [ + 'Use optimistic UI: update immediately, sync later.', + 'Design empty states that teach the interface, not just say "nothing here."', + 'Progressive disclosure: start simple, reveal sophistication on demand.', + ], + dont: [ + 'Make every button primary. Hierarchy matters.', + 'Default to a modal. Exhaust inline alternatives first.', + 'Repeat information the user can already see.', + ], + }, +]; + +export function readPatterns(_rootDir, _relativePath) { + // Hand-curated list — see CURATED_CATEGORIES above. The homepage + // Antidote teaser uses this; the full catalog lives on /anti-patterns. + return { + patterns: CURATED_CATEGORIES.map((c) => ({ name: c.name, items: c.do })), + antipatterns: CURATED_CATEGORIES.map((c) => ({ name: c.name, items: c.dont })), + }; +} + +// Previous SKILL.md parser retained below but disabled; kept as a +// reference for how prefix-style extraction used to work. +function _legacyReadPatterns(rootDir, relativePath = 'source/skills/impeccable/SKILL.md') { const skillPath = path.join(rootDir, relativePath); if (!fs.existsSync(skillPath)) {