ultimate-jekyll-manager 1.4.3 → 1.5.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/CLAUDE-ATTRIBUTION.md +215 -0
  3. package/CLAUDE.md +7 -6
  4. package/README.md +1 -0
  5. package/dist/assets/css/pages/test/libraries/layers/index.scss +28 -0
  6. package/dist/assets/js/modules/redirect.js +5 -4
  7. package/dist/assets/js/pages/download/index.js +1 -1
  8. package/dist/assets/js/pages/feedback/index.js +7 -1
  9. package/dist/assets/js/pages/test/libraries/layers/index.js +11 -0
  10. package/dist/assets/themes/_template/README.md +50 -0
  11. package/dist/assets/themes/_template/_config.scss +60 -0
  12. package/dist/assets/themes/_template/_theme.js +13 -4
  13. package/dist/assets/themes/_template/_theme.scss +16 -4
  14. package/dist/assets/themes/_template/css/base/_root.scss +19 -0
  15. package/dist/assets/themes/_template/css/components/_components.scss +23 -0
  16. package/dist/assets/themes/classy/README.md +18 -6
  17. package/dist/assets/themes/neobrutalism/README.md +98 -0
  18. package/dist/assets/themes/neobrutalism/_config.scss +139 -0
  19. package/dist/assets/themes/neobrutalism/_theme.js +27 -0
  20. package/dist/assets/themes/neobrutalism/_theme.scss +33 -0
  21. package/dist/assets/themes/neobrutalism/css/base/_mixins.scss +46 -0
  22. package/dist/assets/themes/neobrutalism/css/base/_root.scss +80 -0
  23. package/dist/assets/themes/neobrutalism/css/base/_typography.scss +77 -0
  24. package/dist/assets/themes/neobrutalism/css/base/_utilities.scss +25 -0
  25. package/dist/assets/themes/neobrutalism/css/components/_buttons.scss +148 -0
  26. package/dist/assets/themes/neobrutalism/css/components/_cards.scss +69 -0
  27. package/dist/assets/themes/neobrutalism/css/components/_forms.scss +88 -0
  28. package/dist/assets/themes/neobrutalism/css/components/_infinite-scroll.scss +94 -0
  29. package/dist/assets/themes/neobrutalism/css/layout/_general.scss +200 -0
  30. package/dist/assets/themes/neobrutalism/css/layout/_navigation.scss +153 -0
  31. package/dist/assets/themes/neobrutalism/js/initialize-tooltips.js +20 -0
  32. package/dist/assets/themes/neobrutalism/js/navbar-scroll.js +29 -0
  33. package/dist/assets/themes/neobrutalism/pages/index.scss +227 -0
  34. package/dist/assets/themes/neobrutalism/pages/pricing/index.scss +267 -0
  35. package/dist/assets/themes/neobrutalism/pages/test/libraries/layers/index.js +9 -0
  36. package/dist/assets/themes/neobrutalism/pages/test/libraries/layers/index.scss +7 -0
  37. package/dist/build.js +2 -5
  38. package/dist/commands/install.js +1 -1
  39. package/dist/commands/setup.js +41 -0
  40. package/dist/defaults/CLAUDE.md +5 -1
  41. package/dist/defaults/dist/_includes/core/head.html +17 -0
  42. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/footer.html +4 -4
  43. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +2 -0
  44. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/feedback.html +7 -3
  45. package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/core/base.html +31 -0
  46. package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/index.html +345 -0
  47. package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/pricing.html +483 -0
  48. package/dist/defaults/dist/pages/test/libraries/layers.html +57 -0
  49. package/dist/defaults/src/_config.yml +2 -0
  50. package/dist/defaults/test/_init.js +10 -0
  51. package/dist/gulp/tasks/defaults.js +8 -0
  52. package/dist/gulp/tasks/sass.js +43 -2
  53. package/dist/gulp/tasks/translation.js +11 -0
  54. package/dist/gulp/tasks/utils/manage-test-layers.js +97 -0
  55. package/dist/index.js +30 -4
  56. package/dist/test/runner.js +62 -0
  57. package/dist/test/suites/build/manager.test.js +11 -4
  58. package/dist/test/suites/build/mode-helpers.test.js +54 -2
  59. package/dist/utils/mode-helpers.js +65 -40
  60. package/docs/assets.md +6 -1
  61. package/docs/environment-detection.md +85 -0
  62. package/docs/test-framework.md +48 -3
  63. package/docs/themes.md +451 -0
  64. package/package.json +2 -1
  65. package/docs/cross-context-helpers.md +0 -75
