@ethlete/agent-rules 0.1.0-next.2 → 0.1.0-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +275 -0
  2. package/README.md +350 -29
  3. package/THIRD-PARTY-LICENSES.md +35 -0
  4. package/content/git-hooks/post-checkout.sh +10 -0
  5. package/content/git-hooks/pre-push.sh +5 -0
  6. package/content/hooks/context-warning.py +766 -108
  7. package/content/hooks/subagent-model-policy.py +193 -0
  8. package/content/output-styles/ste-clarity.md +131 -0
  9. package/content/rules/app-styling.md +59 -0
  10. package/content/rules/comments.md +53 -20
  11. package/content/rules/lint-and-format.md +6 -5
  12. package/content/rules/nx-layout.md +47 -0
  13. package/content/rules/reactive-state.md +1 -1
  14. package/content/rules/styling.md +9 -7
  15. package/content/rules/subagent-models.md +29 -0
  16. package/content/skills/angular-patterns/SKILL.md +30 -7
  17. package/content/skills/api-source/SKILL.md +130 -0
  18. package/content/skills/app-testing/SKILL.md +141 -0
  19. package/content/skills/codex-subagent/SKILL.md +90 -0
  20. package/content/skills/codex-subagent/codex-agent.mjs +229 -0
  21. package/content/skills/design-exploration/SKILL.md +205 -0
  22. package/content/skills/design-exploration/check-story.mjs +139 -0
  23. package/content/skills/design-exploration/shoot-template.mjs +61 -0
  24. package/content/skills/domain-modeling/ADR-FORMAT.md +47 -0
  25. package/content/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  26. package/content/skills/domain-modeling/SKILL.md +80 -0
  27. package/content/skills/figma-export/SKILL.md +191 -0
  28. package/content/skills/figma-export/dump-figma-layers.py +83 -0
  29. package/content/skills/figma-export/dump-figma-svg.py +235 -0
  30. package/content/skills/figma-export/measure-template.mjs +87 -0
  31. package/content/skills/git-commit/SKILL.md +6 -7
  32. package/content/skills/git-flow/SKILL.md +87 -0
  33. package/content/skills/grill-with-docs/SKILL.md +13 -0
  34. package/content/skills/grilling/SKILL.md +34 -0
  35. package/content/skills/handoff/SKILL.md +74 -4
  36. package/content/skills/query/SKILL.md +165 -64
  37. package/content/skills/rxjs-signals/SKILL.md +31 -4
  38. package/content/skills/sdk-docs/SKILL.md +50 -14
  39. package/content/skills/sdk-local-build/SKILL.md +30 -10
  40. package/content/skills/sdk-local-build/sdk-local-baseline.mjs +64 -0
  41. package/content/skills/sdk-source/SKILL.md +49 -21
  42. package/content/skills/sdk-update/SKILL.md +96 -0
  43. package/content/skills/story-styling/SKILL.md +10 -8
  44. package/content/skills/styleguide/SKILL.md +12 -7
  45. package/content/skills/styleguide/assets.md +54 -0
  46. package/content/skills/styleguide/changesets.md +17 -0
  47. package/content/skills/styleguide/file-structure.md +73 -0
  48. package/content/skills/styleguide/lint-rule-lookup.md +51 -0
  49. package/content/skills/styleguide/storybook-structure.md +25 -0
  50. package/content/skills/theming/SKILL.md +41 -28
  51. package/content/skills/timetrack/SKILL.md +397 -0
  52. package/content/skills/verify-in-app/SKILL.md +107 -0
  53. package/migrations/app-styling-utilities.md +63 -0
  54. package/migrations/list-state-query-form.md +20 -0
  55. package/migrations/nx-layout.md +29 -0
  56. package/migrations/sdk-components-over-hand-built-ui.md +27 -0
  57. package/migrations/search-query-field.md +52 -0
  58. package/migrations.json +48 -0
  59. package/package.json +16 -2
  60. package/src/index.js +63 -28
  61. package/src/index.js.map +1 -1
  62. package/src/lib/cli-args.d.ts +9 -0
  63. package/src/lib/cli-args.js +48 -0
  64. package/src/lib/cli-args.js.map +1 -0
  65. package/src/lib/commitlint.d.ts +10 -0
  66. package/src/lib/commitlint.js +51 -0
  67. package/src/lib/commitlint.js.map +1 -0
  68. package/src/lib/config.d.ts +38 -4
  69. package/src/lib/config.js +84 -8
  70. package/src/lib/config.js.map +1 -1
  71. package/src/lib/filter.d.ts +2 -0
  72. package/src/lib/filter.js +4 -4
  73. package/src/lib/filter.js.map +1 -1
  74. package/src/lib/frontmatter.d.ts +2 -0
  75. package/src/lib/frontmatter.js +33 -5
  76. package/src/lib/frontmatter.js.map +1 -1
  77. package/src/lib/git-flow/build.d.ts +35 -0
  78. package/src/lib/git-flow/build.js +24 -0
  79. package/src/lib/git-flow/build.js.map +1 -0
  80. package/src/lib/git-flow/config.d.ts +59 -0
  81. package/src/lib/git-flow/config.js +50 -0
  82. package/src/lib/git-flow/config.js.map +1 -0
  83. package/src/lib/git-flow/index.d.ts +6 -0
  84. package/src/lib/git-flow/index.js +10 -0
  85. package/src/lib/git-flow/index.js.map +1 -0
  86. package/src/lib/git-flow/parse.d.ts +49 -0
  87. package/src/lib/git-flow/parse.js +300 -0
  88. package/src/lib/git-flow/parse.js.map +1 -0
  89. package/src/lib/git-flow/rename.d.ts +24 -0
  90. package/src/lib/git-flow/rename.js +70 -0
  91. package/src/lib/git-flow/rename.js.map +1 -0
  92. package/src/lib/git-flow/start.d.ts +49 -0
  93. package/src/lib/git-flow/start.js +57 -0
  94. package/src/lib/git-flow/start.js.map +1 -0
  95. package/src/lib/git-flow/validate.d.ts +34 -0
  96. package/src/lib/git-flow/validate.js +72 -0
  97. package/src/lib/git-flow/validate.js.map +1 -0
  98. package/src/lib/git-flow-command.d.ts +4 -0
  99. package/src/lib/git-flow-command.js +157 -0
  100. package/src/lib/git-flow-command.js.map +1 -0
  101. package/src/lib/git-flow-repair.d.ts +17 -0
  102. package/src/lib/git-flow-repair.js +157 -0
  103. package/src/lib/git-flow-repair.js.map +1 -0
  104. package/src/lib/git-flow-start.d.ts +20 -0
  105. package/src/lib/git-flow-start.js +132 -0
  106. package/src/lib/git-flow-start.js.map +1 -0
  107. package/src/lib/git.d.ts +64 -0
  108. package/src/lib/git.js +131 -0
  109. package/src/lib/git.js.map +1 -0
  110. package/src/lib/gitlab.d.ts +35 -0
  111. package/src/lib/gitlab.js +108 -0
  112. package/src/lib/gitlab.js.map +1 -0
  113. package/src/lib/index.d.ts +2 -0
  114. package/src/lib/index.js +2 -0
  115. package/src/lib/index.js.map +1 -1
  116. package/src/lib/migrate.js +1 -1
  117. package/src/lib/migrate.js.map +1 -1
  118. package/src/lib/output-style-command.d.ts +3 -0
  119. package/src/lib/output-style-command.js +69 -0
  120. package/src/lib/output-style-command.js.map +1 -0
  121. package/src/lib/output-style.d.ts +38 -0
  122. package/src/lib/output-style.js +134 -0
  123. package/src/lib/output-style.js.map +1 -0
  124. package/src/lib/owned-paths.js +27 -3
  125. package/src/lib/owned-paths.js.map +1 -1
  126. package/src/lib/package-runner.d.ts +3 -0
  127. package/src/lib/package-runner.js +69 -0
  128. package/src/lib/package-runner.js.map +1 -0
  129. package/src/lib/plain-text.d.ts +9 -0
  130. package/src/lib/plain-text.js +22 -0
  131. package/src/lib/plain-text.js.map +1 -0
  132. package/src/lib/plan.d.ts +6 -6
  133. package/src/lib/plan.js +147 -40
  134. package/src/lib/plan.js.map +1 -1
  135. package/src/lib/prompt.d.ts +8 -0
  136. package/src/lib/prompt.js +27 -0
  137. package/src/lib/prompt.js.map +1 -0
  138. package/src/lib/render.d.ts +24 -2
  139. package/src/lib/render.js +39 -10
  140. package/src/lib/render.js.map +1 -1
  141. package/src/lib/sync.d.ts +0 -1
  142. package/src/lib/sync.js +23 -15
  143. package/src/lib/sync.js.map +1 -1
  144. package/src/lib/targets/agents-skills.js +1 -1
  145. package/src/lib/targets/agents-skills.js.map +1 -1
  146. package/src/lib/targets/claude-hooks.d.ts +1 -23
  147. package/src/lib/targets/claude-hooks.js +17 -85
  148. package/src/lib/targets/claude-hooks.js.map +1 -1
  149. package/src/lib/targets/claude.js +1 -2
  150. package/src/lib/targets/claude.js.map +1 -1
  151. package/src/lib/targets/codex-hooks.d.ts +12 -0
  152. package/src/lib/targets/codex-hooks.js +34 -0
  153. package/src/lib/targets/codex-hooks.js.map +1 -0
  154. package/src/lib/targets/codex.js +4 -4
  155. package/src/lib/targets/codex.js.map +1 -1
  156. package/src/lib/targets/copilot.js +3 -3
  157. package/src/lib/targets/copilot.js.map +1 -1
  158. package/src/lib/targets/cursor.js +2 -2
  159. package/src/lib/targets/cursor.js.map +1 -1
  160. package/src/lib/targets/git-hooks.d.ts +24 -0
  161. package/src/lib/targets/git-hooks.js +71 -0
  162. package/src/lib/targets/git-hooks.js.map +1 -0
  163. package/src/lib/targets/hooks-shared.d.ts +58 -0
  164. package/src/lib/targets/hooks-shared.js +128 -0
  165. package/src/lib/targets/hooks-shared.js.map +1 -0
  166. package/src/lib/targets/shared.d.ts +1 -9
  167. package/src/lib/targets/shared.js +4 -8
  168. package/src/lib/targets/shared.js.map +1 -1
  169. package/src/lib/timetrack-command.d.ts +11 -0
  170. package/src/lib/timetrack-command.js +1055 -0
  171. package/src/lib/timetrack-command.js.map +1 -0
  172. package/src/lib/timetrack-snapshot.d.ts +55 -0
  173. package/src/lib/timetrack-snapshot.js +120 -0
  174. package/src/lib/timetrack-snapshot.js.map +1 -0
  175. package/src/lib/timetrack.d.ts +561 -0
  176. package/src/lib/timetrack.js +271 -0
  177. package/src/lib/timetrack.js.map +1 -0
  178. package/content/skills/styleguide/STYLEGUIDE.md +0 -520
