# CSS Architecture

**Last Updated:** 2026-02-24

Overview of shared vs page-specific CSS, loading strategy, and consolidation recommendations.

## Shared CSS (All Pages via head.php)

| File | Size (min) | Load Strategy | Notes |
|------|------------|---------------|-------|
| `src/critical.css` | ~31–71 KB | Preload, then stylesheet | Extracted from output.css via PurgeCSS |
| `dist/output.min.css` | ~156 KB | `media="print"` onload | Tailwind bundle (v2, html, wp-content) |
| `src/aos.css` | ~25 KB | Conditional, deferred | Only when `$aosScript === "true"` |
| `src/swiper-bundle.min.css` | ~18 KB | Conditional, deferred | Only when `$swiperScript === "true"` |

## Page-Type CSS

| CSS File | Consumer Pages | Size (min) |
|----------|----------------|------------|
| `comparison-pages.min.css` | All compare_*.php (67+ pages) | ~10 KB |
| `shared-content-blocks.min.css` | tools-pages, template-content-blocks (via @import) | ~3 KB |
| `tools-pages.min.css` | All tools_*.php (18+ pages) | ~13 KB |
| `templates-pages.min.css` | templates_template.php | ~18 KB |
| `template-content-blocks.min.css` | templates_template.php | ~10 KB |
| `blog-base.min.css` | All blog pages (shared) | ~32 KB |
| `blog-index.min.css` | Blog index, category, topic-hub | ~20 KB |
| `blog-post.min.css` | Blog post, v2/html/blog/*.html | ~21 KB |
| `product-pages.min.css` | Product pages, cello, pricing | ~6 KB |
| `mobile-app-components.min.css` | product_mobile_app.php | ~23 KB |
| `industry-pages.min.css` | industry_*.php (5 pages) | ~271 B |
| `pricing-page.min.css` | static_pricing_new.php | ~27 KB |
| `testimonials-page.min.css` | static_customers_new.php | ~25 KB |
| `webinar-pages.min.css` | Webinar pages | ~1.4 KB |
| `event-form.min.css` | Event pages | ~21 KB |
| `booking-calendar.min.css` | Pages with booking embed | ~1.4 KB |
| `partner-page.min.css` | static_partner.php | ~1.5 KB |
| `nano-ai-*.min.css` | product_nano_ai.php | ~22 KB |
| `performance-dashboard.min.css` | performance-dashboard.php | ~23 KB |

## Affiliate CSS (affiliate-head.php)

| CSS File | Pages |
|----------|-------|
| `affiliate-shared.min.css` | All affiliate pages (base) |
| `affiliate-levels.min.css` | Levels page |
| `affiliate-referral-urls.min.css` | Referral URLs page |
| `affiliate-admin.min.css` | Admin page |
| `affiliate-dialogs.min.css` | Admin, Referral URLs, Settings |
| `affiliate-resources.min.css` | Resources page |

**Note:** `affiliate-dashboard.min.css` removed (was empty; base styles in affiliate-shared).

## Selector Overlap (Potential Tailwind Duplicates)

### comparison-pages.css

- **Done:** `.hero`, `.container`, `.btn`, `.btn-outline`, `.cta-section` removed – pages use Tailwind equivalents.

### tools-pages.css

- **Done:** `.content-block-*` and `.ordio-tabs` extracted to `shared-content-blocks.css`; tools-pages and template-content-blocks @import it.

## Design Token Duplication

- **blog-base.css** and **comparison-pages.css** define `--ordio-blue`, `--bg-page`, etc.
- **Recommendation:** Consolidate into `src/input.css` or `v2/css/design-tokens.css`.

## Build and Minification

- **Build:** `npm run build:css` → `dist/output.css`
- **Critical:** `npm run build:critical` → `src/critical.css` (PurgeCSS from dist/output.css)
- **Minify:** `npm run minify` → all `.min.css` files
- **Full build:** `npm run build` = build:css + build:critical + minify

## Audit and Coverage Scripts

- **Audit:** `npm run css:audit` (or `python3 v2/scripts/dev-helpers/css-audit-analyzer.py`)

## Minification Verification (Phase 7.2)

- **Minify list:** `minify-assets.js` – all page-specific CSS included
- **Orphaned removed:** `affiliate-dashboard.css` removed from minify (no longer loaded by affiliate-head)
- **Shared via @import:** `shared-content-blocks.css` loaded by tools-pages.css and template-content-blocks.css; included in minify
- **Coverage:** See `docs/systems/css/CSS_COVERAGE_REPORT.md` for manual Chrome DevTools process

## Tailwind Content Scope Evaluation (Phase 3)

**Current:** Single `dist/output.css` (~156 KB minified). Content paths: `v2/**/*.php`, `html/**/*`, `wp-content/**`.

**Findings:**
- Tailwind v3 JIT purges unused classes based on content scan
- `wp-content` inclusion may add WordPress-specific classes not used on v2 pages
- Page-type splitting (output-base + output-comparison, output-tools, etc.) would reduce per-page CSS but adds build complexity and cache fragmentation

**Recommendation:** Keep single build for now. If output.min.css grows significantly or LCP targets are missed, consider: (1) excluding `wp-content` from content paths for v2-only build, or (2) implementing page-type splitting.

## Blog CSS Split (Implemented 2026-02-24)

**Status:** Implemented.

- **Files:** `blog-base.css`, `blog-index.css`, `blog-post.css` (split from former `blog.css`)
- **Loading:** Index/category/topic-hub load base + index (~52 KB total); post pages load base + post (~53 KB total). Previously all loaded single blog.css (~74 KB).
- **Scripts:** `v2/scripts/blog/blog-selector-page-mapping.py` → `docs/analysis/blog-selector-page-mapping.json`; `v2/scripts/blog/split-blog-css.py` performs the split
- **Documentation:** `docs/analysis/blog-css-split-mapping.md`, `docs/content/blog/BLOG_CSS_SPLIT_MAINTENANCE.md`

## AOS and Swiper Loading Audit

**Conditional loading:** `head.php` loads AOS only when `$aosScript === "true"`, Swiper only when `$swiperScript === "true"`.

| Script | Pages that load it | Pages that skip (set "false") |
|--------|--------------------|------------------------------|
| **AOS** | Most marketing pages (product, comparison, industry, tools, pricing, blog post, etc.) | static_privacy, static_terms, static_termsuser, tools_arbeitszeitrechner, tools_prozentrechner, tools_mehrwertsteuer_rechner, shiftops, shiftops-report, blog index/category/post, produkt_updates_admin |
| **Swiper** | start.php, start-v2.php, landingpage_v2-alt.php, start3.php, demo.php, fi.php | All other pages |

**Verification:** No unnecessary loads. Pages without carousels set `$swiperScript = "false"`. Pages without scroll animations set `$aosScript = "false"`.

## CSS Coverage Analysis

- **Page inventory:** `python3 v2/scripts/dev-helpers/css-page-inventory.py` → `PAGE_CSS_INVENTORY.json`
- **Coverage collection:** `npm run css:coverage` (Playwright) → `CSS_COVERAGE_RESULTS.json`, `CSS_COVERAGE_RESULTS.md`
- **Recommendations:** `python3 v2/scripts/dev-helpers/css-coverage-analyzer.py` → `CSS_OPTIMIZATION_RECOMMENDATIONS.md`
- **Page-to-CSS matrix:** See `PAGE_CSS_INVENTORY.json` for which page types load which CSS files

## Optimization History

| Date | Change | Rationale |
|------|--------|-----------|
| 2026-02-24 | industry-pages.min.css: deferred loading (media=print onload) in all 6 industry_*.php | Reduce render-blocking; match product/comparison pattern |
| 2026-02-24 | template-content-blocks.min.css: deferred loading in templates_template.php | Reduce render-blocking |
| 2026-02-24 | Blog CSS split: blog-base + blog-index + blog-post | ~30% reduction per page; index loads base+index, post loads base+post |

## Related Documentation

- [CSS Audit Report](CSS_AUDIT_REPORT.md) – File sizes, page mapping, overlap
- [CSS Coverage Report](CSS_COVERAGE_REPORT.md) – Representative URLs, manual coverage
- [CSS Coverage Results](CSS_COVERAGE_RESULTS.md) – Playwright coverage output
- [CSS Optimization Recommendations](CSS_OPTIMIZATION_RECOMMENDATIONS.md) – Data-driven recommendations
- [v2/data/performance/task-templates/css-optimization.json](../../v2/data/performance/task-templates/css-optimization.json) – Optimization steps
