refactor: migrate CC dark theme feature to the new architecture

Bug: twpowertools:176
Change-Id: Iaea1015a788038a8a31acbdd33b267b551e0b6a1
diff --git a/src/features/Features.ts b/src/features/Features.ts
index a93f8a3..67c93aa 100644
--- a/src/features/Features.ts
+++ b/src/features/Features.ts
@@ -4,12 +4,14 @@
 import ScriptFilterListProvider from '../common/architecture/scripts/ScriptFilterListProvider';
 import ExtraInfoFeature from './extraInfo/extraInfo.feature';
 import WorkflowsFeature from './workflows/workflows.feature';
+import CCDarkThemeFeature from './ccDarkTheme/ccDarkTheme.feature';
 
 export type ConcreteFeatureClass = { new (): Feature };
 
 export default class Features extends ScriptFilterListProvider {
   private features: ConcreteFeatureClass[] = [
     AutoRefreshFeature,
+    CCDarkThemeFeature,
     ExtraInfoFeature,
     InfiniteScrollFeature,
     WorkflowsFeature,
diff --git a/src/features/ccDarkTheme/ccDarkTheme.feature.ts b/src/features/ccDarkTheme/ccDarkTheme.feature.ts
new file mode 100644
index 0000000..74efbf2
--- /dev/null
+++ b/src/features/ccDarkTheme/ccDarkTheme.feature.ts
@@ -0,0 +1,21 @@
+import Feature from '../../common/architecture/features/Feature';
+import { ConcreteScript } from '../../common/architecture/scripts/Script';
+import { OptionCodename } from '../../common/options/optionsPrototype';
+import InjectAutoDarkTheme from './scripts/injectAutoDarkTheme.script';
+import InjectForcedDarkTheme from './scripts/injectForcedDarkTheme.script';
+import CCDarkThemeNodeWatcherScript from './scripts/nodeWatcher.script';
+
+export default class CCDarkThemeFeature extends Feature {
+  public readonly scripts: ConcreteScript[] = [
+    InjectAutoDarkTheme,
+    InjectForcedDarkTheme,
+    CCDarkThemeNodeWatcherScript,
+  ];
+
+  readonly codename = 'darkTheme';
+  readonly relatedOptions: OptionCodename[] = [
+    'ccdarktheme',
+    'ccdarktheme_mode',
+    'ccdarktheme_switch_status',
+  ];
+}
diff --git a/src/features/ccDarkTheme/core/logic/darkTheme.js b/src/features/ccDarkTheme/core/logic/darkTheme.js
new file mode 100644
index 0000000..d3d7e5e
--- /dev/null
+++ b/src/features/ccDarkTheme/core/logic/darkTheme.js
@@ -0,0 +1,84 @@
+import { MDCTooltip } from '@material/tooltip';
+
+import { createPlainTooltip } from '../../../../common/tooltip.js';
+import { createExtBadge } from '../../../../contentScripts/communityConsole/utils/common.js';
+
+export const kColorThemeMode = Object.freeze({
+  Auto: Symbol('auto'),
+  Light: Symbol('light'),
+  Dark: Symbol('dark'),
+});
+
+export function injectDarkThemeButton(rightControl) {
+  var darkThemeSwitch = document.createElement('material-button');
+  darkThemeSwitch.classList.add('TWPT-dark-theme', 'TWPT-btn--with-badge');
+  darkThemeSwitch.setAttribute('button', '');
+
+  darkThemeSwitch.addEventListener('click', () => {
+    chrome.storage.sync.get(null, (currentOptions) => {
+      currentOptions.ccdarktheme_switch_status =
+        !currentOptions.ccdarktheme_switch_status;
+      chrome.storage.sync.set(currentOptions);
+    });
+  });
+
+  var switchContent = document.createElement('div');
+  switchContent.classList.add('content');
+
+  var icon = document.createElement('material-icon');
+
+  var i = document.createElement('i');
+  i.classList.add('material-icon-i', 'material-icons-extended');
+  i.textContent = 'brightness_4';
+
+  icon.appendChild(i);
+  switchContent.appendChild(icon);
+  darkThemeSwitch.appendChild(switchContent);
+
+  let badgeContent, badgeTooltip;
+  [badgeContent, badgeTooltip] = createExtBadge();
+
+  darkThemeSwitch.appendChild(badgeContent);
+
+  rightControl.style.width =
+    parseInt(window.getComputedStyle(rightControl).width) + 58 + 'px';
+  rightControl.insertAdjacentElement('afterbegin', darkThemeSwitch);
+
+  createPlainTooltip(
+    switchContent,
+    chrome.i18n.getMessage('inject_ccdarktheme_helper'),
+  );
+  new MDCTooltip(badgeTooltip);
+}
+
+export function getCurrentColorTheme(options) {
+  if (!options.ccdarktheme) {
+    return kColorThemeMode.Light;
+  } else {
+    if (options.ccdarktheme_mode == 'switch') {
+      return options.ccdarktheme_switch_status
+        ? kColorThemeMode.Dark
+        : kColorThemeMode.Light;
+    } else {
+      return kColorThemeMode.Auto;
+    }
+  }
+}
+
+export function isDarkThemeOn(options) {
+  const activeColorTheme = getCurrentColorTheme(options);
+
+  switch (activeColorTheme) {
+    case kColorThemeMode.Auto:
+      return (
+        window.matchMedia &&
+        window.matchMedia('(prefers-color-scheme: dark)').matches
+      );
+
+    case kColorThemeMode.Light:
+      return false;
+
+    case kColorThemeMode.Dark:
+      return true;
+  }
+}
diff --git a/src/features/ccDarkTheme/core/logic/reportDialog.js b/src/features/ccDarkTheme/core/logic/reportDialog.js
new file mode 100644
index 0000000..4e79f4a
--- /dev/null
+++ b/src/features/ccDarkTheme/core/logic/reportDialog.js
@@ -0,0 +1,30 @@
+import {getCurrentColorTheme, kColorThemeMode} from './darkTheme';
+
+const kReportingWidgetThemes = {
+  [kColorThemeMode.Auto]: '0',
+  [kColorThemeMode.Light]: '1',
+  [kColorThemeMode.Dark]: '2',
+};
+
+export default class ReportDialogColorThemeFix {
+  constructor() {}
+
+  async fixThemeIfReportDialogIframeAndApplicable(iframe, optionsProvider) {
+    if (!this.isReportDialogIframe(iframe)) return;
+
+    const options = await optionsProvider.getOptionsValues();
+    const currentColorTheme = getCurrentColorTheme(options);
+
+    // By default the report dialog is added with the light theme
+    if (currentColorTheme === kColorThemeMode.Light) return;
+
+    console.debug('[reportDialogColorThemeFix] Fixing report dialog iframe');
+    let url = new URL(iframe.src);
+    url.searchParams.set('theme', kReportingWidgetThemes[currentColorTheme]);
+    iframe.src = url.href;
+  }
+
+  isReportDialogIframe(iframe) {
+    return iframe.src?.includes?.('reportingwidget') ?? false;
+  }
+}
diff --git a/src/features/ccDarkTheme/core/logic/unifiedProfiles.js b/src/features/ccDarkTheme/core/logic/unifiedProfiles.js
new file mode 100644
index 0000000..a26c45b
--- /dev/null
+++ b/src/features/ccDarkTheme/core/logic/unifiedProfiles.js
@@ -0,0 +1,12 @@
+export var unifiedProfilesFix = {
+  checkIframe(iframe) {
+    var srcRegex = /support.*\.google\.com\/profile\//;
+    return srcRegex.test(iframe.src ?? '');
+  },
+  fixIframe(iframe) {
+    console.debug('[unifiedProfilesFix] Fixing unified profiles iframe');
+    var url = new URL(iframe.src);
+    url.searchParams.set('dark', 1);
+    iframe.src = url.href;
+  },
+};
diff --git a/src/features/ccDarkTheme/core/styles/abstracts/_variables.scss b/src/features/ccDarkTheme/core/styles/abstracts/_variables.scss
new file mode 100644
index 0000000..bcb922d
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/abstracts/_variables.scss
@@ -0,0 +1,48 @@
+@use '../../../../../md3/theme' as md3-theme;
+
+:root {
+  --TWPT-primary-text: #e8eaed;
+  --TWPT-primary-text-alt: var(--TWPT-primary-text);
+  --TWPT-secondary-text: #bfbfbf;
+  --TWPT-primary-background: #202124;
+  --TWPT-secondary-background: #28292c;
+  --TWPT-active-background: #3c4043;
+  --TWPT-card-border: #5f6368;
+  --TWPT-subtle-border: #383735;
+  --TWPT-link: #8ab4f8;
+  --TWPT-icon-color: rgba(255, 255, 255, .87);
+  --TWPT-highlighted-item-background: rgba(255, 255, 255, .08);
+  --TWPT-thread-read-background: var(--TWPT-highlighted-item-background);
+  --TWPT-drawer-background: #2d2e30;
+  --TWPT-drawer-text: #d2cecb;
+  --TWPT-button-background: #3c3e42;
+  --TWPT-subtle-button-background: rgba(255, 255, 255, .54);
+  --TWPT-input-underline: rgba(255, 255, 255, .28);
+  --TWPT-starred: #fbbc04;
+  --TWPT-blue-100: #BBDEFB;
+  --TWPT-blue-A100: #82B1FF;
+  --TWPT-bad-text: #f6aea9;
+  --TWPT-bad-text-lightbg: #ffc4c0;
+  --TWPT-good-text: #34a853;
+  --TWPT-good-text-lightbg: #3cc160;
+  --TWPT-interop-primary-text: var(--TWPT-primary-text);
+  --TWPT-interop-secondary-text: #c4c7c5;
+  --TWPT-interop-subtle-border: #474747;
+  --TWPT-interop-success: #37be5f;
+  --TWPT-interop-blue: #7cacf8;
+
+  @include md3-theme.dark-theme('TWPT-');
+
+  /* Overrides for variables used by the Community Console styles */
+  --gm-outlinedtextfield-outline-color: var(--TWPT-card-border);
+  --gm-outlinedtextfield-label-color: var(--TWPT-subtle-button-background);
+  --gm-outlinedtextfield-caret-color: var(--TWPT-blue-A100);
+  --gm-outlinedtextfield-outline-color--stateful: var(--TWPT-blue-A100);
+  --gm-outlinedtextfield-label-color--stateful: var(--TWPT-blue-A100);
+  --gm-outlinedtextfield-outline-color--error: var(--TWPT-bad-text);
+  --gm-outlinedtextfield-label-color--error: var(--TWPT-bad-text);
+  --gm-outlinedtextfield-helper-text-color--error: var(--TWPT-bad-text);
+
+  /* TWPT features variables */
+  --TWPT-dark-flatten-replies-more-bg: rgba(89, 89, 89, 0.9);
+}
diff --git a/src/features/ccDarkTheme/core/styles/base/_base.scss b/src/features/ccDarkTheme/core/styles/base/_base.scss
new file mode 100644
index 0000000..c50c151
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/base/_base.scss
@@ -0,0 +1,16 @@
+:root {
+  color-scheme: dark;
+}
+
+body {
+  color: var(--TWPT-primary-text);
+  background-color: var(--TWPT-primary-background)!important;
+}
+
+p {
+  color: var(--TWPT-primary-text);
+}
+
+body.ec a {
+  color: var(--TWPT-link);
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_action-bar.scss b/src/features/ccDarkTheme/core/styles/components/_action-bar.scss
new file mode 100644
index 0000000..9bf28fa
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_action-bar.scss
@@ -0,0 +1,15 @@
+.material-content .action-bar material-button,
+    ec-bulk-actions material-button,
+    ec-back-button material-button,
+    .sort-options material-button {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+.material-content .action-bar .review-button.reviewing {
+  color: #1a73e8!important;
+  background: #dae7ff!important;
+}
+
+.material-content .action-bar material-button.starred {
+  color: var(--TWPT-starred)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_activity-panel.scss b/src/features/ccDarkTheme/core/styles/components/_activity-panel.scss
new file mode 100644
index 0000000..e097612
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_activity-panel.scss
@@ -0,0 +1,24 @@
+ec-activity-panel .title-bar h3 {
+  color: #e8eaf2!important;
+}
+
+ec-activity-panel .title-bar material-button {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+ec-activity-panel ec-activity {
+  color: var(--TWPT-secondary-text)!important;
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-activity-panel ec-activity .message {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+ec-activity-panel ec-activity .thread-title {
+  color: #c3bfbc!important;
+}
+
+ec-activity-panel ec-activity .thread-body {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_canned-responses.scss b/src/features/ccDarkTheme/core/styles/components/_canned-responses.scss
new file mode 100644
index 0000000..2d07bb8
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_canned-responses.scss
@@ -0,0 +1,39 @@
+ec-canned-responses {
+  .filter-label,
+      ec-canned-response-row .name {
+    color: var(--TWPT-primary-text)!important;
+  }
+
+  .label-row,
+      ec-canned-response-row .snippet,
+      ec-canned-response-row .tag .content,
+      ec-canned-response-row .TWPT-tag .TWPT-content {
+    color: var(--TWPT-secondary-text)!important;
+  }
+
+  material-expansionpanel:not(.expanded) .main-header:focus-within {
+    background-color: var(--TWPT-active-background)!important;
+  }
+
+  ec-canned-response-row {
+    .header:hover,
+        .header.closed:focus,
+        .header.closed:hover .toolbar,
+        .header.closed:focus .toolbar,
+        material-expansionpanel:not(.expanded) .main-header:focus-within,
+        material-expansionpanel:not(.expanded) .main-header:hover {
+      background-color: var(--TWPT-active-background)!important;
+    }
+  }
+
+  .filter-row,
+      .label-row,
+      ec-canned-response-row material-expansionpanel {
+    border-bottom-color: var(--TWPT-subtle-border)!important;
+  }
+
+  .create-button {
+    background: #0842a0!important;
+    color: #d3e3fd!important;
+  }
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_drawer.scss b/src/features/ccDarkTheme/core/styles/components/_drawer.scss
new file mode 100644
index 0000000..35fefdd
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_drawer.scss
@@ -0,0 +1,33 @@
+material-drawer, material-drawer .panel, ec-filter-drawer-item > .root, ec-forum-drawer-item material-list-item {
+  background-color: var(--TWPT-drawer-background)!important;
+}
+
+material-drawer material-expansionpanel .main-header > .header:is(:hover, :focus) {
+  background-color: var(--TWPT-active-background)!important;
+}
+
+:is(
+      ec-filter-drawer-item > .root,
+      ec-forum-drawer-item > material-list-item,
+      material-list material-list-item,
+      .drawer-section .drawer-item:not([separator=present])
+    ):is(:hover, :focus, :focus-within, .active, .drawer-item--active) {
+  background: var(--TWPT-active-background)!important;
+}
+
+material-drawer .panel {
+  border-bottom-color: #25231f!important;
+}
+
+material-drawer .drawer-section-title, material-drawer .header > material-icon {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-drawer material-list-item,
+    material-drawer material-list-item .title {
+  color: var(--TWPT-drawer-text)!important;
+}
+
+material-drawer ec-forum-drawer-item material-checkbox material-icon {
+  filter: brightness(1.5);
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_duplicate-thread.scss b/src/features/ccDarkTheme/core/styles/components/_duplicate-thread.scss
new file mode 100644
index 0000000..cf0858f
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_duplicate-thread.scss
@@ -0,0 +1,17 @@
+.search-results ec-thread-option material-expansionpanel .panel {
+  background-color: var(--TWPT-primary-background)!important;
+}
+
+.search-results ec-thread-option material-expansionpanel.selected .panel,
+    .search-results ec-thread-option material-expansionpanel .panel > .main-header > .header.closed:hover,
+    .search-results ec-thread-option material-expansionpanel .panel > .main-header > .header.closed:focus {
+  background-color: #17191c!important;
+}
+
+.search-results .results-title {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+.search-results ec-thread-option material-expansionpanel .panel > .main > .main-content .snippet {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_icon.scss b/src/features/ccDarkTheme/core/styles/components/_icon.scss
new file mode 100644
index 0000000..ccba370
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_icon.scss
@@ -0,0 +1,22 @@
+ec-filter-drawer-item material-icon,
+    ec-filter-drawer-item ec-icon,
+    material-drawer .drawer-section material-icon,
+    material-drawer .drawer-section ec-icon,
+    material-list material-icon,
+    ec-query-builder material-icon,
+    ec-thread-summary material-expansionpanel .title material-icon,
+    .search-results ec-thread-option material-icon,
+    .search-results ec-thread-option ec-icon,
+    ec-rich-text-editor material-icon,
+    ec-editor-command material-icon,
+    ec-canned-responses ec-canned-response-row material-icon,
+    ec-ask-flow > .header material-button {
+  color: var(--TWPT-icon-color)!important;
+}
+
+material-drawer ec-icon,
+  .search-results ec-thread-option ec-icon,
+  ec-thread-summary material-expansionpanel .title ec-icon,
+  ec-announcements-menu-item ec-icon {
+  fill: var(--TWPT-icon-color)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_index.scss b/src/features/ccDarkTheme/core/styles/components/_index.scss
new file mode 100644
index 0000000..6307f8f
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_index.scss
@@ -0,0 +1,26 @@
+@forward 'drawer';
+@forward 'notifications';
+@forward 'tabs';
+@forward 'query-builder';
+@forward 'action-bar';
+@forward 'thread-list';
+@forward 'review-bar';
+@forward 'activity-panel';
+@forward 'thread-view';
+@forward 'stepper';
+@forward 'thread-composer';
+@forward 'profile-chart';
+@forward 'user-badge';
+@forward 'duplicate-thread';
+@forward 'buttons';
+@forward 'icon';
+@forward 'dialogs';
+@forward 'rich-text-editor';
+@forward 'thread-insert';
+@forward 'inputs';
+@forward 'menu';
+@forward 'popups';
+@forward 'canned-responses';
+@forward 'settings';
+@forward 'loading-spinner';
+@forward 'custom';
diff --git a/src/features/ccDarkTheme/core/styles/components/_loading-spinner.scss b/src/features/ccDarkTheme/core/styles/components/_loading-spinner.scss
new file mode 100644
index 0000000..ef71ebc
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_loading-spinner.scss
@@ -0,0 +1,3 @@
+material-spinner {
+  border-color: var(--TWPT-blue-A100)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_menu.scss b/src/features/ccDarkTheme/core/styles/components/_menu.scss
new file mode 100644
index 0000000..b0e5a02
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_menu.scss
@@ -0,0 +1,3 @@
+material-menu material-button {
+  color: var(--TWPT-primary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_profile-chart.scss b/src/features/ccDarkTheme/core/styles/components/_profile-chart.scss
new file mode 100644
index 0000000..2312723
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_profile-chart.scss
@@ -0,0 +1,44 @@
+ec-user bar-chart .axis text,
+    ec-unified-user .scTailwindSharedActivitychartchart .axis text {
+  fill: var(--TWPT-subtle-button-background)!important;
+}
+
+ec-user bar-chart .axis path,
+    ec-user bar-chart .axis .gridline,
+    ec-user bar-chart .axis line,
+    ec-unified-user .scTailwindSharedActivitychartchart .axis path,
+    ec-unified-user .scTailwindSharedActivitychartchart .axis .gridline,
+    ec-unified-user .scTailwindSharedActivitychartchart .axis line {
+  stroke: rgba(255, 255, 255, .12)!important;
+}
+
+ec-user bar-chart .axis line.axis-zero-tick,
+    ec-user bar-chart .axis.x .tick-mark,
+    ec-unified-user .scTailwindSharedActivitychartchart .axis line.axis-zero-tick,
+    ec-unified-user .scTailwindSharedActivitychartchart .axis.x .tick-mark {
+  stroke: rgba(255, 255, 255, .38)!important;
+}
+
+ec-user bar-chart .aplos-legend-entry,
+    ec-unified-user .scTailwindSharedActivitychartchart .aplos-legend-entry {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+.aplos-hovercard {
+  color: var(--TWPT-interop-secondary-text)!important;
+  background: var(--TWPT-secondary-background)!important;
+  border: none!important;
+}
+
+.aplos-hovercard .title {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.aplos-hovercard .subtitle,
+    .aplos-donut-center .subtitle,
+    .aplos-hovercard .series,
+    .aplos-donut-center .series,
+    .aplos-hovercard .value,
+    .aplos-donut-center .value {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_query-builder.scss b/src/features/ccDarkTheme/core/styles/components/_query-builder.scss
new file mode 100644
index 0000000..b7551b7
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_query-builder.scss
@@ -0,0 +1,19 @@
+// Filters (ec-query-builder)
+material-condition-builder .compound-condition-operator {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-condition-builder .compound-condition-operator:is(::before, ::after) {
+  border-left-color: rgba(255, 255, 255, .20)!important;
+}
+
+material-condition-builder .add-button,
+    ec-query-builder .save-filter-button:not([disabled]) {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+material-condition-builder .add-condition,
+    ec-query-builder .close-button {
+  background-color: var(--TWPT-interop-blue)!important;
+  color: #1f1f1f!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_review-bar.scss b/src/features/ccDarkTheme/core/styles/components/_review-bar.scss
new file mode 100644
index 0000000..ea94e0e
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_review-bar.scss
@@ -0,0 +1,47 @@
+// Review bar shown above the main message or replies
+ec-review-bar {
+  background-color: var(--TWPT-active-background)!important;
+}
+
+ec-review-bar material-chip {
+  background-color: var(--TWPT-button-background)!important;
+}
+
+ec-review-bar material-chip:not(.relevant-active):not(.active) {
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-review-bar material-chip:not(.relevant-active):not(.active) material-icon {
+  color: var(--TWPT-primary-text)!important;
+  fill: var(--TWPT-primary-text)!important;
+}
+
+ec-review-bar material-chip:not(.relevant-active):not(.active) .content {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-review-bar material-chip.relevant-active {
+  border-color: var(--TWPT-good-text)!important;
+}
+
+ec-review-bar material-chip.relevant-active material-icon {
+  color: var(--TWPT-good-text)!important;
+  fill: var(--TWPT-good-text)!important;
+}
+
+ec-review-bar material-chip.relevant-active .content {
+  color: var(--TWPT-good-text)!important;
+}
+
+ec-review-bar material-chip.active {
+  border-color: var(--TWPT-bad-text)!important;
+}
+
+ec-review-bar material-chip.active material-icon {
+  color: var(--TWPT-bad-text)!important;
+  fill: var(--TWPT-bad-text)!important;
+}
+
+ec-review-bar material-chip.active .content {
+  color: var(--TWPT-bad-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_rich-text-editor.scss b/src/features/ccDarkTheme/core/styles/components/_rich-text-editor.scss
new file mode 100644
index 0000000..2a6d818
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_rich-text-editor.scss
@@ -0,0 +1,37 @@
+ec-editor-command material-button,
+    ec-formatting-popup material-button {
+  box-shadow: none!important;
+}
+
+ec-editor-command material-button.is-active {
+  background: var(--TWPT-active-background)!important;
+}
+
+ec-rich-text-editor .placeholder {
+  color: rgba(255, 255, 255, .38)!important;
+}
+
+ec-rich-text-editor .input-wrapper,
+    ec-rich-text-editor .spacer {
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-rich-text-editor .input-wrapper.input-wrapper--focused {
+  border-color: var(--TWPT-blue-A100)!important;
+}
+
+ec-rich-text-editor .input {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-rich-text-editor .hint {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+material-select-searchbox + material-list material-list-item {
+  color: var(--TWPT-icon-color)!important;
+}
+
+ec-attachment .filename {
+  color: var(--TWPT-primary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_settings.scss b/src/features/ccDarkTheme/core/styles/components/_settings.scss
new file mode 100644
index 0000000..87ebbe0
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_settings.scss
@@ -0,0 +1,7 @@
+ec-settings .forum-language-container {
+  border-bottom-color: var(--TWPT-subtle-border)!important;
+}
+
+ec-settings .forum-language-container :is(material-button, button) {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_stepper.scss b/src/features/ccDarkTheme/core/styles/components/_stepper.scss
new file mode 100644
index 0000000..5c035b1
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_stepper.scss
@@ -0,0 +1,19 @@
+// The stepper is shown in the "new thread" and "edit message" views
+material-stepper {
+  border-top-color: var(--TWPT-card-border)!important;
+}
+
+material-stepper .stepper-step-name,
+    material-stepper .purpose-title {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-ask-flow .display-name-label,
+    material-stepper .additional-details-label,
+    material-stepper .detail-label {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-stepper .stepper-step[selectable=true]:focus {
+  background-color: rgba(60, 64, 67, .24)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_tabs.scss b/src/features/ccDarkTheme/core/styles/components/_tabs.scss
new file mode 100644
index 0000000..e90bc72
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_tabs.scss
@@ -0,0 +1,11 @@
+material-tab-strip tab-button {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-tab-strip tab-button.active {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+material-tab-strip .tab-indicator {
+  border-top-color: var(--TWPT-blue-A100)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_thread-composer.scss b/src/features/ccDarkTheme/core/styles/components/_thread-composer.scss
new file mode 100644
index 0000000..b4a8cfa
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_thread-composer.scss
@@ -0,0 +1,73 @@
+ec-thread-composer .main-content .title-label,
+    ec-thread-composer .main-content .post-label {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+ec-thread-composer .main-content .title-input,
+    ec-thread-composer .main-content ec-rich-text-editor {
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-thread-composer .main-content .title-alert,
+    ec-thread-composer .main-content .footer-disclaimer-error {
+  color: var(--TWPT-bad-text)!important;
+}
+
+ec-thread-composer .main-content .hero-button-container material-button {
+  border-color: var(--TWPT-input-underline);
+}
+
+ec-thread-composer .main-content .hero-button-container material-button .content {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+ec-thread-composer .main-content .draft-button {
+  background: revert!important;
+  color: var(--TWPT-interop-blue);
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-thread-composer .main-content .post-button {
+  background: var(--TWPT-interop-blue)!important;
+  color: #1f1f1f!important;
+}
+
+ec-thread-composer .main-content .post-button[disabled] {
+  background: rgba(227, 227, 227, 0.122)!important;
+}
+
+ec-thread-composer material-drawer {
+  background-color: inherit!important;
+}
+
+ec-thread-composer material-drawer .right-panel {
+  border-left-color: var(--TWPT-card-border)!important;
+}
+
+ec-thread-composer material-drawer .panel-section-title {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-thread-composer material-drawer .panel-section-divider {
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-thread-composer material-drawer material-radio .radio-label {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+ec-thread-composer material-drawer material-radio .radio-description,
+    ec-thread-composer material-drawer .settings-section .panel-section-item .select-label {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-dialog.community-video-dialog .footer material-button.cancel {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+material-dialog.community-video-dialog .footer material-button.update:not([disabled]) {
+  background: var(--TWPT-interop-blue)!important;
+  color: #1f1f1f!important;
+}
+
+// Note: see _thread-view.scss. There is a rule for the thread creation footer.
diff --git a/src/features/ccDarkTheme/core/styles/components/_thread-insert.scss b/src/features/ccDarkTheme/core/styles/components/_thread-insert.scss
new file mode 100644
index 0000000..ef95c99
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_thread-insert.scss
@@ -0,0 +1,10 @@
+// ec-thread-insert is a card with a summary of a thread when escalating it.
+ec-thread-insert .title {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-thread-insert ec-thread-counts,
+    ec-thread-insert .details,
+    ec-thread-insert ec-relative-time {
+  color: var(--TWPT-subtle-button-background)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_thread-list.scss b/src/features/ccDarkTheme/core/styles/components/_thread-list.scss
new file mode 100644
index 0000000..c3024d1
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_thread-list.scss
@@ -0,0 +1,105 @@
+ec-thread-list ul.thread-group {
+  background-color: var(--TWPT-primary-background)!important;
+}
+
+ec-thread-list ec-bulk-actions, ec-thread-list ec-thread-summary material-expansionpanel {
+  border-bottom-color: var(--TWPT-subtle-border)!important;
+}
+
+ec-thread-list .no-results,
+    ec-thread-list .finished-results {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+ec-thread-summary material-expansionpanel.read:not(.checked) {
+  background-color: var(--TWPT-thread-read-background)!important;
+}
+
+ec-thread-summary material-expansionpanel.read .title span:not(.icon) {
+  opacity: 0.8;
+}
+
+ec-thread-summary material-expansionpanel.read .title .icon {
+  opacity: 0.48!important;
+}
+
+ec-thread-summary material-expansionpanel.checked {
+  background-color: #2c4b77!important;
+}
+
+ec-thread-summary material-expansionpanel .title {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-thread-summary material-expansionpanel .title .purpose-tag {
+  background-color: rgba(255, 255, 255, .06)!important;
+  color: #a8c7fa!important;
+}
+
+ec-thread-summary material-expansionpanel .title .draft-tag {
+  background-color: #0f5223!important;
+  color: #6dd58c!important;
+}
+
+ec-thread-summary material-expansionpanel ec-second-summary-line,
+    material-expansionpanel .header-content,
+    material-expansionpanel ec-thread-counts > span:not(.recommended-answers),
+    material-expansionpanel .duplicate-label {
+  color: #928e89!important;
+}
+
+material-expansionpanel .removed-label {
+  color: var(--TWPT-bad-text)!important;
+}
+
+ec-thread-summary material-expansionpanel ec-safe-html.body,
+    material-expansionpanel .issue-tracking-work-state {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-thread-list material-fab.trigger {
+  background: rgba(124, 172, 248, 0.239)!important;
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.popup-wrapper:has(.actions > .action-wrapper > material-fab.themeable) {
+  background-color: unset!important;
+}
+
+.popup-wrapper .actions > .action-wrapper > material-fab.themeable {
+  background-color: var(--TWPT-button-background)!important;
+  color: var(--TWPT-interop-blue)!important;
+}
+
+// The following section changes the styles of the checkboxes in thread lists,
+// based in the styles defined in the "Checkbox input" section.
+ec-thread-summary material-expansionpanel .action material-button:not(.starred),
+    ec-thread-list material-checkbox material-icon,
+    ec-thread-summary material-expansionpanel .star-button:not(.starred),
+    ec-thread-summary material-expansionpanel .mdc-button.mdc-icon-button material-icon {
+  color: #696867!important; // Custom value to match previous behavior
+  opacity: 1!important;
+}
+
+ec-thread-summary material-expansionpanel .action material-button.starred {
+  color: var(--TWPT-starred)!important;
+}
+
+ec-thread-list material-checkbox material-icon.filled {
+  color: #62a5ff!important; // Custom value to contrast well with the background
+}
+
+// .gm-icons is added by the SMEI_GOOGLE_MATERIAL_ICONS experiment.
+ec-thread-list material-checkbox:focus:not(.disabled).gm-icons .icon,
+    .gm-icons ec-thread-list material-checkbox:focus:not(.disabled) .icon,
+    ec-thread-list material-checkbox:hover:not(.disabled).gm-icons .icon,
+    .gm-icons ec-thread-list material-checkbox:hover:not(.disabled) .icon {
+  color: #807d7c!important; // custom value
+}
+
+ec-thread-list material-checkbox:focus:not(.disabled).gm-icons .icon.filled,
+    .gm-icons ec-thread-list material-checkbox:focus:not(.disabled) .icon.filled,
+    ec-thread-list material-checkbox:hover:not(.disabled).gm-icons .icon.filled,
+    .gm-icons ec-thread-list material-checkbox:hover:not(.disabled) .icon.filled {
+  color: #92c1ff!important; // custom value
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_thread-view.scss b/src/features/ccDarkTheme/core/styles/components/_thread-view.scss
new file mode 100644
index 0000000..0878169
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_thread-view.scss
@@ -0,0 +1,210 @@
+ec-question, .heading + .group, ec-message {
+  background-color: var(--TWPT-secondary-background)!important;
+}
+
+ec-thread .no-review-needed {
+  background-color: #155829!important;
+  border-color: var(--TWPT-subtle-border)!important;
+}
+
+// "Original thread" box inside escalations
+sc-tailwind-thread-question-thread-summary .scTailwindThreadQuestionThreadsummarythread-summary {
+  background: var(--TWPT-active-background)!important;
+  border-color: var(--TWPT-card-border)!important;
+}
+
+sc-tailwind-thread-question-thread-summary .scTailwindThreadQuestionThreadsummarydetails {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+sc-tailwind-thread-question-thread-summary .scTailwindThreadQuestionThreadsummarytitle {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-message-header .header, ec-question .state, ec-question ec-thread-counts > span, ec-message ec-thread-counts > span {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+ec-question .alert, ec-message .alert {
+  background-color: var(--TWPT-active-background)!important;
+}
+
+ec-question .alert material-icon, ec-message .alert material-icon {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-question .alert ec-icon, ec-message .alert ec-icon {
+  color: var(--TWPT-primary-text)!important;
+  fill: var(--TWPT-primary-text)!important;
+}
+
+ec-question .alert material-button {
+  color: var(--TWPT-link)!important;
+}
+
+ec-question .title {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+ec-user-link .name-text {
+  color: var(--TWPT-link)!important;
+}
+
+ec-message-header ec-avatar svg, ec-message-header .role,
+    ec-message .footer .role {
+  filter: brightness(1.5);
+}
+
+ec-question .body, ec-message .body {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-question .thread-insert {
+  background: none!important;
+}
+
+ec-question .details-heading {
+  color: var(--TWPT-primary-text-alt) !important;
+}
+
+ec-question .state-chips material-chip {
+  background-color: var(--TWPT-button-background)!important;
+  border: none!important;
+  box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2),
+      0 1px 1px 0 rgba(0, 0, 0, 0.14),
+      0 1px 3px 0 rgba(0, 0, 0, 0.12)!important;
+}
+
+ec-question .state-chips material-chip .content {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-question .footer,
+    ec-ask-flow .content-disclaimer {
+  color: var(--TWPT-primary-text)!important;
+  background-color: var(--TWPT-active-background)!important;
+  border-top-color: var(--TWPT-card-border)!important;
+}
+
+.heading {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.heading + .group,
+    .load-more-bar,
+    ec-message:not(:first-child),
+    .load-more-bar .load-more-button,
+    .load-more-bar .load-all-button {
+  border-color: var(--TWPT-card-border)!important;
+}
+
+ec-message .type {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-message .footer ec-relative-time,
+    ec-message .footer ec-safe-html {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+ec-message .helpful-prompt {
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-question .me-too-button,
+    ec-question .subscribe-button,
+    ec-message .upvote-button,
+    ec-message .downvote-button {
+  color: var(--TWPT-secondary-text)!important;
+  background-color: var(--TWPT-button-background)!important;
+}
+
+ec-message .alert {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+ec-question .me-too-button.selected,
+    ec-question .subscribe-button.selected,
+    ec-message .upvote-button.selected,
+    ec-message .downvote-button.selected {
+  color: #4285f4!important;
+}
+
+.load-more-bar .load-more-button, .load-more-bar .load-all-button {
+  background-color: var(--TWPT-secondary-background)!important;
+}
+
+.locked-alert {
+  background-color: var(--TWPT-active-background)!important;
+  border: var(--TWPT-card-border)!important;
+}
+
+.locked-alert material-icon {
+  color: rgba(255, 255, 255, .38)!important;
+}
+
+ec-thread button.reply.collapsed {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+ec-thread .finished-question {
+  background-color: var(--TWPT-active-background)!important;
+  border: var(--TWPT-card-border)!important;
+}
+
+ec-thread .finished-question .next-question {
+  color: var(--TWPT-link)!important;
+  border-color: var(--TWPT-link)!important;
+}
+
+.material-content .action-bar material-button.has-activity {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+.material-content .action-bar material-button.showing-sidebar {
+  background-color: var(--TWPT-active-background)!important;
+}
+
+// Recommended answers - show in green where we've overwritten the colors
+.recommended-answers {
+  color: #34a853!important;
+}
+
+// Suggested answers - show brighter blue
+.suggested-icon {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+// Help button (shown in the suggested answers header)
+.explanation-icon material-icon {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+// Help button tooltip
+.popup .paper-container {
+  background: var(--TWPT-drawer-background)!important;
+}
+
+.explanation-icon material-icon:hover {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+// Notice used e.g. for deleted threads
+ec-thread .notice {
+  material-icon {
+    color: var(--TWPT-icon-color)!important;
+  }
+
+  .notice-heading {
+    color: var(--TWPT-primary-text)!important;
+  }
+
+  .notice-message {
+    color: var(--TWPT-secondary-text)!important;
+  }
+
+  material-button {
+    background: var(--TWPT-interop-blue)!important;
+    color: #1f1f1f!important;
+  }
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/_user-badge.scss b/src/features/ccDarkTheme/core/styles/components/_user-badge.scss
new file mode 100644
index 0000000..3915b62
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/_user-badge.scss
@@ -0,0 +1,55 @@
+/**
+ * Some fixes for the interop PE badge components in the Community Console.
+ *
+ * The |.scTailwindThreadPost_headerUserinfotag| elements have a
+ * |style="--color:#aaaaaa"| attribute which indicates the color of the badge,
+ * and we are transforming it to the dark mode color accordingly.
+ *
+ * The | .scTailwindThreadMessageMessageinteractionsuser-label| elements have a
+ * |style="--userLabelColor: #aaaaaa"| attribute, so we do the same there.
+ *
+ * We match only the hex color instead of the whole attribute because over time
+ * the attributes have changed (spaces have been removed, for instance).
+ */
+
+// Alumnus
+.scTailwindThreadPost_headerUserinfotag[style*="#0F9D58" i],
+    .scTailwindThreadMessageMessageinteractionsuser-label[style*="#0F9D58" i] {
+  --color: #C4EED0!important;
+  --userLabelColor: #C4EED0!important;
+}
+
+// Bronze
+.scTailwindThreadPost_headerUserinfotag[style*="#896E63" i],
+    .scTailwindThreadMessageMessageinteractionsuser-label[style*="#896E63" i] {
+  --color: #B9ABA3!important;
+  --userLabelColor: #B9ABA3!important;
+}
+
+// Silver
+.scTailwindThreadPost_headerUserinfotag[style*="#5F6368" i],
+    .scTailwindThreadMessageMessageinteractionsuser-label[style*="#5F6368" i] {
+  --color: #C4C7C5!important;
+  --userLabelColor: #C4C7C5!important;
+}
+
+// Gold
+.scTailwindThreadPost_headerUserinfotag[style*="#E37400" i],
+    .scTailwindThreadMessageMessageinteractionsuser-label[style*="#E37400" i] {
+  --color: #F09D00!important;
+  --userLabelColor: #F09D00!important;
+}
+
+// Platinum
+.scTailwindThreadPost_headerUserinfotag[style*="#455A64" i],
+    .scTailwindThreadMessageMessageinteractionsuser-label[style*="#455A64" i] {
+  --color: #E3E3E3!important;
+  --userLabelColor: #E3E3E3!important;
+}
+
+// Diamond, Community Specialist, Community Manager and Google Employee
+.scTailwindThreadPost_headerUserinfotag[style*="#1A73E8" i],
+    .scTailwindThreadMessageMessageinteractionsuser-label[style*="#1A73E8" i] {
+  --color: #A8C7FA!important;
+  --userLabelColor: #A8C7FA!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/buttons/_button.scss b/src/features/ccDarkTheme/core/styles/components/buttons/_button.scss
new file mode 100644
index 0000000..b748e5d
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/buttons/_button.scss
@@ -0,0 +1,9 @@
+material-button[disabled] {
+  color: rgba(255, 255, 255, .26)!important;
+}
+
+.mdc-button {
+  --gm-colortextbutton-ink-color: var(--TWPT-interop-blue);
+  --gm-colortextbutton-ink-color--stateful: var(--TWPT-interop-blue);
+  --gm-colortextbutton-disabled-ink-color: rgba(255, 255, 255, .26);
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/buttons/_index.scss b/src/features/ccDarkTheme/core/styles/components/buttons/_index.scss
new file mode 100644
index 0000000..ab002dc
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/buttons/_index.scss
@@ -0,0 +1,4 @@
+@forward 'button';
+@forward 'yes-no';
+@forward 'reply';
+@forward 'skip-to-main';
diff --git a/src/features/ccDarkTheme/core/styles/components/buttons/_reply.scss b/src/features/ccDarkTheme/core/styles/components/buttons/_reply.scss
new file mode 100644
index 0000000..bc7aeaf
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/buttons/_reply.scss
@@ -0,0 +1,5 @@
+material-fab.reply-button,
+    material-fab.reply-fab {
+  background-color: var(--TWPT-link)!important;
+  color: var(--TWPT-primary-background)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/buttons/_skip-to-main.scss b/src/features/ccDarkTheme/core/styles/components/buttons/_skip-to-main.scss
new file mode 100644
index 0000000..17eb10f
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/buttons/_skip-to-main.scss
@@ -0,0 +1,3 @@
+.skip-to-main:focus {
+  background: revert!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/buttons/_yes-no.scss b/src/features/ccDarkTheme/core/styles/components/buttons/_yes-no.scss
new file mode 100644
index 0000000..3127b9e
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/buttons/_yes-no.scss
@@ -0,0 +1,21 @@
+material-yes-no-buttons material-button:not([disabled]).highlighted:not([raised]) {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+material-yes-no-buttons material-button:not([disabled]).highlighted:not([raised]):is(:hover, :focus) {
+  background-color: revert!important;
+}
+
+material-yes-no-buttons material-button:not([disabled]).highlighted:not([raised]):is(:hover, :focus):after {
+  content: "";
+  display: block;
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: currentColor;
+  opacity: .12;
+  border-radius: inherit;
+  pointer-events: none;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/custom/_chip.scss b/src/features/ccDarkTheme/core/styles/components/custom/_chip.scss
new file mode 100644
index 0000000..f2840d3
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/custom/_chip.scss
@@ -0,0 +1,4 @@
+.TWPT-extrainfo-chip {
+  border: 1px solid var(--TWPT-interop-subtle-border)!important;
+  color: var(--TWPT-interop-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/custom/_index.scss b/src/features/ccDarkTheme/core/styles/components/custom/_index.scss
new file mode 100644
index 0000000..e73007c
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/custom/_index.scss
@@ -0,0 +1,3 @@
+@forward 'chip';
+@forward 'log';
+@forward 'warning';
diff --git a/src/features/ccDarkTheme/core/styles/components/custom/_log.scss b/src/features/ccDarkTheme/core/styles/components/custom/_log.scss
new file mode 100644
index 0000000..5184810
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/custom/_log.scss
@@ -0,0 +1,7 @@
+.TWPT-log {
+  background-color: #424242!important;
+}
+
+.TWPT-log-entry.TWPT-log-entry--error {
+  color: #ff8A80!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/custom/_warning.scss b/src/features/ccDarkTheme/core/styles/components/custom/_warning.scss
new file mode 100644
index 0000000..f40844a
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/custom/_warning.scss
@@ -0,0 +1,3 @@
+.TWPT-warning {
+  background-color: #670505!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/dialogs/_bug-case-links.scss b/src/features/ccDarkTheme/core/styles/components/dialogs/_bug-case-links.scss
new file mode 100644
index 0000000..0d35544
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/dialogs/_bug-case-links.scss
@@ -0,0 +1,7 @@
+.bug-case-links-dialog material-button.add-button {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+ec-bug-case-link material-button {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/dialogs/_dialog.scss b/src/features/ccDarkTheme/core/styles/components/dialogs/_dialog.scss
new file mode 100644
index 0000000..4f3570c
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/dialogs/_dialog.scss
@@ -0,0 +1,56 @@
+material-dialog, material-dialog .dialog-header {
+  background-color: var(--TWPT-primary-background)!important;
+}
+
+ec-movable-dialog[showminimize] material-dialog .dialog-header {
+  background-color: #d2e3fc!important;
+}
+
+material-dialog .title {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+material-dialog header material-button:is(.close-button, [debugid="close-button"]) material-icon {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+ec-movable-dialog[showminimize] material-dialog .dialog-header .title, ec-movable-dialog[showminimize] material-dialog header material-icon {
+  color: var(--TWPT-primary-background)!important;
+}
+
+ec-movable-dialog material-dialog :is(.header-notice, .notice), material-dialog .legal-prompt {
+  background-color: #394457!important;
+}
+
+ec-movable-dialog material-dialog .main :is(.header-notice, .notice) material-icon[icon="info_outline"] {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+material-dialog .section-title,
+    material-dialog .select-label,
+    material-dialog .input-label,
+    material-dialog .btn-no,
+    ec-display-name-editor,
+    .forum-selection-label {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-dialog main > .user {
+  border-bottom-color: var(--TWPT-card-border)!important;
+}
+
+ec-movable-dialog[showminimize] material-dialog footer > [footer] > .footer > [footer] > simple-html {
+  color: var(--TWPT-secondary-text)!important;
+  background-color: var(--TWPT-active-background)!important;
+  border-top-color: #25231f!important;
+}
+
+ec-movable-dialog[showminimize] material-dialog footer > [footer] > .footer > [footer] > simple-html a {
+  color: var(--TWPT-link)!important;
+}
+
+material-dialog .footer material-button[raised]:not([disabled]),
+    material-dialog .footer .mdc-button.submit:not(:disabled){
+  background-color: var(--TWPT-blue-A100)!important;
+  color: #1f1f1f!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/dialogs/_index.scss b/src/features/ccDarkTheme/core/styles/components/dialogs/_index.scss
new file mode 100644
index 0000000..3ec7a09
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/dialogs/_index.scss
@@ -0,0 +1,5 @@
+@forward 'dialog';
+@forward 'private-message';
+@forward 'keyboard-shortcuts';
+@forward 'bug-case-links';
+@forward 'report';
diff --git a/src/features/ccDarkTheme/core/styles/components/dialogs/_keyboard-shortcuts.scss b/src/features/ccDarkTheme/core/styles/components/dialogs/_keyboard-shortcuts.scss
new file mode 100644
index 0000000..047118b
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/dialogs/_keyboard-shortcuts.scss
@@ -0,0 +1,20 @@
+material-dialog .main.with-scroll-strokes table th {
+  color: var(--TWPT-primary-text)!important;
+}
+
+material-dialog .main.with-scroll-strokes table td {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+material-dialog .main.with-scroll-strokes table tr,
+    material-dialog .main.with-scroll-strokes .shortcut {
+  border-color: var(--TWPT-card-border)!important;
+}
+
+material-dialog .main.with-scroll-strokes.bottom-scroll-stroke {
+  border-bottom-color: var(--TWPT-card-border)!important;
+}
+
+material-dialog .main.with-scroll-strokes.top-scroll-stroke {
+  border-top-color: var(--TWPT-card-border)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/dialogs/_private-message.scss b/src/features/ccDarkTheme/core/styles/components/dialogs/_private-message.scss
new file mode 100644
index 0000000..7e531b9
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/dialogs/_private-message.scss
@@ -0,0 +1,7 @@
+ec-movable-dialog .wrapper > .main > main > .top-row > div { // Note: this is too generic so it might match other things
+  color: var(--TWPT-primary-text)!important;
+}
+
+ec-movable-dialog .wrapper > .main > main > .top-row .recipient-container .recipient {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/dialogs/_report.scss b/src/features/ccDarkTheme/core/styles/components/dialogs/_report.scss
new file mode 100644
index 0000000..8c6bb46
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/dialogs/_report.scss
@@ -0,0 +1,3 @@
+iframe[src*="reportingwidget"] {
+  color-scheme: auto;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_checkbox.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_checkbox.scss
new file mode 100644
index 0000000..657373f
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_checkbox.scss
@@ -0,0 +1,35 @@
+// This doesn't apply to checkboxes in the drawer
+material-checkbox material-icon:not(ec-forum-drawer-item material-icon, ec-thread-list material-icon) {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-checkbox .content:not(ec-forum-drawer-item material-icon, ec-thread-list material-icon) {
+  color: var(--TWPT-primary-text)!important;
+}
+
+material-checkbox.disabled .content:not(ec-forum-drawer-item material-icon, ec-thread-list material-icon) {
+  color: rgba(255, 255, 255, .54)!important;
+}
+
+/* .gm-icons is added by the SMEI_GOOGLE_MATERIAL_ICONS experiment. */
+material-checkbox material-icon.filled:not(ec-forum-drawer-item material-icon, ec-thread-list material-icon) {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+material-checkbox:focus:not(.disabled).gm-icons .icon,
+    .gm-icons material-checkbox:focus:not(.disabled) .icon,
+    material-checkbox:hover:not(.disabled).gm-icons .icon,
+    .gm-icons material-checkbox:hover:not(.disabled) .icon {
+  color: #cfd2d8!important; /* custom value */
+}
+
+material-checkbox:focus:not(.disabled).gm-icons .icon.filled,
+    .gm-icons material-checkbox:focus:not(.disabled) .icon.filled,
+    material-checkbox:hover:not(.disabled).gm-icons .icon.filled,
+    .gm-icons material-checkbox:hover:not(.disabled) .icon.filled {
+  color: var(--TWPT-blue-100)!important;
+}
+
+.gm-icons material-checkbox .icon-container::before{
+  background-color: #dfdedb!important; /* custom value */
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_dropdown-select.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_dropdown-select.scss
new file mode 100644
index 0000000..9ea47d8
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_dropdown-select.scss
@@ -0,0 +1,8 @@
+material-dropdown-select dropdown-button {
+  color: var(--TWPT-primary-text)!important;
+}
+
+material-dropdown-select dropdown-button .button.is-disabled .button-text,
+    material-dropdown-select dropdown-button .button.is-disabled material-icon {
+  color: rgba(255, 255, 255, .32)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_index.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_index.scss
new file mode 100644
index 0000000..a1d509b
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_index.scss
@@ -0,0 +1,7 @@
+@forward 'checkbox';
+@forward 'dropdown-select';
+@forward 'pickers';
+@forward 'radio';
+@forward 'selector';
+@forward 'switch';
+@forward 'text';
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_pickers.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_pickers.scss
new file mode 100644
index 0000000..d551158
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_pickers.scss
@@ -0,0 +1,18 @@
+ec-work-state-picker > button,
+    ec-symptom-picker > button {
+  color: var(--TWPT-secondary-text)!important;
+  background-color: var(--TWPT-button-background)!important;
+  border-color: var(--TWPT-subtle-border)!important;
+}
+
+.material-popup-content .popup-content {
+  header {
+    .title {
+      color: var(--TWPT-primary-text)!important;
+    }
+
+    material-button material-icon {
+      color: var(--TWPT-subtle-button-background)!important;
+    }
+  }
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_radio.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_radio.scss
new file mode 100644
index 0000000..e7b1668
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_radio.scss
@@ -0,0 +1,12 @@
+material-radio .icon-container:not(.checked) material-icon {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+material-radio .icon-container.checked material-icon {
+  color: var(--TWPT-blue-A100)!important;
+}
+
+material-radio {
+  --gm-radio-stroke-color--checked: var(--TWPT-blue-A100);
+  --gm-radio-ink-color: var(--TWPT-blue-A100);
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_selector.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_selector.scss
new file mode 100644
index 0000000..96650ac
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_selector.scss
@@ -0,0 +1,51 @@
+// This applies not only to the selector but also to the ec-work-state-picker.
+material-list, .popup .item-group-list {
+  background-color: var(--TWPT-drawer-background)!important;
+}
+
+material-list [group]:not(.empty) + *:not(script):not(template):not(.empty),
+    .popup .item-group-list [group]:not(.empty) + *:not(script):not(template):not(.empty) {
+  box-shadow: inset 0 8px 0 0 var(--TWPT-drawer-background)!important;
+  border-top-color: #1f1f1f!important;
+}
+
+material-list material-select-item:hover,
+    material-list material-select-item:focus,
+    material-list material-select-dropdown-item:hover,
+    material-list material-select-dropdown-item:focus,
+    material-list material-select-dropdown-item.active,
+    material-list material-select-dropdown-item:not(.multiselect).selected,
+    material-select-searchbox:focus-within + material-list .single-select-item:first-of-type,
+    .popup .item-group-list material-select-item:hover,
+    .popup .item-group-list material-select-item:focus,
+    .popup .item-group-list material-select-item.active,
+    .popup .item-group-list material-select-dropdown-item:hover,
+    .popup .item-group-list material-select-dropdown-item:focus,
+    .popup .item-group-list material-select-dropdown-item.active,
+    .popup .item-group-list material-select-dropdown-item:not(.multiselect).selected {
+  background-color: var(--TWPT-highlighted-item-background)!important;
+}
+
+material-list .single-select-item,
+    material-list .menu-item-label,
+    material-list .label,
+    material-list .text-segment,
+    menu-item-groups .single-select-item,
+    menu-item-groups .menu-item-label,
+    menu-item-groups .label,
+    menu-item-groups .text-segment {
+  color: var(--TWPT-icon-color)!important;
+}
+
+.popup .item-group-list material-icon {
+  color: rgba(255, 255, 255, .7)!important;
+}
+
+material-list [group] > [label] {
+  color: #8a8a8a!important;
+}
+
+// This is shown in the new thread view
+ec-forum-language-picker .labeled-select .select-label {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_switch.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_switch.scss
new file mode 100644
index 0000000..4d1f61d
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_switch.scss
@@ -0,0 +1,15 @@
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__track {
+  background-color: #7d7d7d!important; /* custom value */
+}
+
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb {
+  border-color: #fff!important; /* custom value */
+}
+
+.mdc-switch.mdc-switch--checked .mdc-switch__track {
+  background-color: var(--TWPT-blue-A100)!important;
+}
+
+.mdc-switch.mdc-switch--checked .mdc-switch__thumb {
+  border-color: var(--TWPT-blue-A100)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/inputs/_text.scss b/src/features/ccDarkTheme/core/styles/components/inputs/_text.scss
new file mode 100644
index 0000000..b61da70
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/inputs/_text.scss
@@ -0,0 +1,70 @@
+material-input input {
+  color: var(--TWPT-primary-text)!important;
+}
+
+material-input .label-text,
+    material-input .hint-text,
+    material-input .counter,
+    material-input .leading-text,
+    material-input .leading-text material-icon {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+material-input .underline .unfocused-underline {
+  background-color: var(--TWPT-input-underline)!important;
+}
+
+material-input .underline .focused-underline {
+  background-color: var(--TWPT-blue-A100)!important;
+}
+
+:is(material-input.gm-input, .gm-input material-input) .baseline {
+  border-color: var(--gm-outlinedtextfield-outline-color)!important;
+}
+
+:is(material-input.gm-input, .gm-input material-input) .baseline:hover {
+  border-color: var(--gm-outlinedtextfield-outline-color)!important;
+}
+
+:is(material-input.gm-input, .gm-input material-input) .baseline.focused {
+  border-color: var(--gm-outlinedtextfield-outline-color--stateful)!important;
+}
+
+:is(material-input.gm-input, .gm-input material-input).invalid .baseline {
+  border-color: var(--gm-outlinedtextfield-outline-color--error)!important;
+}
+
+:is(material-input.gm-input, .gm-input material-input).invalid .error-text {
+  color: var(--gm-outlinedtextfield-helper-text-color--error)!important;
+}
+
+label .label,
+    .input-field > .label {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.mdc-text-field--outlined:hover:not(.mdc-text-field--disabled):not(.mdc-text-field--focused) .mdc-floating-label {
+  color: var(--gm-outlinedtextfield-label-color)!important;
+}
+
+.mdc-text-field--outlined:hover:not(.mdc-text-field--disabled):not(.mdc-text-field--focused) .mdc-notched-outline :is(.mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing) {
+  border-color: var(--gm-outlinedtextfield-outline-color)!important;
+}
+
+.mdc-text-field--outlined.mdc-text-field--invalid:hover:not(.mdc-text-field--focused):not(.mdc-text-field--disabled) .mdc-floating-label {
+  color: var(--gm-outlinedtextfield-label-color--error)!important;
+}
+
+.mdc-text-field--outlined.mdc-text-field--invalid:hover:not(.mdc-text-field--disabled):not(.mdc-text-field--focused) .mdc-notched-outline :is(.mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing) {
+  border-color: var(--gm-outlinedtextfield-outline-color--error)!important;
+}
+
+.mdc-text-field--outlined.mdc-text-field--invalid:hover:not(.mdc-text-field--focused):not(.mdc-text-field--disabled) + .mdc-text-field-helper-line .mdc-text-field-helper-text {
+  color: var(--gm-outlinedtextfield-helper-text-color--error)!important;
+}
+
+// Input underline
+material-input .underline .unfocused-underline,
+    material-dropdown-select dropdown-button [buttondecorator] {
+  border-color: var(--TWPT-input-underline)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/notifications/_bell.scss b/src/features/ccDarkTheme/core/styles/components/notifications/_bell.scss
new file mode 100644
index 0000000..1e3d0b5
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/notifications/_bell.scss
@@ -0,0 +1,3 @@
+notification-bell:focus {
+  background-color: rgba(255, 255, 255, .10)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/notifications/_index.scss b/src/features/ccDarkTheme/core/styles/components/notifications/_index.scss
new file mode 100644
index 0000000..f5445bb
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/notifications/_index.scss
@@ -0,0 +1,2 @@
+@forward 'bell';
+@forward 'panel';
diff --git a/src/features/ccDarkTheme/core/styles/components/notifications/_panel.scss b/src/features/ccDarkTheme/core/styles/components/notifications/_panel.scss
new file mode 100644
index 0000000..6e443ec
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/notifications/_panel.scss
@@ -0,0 +1,32 @@
+.notification-panel .header {
+  border-bottom-color: var(--TWPT-card-border)!important;
+}
+
+.notification-panel .header material-button {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+.notification-panel .cards-container .promo-message {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+.notification-panel .cards-container .promo-message .header-text {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.notification-panel .cards-container ec-notification-card-content {
+  border-bottom-color: var(--TWPT-card-border)!important;
+}
+
+.notification-panel .cards-container ec-notification-card-content .text {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.notification-panel .cards-container ec-notification-card-content .text a {
+  color: var(--TWPT-link)!important;
+}
+
+.notification-panel .cards-container ec-notification-card-content .time,
+    .notification-panel .cards-container ec-notification-card-content .close material-button {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/popups/_account-selector.scss b/src/features/ccDarkTheme/core/styles/components/popups/_account-selector.scss
new file mode 100644
index 0000000..f4da84b
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/popups/_account-selector.scss
@@ -0,0 +1,12 @@
+.popup-wrapper .profile .email {
+  color: var(--TWPT-subtle-button-background)!important;
+}
+
+material-gaia-picker-footer {
+  color: var(--TWPT-subtle-button-background)!important;
+  background-color: var(--TWPT-active-background)!important;
+}
+
+material-gaia-picker-footer material-button {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/popups/_announcements.scss b/src/features/ccDarkTheme/core/styles/components/popups/_announcements.scss
new file mode 100644
index 0000000..03b12d1
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/popups/_announcements.scss
@@ -0,0 +1,30 @@
+ec-announcements-content .header,
+    ec-announcements-content .no-announcements,
+    ec-announcements-content .announcement {
+  border-bottom-color: var(--TWPT-card-border)!important;
+}
+
+ec-announcements-content .header .title, ec-announcements-content .announcement-title {
+  color: var(--TWPT-primary-text-alt)!important;
+}
+
+ec-announcements-content .announcement-date {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+ec-announcements-content .no-announcements-message {
+  color: #c3bfbc!important;
+}
+
+ec-announcements-content .view-all-link,
+    ec-announcements-content .read-more-button {
+  color: var(--TWPT-link)!important;
+}
+
+ec-announcements-content ::-webkit-scrollbar-thumb {
+  background-color: rgba(255, 255, 255, .26)!important;
+}
+
+ec-announcements-content ::-webkit-scrollbar-thumb:hover {
+  background-color: #4285f4!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/components/popups/_index.scss b/src/features/ccDarkTheme/core/styles/components/popups/_index.scss
new file mode 100644
index 0000000..a12ea2c
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/popups/_index.scss
@@ -0,0 +1,3 @@
+@forward 'popup';
+@forward 'account-selector';
+@forward 'announcements';
diff --git a/src/features/ccDarkTheme/core/styles/components/popups/_popup.scss b/src/features/ccDarkTheme/core/styles/components/popups/_popup.scss
new file mode 100644
index 0000000..11f01e7
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/components/popups/_popup.scss
@@ -0,0 +1,8 @@
+// Generic popup (for notification bell, account selector, etc.)
+.popup-wrapper {
+  background-color: var(--TWPT-drawer-background)!important;
+
+  .header-text {
+    color: var(--TWPT-primary-text)!important;
+  }
+}
diff --git a/src/features/ccDarkTheme/core/styles/layout/_header.scss b/src/features/ccDarkTheme/core/styles/layout/_header.scss
new file mode 100644
index 0000000..8e13bac
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/layout/_header.scss
@@ -0,0 +1,34 @@
+.material-content > header {
+  background-color: var(--TWPT-primary-background)!important;
+}
+
+.material-content > header .app-title-button,
+    .material-content > header .app-title-text {
+  color: var(--TWPT-secondary-text)!important;
+}
+
+.material-content > header :is(material-button,
+    material-button material-icon,
+    .mdc-button.mdc-icon-button,
+    .mdc-button.mdc-icon-button material-icon,
+    notification-bell material-icon) {
+  color: var(--TWPT-icon-color)!important;
+}
+
+.search-box {
+  background-color: #313235!important;
+}
+
+.search-box .clear-icon {
+  opacity: 0.8;
+  color: var(--TWPT-icon-color)!important;
+}
+
+.material-content > header .bell.mixin {
+  fill: var(--TWPT-icon-color)!important;
+}
+
+// Header menus
+.popup material-list-item {
+  color: var(--TWPT-drawer-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/layout/_index.scss b/src/features/ccDarkTheme/core/styles/layout/_index.scss
new file mode 100644
index 0000000..c50e4e1
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/layout/_index.scss
@@ -0,0 +1,2 @@
+@forward 'header';
+@forward 'main';
diff --git a/src/features/ccDarkTheme/core/styles/layout/_main.scss b/src/features/ccDarkTheme/core/styles/layout/_main.scss
new file mode 100644
index 0000000..0f50d46
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/layout/_main.scss
@@ -0,0 +1,27 @@
+.main {
+  color: var(--TWPT-primary-text)!important;
+}
+
+// Border color for the page title bar (most pages use .title-bar although
+// some use .page-header).
+main .title-bar, main .page-header {
+  border-bottom-color: var(--TWPT-subtle-border)!important;
+}
+
+main .title-bar .title, main .page-header h1, main .header h1 {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.card {
+  background-color: var(--TWPT-secondary-background)!important;
+  color: var(--TWPT-primary-text)!important;
+  border-color: var(--TWPT-card-border)!important;
+}
+
+.card .card-title, .card, .card-section-title {
+  color: var(--TWPT-primary-text)!important;
+}
+
+.card .card-section-hint, .card .card-section-checkbox-hint {
+  color: var(--TWPT-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/main.scss b/src/features/ccDarkTheme/core/styles/main.scss
new file mode 100644
index 0000000..34f4679
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/main.scss
@@ -0,0 +1,5 @@
+@use 'abstracts/variables';
+@use 'base/base';
+@use 'layout';
+@use 'components';
+@use 'vendors';
diff --git a/src/features/ccDarkTheme/core/styles/vendors/_index.scss b/src/features/ccDarkTheme/core/styles/vendors/_index.scss
new file mode 100644
index 0000000..c26393a
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/vendors/_index.scss
@@ -0,0 +1 @@
+@forward 'google';
diff --git a/src/features/ccDarkTheme/core/styles/vendors/google/IMPORTANT_NOTICE.txt b/src/features/ccDarkTheme/core/styles/vendors/google/IMPORTANT_NOTICE.txt
new file mode 100644
index 0000000..7825047
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/vendors/google/IMPORTANT_NOTICE.txt
@@ -0,0 +1,2 @@
+IMPORTANT NOTICE: the styles in this folder have been written by Googlers and
+thus are not included as part of the MIT license.
diff --git a/src/features/ccDarkTheme/core/styles/vendors/google/_common-interop-components.scss b/src/features/ccDarkTheme/core/styles/vendors/google/_common-interop-components.scss
new file mode 100644
index 0000000..6a9f28a
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/vendors/google/_common-interop-components.scss
@@ -0,0 +1,770 @@
+/*
+ * IMPORTANT NOTICE:
+ * Note: the following styles have been written by Googlers and thus are not
+ * included as part of the MIT license.
+ **/
+
+.scSharedCalloutroot {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scSharedCallouterror {
+  background-color: #523a3b!important;
+  border-color: #f9dedc!important;
+}
+
+.scSharedCallouterror sc-shared-material-icon {
+  color: #f9dedc!important;
+}
+
+.scSharedCallouterror>.scSharedCalloutsecondary-button button {
+  color: #ec928e!important;
+}
+
+.scSharedCalloutcaution {
+  background-color: #554c33!important;
+  border-color: #ffdf99!important;
+}
+
+.scSharedCalloutcaution sc-shared-material-icon {
+  color: #ffdf99!important;
+}
+
+.scSharedCalloutcaution>.scSharedCalloutsecondary-button button {
+  color: #f09d00!important;
+}
+
+.scSharedCalloutinformational {
+  background-color: #394457!important;
+  border-color: #d3e3fd!important;
+}
+
+.scSharedCalloutinformational sc-shared-material-icon {
+  color: #d3e3fd!important;
+}
+
+.scSharedCalloutinformational>.scSharedCalloutsecondary-button button {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedCalloutsuccess {
+  background-color: #37493f!important;
+  border-color: #c4eed0!important;
+}
+
+.scSharedCalloutsuccess sc-shared-material-icon {
+  color: #c4eed0!important;
+}
+
+.scSharedCalloutsuccess>.scSharedCalloutsecondary-button button {
+  color: var(--TWPT-interop-success)!important;
+}
+
+.scSharedMaterialbuttonroot {
+  --m-btn-text-color: var(--TWPT-interop-blue);
+  --m-btn-background-color: transparent;
+  --m-btn-outline-color: var(--TWPT-interop-blue);
+  background: var(--m-btn-background-color)!important;
+  color: var(--m-btn-text-color)!important;
+}
+
+.scSharedMaterialbuttonroot:disabled {
+  color: rgba(227, 227, 227, 0.369)!important;
+}
+
+.scSharedMaterialbuttontext {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialbuttoncolor-label {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialbuttoncolor-hint {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialbuttonnavigational {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scSharedMaterialbuttonnavigational-alt {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialbuttonhairline, .scSharedMaterialbuttonpill {
+  outline: 1px solid var(--m-btn-outline-color)!important;
+}
+
+.scSharedMaterialbuttonhairline:hover, .scSharedMaterialbuttonhairline:focus, .scSharedMaterialbuttonpill:hover, .scSharedMaterialbuttonpill:focus {
+  --m-btn-outline-color: currentColor!important;
+}
+
+.scSharedMaterialbuttonhairline {
+  --m-btn-outline-color: var(--TWPT-interop-subtle-border)!important;
+}
+
+.scSharedMaterialbuttonhairline:disabled {
+  --m-btn-outline-color: rgba(227, 227, 227, 0.369)!important;
+}
+
+.scSharedMaterialbuttonhairline:active {
+  box-shadow: 0 1px 2px 0 rgba(227, 227, 227, 0.302), 0 1px 3px 1px rgba(227, 227, 227, 0.149)!important;
+}
+
+.scSharedMaterialbuttontonal {
+  color: var(--TWPT-interop-blue)!important;
+  background: #394457!important;
+  outline: 1px solid #474747!important;
+}
+
+.scSharedMaterialbuttontonal:hover {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149)!important;
+}
+
+.scSharedMaterialbuttontonal:active {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 2px 6px 2px rgba(0, 0, 0, 0.149)!important;
+}
+
+.scSharedMaterialbuttontonal:disabled {
+  background: rgba(227, 227, 227, 0.122)!important;
+}
+
+.scSharedMaterialbuttonfilled {
+  background: var(--TWPT-interop-blue)!important;
+  color: #1f1f1f!important;
+}
+
+.scSharedMaterialbuttonfilled:disabled {
+  background: rgba(227, 227, 227, 0.122)!important;
+}
+
+.scSharedMaterialbuttonfilled:hover,
+    .scSharedMaterialbuttonfilled:focus {
+  box-shadow: 0 1px 2px 0 rgba(124, 172, 248, 0.302), 0 1px 3px 1px rgba(124, 172, 248, 0.149)!important;
+}
+
+.scSharedMaterialbuttonfilled:active {
+  box-shadow: 0 1px 3px 0 rgba(124, 172, 248, 0.302), 0 4px 8px 3px rgba(124, 172, 248, 0.149)!important;
+}
+
+.scSharedMaterialbuttonprotected {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149)!important;
+  background: #1f1f1f!important;
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialbuttonprotected:disabled {
+  background: rgba(227, 227, 227, 0.122)!important;
+}
+
+.scSharedMaterialbuttonprotected:hover {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149)!important;
+}
+
+.scSharedMaterialbuttonprotected:focus {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 2px 6px 2px rgba(0, 0, 0, 0.149)!important;
+}
+
+.scSharedMaterialbuttonprotected:active {
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.302), 0 4px 8px 3px rgba(0, 0, 0, 0.149)!important;
+}
+
+.scSharedMaterialbuttonsuccess {
+  --m-btn-text-color: var(--TWPT-interop-success)!important;
+  --m-btn-outline-color: var(--TWPT-interop-success)!important;
+}
+
+.scSharedMaterialbuttonsuccess.scSharedMaterialbuttonfilled {
+  --m-btn-text-color: #1f1f1f!important;
+  --m-btn-background-color: var(--TWPT-interop-success)!important;
+}
+
+.scSharedMaterialbuttonsuccess.scSharedMaterialbuttontonal {
+  --m-btn-background-color: #0f5223
+}
+
+@media (forced-colors:active) {
+    .scSharedMaterialbuttonroot:focus {
+        outline: 2px solid #e3e3e3;
+    }
+}
+
+@media (prefers-contrast:more) {
+    .scSharedMaterialbuttonroot:focus {
+        outline: 2px solid #e3e3e3;
+    }
+}
+
+.scSharedExpandabletextexpander {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialborderfilled {
+  background: #313235!important;
+  border-bottom: 1px solid var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialborderfilled-error {
+  border-bottom-color: #ec928e!important;
+}
+
+.scSharedMaterialborderfilled-bottom {
+  background-color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialborderfilled-label {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialborderfilled-label-focused {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialborderlabel {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialborderleft {
+  border-bottom-color: var(--TWPT-interop-secondary-text)!important;
+  border-left-color: var(--TWPT-interop-secondary-text)!important;
+  border-top-color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialborderleft-error {
+  border-bottom-color: #ec928e!important;
+  border-left-color: #ec928e!important;
+  border-top-color: #ec928e!important;
+}
+
+.scSharedMaterialbordermid {
+  border-bottom-color: var(--TWPT-interop-secondary-text)!important;
+  border-top-color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialbordermid-error {
+  border-bottom-color: #ec928e!important;
+  border-top-color: #ec928e!important;
+}
+
+.scSharedMaterialborderright {
+  border-bottom-color: var(--TWPT-interop-secondary-text)!important;
+  border-right-color: var(--TWPT-interop-secondary-text)!important;
+  border-top-color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialborderright-error {
+  border-bottom-color: #ec928e!important;
+  border-right-color: #ec928e!important;
+  border-top-color: #ec928e!important;
+}
+
+.scSharedMaterialborderfocused {
+  border-color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialborderdisabled {
+  border-color: var(--TWPT-interop-subtle-border)!important;
+}
+
+.scSharedMaterialborderlabel-focused {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialborderlabel-disabled {
+  color: rgba(255, 255, 255, 0.239)!important;
+}
+
+.scSharedMaterialborderlabel-error {
+  color: #ec928e!important;
+}
+
+.scSharedMaterialcardroot {
+  background: #1f1f1f;
+  border: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scSharedMaterialcardelevation-1 {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149)!important;
+  background: #2a2b2f!important;
+}
+
+.scSharedMaterialcardelevation-2 {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 2px 6px 2px rgba(0, 0, 0, 0.149)!important;
+  background: #303135!important;
+}
+
+.scSharedMaterialcardelevation-3 {
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.302), 0 4px 8px 3px rgba(0, 0, 0, 0.149)!important;
+  background: #36383a!important;
+}
+
+.scSharedMaterialcardelevation-4 {
+  box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.302), 0 6px 10px 4px rgba(0, 0, 0, 0.149)!important;
+  background: #39393c!important;
+}
+
+.scSharedMaterialcardelevation-5 {
+  box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.302), 0 8px 12px 6px rgba(0, 0, 0, 0.149)!important;
+  background: #3c3e40!important;
+}
+
+@media (forced-colors:active) {
+  .scsharedmaterialcardroot {
+    border-color: #e3e3e3;
+  }
+}
+
+@media (prefers-contrast:more) {
+  .scsharedmaterialcardroot {
+    border-color: #e3e3e3;
+  }
+}
+
+.scSharedMaterialcheckboxcheckbox {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialcheckboxbox {
+  border-color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialcheckboxnative-control:checked:disabled+.scSharedMaterialcheckboxbox,
+.scSharedMaterialcheckboxnative-control:indeterminate:disabled+.scSharedMaterialcheckboxbox {
+  background: rgba(0, 0, 0, .26);
+  border-color: transparent;
+}
+
+.scSharedMaterialcheckboxnative-control:disabled+.scSharedMaterialcheckboxbox {
+  border-color: rgba(0, 0, 0, .26);
+}
+
+.scSharedMaterialcheckboxcheckmark-path {
+  stroke: #1f1f1f!important;
+}
+
+.scSharedMaterialcheckboxmixedmark {
+  border-color: #1f1f1f!important;
+}
+
+.scSharedMaterialfabroot {
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.302), 0 4px 8px 3px rgba(0, 0, 0, 0.149);
+  background: #303135;
+  color: var(--TWPT-interop-blue);
+}
+
+@media (forced-colors:active) {
+  .scSharedMaterialfabroot {
+    outline: 3px solid var(--TWPT-interop-blue);
+  }
+}
+
+.scSharedMaterialfabroot.scSharedMaterialfabgrey {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scSharedMaterialfabroot:hover,
+.scSharedMaterialfabroot:focus {
+  box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.302), 0 6px 10px 4px rgba(0, 0, 0, 0.149);
+}
+
+.scSharedMaterialfabroot:active {
+  box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.302), 0 8px 12px 6px rgba(0, 0, 0, 0.149);
+}
+
+.scSharedMaterialfablowered {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149);
+}
+
+.scSharedMaterialfablowered.scSharedMaterialfabfake-focus,
+.scSharedMaterialfablowered:hover,
+.scSharedMaterialfablowered:focus {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 2px 6px 2px rgba(0, 0, 0, 0.149);
+}
+
+.scSharedMaterialfablowered:active {
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.302), 0 4px 8px 3px rgba(0, 0, 0, 0.149);
+}
+
+.scSharedMaterialfabfilled {
+  background: rgba(124,172,248,0.239);
+  color: var(--TWPT-interop-blue);
+}
+
+.scSharedMaterialfabfilled.scSharedMaterialfabgrey {
+  background: var(--TWPT-interop-secondary-text);
+  color: #1f1f1f;
+}
+
+.scSharedMaterial_dialogDialogcontentloading-overlay {
+  background: rgba(227, 227, 227, 0.122)!important;
+}
+
+.scSharedMaterialpopupbackground {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149)!important;
+  background: #2a2b2f!important;
+  border: 1px solid var(--TWPT-interop-subtle-border)!important;
+}
+
+@media (forced-colors:active) {
+  .scSharedMaterialpopupbackground {
+    border-color: #e3e3e3;
+  }
+}
+
+@media (prefers-contrast:more) {
+  .scSharedMaterialpopupbackground {
+    border-color: #e3e3e3;
+  }
+}
+
+.scSharedMaterialmenuroot {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149)!important;
+  background: #2a2b2f!important;
+}
+
+.scSharedMaterialmenuitem {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scSharedMaterialmenuitem[disabled] {
+  color: var(--TWPT-interop-subtle-border);
+}
+
+.scSharedMaterialmenuitem-separator {
+  border-top-color: var(--TWPT-interop-subtle-border)!important;
+}
+
+.scSharedMaterialmenuhighlight:focus,
+    .scSharedMaterialmenuhighlight:hover {
+  background-color: #394457!important;
+}
+
+.scSharedMaterialmenuhighlight:focus {
+  outline: auto var(--TWPT-interop-blue) 1px!important;
+}
+
+.scSharedMaterialtooltipcontainer {
+  background-color: #e3e3e3;
+  color: #1f1f1f;
+}
+
+.scSharedMaterialradioradio {
+  color: var(--TWPT-interop-blue);
+}
+
+.scSharedMaterialradioring {
+  border: 2px solid var(--TWPT-interop-secondary-text);
+}
+
+.scSharedMaterialradionative-control:disabled~.scSharedMaterialradioring {
+  border-color: rgba(0, 0, 0, .26);
+}
+
+.scSharedMaterialradiodot {
+  border-color: var(--TWPT-interop-blue);
+}
+
+.scSharedMaterialradionative-control:disabled~.scSharedMaterialradiodot {
+  background: rgba(0, 0, 0, .26);
+}
+
+.scSharedMaterialrichtooltipcontainer {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149);
+}
+
+.scSharedMaterialrichtooltiproot.scSharedMaterialrichtooltipstyle-normal .scSharedMaterialrichtooltipcontainer {
+  background: #2a2b2f;
+}
+
+.scSharedMaterialrichtooltiproot.scSharedMaterialrichtooltipstyle-accented .scSharedMaterialrichtooltipcontainer {
+  background: var(--TWPT-interop-blue);
+  color: #1f1f1f;
+}
+
+.scSharedMaterialrichtooltipcaret {
+  box-shadow: 1.5px 1.5px 1px -1px rgba(0, 0, 0, 0.2), .75px .75px 1px 0 rgba(0, 0, 0, 0.141), .75px .75px 3px 0 rgba(0, 0, 0, 0.122);
+  background: #2a2b2f;
+}
+
+.scSharedMaterialrichtooltiproot.scSharedMaterialrichtooltipstyle-normal .scSharedMaterialrichtooltipcaret {
+  background: #2a2b2f;
+}
+
+.scSharedMaterialrichtooltiproot.scSharedMaterialrichtooltipstyle-accented .scSharedMaterialrichtooltipcaret {
+  background: var(--TWPT-interop-blue);
+}
+
+.scSharedMaterialselectlabel {
+  color: #e3e3e3;
+}
+
+.scSharedMaterialselectarrow {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scSharedMaterialselectactive .scSharedMaterialselectarrow {
+  color: var(--TWPT-interop-blue);
+}
+
+.scSharedMaterialselectdisabled .scSharedMaterialselectselection,
+.scSharedMaterialselectdisabled .scSharedMaterialselectarrow {
+  color: rgba(255, 255, 255, 0.239);
+}
+
+.scSharedMaterialsnackbarsnackbar {
+  background: var(--TWPT-interop-primary-text)!important;
+  color: #1f1f1f!important;
+}
+
+.scSharedMaterialsnackbaraction button {
+  color: #0b57d0!important;
+}
+
+.scSharedMaterialtabbartab {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scSharedMaterialtabbartab:hover,
+    .scSharedMaterialtabbartab:focus {
+  background-color: #313235!important;
+}
+
+.scSharedMaterialtabbarselected {
+  border-bottom-color: var(--TWPT-interop-blue)!important;
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialtextfieldlabel {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scSharedMaterialtextfieldnative-control {
+  caret-color: var(--TWPT-interop-blue)!important;
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scSharedMaterialtextfieldinvalid .scSharedMaterialtextfieldnative-control {
+  caret-color: #ec928e!important;
+}
+
+.scSharedMaterialtextfieldnative-control:disabled {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialtextfieldfocused .scSharedMaterialtextfieldlabel {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scSharedMaterialtextfieldinvalid .scSharedMaterialtextfieldlabel {
+  color: #ec928e!important;
+}
+
+.scSharedMaterialtextfielddisabled .scSharedMaterialtextfieldlabel {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialtextfieldhelper-text {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scSharedMaterialtextfieldhelper-text-invalid {
+  color: #ec928e!important;
+}
+
+.scSharedMaterialtextfieldhelper-text-disabled {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindSharedActivitychartroot {
+  border: 1px solid var(--TWPT-interop-subtle-border)!important;
+}
+
+.scTailwindSharedAvatarroot {
+  background-color: #f1f3f4;
+  border: .375rem solid #f1f3f4;
+}
+
+.scTailwindSharedAvatarroot.scTailwindSharedAvatarmedium.scTailwindSharedAvatarat-least-silver,
+.scTailwindSharedAvatarroot.scTailwindSharedAvatarsmall.scTailwindSharedAvatarat-least-silver {
+  border: .125rem solid #f1f3f4;
+}
+
+.scTailwindSharedAvatarsilhouette {
+  background-color: #fff;
+}
+
+.scTailwindSharedAvataravatar-loading {
+  background: #1f1f1f!important;
+}
+
+.scTailwindSharedAvataruploadedit-button {
+  background-color: rgba(0, 0, 0, 0.4);
+  color: #fff;
+}
+
+.scTailwindSharedAvataruploadroot:focus .scTailwindSharedAvataruploadedit-button,
+.scTailwindSharedAvataruploadroot:focus-within .scTailwindSharedAvataruploadedit-button,
+.scTailwindSharedAvataruploadroot:hover .scTailwindSharedAvataruploadedit-button {
+  background-color: rgba(0, 0, 0, 0.54);
+}
+
+.scTailwindSharedDisplay_name_editorDisplaynameeditorlabel {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedPiidialogfinding {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedReportabusedialogcontent .abuse-link {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scTailwindSharedRich_text_editorAttachmentFailedoverlayroot {
+  background: rgba(0, 0, 0, 0.902);
+  color: #ec928e;
+}
+
+.scTailwindSharedRich_text_editorAttachmentLoadingoverlayroot {
+  background: rgba(227, 227, 227, 0.369);
+}
+
+.scTailwindSharedRich_text_editorAttachmentRemovebuttonremove-button {
+  background: #1f1f1f;
+  border: 1px solid #27282b;
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedRich_text_editorAttachmentRemovebuttonremove-button:hover,
+.scTailwindSharedRich_text_editorAttachmentRemovebuttonremove-button:focus {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149);
+}
+
+.scTailwindSharedRich_text_editorAttachmentNoninlinedattachmentroot {
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 1px 3px 1px rgba(0, 0, 0, 0.149);
+  background: #36373a;
+}
+
+.scTailwindSharedRich_text_editorAttachmentNoninlinedattachmentfilename {
+  color: #e3e3e3;
+}
+
+.scTailwindSharedRich_text_editorAttachmentNoninlinedattachmentextension {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedRich_text_editorLinktooltiproot button {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindSharedRichtexteditoreditor {
+  background: #1f1f1f;
+  color: #e3e3e3;
+}
+
+.scTailwindSharedRichtexteditorplaceholder {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedRichtexteditorhas-bottom-panel {
+  border-bottom: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindSharedRichtexteditorhint {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedRich_text_editorToolbarcontrolroot {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedRich_text_editorToolbarcontrolroot:hover {
+  color: #e3e3e3;
+}
+
+.scTailwindSharedRich_text_editorToolbarcontrolroot:focus {
+  border: .125rem solid var(--TWPT-interop-blue);
+}
+
+.scTailwindSharedRich_text_editorToolbarcontrolactive {
+  background: rgba(227, 227, 227, 0.122);
+}
+
+.scTailwindSharedRich_text_editorToolbarMobiletoolbarattachment,
+.scTailwindSharedRich_text_editorToolbarMobiletoolbartext-format {
+  border-right: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindSharedRich_text_editorToolbarMobiletoolbartext-format-button {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindSharedRich_text_editorToolbarMobiletoolbargroup {
+  border-right: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindSharedRich_text_editorToolbargroup:not(:first-child) {
+  border-left: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindSharedTitlefieldhelper-text {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.sc-select {
+  border: .0625rem solid var(--TWPT-interop-secondary-text);
+  color: #e3e3e3;
+}
+
+.sc-select.keyboard-focus {
+  border-color: transparent;
+  box-shadow: 0 0 0 .125rem #a8c7fa;
+}
+
+.sc-select svg {
+  fill: var(--TWPT-interop-secondary-text);
+}
+
+.sc-select ol {
+  background: #272727;
+  box-shadow: 0 .1875rem .3125rem -.0625rem rgba(0, 0, 0, 0.4), 0 .375rem .625rem 0 rgba(0, 0, 0, 0.28), 0 .0625rem 1.125rem 0 rgba(0, 0, 0, 0.24);
+}
+
+.sc-select .sc-select-highlight {
+  background-color: #5ab3f0;
+  color: #1f1f1f;
+}
+
+.scRecommended_resourcesVideo_carouselVideocardroot {
+  background: #1f1f1f!important;
+  border: 1px solid var(--TWPT-interop-subtle-border)!important;
+}
+
+// The Community Console doesn't support the dark theme, so we need to style the
+// light components as if they were dark.
+.scRecommended_resourcesVideo_carouselVideocardlight:hover,.scRecommended_resourcesVideo_carouselVideocardlight:focus, .scRecommended_resourcesVideo_carouselVideocarddark:hover,.scRecommended_resourcesVideo_carouselVideocarddark:focus {
+  background: linear-gradient(0deg,rgba(168,199,250,.05),rgba(168,199,250,.05)),linear-gradient(0deg,rgba(199,199,199,.02),rgba(199,199,199,.02)),linear-gradient(0deg,#1f1f1f,#1f1f1f)!important;
+  border-color: transparent!important;
+}
+
+.scRecommended_resourcesVideo_carouselVideocardlight:focus, .scRecommended_resourcesVideo_carouselVideocarddark:focus {
+  outline: .125rem #fff solid!important;
+}
+
+.scRecommended_resourcesVideo_carouselVideocardtitle {
+  color: #e3e3e3!important;
+}
+
+.scRecommended_resourcesVideo_carouselVideocardicon {
+  filter: drop-shadow(0 0 24px rgba(0,0,0,.35))!important;
+}
+
+.scRecommended_resourcesVideo_carouselVideocardicon svg {
+  fill: #fff!important;
+}
+
+.scRecommended_resourcesVideo_carouselVideocardduration {
+  background-color: var(--TWPT-interop-secondary-text)!important;
+  color: #1f1f1f!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/vendors/google/_index.scss b/src/features/ccDarkTheme/core/styles/vendors/google/_index.scss
new file mode 100644
index 0000000..0e0a538
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/vendors/google/_index.scss
@@ -0,0 +1,3 @@
+@forward 'common-interop-components';
+@forward 'profile';
+@forward 'thread';
diff --git a/src/features/ccDarkTheme/core/styles/vendors/google/_profile.scss b/src/features/ccDarkTheme/core/styles/vendors/google/_profile.scss
new file mode 100644
index 0000000..4b7ca00
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/vendors/google/_profile.scss
@@ -0,0 +1,162 @@
+/*
+ * IMPORTANT NOTICE:
+ * Note: the following styles have been written by Googlers and thus are not
+ * included as part of the MIT license.
+ **/
+
+.scTailwindUser_profileAchievementsempty a,
+    .scTailwindUser_profileAchievementsempty a:visited,
+    sc-tailwind-user_profile-user-profile .link-icon {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scTailwindUser_profileBiosectionsection-heading {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileBiosectionbio {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scTailwindUser_profileBiosectionlinks,
+    .scTailwindUser_profileBiosectionlink {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scTailwindUser_profileBiosectioninput-label {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileEmaildisplayemail-display {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileEmaildisplayshow-email {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scTailwindUser_profileMessagecardthread-link {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileMessagecardlabel {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileMessagecardcontent {
+  border-left: 2px solid var(--TWPT-interop-subtle-border)!important;
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scTailwindUser_profileMessagecardcount {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileMessagecardrecommended-answer {
+  color: #6dd58c!important;
+}
+
+.scTailwindUser_profileMessagecardrecommended-answer .icon {
+  background-color: #6dd58c!important;
+  color: #1f1f1f!important;
+}
+
+sc-tailwind-user_profile-user-profile .notificationIcon {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+sc-tailwind-user_profile-user-profile .deleteIcon,
+    sc-tailwind-user_profile-user-profile .reportAbuseIcon,
+    sc-tailwind-user_profile-user-profile .reactivateIcon {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profilePosthistorysection+.scTailwindUser_profilePosthistorysection {
+  border-top-color: var(--TWPT-interop-subtle-border)!important;
+}
+
+.scTailwindUser_profilePosthistorycontent,
+    .scTailwindUser_profilePosthistoryheader,
+    .scTailwindUser_profilePosthistoryerror {
+  border-color: var(--TWPT-interop-subtle-border)!important;
+}
+
+.scTailwindUser_profileThreadcardtitle {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scTailwindUser_profileThreadcardlabel {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileThreadcardcontent {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scTailwindUser_profileThreadcardcount {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileThreadcardreply .icon {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileThreadcardrecommended-answer {
+  color: #6dd58c!important;
+}
+
+.scTailwindUser_profileThreadcardrecommended-answer .icon {
+  background-color: #6dd58c!important;
+  color: #1f1f1f!important;
+}
+
+.scTailwindUserprofileUgcsectionroot {
+  border: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindUserprofileUgcsectioncard-ugc-guide {
+  background-color: #1e1f20;
+}
+
+.scTailwindUserprofileUgcsectionthread-title {
+  color: #e3e3e3;
+}
+
+.scTailwindUserprofileUgcsectiondraft-tag {
+  background-color: #0f5223;
+  color: #6dd58c;
+}
+
+.scTailwindUserprofileUgcsectionthread-body {
+  color: #e3e3e3;
+}
+
+.scTailwindUser_profileUsercardroot {
+  border: 1px solid var(--TWPT-interop-subtle-border)!important;
+}
+
+.scTailwindUser_profileUsercardinput-label {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileUsercardheadline {
+  color: var(--TWPT-interop-primary-text)!important;
+}
+
+.scTailwindUser_profileUsercarddetails {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
+
+.scTailwindUser_profileUsercardlinks,
+    .scTailwindUser_profileUsercardlink {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scTailwindUser_profileUsercardhorizontal-separator {
+  background-color: var(--TWPT-interop-subtle-border)!important;
+  color: var(--TWPT-interop-subtle-border)!important;
+}
+
+.scTailwindUser_profileUsercardsection-heading {
+  color: var(--TWPT-interop-secondary-text)!important;
+}
diff --git a/src/features/ccDarkTheme/core/styles/vendors/google/_thread.scss b/src/features/ccDarkTheme/core/styles/vendors/google/_thread.scss
new file mode 100644
index 0000000..86b370b
--- /dev/null
+++ b/src/features/ccDarkTheme/core/styles/vendors/google/_thread.scss
@@ -0,0 +1,307 @@
+/*
+ * IMPORTANT NOTICE:
+ * Note: the following styles have been written by Googlers and thus are not
+ * included as part of the MIT license.
+ **/
+
+.scTailwindThreadEditquestiondialogroot.scTailwindThreadEditquestiondialogscrollable {
+  -webkit-box-shadow: inset 0 -11px 5px -11px #000;
+  box-shadow: inset 0 -11px 5px -11px #000;
+}
+
+.scTailwindThreadEditquestiondialogerror {
+  color: #ec928e;
+}
+
+.scTailwindThreadGetlinkdialoglink-container {
+  border-bottom: 2px solid #a8c7fa;
+}
+
+.scTailwindThreadMessageHelpfulnessbuttonslabel {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadMessageMessagecardsub-content {
+  background: #3c4043;
+  border-top: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadMessageMessagecardnested-reply:not(:first-child) {
+  border-top: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadMessageMessagecardtargeted {
+  border-left: .125rem solid var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadMessageMessagecardcallouthelp-icon {
+  color: #c4c7c5;
+}
+
+.scTailwindThreadMessageMessagecardcalloutroot.scTailwindThreadMessageMessagecardcalloutrecommended {
+  background: #0f5223;
+  border-color: #6dd58c;
+}
+
+.scTailwindThreadMessageMessagecardcalloutroot.scTailwindThreadMessageMessagecardcalloutrelevant {
+  background: #394457;
+  border-color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadMessageMessagetagrecommended.scTailwindThreadMessageMessagetagnormal {
+  color: #6dd58c;
+}
+
+.scTailwindThreadMessageMessagetagrecommended.scTailwindThreadMessageMessagetagstrong {
+  color: #6dd58c;
+}
+
+.scTailwindThreadMessageMessagetagrelevant.scTailwindThreadMessageMessagetagnormal {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadMessageMessagetagrelevant.scTailwindThreadMessageMessagetagstrong {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadMessageMessageinteractionsinteraction {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+p.scTailwindThreadMessageMessagetombstoneroot {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+p.scTailwindThreadMessageMessagetombstoneroot .scTailwindThreadMessageMessagetombstoneclickable {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadPostcontentroot {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadPostcontentroot a {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadPostcontentedited {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadPost_headerOverflowmenuicon {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadPost_headerPostdateroot {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadPostheaderunread {
+  color: #ec928e;
+}
+
+a .scTailwindThreadPost_headerUserinfoname {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadPost_headerUserinfotag {
+  color: var(--color, #e3e3e3);
+}
+
+.scTailwindThreadPost_headerUserinfoheadline {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadReplyeditorroot {
+  background: #2a2b2f;
+  border-color: var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadReplyeditortop-row {
+  border-bottom-color: 1px solid rgba(255, 255, 255, 0.239);
+}
+
+.scTailwindThreadReplyeditorfooter {
+  background: #36373a;
+  border-top-color: rgba(255, 255, 255, 0.239);
+}
+
+.scTailwindThreadReplyeditorfooter a {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadReplyeditorroot .scTailwindThreadReplyeditorerror {
+  color: #ec928e;
+}
+
+.scTailwindThreadReplydialogroot {
+  background: #2a2b2f;
+}
+
+.scTailwindThreadReplydialogheader {
+  background: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadReplydialogheader h1.scTailwindThreadReplydialogheading {
+  color: #1f1f1f;
+}
+
+.scTailwindThreadReplydialogheading-button {
+  color: #1f1f1f;
+}
+
+.scTailwindThreadReplydialogtop-row {
+  border-bottom: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadReplydialogfooter {
+  background: #36373a;
+}
+
+.scTailwindThreadReplydialogfooter a {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadReplydialogminimized .scTailwindThreadReplydialogheader {
+  background: #e3e3e3;
+  color: #1f1f1f;
+}
+
+.scTailwindThreadReplydialogroot .scTailwindThreadReplydialogerror {
+  color: #ec928e;
+}
+
+@media (min-width:48.125rem) {
+  .scTailwindThreadReplydialogroot {
+    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.302), 0 2px 6px 2px rgba(0, 0, 0, 0.149);
+  }
+}
+
+.scTailwindThreadMessageMessagelisthelp-icon {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadMessageMessagelistrecommended-icon {
+  color: #c4eed0;
+}
+
+.scTailwindThreadMessageMessagelistrelevant-icon {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadMorebuttondivider {
+  background: var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadMorebuttonbutton {
+  background: #1f1f1f;
+  border: 1px solid var(--TWPT-interop-subtle-border);
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadMessagegapdivider {
+  background: var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadMessagegapbutton {
+  background: #1f1f1f;
+  border: 1px solid var(--TWPT-interop-subtle-border);
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadMessagegapmore-nested-replies {
+  background: #3c4043;
+}
+
+.scTailwindThreadMessagegapmore-nested-replies-divider {
+  background: #27282b;
+}
+
+.scTailwindThreadPesignupdialogclose-button-row button {
+  color: #fff;
+}
+
+.scTailwindThreadPesignupdialogdialog-body p {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadPesignupdialogpe-dialog-container {
+  background-color: #1f1f1f;
+  -webkit-box-shadow: 0 .063rem .188rem rgba(60, 64, 67, 0.3), 0 .25rem .5rem rgba(60, 64, 67, 0.15);
+  box-shadow: 0 .063rem .188rem rgba(60, 64, 67, 0.3), 0 .25rem .5rem rgba(60, 64, 67, 0.15);
+}
+
+.scTailwindThreadPostconfirmationdialogclose-button-row button {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadPostconfirmationdialogdialog-body p {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadPostconfirmationdialogdialog-container {
+  background-color: #1f1f1f;
+  -webkit-box-shadow: 0 .063rem .188rem rgba(60, 64, 67, 0.3), 0 .25rem .5rem rgba(60, 64, 67, 0.15);
+  box-shadow: 0 .063rem .188rem rgba(60, 64, 67, 0.3), 0 .25rem .5rem rgba(60, 64, 67, 0.15);
+}
+
+.scTailwindThreadQuestionQuestioncardsub-content {
+  background: #3c4043;
+  border-top: 1px solid var(--TWPT-interop-subtle-border);
+}
+
+.scTailwindThreadQuestionQuestioncardtitle {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadQuestionQuestioncardbody {
+  color: #e3e3e3;
+}
+
+.scTailwindThreadQuestionQuestioncardbody a {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadQuestionQuestioncarddisclaimer,
+.scTailwindThreadQuestionQuestioncardedited {
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadQuestionQuestioncarddisclaimer a,
+.scTailwindThreadQuestionQuestioncardedited a {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadQuestionQuestiondetailsdetail-link {
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadQuestionQuestionpurposetag {
+  background: #394457;
+  color: var(--TWPT-interop-blue);
+}
+
+.scTailwindThreadQuestionStatechipschip {
+  border: 1px solid var(--TWPT-interop-subtle-border);
+  color: var(--TWPT-interop-secondary-text);
+}
+
+.scTailwindThreadQuestionThreadcountsrecommended-answers {
+  color: #6dd58c!important;
+}
+
+.scTailwindThreadQuestionThreadcountssuggested-answers {
+  color: var(--TWPT-interop-blue)!important;
+}
+
+.scTailwindThreadQuestionThreadcountssuggested-icon {
+  background: #394457!important;
+}
+
+.scTailwindThreadQuestionUgcvideodetailsyoutube-label {
+  color: #c4c7c5!important;
+}
+
+.scTailwindThreadThreaddeleted-icon {
+  color: var(--TWPT-interop-secondary-text);
+}
diff --git a/src/features/ccDarkTheme/nodeWatcherHandlers/ecApp.handler.ts b/src/features/ccDarkTheme/nodeWatcherHandlers/ecApp.handler.ts
new file mode 100644
index 0000000..12d50bb
--- /dev/null
+++ b/src/features/ccDarkTheme/nodeWatcherHandlers/ecApp.handler.ts
@@ -0,0 +1,26 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../common/nodeWatcher/NodeWatcherHandler';
+import { injectDarkThemeButton } from '../core/logic/darkTheme';
+import { CCDarkThemeNodeWatcherDependencies } from '../scripts/nodeWatcher.script';
+
+/**
+ * Injects the dark theme button.
+ */
+export default class CCDarkThemeEcAppHandler extends CssSelectorNodeWatcherScriptHandler<CCDarkThemeNodeWatcherDependencies> {
+  cssSelector = 'ec-app';
+
+  async onMutatedNode(mutation: NodeMutation) {
+    if (!(mutation.node instanceof Element)) return;
+
+    const optionsProvider = this.options.optionsProvider;
+    const isEnabled = await optionsProvider.isEnabled('ccdarktheme');
+    const mode = await optionsProvider.getOptionValue('ccdarktheme_mode');
+
+    // TODO(avm99963): make this feature dynamic.
+    if (isEnabled && mode === 'switch') {
+      const rightControl = mutation.node.querySelector('header .right-control');
+      if (rightControl === null) return;
+      injectDarkThemeButton(rightControl);
+    }
+  }
+}
diff --git a/src/features/ccDarkTheme/nodeWatcherHandlers/reportDialog.handler.ts b/src/features/ccDarkTheme/nodeWatcherHandlers/reportDialog.handler.ts
new file mode 100644
index 0000000..83942e5
--- /dev/null
+++ b/src/features/ccDarkTheme/nodeWatcherHandlers/reportDialog.handler.ts
@@ -0,0 +1,17 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../common/nodeWatcher/NodeWatcherHandler';
+import { CCDarkThemeNodeWatcherDependencies } from '../scripts/nodeWatcher.script';
+
+/**
+ * Sets the report dialog iframe's theme to the appropriate theme.
+ */
+export default class CCDarkThemeReportDialogHandler extends CssSelectorNodeWatcherScriptHandler<CCDarkThemeNodeWatcherDependencies> {
+  cssSelector = 'iframe';
+
+  onMutatedNode(mutation: NodeMutation) {
+    this.options.reportDialogColorThemeFix.fixThemeIfReportDialogIframeAndApplicable(
+      mutation.node,
+      this.options.optionsProvider,
+    );
+  }
+}
diff --git a/src/features/ccDarkTheme/nodeWatcherHandlers/unifiedProfilesIframe.handler.ts b/src/features/ccDarkTheme/nodeWatcherHandlers/unifiedProfilesIframe.handler.ts
new file mode 100644
index 0000000..b71b9a7
--- /dev/null
+++ b/src/features/ccDarkTheme/nodeWatcherHandlers/unifiedProfilesIframe.handler.ts
@@ -0,0 +1,23 @@
+import CssSelectorNodeWatcherScriptHandler from '../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
+import { NodeMutation } from '../../../common/nodeWatcher/NodeWatcherHandler';
+import { isDarkThemeOn } from '../core/logic/darkTheme';
+import { unifiedProfilesFix } from '../core/logic/unifiedProfiles';
+import { CCDarkThemeNodeWatcherDependencies } from '../scripts/nodeWatcher.script';
+
+/**
+ * Redirect unified profile iframe to dark version if applicable
+ */
+export default class CCDarkThemeUnifiedProfilesIframeHandler extends CssSelectorNodeWatcherScriptHandler<CCDarkThemeNodeWatcherDependencies> {
+  cssSelector = 'iframe';
+
+  async onMutatedNode(mutation: NodeMutation) {
+    const optionsValues = await this.options.optionsProvider.getOptionsValues();
+
+    if (
+      isDarkThemeOn(optionsValues) &&
+      unifiedProfilesFix.checkIframe(mutation.node)
+    ) {
+      unifiedProfilesFix.fixIframe(mutation.node);
+    }
+  }
+}
diff --git a/src/features/ccDarkTheme/scripts/injectAutoDarkTheme.script.ts b/src/features/ccDarkTheme/scripts/injectAutoDarkTheme.script.ts
new file mode 100644
index 0000000..c462a03
--- /dev/null
+++ b/src/features/ccDarkTheme/scripts/injectAutoDarkTheme.script.ts
@@ -0,0 +1,17 @@
+import { ScriptPage } from '../../../common/architecture/scripts/Script';
+import StylesheetScript from '../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class InjectAutoDarkTheme extends StylesheetScript {
+  stylesheet = 'ccDarkTheme.bundle.css';
+  attributes = { media: '(prefers-color-scheme: dark)' };
+  page = ScriptPage.CommunityConsole;
+
+  async shouldBeInjected(): Promise<boolean> {
+    const ccDarkThemeEnabled =
+      await this.optionsProvider.isEnabled('ccdarktheme');
+    const ccDarkThemeMode =
+      await this.optionsProvider.getOptionValue('ccdarktheme_mode');
+
+    return ccDarkThemeEnabled && ccDarkThemeMode === 'system';
+  }
+}
diff --git a/src/features/ccDarkTheme/scripts/injectForcedDarkTheme.script.ts b/src/features/ccDarkTheme/scripts/injectForcedDarkTheme.script.ts
new file mode 100644
index 0000000..ebd221b
--- /dev/null
+++ b/src/features/ccDarkTheme/scripts/injectForcedDarkTheme.script.ts
@@ -0,0 +1,23 @@
+import { ScriptPage } from '../../../common/architecture/scripts/Script';
+import StylesheetScript from '../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class InjectForcedDarkTheme extends StylesheetScript {
+  stylesheet = 'ccDarkTheme.bundle.css';
+  page = ScriptPage.CommunityConsole;
+
+  async shouldBeInjected(): Promise<boolean> {
+    const ccDarkThemeEnabled =
+      await this.optionsProvider.isEnabled('ccdarktheme');
+    const ccDarkThemeMode =
+      await this.optionsProvider.getOptionValue('ccdarktheme_mode');
+    const ccDarkThemeSwitchEnabled = await this.optionsProvider.isEnabled(
+      'ccdarktheme_switch_status',
+    );
+
+    return (
+      ccDarkThemeEnabled &&
+      ccDarkThemeMode === 'switch' &&
+      ccDarkThemeSwitchEnabled
+    );
+  }
+}
diff --git a/src/features/ccDarkTheme/scripts/nodeWatcher.script.ts b/src/features/ccDarkTheme/scripts/nodeWatcher.script.ts
new file mode 100644
index 0000000..7a78798
--- /dev/null
+++ b/src/features/ccDarkTheme/scripts/nodeWatcher.script.ts
@@ -0,0 +1,46 @@
+import DependenciesProviderSingleton, {
+  OptionsProviderDependency,
+  ReportDialogColorThemeFixDependency,
+} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
+import {
+  ScriptEnvironment,
+  ScriptPage,
+  ScriptRunPhase,
+} from '../../../common/architecture/scripts/Script';
+import NodeWatcherScript from '../../../common/architecture/scripts/nodeWatcher/NodeWatcherScript';
+import OptionsProvider from '../../../common/options/OptionsProvider';
+import ReportDialogColorThemeFix from '../core/logic/reportDialog';
+import CCDarkThemeEcAppHandler from '../nodeWatcherHandlers/ecApp.handler';
+import CCDarkThemeReportDialogHandler from '../nodeWatcherHandlers/reportDialog.handler';
+import CCDarkThemeUnifiedProfilesIframeHandler from '../nodeWatcherHandlers/unifiedProfilesIframe.handler';
+
+export interface CCDarkThemeNodeWatcherDependencies {
+  reportDialogColorThemeFix: ReportDialogColorThemeFix;
+  optionsProvider: OptionsProvider;
+}
+
+export default class CCDarkThemeNodeWatcherScript extends NodeWatcherScript<CCDarkThemeNodeWatcherDependencies> {
+  public page = ScriptPage.CommunityConsole;
+  public environment = ScriptEnvironment.ContentScript;
+  public runPhase = ScriptRunPhase.Main;
+  public handlers = new Map([
+    ['cc-dark-theme-ec-app', CCDarkThemeEcAppHandler],
+    ['cc-dark-theme-report-dialog', CCDarkThemeReportDialogHandler],
+    [
+      'cc-dark-theme-unified-profiles-iframe',
+      CCDarkThemeUnifiedProfilesIframeHandler,
+    ],
+  ]);
+
+  protected optionsFactory(): CCDarkThemeNodeWatcherDependencies {
+    const dependenciesProvider = DependenciesProviderSingleton.getInstance();
+    return {
+      reportDialogColorThemeFix: dependenciesProvider.getDependency(
+        ReportDialogColorThemeFixDependency,
+      ),
+      optionsProvider: dependenciesProvider.getDependency(
+        OptionsProviderDependency,
+      ),
+    };
+  }
+}