skills/frontend-styler/SKILL.md
--- name: frontend-styler description: Frontend styling: layout debugging, style consistency, CSS best practices for Svelte/SvelteKit. user-invocable: false effort: medium paths: - "**/*.svelte" - "**/*.css" allowed-tools: - Read - Glob - Grep --- # Frontend Styling Comprehensive guidance for debugging layout issues, ensuring style consistency, and applying best practices in frontend development, with emphasis on Svelte/SvelteKit projects. --- ## When This Skill Applies Use this s
npx skillsauth add jasonwarrenuk/goblin-mode skills/frontend-stylerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive guidance for debugging layout issues, ensuring style consistency, and applying best practices in frontend development, with emphasis on Svelte/SvelteKit projects.
Use this skill when:
Accessibility is not a polish step — it's a structural requirement. Every styling decision should pass the accessibility check before considering aesthetics.
Non-negotiable:
prefers-reduced-motion/* Always include focus styles */
:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
/* Respect motion preferences */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
/* Never rely on colour alone */
.error-field {
border-color: var(--color-error);
border-width: 2px; /* Visual indicator beyond colour */
}
.error-message {
color: var(--color-error);
}
.error-message::before {
content: "⚠ "; /* Icon reinforces the colour */
}
For non-trivial styling changes:
When fixing multiple issues:
Svelte's <style> blocks are scoped by default - leverage this:
<style>
/* Scoped automatically - no class name collisions */
.button {
padding: 0.5rem 1rem;
border-radius: 0.25rem;
}
.button--primary {
background: var(--color-primary);
}
</style>
Use :global() sparingly and intentionally:
<style>
/* Only when deliberately styling external elements */
:global(.markdown-content h1) {
margin-top: 2rem;
}
</style>
Prefer CSS variables for theming and consistency:
<style>
.card {
background: var(--card-bg, #fff);
border: 1px solid var(--card-border, #e5e7eb);
border-radius: var(--radius-md, 0.5rem);
}
</style>
Use Svelte's class directive for dynamic styling:
<button
class="btn"
class:btn--active={isActive}
class:btn--disabled={disabled}
>
Click me
</button>
Common layout issues and their causes:
Alignment Problems:
display property (flex/grid/block)align-items, justify-content, align-selfposition: absolute breaking flowSpacing Issues:
box-sizing mismatchesResponsive Breakage:
min-width vs max-width logicZ-Index Conflicts:
position property (relative/absolute/fixed)z-index valuesAsk: "Should this be fixed in the component or its parent?"
Fix in Component When:
Fix in Parent When:
Check for:
<style> vs external CSSCompare component styling against project patterns:
✗ Inconsistent: <div class="cardContainer">
✓ Consistent: <div class="card-container">
✗ Inconsistent: padding: 8px;
✓ Consistent: padding: 0.5rem;
✗ Inconsistent: background: #3B82F6;
✓ Consistent: background: var(--color-primary); /* → --color-azure-3 */
List specific changes needed to match project patterns:
<style> block"Apply changes in logical order:
kebab-case (e.g., card-header, btn-primary)PascalCase.svelte (e.g., UserCard.svelte)btn--primary, card--elevated)rem for spacing (0.25rem, 0.5rem, 1rem, 1.5rem, 2rem)em for typography-relative spacing--color-primary, not --blue-500)npm install reasonable-colors or CDN unpkg.com/[email protected]/reasonable-colors.css):root; components only reference semantic vars::root {
/* Map Reasonable Colors → semantic roles */
--color-primary: var(--color-azure-3);
--color-primary-bg: var(--color-azure-1);
--color-on-primary: var(--color-azure-6);
--color-danger: var(--color-red-3);
--color-danger-bg: var(--color-red-1);
--color-surface: var(--color-gray-1);
--color-on-surface: var(--color-gray-6);
}
sm: 640pxmd: 768pxlg: 1024pxxl: 1280px/* Center content */
.container {
display: flex;
align-items: center;
justify-content: center;
}
/* Responsive row to column */
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
/* Responsive grid */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
}
<script>
// Logic
</script>
<div class="component">
<!-- Template -->
</div>
<style>
.component {
/* Styles scoped to component */
}
</style>
<!-- ✗ Bad: Mixing inline styles with classes -->
<div class="card" style="margin: 10px;">
/* ✗ Bad: Deep nesting */
.container .wrapper .card .header .title {
font-size: 1.5rem;
}
/* ✓ Good: Flat structure */
.card-title {
font-size: 1.5rem;
}
!important Without Cause/* ✗ Bad: Using important as a crutch */
.button {
color: red !important;
}
/* ✓ Good: Increase specificity properly */
.card .button {
color: red;
}
/* ✗ Bad: Repeated magic numbers */
.card { padding: 16px; }
.modal { padding: 16px; }
.panel { padding: 16px; }
/* ✓ Good: Use variables */
:root {
--spacing-md: 1rem;
}
.card, .modal, .panel {
padding: var(--spacing-md);
}
When building or reviewing UI components:
aria-hidden) or labelled (alt/aria-label)?<label> elements?aria-describedby?prefers-reduced-motion disable animations?When encountering styling issues, verify:
box-sizing: border-box set globally?<style> block scoped correctly?Always ask permission before:
Always explain:
For deeper dives into specific topics:
A styling task is complete when:
prefers-reduced-motiontools
{{ 𝚫𝚫𝚫 }} Rebuild roadmap-system.zip, the distributable snapshot of the roadmap tooling (scripts, HTML template, conventions reference, and every roadmap-touching skill, including this one).
tools
--- name: "Suggest: Task" description: "{{ 𝚫𝚫𝚫 }} Suggest the next logical task — grounded in the roadmap's pre-vetted ready-set when one exists, codebase analysis otherwise" when_to_use: "When you don't know what to work on next and want a grounded recommendation rather than picking arbitrarily." model: haiku effort: low disable-model-invocation: true allowed-tools: ["Read", "Glob", "Grep", "Bash(python3:*)", "Bash(npm:*)", "Bash(bun:*)", "Bash(pnpm:*)", "Bash(deno:*)"] argument-hint: [named
development
{{ 𝛀𝛀𝛀 }} Convert an old simple-style roadmap (single Markdown, four statuses, <a name> anchors, roadmaps.json pointer registry) into the rich phase-array format (roadmaps.json source of truth + PHASE task list + prose overview).
data-ai
{{ ƔƔƔ }} Create a pull request to main — wordy or shiny (with screenshots), ready-for-review or draft