Post-Tailwind-v4 SCSS cleanup: 280 → 128 stylesheets#5357
Merged
norman-abramovitz merged 27 commits intoMay 21, 2026
Merged
Conversation
Neither file was loaded by its component:
- card-app-status.component.scss: parent .ts has no styleUrls,
so .card-app-status__large { font-size: 16px } never applied.
- custom-expansion-panel.component.scss: stale duplicate of the
inline styles: [...] block already declared on the @component.
Found via SCSS classifier styleUrls cross-reference. No callers
in the tree reference either path.
Each component .scss either declared rules whose selectors never matched any element in the component's template (dead) or declared trivial single-class rules that translate directly to Tailwind utility classes in the template. Migration per file: - delete the .scss - remove styleUrls from the @component decorator - where the rule was live: replace the SCSS class on the element with the equivalent utility string Net: 35 .scss files deleted, no behavioral change. Production build passes with 0 errors. Bundle transfer size unchanged. SCSS count in src/frontend/packages: 281 -> 244.
The classifier's enhanced dead-rule check (cross-references every styleUrls
consumer's template + .ts) caught these: their selectors target nothing in
any consumer's markup. They survived earlier Class A passes because they
had bare-tag-nesting (`mat-icon { ... }`, `div { > span { ... } }`) which
the classifier treated as Class B, but the bare tags themselves were also
absent from the templates after v4 work.
Removed:
- cf-autoscaler/.../edit-autoscaler-policy-step2.component.scss
- cf-autoscaler/.../app-autoscaler-metric-chart-card.component.scss
- cloud-foundry/.../table-cell-confirm-org-space.component.scss
- kubernetes/.../kubernetes-node-ips.component.scss
- kubernetes/.../kubernetes-node-labels.component.scss
- kubernetes/.../kubernetes-node-link.component.scss
Each .ts loses its styleUrls entry. No template changes. Production build
passes with 0 errors.
SCSS count in src/frontend/packages: 244 -> 238.
The .scss declared 12 BEM-style rules (.entity-summary, &__img, &__logo, &__sub-header, &__content, etc.) — 10 used in the template, 2 dead. The classifier marked the file Class B because of BEM nesting; flattening each rule's CSS to inline Tailwind utilities on the matching element eliminates the .scss entirely. Migration: - .entity-summary -> my-[10px] - &__header-section -> flex m-[10px] - &__img -> grow-0 shrink-0 basis-16 max-h-16 self-center h-16 object-contain w-16 - &__logo -> grow-0 shrink-0 basis-16 max-h-16 text-[54px] - &__header-inner -> flex-1 ml-[10px] - &__header-wrapper -> flex items-baseline - &__header -> m-0 - &__header-info -> text-xl ml-[10px] opacity-40 - &__sub-header -> text-base -mt-[3px] opacity-60 - &__sub-text -> text-base opacity-60 pt-[10px] - &__content -> mt-0 -mx-[20px] -mb-[20px] pt-0 px-[20px] pb-[20px] - &__dashboard, &__spacing dropped (dead) BEM class names dropped from template — no external CSS or ::ng-deep references found across the codebase. Production build passes with 0 errors. SCSS count: 238 -> 237.
Manual verification across the git and cf-autoscaler packages caught
three additional files whose selectors are absent from their consumers'
templates. The classifier missed these because nested bare-tag rules
(`.parent__icon img { ... }`) were treated as live when any `<img>`
appears in the template, even when the `.parent__icon` wrapper itself
is absent.
Removed:
- git/.../git-endpoint-details.component.scss
- git/.../github-commit-author.component.scss
- cf-autoscaler/.../card-autoscaler-default.component.scss
Each .ts loses its styleUrls entry. No template changes. Production
build passes with 0 errors.
SCSS count in src/frontend/packages: 237 -> 234.
Each file's class selectors flattened into the template, nested bare-tag rules dropped (dead targets) or inlined onto matching elements. Production build passes with 0 errors. Per file: panel.component - 5 simple @apply classes (.panel, --background, --container, --border, __title) inlined; ngClass map switched from BEM names to utility strings so the conditional behavior is preserved. catalog-tab.component - 2 BEM classes (charts__repos--collapse, --expand) inlined via [ngClass]. `app-list { flex: 4 }` rule dropped — template uses <app-signal-list>, not <app-list>. kubernetes-certs-auth-form.component - .kube-certs-auth__content inlined as `flex flex-col gap-3 pt-4`. Nested textarea rule dropped — template-inlined `min-h-[200px] font-mono text-sm` overrode the SCSS-specified 60-75px range anyway. `> * { margin-bottom: 10px }` dropped — `gap-3` already provides equivalent inter-child spacing. kubernetes-serviceaccount-auth-form.component - .kube-sa-auth__form inlined as `flex flex-col`. Nested textarea rule (font, line-break) inlined onto the textarea as `font-mono [line-break:anywhere]`. kubernetes-resource-list.component - .sub-nav-menu-button / __btn inlined as `rounded ml-5 w-[200px]` on wrapper and `w-full leading-7 py-0 pr-2 pl-3` on the button. __icon class dropped (no rule). `.menu` and `.btn-wrapper` rules dropped — neither selector appears in the template. kubernetes-resource-viewer.component - .resource-preview__side-by-side inlined as `flex space-x-10` (replaces `app-metadata-item { margin-right: 40px }` nested rule). .resource-preview__header inlined as `flex justify-end`. Nested `mat-icon` rule dropped — template uses `<span class="material- icons">`, not <mat-icon>. kubernetes-pod-containers.component - .pod-container-icon inlined as `flex items-center h-15 w-[50px]`. Nested `mat-icon` rule dropped — template uses <span>, not <mat-icon>. SCSS count in src/frontend/packages: 234 -> 227.
Audit-trail for dropped paths used class-attr / ngClass-literal-key
matching (not bare substring grep). The earlier substring approach
gave false positives against button IDs (e.g. autoscaler-policy-edit
matching id="autoscaler-policy-edit-edit") and Angular component
selectors (e.g. app-metadata matching <app-metadata-item>).
autoscaler-tab-extension.component
- 14 BEM/utility classes flattened to template (.autoscaler-tab,
__actions, __latest-metrics, .app-metadata, .app-metadata-table,
__two-cols, .app-autoscaler-tile-grid-100, .autoscaler-tab-table-
no-record, .autoscaler-tile-events, __no-policy, __header,
.nav-button-with-text, __span, __icon).
- Nested .app-metadata app-metadata-item / :first-child rules
combined as `my-0` on the one app-metadata-item per iteration.
- Dropped as dead (verified absent from template):
* .table-header:first-of-type — no `class="table-header"` in
template; <th> elements have inline `px-6 py-3 ...` utilities
* <table> / <td> bare-tag rules — tables have `min-w-full
divide-y ...`; tds have `px-6 py-4 ...`; the SCSS w-full / pl-2
were redundant or overridden
* .autoscaler-tile-events__header .card-title — no .card-title
class; element is <app-card-title> Angular component (parent's
emulated-encapsulation SCSS cannot pierce into the child
component's rendered output)
* .autoscaler-tile-events__header button — only direct child
under <app-card-header class="autoscaler-tile-events__header">
is <app-card-title>, no <button>
edit-autoscaler-policy-step3.component
- ALL 10 SCSS classes (radio-outer-circle, app-autoscaler-tile-grid-
100, autoscaler-policy-edit, __actions, app-metadata, __two-cols,
autoscaler-policy-edit-recurring, form-field-left, form-field-30,
form-field-50) are absent from the template (which uses .card,
.card-header, .card-title, .form-group, .label, .input, .radio,
.radio-label, etc.). File is fully dead — delete + drop styleUrls.
edit-autoscaler-policy-step4.component
- ALL 8 SCSS classes are absent from the template (same disposition
as step3). File is fully dead — delete + drop styleUrls.
Production build passes with 0 errors.
SCSS count in src/frontend/packages: 227 -> 224.
.form-field { @apply pt-1.5 } targets a class that does not appear in
the template. The template uses <app-form-field> Angular component,
which is a selector, not a `.form-field` CSS class — and Angular's
emulated encapsulation prevents the parent's SCSS from reaching into
the child component's rendered output.
Production build passes with 0 errors.
SCSS count in src/frontend/packages: 224 -> 223.
Verified each dropped path with class-attr / ngClass-literal-key matching against the template. Production build passes with 0 errors. SCSS count: 223 -> 218. table-cell-edit-variable.component - .cell-edit-variable -> w-full - .cell-value-variable -> cursor-pointer - Dropped .form-field .form-field-infix (no .form-field in template; <app-form-field> is an Angular component selector, not a CSS class) cli-info.component - .cli-info -> flex flex-col h-full w-full - .cli-info__content -> flex-1 pb-12 - Dropped .cli-info__footer (not in template) service-icon.component - .service-icon -> self-end flex - .service-icon__padding (conditional via [ngClass]) -> pr-6 - Nested rule for img/mat-icon/app-custom-icon/.custom-icon sizing inlined on the matching elements: <app-custom-icon> gets `text-[48px] h-12 w-12`; <img> gets `h-12 w-12` (font-size no-op on img). Dropped mat-icon and .custom-icon target selectors — not in template. table-cell-service.component - div > div top-level rule inlined as `pb-[5px]` on each direct- child <div> (5 elements) — preserves original padding-bottom behavior including for the last child. - .broker -> flex (2 occurrences) - Nested app-table-cell-service-broker pl-[5px] inlined on the 2 <app-table-cell-service-broker> elements inside .broker. gitscm-tab.component - .gitscm-tab__deployment__commit-warning -> flex flex-row - .gitscm-tab__deployment__commit-warning__msg -> pl-6 - .gitscm-tab__repo__name -> flex items-center break-all - .gitscm-tab__repo__name a -> flex-1 (on the <a> inside) - .gitscm-tab__repo__name--icon -> text-[18px] h-[18px] leading- [18px] ml-[5px] mr-0 w-[18px] - Dropped class-only-no-rule selectors (.gitscm-tab, __deployment, __deployment__commit, __avatar — no styling)
Each class verified live or dead with class-attr / ngClass-literal-key matching. Production build passes with 0 errors. SCSS count: 218 -> 213. cloud-foundry-cell-summary.component - .cell-summary__summary -> mb-5 - .cell-summary__summary__app-metadata -> flex flex-row - .cell-summary__summary__app-metadata--twoCols -> flex-1 - Nested app-metadata-item:first-child mt-0 -> applied to the first <app-metadata-item> in each twoCols div (2 elements) - Dropped class-only-no-rule .cell-summary, __usage, __health cf-admin-add-user-warning.component - .user-warning -> items-center flex text-sm mb-3 px-[22px] py-3 - .user-warning__icon -> text-[22px] mr-[13px] application-delete.component - .app-delete__monitors -> flex flex-col w-full (4 occurrences) - .app-delete__step-table -> w-full (2 occurrences) - Dropped .app-delete__monitor (no class= match in template) cf-service-card.component - .service-card__title -> flex flex-row justify-between w-full - Dropped .service-card (no own rule, just a parent BEM anchor) - Dropped .service-card__icon-link and .service-card__title__link (no class= match in template) add-service-instance-base-step.component - .select-service-step -> w-full - .select-service-step__help -> pb-[10px]
Class-attr / ngClass-literal-key matching used to verify live/dead. Production build passes with 0 errors. SCSS count: 213 -> 209. cloud-foundry-invite-user-link.component - .invite-user-details -> mb-3 px-6 py-1.5 - .invite-user-details__text -> pr-[5px] - .invite-user-details__content -> flex items-baseline - Dropped .invite-user-details__button (no rule defined) cf-endpoint-details.component - .cf-details -> flex flex-col - .cf-details__line -> flex items-center - .cf-details__icon -> flex items-center justify-center mr-2 env-var-view.component - .env-var-view -> flex flex-col - .env-var-view__content__key -> mb-0 - .env-var-view__content__value -> mt-0 whitespace-pre-wrap - .env-var-view__actions -> flex flex-row-reverse justify-self-start - Dropped class-only-no-rule .env-var-view__content service-summary-card.component - .service-summary__title -> flex flex-row justify-between - .service-summary__description -> leading-normal (CSS 1.5em line- height ≡ unitless 1.5 multiplier for non-inheriting context) - Dropped class-only-no-rule .service-summary, __title__link
Class-attr / ngClass-literal-key matching used to verify live/dead. Production build passes with 0 errors. SCSS count: 209 -> 204. card-cf-info.component - .app-metadata -> flex flex-row - .app-metadata__two-cols -> flex-1 (first app-metadata-item gets mt-0) - .app-metadata__address -> flex min-h-6 - .app-metadata__address__value -> items-center flex mr-7 break-all - .user-invites button (nested) -> [line-height:initial] m-0 min-w-[auto] p-0 inlined on each <button> (2 buttons). Wrapper .user-invites class dropped (no own rule). card-cf-org-user-details.component / card-cf-space-details.component - .app-metadata -> flex flex-row - .app-metadata__two-cols -> flex-1 (first app-metadata-item gets mt-0) - .card-title -> font-medium (locally scoped — verified no global .card-title rule in core/cloud-foundry/theme; only same-pattern component-scoped rules exist elsewhere) service-instance-last-op.component - .last-op--row1 -> items-center flex pb-[5px] + conditional justify-end/justify-start via [ngClass] (replaces the `.align-right .last-op--row1` descendant override) - .last-op--item -> conditional pl-[5px] pr-0 / pr-[5px] via [ngClass] on each <app-boolean-indicator> (2 elements) - Dropped class-only-no-rule .last-op, .align-right, .last-op--row2 application-action-bar.component - .summary__sub-nav -> flex w-full - .summary__actions -> flex - .summary__anchor -> flex justify-center (on <a>) - Dropped .summary__sub-nav__poll (no class= match in template)
This empties cloud-foundry Class B. Production build passes with 0
errors. SCSS count: 204 -> 201.
build-tab.component
- .summary__staging-error -> items-center flex (nested mat-icon
rule dropped — template uses <span class="material-icons">)
- .app-metadata -> flex flex-row
- .app-metadata__two-cols -> flex-1 (first app-metadata-item: mt-0)
- .cli-link -> mt-6
- .summary__gitscm -> flex; nested `div { flex: 1 }` inlined as
flex-1 on each of the 2 inner <div>s; nested `app-metadata-item:
first-of-type { mt-0 }` inlined on the first <app-metadata-item>
in each div
- Dropped dead .summary, __cards, __card, __large, __tile_actions,
__actions, __sub-nav, __sub-nav__poll, __anchor (none of these
selectors appear as class= in this template — the build-tab file
was a copy-paste of application-action-bar styles before the
sub-nav block was moved out to its own component; comment in the
original .scss already flags this. Verified no class= matches.)
deploy-application-fs.component
- .deploy-app-local__title -> font-semibold my-6 (2 occurrences)
- .deploy-app-local__input -> h-0 invisible w-0 (2 occurrences)
- .deploy-app-local__info -> mt-6
- .deploy-app-local__indicator -> items-center flex mb-3 (2
occurrences); nested mat-icon rule dropped — template uses <span
class="material-icons">, not <mat-icon>
- .deploy-app-local__next -> pt-6
- Nested `button { margin: 0 1px }` -> mx-px inlined on the 2
<button class="btn btn-primary"> elements
- Dropped .deploy-app-local parent (no own rule)
quota-definition-base.component (cross-consumer)
- This .scss is loaded by two sibling consumer components via
../quota-definition-base/... relative styleUrls — neither has its
own .scss. Both consumer templates flattened identically:
quota-definition.component.html
space-quota-definition.component.html
- .quota-definition-base parent class dropped from both (no own
rule); the page-scope classes (.quota-definition-page,
.space-quota-definition-page) kept on the wrapper div in case
consumers add their own styling later.
- Replacements (all replace_all on both templates):
__name-sub-text -> text-sm opacity-60
__name -> m-0
__basic-services -> flex my-2
__basic-services-label -> mr-[10px] opacity-60
__title -> my-[10px]
__section-header -> my-[10px] opacity-60
- styleUrls entry removed from both consumer .ts files; the .scss
is deleted.
Three pure dead-rule removals plus one near-dead migration.
SCSS files deleted and their styleUrls entries dropped.
- features/setup/domain-mismatch: template already uses
Tailwind utilities; all .domain* classes dead.
- features/setup/upgrade-page: template already Tailwind-only;
all .upgrade* classes dead.
- shared/components/boolean-indicator: SCSS uses
.boolean-indicator__* BEM but template uses single-dash
.boolean-indicator-container; nested mat-icon rules dead
(template uses <span class="material-icons">).
- shared/components/cards/card-boolean-metric: same BEM/dash
mismatch; one live root rule
(.boolean-metric-card { height: 100% }) inlined as h-full
on the root div.
Build green.
All five files were thin BEM wrappers with a single live class each — straightforward Tailwind inlining. - connect-endpoint: drop parent .connect (no rules); replace .connect__auth-type with w-full on app-form-field. - connect-endpoint-dialog/auth-forms/credentials-auth-form: .credentials-auth__form -> flex flex-col. - connect-endpoint-dialog/auth-forms/none-auth-form: .none-auth__form -> flex flex-col mb-6 (24px). - connect-endpoint-dialog/auth-forms/sso-auth-form: .sso-auth__form -> flex flex-col. - create-endpoint/create-endpoint-base-step: .select-step -> w-full; .select-step__help was dead (only referenced in a commented-out <p> block). Build green.
- features/api-keys/api-keys-page: pure dead-rule removal. All nested rules targeted mat-card / mat-card-header / mat-icon, but the template uses app-card / app-card-header / app-custom-icon. - features/metrics/metrics-endpoint-details: .metrics-details -> flex flex-col; __line -> flex items-center; __icon -> flex items-center justify-center mr-2 (preserving text- warning). - shared/components/list/list-types/endpoint/table-cell- endpoint-address: .endpoint-address-cell -> flex items- center; __copy -> w-6. - shared/components/list/list-types/endpoint/table-cell- endpoint-name: .endpoint-name-cell -> flex items-center; __icon -> text-[20px] h-5 w-5 pl-2. - shared/components/list/max-list-message: .maxed -> flex flex-col items-center; __load was dead. Build green.
- features/login/logout-page: .logout (no rules) dropped; .logout__card -> p-0 w-[300px]; .logout__body -> p-6 text-center; .logout__msg -> text-lg pb-5; .logout__loading had no rule. - features/home/home/default-endpoint-home-component: .default-home-card -> m-4; __address -> flex min-h-6; __address__value -> flex items-center mr-7 break-all. - features/home/home/favorites-side-panel: __card on <app-favorites-meta-card> -> flex flex-col mb-1.5; parent .fav-side-panel rule had no own body. - features/user-profile/edit-profile-info: .edit-profile (mt-2.5) + .edit-profile__group (flex flex-col max-w-full) combined into single class attribute on form root; second occurrence on inner div migrated. Nested .custom-form-field rule was dead (component selector under emulated scope). - core/entity-favorite-star: .favorite-star -> flex items-center cursor-pointer; conditional size via [ngClass]="small ? 'h-5 w-5' : 'h-6 w-6'". Nested mat-icon rule was dead (template uses <app-custom-icon>). Build green.
- shared/components/display-value: .display-value -> min-w-[200px]; __label -> font-bold text-sm mb-2.5. - shared/components/page-sub-nav-section: .sub-nav-section -> inline-block; __inner -> flex items-center; __divider -> border-r border-[rgba(100,121,143,0.4)] h-5 mr-2.5 pr-2.5. - shared/components/stacked-input-actions: only live rule was __add--content -> flex items-center; parent shells and nested mat-icon were dead (template uses <app-custom-icon>). - shared/components/start-end-date: .start-end-date -> flex items-center flex-wrap w-full; __selector -> flex-none px-[5px]; __arrow -> px-[5px]; .invalid-message -> text-xs min-h-4. - shared/components/list/list-table/table-cell-expander: drop .expander (template already had cursor-pointer inline-flex items-center justify-center w-6 h-6); __icon-container -> h-[18px] w-[8px]. Build green.
- shared/components/user-profile-banner: .user-profile-banner -> flex flex-row p-6; __avatar -> flex-none mr-6; __email -> text-base; __title -> flex-1 text-[28px]. Nested mat-icon rule was dead (template uses <app-user-avatar>). - shared/components/application-state: .app-state -> flex flex-row items-center; __with-icon -> conditional h-[25px] via [class.h-\[25px\]]; __label and __sub-label -> overflow-hidden text-ellipsis; nested app-application-state-icon padding-right inlined as pr-[5px] on the component element. - shared/components/list/list-table/app-table-cell-default: .link parent had no rules; __short -> flex; __short__icon -> text-[17px]. Nested mat-icon rule was dead (template uses <app-custom-icon>). Build green.
- shared/components/chips: drop .app-chips on container (replaced with my-[5px]); drop .app-chip__container (was redundant flex items-center); __label -> flex-1 h-[18px] leading-[18px] break-all; __close -> text-[15px] h-[15px] w-[15px] flex-none ml-[5px]; __busy-spinner -> flex-none ml-[5px]; __limit on button -> cursor-pointer font-light min-w-0 px-[5px]; removed no-rule __show-more and __show-less conditional ngClass. - shared/components/code-block: .app-code-block -> p-[10px_20px] bg-[var(--code-block-bg)] border border-[var(--code-block-border)] text-[var(--code-block-text)]; __content -> flex flex-col justify-center mr-[20px] (added to existing utilities); __pre conditional -> [class.px-[20px]]; __copy -> top-[10px] right-[20px] (replacing prior top-2 right-2 to match SCSS). - shared/components/list/list-table/table-cell-edit: .edit -> flex gap-1 justify-end; --subtle modifier was a parent-conditional rule against .btn-icon descendants; rewrote as per-button [ngClass]="subtle ? '...' : ''" with the exact utility set inlined on each of the three edit/ save/cancel buttons. Build green.
- shared/components/user-avatar: parent-conditional __large state rewritten as size-aware [ngClass] on each child. Base: flex items-center justify-center. Root gets h-16 w-16 when large. Placeholder span: large -> text-[64px] h-16 w-16; small -> text-[36px] h-9 w-9 leading-[initial]. Initials div: large -> text-[26px] h-[60px] w-[60px] leading-[60px]; small -> text-sm h-[30px] w-[30px] leading-[30px]; rounded-full text-center always. Gravatar img: large -> h-16 w-16; small -> h-9 w-9; rounded-full always. - shared/components/file-input: .file-input -> flex flex-col; __disabled rewritten as [class.opacity-50]="disabled" [class.pointer-events-none]="disabled" on root. .file-input __input -> flex-1 bg-transparent border-none outline-none text-[inherit] font-[inherit] p-0 min-w-0. __button -> btn btn-sm btn-secondary ml-1 flex-none leading-[inherit] min-w-[auto] px-1. __field __form-field were redundant containers; __none and __hint had no template references (dead). Build green.
- shared/components/stratos-title: .stratos-title -> flex
flex-col justify-center pt-6 (text-center already on
template); __logo -> self-center pt-3 pb-4 w-60 (preserving
existing mx-auto mb-4); __header had display:none -> hidden
(h1 stays in DOM for accessibility but visually hidden as
the logo image is the visual title); __subtitle p element
had no SCSS rule, just kept its existing utilities.
- shared/components/list/list-types/endpoint/table-cell-
endpoint-status: bare div selector inlined as flex
items-center on the root div; bare span { margin-right:
8px } rule was global to all descendant spans (including
nested (local) spans); migrated as explicit mr-2 on each
text-label span and on the two nested (local) spans to
preserve original cascade behavior.
- shared/components/copy-to-clipboard: parent-conditional
.copy__success rule replaced by direct opacity bindings on
each child. .copy__copied-div -> absolute right-0 top-0
flex items-center gap-1 transition-opacity duration-300
with [class.opacity-100]/[class.opacity-0] driven by
copySuccessWait. .copy__copy-icon -> absolute right-0 top-0
transition-opacity duration-300 with inverse opacity
binding. The bare-span margin-right: 5px under
__copied-div migrated as mr-[5px] on the msg and icon
spans. .copy__copy-icon-small was dead (no template ref).
Build green.
Both files used parent-conditional state CSS that toggled
child styles when a state class was present on the root.
Rewritten as direct conditional [ngClass] / [class.X] on
each affected element keyed off the same signal.
- shared/components/sidepanel-preview: root no longer carries
.sidepanel-preview / .sidepanel-preview__preview; instead
each affected element binds against
sidePanelService.previewMode():
- root: h-[calc(100vh-57px)] vs h-screen
- header: h-[48px] flex-[0_0_48px] vs h-14 flex-[0_0_56px]
- h1: text-[16px] vs text-xl
- close button top: top-[3px] vs top-[7px]
Static utilities (bg/border/CSS vars, header layout,
favorite, custom slot, content) inlined directly.
- shared/components/upload-progress-indicator: dropped the
parent .upload-progress-done toggle; each of the three
children (cloud icon, done icon, spinner) binds
[class.opacity-0]/[class.opacity-100] off value === 100,
using the same transition-opacity duration-1000 base.
Sass $progress-size (140px) and $progress-transition-speed
(1s) inlined as h-[140px] / w-[140px] / duration-1000.
Build green.
Re-audited the four files the read-only audit agents had
flagged as Class C. All four turned out to be migratable
after closer inspection.
- features/user-profile/profile-info: ENTIRELY dead. None of
.user-profile / .user-profile__* / mat-card:not(:first-
child) match the template (template uses .card / .card-
header / .card-body Tailwind component classes and no
<mat-card>). Just delete + drop styleUrls.
- core/log-out-dialog: mat-dialog-actions bare selector and
__message > mat-icon nested rule were dead (template uses
<div class="dialog-actions"> and <i class="material-icons">
respectively). Live rules inlined: __outer ->
m-[-24px_-24px_0] p-[24px_50px] relative; __progress ->
absolute inset-x-0 top-0; __content -> p-5; __message ->
flex flex-row items-center; __message > div bare-tag ->
flex-1 text-lg font-bold; __actions -> justify-center.
- features/setup/local-account-wizard: all .local-setup-
wizard* BEM was dead (template never uses them). All
nested app-steppers .child { @apply ... } rules were dead
under emulated encapsulation (the child elements live in
the steppers child component's own template). app-stratos-
title rule dead (no <app-stratos-title> in template).
Three live rules inlined: .page-container -> flex flex-
col h-full on root; bare form -> min-w-[400px] w-full on
the password form; app-steppers host -> class="flex flex-1
my-6".
- features/setup/uaa-wizard/console-uaa-wizard: identical
shape to local-account-wizard, EXCEPT the component had
encapsulation: ViewEncapsulation.None, which made the
otherwise-dead nested rules leak globally to every
<app-steppers> instance in the app. Switched encapsulation
back to default (Emulated) and dropped the SCSS. Same
three live rules inlined as in the sibling wizard, plus
the second form (UAA Scope step) gets the same
min-w-[400px] w-full.
41/41 Class B core files now migrated. Build green.
Add .app-host-fill and .app-host-flex-1 to core/src/styles.scss,
then convert 21 cloud-foundry components with single-rule :host
stylesheets to apply the new class via host: { class: '...' } in
the @component decorator.
Removed stylesheets:
- 12 :host { display:block; height:100%; min-height:0 } files
(cf signal-tab cluster: applications, marketplace, organizations,
organization-spaces, routes, services, users, plus all 5 nested
space-* signal tabs)
- 9 :host { flex: 1 } files (create-application step1/step2/step3,
deploy-application-step2-1, create-organization-step,
create-space-step, edit-organization-step, detach-apps,
select-service)
styleUrls entries dropped; no template changes; component public
API unchanged. Build green: 0 errors, 14.4s.
Move single-rule :host stylesheets to host: { class: '...' } in the
@component decorator and inline descendant utilities into templates;
delete the .scss files; drop styleUrls entries.
Files migrated:
- core: app.component, endpoints-page, endpoints-signal-list,
endpoints-missing, list-cards/card, list-generics/list-view,
monaco-editor
- kubernetes: kube-config-import, kube-config-selection,
kubernetes-node-info-card
Template inlines:
- app.component.html: .user-id → .hidden (drops dead .user-id
rule under emulated encapsulation)
- endpoints-missing: <app-no-content-message> gets flex w-full
relative overflow-visible classes (replaces descendant rule)
- monaco-editor: #editorContainer gets w-full h-full min-h-[200px]
utilities directly (drops .monaco-editor-container class)
app.component's html/body/material-app rule block dropped — under
emulated encapsulation it never applied; global html/body styles
already live in core/src/styles.scss.
endpoints-page's redundant app-endpoints-signal-list descendant
rule is dropped via .scss deletion; child component's host class
now carries the same flex utilities.
Build green: 0 errors, 14.4s.
Batch 4 (0093467) renamed the clickable div's class from .favorite-star to utility classes (flex items-center cursor-pointer). The spec still queried for .favorite-star, returning null, which caused all 3 click tests to throw TypeError: Cannot read properties of null (reading 'click'). Switch the spec's three element.querySelector call sites from '.favorite-star' to '[role="button"]'. The accessibility attribute is already on the same div and is semantically stable.
norman-abramovitz
approved these changes
May 21, 2026
Contributor
norman-abramovitz
left a comment
There was a problem hiding this comment.
This work on removing SCCS is about 50% complete. Removing most of the remaining SCCS files will require updates to the stratos extensions. The extension updates were not in the picture at this time.
The work to make more of the code Angular 21-native will need to land first, and then a fix-up path will be taken.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Eliminates 152 SCSS files (280 → 128, -54%) in the post-Tailwind-v4 cleanup. Class A files (utility-only rules) are inlined into templates and deleted. Class B files (BEM +
:hostblocks) are rewritten as@applydirectives in retained stylesheets. The largest single-pattern cluster — 21 cf signal-tab and stepper-step components with single-rule:hostboilerplate — is collapsed onto two shared utility classes applied viahost: { class: '...' }in@Componentdecorators, deleting the stylesheets entirely.Net: 403 files changed, 407 insertions, 2764 deletions. Component public APIs unchanged.
Approach
styleUrls, delete the.scss. Example:app.component.scss:host { display:flex; flex-direction:column; flex:1 1 0%; height:100vh; min-height:0 }→host: { class: 'flex flex-col flex-1 h-screen min-h-0' }.@apply. Selectors stay; only property values change.:hostutility classes (batch 12) — add.app-host-fill(@apply block h-full min-h-0) and.app-host-flex-1(@apply flex-1) tocore/src/styles.scss. Apply viahost: { class: '...' }so trivial single-rule:hoststylesheets can be deleted outright.Commit groupings (26 commits)
7c6b56c035— Remove 2 orphan component SCSS filesd856ca4a45— Migrate 35 Class A SCSS to Tailwind utilitiese431428360,e11ee121f2— Remove 9 dead-rule Class B SCSS files621f8e7175— Flatten entity-summary-title BEM to template utilities31ade961c4— Remove dead-rule table-cell-select-org SCSS47fa9ca3fd— Migrate 7 Class B in kubernetesbf18b1591d— Migrate 3 Class B in cf-autoscalere9298f6173..87417a2f64) — 22 Class B filese309956bd9..af000c79d6) — 41 Class B files0eddc659aa— Batch 12: 21 cf:hostSCSS → shared utility classescf38bf1cd4— Batch 13: 10 Class A core+k8s SCSS →host:{class}+ template inlinesTest plan
make buildgreen (0 errors, 14.4s, full cross-compile of jetstream backends)app.componenthost-class)/endpointspage (endpoints-page + signal-list + missing host-classes)/cloud-foundrylist page/stacks+ signal-tab cluster)cloud-foundry-applications-signal— batch 12 fill cluster)styleUrlsremovals andhost: { class }additions in@ComponentdecoratorsNot in this PR (parked follow-up workstream)
@keyframes→animate-*,:host-context(.dark)→dark:variant,::ng-deepreworkable via wrapper class):root/dark-theme CSS-vars, parameterized@mixindefinitions,::ng-deepinto ngx-charts framework internals, global stylesheets loaded outsidestyleUrls).scss-only rewrites but bundled with the C/D workstreamNote: pre-existing unrelated bug surfaced during verification
The CF Organizations signal-list
refresh()action updates the total-count signal but does NOT re-fetch the row dataset. After creating an org via the wizard, the list shows stale rows until a full navigation. Bug lives incf-orgs-signal-config.service.ts(and parallel CfApps/CfRoutes/CfServices config services likely share it). Not caused by this PR — the host-class refactor only touches the layout, not the data flow.Release sequence
developafter the fixup pass lands, giving testers a coherent baseline that combines the Class A/B cleanup with the operational fixes.Whether the remaining Class C/D SCSS work (and the ~28 easier-B files bundled with it) lands inside the alpha cycle or after is TBD — it depends on the extension-fixup analysis, which has not started yet.