# Refactor: Split gin.css into Individual PostCSS Files

## Goal

Replace the monolithic `gin.css` (compiled from Sass) with individual `.pcss.css`
files that are compiled by Drupal core's PostCSS build pipeline, then loaded via
`libraries.yml` entries in correct source order.

## Readiness Assessment

### Sass features remaining

| Feature | Count | Conversion needed |
|---------|-------|-------------------|
| `&:pseudo` nesting (`&:hover`, `&::before`, etc.) | ~88 | Works in CSS nesting ✓ |
| `&.class` nesting (`&.is-active`) | ~12 | Works in CSS nesting ✓ |
| `& ,` in selector lists (`&, &:hover`) | ~15 | Works in CSS nesting ✓ |
| Reverse nesting (`.gin--dark-mode &`) | 42 | Works in CSS nesting ✓ |
| `#{...}` interpolation | 4 | Convert to plain CSS selectors |
| `//` single-line comments | 55 | Convert to `/* */` comments |
| `unquote()` | 0 | Already removed ✓ |
| `@extend` / `@mixin` / `$variables` | 0 | Already removed ✓ |

**Verdict: Ready to proceed.** The remaining conversions are minimal:
- Interpolation → already plain CSS strings, just remove the `#{}` wrapper
- `//` comments → convert to `/* */`
- All nesting patterns (including reverse/ancestor nesting) are valid CSS nesting
  and handled by `postcss-preset-env`

### The `:where()` / `:is()` wrapper

The Sass entry point wraps most partials inside:
```scss
:where(*) {
  @import "base/regions";
  // ... 38 more partials
}
```

In the PostCSS files, each rule that was inside this wrapper needs the wrapper
added explicitly. Two approaches:

**Option A: Wrap entire file contents**
```css
:where(*) {
  /* entire file contents */
}
```

**Option B: Wrap each top-level rule individually**
```css
:where(*) .region-sticky {
  /* styles */
}
```

**Recommendation: Option A** — it's simpler, matches the current Sass structure,
and CSS nesting makes this clean. The 3 files imported outside the wrapper
(`_icons`, `_body`, `_color-overrides`, `_views-unwrapped`) don't get wrapped.

## Plan

### Step 1: Convert each Sass partial to a `.pcss.css` file

For each of the 44 Sass partials, create a corresponding `.pcss.css` file in
`migration/css/base/`. The conversion for each file:

1. Copy the `.scss` content
2. Convert `//` comments to `/* */`
3. Remove `#{}` interpolation wrappers (the strings inside are already valid CSS)
4. For files that were inside the `:where()` wrapper in `gin.scss`, wrap
   the entire file content in the wrapper block
5. Add `@import` for `media-queries.pcss.css` at the top if the file uses
   custom media queries

#### File mapping (source order preserved)

Files outside wrapper (no `:where()` wrapping needed):
```
styles/base/_icons.scss         → css/base/gin-icons.pcss.css
styles/base/_body.scss          → css/base/gin-body.pcss.css
styles/base/_color-overrides.scss → css/base/gin-color-overrides.pcss.css
styles/base/_views-unwrapped.scss → css/base/gin-views-unwrapped.pcss.css
```

Files inside wrapper (need `:where()` wrapping):
```
styles/base/_regions.scss       → css/base/gin-regions.pcss.css
styles/base/_layers.scss        → css/base/gin-layers.pcss.css
styles/base/_title.scss         → css/base/gin-title.pcss.css
styles/base/_extend.scss        → css/base/gin-extend.pcss.css
styles/base/_claro_improvements.scss → css/base/gin-claro-improvements.pcss.css
styles/base/_views.scss         → css/base/gin-views.pcss.css
styles/base/_table.scss         → css/base/gin-table.pcss.css
styles/base/_tabledrag.scss     → css/base/gin-tabledrag.pcss.css
styles/base/_form.scss          → css/base/gin-form.pcss.css
styles/base/_button.scss        → css/base/gin-button.pcss.css
styles/base/_dropbutton.scss    → css/base/gin-dropbutton.pcss.css
styles/base/_action-link.scss   → css/base/gin-action-link.pcss.css
styles/base/_pager.scss         → css/base/gin-pager.pcss.css
styles/base/_help.scss          → css/base/gin-help.pcss.css
styles/base/_system-report.scss → css/base/gin-system-report.pcss.css
styles/base/_messages.scss      → css/base/gin-messages.pcss.css
styles/base/_field-ui.scss      → css/base/gin-field-ui.pcss.css
styles/base/_card.scss          → css/base/gin-card.pcss.css
styles/base/_elements.scss      → css/base/gin-elements.pcss.css
styles/base/_admin-item.scss    → css/base/gin-admin-item.pcss.css
styles/base/_focus.scss         → css/base/gin-focus.pcss.css
styles/base/_system-modules.scss → css/base/gin-system-modules.pcss.css
styles/base/_system-diff.scss   → css/base/gin-system-diff.pcss.css
styles/base/_update.scss        → css/base/gin-update.pcss.css
styles/base/_status-report.scss → css/base/gin-status-report.pcss.css
styles/base/_divider.scss       → css/base/gin-divider.pcss.css
styles/base/_progress.scss      → css/base/gin-progress.pcss.css
styles/base/_insert.scss        → css/base/gin-insert.pcss.css
styles/base/_system-themes.scss → css/base/gin-system-themes.pcss.css
styles/base/_panel.scss         → css/base/gin-panel.pcss.css
styles/base/_blocks.scss        → css/base/gin-blocks.pcss.css
styles/base/_batch.scss         → css/base/gin-batch.pcss.css
styles/base/_maxlength.scss     → css/base/gin-maxlength.pcss.css
styles/base/_local-actions.scss → css/base/gin-local-actions.pcss.css
styles/base/_tour.scss          → css/base/gin-tour.pcss.css
styles/base/_quotation.scss     → css/base/gin-quotation.pcss.css
styles/base/_image-preview.scss → css/base/gin-image-preview.pcss.css
styles/base/_permissions.scss   → css/base/gin-permissions.pcss.css
styles/base/_taxonomy.scss      → css/base/gin-taxonomy.pcss.css
```

