# Skill: Frontend Styling SCSS

Skill ID: `frontend-styling-scss`

Rules
- SCSS source path is `/css/`; do not create `/scss/` directories.
- Class naming: BEM with plugin prefix (`presszone-translate-*`).
- Variables: plugin-prefixed SCSS variables (`$presszone-translate-*`).
- Colors, spacing, radius, z-index, breakpoints come from variables/tokens only.
- Use namespaced z-index and breakpoint variables; avoid generic `$z-index` and `$breakpoint-*`.
- Use class-based variants for runtime states/settings.
- Keep dark mode overrides co-located with `body.dark-mode &` nesting.
- Avoid CSS custom properties for feature logic (`var(--*)`); prefer SCSS vars + state classes.
- Avoid hardcoded colors, magic numbers, deep selector chains, float/clearfix layout patterns.
- Use Flexbox/Grid.
- Avoid `!important` unless overriding unavoidable core/third-party rules.
- Reuse shared keyframes/animation tokens; do not duplicate animation blocks.

Accessibility
- Visible focus indicators.
- Contrast targets: 4.5:1 normal text, 3:1 large text.
- Layout remains usable at 200% zoom.
- Respect `prefers-reduced-motion`.
- Do not encode status by color alone.

Code examples

```scss
// css/components/_translation-card.scss
@use '../tokens/variables' as *;

// Tokens are defined in shared variables files.
// Do not hardcode colors/sizes in component files.

.presszone-translate-card {
  display: grid;
  gap: $presszone-translate-space-3;
  padding: $presszone-translate-space-4;
  background: $presszone-translate-color-bg;
  color: $presszone-translate-color-text;
  border: 1px solid $presszone-translate-color-border;
  border-radius: $presszone-translate-radius-md;

  body.dark-mode & {
    background: $presszone-translate-color-bg-dark;
    color: $presszone-translate-color-text-dark;
    border-color: $presszone-translate-color-border-dark;
  }

  &__title {
    font-weight: 600;
  }

  &--is-loading {
    opacity: 0.7;
    pointer-events: none;
  }

  &--status-error {
    border-color: $presszone-translate-color-status-error;
  }

  &--status-pending {
    border-color: $presszone-translate-color-status-pending;
  }

  &--status-complete {
    border-color: $presszone-translate-color-status-complete;
  }
}

@media (min-width: $presszone-translate-breakpoint-md) {
  .presszone-translate-card {
    grid-template-columns: 1fr auto;
    align-items: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .presszone-translate-card,
  .presszone-translate-card * {
    transition-duration: 0s;
    animation-duration: 0s;
    animation-iteration-count: 1;
  }
}

.presszone-translate-button:focus-visible {
  outline: $presszone-translate-focus-width solid $presszone-translate-color-focus;
  outline-offset: $presszone-translate-focus-offset;
}
```

```scss
// State class pattern (recommended)
.presszone-translate-job {
  &--status-pending { border-left: $presszone-translate-border-strong solid $presszone-translate-color-status-pending; }
  &--status-complete { border-left: $presszone-translate-border-strong solid $presszone-translate-color-status-complete; }
  &--status-failed { border-left: $presszone-translate-border-strong solid $presszone-translate-color-status-error; }
}

// Avoid: inline style="border-left-color: ..."
```

Build
- `npm run build:css`
- If admin SCSS changed: `cd admin && npm run build`

Mistakes to avoid
| Mistake | Fix |
|---|---|
| Using `/scss/` folders | Keep SCSS in `/css/` |
| CSS custom properties for logic | Use SCSS vars + explicit classes |
| Hardcoded dark-mode colors | Use vars with `.dark-mode &` nesting |
| Class chaining like `.a.b` | Use single-purpose BEM classes |
| Duplicated keyframes | Reuse shared animation rules |
| Deep nesting / `!important` overuse | Flatten selectors and raise specificity correctly |
| Missing reduced-motion rules | Add `@media (prefers-reduced-motion: reduce)` |
| Forgetting CSS build | Run `npm run build:css` |
| Using generic `$z-index`/`$breakpoint-*` names | Use plugin namespaced vars |
| Inline style values for dynamic states | Switch to explicit state classes |