@@ -0,0 +1,98 @@
1
+ # Neobrutalism Theme
2
+
3
+ A bold, high-contrast UJM theme built on the neobrutalist design language:
4
+ **pure-ink borders, hard offset shadows (no blur), zero border-radius, chunky
5
+ grotesk display type, and flat saturated color blocks.** Buttons and cards
6
+ "press" into the page on interaction. Full light + dark mode support.
7
+
8
+ > See [`docs/themes.md`](../../../../docs/themes.md) for how the theme system
9
+ > works and how to author your own theme (inside UJM or in a consumer project).
10
+
11
+ ## Use it
12
+
13
+ In your consuming project's `src/_config.yml`:
14
+
15
+ ```yaml
16
+ theme:
17
+ id: "neobrutalism"
18
+ appearance: "light" # or "dark" / "system"
19
+ ```
20
+
21
+ That's it — every layout, nav, footer, and page is inherited from the shared
22
+ defaults (via the Classy layout fallback) and restyled in neobrutalist form.
23
+
24
+ ## Customize it (without editing the theme)
25
+
26
+ All design tokens are `!default` variables. Override them **before** the theme
27
+ is imported — in your project's `src/assets/css/main.scss`, set the variables,
28
+ then `@use 'ultimate-jekyll-manager' as *;`:
29
+
30
+ ```scss
31
+ // Change the accent + structure, then import the framework (which loads the theme)
32
+ $primary: #FF5C00; // your brand color
33
+ $nb-border-width: 4px; // chunkier borders
34
+ $nb-shadow-offset: 7px; // deeper hard shadow
35
+ $nb-accent-yellow: #D4FF00; // swap the signature highlight
36
+
37
+ @use 'ultimate-jekyll-manager' as *;
38
+ ```
39
+
40
+ ### Key tokens (see `_config.scss` for the full list)
41
+
42
+ | Token | Purpose | Default |
43
+ |---|---|---|
44
+ | `$primary` … `$danger` | Bootstrap semantic colors | electric blue, hot pink, etc. |
45
+ | `$nb-ink` / `$nb-paper` | Border/shadow color + page surface (light) | `#111` / `#FFFEF2` |
46
+ | `$nb-ink-dark` / `$nb-paper-dark` | Same, dark mode | `#F5F5F5` / `#16161A` |
47
+ | `$nb-border-width` | Standard border thickness | `3px` |
48
+ | `$nb-shadow-offset` | Hard shadow distance | `5px` |
49
+ | `$nb-accent-*` | Color-block palette | blue/pink/yellow/green/purple/orange |
50
+ | `$nb-font-display` | Heading font | `Archivo` |
51
+ | `$font-family-sans-serif` | Body font | `Space Grotesk` |
52
+
53
+ > Fonts are loaded via the theme's `head` block in the base layout. If you
54
+ > change the font tokens, update the Google Fonts `<link>` accordingly (in your
55
+ > page/layout `theme.head.content`, or by overriding the base layout).
56
+
57
+ ## No theme-prefixed classes
58
+
59
+ This theme deliberately uses **NO `nb-` prefixed classes in markup** — so the same
60
+ HTML is swappable across themes (change `theme.id`, done). It styles:
61
+
62
+ - **Standard Bootstrap classes** wherever they fit: `.card` (the canonical container —
63
+ gets the ink frame + hard shadow), `.btn` / `.btn-primary` / `.btn-warning` (yellow
64
+ accent), `.text-bg-{primary,secondary,success,warning,…}` (the color-block fills),
65
+ `.border`, `.shadow`, `.accordion`, `.badge`.
66
+ - **Universal semantic layout classes** for structures with no Bootstrap equivalent:
67
+ `.section-hero`, `.hero-title`, `.action-block`, `.logo-strip`, `.showcase-row`,
68
+ `.step-card`, `.stat-block`, `.cta-panel`, `.pricing-plan`, `.billing-toggle`,
69
+ `.kicker`, `.highlight`. Any theme can style these same names. See
70
+ [docs/themes.md → Universal layout classes](../../../../docs/themes.md).
71
+
72
+ The `nb-` prefix survives ONLY on SCSS internals (the `$nb-*` config tokens, `--nb-*`
73
+ CSS variables, and `@mixin nb-border/nb-shadow/nb-press`) — these never appear in HTML.
74
+
75
+ ## Structure
76
+
77
+ ```
78
+ neobrutalism/
79
+ ├── _config.scss ← all customizable tokens (!default) + Bootstrap forward
80
+ ├── _theme.scss ← entry point (config → mixins → root → base → layout → components → bootstrap overrides)
81
+ ├── _theme.js ← JS entry (Bootstrap UMD + behaviors on DOM ready)
82
+ ├── css/
83
+ │ ├── base/
84
+ │ │ ├── _mixins.scss ← nb-border / nb-shadow / nb-press (the SSOT for the look)
85
+ │ │ ├── _root.scss ← SCSS → CSS-variable bridge (light/dark)
86
+ │ │ ├── _typography.scss
87
+ │ │ └── _utilities.scss
88
+ │ ├── layout/
89
+ │ │ ├── _general.scss ← sections, hero, footer, gradient/accent overrides
90
+ │ │ └── _navigation.scss
91
+ │ └── components/
92
+ │ ├── _buttons.scss
93
+ │ ├── _cards.scss
94
+ │ └── _forms.scss
95
+ └── js/
96
+ ├── navbar-scroll.js
97
+ └── initialize-tooltips.js
98
+ ```
@@ -0,0 +1,139 @@
1
+ // Neobrutalism Theme Configuration
2
+ // ALL customizable variables are defined here with !default.
3
+ // Consuming projects override any of these BEFORE the theme is imported.
4
+ //
5
+ // Design language: raw, high-contrast color blocks; pure-black hard borders;
6
+ // hard offset shadows (no blur); zero border-radius; chunky grotesk type.
7
+ // This is NOT a recolored Classy — the shadow/border/press system is the identity.
8
+
9
+ // ============================================
10
+ // Bootstrap Color Overrides
11
+ // ============================================
12
+ // Loud, saturated, high-contrast. These map onto Bootstrap's semantic colors.
13
+ $primary: #2563EB !default; // electric blue
14
+ $secondary: #EC4899 !default; // hot pink
15
+ $success: #16A34A !default; // grass green
16
+ $info: #06B6D4 !default; // cyan
17
+ $warning: #FACC15 !default; // acid yellow
18
+ $danger: #EF4444 !default; // red
19
+ $light: #FFFEF2 !default; // paper white (warm off-white)
20
+ $dark: #111111 !default; // near-black
21
+
22
+ // ============================================
23
+ // Ink & Paper (the structural neutrals)
24
+ // ============================================
25
+ // "Ink" = the universal border/shadow color. "Paper" = the page surface.
26
+ $nb-ink: #111111 !default; // borders + hard shadows (light mode)
27
+ $nb-paper: #FFFEF2 !default; // body background (light mode)
28
+ $nb-surface: #FFFFFF !default; // cards / elevated surfaces (light mode)
29
+ $nb-surface-alt: #F4F1E4 !default; // alt sections / wells (light mode)
30
+
31
+ // Dark mode counterparts
32
+ $nb-ink-dark: #F5F5F5 !default; // borders + shadows become near-white
33
+ $nb-paper-dark: #16161A !default; // body background (dark mode)
34
+ $nb-surface-dark: #1F1F25 !default; // cards (dark mode)
35
+ $nb-surface-alt-dark: #25252D !default; // alt sections (dark mode)
36
+
37
+ // ============================================
38
+ // Accent Palette (for color-block sections, tags, highlights)
39
+ // ============================================
40
+ // Used directly as section backgrounds and decorative blocks.
41
+ $nb-accent-blue: #2563EB !default;
42
+ $nb-accent-pink: #EC4899 !default;
43
+ $nb-accent-yellow: #FACC15 !default;
44
+ $nb-accent-green: #16A34A !default;
45
+ $nb-accent-purple: #8B5CF6 !default;
46
+ $nb-accent-orange: #FB923C !default;
47
+
48
+ // ============================================
49
+ // Borders — the defining structural element
50
+ // ============================================
51
+ $nb-border-width: 3px !default; // standard border thickness
52
+ $nb-border-width-lg: 4px !default; // emphasis (hero buttons, feature cards)
53
+ $nb-border-width-sm: 2px !default; // small controls (inputs, tags)
54
+ $nb-border-color: $nb-ink !default; // remapped to ink-dark in dark mode via _root
55
+ $nb-border: $nb-border-width solid $nb-border-color !default;
56
+
57
+ // Zero radius everywhere — this is the neobrutalist signature.
58
+ $border-radius: 0 !default;
59
+ $border-radius-sm: 0 !default;
60
+ $border-radius-lg: 0 !default;
61
+ $border-radius-xl: 0 !default;
62
+ $border-radius-2xl: 0 !default;
63
+ $border-radius-pill: 0 !default;
64
+
65
+ // ============================================
66
+ // Hard Offset Shadows — the second defining element
67
+ // ============================================
68
+ // No blur, no spread — a solid block offset down-right in ink color.
69
+ $nb-shadow-offset: 5px !default; // default offset distance
70
+ $nb-shadow-offset-sm: 3px !default;
71
+ $nb-shadow-offset-lg: 8px !default;
72
+ $nb-shadow-color: $nb-ink !default; // remapped in dark mode via _root
73
+
74
+ $nb-shadow-sm: $nb-shadow-offset-sm $nb-shadow-offset-sm 0 $nb-shadow-color !default;
75
+ $nb-shadow: $nb-shadow-offset $nb-shadow-offset 0 $nb-shadow-color !default;
76
+ $nb-shadow-lg: $nb-shadow-offset-lg $nb-shadow-offset-lg 0 $nb-shadow-color !default;
77
+
78
+ // ============================================
79
+ // Typography
80
+ // ============================================
81
+ // Chunky geometric grotesk for display; clean grotesk for body.
82
+ $font-family-sans-serif: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !default;
83
+ $nb-font-display: 'Archivo', 'Space Grotesk', sans-serif !default;
84
+ $nb-font-mono: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace !default;
85
+
86
+ $headings-font-weight: 800 !default;
87
+ $nb-heading-letter-spacing: -0.02em !default;
88
+ $font-weight-bold: 700 !default;
89
+
90
+ // ============================================
91
+ // Motion — snappy, mechanical, no easing softness
92
+ // ============================================
93
+ // Neobrutalism favors instant/linear motion over smooth cubic-beziers.
94
+ $nb-transition-fast: all 0.08s ease-out !default;
95
+ $nb-transition: all 0.12s ease-out !default;
96
+
97
+ // ============================================
98
+ // Component Sizing
99
+ // ============================================
100
+ // Avatar sizes map (matches Classy so shared layouts/includes render correctly)
101
+ $avatar-sizes: (
102
+ null: 3rem,
103
+ 2xs: 0.5rem,
104
+ xs: 1.5rem,
105
+ sm: 2rem,
106
+ md: 2.5rem,
107
+ lg: 3.5rem,
108
+ xl: 5rem,
109
+ 2xl: 7.5rem,
110
+ 3xl: 10rem,
111
+ 4xl: 12.5rem,
112
+ 5xl: 15rem
113
+ ) !default;
114
+
115
+ // ============================================
116
+ // Forward Bootstrap with our configuration
117
+ // ============================================
118
+ @forward '../bootstrap/scss/bootstrap.scss' with (
119
+ $primary: $primary,
120
+ $secondary: $secondary,
121
+ $success: $success,
122
+ $info: $info,
123
+ $warning: $warning,
124
+ $danger: $danger,
125
+ $light: $light,
126
+ $dark: $dark,
127
+ $font-family-sans-serif: $font-family-sans-serif,
128
+ $headings-font-weight: $headings-font-weight,
129
+ $font-weight-bold: $font-weight-bold,
130
+ $border-radius: $border-radius,
131
+ $border-radius-sm: $border-radius-sm,
132
+ $border-radius-lg: $border-radius-lg,
133
+ // Neobrutalism uses solid borders everywhere, so Bootstrap's default
134
+ // border width is bumped and box-shadow softness is disabled.
135
+ $border-width: $nb-border-width,
136
+ $enable-rounded: false,
137
+ $enable-shadows: false,
138
+ $enable-negative-margins: true
139
+ );
@@ -0,0 +1,27 @@
1
+ // Neobrutalism Theme — JS entry point
2
+ // Loaded at runtime via webpack's __theme__ alias (import('__theme__/_theme.js')).
3
+ // Exposes Bootstrap globally and wires up theme behaviors on DOM ready.
4
+ import bootstrap from '__main_assets__/themes/bootstrap/js/index.umd.js';
5
+ import { ready as domReady } from 'web-manager/modules/dom.js';
6
+
7
+ // Make Bootstrap available globally (used by UJM utilities + components)
8
+ window.bootstrap = bootstrap;
9
+
10
+ /* @dev-only:start */
11
+ {
12
+ console.log('Neobrutalism theme loaded successfully (assets/themes/neobrutalism/_theme.js)');
13
+ }
14
+ /* @dev-only:end */
15
+
16
+ // Theme behaviors
17
+ import setupNavbarScroll from './js/navbar-scroll.js';
18
+ import initializeTooltips from './js/initialize-tooltips.js';
19
+
20
+ // Initialize when DOM is ready
21
+ domReady().then(() => {
22
+ // Neobrutalism behaviors
23
+ setupNavbarScroll();
24
+
25
+ // Generic Bootstrap initializations
26
+ initializeTooltips();
27
+ });
@@ -0,0 +1,33 @@
1
+ // Neobrutalism Theme — SCSS entry point
2
+ // Forwards config (so consuming projects can override vars), loads Bootstrap via
3
+ // config, then layers the neobrutalist system on top. Import order matters:
4
+ // config → mixins → root vars → base → layout → components → bootstrap overrides.
5
+
6
+ // Forward theme configuration (allows consuming project to override)
7
+ @forward 'config';
8
+ @use 'config' as *;
9
+
10
+ // Mixins must be available to every partial below.
11
+ // @import (not @use) so the mixins land in the global scope the @imports share.
12
+ @import 'css/base/mixins';
13
+
14
+ // CSS custom properties (light/dark bridge)
15
+ @import 'css/base/root';
16
+
17
+ // Base styles
18
+ @import 'css/base/typography';
19
+ @import 'css/base/utilities';
20
+
21
+ // Layout styles
22
+ @import 'css/layout/general';
23
+ @import 'css/layout/navigation';
24
+
25
+ // Component styles
26
+ @import 'css/components/buttons';
27
+ @import 'css/components/cards';
28
+ @import 'css/components/forms';
29
+ @import 'css/components/infinite-scroll';
30
+
31
+ // Universal Bootstrap overrides (shared across all UJ themes).
32
+ // Must come AFTER Bootstrap is loaded via config to use @extend.
33
+ @import '../bootstrap/overrides';
@@ -0,0 +1,46 @@
1
+ // Neobrutalism Theme — Mixins
2
+ // The shared building blocks of the neobrutalist look. Components @include these
3
+ // so the border/shadow/press system lives in ONE place (SSOT) rather than being
4
+ // copy-pasted across buttons, cards, inputs, etc.
5
+
6
+ // Hard border in the current ink color.
7
+ @mixin nb-border($width: var(--nb-border-width)) {
8
+ border: $width solid var(--nb-border-color);
9
+ }
10
+
11
+ // Hard offset shadow (no blur). $size: sm | md | lg.
12
+ @mixin nb-shadow($size: md) {
13
+ @if $size == sm {
14
+ box-shadow: var(--nb-shadow-sm);
15
+ } @else if $size == lg {
16
+ box-shadow: var(--nb-shadow-lg);
17
+ } @else {
18
+ box-shadow: var(--nb-shadow);
19
+ }
20
+ }
21
+
22
+ // The signature interaction: the element sits on a hard offset shadow, then
23
+ // "presses" toward the page on hover/active. THE INVARIANT: the element's
24
+ // translate distance + the shrunk shadow offset must always equal the RESTING
25
+ // shadow offset, so the bottom-right edge stays perfectly pinned (the face and
26
+ // shadow line up exactly when the press completes — no drift).
27
+ //
28
+ // $rest = the element's resting shadow offset. Pass the SAME size you gave
29
+ // nb-shadow() (default 5px = md; pass $nb-shadow-offset-lg for lg-shadow elements).
30
+ @mixin nb-press($rest: $nb-shadow-offset) {
31
+ transition: $nb-transition;
32
+
33
+ // Hover: press ~40% of the way in. shadow = rest - translate (stays pinned).
34
+ &:hover {
35
+ $hover-move: round($rest * 0.4);
36
+ $hover-shadow: $rest - $hover-move;
37
+ transform: translate($hover-move, $hover-move);
38
+ box-shadow: #{$hover-shadow} #{$hover-shadow} 0 var(--nb-shadow-color);
39
+ }
40
+
41
+ // Active: press fully in. translate == rest, shadow collapses to 0 → flush.
42
+ &:active {
43
+ transform: translate($rest, $rest);
44
+ box-shadow: 0 0 0 var(--nb-shadow-color);
45
+ }
46
+ }
@@ -0,0 +1,80 @@
1
+ // Neobrutalism Theme — CSS Custom Properties
2
+ // Bridges SCSS config into runtime CSS variables so light/dark mode switching
3
+ // works without recompilation. Components read these var(--nb-*) tokens, never
4
+ // the raw SCSS values, so dark mode is a single block of overrides.
5
+
6
+ // ============================================
7
+ // Light Mode (default)
8
+ // ============================================
9
+ :root,
10
+ [data-bs-theme="light"] {
11
+ // Structural tokens
12
+ --nb-ink: #{$nb-ink};
13
+ --nb-paper: #{$nb-paper};
14
+ --nb-surface: #{$nb-surface};
15
+ --nb-surface-alt: #{$nb-surface-alt};
16
+
17
+ // Height of the fixed navbar — the first section adds this to its top padding
18
+ // so content clears the overlapping nav (see _general.scss "Section rhythm").
19
+ --nb-navbar-height: 4.5rem;
20
+
21
+ // Border + shadow color follow the ink
22
+ --nb-border-color: var(--nb-ink);
23
+ --nb-shadow-color: var(--nb-ink);
24
+
25
+ // Border + shadow recipes (used by components)
26
+ --nb-border-width: #{$nb-border-width};
27
+ --nb-border: #{$nb-border-width} solid var(--nb-border-color);
28
+ --nb-shadow-sm: #{$nb-shadow-offset-sm} #{$nb-shadow-offset-sm} 0 var(--nb-shadow-color);
29
+ --nb-shadow: #{$nb-shadow-offset} #{$nb-shadow-offset} 0 var(--nb-shadow-color);
30
+ --nb-shadow-lg: #{$nb-shadow-offset-lg} #{$nb-shadow-offset-lg} 0 var(--nb-shadow-color);
31
+
32
+ // Accent palette (for color-block sections)
33
+ --nb-accent-blue: #{$nb-accent-blue};
34
+ --nb-accent-pink: #{$nb-accent-pink};
35
+ --nb-accent-yellow: #{$nb-accent-yellow};
36
+ --nb-accent-green: #{$nb-accent-green};
37
+ --nb-accent-purple: #{$nb-accent-purple};
38
+ --nb-accent-orange: #{$nb-accent-orange};
39
+
40
+ // INTERACTIVE accent — the single token every hover/active fill points at
41
+ // (nav links, footer links, dropdown items, body links, mobile toggler). It
42
+ // tracks the rendered primary blue (--bs-primary), NOT the yellow signature
43
+ // accent. Retune all interactive states from this one line. Yellow stays
44
+ // reserved for static signature blocks (kicker, highlight, hero, badges).
45
+ --nb-accent-interactive: var(--bs-primary);
46
+ --nb-accent-interactive-ink: #ffffff; // readable text on the interactive fill
47
+
48
+ // Map onto Bootstrap surfaces
49
+ --bs-body-bg: #{$nb-paper};
50
+ --bs-body-bg-rgb: #{red($nb-paper)}, #{green($nb-paper)}, #{blue($nb-paper)};
51
+ --bs-body-color: #{$nb-ink};
52
+ --bs-secondary-bg: #{$nb-surface};
53
+ --bs-tertiary-bg: #{$nb-surface-alt};
54
+ --bs-border-color: var(--nb-ink);
55
+ --bs-card-bg: #{$nb-surface};
56
+ --bs-emphasis-color: #{$nb-ink};
57
+ }
58
+
59
+ // ============================================
60
+ // Dark Mode
61
+ // ============================================
62
+ // Ink flips to near-white: borders and hard shadows become light on dark paper.
63
+ [data-bs-theme="dark"] {
64
+ --nb-ink: #{$nb-ink-dark};
65
+ --nb-paper: #{$nb-paper-dark};
66
+ --nb-surface: #{$nb-surface-dark};
67
+ --nb-surface-alt: #{$nb-surface-alt-dark};
68
+
69
+ --nb-border-color: var(--nb-ink);
70
+ --nb-shadow-color: var(--nb-ink);
71
+
72
+ --bs-body-bg: #{$nb-paper-dark};
73
+ --bs-body-bg-rgb: #{red($nb-paper-dark)}, #{green($nb-paper-dark)}, #{blue($nb-paper-dark)};
74
+ --bs-body-color: #{$nb-ink-dark};
75
+ --bs-secondary-bg: #{$nb-surface-dark};
76
+ --bs-tertiary-bg: #{$nb-surface-alt-dark};
77
+ --bs-border-color: var(--nb-ink);
78
+ --bs-card-bg: #{$nb-surface-dark};
79
+ --bs-emphasis-color: #{$nb-ink-dark};
80
+ }
@@ -0,0 +1,77 @@
1
+ // Neobrutalism Theme — Typography
2
+ // Chunky, confident, tightly-tracked headings; clean grotesk body.
3
+ // Fonts are loaded via the theme's `head` block in base.html (Google Fonts),
4
+ // NOT @import-ed here, to avoid render-blocking duplicate loads.
5
+
6
+ body {
7
+ font-family: $font-family-sans-serif;
8
+ font-weight: 400;
9
+ -webkit-font-smoothing: antialiased;
10
+ }
11
+
12
+ h1, h2, h3, h4, h5, h6,
13
+ .h1, .h2, .h3, .h4, .h5, .h6 {
14
+ font-family: $nb-font-display;
15
+ font-weight: $headings-font-weight;
16
+ letter-spacing: $nb-heading-letter-spacing;
17
+ line-height: 1.05;
18
+ text-wrap: balance;
19
+ }
20
+
21
+ // Display headings get extra weight + tighter tracking
22
+ .display-1, .display-2, .display-3, .display-4, .display-5, .display-6 {
23
+ font-family: $nb-font-display;
24
+ font-weight: 900;
25
+ letter-spacing: -0.03em;
26
+ line-height: 0.98;
27
+ }
28
+
29
+ // Monospace accents (kickers, labels, code-ish tags)
30
+ .font-mono,
31
+ code, kbd, samp, pre {
32
+ font-family: $nb-font-mono;
33
+ }
34
+
35
+ // Eyebrow / kicker label — universal "section kicker" above headlines.
36
+ .kicker {
37
+ display: inline-block;
38
+ font-family: $nb-font-mono;
39
+ font-weight: 700;
40
+ font-size: 0.8rem;
41
+ text-transform: uppercase;
42
+ letter-spacing: 0.08em;
43
+ padding: 0.35rem 0.65rem;
44
+ background: var(--nb-accent-yellow);
45
+ color: #111111;
46
+ @include nb-border($nb-border-width-sm);
47
+
48
+ // On a dark/ink panel (e.g. the CTA), keep the accent block readable.
49
+ &--invert { background: var(--nb-accent-yellow); color: #111111; }
50
+ }
51
+
52
+ // Highlighted inline text — marker-style background swipe.
53
+ .highlight {
54
+ background: var(--nb-accent-yellow);
55
+ color: #111111;
56
+ padding: 0 0.15em;
57
+ box-decoration-break: clone;
58
+ -webkit-box-decoration-break: clone;
59
+ }
60
+
61
+ // Links: bold, underlined, no fade — they look clickable and stay readable in both
62
+ // modes. Hover shifts to the interactive accent (blue), matching every other hover
63
+ // in the theme. Buttons/nav/dropdown/footer links opt out of this generic rule via
64
+ // their own higher-specificity hover, so this only catches plain in-content links.
65
+ a {
66
+ font-weight: 600;
67
+ text-underline-offset: 0.15em;
68
+ text-decoration-thickness: 2px;
69
+
70
+ &:hover { color: var(--nb-accent-interactive); }
71
+ }
72
+
73
+ // Buttons are <a> too, but set their text via --bs-btn-color. A direct `color` on
74
+ // `a:hover` would beat that var and turn button labels blue — exclude them so the
75
+ // button keeps its own (frozen) text color. Nav/dropdown/footer links already win
76
+ // on specificity with their explicit white hover, so they need no guard here.
77
+ a.btn:hover { color: var(--bs-btn-color); }
@@ -0,0 +1,25 @@
1
+ // Neobrutalism Theme — Base
2
+ // Body surface + neobrutalist treatment of Bootstrap's accent-block utilities.
3
+ // No theme-prefixed classes: the look comes from restyling STANDARD classes
4
+ // (.text-bg-*, .border, .shadow, .card) so markup stays swappable across themes.
5
+
6
+ // Body surface
7
+ body {
8
+ background-color: var(--nb-paper);
9
+ color: var(--bs-body-color);
10
+ }
11
+
12
+ // ============================================
13
+ // Accent blocks: .text-bg-* (Bootstrap) get the hard neobrutalist edge when
14
+ // used as full-bleed section/decorative blocks. Bootstrap already sets the
15
+ // background + a readable contrast color; we just square the corners.
16
+ // (Borders/shadows are added per-component where needed, e.g. .showcase-num.)
17
+ // ============================================
18
+ .text-bg-primary,
19
+ .text-bg-secondary,
20
+ .text-bg-success,
21
+ .text-bg-info,
22
+ .text-bg-warning,
23
+ .text-bg-danger {
24
+ border-radius: 0;
25
+ }
@@ -0,0 +1,148 @@
1
+ // Neobrutalism Theme — Buttons
2
+ // Every button is a hard-bordered block sitting on an offset shadow that
3
+ // "presses" into the page on interaction. This restyles Bootstrap's own
4
+ // .btn / .btn-* classes so all existing markup (nav CTAs, hero buttons,
5
+ // forms) inherits the look with zero HTML changes.
6
+
7
+ .btn {
8
+ font-family: $nb-font-display;
9
+ font-weight: 700;
10
+ letter-spacing: -0.01em;
11
+ border-radius: 0;
12
+ @include nb-border();
13
+ @include nb-shadow(md);
14
+ text-transform: none;
15
+ padding: 0.6rem 1.25rem;
16
+ }
17
+
18
+ // Press EXACTLY like the stat cards. These use the DOUBLED `.btn.btn` selector
19
+ // (specificity 0,2,0) on purpose: every theme page bundle re-emits Bootstrap's own
20
+ // `.btn { transition: color … }` and `.btn:hover` (because page SCSS @forwards
21
+ // Bootstrap), and those load AFTER the main bundle. The doubled class beats them so
22
+ // the press is pure transform+shadow with the stat-card timing — no color flash, no
23
+ // focus-ring fighting the offset shadow.
24
+ .btn.btn {
25
+ // Same transition the stat cards use → identical feel.
26
+ @include nb-press();
27
+
28
+ // Focus shows an OUTLINE ring (outside the box, never conflicts with the offset
29
+ // shadow). No focus box-shadow — that was the "flash of border".
30
+ &:focus { outline: 0; }
31
+ &:focus-visible {
32
+ outline: 3px solid var(--nb-border-color);
33
+ outline-offset: 3px;
34
+ }
35
+ }
36
+
37
+ .btn {
38
+
39
+ // Bootstrap adds a subtle border-color per-variant; force ink so the
40
+ // signature black/white frame is consistent across every color.
41
+ // (btn-adaptive / -inverse are the mode-flipping solids used by the nav CTA,
42
+ // auth buttons, etc. — they MUST be in this list or they'd keep Bootstrap's
43
+ // default "darken on hover" and feel different from every other button.)
44
+ &.btn-primary,
45
+ &.btn-secondary,
46
+ &.btn-success,
47
+ &.btn-info,
48
+ &.btn-warning,
49
+ &.btn-danger,
50
+ &.btn-light,
51
+ &.btn-dark,
52
+ &.btn-adaptive,
53
+ &.btn-adaptive-inverse {
54
+ border-color: var(--nb-border-color);
55
+ --bs-btn-hover-border-color: var(--nb-border-color);
56
+ --bs-btn-active-border-color: var(--nb-border-color);
57
+ }
58
+
59
+ // 3. SOLID buttons: freeze hover/active fill to the resting color so the press is
60
+ // pure transform+shadow (no color shift) — exactly the stat-card feel. Outline
61
+ // buttons are intentionally EXCLUDED so they keep their fill-on-hover.
62
+ // Freezing to `var(--bs-btn-bg)` works in BOTH modes automatically because the
63
+ // adaptive classes already set --bs-btn-bg per light/dark.
64
+ &.btn-primary, &.btn-secondary, &.btn-success,
65
+ &.btn-info, &.btn-warning, &.btn-danger,
66
+ &.btn-light, &.btn-dark,
67
+ &.btn-adaptive, &.btn-adaptive-inverse {
68
+ --bs-btn-hover-bg: var(--bs-btn-bg);
69
+ --bs-btn-hover-color: var(--bs-btn-color);
70
+ --bs-btn-active-bg: var(--bs-btn-bg);
71
+ --bs-btn-active-color: var(--bs-btn-color);
72
+ }
73
+ }
74
+
75
+ // btn-adaptive / -inverse RESTING fill. The global _buttons-adaptive.scss sets these
76
+ // via `.btn-adaptive` (0,1,0), but Bootstrap's own `.btn { --bs-btn-bg: transparent }`
77
+ // re-emission can tie/beat it on order, leaving the button transparent. Restate the
78
+ // resting fill here at `.btn.btn-adaptive` (0,2,0) so it always wins — same trick the
79
+ // press uses. Mode-flip handled by pairing with [data-bs-theme="dark"].
80
+ .btn.btn-adaptive {
81
+ --bs-btn-color: #fff;
82
+ --bs-btn-bg: var(--bs-dark);
83
+ --bs-btn-border-color: var(--nb-border-color);
84
+ }
85
+ [data-bs-theme="dark"] .btn.btn-adaptive {
86
+ --bs-btn-color: #000;
87
+ --bs-btn-bg: var(--bs-light);
88
+ }
89
+ .btn.btn-adaptive-inverse {
90
+ --bs-btn-color: #000;
91
+ --bs-btn-bg: var(--bs-light);
92
+ --bs-btn-border-color: var(--nb-border-color);
93
+ }
94
+ [data-bs-theme="dark"] .btn.btn-adaptive-inverse {
95
+ --bs-btn-color: #fff;
96
+ --bs-btn-bg: var(--bs-dark);
97
+ }
98
+
99
+ // Size variants keep the chunky proportions
100
+ .btn-lg {
101
+ padding: 0.85rem 1.75rem;
102
+ font-size: 1.1rem;
103
+ @include nb-border($nb-border-width-lg);
104
+ }
105
+
106
+ .btn-sm {
107
+ padding: 0.35rem 0.8rem;
108
+ font-size: 0.85rem;
109
+ }
110
+
111
+ // Outline buttons: transparent fill, ink frame, fill-on-hover (no fade)
112
+ [class*="btn-outline-"] {
113
+ background: transparent;
114
+ border-color: var(--nb-border-color);
115
+ color: var(--bs-body-color);
116
+
117
+ &:hover {
118
+ color: #111111;
119
+ }
120
+ }
121
+ .btn-outline-primary:hover { background: $primary; }
122
+ .btn-outline-secondary:hover { background: $secondary; }
123
+ .btn-outline-success:hover { background: $success; }
124
+ .btn-outline-danger:hover { background: $danger; }
125
+ .btn-outline-warning:hover { background: $warning; }
126
+ .btn-outline-info:hover { background: $info; }
127
+
128
+ // Link-style button stays flat (no border/shadow) but bold + underlined
129
+ .btn-link {
130
+ border: 0;
131
+ box-shadow: none;
132
+ font-weight: 700;
133
+ text-decoration: underline;
134
+ text-underline-offset: 0.2em;
135
+
136
+ &:hover,
137
+ &:active {
138
+ transform: none;
139
+ box-shadow: none;
140
+ }
141
+ }
142
+
143
+ // NOTE: There are intentionally NO theme-specific accent button classes
144
+ // (e.g. .btn-nb-yellow). Themes must restyle the STANDARD Bootstrap button
145
+ // classes so the same markup works across themes (swap theme.id, done). Need a
146
+ // yellow CTA? Use `.btn-warning` ($warning is the acid-yellow accent). Need other
147
+ // accents? Use `.btn-primary` / `.btn-success` / etc. The base `.btn` rule above
148
+ // already gives every variant the neobrutalist border + offset shadow + press.