Toolbar icons (from helpers/):
```
styles/helpers/_toolbar-icons.scss → css/base/gin-toolbar-icons.pcss.css
```

### Step 2: Compile with core's PostCSS build

Run from `/drupal/core/`:
```
yarn build:css --file themes/default_admin/migration/css/base/gin-icons.pcss.css
```

Or compile all at once:
```
yarn build:css
```

Each `.pcss.css` file produces a corresponding `.css` file in the same directory.

### Step 3: Update `libraries.yml`

Replace the single `gin.css` entry with all individual CSS files in source order.
These go in the `theme:` section (same position as `gin.css` currently):

```yaml
    theme:
      css/theme/colors.css: {}
      # Migration: gin.css split into individual files
      migration/css/base/gin-icons.css: {}
      migration/css/base/gin-body.css: {}
      migration/css/base/gin-color-overrides.css: {}
      migration/css/base/gin-views-unwrapped.css: {}
      migration/css/base/gin-regions.css: {}
      migration/css/base/gin-layers.css: {}
      migration/css/base/gin-title.css: {}
      migration/css/base/gin-extend.css: {}
      migration/css/base/gin-claro-improvements.css: {}
      migration/css/base/gin-views.css: {}
      migration/css/base/gin-table.css: {}
      migration/css/base/gin-tabledrag.css: {}
      migration/css/base/gin-form.css: {}
      migration/css/base/gin-button.css: {}
      migration/css/base/gin-dropbutton.css: {}
      migration/css/base/gin-action-link.css: {}
      migration/css/base/gin-pager.css: {}
      migration/css/base/gin-help.css: {}
      migration/css/base/gin-system-report.css: {}
      migration/css/base/gin-messages.css: {}
      migration/css/base/gin-field-ui.css: {}
      migration/css/base/gin-card.css: {}
      migration/css/base/gin-elements.css: {}
      migration/css/base/gin-admin-item.css: {}
      migration/css/base/gin-focus.css: {}
      migration/css/base/gin-system-modules.css: {}
      migration/css/base/gin-system-diff.css: {}
      migration/css/base/gin-update.css: {}
      migration/css/base/gin-status-report.css: {}
      migration/css/base/gin-divider.css: {}
      migration/css/base/gin-progress.css: {}
      migration/css/base/gin-insert.css: {}
      migration/css/base/gin-system-themes.css: {}
      migration/css/base/gin-panel.css: {}
      migration/css/base/gin-blocks.css: {}
      migration/css/base/gin-batch.css: {}
      migration/css/base/gin-maxlength.css: {}
      migration/css/base/gin-local-actions.css: {}
      migration/css/base/gin-tour.css: {}
      migration/css/base/gin-quotation.css: {}
      migration/css/base/gin-image-preview.css: {}
      migration/css/base/gin-permissions.css: {}
      migration/css/base/gin-taxonomy.css: {}
      migration/css/base/gin-toolbar-icons.css: {}
```

### Step 4: Remove gin.css from libraries.yml

Delete the line:
```yaml
      migration/css/base/gin.css: { minified: false }
```

Leave the `gin.css` file on disk (to be deleted in a later cleanup step).

### Step 5: Verify

- Run core's PostCSS build to compile all `.pcss.css` files
- Load the admin theme in a browser
- Visual regression test — the split files should produce identical rendering
  to the monolithic `gin.css`

## Conversion reference

### `//` comment conversion

```scss
// This is a Sass comment
/* This is a CSS comment */
```

### `#{...}` interpolation removal

```scss
/* Sass */
#{":not(.a, .b, .c)"} > .form-type--checkbox {

/* PostCSS */
:not(.a, .b, .c) > .form-type--checkbox {
```

### `:where()` wrapper (for files inside the wrapper)

```css
/* Each wrapped file starts with: */
:where(*) {
  /* file contents here, indented */

  .region-sticky {
    position: sticky;
  }
}
```

### Media queries import

Files using `@media (--admin-large)` etc. need:
```css
@import "../base/media-queries.pcss.css";
```

## Risks / Notes

- **Source order matters.** The `libraries.yml` entries must match the import
  order in `gin.scss` exactly, or cascade/override behavior could break.
- **The `:where()` wrapper** adds specificity context. Files outside the
  wrapper (`_body`, `_color-overrides`, `_icons`, `_views-unwrapped`) must NOT
  be wrapped.
- **CSS nesting** is handled by `postcss-preset-env` in core's build pipeline,
  so `&:hover`, `&::before`, etc. will compile correctly.
- The Sass source files remain in place during this step — they can be removed
  in a later cleanup once the PostCSS files are verified.
- The `gin-raw.css` intermediate file and migration `package.json` build scripts
  become unnecessary after this step (cleanup later).
