active_admin_theme 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,13 +5,337 @@ $skinMainSecondColor: #5ea3d3!default;
5
5
  $skinBorderRadius: 4px!default;
6
6
  $skinBorderWindowColor: #e6e9ee!default;
7
7
  $skinTablePadding: 10px!default;
8
+
9
+ // Content palette — the surfaces, text and borders the UI is built from, per
10
+ // mode. Each has a light value (the existing look) and a *Dark value; they feed
11
+ // the --aa-* custom properties below. Defaults reproduce the current colors, so
12
+ // non-configuring projects are unchanged.
13
+ $skinPageBgColor: #f7f9fb!default; $skinPageBgColorDark: #161a1e!default; // page background
14
+ $skinSurfaceColor: #ffffff!default; $skinSurfaceColorDark: #25292f!default; // panels / cards / content
15
+ $skinSurface2Color: #f0f2f5!default; $skinSurface2ColorDark: #2c3137!default; // table headers / striping / subtle fills
16
+ $skinSurfaceHoverColor: #f5f7fa!default; $skinSurfaceHoverColorDark:#3f454d!default; // row / item hover
17
+ $skinSelectedRowColor: #d9e4ec!default; $skinSelectedRowColorDark: #304457!default; // checked table row
18
+ // Things that float above the page — tool-row buttons and dropdown panels.
19
+ // On light they match the content surface; on dark they have to sit a step
20
+ // lighter than the page or they read as holes in it.
21
+ $skinElevatedColor: $skinSurfaceColor!default; $skinElevatedColorDark: #363c43!default;
22
+ $skinTextColor: #323537!default; $skinTextColorDark: #dde2e8!default; // body text
23
+ $skinTextMutedColor: #6b7177!default; $skinTextMutedColorDark: #b0b8c2!default; // secondary text / axis labels
24
+ $skinBorderColor: #e0e4e9!default; $skinBorderColorDark: #404750!default; // borders / grid lines
25
+ $skinInputBgColor: #ffffff!default; $skinInputBgColorDark: #1e2227!default; // form control background
26
+ $skinInputBorderColor: #c9ced4!default; $skinInputBorderColorDark: #4d555f!default; // form control border
27
+
28
+ // Header menu colors. Each defaults to the previous value, so projects that do
29
+ // not set these compile to identical CSS (and a project that overrides
30
+ // $skinMainSecondColor still gets the menu following that accent).
31
+ $skinMenuPillColor: #2e3236!default; // top-level current/hover pill
32
+ $skinMenuTextColor: #dfe2e6!default; // dropdown item text (was: inherited #fff)
33
+ $skinMenuPillTextColor: #6cb0de!default; // text on that pill; follows the dropdown text so a
34
+ // light menu is one variable to set, not two
35
+ $skinMenuPanelColor: #2e3236!default; // dropdown panel bg + hover "bridge" border
36
+ $skinMenuItemHoverColor: #3f454c!default; // dropdown item hover/current bg (was: none)
37
+ $skinMenuItemHoverTextColor: #6cb0de!default; // hover/current dropdown item text, same reason
38
+
39
+ // Header / menu sizing. Defaults reproduce (or keep the same total as) the
40
+ // previous hard-coded values, so non-configuring projects are unchanged.
41
+ $skinMenuFontSize: 13px!default; // header menu text size
42
+ $skinMenuItemPaddingY: 5px!default; // dropdown item top/bottom padding (was 6px/4px + a 7px border)
43
+ $skinMenuPanelMaxWidth: 260px!default; // dropdown panel ceiling; longer labels wrap instead of leaving the viewport
44
+ $skinMenuItemLineHeight: 1.35!default; // dropdown item line-height
45
+ // Header padding. Set $skinHeaderPaddingY for the same value top and bottom,
46
+ // or the two halves separately — the halves win, since they are read last.
47
+ $skinHeaderPaddingY: null!default;
48
+ $skinHeaderPaddingTop: if($skinHeaderPaddingY == null, 4.5px, $skinHeaderPaddingY)!default;
49
+ $skinHeaderPaddingBottom: if($skinHeaderPaddingY == null, 4.5px, $skinHeaderPaddingY)!default;
50
+ $skinHeaderLogoMaxHeight: none!default; // cap the site_title logo image height
51
+
52
+ // Title bar
53
+ $skinTitleBarColor: #343c46!default;
54
+ $skinTitleBarBorderColor: $skinMainSecondColor!default;
55
+ $skinTitleBarBorderWidth: 0!default;
56
+ $skinTitleBarButtonPaddingY: 6px!default; // action button vertical padding
57
+ $skinTitleBarButtonPaddingX: 10px!default; // action button horizontal padding
58
+
59
+ // Panel/section headers + tabs accent (the blue bar on panel headers and the
60
+ // inactive tabs). $skinPanelHeaderColor is the base/light value;
61
+ // $skinPanelHeaderColorDark lets a project use a different color in dark mode.
62
+ $skinPanelHeaderColor: var(--aa-page-bg)!default;
63
+ $skinPanelHeaderColorDark: var(--aa-page-bg)!default;
64
+ // Panel/section header TEXT color (the label on the colored header bar), per mode.
65
+ $skinPanelHeaderTextColor: var(--aa-inactive-tab-text)!default;
66
+ $skinPanelHeaderTextColorDark: var(--aa-inactive-tab-text)!default;
67
+
68
+ // Form label / legend text — a muted blue-grey in light; the regular text color
69
+ // in dark (where the muted blue-grey would be too dim).
70
+ $skinLabelColor: #8494a8!default;
71
+ $skinLabelColorDark: $skinTextColorDark!default;
72
+
73
+ // Buttons (form submit, title-bar action buttons, batch actions). Separate from
74
+ // the accent so buttons can be a non-blue color, with a dark-mode override.
75
+ // Darker than the accent because the label is white: the accent itself gives
76
+ // 2.74:1, under the 4.5:1 small text needs. At -20% it is 5.35:1, and it is the
77
+ // tone dark mode already used, so the button is now one colour in both modes.
78
+ $skinButtonColor: darken($skinMainSecondColor, 20%)!default;
79
+ // Label on those buttons. A project is invited above to pick a non-blue fill;
80
+ // without this the label stays white and a light fill is unreadable.
81
+ $skinButtonTextColor: #ffffff!default;
82
+ $skinButtonTextColorDark: $skinButtonTextColor!default;
83
+ $skinButtonColorDark: $skinButtonColor!default;
84
+
85
+ // Vertical padding controlling the height of panel/section headers and tabs.
86
+ $skinPanelHeaderPaddingY: 5px!default; // panel + sidebar header height
87
+ $skinTabPaddingY: 8px!default; // tab height
88
+ $skinTabPaddingX: 15px!default; // tab label horizontal padding (text → border)
89
+ // Height of every table-tools button (scopes, batch actions, view switcher,
90
+ // custom tools) — matched to the panel-header height.
91
+ $skinTableToolsHeight: 30px!default;
92
+ // Horizontal text padding inside each table-tools button (controls button width).
93
+ // Derived from the button height so the two scale together.
94
+ $skinTableToolsPaddingX: $skinTableToolsHeight * 0.4 !default; // 12px at 30px
95
+ // Per-group table-tools button fills. All default to the surface palette so the
96
+ // whole row shares one neutral look; override any group independently (both modes).
97
+
98
+ // Index-table column header text (both the sortable links and plain headers use
99
+ // one color, configurable per mode).
100
+
101
+ // Inactive tab background. Defaults to the panel-header color so tabs stay
102
+ // consistent, but can be set separately (e.g. a more subdued tab bar).
103
+
104
+ // Tab text colors — the active (selected) tab and the inactive tabs, per mode.
105
+
106
+ // Content link color (generic links inside the admin content), per mode.
107
+ // Focus ring / accent outline. Follows the theme accent, so a project that
108
+ // rebrands $skinMainSecondColor does not keep a stray blue focus border.
109
+ $skinAccentColor: $skinMainSecondColor!default;
110
+ $skinAccentColorDark: $skinAccentColor!default;
111
+ // Darker than the theme accent on purpose: the accent is a fill colour and
112
+ // fails WCAG AA as body text — #5ea3d3 is 2.74 on white, where 4.5 is the bar
113
+ // for text this size — and links also sit on zebra rows, table headers and
114
+ // selected rows, so the worst of those is what has to clear it. #1f5f8d
115
+ // keeps the hue and gives 5.28 against the darkest of them.
116
+ $skinLinkColor: #38678b!default;
117
+ $skinLinkColorDark: #7cc0ec!default;
118
+
119
+ // Delete / destroy links. Light follows the regular link color (so action links
120
+ // match); dark uses a lightened red, since the default red is too dark there.
121
+ $skinDeleteLinkColor: $skinLinkColor!default;
122
+ $skinDeleteLinkColorDark: #f49b9b!default;
123
+ // Tabs: fill and label colours per mode. yeti-web sets all four to make the
124
+ // inactive tabs recede to the page background and the active one read as raised.
125
+ $skinTabInactiveColor: #f7f9fb!default;
126
+ $skinTabInactiveColorDark: #161a1e!default;
127
+ $skinActiveTabTextColor: $skinMainSecondColor!default;
128
+ $skinActiveTabTextColorDark: #7cc0ec!default;
129
+ $skinInactiveTabTextColor: #5e6469!default;
130
+ $skinInactiveTabTextColorDark: #b0b8c2!default;
131
+ // Index-table column header text, one colour for sortable and plain headers.
132
+ $skinTableHeaderTextColor: #5e6469!default;
133
+ $skinTableHeaderTextColorDark: #dde2e8!default;
134
+
135
+ //DARK-MODE PALETTE---------------------------------------------------------------------------------------------------//
136
+ // Semantic CSS custom properties for runtime light/dark switching. Light values
137
+ // (= the existing look) live on :root; the dark values are applied either by the
138
+ // OS preference (unless the user forced light) or by an explicit html[data-theme].
139
+ // Phase 0: defined only — surfaces are repointed to these vars in later phases,
140
+ // so there is no visual change yet.
141
+ @mixin aa-dark-palette {
142
+ // Render native controls (checkboxes, radios, native selects, scrollbars) dark.
143
+ color-scheme: dark;
144
+ --aa-page-bg: #{$skinPageBgColorDark};
145
+ --aa-surface: #{$skinSurfaceColorDark};
146
+ --aa-surface-2: #{$skinSurface2ColorDark};
147
+ // Not $skinSurface2ColorDark: that is the zebra fill, and feeding both from
148
+ // one variable left the header band and every other row byte-identical.
149
+ // Light mode never had that problem — $skinBorderWindowColor gives the
150
+ // header its own step there.
151
+ --aa-table-header: #{$skinElevatedColorDark};
152
+ --aa-surface-hover: #{$skinSurfaceHoverColorDark};
153
+ --aa-selected: #{$skinSelectedRowColorDark};
154
+ --aa-elevated: #{$skinElevatedColorDark};
155
+ --aa-text: #{$skinTextColorDark};
156
+ --aa-text-muted: #{$skinTextMutedColorDark};
157
+ --aa-border: #{$skinBorderColorDark};
158
+ --aa-link: #{$skinLinkColorDark};
159
+ --aa-accent: #{$skinAccentColorDark};
160
+ --aa-input-bg: #{$skinInputBgColorDark};
161
+ --aa-input-border: #{$skinInputBorderColorDark};
162
+ --aa-shadow: rgba(0, 0, 0, 0.45);
163
+ --aa-panel-header: #{$skinPanelHeaderColorDark};
164
+ --aa-panel-header-text: #{$skinPanelHeaderTextColorDark};
165
+ --aa-label-text: #{$skinLabelColorDark};
166
+ --aa-button: #{$skinButtonColorDark};
167
+ --aa-button-text: #{$skinButtonTextColorDark};
168
+ --aa-button-hover: #{darken($skinButtonColorDark, 8%)};
169
+ --aa-table-header-text: #{$skinTableHeaderTextColorDark};
170
+ --aa-tab-inactive: #{$skinTabInactiveColorDark};
171
+ --aa-active-tab-text: #{$skinActiveTabTextColorDark};
172
+ --aa-inactive-tab-text: #{$skinInactiveTabTextColorDark};
173
+ --aa-delete-link: #{$skinDeleteLinkColorDark};
174
+ }
175
+ :root {
176
+ color-scheme: light;
177
+ --aa-page-bg: #{$skinPageBgColor};
178
+ --aa-surface: #{$skinSurfaceColor};
179
+ --aa-surface-2: #{$skinSurface2Color};
180
+ // Index-table headers keep following $skinBorderWindowColor, the knob the
181
+ // README has documented for years, instead of the new surface scale.
182
+ --aa-table-header: #{$skinBorderWindowColor};
183
+ --aa-surface-hover: #{$skinSurfaceHoverColor};
184
+ --aa-selected: #{$skinSelectedRowColor};
185
+ --aa-elevated: #{$skinElevatedColor};
186
+ --aa-text: #{$skinTextColor};
187
+ --aa-text-muted: #{$skinTextMutedColor};
188
+ --aa-border: #{$skinBorderColor};
189
+ --aa-link: #{$skinLinkColor};
190
+ --aa-accent: #{$skinAccentColor};
191
+ --aa-input-bg: #{$skinInputBgColor};
192
+ --aa-input-border: #{$skinInputBorderColor};
193
+ --aa-shadow: rgba(0, 0, 0, 0.08);
194
+ --aa-panel-header: #{$skinPanelHeaderColor};
195
+ --aa-panel-header-text: #{$skinPanelHeaderTextColor};
196
+ --aa-label-text: #{$skinLabelColor};
197
+ --aa-button: #{$skinButtonColor};
198
+ --aa-button-text: #{$skinButtonTextColor};
199
+ --aa-button-hover: #{darken($skinButtonColor, 8%)};
200
+ --aa-table-header-text: #{$skinTableHeaderTextColor};
201
+ --aa-tab-inactive: #{$skinTabInactiveColor};
202
+ --aa-active-tab-text: #{$skinActiveTabTextColor};
203
+ --aa-inactive-tab-text: #{$skinInactiveTabTextColor};
204
+ --aa-delete-link: #{$skinDeleteLinkColor};
205
+ }
206
+ // OS preference, unless the user explicitly chose light
207
+ @media (prefers-color-scheme: dark) {
208
+ html:not([data-theme="light"]) { @include aa-dark-palette; }
209
+ }
210
+ // Explicit user choice always wins
211
+ html[data-theme="dark"] { @include aa-dark-palette; }
212
+
213
+ // Public helper so a host app can scope its own (project-specific) overrides to
214
+ // dark mode using the same triggers. Use at the top level and put full selectors
215
+ // inside; the --aa-* custom properties are available:
216
+ // @include aa-dark { .my-widget { background: var(--aa-surface); } }
217
+ @mixin aa-dark {
218
+ @media (prefers-color-scheme: dark) {
219
+ html:not([data-theme="light"]) { @content; }
220
+ }
221
+ html[data-theme="dark"] { @content; }
222
+ }
223
+
224
+ // Иконки переключателя тем. Инлайном, потому что гем не возит картинок, и
225
+ // маской, а не цветным SVG: маска красится currentColor и сама идёт за
226
+ // $skinMenuTextColor. Половинка круга — auto, солнце — light, месяц — dark.
227
+ $theme-icon-auto: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.6' fill='none' stroke='black' stroke-width='1.4'/%3E%3Cpath d='M8 2.6a5.4 5.4 0 0 1 0 10.8z'/%3E%3C/svg%3E")!default;
228
+ $theme-icon-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='3.1'/%3E%3Cpath d='M8 .9v1.8M8 13.3v1.8M.9 8h1.8M13.3 8h1.8M2.9 2.9l1.3 1.3M11.8 11.8l1.3 1.3M13.1 2.9l-1.3 1.3M4.2 11.8l-1.3 1.3'/%3E%3C/svg%3E")!default;
229
+ $theme-icon-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13.4 9.6A5.9 5.9 0 0 1 6.4 2.6a5.9 5.9 0 1 0 7 7z'/%3E%3C/svg%3E")!default;
230
+
231
+ // A wrong-typed override is legal SassScript, so it compiles without a word and
232
+ // emits CSS the browser drops — `border-bottom: none solid #5ea3d3`,
233
+ // `padding: 10 12px`. The rule silently vanishes and ActiveAdmin's own value
234
+ // reappears. Fail the build with a readable message instead.
235
+ @each $name, $value in (
236
+ skinBorderRadius: $skinBorderRadius,
237
+ skinTablePadding: $skinTablePadding,
238
+ skinMenuFontSize: $skinMenuFontSize,
239
+ skinMenuItemPaddingY: $skinMenuItemPaddingY,
240
+ skinMenuPanelMaxWidth: $skinMenuPanelMaxWidth,
241
+ skinHeaderPaddingTop: $skinHeaderPaddingTop,
242
+ skinHeaderPaddingBottom: $skinHeaderPaddingBottom,
243
+ skinTitleBarBorderWidth: $skinTitleBarBorderWidth,
244
+ skinTitleBarButtonPaddingY: $skinTitleBarButtonPaddingY,
245
+ skinTitleBarButtonPaddingX: $skinTitleBarButtonPaddingX
246
+ ) {
247
+ @if type-of($value) != number or (unitless($value) and $value != 0) {
248
+ @error "$#{$name} must be a length with a unit (e.g. 10px), got `#{$value}`.";
249
+ }
250
+ }
251
+ @each $name, $value in (
252
+ skinMainFirstColor: $skinMainFirstColor,
253
+ skinMainSecondColor: $skinMainSecondColor,
254
+ skinBorderWindowColor: $skinBorderWindowColor,
255
+ skinMenuPillColor: $skinMenuPillColor,
256
+ skinMenuPillTextColor: $skinMenuPillTextColor,
257
+ skinMenuPanelColor: $skinMenuPanelColor,
258
+ skinMenuItemHoverColor: $skinMenuItemHoverColor,
259
+ skinMenuTextColor: $skinMenuTextColor,
260
+ skinTitleBarColor: $skinTitleBarColor,
261
+ skinTitleBarBorderColor: $skinTitleBarBorderColor,
262
+ skinSelectedRowColor: $skinSelectedRowColor,
263
+ skinSelectedRowColorDark: $skinSelectedRowColorDark,
264
+ skinAccentColor: $skinAccentColor,
265
+ skinAccentColorDark: $skinAccentColorDark,
266
+ skinButtonTextColor: $skinButtonTextColor,
267
+ skinButtonTextColorDark: $skinButtonTextColorDark,
268
+ skinPageBgColor: $skinPageBgColor,
269
+ skinPageBgColorDark: $skinPageBgColorDark,
270
+ skinSurfaceColor: $skinSurfaceColor,
271
+ skinSurfaceColorDark: $skinSurfaceColorDark,
272
+ skinSurface2Color: $skinSurface2Color,
273
+ skinSurface2ColorDark: $skinSurface2ColorDark,
274
+ skinSurfaceHoverColor: $skinSurfaceHoverColor,
275
+ skinSurfaceHoverColorDark: $skinSurfaceHoverColorDark,
276
+ skinElevatedColor: $skinElevatedColor,
277
+ skinElevatedColorDark: $skinElevatedColorDark,
278
+ skinTextColor: $skinTextColor,
279
+ skinTextColorDark: $skinTextColorDark,
280
+ skinTextMutedColor: $skinTextMutedColor,
281
+ skinTextMutedColorDark: $skinTextMutedColorDark,
282
+ skinBorderColor: $skinBorderColor,
283
+ skinBorderColorDark: $skinBorderColorDark,
284
+ skinInputBgColor: $skinInputBgColor,
285
+ skinInputBgColorDark: $skinInputBgColorDark,
286
+ skinInputBorderColor: $skinInputBorderColor,
287
+ skinInputBorderColorDark: $skinInputBorderColorDark,
288
+ skinMenuItemHoverTextColor: $skinMenuItemHoverTextColor,
289
+ skinLabelColor: $skinLabelColor,
290
+ skinLabelColorDark: $skinLabelColorDark,
291
+ skinButtonColor: $skinButtonColor,
292
+ skinButtonColorDark: $skinButtonColorDark,
293
+ skinLinkColor: $skinLinkColor,
294
+ skinLinkColorDark: $skinLinkColorDark,
295
+ skinDeleteLinkColor: $skinDeleteLinkColor,
296
+ skinDeleteLinkColorDark: $skinDeleteLinkColorDark,
297
+ skinTabInactiveColor: $skinTabInactiveColor,
298
+ skinTabInactiveColorDark: $skinTabInactiveColorDark,
299
+ skinActiveTabTextColor: $skinActiveTabTextColor,
300
+ skinActiveTabTextColorDark: $skinActiveTabTextColorDark,
301
+ skinInactiveTabTextColor: $skinInactiveTabTextColor,
302
+ skinInactiveTabTextColorDark: $skinInactiveTabTextColorDark,
303
+ skinTableHeaderTextColor: $skinTableHeaderTextColor,
304
+ skinTableHeaderTextColorDark: $skinTableHeaderTextColorDark
305
+ ) {
306
+ @if type-of($value) != color {
307
+ @error "$#{$name} must be a color (use `transparent`, not `none`), got `#{$value}`.";
308
+ }
309
+ }
310
+ // The panel header pair defaults to a custom property and is documented as
311
+ // accepting one, so a plain `type-of != color` would reject the shipped value.
312
+ @each $name, $value in (
313
+ skinPanelHeaderColor: $skinPanelHeaderColor,
314
+ skinPanelHeaderColorDark: $skinPanelHeaderColorDark,
315
+ skinPanelHeaderTextColor: $skinPanelHeaderTextColor,
316
+ skinPanelHeaderTextColorDark: $skinPanelHeaderTextColorDark
317
+ ) {
318
+ @if type-of($value) != color and str-index("#{$value}", "var(") != 1 {
319
+ @error "$#{$name} must be a color or a CSS custom property (e.g. var(--aa-page-bg)), got `#{$value}`.";
320
+ }
321
+ }
322
+ // Радиус внутреннего угла ячейки — на 1px меньше внешнего, чтобы не торчал
323
+ // из-под рамки таблицы. Вычитать px напрямую нельзя: $skinBorderRadius задаёт
324
+ // проект, и 0.25rem роняет всю компиляцию с «Incompatible units». calc()
325
+ // откладывает вычитание до браузера, а безразмерный 0 обрабатываем отдельно —
326
+ // calc(0 - 1px) невалиден.
327
+ @function inner-radius($radius) {
328
+ @if unitless($radius) { @return 0; }
329
+ @return calc(#{$radius} - 1px);
330
+ }
331
+
8
332
  //HTML----------------------------------------------------------------------------------------------------------------//
9
333
 
10
334
  html {
11
- background: #f7f9fb;
335
+ background: var(--aa-page-bg);
12
336
  }
13
337
  body.active_admin {
14
- background: #f7f9fb;
338
+ background: var(--aa-page-bg);
15
339
  }
16
340
  #wrapper {
17
341
  div.tabs {
@@ -21,11 +345,15 @@ body.active_admin {
21
345
  text-shadow: none;
22
346
  box-shadow: none;
23
347
  margin-bottom: 11px;
24
- border: none;
25
- background-color: $skinMainSecondColor;
26
- color: #ffffff;
348
+ // Top/side outline only; no bottom outline (the content panel's own top
349
+ // border is the baseline, drawn over the tabs via z-index below).
350
+ border: 1px solid var(--aa-border);
351
+ border-bottom: 0;
352
+ vertical-align: top;
353
+ background-color: var(--aa-tab-inactive);
354
+ color: var(--aa-inactive-tab-text);
27
355
  margin-right: 5px;
28
- padding: 10px 20px;
356
+ padding: $skinTabPaddingY $skinTabPaddingX;
29
357
 
30
358
  -webkit-border-top-left-radius: $skinBorderRadius;
31
359
  -webkit-border-top-right-radius: $skinBorderRadius;
@@ -42,68 +370,162 @@ body.active_admin {
42
370
  -moz-border-radius-bottomright: 0;
43
371
  border-bottom-right-radius: 0;
44
372
  }
373
+ // Active tab sits above the content panel (z-index: 2) and is filled with the
374
+ // content color, so it covers the panel's top border there and merges in.
45
375
  ul > li.ui-state-active > a {
46
- background-color: #ffffff;
47
- border: 1px solid $skinBorderWindowColor;
48
- border-bottom: 0;
49
- color: $skinMainSecondColor;
376
+ background-color: var(--aa-surface);
377
+ border: 1px solid var(--aa-border);
378
+ border-bottom-color: var(--aa-surface);
379
+ color: var(--aa-active-tab-text);
380
+ position: relative;
381
+ z-index: 2;
382
+ vertical-align: top;
50
383
  }
51
384
  div.tab-content {
52
- background-color: #ffffff;
53
- border: 1px solid $skinBorderWindowColor;
54
- border-bottom: 2px solid $skinBorderWindowColor;
385
+ background-color: var(--aa-surface);
386
+ // Uniform 1px border (no thicker bottom) so the rounded corners are even.
387
+ border: 1px solid var(--aa-border);
55
388
  @include rounded($skinBorderRadius);
389
+ // Paint above the inactive tabs so the panel's own top border is the
390
+ // baseline drawn over them (the active tab paints above this, z-index: 2).
391
+ position: relative;
392
+ z-index: 1;
56
393
  }
57
394
  }
58
395
  #header {
59
396
  background-color: $skinMainFirstColor;
60
397
  border-bottom: 1px solid lighten( $skinMainFirstColor, 15% )!important;
61
- padding-bottom: 9px;
398
+ padding-top: $skinHeaderPaddingTop;
399
+ padding-bottom: $skinHeaderPaddingBottom;
62
400
  border: none;
63
401
  text-shadow: none;
64
402
  background-image: none;
65
403
  h1.site_title {
66
404
  color: $skinMainSecondColor;
67
405
  font-size: 16px;
406
+ img {
407
+ max-height: $skinHeaderLogoMaxHeight;
408
+ }
68
409
  }
69
410
  a, a:link {
70
411
  color: #ffffff;
71
412
  }
72
413
  ul.tabs > li > a {
73
- color: #ffffff;
414
+ // On the anchor, not the li, so the dropdown subtree does not inherit it.
415
+ font-size: $skinMenuFontSize;
74
416
  @include rounded($skinBorderRadius);
75
417
  padding: 6px 10px 6px 10px;
76
418
  }
77
419
  ul.tabs > li.current > a, ul.tabs > li:hover > a {
78
- background-color: $skinMainSecondColor;
420
+ background-color: $skinMenuPillColor;
421
+ color: $skinMenuPillTextColor;
422
+ }
423
+ // ActiveAdmin swaps in its "dark" submenu arrow on the current/hovered item,
424
+ // which assumes the highlight is lighter than the bar. The default pill is
425
+ // not, so keep the light arrow there.
426
+ ul.tabs > li.has_nested.current > a, ul.tabs > li.has_nested:hover > a {
427
+ background-image: url($menu-arrow-light-icon-url);
428
+ }
429
+ // The utility nav (username, clock, theme switcher, logout) are not navigation
430
+ // tabs: drop the pill padding, and on hover highlight by text colour only — no
431
+ // background block. The clock has no click action, so it gets no hover at all.
432
+ #utility_nav {
433
+ > li > a { padding: 0 5px; }
434
+ > li:hover > a, > li.current > a { background-color: transparent; }
435
+ > li#servertime:hover > a { color: #ffffff; }
436
+
437
+ // The theme switch (app/assets/javascripts/wigu/theme_toggle.js). The
438
+ // script only writes data-mode; the glyph is drawn here, so a project can
439
+ // swap it for its own icon font without forking the script. Masked rather
440
+ // than embedded as a coloured SVG so it takes currentColor and follows
441
+ // $skinMenuTextColor like every other item in the bar.
442
+ // On the li, not only the anchor: font-size 0 collapses the anchor to the
443
+ // icon's own 16px, which then sits at the top of the item instead of on
444
+ // the line the rest of the bar shares.
445
+ > li#theme_toggle { display: flex; align-items: center; }
446
+ > li#theme_toggle > a {
447
+ display: flex;
448
+ align-items: center;
449
+ font-size: 0;
450
+ opacity: 0.75;
451
+
452
+ &:before {
453
+ content: "";
454
+ display: block;
455
+ width: 16px;
456
+ height: 16px;
457
+ background-color: currentColor;
458
+ -webkit-mask: #{$theme-icon-auto} center / contain no-repeat;
459
+ mask: #{$theme-icon-auto} center / contain no-repeat;
460
+ }
461
+ &:hover, &:focus { opacity: 1; }
462
+ }
463
+ > li#theme_toggle[data-mode="light"] > a:before {
464
+ -webkit-mask-image: $theme-icon-light;
465
+ mask-image: $theme-icon-light;
466
+ }
467
+ > li#theme_toggle[data-mode="dark"] > a:before {
468
+ -webkit-mask-image: $theme-icon-dark;
469
+ mask-image: $theme-icon-dark;
470
+ }
79
471
  }
