Nano Banana Pro
Agent skill for nano-banana-pro
Audit and refactor CSS to comply with Game Loopers design system and BEM methodology
Sign in to like and favorite skills
css-bem-auditor
Audit, normalize, and refactor CSS across the Game Loopers application to comply with the project's BEM (Block–Element–Modifier) methodology and design system, ensuring maintainability, consistency, and scalability.
This skill identifies non-compliant selectors, design token violations, naming collisions, overly-specific rules, and architectural inconsistencies, then proposes or applies BEM-aligned fixes specific to Game Loopers.
Critical: This project uses strict BEM with NO utility-first CSS (no Tailwind, no inline utilities). All styles must use component-scoped CSS with BEM naming.
This skill operates on:
.astro files with <style> blocks).tsx files with co-located .css files)/src/styles/global.css)product-files-form.css)It does not redesign UI or change visual intent unless explicitly requested.
Game Loopers has a comprehensive design system defined in
DESIGN_SYSTEM.md (co-located in this directory). All CSS must comply with:
Semantic Colors:
--primary /* Black in light mode */ --primary-foreground /* White text on primary */ --secondary /* Light gray */ --secondary-foreground --destructive /* Red for errors/delete */ --destructive-foreground --accent /* Highlights, hover states */ --accent-foreground --background /* Page background */ --foreground /* Primary text */ --card /* Card backgrounds */ --card-foreground --muted /* Low emphasis backgrounds */ --muted-foreground /* Secondary text */ --border /* Default borders */ --input /* Input borders */ --ring /* Focus ring color */
Status Colors:
--color-success /* Green - confirmations */ --color-success-foreground --color-warning /* Yellow - cautions */ --color-warning-foreground --color-error /* Red - failures */ --color-error-foreground --color-info /* Blue - notifications */ --color-info-foreground
--text-xs: 0.75rem; /* 12px */ --text-sm: 0.875rem; /* 14px */ --text-base: 1rem; /* 16px */ --text-lg: 1.125rem; /* 18px */ --text-xl: 1.25rem; /* 20px */ --text-2xl: 1.5rem; /* 24px */ --text-3xl: 1.875rem; /* 30px */ --text-4xl: 2.25rem; /* 36px */ --text-5xl: 3rem; /* 48px */ --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; --leading-tight: 1.25; --leading-snug: 1.375; --leading-normal: 1.5; --leading-relaxed: 1.625;
--spacing-xs: 0.25rem; /* 4px */ --spacing-sm: 0.5rem; /* 8px */ --spacing-md: 1rem; /* 16px */ --spacing-lg: 1.5rem; /* 24px */ --spacing-xl: 2rem; /* 32px */ --spacing-2xl: 3rem; /* 48px */ --spacing-3xl: 4rem; /* 64px */ --spacing-4xl: 6rem; /* 96px */ --gap-xs: 0.25rem; --gap-sm: 0.5rem; --gap-md: 1rem; --gap-lg: 1.5rem; --gap-xl: 2rem; --gap-2xl: 3rem;
--radius-sm: 0.125rem; /* 2px */ --radius-md: 0.375rem; /* 6px */ --radius-lg: 0.5rem; /* 8px */ --radius-xl: 0.75rem; /* 12px */ --radius-2xl: 1rem; /* 16px */ --radius-full: 9999px; /* Fully rounded */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
.block {} .block__element {} .block--modifier {} .block__element--modifier {}
Block Naming:
.product-card, .browse-cta)Element Naming:
__) separates block from element.button__text, .card__header)Modifier Naming:
--) separates block/element from modifier.button--primary, .card--elevated)Core Components:
.button (Button.astro).card (Card.astro).page-header (PageHeader.astro).navigation (Navigation.astro).browse-cta (BrowseCTA.astro)Browse Components (global.css):
.browse-search.browse-tags.browse-grid.browse-card.browse-empty.browse-paginationProduct Components:
.product-chat.add-to-cart.add-to-cart-modal.product-documents-form.document-list.product-contributors.price-breakdown.status-editor.status-badge.revenue-preview.royalty-breakdown.product-files-form.product-royalty-breakdown.product-status-editor.product-embeddable-toggle.product-embedded-productsDocument Components:
.document-chatInteractive Components:
.confirm-dialog.modal-overlay, .modal-content, .modal-header, .modal-body❌ Strictly Forbidden:
/* NO Tailwind-style utilities */ .flex { display: flex; } .text-center { text-align: center; } .mt-4 { margin-top: 1rem; } /* NO chained selectors (breaks BEM) */ .card .title { } .button .icon { } /* NO tag-qualified classes */ div.card { } a.button { } /* NO ID selectors */ #header { } /* NO deep nesting beyond 2 levels */ .card__header__title__icon { } /* Too deep */ /* NO generic state classes without block context */ .is-active { } /* Use .button--active instead */ .has-error { } /* Use .input--error instead */ /* NO hardcoded colors/sizes (use design tokens) */ .card { color: #333; /* ❌ Use var(--foreground) */ padding: 24px; /* ❌ Use var(--spacing-lg) */ border-radius: 8px; /* ❌ Use var(--radius-lg) */ }
✅ Correct Usage:
/* Flat class selectors with design tokens */ .card { background-color: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--spacing-3xl); } /* Explicit block ownership */ .card__title { font-size: var(--text-xl); font-weight: var(--font-weight-semibold); color: var(--card-foreground); } /* Boolean and value modifiers */ .button--primary { } .button--lg { } .card--elevated { } /* Pseudo-states on BEM classes */ .button:hover { } .button:focus-visible { } .button:disabled { } /* Global page utilities (limited exceptions) */ .page { } .page__container { } /* Third-party libraries (unmodifiable) */ .tiptap { } .astro-* { }
.astro and .css filesEach selector is categorized as:
.page, .page__container).tiptap, .astro-*)Naming Violations:
_ instead of __, - instead of --).block__element__subelement)Design Token Violations:
var(--primary), var(--muted-foreground), etc.var(--spacing-*) or var(--gap-*)var(--text-*)var(--radius-*)var(--shadow-*)Structural Violations:
.card .button__text)div.button)For each violation:
-- separator)Ensure all CSS uses design tokens:
/* BEFORE (violations) */ .card { color: #333; background: #fff; padding: 24px; margin-bottom: 32px; border-radius: 8px; font-size: 18px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } /* AFTER (compliant) */ .card { color: var(--foreground); background: var(--card); padding: var(--spacing-lg); margin-bottom: var(--spacing-xl); border-radius: var(--radius-lg); font-size: var(--text-lg); box-shadow: var(--shadow-md); }
BEFORE (Violation):
<!-- Astro component using Tailwind-style classes --> <div class="flex gap-4 p-6 rounded-lg bg-white"> <h2 class="text-xl font-bold">Title</h2> <p class="text-gray-600">Description</p> </div> <style> .flex { display: flex; } .gap-4 { gap: 1rem; } .p-6 { padding: 1.5rem; } .rounded-lg { border-radius: 0.5rem; } .bg-white { background: white; } .text-xl { font-size: 1.25rem; } .font-bold { font-weight: bold; } .text-gray-600 { color: #666; } </style>
AFTER (BEM Compliant):
<div class="product-card"> <h2 class="product-card__title">Title</h2> <p class="product-card__description">Description</p> </div> <style> .product-card { display: flex; gap: var(--gap-md); padding: var(--spacing-lg); border-radius: var(--radius-lg); background: var(--card); } .product-card__title { font-size: var(--text-xl); font-weight: var(--font-weight-bold); color: var(--card-foreground); } .product-card__description { color: var(--muted-foreground); } </style>
BEFORE (Violation):
.card .header .title { font-size: 20px; } .card.active { border-color: blue; } .card .footer button { padding: 12px 24px; }
AFTER (BEM Compliant):
.card__title { font-size: var(--text-xl); } .card--active { border-color: var(--primary); } .card__footer-button { padding: var(--spacing-sm) var(--spacing-lg); }
<div class="card card--active"> <div class="card__header"> <h2 class="card__title">Title</h2> </div> <div class="card__footer"> <button class="card__footer-button">Action</button> </div> </div>
BEFORE (Violations):
.product-card { background: #ffffff; color: #333333; border: 1px solid #e0e0e0; padding: 16px 24px; margin-bottom: 32px; border-radius: 8px; font-size: 16px; line-height: 1.5; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .product-card__title { color: #000000; font-size: 24px; font-weight: 600; margin-bottom: 8px; } .product-card__description { color: #666666; font-size: 14px; line-height: 1.6; } .product-card:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); }
AFTER (Design Token Compliant):
.product-card { background: var(--card); color: var(--card-foreground); border: 1px solid var(--border); padding: var(--spacing-md) var(--spacing-lg); margin-bottom: var(--spacing-xl); border-radius: var(--radius-lg); font-size: var(--text-base); line-height: var(--leading-normal); box-shadow: var(--shadow-sm); } .product-card__title { color: var(--foreground); font-size: var(--text-2xl); font-weight: var(--font-weight-semibold); margin-bottom: var(--spacing-sm); } .product-card__description { color: var(--muted-foreground); font-size: var(--text-sm); line-height: var(--leading-relaxed); } .product-card:hover { box-shadow: var(--shadow-md); }
/* Base button block */ .button { display: inline-flex; align-items: center; justify-content: center; padding: var(--spacing-sm) var(--spacing-lg); border-radius: var(--radius-md); font-size: var(--text-base); font-weight: var(--font-weight-medium); transition: background-color 150ms; } /* Variant modifiers */ .button--primary { background-color: var(--primary); color: var(--primary-foreground); } .button--secondary { background-color: var(--secondary); color: var(--secondary-foreground); } .button--destructive { background-color: var(--destructive); color: var(--destructive-foreground); } /* Size modifiers */ .button--sm { padding: var(--spacing-xs) var(--spacing-md); font-size: var(--text-sm); } .button--lg { padding: var(--spacing-md) var(--spacing-xl); font-size: var(--text-lg); } /* Elements */ .button__icon { margin-right: var(--spacing-xs); } .button__text { } /* States */ .button:hover { opacity: 0.9; } .button:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } .button:disabled { opacity: 0.5; pointer-events: none; }
.modal-overlay { position: fixed; inset: 0; background: rgb(0 0 0 / 0.5); display: flex; align-items: center; justify-content: center; padding: var(--spacing-lg); z-index: 50; } .modal-content { background: var(--card); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); max-width: 32rem; width: 100%; max-height: 90vh; overflow-y: auto; } .modal-header { display: flex; justify-content: space-between; align-items: center; padding: var(--spacing-lg); border-bottom: 1px solid var(--border); } .modal-title { font-size: var(--text-xl); font-weight: var(--font-weight-semibold); color: var(--foreground); } .modal-close { padding: var(--spacing-xs); color: var(--muted-foreground); } .modal-close:hover { color: var(--foreground); } .modal-body { padding: var(--spacing-lg); }
All CSS must support accessibility standards:
/* All interactive elements MUST have visible focus indicators */ .button:focus-visible, .browse-tags__tag:focus-visible, .navigation__link:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
All semantic color tokens meet WCAG 2.1 Level AA standards.
/* Hidden but accessible to screen readers */ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } /* Decorative elements should be hidden from screen readers via aria-hidden="true" */ /* No CSS-only hiding for interactive elements */
CSS files must follow this structure:
src/ ├── styles/ │ └── global.css # Global styles, shared .browse-* classes ├── components/ │ ├── Button.astro # <style> block in component │ ├── Card.astro # <style> block in component │ ├── products/ │ │ ├── ProductFilesForm.tsx # SolidJS component │ │ ├── product-files-form.css # Co-located CSS │ │ ├── ProductRoyaltyBreakdown.tsx │ │ └── product-royalty-breakdown.css
Rules:
<style> blocks in .astro files.css files with matching names.browse-* classes in global.css<style> blocks in page .astro filesGenerates:
Generates:
.astro and .tsx files)Generates:
.astro, .tsx, .css)✅ Pass Conditions:
.block__element--modifier)This skill enforces Game Loopers' strict BEM architecture and design system compliance. It ensures:
This is critical for a product-market fit focused MVP where consistency and maintainability enable rapid iteration.