From 95ae364c1a0634ee62277444665718dc852f5567 Mon Sep 17 00:00:00 2001 From: Eli Pinkerton Date: Sun, 25 Jan 2026 19:02:41 -0800 Subject: [PATCH 1/3] Potential github pages fixes --- assets/css/style.scss | 8 ++- assets/css/theme.css | 76 ++++++++++++++++++++++++++++ docs/images/unity-helpers-banner.svg | 20 ++++---- docs/stylesheets/custom.css | 75 ++++++++++++++++++++++++++- 4 files changed, 167 insertions(+), 12 deletions(-) diff --git a/assets/css/style.scss b/assets/css/style.scss index 6ed717dd..85bc251e 100644 --- a/assets/css/style.scss +++ b/assets/css/style.scss @@ -175,8 +175,12 @@ table[data-sortable] th::after { color: var(--text-muted); } -/* Hide default indicator when sort indicator is present */ -table[data-sortable] th:has(.sort-indicator)::after { +/* + * Hide default indicator when sort indicator is present + * Note: Using .sort-indicator-active class instead of :has() for browser compatibility + * (Safari 15.3 and below, Firefox 120 and below don't support :has()) + */ +table[data-sortable] th.sort-indicator-active::after { display: none; } diff --git a/assets/css/theme.css b/assets/css/theme.css index f1cfe3f4..62e0c8f4 100644 --- a/assets/css/theme.css +++ b/assets/css/theme.css @@ -556,6 +556,82 @@ img { border-radius: 6px; } +/* SVG banner styling - ensure transparency and proper blending */ +img[src*="banner.svg"], +img[alt*="Banner"] { + background: transparent !important; + border: none !important; + box-shadow: none !important; + border-radius: 12px; +} + +/* Light mode banner - subtle shadow for depth on light backgrounds */ +[data-theme="light"] img[src*="banner.svg"], +[data-theme="light"] img[alt*="Banner"] { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; +} + +/* Dark mode banner - no shadow needed */ +[data-theme="dark"] img[src*="banner.svg"], +[data-theme="dark"] img[alt*="Banner"] { + box-shadow: none !important; +} + +/* + * Banner container centering for Jekyll pages + * Note: HTML uses

which handles centering natively. + * These styles provide additional sizing constraints. + * Avoiding :has() selector due to poor browser support (Safari 15.3-, Firefox 120-). + */ +section p[align="center"] { + margin: 1rem auto 2rem; + max-width: 800px; +} + +/* Responsive banner sizing - tablet */ +@media (max-width: 960px) { + section p[align="center"] { + max-width: 100%; + margin: 0.75rem auto 1.5rem; + padding: 0 1rem; + } +} + +/* Responsive banner sizing - small tablet */ +@media (max-width: 768px) { + section p[align="center"] { + margin: 0.5rem auto 1.25rem; + padding: 0 0.75rem; + } + + img[src*="banner.svg"], + img[alt*="Banner"] { + border-radius: 10px; + } +} + +/* Responsive banner sizing - mobile */ +@media (max-width: 600px) { + section p[align="center"] { + margin: 0.5rem auto 1rem; + padding: 0 0.5rem; + } + + img[src*="banner.svg"], + img[alt*="Banner"] { + border-radius: 8px; + } +} + +/* Print media query - hide banner for cleaner print output */ +@media print { + section p[align="center"], + img[src*="banner.svg"], + img[alt*="Banner"] { + display: none !important; + } +} + /* Ensure mermaid diagrams respect theme */ .mermaid { background-color: transparent !important; diff --git a/docs/images/unity-helpers-banner.svg b/docs/images/unity-helpers-banner.svg index e65dbe3d..44b3de32 100644 --- a/docs/images/unity-helpers-banner.svg +++ b/docs/images/unity-helpers-banner.svg @@ -1,4 +1,4 @@ - + @@ -39,11 +39,11 @@ - + - - - + + + @@ -51,8 +51,6 @@ - - @@ -67,8 +65,12 @@ - - + + diff --git a/docs/stylesheets/custom.css b/docs/stylesheets/custom.css index 9fb76035..13f04e30 100644 --- a/docs/stylesheets/custom.css +++ b/docs/stylesheets/custom.css @@ -689,6 +689,7 @@ textarea:focus { width: 100%; margin: 1rem auto 2rem; text-align: center; + background: transparent; } .md-typeset .md-banner img, @@ -697,9 +698,81 @@ textarea:focus { max-width: 100%; height: auto; margin: 0 auto; + background: transparent; } -/* Ensure banner looks good on both light and dark backgrounds */ +/* Base banner styles - works on any background */ .md-typeset .md-banner img { border-radius: 12px; + box-shadow: none; + border: none; +} + +/* SVG banners - ensure full transparency + Note: img[src*="banner.svg"] catches all banner SVGs regardless of container */ +.md-typeset img[src*="banner.svg"], +.md-typeset img[alt*="Banner"] { + background: transparent; + border: none; + box-shadow: none; + border-radius: 12px; +} + +/* Light mode banner adjustments */ +[data-md-color-scheme="default"] .md-typeset .md-banner img, +[data-md-color-scheme="default"] .md-typeset img[src*="banner.svg"] { + /* Subtle shadow for depth on light backgrounds */ + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +/* Dark mode banner - no shadow needed */ +[data-md-color-scheme="slate"] .md-typeset .md-banner img, +[data-md-color-scheme="slate"] .md-typeset img[src*="banner.svg"] { + box-shadow: none; +} + +/* Responsive banner styles - tablet */ +@media (max-width: 960px) { + .md-typeset .md-banner { + max-width: 100%; + margin: 0.75rem auto 1.5rem; + padding: 0 1rem; + } +} + +/* Responsive banner styles - small tablet (768px breakpoint) */ +@media (max-width: 768px) { + .md-typeset .md-banner { + margin: 0.5rem auto 1.25rem; + padding: 0 0.75rem; + } + + .md-typeset .md-banner img { + border-radius: 10px; + } +} + +/* Responsive banner styles - mobile */ +@media (max-width: 600px) { + .md-typeset .md-banner { + margin: 0.5rem auto 1rem; + padding: 0 0.5rem; + } + + .md-typeset .md-banner img { + border-radius: 8px; + } + + .md-typeset img[src*="banner.svg"], + .md-typeset img[alt*="Banner"] { + border-radius: 8px; + } +} + +/* Print media query - hide colorful banner since embedded colors don't print well */ +@media print { + .md-typeset .md-banner, + .md-typeset img[src*="banner.svg"] { + display: none; + } } From 25f8fc13383207e84c6bd6602fd5e9f119310ad0 Mon Sep 17 00:00:00 2001 From: Eli Pinkerton Date: Sun, 25 Jan 2026 19:40:36 -0800 Subject: [PATCH 2/3] PR feedback --- .llm/skills/github-pages.md | 44 +++++++++++++++++++++++++++++++++++++ assets/css/style.scss | 7 +++--- assets/css/theme.css | 12 +++++----- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/.llm/skills/github-pages.md b/.llm/skills/github-pages.md index eb5cb53f..79afab9d 100644 --- a/.llm/skills/github-pages.md +++ b/.llm/skills/github-pages.md @@ -340,6 +340,50 @@ td { **Rule**: If one rule in a group uses a parent scope (`.md-typeset`, `.markdown-body`, etc.), ALL related rules must use the same scope. +### Avoid Overly Broad Structural Selectors + +When targeting specific page elements (banners, hero sections, featured content), use pseudo-classes to prevent unintended side effects on similar elements: + +```css +/* ❌ WRONG: Affects ALL centered paragraphs including badges */ +section p[align="center"] { + margin: 1rem auto; + max-width: 800px; +} + +/* ✅ CORRECT: Only affects the first centered paragraph (banner) */ +section p[align="center"]:first-of-type { + margin: 1rem auto; + max-width: 800px; +} +``` + +**Why this matters:** + +1. **Unintended cascade** — Multiple elements may match broad selectors +2. **Structural precision** — `:first-of-type`, `:last-of-type`, `:nth-of-type()` target specific positions +3. **Future-proofing** — Prevents CSS conflicts when page content structure changes + +**Related pattern - Use ARIA attributes for JavaScript-controlled states:** + +```css +/* ❌ WRONG: CSS class never applied by JavaScript */ +table[data-sortable] th.sort-indicator-active::after { + display: none; +} + +/* ✅ CORRECT: Use ARIA attributes that JavaScript already manages */ +table[data-sortable] th[aria-sort]:not([aria-sort="none"])::after { + display: none; +} +``` + +**Why ARIA over custom classes:** + +1. **Single source of truth** — JavaScript sets ARIA for accessibility; CSS uses same attributes +2. **No orphaned classes** — Can't have CSS targeting a class that JavaScript never applies +3. **Accessibility alignment** — Visual presentation matches what screen readers see + --- ## Testing Links Locally diff --git a/assets/css/style.scss b/assets/css/style.scss index 85bc251e..5cc3dd62 100644 --- a/assets/css/style.scss +++ b/assets/css/style.scss @@ -176,11 +176,10 @@ table[data-sortable] th::after { } /* - * Hide default indicator when sort indicator is present - * Note: Using .sort-indicator-active class instead of :has() for browser compatibility - * (Safari 15.3 and below, Firefox 120 and below don't support :has()) + * Hide default indicator when column is actively sorted + * Uses aria-sort attribute which is set by the JavaScript sorting logic */ -table[data-sortable] th.sort-indicator-active::after { +table[data-sortable] th[aria-sort]:not([aria-sort="none"])::after { display: none; } diff --git a/assets/css/theme.css b/assets/css/theme.css index 62e0c8f4..aec291ee 100644 --- a/assets/css/theme.css +++ b/assets/css/theme.css @@ -581,16 +581,16 @@ img[alt*="Banner"] { * Banner container centering for Jekyll pages * Note: HTML uses

which handles centering natively. * These styles provide additional sizing constraints. - * Avoiding :has() selector due to poor browser support (Safari 15.3-, Firefox 120-). + * Using :first-of-type to target only the banner, not other centered paragraphs (e.g., badges). */ -section p[align="center"] { +section p[align="center"]:first-of-type { margin: 1rem auto 2rem; max-width: 800px; } /* Responsive banner sizing - tablet */ @media (max-width: 960px) { - section p[align="center"] { + section p[align="center"]:first-of-type { max-width: 100%; margin: 0.75rem auto 1.5rem; padding: 0 1rem; @@ -599,7 +599,7 @@ section p[align="center"] { /* Responsive banner sizing - small tablet */ @media (max-width: 768px) { - section p[align="center"] { + section p[align="center"]:first-of-type { margin: 0.5rem auto 1.25rem; padding: 0 0.75rem; } @@ -612,7 +612,7 @@ section p[align="center"] { /* Responsive banner sizing - mobile */ @media (max-width: 600px) { - section p[align="center"] { + section p[align="center"]:first-of-type { margin: 0.5rem auto 1rem; padding: 0 0.5rem; } @@ -625,7 +625,7 @@ section p[align="center"] { /* Print media query - hide banner for cleaner print output */ @media print { - section p[align="center"], + section p[align="center"]:first-of-type, img[src*="banner.svg"], img[alt*="Banner"] { display: none !important; From fea0f1014943792b9d5b06c540345f1616bdb6b5 Mon Sep 17 00:00:00 2001 From: Eli Pinkerton Date: Sun, 25 Jan 2026 20:11:29 -0800 Subject: [PATCH 3/3] PR feedback --- .llm/context.md | 7 +- .llm/skills/github-pages-theming.md | 235 ++++++++++++++++++++++++++++ .llm/skills/github-pages.md | 198 +---------------------- 3 files changed, 240 insertions(+), 200 deletions(-) create mode 100644 .llm/skills/github-pages-theming.md diff --git a/.llm/context.md b/.llm/context.md index b94a9d2a..f9ce4b2b 100644 --- a/.llm/context.md +++ b/.llm/context.md @@ -83,7 +83,7 @@ Invoke these skills for specific tasks. **Regenerate with**: `pwsh -NoProfile -File scripts/generate-skills-index.ps1` - + ### Core Skills (Always Consider) @@ -153,6 +153,7 @@ Invoke these skills for specific tasks. | [debug-il2cpp](./skills/debug-il2cpp.md) | IL2CPP build issues or AOT errors | | [github-actions-script-pattern](./skills/github-actions-script-pattern.md) | Extract GHA logic to testable scripts | | [github-pages](./skills/github-pages.md) | GitHub Pages, Jekyll, markdown link format | +| [github-pages-theming](./skills/github-pages-theming.md) | GitHub Pages CSS theming, Jekyll theme customization | | [github-workflow-permissions](./skills/github-workflow-permissions.md) | Workflow permissions, automated PRs, debugging | | [integrate-odin-inspector](./skills/integrate-odin-inspector.md) | Odin Inspector integration patterns | | [integrate-optional-dependency](./skills/integrate-optional-dependency.md) | Odin, VContainer, Zenject integration patterns | @@ -177,10 +178,6 @@ Invoke these skills for specific tasks. ---- - -## Documentation Is a Deliverable (MANDATORY) - **Documentation is NOT optional.** Every customer-visible change MUST include documentation updates. Incomplete documentation = incomplete work. ### What Requires Documentation Updates diff --git a/.llm/skills/github-pages-theming.md b/.llm/skills/github-pages-theming.md new file mode 100644 index 00000000..86b1518a --- /dev/null +++ b/.llm/skills/github-pages-theming.md @@ -0,0 +1,235 @@ +# Skill: GitHub Pages CSS Theming + + + +**Trigger**: When customizing CSS themes for GitHub Pages or Jekyll documentation sites. + +--- + +## When to Use + +This skill applies when: + +- Overriding remote Jekyll themes (like `pages-themes/minimal`) +- Creating dark/light theme switching +- Fixing "box" appearance issues in themed pages +- Adding CSS accessibility features +- Debugging CSS specificity issues with framework components + +--- + +## CSS Variables in `:root` + +**Always define default CSS variables in `:root`** to ensure themes work before JavaScript loads: + +```css +:root { + /* Define ALL theme variables with defaults */ + --bg-primary: #1e1e1e; + --bg-secondary: #252526; + --text-primary: #d4d4d4; + --text-secondary: #b0b0b0; + --border-color: #3c3c3c; + --link-color: #569cd6; + /* ... all other variables */ +} +``` + +--- + +## Override Remote Theme Elements Comprehensively + +When using a remote theme (like `pages-themes/minimal`), override ALL structural elements to prevent "box" appearance: + +```css +/* Make all nested elements transparent */ +.wrapper, +.wrapper > *, +.inner, +header, +header *, +section, +section *, +footer, +footer * { + background-color: transparent !important; + box-shadow: none !important; +} + +/* Re-apply backgrounds ONLY to root containers */ +body { + background-color: var(--bg-primary) !important; +} + +header { + background-color: var(--bg-primary) !important; + border-bottom: 1px solid var(--border-color) !important; +} + +section { + background-color: var(--bg-primary) !important; +} + +footer { + background-color: var(--bg-primary) !important; + border-top: 1px solid var(--border-color) !important; +} +``` + +--- + +## Theming Best Practices + +| Principle | Implementation | +| ---------------------------- | --------------------------------------------------------------------- | +| Transparent nested elements | Apply `background: transparent` to all children | +| Root-only backgrounds | Apply background colors only to `body`, `header`, `section`, `footer` | +| Consistent color family | Use same `--bg-primary` for all containers | +| No box shadows on containers | Remove `box-shadow` from theme elements | +| Use `!important` sparingly | Required to override remote theme styles | + +--- + +## Theme Switching Support + +```css +/* Dark theme (default) */ +[data-theme="dark"] { + --bg-primary: var(--dark-bg-primary); + --text-primary: var(--dark-text-primary); + /* ... */ +} + +/* Light theme */ +[data-theme="light"] { + --bg-primary: var(--light-bg-primary); + --text-primary: var(--light-text-primary); + /* ... */ +} +``` + +--- + +## CSS Accessibility Requirements + +**Always respect `prefers-reduced-motion` for animations**. This is required by WCAG 2.1 SC 2.3.3 (Animation from Interactions) for users with vestibular disorders. + +```css +/* ✅ CORRECT: Completely disable animation */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0s !important; + transition-duration: 0s !important; + scroll-behavior: auto !important; + } +} + +/* ❌ WRONG: Near-zero values still trigger animation */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; /* Still plays briefly! */ + } +} +``` + +**Why `0s` not `0.01ms`**: + +- `0s` truly disables the animation—no visual flicker, no animation callbacks +- `0.01ms` was a legacy workaround for old browser bugs that is now obsolete +- Semantically clearer: `0s` means "no animation" while `0.01ms` implies "very fast animation" + +--- + +## CSS Selector Scoping Consistency + +**CRITICAL**: When styling components in a framework (MkDocs, Jekyll themes, etc.), use consistent scoping for related rules. Inconsistent prefixes cause specificity bugs. + +```css +/* ❌ WRONG: Inconsistent scoping - some rules use .md-typeset, some don't */ +.md-typeset table { + width: 100%; +} +.md-typeset th { + background: var(--bg-secondary); +} +td { + /* Missing .md-typeset prefix! */ + padding: 0.5rem; +} + +/* ✅ CORRECT: All related rules use same scoping */ +.md-typeset table { + width: 100%; +} +.md-typeset th { + background: var(--bg-secondary); +} +.md-typeset td { + padding: 0.5rem; +} +``` + +**Why this matters:** + +1. **Specificity consistency** — All rules have same weight, predictable cascade +2. **Scope isolation** — Styles only affect intended context, don't leak +3. **Maintainability** — Easy to identify which rules belong together + +**Rule**: If one rule in a group uses a parent scope (`.md-typeset`, `.markdown-body`, etc.), ALL related rules must use the same scope. + +--- + +## Avoid Overly Broad Structural Selectors + +When targeting specific page elements (banners, hero sections, featured content), use pseudo-classes to prevent unintended side effects on similar elements: + +```css +/* ❌ WRONG: Affects ALL centered paragraphs including badges */ +section p[align="center"] { + margin: 1rem auto; + max-width: 800px; +} + +/* ✅ CORRECT: Only affects the first centered paragraph (banner) */ +section p[align="center"]:first-of-type { + margin: 1rem auto; + max-width: 800px; +} +``` + +**Why this matters:** + +1. **Unintended cascade** — Multiple elements may match broad selectors +2. **Structural precision** — `:first-of-type`, `:last-of-type`, `:nth-of-type()` target specific positions +3. **Future-proofing** — Prevents CSS conflicts when page content structure changes + +--- + +## Use ARIA Attributes for JavaScript-Controlled States + +```css +/* ❌ WRONG: CSS class never applied by JavaScript */ +table[data-sortable] th.sort-indicator-active::after { + display: none; +} + +/* ✅ CORRECT: Use ARIA attributes that JavaScript already manages */ +table[data-sortable] th[aria-sort]:not([aria-sort="none"])::after { + display: none; +} +``` + +**Why ARIA over custom classes:** + +1. **Single source of truth** — JavaScript sets ARIA for accessibility; CSS uses same attributes +2. **No orphaned classes** — Can't have CSS targeting a class that JavaScript never applies +3. **Accessibility alignment** — Visual presentation matches what screen readers see + +--- + +## Related Skills + +- [github-pages](./github-pages.md) — Jekyll configuration, markdown links, CI/CD validation +- [markdown-reference](./markdown-reference.md) — Link formatting, escaping, linting rules diff --git a/.llm/skills/github-pages.md b/.llm/skills/github-pages.md index 79afab9d..2d0ab784 100644 --- a/.llm/skills/github-pages.md +++ b/.llm/skills/github-pages.md @@ -187,202 +187,9 @@ Final (correct): ../overview/getting-started (with extension) --- -## CSS Theming for Unified Appearance - -### CSS Variables in `:root` - -**Always define default CSS variables in `:root`** to ensure themes work before JavaScript loads: - -```css -:root { - /* Define ALL theme variables with defaults */ - --bg-primary: #1e1e1e; - --bg-secondary: #252526; - --text-primary: #d4d4d4; - --text-secondary: #b0b0b0; - --border-color: #3c3c3c; - --link-color: #569cd6; - /* ... all other variables */ -} -``` - -### Override Remote Theme Elements Comprehensively - -When using a remote theme (like `pages-themes/minimal`), override ALL structural elements to prevent "box" appearance: - -```css -/* Make all nested elements transparent */ -.wrapper, -.wrapper > *, -.inner, -header, -header *, -section, -section *, -footer, -footer * { - background-color: transparent !important; - box-shadow: none !important; -} - -/* Re-apply backgrounds ONLY to root containers */ -body { - background-color: var(--bg-primary) !important; -} - -header { - background-color: var(--bg-primary) !important; - border-bottom: 1px solid var(--border-color) !important; -} - -section { - background-color: var(--bg-primary) !important; -} - -footer { - background-color: var(--bg-primary) !important; - border-top: 1px solid var(--border-color) !important; -} -``` - -### Theming Best Practices - -| Principle | Implementation | -| ---------------------------- | --------------------------------------------------------------------- | -| Transparent nested elements | Apply `background: transparent` to all children | -| Root-only backgrounds | Apply background colors only to `body`, `header`, `section`, `footer` | -| Consistent color family | Use same `--bg-primary` for all containers | -| No box shadows on containers | Remove `box-shadow` from theme elements | -| Use `!important` sparingly | Required to override remote theme styles | - -### Theme Switching Support - -```css -/* Dark theme (default) */ -[data-theme="dark"] { - --bg-primary: var(--dark-bg-primary); - --text-primary: var(--dark-text-primary); - /* ... */ -} - -/* Light theme */ -[data-theme="light"] { - --bg-primary: var(--light-bg-primary); - --text-primary: var(--light-text-primary); - /* ... */ -} -``` - -### CSS Accessibility Requirements - -**Always respect `prefers-reduced-motion` for animations**. This is required by WCAG 2.1 SC 2.3.3 (Animation from Interactions) for users with vestibular disorders. - -```css -/* ✅ CORRECT: Completely disable animation */ -@media (prefers-reduced-motion: reduce) { - *, - *::before, - *::after { - animation-duration: 0s !important; - transition-duration: 0s !important; - scroll-behavior: auto !important; - } -} - -/* ❌ WRONG: Near-zero values still trigger animation */ -@media (prefers-reduced-motion: reduce) { - * { - animation-duration: 0.01ms !important; /* Still plays briefly! */ - } -} -``` - -**Why `0s` not `0.01ms`**: - -- `0s` truly disables the animation—no visual flicker, no animation callbacks -- `0.01ms` was a legacy workaround for old browser bugs that is now obsolete -- Semantically clearer: `0s` means "no animation" while `0.01ms` implies "very fast animation" - -### CSS Selector Scoping Consistency - -**CRITICAL**: When styling components in a framework (MkDocs, Jekyll themes, etc.), use consistent scoping for related rules. Inconsistent prefixes cause specificity bugs. - -```css -/* ❌ WRONG: Inconsistent scoping - some rules use .md-typeset, some don't */ -.md-typeset table { - width: 100%; -} -.md-typeset th { - background: var(--bg-secondary); -} -td { - /* Missing .md-typeset prefix! */ - padding: 0.5rem; -} - -/* ✅ CORRECT: All related rules use same scoping */ -.md-typeset table { - width: 100%; -} -.md-typeset th { - background: var(--bg-secondary); -} -.md-typeset td { - padding: 0.5rem; -} -``` - -**Why this matters:** - -1. **Specificity consistency** — All rules have same weight, predictable cascade -2. **Scope isolation** — Styles only affect intended context, don't leak -3. **Maintainability** — Easy to identify which rules belong together - -**Rule**: If one rule in a group uses a parent scope (`.md-typeset`, `.markdown-body`, etc.), ALL related rules must use the same scope. - -### Avoid Overly Broad Structural Selectors - -When targeting specific page elements (banners, hero sections, featured content), use pseudo-classes to prevent unintended side effects on similar elements: - -```css -/* ❌ WRONG: Affects ALL centered paragraphs including badges */ -section p[align="center"] { - margin: 1rem auto; - max-width: 800px; -} - -/* ✅ CORRECT: Only affects the first centered paragraph (banner) */ -section p[align="center"]:first-of-type { - margin: 1rem auto; - max-width: 800px; -} -``` - -**Why this matters:** - -1. **Unintended cascade** — Multiple elements may match broad selectors -2. **Structural precision** — `:first-of-type`, `:last-of-type`, `:nth-of-type()` target specific positions -3. **Future-proofing** — Prevents CSS conflicts when page content structure changes - -**Related pattern - Use ARIA attributes for JavaScript-controlled states:** - -```css -/* ❌ WRONG: CSS class never applied by JavaScript */ -table[data-sortable] th.sort-indicator-active::after { - display: none; -} - -/* ✅ CORRECT: Use ARIA attributes that JavaScript already manages */ -table[data-sortable] th[aria-sort]:not([aria-sort="none"])::after { - display: none; -} -``` - -**Why ARIA over custom classes:** +## CSS Theming -1. **Single source of truth** — JavaScript sets ARIA for accessibility; CSS uses same attributes -2. **No orphaned classes** — Can't have CSS targeting a class that JavaScript never applies -3. **Accessibility alignment** — Visual presentation matches what screen readers see +For comprehensive CSS theming guidance including theme switching, accessibility requirements, and selector best practices, see [github-pages-theming](./github-pages-theming.md). --- @@ -514,6 +321,7 @@ npx prettier --write "**/*.md" ## Related Skills +- [github-pages-theming](./github-pages-theming.md) — CSS theming, accessibility, selectors - [markdown-reference](./markdown-reference.md) — Link formatting, escaping, linting rules - [update-documentation](./update-documentation.md) — Documentation standards and CHANGELOG format - [formatting](./formatting.md) — CSharpier, Prettier, markdownlint workflow