80
472
  ul.tabs {
81
473
  li.has_nested {
82
- a {
474
+ // `> a` only: leaf items need no room for the submenu arrow.
475
+ > a {
83
476
  padding-right: 20px;
84
477
  }
85
478
  ul {
86
- background-color: $skinMainSecondColor;
87
- @include rounded($skinBorderRadius);
479
+ background-color: $skinMenuPanelColor;
480
+ @include rounded-all(0, $skinBorderRadius, $skinBorderRadius, $skinBorderRadius);
481
+ // Size to content instead of the base's max-width: calc(100% + 20px),
482
+ // which wraps long labels onto a second line — but keep a ceiling, or
483
+ // a long label pushes the panel out of the viewport where the :hover
484
+ // chain cannot follow it. Past the ceiling, labels wrap as before.
485
+ // Known limit: a depth-2 flyout under a right-edge tab can still leave
486
+ // a 1280px viewport — it sits at left:100% of an already-offset panel,
487
+ // and CSS cannot see the distance to the viewport edge. ActiveAdmin's
488
+ // own 175px panels already land within 5px of the edge there, so any
489
+ // widening inherits this. A full fix needs JS that flips the flyout to
490
+ // `right:100%`, or CSS anchor positioning once it is baseline.
491
+ width: max-content;
492
+ max-width: $skinMenuPanelMaxWidth;
493
+ overflow-wrap: break-word;
88
494
  li > a {
89
495
  padding-left: 15px;
496
+ color: $skinMenuTextColor;
497
+ line-height: $skinMenuItemLineHeight;
498
+ padding-top: $skinMenuItemPaddingY;
499
+ padding-bottom: $skinMenuItemPaddingY;
90
500
  }
91
- li.current > a::before, li:hover > a::before {
501
+ li:hover > a, li.current > a, li > a:focus {
502
+ background-color: $skinMenuItemHoverColor;
503
+ color: $skinMenuItemHoverTextColor;
504
+ }
505
+ li.current > a::before, li:hover > a::before, li > a:focus::before {
92
506
  content: '';
93
507
  display: block;
94
- width: 7px;
95
- height: 4px;
96
508
  position: absolute;
97
- top: 12px;
509
+ top: 50%;
98
510
  left: 4px;
99
- background: transparent url($menu-arrow-dark-icon-url) no-repeat 0 0;
100
- transform: rotate(-90deg);
511
+ // currentColor, so the marker follows $skinMenuTextColor instead of
512
+ // a fixed-palette PNG that only reads against the default panel.
513
+ border: 3px solid transparent;
514
+ border-left-color: currentColor;
515
+ margin-top: -3px;
101
516
  }
102
517
  }
103
518
  }
104
- li.has_nested:hover {
105
- a {
106
- border-bottom: 7px solid $skinMainSecondColor;
519
+ // `> li.has_nested` + `> a` so the "bridge" border is added only to a
520
+ // hovered TOP-LEVEL menu item (bridging its pill to the dropdown). Without
521
+ // the `>`, nested has_nested items (e.g. System > Components) also got the
522
+ // border, which pushed the next dropdown item down when their submenu
523
+ // opened. 5px to match the base's `ul { margin-top: 5px }` gap, and square
524
+ // off the corners that face the panel so the header does not show through.
525
+ > li.has_nested:hover {
526
+ > a {
527
+ @include rounded-top($skinBorderRadius);
528
+ border-bottom: 5px solid $skinMenuPanelColor;
107
529
  }
108
530
  }
109
531
  }
@@ -112,9 +534,9 @@ body.active_admin {
112
534
  background-image: none;
113
535
  border: none;
114
536
  box-shadow: none;
115
- background-color: lighten( $skinMainFirstColor, 8% );
537
+ background-color: $skinTitleBarColor;
116
538
  border: none;
117
- border-bottom: 3px solid $skinMainSecondColor;
539
+ border-bottom: $skinTitleBarBorderWidth solid $skinTitleBarBorderColor;
118
540
  #titlebar_left {
119
541
  span.breadcrumb {
120
542
  font-size: 12px;
@@ -130,62 +552,61 @@ body.active_admin {
130
552
  }
131
553
  }
132
554
  #titlebar_right {
133
- .action_item a {
555
+ // `> a` and `> .dropdown_menu > a`: an action item may hold a dropdown, and
556
+ // a descendant selector here paints its menu entries with the button fill
557
+ // too — with !important, so the entry rules below cannot undo it.
558
+ .action_item > a,
559
+ .action_item > .dropdown_menu > a {
134
560
  background-image: none;
135
561
  border: none;
136
562
  box-shadow: none;
137
563
  text-shadow: none;
138
564
  @include rounded($skinBorderRadius);
139
- background-color: $skinMainSecondColor;
565
+ background-color: var(--aa-button);
140
566
  border: none;
141
- padding: 10px 20px;
142
- color: #ffffff;
567
+ padding: $skinTitleBarButtonPaddingY $skinTitleBarButtonPaddingX;
568
+ color: var(--aa-button-text);
143
569
  font-weight: 600;
144
570
  &:hover {
145
- background-color: lighten( $skinMainSecondColor, 5% )!important;
571
+ background-color: var(--aa-button-hover)!important;
146
572
  }
147
573
  }
148
574
  div.dropdown_menu {
149
575
  div.dropdown_menu_list_wrapper {
150
- background-color: $skinMainFirstColor;
151
- border: none;
576
+ background-color: var(--aa-elevated);
577
+ border: 1px solid var(--aa-border);
152
578
  background-image: none;
153
- border: none;
154
579
  box-shadow: none;
155
- div.dropdown_menu_nipple, div.dropdown_menu_nipple:after, div.dropdown_menu_nipple:before {
156
- border-color: $skinMainFirstColor transparent;
580
+ // ActiveAdmin draws the nipple as three stacked triangles: the element
581
+ // itself is the outline, :before the inner shadow, :after the fill.
582
+ // Painting all three the same colour collapses it into a solid arrow
583
+ // that is invisible whenever the panel fill is close to the page —
584
+ // which is exactly what a light surface is. Outline it like the panel.
585
+ div.dropdown_menu_nipple {
586
+ border-color: var(--aa-border) transparent;
587
+ &:before, &:after { border-color: var(--aa-elevated) transparent; }
157
588
  }
158
589
  ul.dropdown_menu_list {
159
590
  box-shadow: none;
160
591
  li {
161
592
  a {
162
- background-color: #ffffff;
163
- color: $skinMainFirstColor;
593
+ background-color: var(--aa-surface);
594
+ color: var(--aa-text);
164
595
  border-radius: 0;
165
596
  &:hover {
166
- background-color: $skinMainSecondColor;
167
- color: #ffffff;
597
+ // background-image, not just background-color: ActiveAdmin
598
+ // paints this hover with a linear-gradient, and a gradient
599
+ // sits on top of the background colour — leaving it in place
600
+ // made every colour set here invisible.
601
+ background-image: none;
602
+ background-color: var(--aa-selected);
603
+ color: var(--aa-text);
168
604
  }
169
605
  }
170
606
  }
171
607
  }
172
608
  }
173
609
  }
174
- div.batch_actions_selector {
175
- a {
176
- background-image: none;
177
- border: none;
178
- box-shadow: none;
179
- background-color: $skinMainSecondColor;
180
- @include rounded($skinBorderRadius);
181
- border: none;
182
- padding: 10px 20px;
183
- color: #ffffff;
184
- &:hover {
185
- background-color: lighten( $skinMainSecondColor, 5% );
186
- }
187
- }
188
- }
189
610
  }
190
611
  }
191
612
  .flashes {
@@ -210,32 +631,77 @@ body.active_admin {
210
631
  }
211
632
  #active_admin_content {
212
633
  span.blank_slate {
213
- border: 2px solid lighten( $skinMainSecondColor, 30% );
214
- color: #8494a8;
634
+ // Was a hardcoded lightened blue (too bright in dark mode); use the palette
635
+ // border + muted text so it adapts to light/dark.
636
+ border: 2px solid var(--aa-border);
637
+ color: var(--aa-text-muted);
215
638
  @include rounded($skinBorderRadius);
216
639
  }
217
640
  div.table_tools {
218
- margin-bottom: 35px;
641
+ margin-bottom: 14px; // match the gap between sidebar sections
642
+ // The gem shrinks the scope / batch / tool buttons to 0.9em; reset to 1em so
643
+ // they match the surrounding base text — the same size the panel headers use.
644
+ .scopes a, a.table_tools_button, .dropdown_menu_button { font-size: 1em; }
645
+ // Contain the floated buttons so the margin sits below them. The collapsible-
646
+ // sidebar gem sets `.table_tools:after { clear: none; padding-bottom: 16px }`,
647
+ // which disables the float clearfix and otherwise leaves the box ~16px tall
648
+ // with the 29px buttons overflowing into the margin.
649
+ display: flow-root;
650
+ &::after { padding-bottom: 0; }
651
+ // Gap between the batch-actions button and the scopes — only rendered when
652
+ // the button is present, so scope-only pages stay flush with the table edge.
653
+ div.batch_actions_selector { margin-right: 10px; }
654
+ // Baseline for any table_tools button (the index-list view switcher, custom
655
+ // tools like "Visible columns", etc.). The base AA style is a light gradient;
656
+ // theme it via the --aa-* vars. Scopes override the fill + segmented-control
657
+ // geometry below (they reset border-radius and re-round only the ends).
658
+ // .dropdown_menu_button is the same control with a different class (the
659
+ // "Visible columns" style tools); without it here it keeps ActiveAdmin's
660
+ // white gradient pill at 22px next to the themed 30px buttons.
661
+ a.table_tools_button, a.dropdown_menu_button {
662
+ box-sizing: border-box;
663
+ height: $skinTableToolsHeight;
664
+ line-height: $skinTableToolsHeight; // = button height: nudges the text to the optical centre (the font otherwise sits high in the line box)
665
+ background: var(--aa-elevated);
666
+ background-image: none;
667
+ border: 1px solid var(--aa-border);
668
+ color: var(--aa-text);
669
+ @include rounded($skinBorderRadius);
670
+ padding: 0 $skinTableToolsPaddingX;
671
+ box-shadow: none;
672
+ text-shadow: none;
673
+ &:hover { background: var(--aa-surface-hover); }
674
+ }
219
675
  div.dropdown_menu {
220
676
  div.dropdown_menu_list_wrapper {
221
- background-color: $skinMainFirstColor;
222
- border: none;
677
+ background-color: var(--aa-elevated);
678
+ border: 1px solid var(--aa-border);
223
679
  background-image: none;
224
- border: none;
225
680
  box-shadow: none;
226
- div.dropdown_menu_nipple, div.dropdown_menu_nipple:after, div.dropdown_menu_nipple:before {
227
- border-color: $skinMainFirstColor transparent;
681
+ // ActiveAdmin draws the nipple as three stacked triangles: the element
682
+ // itself is the outline, :before the inner shadow, :after the fill.
683
+ // Painting all three the same colour collapses it into a solid arrow
684
+ // that is invisible whenever the panel fill is close to the page —
685
+ // which is exactly what a light surface is. Outline it like the panel.
686
+ div.dropdown_menu_nipple {
687
+ border-color: var(--aa-border) transparent;
688
+ &:before, &:after { border-color: var(--aa-elevated) transparent; }
228
689
  }
229
690
  ul.dropdown_menu_list {
230
691
  box-shadow: none;
231
692
  li {
232
693
  a {
233
- background-color: #ffffff;
234
- color: $skinMainFirstColor;
694
+ background-color: var(--aa-surface);
695
+ color: var(--aa-text);
235
696
  border-radius: 0;
236
697
  &:hover {
237
- background-color: $skinMainSecondColor;
238
- color: #ffffff;
698
+ // background-image, not just background-color: ActiveAdmin
699
+ // paints this hover with a linear-gradient, and a gradient
700
+ // sits on top of the background colour — leaving it in place
701
+ // made every colour set here invisible.
702
+ background-image: none;
703
+ background-color: var(--aa-selected);
704
+ color: var(--aa-text);
239
705
  }
240
706
  }
241
707
  }
@@ -243,40 +709,53 @@ body.active_admin {
243
709
  }
244
710
  }
245
711
  div.batch_actions_selector {
246
- a {
712
+ > a {
713
+ box-sizing: border-box;
714
+ height: $skinTableToolsHeight;
715
+ line-height: $skinTableToolsHeight;
247
716
  background-image: none;
248
- border: none;
249
717
  box-shadow: none;
250
- background-color: $skinMainSecondColor;
718
+ background-color: var(--aa-elevated);
251
719
  @include rounded($skinBorderRadius);
252
- border: none;
253
- padding: 10px 20px;
254
- color: #ffffff;
720
+ border: 1px solid var(--aa-border);
721
+ padding: 0 $skinTableToolsPaddingX;
722
+ color: var(--aa-text);
255
723
  &:hover {
256
- background-color: lighten( $skinMainSecondColor, 5% );
724
+ background-color: var(--aa-surface-hover);
257
725
  }
258
726
  }
259
727
  }
260
728
  div.dropdown_menu {
261
729
  div.dropdown_menu_list_wrapper {
262
- background-color: $skinMainFirstColor;
263
- border: none;
730
+ background-color: var(--aa-elevated);
731
+ border: 1px solid var(--aa-border);
264
732
  background-image: none;
265
- div.dropdown_menu_nipple, div.dropdown_menu_nipple:after, div.dropdown_menu_nipple:before {
266
- border-color: $skinMainFirstColor transparent;
733
+ // ActiveAdmin draws the nipple as three stacked triangles: the element
734
+ // itself is the outline, :before the inner shadow, :after the fill.
735
+ // Painting all three the same colour collapses it into a solid arrow
736
+ // that is invisible whenever the panel fill is close to the page —
737
+ // which is exactly what a light surface is. Outline it like the panel.
738
+ div.dropdown_menu_nipple {
739
+ border-color: var(--aa-border) transparent;
740
+ &:before, &:after { border-color: var(--aa-elevated) transparent; }
267
741
  }
268
742
  ul.dropdown_menu_list {
269
743
  box-shadow: none;
270
744
  li {
271
745
  a {
272
- background-color: #ffffff;
746
+ background-color: var(--aa-surface);
273
747
  box-shadow: none;
274
- color: $skinMainFirstColor;
748
+ color: var(--aa-text);
275
749
  border-radius: 0;
276
750
  text-shadow: none;
277
751
  &:hover {
278
- background-color: $skinMainSecondColor;
279
- color: #ffffff;
752
+ // background-image, not just background-color: ActiveAdmin
753
+ // paints this hover with a linear-gradient, and a gradient
754
+ // sits on top of the background colour — leaving it in place
755
+ // made every colour set here invisible.
756
+ background-image: none;
757
+ background-color: var(--aa-selected);
758
+ color: var(--aa-text);
280
759
  }
281
760
  }
282
761
  }
@@ -284,41 +763,61 @@ body.active_admin {
284
763
  }
285
764
  }
286
765
  div.batch_actions_selector {
287
- a {
766
+ > a {
767
+ box-sizing: border-box;
768
+ height: $skinTableToolsHeight;
769
+ line-height: $skinTableToolsHeight;
288
770
  background-image: none;
289
- background-color: $skinMainSecondColor;
771
+ background-color: var(--aa-elevated);
290
772
  @include rounded($skinBorderRadius);
291
- border: none;
292
- padding: 10px 20px;
293
- color: #ffffff;
773
+ border: 1px solid var(--aa-border);
774
+ padding: 0 $skinTableToolsPaddingX;
775
+ color: var(--aa-text);
294
776
  text-shadow: none;
295
777
  box-shadow: none;
296
778
  &:hover {
297
- background-color: lighten( $skinMainSecondColor, 5% );
779
+ background-color: var(--aa-surface-hover);
298
780
  box-shadow: none;
299
781
  }
300
782
  }
301
783
  }
302
- ul.scopes, div.scopes > ul {
784
+ // ActiveAdmin renders the index view switcher with the same classes as
785
+ // the scope bar — ul.indexes.table_tools_segmented_control, anchors
786
+ // carrying .table_tools_button — so it needs the same segmented
787
+ // geometry. Without it the switcher keeps the generic button radius on
788
+ // every segment, the shared borders double up, and the selected view is
789
+ // indistinguishable from the others.
790
+ ul.scopes, div.scopes > ul, ul.indexes {
303
791
  li {
304
792
  a {
305
793
  background-image: none;
306
- border: none;
794
+ // Reset the generic .table_tools_button radius — scopes are a segmented
795
+ // control, so only the first/last child are re-rounded (below).
796
+ @include rounded(0);
797
+ // Outline the segmented control with the border color (was a white
798
+ // right-divider, which is invisible when the scope bar matches the
799
+ // page background). Adjacent borders are collapsed below.
800
+ border: 1px solid var(--aa-border);
307
801
  box-shadow: none;
308
- background-color: $skinMainSecondColor;
309
- padding: 10px 20px;
310
- color: #ffffff;
802
+ background-color: var(--aa-surface);
803
+ padding: 0 $skinTableToolsPaddingX;
804
+ color: var(--aa-text);
311
805
  text-shadow: none;
312
- border-right: 1px solid #ffffff;
313
806
  span {
314
- color: #ffffff;
807
+ color: var(--aa-text);
315
808
  font-size: 11px;
316
809
  font-weight: bold;
317
810
  }
318
811
  }
319
812
  }
813
+ li + li a { margin-left: -1px; } // collapse the shared border between scopes
320
814
  li:first-child {
321
815
  a {
816
+ // Override AA's base `.scopes li:first-child a { margin-left: 10px }`.
817
+ // That gap belongs on the batch-actions button (margin-right below), so
818
+ // the scope bar aligns with the table's left edge when there are no
819
+ // batch actions.
820
+ margin-left: 0;
322
821
  -webkit-border-top-left-radius: $skinBorderRadius;
323
822
  -webkit-border-bottom-left-radius: $skinBorderRadius;
324
823
  -moz-border-radius-topleft: $skinBorderRadius;
@@ -339,16 +838,24 @@ body.active_admin {
339
838
  }
340
839
  li.selected {
341
840
  a {
342
- background-color: lighten( $skinMainSecondColor, 15% );
841
+ // Selected scope: a touch lighter than the neutral fill, plus an accent
842
+ // text colour so the active scope's label stands out.
843
+ background-color: var(--aa-surface-hover);
844
+ color: var(--aa-link);
845
+ span { color: var(--aa-link); }
343
846
  }
344
847
  }
345
848
  }
346
849
  }
347
850
  }
348
851
  table.index_table {
349
- background-color: #ffffff;
350
- border: 1px solid $skinBorderWindowColor;
351
- border-bottom: 2px solid $skinBorderWindowColor;
852
+ background-color: var(--aa-surface);
853
+ // Uniform 1px border (no thicker bottom) so the rounded corners are even.
854
+ border: 1px solid var(--aa-border);
855
+ // The right edge is owned by the last-column cells (below) rather than the
856
+ // table itself, so a last-column cell's own border-right doesn't stack
857
+ // against the table border 1px further out (a doubled right line).
858
+ border-right: 0;
352
859
  @include rounded($skinBorderRadius);
353
860
  th {
354
861
  background-image: none;
@@ -359,16 +866,46 @@ body.active_admin {
359
866
  font-weight: bold;
360
867
  background-color: $skinBorderWindowColor;
361
868
  padding: $skinTablePadding 12px $skinTablePadding 12px;
362
- border-bottom: 3px solid darken( $skinBorderWindowColor, 5% );
869
+ // 1px header underline (was 3px) so it matches the other 1px borders.
870
+ border-bottom: 1px solid darken( $skinBorderWindowColor, 5% );
363
871
  border-right: 1px solid darken( $skinBorderWindowColor, 5% );
364
872
  a {
365
873
  font-size: 1.0em;
366
874
  font-weight: bold!important;
367
875
  }
368
876
  }
877
+ // Right edge = a single 1px line on the last-column cells (header th, body
878
+ // td, footer cells) coloured like the table border, since the table itself
879
+ // no longer draws a right border.
880
+ thead th:last-child,
881
+ tbody td:last-child,
882
+ tfoot tr > :last-child {
883
+ border-right: 1px solid var(--aa-border);
884
+ }
885
+ // Drop the bottom row's cell border: with border-collapse: separate it sits
886
+ // just inside the table's own bottom border, so the two stack and the bottom
887
+ // edge looks thicker than the other sides. The bottom row is the footer's
888
+ // last row when there's a totals footer, otherwise the body's last row.
889
+ tfoot tr:last-child > td,
890
+ tfoot tr:last-child > th { border-bottom: 0; }
891
+ &:not(:has(tfoot)) tbody tr:last-child > td { border-bottom: 0; }
892
+ // Round the corner cells so their square backgrounds follow the table's
893
+ // rounded border instead of cutting square notches into it (separate borders
894
+ // don't round cell backgrounds). Nest 1px inside the table's outer radius.
895
+ thead th:first-child { border-top-left-radius: inner-radius($skinBorderRadius); }
896
+ thead th:last-child { border-top-right-radius: inner-radius($skinBorderRadius); }
897
+ tfoot tr:last-child > :first-child { border-bottom-left-radius: inner-radius($skinBorderRadius); }
898
+ tfoot tr:last-child > :last-child { border-bottom-right-radius: inner-radius($skinBorderRadius); }
899
+ &:not(:has(tfoot)) tbody tr:last-child > td:first-child { border-bottom-left-radius: inner-radius($skinBorderRadius); }
900
+ &:not(:has(tfoot)) tbody tr:last-child > td:last-child { border-bottom-right-radius: inner-radius($skinBorderRadius); }
369
901
  th.col-selectable {
370
902
  width: 12px;
371
903
  }
904
+ // Center the batch-actions checkboxes (header select-all + per-row): they are
905
+ // baseline-aligned and otherwise ride a few px high in the cell.
906
+ .col-selectable input[type="checkbox"] {
907
+ vertical-align: middle;
908
+ }
372
909
  th.sorted-desc {
373
910
  background-color: $skinBorderWindowColor;
374
911
  }
@@ -388,18 +925,19 @@ body.active_admin {
388
925
  .sidebar_section.panel {
389
926
  background-image: none;
390
927
  box-shadow: none;
391
- background-color: #ffffff;
392
- border: 1px solid $skinBorderWindowColor;
393
- border-bottom: 2px solid $skinBorderWindowColor;
928
+ background-color: var(--aa-surface);
929
+ // Uniform 1px border (no thicker bottom) so the rounded corners are even.
930
+ border: 1px solid var(--aa-border);
394
931
  & > h3 {
395
932
  background-image: none;
396
933
  box-shadow: none;
397
934
  text-shadow: none;
398
- background-color: $skinMainSecondColor;
399
- color: #ffffff;
935
+ background-color: var(--aa-panel-header);
936
+ color: var(--aa-panel-header-text);
400
937
  border: none;
401
- padding: 8px 15px;
402
- font-weight: 400;
938
+ border-bottom: 1px solid var(--aa-border);
939
+ padding: $skinPanelHeaderPaddingY 15px;
940
+ font-weight: 700; // match the tab label weight
403
941
 
404
942
  -webkit-border-top-left-radius: $skinBorderRadius;
405
943
  -webkit-border-top-right-radius: $skinBorderRadius;
@@ -410,11 +948,11 @@ body.active_admin {
410
948
  }
411
949
  .filter_form_field {
412
950
  label {
413
- color: #8494a8;
951
+ color: var(--aa-label-text);
414
952
  }
415
953
  input {
416
- border: 1px solid #e6e9ee;
417
- background-color: #fdfefe;
954
+ border: 1px solid var(--aa-input-border);
955
+ background-color: var(--aa-input-bg);
418
956
  }
419
957
  input:focus {
420
958
  border-color: lighten( $skinMainSecondColor, 20% ) ;
@@ -429,18 +967,18 @@ form fieldset > ol > li fieldset.fragments ol {
429
967
  form fieldset ol > li.has_many_container h3 {
430
968
  color: #8494a8;
431
969
  }
432
- form input[type=submit], a.button, a:link.button, a:visited.button, fieldset.actions > ol > li.button_action > button {
970
+ form input[type=submit], form input[type=button], form button, a.button, a:link.button, a:visited.button {
433
971
  background-image: none;
434
972
  box-shadow: none;
435
973
  text-shadow: none;
436
- background-color: $skinMainSecondColor;
974
+ background-color: var(--aa-button);
437
975
  @include rounded($skinBorderRadius);
438
976
  border: none;
439
977
  padding: 10px 20px;
440
- color: #ffffff;
978
+ color: var(--aa-button-text);
441
979
  &:hover {
442
980
  background-image: none!important;
443
- background-color: lighten( $skinMainSecondColor, 5% )!important;
981
+ background-color: var(--aa-button-hover)!important;
444
982
  }
445
983
  }
446
984
  form fieldset.buttons li.cancel a, form fieldset.actions li.cancel a, form.filter_form a.clear_filters_btn {
@@ -461,20 +999,21 @@ form fieldset.inputs {
461
999
  box-shadow: none;
462
1000
  text-shadow: none;
463
1001
  box-shadow: none;
464
- background-color: #ffffff;
465
- border: 1px solid #e6e9ee;
466
- border-bottom: 2px solid #e6e9ee;
1002
+ background-color: var(--aa-surface);
1003
+ // Uniform 1px border (no thicker bottom) so the rounded corners stay even.
1004
+ border: 1px solid var(--aa-input-border);
467
1005
  legend {
468
1006
  span {
469
1007
  background-image: none;
470
1008
  box-shadow: none;
471
1009
  text-shadow: none;
472
1010
  box-shadow: none;
473
- background-color: $skinMainSecondColor;
474
- color: #ffffff;
1011
+ background-color: var(--aa-panel-header);
1012
+ color: var(--aa-panel-header-text);
475
1013
  border: none;
476
- padding: 8px 15px;
477
- font-weight: 400;
1014
+ border-bottom: 1px solid var(--aa-border);
1015
+ padding: $skinPanelHeaderPaddingY 15px;
1016
+ font-weight: 700; // match the tab label weight
478
1017
 
479
1018
  -webkit-border-top-left-radius: $skinBorderRadius;
480
1019
  -webkit-border-top-right-radius: $skinBorderRadius;
@@ -486,11 +1025,11 @@ form fieldset.inputs {
486
1025
  }
487
1026
  ol > li {
488
1027
  label {
489
- color: #8494a8;
1028
+ color: var(--aa-label-text);
490
1029
  }
491
1030
  input, textarea {
492
- border: 1px solid #e6e9ee;
493
- background-color: #fdfefe;
1031
+ border: 1px solid var(--aa-input-border);
1032
+ background-color: var(--aa-input-bg);
494
1033
  }
495
1034
  input:focus, textarea:focus {
496
1035
  border-color: lighten( $skinMainSecondColor, 20% ) ;
@@ -521,7 +1060,7 @@ form fieldset.inputs {
521
1060
  border-bottom: 10px solid $skinMainSecondColor;
522
1061
  }
523
1062
  table.ui-datepicker-calendar {
524
- background-color: #ffffff;
1063
+ background-color: var(--aa-surface);
525
1064
  border-color: $skinMainSecondColor;
526
1065
  thead {
527
1066
  tr {
@@ -551,20 +1090,24 @@ form fieldset.inputs {
551
1090
  box-shadow: none;
552
1091
  text-shadow: none;
553
1092
  box-shadow: none;
554
- background-color: #ffffff;
555
- border: 1px solid $skinBorderWindowColor;
556
- border-bottom: 2px solid $skinBorderWindowColor;
1093
+ background-color: var(--aa-surface);
1094
+ // Uniform border width on all sides: a thicker (2px) bottom border combined
1095
+ // with border-radius renders a distorted, non-uniform bottom corner (the outer
1096
+ // edge curves but the border's inner edge looks square). 1px all round keeps
1097
+ // the rounded corners symmetric.
1098
+ border: 1px solid var(--aa-border);
557
1099
  > h3 {
558
1100
  background-image: none;
559
1101
  box-shadow: none;
560
1102
  text-shadow: none;
561
1103
  box-shadow: none;
562
- background-color: $skinMainSecondColor;
563
- color: #ffffff;
1104
+ background-color: var(--aa-panel-header);
1105
+ color: var(--aa-panel-header-text);
564
1106
  border: none;
565
- padding: 8px 15px;
1107
+ border-bottom: 1px solid var(--aa-border);
1108
+ padding: $skinPanelHeaderPaddingY 15px;
566
1109
  margin-top: 0;
567
- font-weight: 400;
1110
+ font-weight: 700; // match the tab label weight
568
1111
 
569
1112
  -webkit-border-top-left-radius: $skinBorderRadius;
570
1113
  -webkit-border-top-right-radius: $skinBorderRadius;
@@ -581,11 +1124,46 @@ form fieldset.inputs {
581
1124
  padding: 10px 0;
582
1125
  }
583
1126
  .attributes_table table th {
584
- color: #8494a8;
1127
+ color: var(--aa-label-text);
1128
+ // base AA gives attribute labels an emboss text-shadow, which reads as a
1129
+ // blurry halo. Drop it (the index table headers are already shadow-free).
1130
+ text-shadow: none;
1131
+ }
1132
+ // Index-table column headers: one color for both the sortable <a> links and the
1133
+ // plain headers (configurable via --aa-table-header-text). !important overrides
1134
+ // the dark-mode content-link recolor that would otherwise turn sortable headers
1135
+ // blue.
1136
+ table.index_table thead th,
1137
+ table.index_table thead th a {
1138
+ color: var(--aa-table-header-text) !important;
585
1139
  }
1140
+
1141
+ // Form section header: a <legend> interrupts the fieldset's top border, so the
1142
+ // header bar has no border around it (unlike a panel header). Float the legend
1143
+ // so it flows as a normal block and the fieldset border wraps around it.
1144
+ // padding-top: 0 so the header sits flush against the top border (the fieldset's
1145
+ // 10px top padding would otherwise leave a gap above the floated legend).
1146
+ form fieldset.inputs { padding-top: 0; }
1147
+ form fieldset.inputs > legend { float: left; width: 100%; }
1148
+ form fieldset.inputs > ol { clear: both; }
586
1149
  .comments form.active_admin_comment fieldset.inputs {
587
1150
  border: none
588
1151
  }
1152
+ // Comment meta column (author / date / "Delete Comment"). AA's base _comments.scss
1153
+ // caps it at 130px — too narrow for the timestamp (~99px) and the "Delete Comment"
1154
+ // link (~77px) to share a line, so the link wraps to its own row. Widen the column
1155
+ // so date + link sit together; keep the body/form offset (base = meta width + 20px)
1156
+ // in step.
1157
+ .comments .active_admin_comment {
1158
+ .active_admin_comment_meta { width: 200px; }
1159
+ .active_admin_comment_body { margin-left: 220px; }
1160
+ }
1161
+ .comments form.active_admin_comment { margin-left: 220px; }
1162
+ // AA base sets `.pagination_information b { color: #5c6469 }` globally (the
1163
+ // "Displaying 1 comment" line) — black-on-dark in dark mode. Re-point to the
1164
+ // themed text color so it reads in both modes.
1165
+ .pagination_information,
1166
+ .pagination_information b { color: var(--aa-text); }
589
1167
  .pagination {
590
1168
  span > a {
591
1169
  background-image: none;
@@ -625,20 +1203,26 @@ body.logged_out #content_wrapper #active_admin_content {
625
1203
  box-shadow: none;
626
1204
  @include rounded($skinBorderRadius);
627
1205
 
628
- background-color: #ffffff;
629
- border: 1px solid $skinBorderWindowColor;
630
- border-bottom: 2px solid $skinBorderWindowColor;
1206
+ // The login page uses #content_wrapper (not #wrapper), so the aa-content dark
1207
+ // rules don't reach it — point the box at the palette vars directly so it
1208
+ // follows light/dark like everything else.
1209
+ background-color: var(--aa-surface);
1210
+ color: var(--aa-text);
1211
+ border: 1px solid var(--aa-border);
631
1212
  #login {
632
1213
  h2 {
633
1214
  background-image: none;
634
1215
  box-shadow: none;
635
1216
  text-shadow: none;
636
1217
  box-shadow: none;
637
- background-color: $skinMainSecondColor;
638
- color: #ffffff;
1218
+ // Match the regular panel header: receding header color, header text color,
1219
+ // bottom outline and header height — all from the same vars.
1220
+ background-color: var(--aa-panel-header);
1221
+ color: var(--aa-panel-header-text);
639
1222
  border: none;
640
- padding: 8px 15px;
641
- font-weight: 400;
1223
+ border-bottom: 1px solid var(--aa-border);
1224
+ padding: $skinPanelHeaderPaddingY 15px;
1225
+ font-weight: 700; // match the tab label weight
642
1226
 
643
1227
  -webkit-border-top-left-radius: $skinBorderRadius;
644
1228
  -webkit-border-top-right-radius: $skinBorderRadius;
@@ -654,7 +1238,7 @@ body.logged_out #content_wrapper #active_admin_content {
654
1238
  ol {
655
1239
  li {
656
1240
  label {
657
- color: #8494a8;
1241
+ color: var(--aa-label-text);
658
1242
  }
659
1243
  }
660
1244
  }
@@ -663,8 +1247,22 @@ body.logged_out #content_wrapper #active_admin_content {
663
1247
  }
664
1248
  }
665
1249
  form input[type=text], form input[type=password], form input[type=email], form input[type=number], form input[type=url], form input[type=tel], form textarea {
666
- border: 1px solid #e6e9ee;
667
- background-color: #fdfefe;
1250
+ border: 1px solid var(--aa-input-border);
1251
+ background-color: var(--aa-input-bg);
1252
+ color: var(--aa-text);
1253
+ }
1254
+ // Flat form controls: strip the base ActiveAdmin emboss (white gradient fill,
1255
+ // white emboss text-shadow, inset light box-shadow) from text inputs, selects
1256
+ // and textareas in BOTH modes. Keeping this mode-agnostic means dark mode only
1257
+ // has to recolor the controls via the --aa-* vars (no extra dark-only resets).
1258
+ #active_admin_content {
1259
+ input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=file]):not([type=image]),
1260
+ textarea,
1261
+ select {
1262
+ background-image: none;
1263
+ text-shadow: none;
1264
+ box-shadow: none;
1265
+ }
668
1266
  }
669
1267
  form fieldset > ol > li fieldset ol li {
670
1268
  clear: both;
@@ -672,23 +1270,40 @@ form fieldset > ol > li fieldset ol li {
672
1270
  margin-top: 6px
673
1271
  }
674
1272
  }
1273
+ // Dropdown (batch-actions / title-bar / table-tools) menu items: keep them on the
1274
+ // surface text colour, not the global link blue that otherwise leaks in.
1275
+ .dropdown_menu_list li a { color: var(--aa-text) !important; }
1276
+ // The list itself and its row dividers were never repainted — ActiveAdmin
1277
+ // leaves them #FFF and #ebebeb, which in dark mode is a white panel behind
1278
+ // the items and a bright hairline between every one of them. Same selector
1279
+ // depth as the base rules, so source order decides and this comes later.
1280
+ .dropdown_menu .dropdown_menu_list_wrapper .dropdown_menu_list {
1281
+ background-color: var(--aa-elevated);
1282
+ border-color: var(--aa-border);
1283
+ }
1284
+ .dropdown_menu .dropdown_menu_list_wrapper .dropdown_menu_list li {
1285
+ border-bottom-color: var(--aa-border);
1286
+ }
1287
+
675
1288
  .ui-dialog {
676
1289
  background-image: none;
677
1290
  box-shadow: none;
678
1291
  text-shadow: none;
679
- box-shadow: none;
680
- background-color: #ffffff;
681
- border-bottom: 2px solid $skinBorderWindowColor;
1292
+ background-color: var(--aa-surface);
1293
+ color: var(--aa-text);
1294
+ border-bottom: 1px solid var(--aa-border);
682
1295
  .ui-dialog-titlebar {
683
1296
  background-image: none;
684
1297
  box-shadow: none;
685
1298
  text-shadow: none;
686
1299
  box-shadow: none;
687
- background-color: $skinMainSecondColor;
688
- color: #ffffff;
1300
+ background-color: var(--aa-panel-header);
1301
+ color: var(--aa-panel-header-text);
689
1302
  border: none;
690
- padding: 8px 15px;
691
- font-weight: 400;
1303
+ border-bottom: 1px solid var(--aa-border);
1304
+ padding: $skinPanelHeaderPaddingY 15px;
1305
+ font-weight: 700;
1306
+ font-size: 1em;
692
1307
 
693
1308
  -webkit-border-top-left-radius: $skinBorderRadius;
694
1309
  -webkit-border-top-right-radius: $skinBorderRadius;
@@ -697,6 +1312,15 @@ form fieldset > ol > li fieldset ol li {
697
1312
  border-top-left-radius: $skinBorderRadius;
698
1313
  border-top-right-radius: $skinBorderRadius;
699
1314
  }
1315
+ // jQuery-UI close button: drop the default grey gradient pill so it blends into
1316
+ // the accent titlebar.
1317
+ .ui-dialog-titlebar-close {
1318
+ background: transparent;
1319
+ background-image: none;
1320
+ border: none;
1321
+ box-shadow: none;
1322
+ color: var(--aa-panel-header-text);
1323
+ }
700
1324
  form {
701
1325
  ul {
702
1326
  li {
@@ -706,8 +1330,8 @@ form fieldset > ol > li fieldset ol li {
706
1330
  }
707
1331
  input[type="text"], input[type="number"], input[type="datepicker"], textarea {
708
1332
  padding: 8px 10px 7px;
709
- border: 1px solid #e6e9ee;
710
- background-color: #fdfefe;
1333
+ border: 1px solid var(--aa-input-border);
1334
+ background-color: var(--aa-input-bg);
711
1335
  outline: none;
712
1336
  @include rounded($skinBorderRadius);
713
1337
  width: 247px;
@@ -727,28 +1351,28 @@ form fieldset > ol > li fieldset ol li {
727
1351
  text-shadow: none;
728
1352
  box-shadow: none;
729
1353
  @include rounded($skinBorderRadius);
730
- background-color: $skinMainSecondColor;
1354
+ background-color: var(--aa-button);
731
1355
  border: none;
732
- color: #ffffff;
1356
+ color: var(--aa-button-text);
733
1357
  font-weight: 400;
734
1358
  padding: 10px 20px;
735
1359
  &:hover {
736
1360
  background-image: none!important;
737
- background-color: lighten( $skinMainSecondColor, 5% )!important;
1361
+ background-color: var(--aa-button-hover)!important;
738
1362
  }
739
1363
  }
740
1364
  button:last-child {
741
1365
  background-image: none;
742
1366
  box-shadow: none;
743
1367
  text-shadow: none;
744
- box-shadow: none;
745
- background-color: #ffffff;
1368
+ background-color: var(--aa-surface);
1369
+ color: var(--aa-text);
746
1370
  @include rounded($skinBorderRadius);
747
1371
  padding: 9px 20px 9px 20px;
748
- border-color: #E4E4E4;
1372
+ border: 1px solid var(--aa-border);
749
1373
  &:hover {
750
1374
  background-image: none!important;
751
- background-color: #F4F4F4!important;
1375
+ background-color: var(--aa-surface-hover)!important;
752
1376
  }
753
1377
  }
754
1378
  }
@@ -783,6 +1407,249 @@ input[type='radio'] {
783
1407
  }
784
1408
  }
785
1409
 
786
- .attributes_table table td .status_tag.empty {
787
- color: #ffffff;
1410
+ // Status tag: solid colour fill with a white label (high visibility), and an
1411
+ // outline a shade darker than the fill so the edge reads in the tag's own
1412
+ // colour. All colours are fixed, so a tag looks identical in light and dark.
1413
+ @mixin status-tag-colors($c) {
1414
+ background: $c;
1415
+ border-color: mix($c, #000000, 84%); // = darken($c) — outline in the fill colour
1416
+ // Black, not white: the five fills below are mid-tone, and white lands
1417
+ // between 2.35 and 3.78 against them — under the 4.5 WCAG AA asks for text
1418
+ // this small. Black gives at least 5.56 on every one of them. #1a1d21 was
1419
+ // the first thing tried and misses by 0.02 on the error red.
1420
+ color: #000000;
1421
+ }
1422
+
1423
+ //CONTENT (both modes)-----------------------------------------------------------//
1424
+ // Repaint ActiveAdmin's content onto the semantic palette. Included
1425
+ // unconditionally; the --aa-* custom properties carry the per-mode values (light
1426
+ // on :root, dark via aa-dark-palette), so this one rule set themes both modes.
1427
+ // Only the genuinely-dark overrides (see aa-dark-content, below) stay dark-scoped.
1428
+ @mixin aa-content {
1429
+ body.active_admin { color: var(--aa-text); }
1430
+
1431
+ #wrapper #active_admin_content {
1432
+ color: var(--aa-text);
1433
+
1434
+ // Status tags: solid colour fill + white label (high visibility), an
1435
+ // in-colour outline, rounded corners and a centered label. Colours are
1436
+ // mode-independent (same in light and dark). The base ActiveAdmin rule
1437
+ // supplies uppercase + letter-spacing + font-size; text-indent offsets the
1438
+ // trailing letter-spacing so the label is horizontally centered.
1439
+ .status_tag {
1440
+ display: inline-block;
1441
+ line-height: 1;
1442
+ // 4px (not 5px) horizontal padding so the added 1px border doesn't widen
1443
+ // the tag past ActiveAdmin's original borderless 5px-padded width. 1px less
1444
+ // bottom padding than top (like the stock AA tag) optically centers the
1445
+ // uppercase label, which otherwise rides high (no descenders to fill the
1446
+ // reserved space below the baseline).
1447
+ padding: 3px 4px 2px;
1448
+ text-indent: 0.15em;
1449
+ border-radius: 2px;
1450
+ border: 1px solid;
1451
+
1452
+ @include status-tag-colors(#8a909a); // neutral default (e.g. "No", protocol tags)
1453
+ &.ok, &.published, &.complete, &.completed, &.green, &.yes { @include status-tag-colors(#8daa92); }
1454
+ &.notice, &.blue { @include status-tag-colors(#6090db); }
1455
+ &.warn, &.warning, &.orange { @include status-tag-colors(#e29b20); }
1456
+ &.error, &.errored, &.red { @include status-tag-colors(#d45f53); }
1457
+ &.empty, &.unknown, &.none {
1458
+ background: none;
1459
+ border: 0; // placeholder/empty tags stay unobtrusive (no outline)
1460
+ color: var(--aa-text-muted);
1461
+ font-weight: bold;
1462
+ font-size: 0.8em;
1463
+ text-indent: 0;
1464
+ }
1465
+ }
1466
+
1467
+ // Generic content links take the link color. Exclude UI "chrome" links that
1468
+ // carry their own color — buttons, title-bar actions, scope/batch buttons
1469
+ // (.table_tools_button), jQuery-UI tab anchors (.ui-tabs-anchor) — and delete
1470
+ // links (handled by their own rule). Excluding them means those rules win on
1471
+ // their own, with no need for !important.
1472
+ // :where() wraps the exclusions so they filter without adding weight. Bare,
1473
+ // the seven :not()s are worth seven class-level points, and that beat every
1474
+ // component rule declared later — pagination links and the Clear Filters
1475
+ // button came out --aa-link instead of --aa-text.
1476
+ a:where(:not(.button):not(.action_item):not(.table_tools_button):not(.dropdown_menu_button):not(.ui-tabs-anchor):not(.delete_link):not([data-method="delete"])) { color: var(--aa-link); }
1477
+ a[data-method="delete"], a.delete_link { color: var(--aa-delete-link); }
1478
+
1479
+ // Pagination — non-current page chips use a light-grey bg in the theme
1480
+ .pagination span > a { background-color: var(--aa-surface-2); color: var(--aa-text); }
1481
+ // The hovered page link keeps its accent fill, so the label has to be
1482
+ // the colour that reads on the accent — not the link colour. The generic
1483
+ // link rule above scores (2,6,1) thanks to its six :not() clauses and
1484
+ // cannot be out-specified by anything sane here, which is why this needs
1485
+ // !important, like the accent fill one line over in the base pagination
1486
+ // block. Without it the digit renders at 1.00:1 on its own background.
1487
+ .pagination span > a:hover { color: $skinMenuPillTextColor !important; }
1488
+
1489
+ // Batch-actions / table-tools dropdown menu items are white by default
1490
+ .table_tools .dropdown_menu_list li a {
1491
+ background-color: var(--aa-surface);
1492
+ color: var(--aa-text);
1493
+ }
1494
+
1495
+ // NB: do NOT give .panel_contents its own background — it's a square-cornered
1496
+ // child that fills the panel, so a bg on it would paint over the panel's
1497
+ // rounded inner border edge and make the corners look square. The parent
1498
+ // .panel background shows through instead.
1499
+ .panel,
1500
+ .sidebar_section,
1501
+ .dashboard_section,
1502
+ fieldset.inputs {
1503
+ background: var(--aa-surface);
1504
+ border-color: var(--aa-border);
1505
+ color: var(--aa-text);
1506
+ }
1507
+ // .index_content wraps the index table, which already paints its own
1508
+ // (rounded) surface. Giving this square-cornered wrapper a surface bg makes
1509
+ // it show through the table's rounded corners as white squares, so leave it
1510
+ // transparent (same reasoning as .panel_contents above).
1511
+ .index_content { color: var(--aa-text); }
1512
+ // Blank-slate ("No records") container blends into the page background
1513
+ // rather than reading as a panel surface.
1514
+ .blank_slate_container {
1515
+ background: var(--aa-page-bg);
1516
+ color: var(--aa-text);
1517
+ }
1518
+ // Cancel / clear buttons are white in the theme (a light secondary button)
1519
+ fieldset.buttons li.cancel a, fieldset.actions li.cancel a,
1520
+ form.filter_form a.clear_filters_btn {
1521
+ background-color: var(--aa-surface-2);
1522
+ color: var(--aa-text);
1523
+ border-color: var(--aa-input-border);
1524
+ }
1525
+ // (Tab styling — colors, the no-bottom-outline inactive tabs, and the z-index
1526
+ // baseline — lives in the base #wrapper div.tabs block now, so it applies in
1527
+ // both light and dark via the --aa-* vars.)
1528
+
1529
+ table.index_table,
1530
+ .attributes_table table,
1531
+ table {
1532
+ background: var(--aa-surface);
1533
+ color: var(--aa-text);
1534
+ border-color: var(--aa-border);
1535
+ }
1536
+ // Column headers (index AND plain content tables, e.g. the CDR "Attempts"
1537
+ // table) get a distinct header-row shade so they don't blend with the rows.
1538
+ // Plain table headers are otherwise transparent and read like an odd row.
1539
+ table thead th {
1540
+ background: var(--aa-surface-2);
1541
+ }
1542
+ table.index_table thead th { background: var(--aa-table-header); }
1543
+ table.index_table thead th,
1544
+ .attributes_table th {
1545
+ border-color: var(--aa-border);
1546
+ }
1547
+ table th, table td,
1548
+ table.index_table td,
1549
+ .attributes_table td {
1550
+ border-color: var(--aa-border);
1551
+ color: var(--aa-text);
1552
+ }
1553
+ // Attribute-table labels (the field-name column) use the muted label color;
1554
+ // the more specific selector wins over the generic `table th` rule above.
1555
+ .attributes_table th { color: var(--aa-label-text); }
1556
+ table.index_table tbody tr:nth-child(even) > td,
1557
+ table.index_table tbody tr.even > td { background: var(--aa-surface-2); }
1558
+ table.index_table tbody tr:hover > td { background: var(--aa-surface-hover); }
1559
+ // Checked rows: the zebra and hover rules above outrank ActiveAdmin's own
1560
+ // `tr.selected td`, so without this a ticked row looks exactly like an
1561
+ // unticked one. The :hover variant keeps the selection visible while the
1562
+ // pointer is over the row.
1563
+ table.index_table tbody tr.selected > td,
1564
+ table.index_table tbody tr.selected:hover > td { background: var(--aa-selected); }
1565
+ // Plain content tables (e.g. the CDR show "Attempts" table) are striped by the
1566
+ // base CSS with light fills; map the odd/even rows onto the dark surfaces too.
1567
+ table tbody tr.odd > td, table tbody tr.odd > th { background-color: var(--aa-surface); }
1568
+ table tbody tr.even > td, table tbody tr.even > th { background-color: var(--aa-surface-2); }
1569
+ // Plain table headers carry a white emboss text-shadow (subtle on a light bg,
1570
+ // a blurry halo on dark). Drop it — index tables are already shadow-free.
1571
+ table thead th, table thead td { text-shadow: none; }
1572
+ // Footer / totals row (theme gives it a light grey bg, which on the dark
1573
+ // panel reads as a light rectangle poking against the rounded panel border).
1574
+ table.index_table tfoot tr,
1575
+ table.index_table tfoot td,
1576
+ table.index_table tfoot th {
1577
+ background: var(--aa-surface-2);
1578
+ color: var(--aa-text);
1579
+ }
1580
+
1581
+ // Index footer (per-page selector, pagination, "displaying…" info, download
1582
+ // links): lay them out in one left-packed, vertically-centred row. The gem
1583
+ // floats them, so they sat top-aligned and, having different heights, looked
1584
+ // misaligned. A slightly larger font than the gem default (0.85em) too.
1585
+ #index_footer {
1586
+ text-align: left;
1587
+ font-size: 0.95em;
1588
+ .pagination_per_page,
1589
+ .pagination,
1590
+ .pagination_information,
1591
+ .download_links {
1592
+ float: none;
1593
+ display: inline-block;
1594
+ vertical-align: middle;
1595
+ margin: 0 8px 0 0;
1596
+ }
1597
+ }
1598
+
1599
+ // Forms & inputs
1600
+ // :focus is nested rather than written out alongside: the six :not()s count
1601
+ // as six class-level points, so a sibling `input:focus` (one) loses to the
1602
+ // resting border every time and the focus indicator never appears at all.
1603
+ input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=file]):not([type=image]),
1604
+ textarea,
1605
+ select {
1606
+ background-color: var(--aa-input-bg);
1607
+ border-color: var(--aa-input-border);
1608
+ color: var(--aa-text);
1609
+
1610
+ &:focus { border-color: var(--aa-accent); }
1611
+ }
1612
+ input::placeholder, textarea::placeholder { color: var(--aa-text-muted); }
1613
+ option, optgroup { background-color: var(--aa-input-bg); color: var(--aa-text); }
1614
+ label, fieldset > legend, .fieldset > legend { color: var(--aa-label-text); }
1615
+ .inline-hints, .inline_hints, p.inline-hints { color: var(--aa-text-muted); }
1616
+ }
1617
+
1618
+ // jQuery UI datepicker (appended to <body>, so styled at the mixin level)
1619
+ // #ui-datepicker-div, not .ui-datepicker.ui-widget: both ActiveAdmin and the
1620
+ // block higher up this file address it by id, and an id beats any number of
1621
+ // classes — the class-only form here never applied, leaving the calendar on
1622
+ // its light fills with #666 day numbers on the dark surface (2.61:1).
1623
+ #ui-datepicker-div.ui-datepicker {
1624
+ background: var(--aa-surface);
1625
+ border-color: var(--aa-border);
1626
+ color: var(--aa-text);
1627
+ // The header keeps the accent fill and its white label in both modes — the
1628
+ // theme paints it that way above, and it reads on either background. Only
1629
+ // the calendar body needs repointing; a blanket `a` here would turn the
1630
+ // header's month arrows and title dark on the accent.
1631
+ border-color: var(--aa-border);
1632
+ table.ui-datepicker-calendar { background-color: var(--aa-surface); }
1633
+ table.ui-datepicker-calendar thead th { background-color: var(--aa-surface-2); color: var(--aa-text-muted); }
1634
+ table.ui-datepicker-calendar tbody td a { color: var(--aa-text); }
1635
+ table.ui-datepicker-calendar tbody td span { color: var(--aa-text-muted); }
1636
+ .ui-state-hover, .ui-state-active { background: var(--aa-surface-hover); }
1637
+ }
1638
+ }
1639
+
1640
+ // DARK-ONLY content overrides — genuinely dark-specific values with no light
1641
+ // equivalent (or that would be wrong on a light surface), so these stay scoped
1642
+ // to dark mode while everything in aa-content is mode-agnostic.
1643
+ @mixin aa-dark-content {
1644
+ // (Currently empty — status tags now use mode-independent soft colours in
1645
+ // aa-content, so no dark-only override is needed. Kept for future dark-only
1646
+ // content rules.)
1647
+ }
1648
+
1649
+ // Content styling applies in BOTH modes (aa-dark-palette supplies the per-mode
1650
+ // --aa-* values); only the genuinely-dark overrides are dark-scoped.
1651
+ @include aa-content;
1652
+ @media (prefers-color-scheme: dark) {
1653
+ html:not([data-theme="light"]) { @include aa-dark-content; }
788
1654
  }
1655
+ html[data-theme="dark"] { @include aa-dark-content; }