@@ -0,0 +1,73 @@
1
+ # File structure
2
+
3
+ Read this file when placing routes, views, components, providers, or local utilities.
4
+
5
+ Mirror the route tree in folders and suffix routing components with `-view`:
6
+
7
+ ```ts
8
+ import { Routes } from '@angular/router';
9
+
10
+ export const SHOP_ROUTES: Routes = [
11
+ {
12
+ path: 'items',
13
+ loadComponent: () =>
14
+ import('./items-list-view/items-list-view.component').then((module) => module.ItemsListViewComponent),
15
+ },
16
+ {
17
+ path: 'items/:id',
18
+ loadComponent: () =>
19
+ import('./item-detail-host-view/item-detail-host-view.component').then(
20
+ (module) => module.ItemDetailHostViewComponent,
21
+ ),
22
+ children: [
23
+ {
24
+ path: '',
25
+ loadComponent: () =>
26
+ import('./item-detail-host-view/item-detail-view/item-detail-view.component').then(
27
+ (module) => module.ItemDetailViewComponent,
28
+ ),
29
+ },
30
+ {
31
+ path: 'reviews',
32
+ loadComponent: () =>
33
+ import('./item-detail-host-view/item-reviews-view/item-reviews-view.component').then(
34
+ (module) => module.ItemReviewsViewComponent,
35
+ ),
36
+ },
37
+ ],
38
+ },
39
+ ];
40
+ ```
41
+
42
+ Use these placement rules:
43
+
44
+ - Put reusable view-level pieces in `components/`.
45
+ - Put children used only by one parent in that parent's `partials/`.
46
+ - Put generic presentation-only pieces in `uikit/`.
47
+ - Put application-shell pieces in `shell/`.
48
+ - Keep a directive, pipe, provider, form configuration, or utility beside its narrowest
49
+ consumer. Move it upward only when more consumers appear.
50
+ - Use simple utility names such as `items-list-filter-form.ts`, not `.utils.ts`.
51
+ - Give exportable folders an `index.ts`, but import source files directly. Do not import
52
+ a parent barrel from its subdirectory.
53
+ - Keep application projects thin; move shared or domain logic into buildable libraries
54
+ with clear import paths.
55
+
56
+ ```plaintext
57
+ shop/
58
+ ├── items-list-view/
59
+ │ ├── components/
60
+ │ │ └── item-card/
61
+ │ │ ├── partials/
62
+ │ │ │ ├── item-image/
63
+ │ │ │ └── item-price/
64
+ │ │ ├── item-card.component.ts
65
+ │ │ └── item-card.component.html
66
+ │ ├── items-list-filter-form.ts
67
+ │ └── items-list-view.component.ts
68
+ └── item-detail-host-view/
69
+ ├── item-detail-view/
70
+ ├── item-reviews-view/
71
+ ├── item-detail.provider.ts
72
+ └── item-detail-host-view.component.ts
73
+ ```
@@ -0,0 +1,51 @@
1
+ # Lint rule lookup
2
+
3
+ Read this file only to explain a lint result or identify which rule owns a mechanical
4
+ convention. Run lint with `--fix`; do not hand-check this table before linting.
5
+
6
+ | Convention | Rule |
7
+ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
+ | No `any` / `$any()`; narrow `unknown` | `@typescript-eslint/no-explicit-any`, `@angular-eslint/template/no-any` |
9
+ | Static strings and booleans use attributes | `@angular-eslint/template/prefer-static-string-properties`, `ethlete/prefer-static-boolean-properties` |
10
+ | `type`, not `interface` (module augmentations stay interfaces) | `ethlete/consistent-type-definitions` |
11
+ | No `enum` or `const enum` | `ethlete/no-enum` |
12
+ | `const` by default; one declaration per statement | `no-var`, `prefer-const`, `one-var` |
13
+ | Strict equality | `eqeqeq` |
14
+ | Maximum two positional parameters | `max-params` |
15
+ | No type-only imports | `ethlete/no-type-only-import` |
16
+ | Descriptive `T`-prefixed generic names | `@typescript-eslint/naming-convention` |
17
+ | No `async` / `await` | `ethlete/no-async-await` |
18
+ | Arrow functions standalone; methods in classes | `no-restricted-syntax` |
19
+ | Blank line before a multiline guard return | `ethlete/guard-return-newline` |
20
+ | No trivially inferable return type | `ethlete/no-trivial-return-type` |
21
+ | Member and local naming conventions | `@typescript-eslint/naming-convention`, `ethlete/no-leading-underscore-class-member`, `ethlete/no-screaming-case-local` |
22
+ | Class constants are `readonly` and upper case | `ethlete/class-constant-property` |
23
+ | No `readonly` on reactive members | `ethlete/no-readonly-signal` |
24
+ | Injected and template-visible member accessibility | `ethlete/inject-member-accessibility`, `ethlete/template-member-accessibility` |
25
+ | No inject chains, pure aliases, or trivial wrappers | `ethlete/no-inject-chain`, `ethlete/no-member-alias`, `ethlete/no-trivial-wrapper-method` |
26
+ | No unused private or protected members | `ethlete/no-unused-class-member` |
27
+ | Pure module-scope provider calls | `ethlete/no-impure-top-level-provider` |
28
+ | No redundant `@internal` | `ethlete/no-redundant-internal` |
29
+ | Observable names end in `$` | `ethlete/require-dollar-suffix` |
30
+ | No subscribe body, subscribe in pipe, or RxJS in signal derivations | `ethlete/no-subscribe-with-body`, `ethlete/no-subscribe-in-pipe`, `ethlete/no-rxjs-in-effect` |
31
+ | `takeUntilDestroyed()` is the last operator in its pipe | `ethlete/take-until-destroyed-last` |
32
+ | Effect teardown uses `onCleanup` or `DestroyRef` | `ethlete/no-effect-cleanup-return` |
33
+ | Prefer `linkedSignal` for writable derived state | `ethlete/prefer-linked-signal` |
34
+ | Global component CSS encapsulation | `ethlete/require-view-encapsulation-none` |
35
+ | Angular-version-correct change detection metadata | `ethlete/require-on-push-change-detection`, `ethlete/no-redundant-on-push-change-detection` |
36
+ | No redundant standalone flag or empty metadata arrays | `ethlete/no-standalone-flag`, `ethlete/no-empty-angular-metadata-arrays` |
37
+ | No legacy lifecycle hooks or decorators | `no-restricted-syntax`, `ethlete/no-legacy-angular-decorators` |
38
+ | No injectable services, guards, or resolvers | `no-restricted-syntax` |
39
+ | Output naming | `@angular-eslint/no-output-on-prefix`, `@angular-eslint/no-output-native`, `ethlete/prefer-present-tense-output` |
40
+ | Inputs do not collide with global HTML attributes | `ethlete/no-native-html-input-name` |
41
+ | No pipe logic | `ethlete/no-pipe-logic` |
42
+ | Class members and decorator metadata stay ordered | `ethlete/class-member-order`, `ethlete/angular-decorator-property-order` |
43
+ | Routing views use `-view` / `ViewComponent` | `ethlete/enforce-routing-view-naming` |
44
+ | No direct browser globals, DOM queries, native observers, or cookies | `no-restricted-globals`, `ethlete/no-direct-dom-manipulation`, `ethlete/no-dom-query`, `ethlete/no-native-observers`, `ethlete/no-document-cookie` |
45
+ | No barrel imports | `no-restricted-syntax` |
46
+ | Prefer the SDK wrappers for platform utilities | `ethlete/prefer-clone-equal`, `ethlete/prefer-rxjs-timer`, `ethlete/prefer-match-media`, `ethlete/prefer-viewport-size`, `ethlete/no-angular-seo-services`, `ethlete/no-locale-id`, `ethlete/no-angular-router-api` |
47
+
48
+ Judgment still belongs outside lint: name things after their behavior, use an object
49
+ parameter after two positional parameters, expose injected members directly instead of
50
+ aliasing them, and use `/** @internal */` only on technically public library API that
51
+ must be stripped from declarations.
@@ -0,0 +1,25 @@
1
+ # Storybook structure
2
+
3
+ Read this file when placing a `*.stories.ts` file or code used only to render stories.
4
+
5
+ - Keep the `*.stories.ts` file beside the component it documents.
6
+ - Put private host components, dummy data, and story-only helpers in `storybook/`.
7
+ - Never export Storybook-only code from the component's public barrel.
8
+ - A private `storybook/index.ts` may simplify imports into the adjacent story, but no
9
+ production source may import it.
10
+
11
+ ```plaintext
12
+ settings-form/
13
+ ├── storybook/
14
+ │ ├── settings-form-storybook.component.ts
15
+ │ ├── settings-form-storybook.component.html
16
+ │ ├── settings-form-dummy-data.ts
17
+ │ └── index.ts
18
+ ├── settings-form.component.ts
19
+ ├── settings-form.component.html
20
+ ├── settings-form.component.stories.ts
21
+ └── index.ts
22
+ ```
23
+
24
+ The story file stays at the component root; only its private support code goes into
25
+ `storybook/`.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: theming
3
- description: The two runtime theming systems in @ethlete/core - surface theming (elevation-aware neutrals) and color theming (semantic accent palettes) - how to register them in an app and how components must consume them. Read BEFORE writing or reviewing CSS that involves any color, background, border, or interaction state, and when wiring theme context across overlay/portal boundaries.
3
+ description: The two runtime theming systems in @ethlete/core - surface theming (elevation-aware neutrals) and color theming (semantic accent palettes). Read BEFORE writing or reviewing CSS involving color, background, border, or interaction state, and when wiring theme context across overlay/portal boundaries.
4
4
  kind: skill
