Resolve duplicate CSS selectors reported by Stylelint (#7212)

Fixes #7189

Consolidates all 29 `no-duplicate-selectors` violations across 18
stylesheets by merging later duplicate rule blocks into the first
occurrence. Where duplicates had conflicting values, the cascade-winning
(later) value was kept, so computed styles are unchanged.

Also:
- Adds `frontend/stylelint.config.mjs` with only
`no-duplicate-selectors` enabled (Prettier and the theme linter own
everything else).
- Adds a `frontend:lint:css` task, wired into `task frontend:lint` as a
blocking check so regressions can't creep back in.
- Lints all first-party CSS (`editor/**/*.css`, so `public/css` and any
future non-`src` stylesheets are covered too), excluding only the
vendored `cookieconsent.css` and build output via `ignoreFiles`. This
surfaced and fixed 5 additional duplicate selectors in
`cookieconsentCustomisation.css` that weren't in the original issue
report.

Note: `portal/views/Sources.css` goes beyond dedup — the whole
`.portal-sources__connections*` block is deleted as dead code
(unreferenced since the S3 connections redesign in #6965; only
`-actions` in it was an actual duplicate).

🤖 Generated with [Claude Code](https://claude.ai/code)
This commit is contained in:
EthanHealy01
2026-07-31 16:46:31 +00:00
committed by GitHub
parent 041b6a4b5f
commit 9d473fb435
22 changed files with 1153 additions and 405 deletions
+10
View File
@@ -263,6 +263,16 @@ tasks:
- task: lint:eslint
- task: lint:dpdm
- task: lint:colors
- task: lint:css
lint:css:
desc: "Lint stylesheets for duplicate selectors"
deps: [install]
cmds:
# Covers the whole editor tree, including the portal/processor layer and
# public/css. Vendored CSS and build output are excluded via ignoreFiles
# in stylelint.config.mjs.
- npx stylelint "editor/**/*.css"
lint:colors:
desc: "Enforce theme tokens — no hardcoded colours or raw primitives in components"
@@ -130,21 +130,35 @@
opacity: 0 !important; /* Keep invisible but functional */
}
/* Track: flat fill in both themes, no outline ring or border */
#cc-main .toggle__icon {
display: flex !important;
align-items: center !important;
justify-content: flex-start !important;
background: var(--cc-toggle-off-bg) !important;
border: none !important;
box-shadow: none !important;
transition: background-color 150ms ease !important;
}
/* Thumb: small plain circle, vertically centred, no drop shadow */
#cc-main .toggle__icon-circle {
display: block !important;
position: absolute !important;
transition: transform 0.25s ease !important;
width: 14px !important;
height: 14px !important;
top: 3px !important;
left: 2.5px !important;
box-shadow: none !important;
transition:
transform 150ms ease,
background-color 150ms ease !important;
}
/* Mantine switches have no check/cross glyph inside the thumb */
#cc-main .toggle__icon-on,
#cc-main .toggle__icon-off {
display: flex !important;
display: none !important;
align-items: center !important;
justify-content: center !important;
position: absolute !important;
@@ -152,15 +166,11 @@
height: 100% !important;
}
/* Ensure toggles are visible in both themes */
#cc-main .toggle__icon {
background: var(--cc-toggle-off-bg) !important;
border: 1px solid var(--cc-toggle-off-bg) !important;
}
/* Checked track visible in both themes, same flat Mantine look */
#cc-main .section__toggle:checked ~ .toggle__icon {
background: var(--cc-toggle-on-bg) !important;
border: 1px solid var(--cc-toggle-on-bg) !important;
border: none !important;
box-shadow: none !important;
}
/* Ensure toggle text is visible */
@@ -226,18 +236,6 @@
border-radius: 1000px !important;
}
/* Track: flat fill, no outline ring or border */
#cc-main .toggle__icon {
border: none !important;
box-shadow: none !important;
transition: background-color 150ms ease !important;
}
#cc-main .section__toggle:checked ~ .toggle__icon {
border: none !important;
box-shadow: none !important;
}
/* Always-enabled categories = Mantine disabled switch (must out-prioritise
the !important checked-track rule above) */
#cc-main .section__toggle:checked:disabled ~ .toggle__icon {
@@ -250,25 +248,7 @@
cursor: not-allowed !important;
}
/* Thumb: small plain circle, vertically centred, no drop shadow */
#cc-main .toggle__icon-circle {
width: 14px !important;
height: 14px !important;
top: 3px !important;
left: 2.5px !important;
box-shadow: none !important;
transition:
transform 150ms ease,
background-color 150ms ease !important;
}
/* Checked thumb travel: 38 14 2.5 = 21.5px end position */
#cc-main .section__toggle:checked ~ .toggle__icon .toggle__icon-circle {
transform: translateX(19px) !important;
}
/* Mantine switches have no check/cross glyph inside the thumb */
#cc-main .toggle__icon-on,
#cc-main .toggle__icon-off {
display: none !important;
}
@@ -320,11 +320,6 @@
color: var(--c-text-muted); /* subtitle text */
}
/* Light mode selected header stroke override */
:global([data-mantine-color-scheme="light"]) .card[data-selected="true"] {
outline-color: var(--c-primary);
}
/* =========================
Add File Card Styles
========================= */
@@ -156,6 +156,11 @@
flex-shrink: 0;
flex-wrap: wrap;
min-height: 3rem;
/* Safety net - the content should always fit thanks to the shrink rules on
`.files-page-toolbar-actions` below, but if a future addition ever breaks
that, this stops the action group bleeding into sibling areas (notably the
details panel on the right). */
overflow-x: hidden;
}
.files-page-toolbar-info {
@@ -210,13 +215,6 @@
.files-page-toolbar-actions .mantine-SegmentedControl-root {
flex-shrink: 0;
}
/* Clip overflow on the toolbar itself as a safety net - the content
should always fit thanks to the rules above, but if a future addition
ever breaks that, this prevents the action group from bleeding into
sibling areas (notably the details panel on the right). */
.files-page-toolbar {
overflow-x: hidden;
}
.files-page-toolbar-divider {
width: 1px;
@@ -1319,9 +1317,6 @@
gap: 0.3rem;
flex-wrap: nowrap;
}
.files-page-search {
flex: 1 1 100%;
}
.files-page-breadcrumbs {
font-size: 0.85rem;
flex-wrap: nowrap;
@@ -447,19 +447,14 @@
}
.file-sidebar-section-header {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 12px 14px 6px 14px;
padding: 10px 14px 6px 14px;
margin: 4px 0 0 0;
}
.file-sidebar-section-header {
position: relative;
border-top: 1px solid var(--c-border-subtle);
padding-top: 10px;
margin-top: 4px;
flex-shrink: 0;
}
@@ -56,12 +56,6 @@
pointer-events: auto;
}
/* Always reserve space for action buttons so file name truncation dots (...)
never bleed under action buttons or overlap their outline/focus box. */
.file-sidebar-file-info {
padding-right: 3.75rem;
}
.file-sidebar-file-item:hover:not(.selected) {
background-color: color-mix(in srgb, var(--c-primary) 6%, transparent);
}
@@ -173,6 +167,9 @@
.file-sidebar-file-info {
flex: 1;
min-width: 0;
/* Always reserve space for action buttons so file name truncation dots (...)
never bleed under action buttons or overlap their outline/focus box. */
padding-right: 3.75rem;
}
.file-sidebar-file-name {
@@ -9,113 +9,6 @@
flex-shrink: 0;
}
/* CSS Custom Properties for Fullscreen Mode */
.tool-panel__fullscreen-surface-inner {
--fullscreen-bg-surface-1: color-mix(
in srgb,
var(--c-bg-raised) 96%,
transparent
);
--fullscreen-bg-surface-2: color-mix(in srgb, var(--c-bg) 90%, transparent);
--fullscreen-bg-header: var(--c-bg-raised);
--fullscreen-bg-controls-1: var(--c-bg-raised);
--fullscreen-bg-controls-2: color-mix(
in srgb,
var(--c-bg-raised) 95%,
var(--c-bg)
);
--fullscreen-bg-body-1: color-mix(in srgb, var(--c-bg) 86%, transparent);
--fullscreen-bg-body-2: color-mix(
in srgb,
var(--c-bg-raised) 78%,
transparent
);
--fullscreen-bg-group: color-mix(
in srgb,
var(--c-bg-raised) 82%,
transparent
);
--fullscreen-bg-item: color-mix(in srgb, var(--c-bg-raised) 88%, transparent);
--fullscreen-bg-list-item: color-mix(
in srgb,
var(--c-bg-raised) 86%,
transparent
);
--fullscreen-bg-icon-detailed: color-mix(
in srgb,
var(--c-surface-sunken) 75%,
transparent
);
--fullscreen-bg-icon-compact: color-mix(
in srgb,
var(--c-surface-sunken) 70%,
transparent
);
--fullscreen-border-subtle-75: color-mix(
in srgb,
var(--c-border-subtle) 75%,
transparent
);
--fullscreen-border-subtle-70: color-mix(
in srgb,
var(--c-border-subtle) 70%,
transparent
);
--fullscreen-border-subtle-65: color-mix(
in srgb,
var(--c-border-subtle) 65%,
transparent
);
--fullscreen-border-favorites: color-mix(
in srgb,
var(--special-color-favorites) 25%,
var(--c-border-subtle)
);
--fullscreen-border-recommended: color-mix(
in srgb,
var(--special-color-recommended) 25%,
var(--c-border-subtle)
);
--fullscreen-shadow-primary: color-mix(
in srgb,
var(--shadow-color, color-mix(in srgb, black 55%, transparent)) 25%,
transparent
);
--fullscreen-shadow-secondary: color-mix(
in srgb,
var(--shadow-color, color-mix(in srgb, black 35%, transparent)) 30%,
transparent
);
--fullscreen-shadow-group: color-mix(
in srgb,
var(--shadow-color, color-mix(in srgb, black 45%, transparent)) 18%,
transparent
);
--fullscreen-accent-hover: color-mix(
in srgb,
var(--c-text) 20%,
var(--c-border-subtle)
);
--fullscreen-accent-selected: color-mix(
in srgb,
var(--c-text) 30%,
var(--c-border-subtle)
);
--fullscreen-accent-ring: color-mix(in srgb, var(--c-text) 15%, transparent);
--fullscreen-accent-list-bg: color-mix(
in srgb,
var(--c-text) 8%,
var(--c-bg-raised)
);
--fullscreen-accent-list-border: color-mix(
in srgb,
var(--c-text) 20%,
var(--c-border-subtle)
);
--fullscreen-text-icon: var(--c-text);
--fullscreen-text-icon-compact: var(--c-text);
}
.tool-panel {
position: relative;
transition:
@@ -373,6 +266,110 @@
--fullscreen-anim-out-duration: var(--fullscreen-anim-duration-out);
animation: tool-panel-fullscreen-slide-in var(--fullscreen-anim-in-duration)
ease forwards;
--fullscreen-bg-surface-1: color-mix(
in srgb,
var(--c-bg-raised) 96%,
transparent
);
--fullscreen-bg-surface-2: color-mix(in srgb, var(--c-bg) 90%, transparent);
--fullscreen-bg-header: var(--c-bg-raised);
--fullscreen-bg-controls-1: var(--c-bg-raised);
--fullscreen-bg-controls-2: color-mix(
in srgb,
var(--c-bg-raised) 95%,
var(--c-bg)
);
--fullscreen-bg-body-1: color-mix(in srgb, var(--c-bg) 86%, transparent);
--fullscreen-bg-body-2: color-mix(
in srgb,
var(--c-bg-raised) 78%,
transparent
);
--fullscreen-bg-group: color-mix(
in srgb,
var(--c-bg-raised) 82%,
transparent
);
--fullscreen-bg-item: color-mix(in srgb, var(--c-bg-raised) 88%, transparent);
--fullscreen-bg-list-item: color-mix(
in srgb,
var(--c-bg-raised) 86%,
transparent
);
--fullscreen-bg-icon-detailed: color-mix(
in srgb,
var(--c-surface-sunken) 75%,
transparent
);
--fullscreen-bg-icon-compact: color-mix(
in srgb,
var(--c-surface-sunken) 70%,
transparent
);
--fullscreen-border-subtle-75: color-mix(
in srgb,
var(--c-border-subtle) 75%,
transparent
);
--fullscreen-border-subtle-70: color-mix(
in srgb,
var(--c-border-subtle) 70%,
transparent
);
--fullscreen-border-subtle-65: color-mix(
in srgb,
var(--c-border-subtle) 65%,
transparent
);
--fullscreen-border-favorites: color-mix(
in srgb,
var(--special-color-favorites) 25%,
var(--c-border-subtle)
);
--fullscreen-border-recommended: color-mix(
in srgb,
var(--special-color-recommended) 25%,
var(--c-border-subtle)
);
--fullscreen-shadow-primary: color-mix(
in srgb,
var(--shadow-color, color-mix(in srgb, black 55%, transparent)) 25%,
transparent
);
--fullscreen-shadow-secondary: color-mix(
in srgb,
var(--shadow-color, color-mix(in srgb, black 35%, transparent)) 30%,
transparent
);
--fullscreen-shadow-group: color-mix(
in srgb,
var(--shadow-color, color-mix(in srgb, black 45%, transparent)) 18%,
transparent
);
--fullscreen-accent-hover: color-mix(
in srgb,
var(--c-text) 20%,
var(--c-border-subtle)
);
--fullscreen-accent-selected: color-mix(
in srgb,
var(--c-text) 30%,
var(--c-border-subtle)
);
--fullscreen-accent-ring: color-mix(in srgb, var(--c-text) 15%, transparent);
--fullscreen-accent-list-bg: color-mix(
in srgb,
var(--c-text) 8%,
var(--c-bg-raised)
);
--fullscreen-accent-list-border: color-mix(
in srgb,
var(--c-text) 20%,
var(--c-border-subtle)
);
--fullscreen-text-icon: var(--c-text);
--fullscreen-text-icon-compact: var(--c-text);
}
.tool-panel__fullscreen-surface-inner--exiting {
@@ -428,8 +425,15 @@
flex: 1 1 auto;
}
/* Used by both FullscreenToolSurface and DetailedToolItem. */
.tool-panel__fullscreen-body {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.4rem;
text-align: left;
/* Prevent long content (names, descriptions, shortcuts) from overflowing */
flex: 1 1 auto;
min-width: 0;
min-height: 0;
background: transparent;
}
@@ -639,16 +643,6 @@
z-index: var(--z-fullscreen-icon-svg);
}
.tool-panel__fullscreen-body {
display: flex;
flex-direction: column;
gap: 0.4rem;
text-align: left;
/* Prevent long content (names, descriptions, shortcuts) from overflowing */
flex: 1 1 auto;
min-width: 0;
}
.tool-panel__fullscreen-name {
color: var(--c-text);
font-size: 13px !important;
@@ -52,6 +52,7 @@
user-select: none;
font-weight: 600;
position: relative;
padding: 8px;
}
/* Position numbers at edges within each tile with extra top/bottom spacing */
@@ -98,11 +99,6 @@
padding-bottom: 4px;
} /* bottom-right */
/* Base padding for all tiles */
.gridTile {
padding: 8px;
}
.gridTileSelected,
.gridTileHovered {
border: 2px solid var(--c-primary);
@@ -1,5 +1,6 @@
.compare-dropdown-scrollwrap {
position: relative;
margin: 0;
}
.compare-dropdown-sticky {
@@ -138,20 +139,11 @@
border-radius: 8px !important; /* match dropdown container radius */
}
/* Ensure options text uses full width inside wider dropdown */
.compare-dropdown-option__text {
max-width: 100%;
}
/* Remove default padding inside Mantine options list so sticky header touches edges */
.compare-changes-dropdown .mantine-Combobox-options {
padding: 0 !important;
}
.compare-dropdown-scrollwrap {
margin: 0;
}
/* Ensure search field sits flush and does not overflow */
.compare-changes-dropdown .mantine-Combobox-search {
box-sizing: border-box;
@@ -435,6 +427,7 @@
overflow: hidden;
text-overflow: ellipsis;
line-clamp: 3;
max-width: 100%;
}
/* Non-sticky in-flow group headers; sticky handled by floating header */
@@ -8,13 +8,14 @@
display: flex;
flex-direction: column;
gap: 4px;
color: var(--c-text) !important;
}
.field-value {
border: 1px solid rgb(var(--pdf-light-box-border));
border: 1px solid var(--c-border) !important;
border-radius: 8px;
padding: 0.65rem 0.75rem;
background-color: rgb(var(--pdf-light-box-bg));
background-color: var(--c-surface-raised) !important;
min-height: 44px;
}
@@ -65,16 +66,6 @@
overflow-y: auto;
}
/* Keep field blocks stable colors across themes */
.field-value {
border: 1px solid var(--c-border) !important;
background-color: var(--c-surface-raised) !important;
}
.field-container {
color: var(--c-text) !important;
}
/* Thumbnail preview styles */
.thumbnail-container {
width: 140px;
@@ -5,6 +5,7 @@
display: flex;
flex-direction: column;
gap: 0.25rem;
animation: attachment-fade-in 0.2s ease;
}
/* Attachment Items */
@@ -91,10 +92,6 @@
}
}
.attachment-list {
animation: attachment-fade-in 0.2s ease;
}
/* Accessibility & Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.attachment-item,
@@ -108,6 +108,7 @@
flex-direction: column;
gap: 0.25rem;
margin-top: 0.25rem;
animation: bookmark-fade-in 0.2s ease;
}
/* Smooth expand/collapse animation */
@@ -122,10 +123,6 @@
}
}
.bookmark-item__children {
animation: bookmark-fade-in 0.2s ease;
}
/* Accessibility & Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.bookmark-item,
@@ -100,6 +100,7 @@
color-mix(in srgb, var(--c-border-subtle) 60%, transparent);
margin-left: 0.875rem;
padding-left: 0.25rem;
animation: layer-fade-in 0.15s ease;
}
/* Footer with Apply button */
@@ -133,10 +134,6 @@
}
}
.layer-item__children {
animation: layer-fade-in 0.15s ease;
}
/* Accessibility & Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.layer-item,
+34 -56
View File
@@ -49,11 +49,9 @@
var(--p-green-500) 30%,
transparent
); /* Green border for active badge */
}
/* CSS variables for Tailwind + Mantine integration */
:root {
/* Global animation durations */
--fullscreen-anim-duration-in: 0.28s;
--fullscreen-anim-duration-out: 0.22s;
@@ -284,12 +282,25 @@
--dropdown-panel-bg: var(--mantine-color-white);
--dropdown-panel-border: var(--mantine-color-gray-4);
--dropdown-group-label: var(--mantine-color-gray-6);
}
/* Onboarding (light mode) */
:root {
--onboarding-step-active: var(--p-gray-800);
--onboarding-step-inactive: var(--p-gray-300);
/* PDF Link Overlay (viewer) */
--link-hover-bg: color-mix(in srgb, var(--p-blue-500) 10%, transparent);
--link-hover-border: color-mix(in srgb, var(--p-blue-500) 32%, transparent);
--link-hover-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.35),
0 1px 4px color-mix(in srgb, var(--p-azure-500) 12%, transparent);
--link-focus-ring: color-mix(in srgb, var(--p-blue-500) 25%, transparent);
--link-toolbar-bg: color-mix(in srgb, var(--p-blue-700) 88%, transparent);
--link-toolbar-border: rgba(255, 255, 255, 0.1);
--link-toolbar-shadow:
0 12px 40px rgba(0, 0, 0, 0.2), 0 4px 12px rgba(0, 0, 0, 0.16),
0 0 0 0.5px rgba(255, 255, 255, 0.05);
--shadow-color: color-mix(in srgb, var(--p-blue-700) 55%, transparent);
}
[data-mantine-color-scheme="dark"] {
@@ -484,6 +495,19 @@
--dropdown-panel-bg: var(--mantine-color-dark-7);
--dropdown-panel-border: var(--mantine-color-dark-4);
--dropdown-group-label: var(--mantine-color-dark-2);
/* PDF Link Overlay (viewer) */
--link-hover-bg: color-mix(in srgb, var(--p-blue-500) 14%, transparent);
--link-hover-border: color-mix(in srgb, var(--p-blue-500) 38%, transparent);
--link-hover-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.1),
0 1px 4px color-mix(in srgb, var(--p-c-4f8ef5) 18%, transparent);
--link-focus-ring: color-mix(in srgb, var(--p-blue-500) 30%, transparent);
--link-toolbar-bg: color-mix(in srgb, var(--p-blue-700) 94%, transparent);
--link-toolbar-border: rgba(255, 255, 255, 0.07);
--link-toolbar-shadow:
0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.35),
0 0 0 0.5px rgba(255, 255, 255, 0.04);
}
/* Dropzone drop state styling */
@@ -581,34 +605,6 @@
border-color 0.2s ease;
}
/* ── PDF Link Overlay (viewer) ── */
:root {
--link-hover-bg: color-mix(in srgb, var(--p-blue-500) 10%, transparent);
--link-hover-border: color-mix(in srgb, var(--p-blue-500) 32%, transparent);
--link-hover-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.35),
0 1px 4px color-mix(in srgb, var(--p-azure-500) 12%, transparent);
--link-focus-ring: color-mix(in srgb, var(--p-blue-500) 25%, transparent);
--link-toolbar-bg: color-mix(in srgb, var(--p-blue-700) 88%, transparent);
--link-toolbar-border: rgba(255, 255, 255, 0.1);
--link-toolbar-shadow:
0 12px 40px rgba(0, 0, 0, 0.2), 0 4px 12px rgba(0, 0, 0, 0.16),
0 0 0 0.5px rgba(255, 255, 255, 0.05);
}
[data-mantine-color-scheme="dark"] {
--link-hover-bg: color-mix(in srgb, var(--p-blue-500) 14%, transparent);
--link-hover-border: color-mix(in srgb, var(--p-blue-500) 38%, transparent);
--link-hover-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.1),
0 1px 4px color-mix(in srgb, var(--p-c-4f8ef5) 18%, transparent);
--link-focus-ring: color-mix(in srgb, var(--p-blue-500) 30%, transparent);
--link-toolbar-bg: color-mix(in srgb, var(--p-blue-700) 94%, transparent);
--link-toolbar-border: rgba(255, 255, 255, 0.07);
--link-toolbar-shadow:
0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.35),
0 0 0 0.5px rgba(255, 255, 255, 0.04);
}
/* ── Link hit-area ── */
.pdf-link-overlay {
position: absolute;
@@ -739,28 +735,13 @@
.pdf-link-toolbar-btn:hover {
background: rgba(255, 255, 255, 0.08);
}
.pdf-link-toolbar-btn--delete:hover {
background: color-mix(in srgb, var(--p-red-500) 15%, transparent);
color: var(--p-art-red-light);
}
.pdf-link-toolbar-sep {
width: 1px;
height: 12px;
background: rgba(255, 255, 255, 0.12);
margin: 0 4px;
color: #fff;
}
.pdf-link-toolbar-btn:last-child {
border-radius: 0 9px 9px 0;
}
.pdf-link-toolbar-btn:hover {
color: #fff;
}
.pdf-link-toolbar-btn--delete {
padding: 0 10px;
}
@@ -770,25 +751,22 @@
color: var(--p-red-400);
}
.pdf-link-toolbar-btn--go:hover {
background: rgba(255, 255, 255, 0.08);
}
.pdf-link-toolbar-btn--go {
min-width: 0;
}
.pdf-link-toolbar-btn--go:hover {
background: rgba(255, 255, 255, 0.08);
}
.pdf-link-toolbar-sep {
width: 1px;
height: 16px;
background: rgba(255, 255, 255, 0.1);
margin: 0 4px;
flex-shrink: 0;
}
:root {
--shadow-color: color-mix(in srgb, var(--p-blue-700) 55%, transparent);
}
[data-theme="dark"] {
--shadow-color: rgba(0, 0, 0, 0.88);
}
+22 -24
View File
@@ -153,6 +153,27 @@
var(--p-red-500) 50%,
var(--p-red-600) 100%
);
/* Code palette — theme-aware: a light GitHub-style box in light mode, the
dark terminal palette in dark mode. (CodeBlock renders plain text, so only
the base colours are load-bearing; the syntax slots are kept for future
Shiki. */
--code-bg: var(--p-c-f6f8fa);
--code-bg-alt: var(--p-c-eef1f4);
--code-bg-header: var(--p-c-eaeef2);
--code-text: var(--p-c-1f2328);
--code-dim: var(--p-c-656d76);
--code-muted: var(--p-c-8c959f);
--code-keyword: var(--p-c-cf222e);
--code-string: var(--p-code-string);
--code-number: var(--p-c-0550ae);
--code-fn: var(--p-c-8250df);
--code-type: var(--p-code-type);
--code-property: var(--p-c-0550ae);
--code-comment: var(--p-c-6e7781);
--code-border: var(--p-c-d0d7de);
/* Window-chrome traffic-light dots in the code-block header. */
--code-dot: var(--p-c-d0d7de);
}
[data-theme="dark"] {
@@ -224,31 +245,8 @@
var(--p-blue-600) 50%,
var(--p-blue-700) 100%
);
}
/* Code palette — theme-aware: a light GitHub-style box in light mode, the dark
terminal palette in dark mode. (CodeBlock renders plain text, so only the
base colours are load-bearing; the syntax slots are kept for future Shiki. */
:root,
[data-theme="light"] {
--code-bg: var(--p-c-f6f8fa);
--code-bg-alt: var(--p-c-eef1f4);
--code-bg-header: var(--p-c-eaeef2);
--code-text: var(--p-c-1f2328);
--code-dim: var(--p-c-656d76);
--code-muted: var(--p-c-8c959f);
--code-keyword: var(--p-c-cf222e);
--code-string: var(--p-code-string);
--code-number: var(--p-c-0550ae);
--code-fn: var(--p-c-8250df);
--code-type: var(--p-code-type);
--code-property: var(--p-c-0550ae);
--code-comment: var(--p-c-6e7781);
--code-border: var(--p-c-d0d7de);
/* Window-chrome traffic-light dots in the code-block header. */
--code-dot: var(--p-c-d0d7de);
}
[data-theme="dark"] {
/* Code palette */
--code-bg: var(--p-c-0f172a);
--code-bg-alt: var(--p-c-1e293b);
--code-bg-header: var(--p-c-1a2332);
+5 -7
View File
@@ -61,18 +61,16 @@
.sui-check--mixed .sui-check__tick {
opacity: 0;
}
.sui-check--mixed .sui-check__dash {
position: absolute;
width: 0.5rem;
height: 2px;
background: var(--color-text-on-accent);
border-radius: 1px;
}
.sui-check__dash {
display: none;
}
.sui-check--mixed .sui-check__dash {
display: block;
position: absolute;
width: 0.5rem;
height: 2px;
background: var(--color-text-on-accent);
border-radius: 1px;
}
.sui-check__icon {
@@ -1276,10 +1276,12 @@
flex-direction: column;
gap: 1.25rem;
}
/* Shared by the calculator and payment steps, kept compact so the payment step
fits without scrolling. */
.portal-billing__bundle-fields {
display: flex;
flex-direction: column;
gap: 1rem;
gap: 0.625rem;
}
.portal-billing__bundle-field-label {
font-size: 0.8125rem;
@@ -1460,12 +1462,6 @@
padding-top: 0.75rem;
border-top: 1px solid var(--c-border-subtle);
}
/* Recipient fields on the payment step, kept compact so the step fits without scrolling. */
.portal-billing__bundle-fields {
display: flex;
flex-direction: column;
gap: 0.625rem;
}
/* Company name + PO number share a row. */
.portal-billing__bundle-field-row {
display: flex;
@@ -560,70 +560,6 @@
outline-offset: -1px;
}
.portal-sources__connections {
margin-top: 1.5rem;
}
.portal-sources__connections-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--c-text-muted);
margin: 0 0 0.5rem;
}
.portal-sources__connections-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.portal-sources__connections-row {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.375rem 0;
border-bottom: 1px solid var(--color-border-2);
}
.portal-sources__connections-name {
font-weight: 500;
color: var(--c-text);
}
.portal-sources__connections-bucket {
color: var(--c-text-subtle);
font-size: 0.8125rem;
}
.portal-sources__connections-actions {
margin-left: auto;
display: flex;
gap: 0.25rem;
}
.portal-sources__connections-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-bottom: 0.5rem;
}
.portal-sources__connections-sub {
color: var(--c-text-subtle);
font-size: 0.875rem;
margin: 0;
}
.portal-sources__connections-actions {
display: inline-flex;
gap: 0.25rem;
justify-content: flex-end;
}
/* ---- Integration picker ---------------------------------------------------------------------
A searchable grid of what we can connect to. Sized so a full category is visible without
scrolling on a laptop, and so the search box is the first thing focus lands on. */
@@ -766,12 +766,6 @@
min-height: 0;
}
.oauth-container-fullwidth {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.oauth-button-fullwidth {
width: 100%;
display: flex;
+913 -16
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -154,6 +154,7 @@
"puppeteer": "^24.25.0",
"rollup-plugin-visualizer": "^7.0.1",
"storybook": "^9.1.20",
"stylelint": "^17.14.1",
"tsx": "^4.22.4",
"typescript": "npm:@typescript/typescript6@^6.0.2",
"typescript-eslint": "^8.61.1",
+13
View File
@@ -0,0 +1,13 @@
// Deliberately minimal: Prettier owns formatting and `task frontend:lint:colors`
// owns the theme tokens, so this only carries rules that catch real bugs.
export default {
ignoreFiles: [
"**/dist/**",
"**/src-tauri/**",
// Vendored third-party CSS (its first-party customisation file IS linted).
"**/editor/public/css/cookieconsent.css",
],
rules: {
"no-duplicate-selectors": true,
},
};