5
5
  scope: consumer
6
6
  requires: ['@ethlete/core']
@@ -37,16 +37,16 @@ The generated CSS defines the raw vars on `.et-surface--<name>` / `.et-color--<n
37
37
  classes (plus `:root` defaults) and derives the public tokens below on `:root` **and**
38
38
  every scope class - so the tokens are always resolvable and components just read them.
39
39
 
40
- **Theme names are yours.** `brand`, `danger`, `neutral`, `dark-elevated` are only
41
- examples. Never hardcode a theme-name union in a component type, a doc or an example.
42
- The portable handle is the theme **`type`**: `injectErrorTheme()` finds whichever theme
43
- the app registered with `type: 'error'`.
40
+ **Theme names are yours.** Never hardcode them as an SDK-defined union or reusable API
41
+ contract. App-specific docs may name their own themes when they label them as app values.
42
+ The portable handle is the theme **`type`**: `injectSemanticColorTheme('error')` finds
43
+ whichever theme the app registered with `type: 'error'`.
44
44
 
45
45
  ## Tokens components may consume
46
46
 
47
47
  Use these **derived** tokens - never the raw `--et-surface-background` /
48
- `--et-color-primary` channel triplets, and never a hardcoded color (a static fallback
49
- _after_ the token is fine).
48
+ `--et-color-primary` channel triplets. Never use a hardcoded color as the primary value.
49
+ A static fallback inside `var(--token, <fallback>)` is permitted, but not required.
50
50
 
51
51
  Surface (each exists as `-solid` = usable color, `-rgb` = `R G B` channels):
52
52
 
@@ -61,12 +61,12 @@ Surface (each exists as `-solid` = usable color, `-rgb` = `R G B` channels):
61
61
 
62
62
  Color (from the nearest `[etProvideColor]` scope):
63
63
 
64
- | Token | Use for |
65
- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
66
- | `--et-theme-color-primary` | filled backgrounds; **opacity-aware** - set `--et-theme-color-primary-opacity: 0.16` etc. per state to tint without changing the color |
67
- | `--et-theme-color-primary-solid` | accents at full strength: focus borders, selected marks, spinners |
68
- | `--et-theme-color-on-primary` | text/icons on a primary-filled background |
69
- | `--et-theme-color-ink-solid` | primary-tinted text/border on transparent/tonal fills |
64
+ | Token | Use for |
65
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
+ | `--et-theme-color-primary` | filled backgrounds on an element you do **not** tint. To tint per state, set `--et-theme-color-primary-opacity: 0.16` and compose the color yourself: `rgb(var(--et-theme-color-primary-rgb) / var(--et-theme-color-primary-opacity))`. The alias is substituted at the `et-color--*` scope, so an inherited value carries the scope's opacity, never the element's |
67
+ | `--et-theme-color-primary-solid` | accents at full strength: focus borders, selected marks, spinners |
68
+ | `--et-theme-color-on-primary` | text/icons on a primary-filled background |
69
+ | `--et-theme-color-ink-solid` | primary-tinted text/border on transparent/tonal fills |
70
70
 
71
71
  Interaction-state variants (`--et-surface-interaction-{hover,focus,active,disabled}-solid`)
72
72
  resolve automatically per CSS state when the element has `[etSurfaceInteractive]`;
@@ -75,8 +75,8 @@ the interactive element itself, never on a wrapper.
75
75
 
76
76
  ## Providing context
77
77
 
78
- - `[etProvideSurface]="'dark-elevated'"` / `[etAutoSurface]` (auto-picks the next
79
- elevation) set the surface scope; `[etProvideColor]="'brand'"` sets the color scope.
78
+ - `[etProvideSurface]="surfaceThemeName"` / `[etAutoSurface]` (auto-picks the next
79
+ elevation) set the surface scope; `[etProvideColor]="colorThemeName"` sets the color scope.
80
80
  A component that owns a themed region usually adds `ProvideColorDirective` /
81
81
  `ProvideSurfaceDirective` as `hostDirectives`.
82
82
  - **Detached overlay panes (menu, dialog, tooltip…) do not inherit DOM context.**
@@ -85,10 +85,17 @@ the interactive element itself, never on a wrapper.
85
85
  color and `resolveSurfaceByElevation(themes, type, elevation + 1)` for the surface.
86
86
  - **Semantic colors come through DI, not CSS.** There is no global "error color"
87
87
  variable - error/warning/success are just color themes. To render something in the
88
- error color, `injectErrorTheme()` (it throws if the app registered no `type: 'error'`
89
- theme) and either bind it (`[etProvideColor]="errorColorTheme"`) or force it
90
- programmatically (`provideColor.forceColor(theme)` / `clearForcedColor()`). Inside
91
- that scope, `--et-theme-color-primary-*` _is_ the error color.
88
+ error color, `injectSemanticColorTheme('error')` (reading it throws if the app
89
+ registered no `type: 'error'` theme) and either bind it
90
+ (`[etProvideColor]="errorColorTheme()"`) or force it programmatically
91
+ (`provideColor.forceColor(theme)` / `clearForcedColor()`). Inside that scope,
92
+ `--et-theme-color-primary-*` _is_ the error color.
93
+ - **`injectSemanticColorTheme(type)` follows the surface**: it is a signal of the theme
94
+ the nearest surface names in `SurfaceTheme.semanticColorThemes` (e.g.
95
+ `{ success: 'success-on-light' }`, an extra theme registered without a `type`), else
96
+ the theme of that `type`. Never add per-surface logic to a color theme or new CSS vars
97
+ for it. `injectErrorTheme()`, `injectWarningTheme()` and `injectSuccessTheme()` are
98
+ deprecated: they ignore the surface.
92
99
 
93
100
  ## Pitfalls
94
101
 
@@ -96,15 +103,21 @@ the interactive element itself, never on a wrapper.
96
103
  declared via `@property` can never default to a theme token. If the default should
97
104
  come from the theme, don't declare an `@property` - consume the theme token directly
98
105
  (optionally behind a `--_et-*` indirection var).
106
+ - `@property` `initial-value` also cannot use a **font-relative or container unit**
107
+ (`em`, `rem`, `ex`, `ch`, `lh`, `cap`, `ic`, `cq*`). The value must be computationally
108
+ independent, so the browser drops the whole rule and leaves the token unregistered -
109
+ with no error. Percentages and viewport units (`vh`, `vw`, `dvh`) are fine. When the
110
+ default has to be relative, use `syntax: '*'` with no `initial-value` and put the
111
+ default in a fallback at each use site: `var(--et-skeleton-size, 1em)`.
99
112
  - `--et-theme-color-primary-*` always resolves to the **nearest color scope**. A
100
113
  hardcoded semantic color in CSS can't be replaced by it unless the right theme is
101
114
  provided on that element.
102
- - Keep a static fallback (`var(--et-surface-border-solid, rgb(255 255 255 / 0.1))`) so
103
- components degrade in theme-less setups. `injectErrorTheme()` is the exception: it is
104
- a hard requirement wherever it is used.
105
- - **Cascade layers, not `:where()`, are what let a Tailwind utility override component
106
- CSS.** Wrap every component CSS file in `@layer components { … }`; `:where()` only
107
- flattens a component's own modifiers to single-class weight. See the `styling` rule.
108
-
109
- Styling a **story** file rather than a component? The colour rule is the same, but the
110
- Tailwind side has its own traps - {%skill:story-styling%}.
115
+ - A static fallback (`var(--et-surface-border-solid, rgb(255 255 255 / 0.1))`) is
116
+ permitted for theme-less setups, but themes make it unnecessary. `injectSemanticColorTheme()`
117
+ is a hard requirement wherever it is read.
118
+ - **Cascade layers, not `:where()`, decide who wins against SDK component CSS.** SDK
119
+ styles live in `@layer components`, so a utility or unlayered app CSS overrides them.
120
+ An app rule inside `@layer components` loses. See the `app-styling` rule.
121
+
122
+ Styling a **story** file rather than a component? The colour rule is the same. Check the
123
+ repository's Storybook guidance before assuming a Tailwind utility exists.