ultimate-jekyll-manager 1.7.2 → 1.8.1

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 (84) hide show
  1. package/CHANGELOG.md +69 -1
  2. package/CLAUDE.md +36 -15
  3. package/README.md +4 -2
  4. package/TODO-AUTH-TESTING.md +1 -1
  5. package/dist/assets/themes/newsflash/README.md +58 -0
  6. package/dist/assets/themes/newsflash/_config.scss +138 -0
  7. package/dist/assets/themes/newsflash/_theme.js +27 -0
  8. package/dist/assets/themes/newsflash/_theme.scss +37 -0
  9. package/dist/assets/themes/newsflash/css/base/_mixins.scss +50 -0
  10. package/dist/assets/themes/newsflash/css/base/_root.scss +134 -0
  11. package/dist/assets/themes/newsflash/css/base/_typography.scss +49 -0
  12. package/dist/assets/themes/newsflash/css/base/_utilities.scss +58 -0
  13. package/dist/assets/themes/newsflash/css/components/_badges.scss +65 -0
  14. package/dist/assets/themes/newsflash/css/components/_buttons.scss +139 -0
  15. package/dist/assets/themes/newsflash/css/components/_cards.scss +52 -0
  16. package/dist/assets/themes/newsflash/css/components/_editorial.scss +182 -0
  17. package/dist/assets/themes/newsflash/css/components/_forms.scss +75 -0
  18. package/dist/assets/themes/newsflash/css/components/_infinite-scroll.scss +102 -0
  19. package/dist/assets/themes/newsflash/css/components/_panels.scss +91 -0
  20. package/dist/assets/themes/newsflash/css/components/_ticker.scss +70 -0
  21. package/dist/assets/themes/newsflash/css/layout/_general.scss +264 -0
  22. package/dist/assets/themes/newsflash/css/layout/_navigation.scss +164 -0
  23. package/dist/assets/themes/newsflash/js/initialize-tooltips.js +20 -0
  24. package/dist/assets/themes/newsflash/js/masthead-scroll.js +29 -0
  25. package/dist/assets/themes/newsflash/pages/404/index.scss +27 -0
  26. package/dist/assets/themes/newsflash/pages/about/index.scss +70 -0
  27. package/dist/assets/themes/newsflash/pages/blog/index.scss +17 -0
  28. package/dist/assets/themes/newsflash/pages/blog/post.js +29 -0
  29. package/dist/assets/themes/newsflash/pages/blog/post.scss +164 -0
  30. package/dist/assets/themes/newsflash/pages/index.scss +159 -0
  31. package/dist/assets/themes/newsflash/pages/pricing/index.scss +194 -0
  32. package/dist/assets/themes/newsflash/pages/test/libraries/layers/index.js +9 -0
  33. package/dist/assets/themes/newsflash/pages/test/libraries/layers/index.scss +7 -0
  34. package/dist/commands/blogify.js +6 -3
  35. package/dist/commands/test.js +34 -5
  36. package/dist/defaults/CLAUDE.md +17 -4
  37. package/dist/defaults/dist/_includes/core/pricing/resolve-plan.html +59 -0
  38. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/footer.html +20 -3
  39. package/dist/defaults/dist/_layouts/themes/classy/admin/core/minimal-viewport-locked.html +1 -1
  40. package/dist/defaults/dist/_layouts/themes/classy/admin/core/minimal.html +1 -1
  41. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +5 -40
  42. package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/pricing.html +33 -34
  43. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/core/base.html +61 -0
  44. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/404.html +86 -0
  45. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/about.html +353 -0
  46. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/categories/category.html +105 -0
  47. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/categories/index.html +93 -0
  48. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/index.html +373 -0
  49. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/post.html +289 -0
  50. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/tags/index.html +90 -0
  51. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/tags/tag.html +107 -0
  52. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/contact.html +340 -0
  53. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/index.html +522 -0
  54. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/pricing.html +485 -0
  55. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/team/index.html +207 -0
  56. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/team/member.html +134 -0
  57. package/dist/defaults/test/README.md +4 -0
  58. package/dist/gulp/tasks/jekyll.js +4 -2
  59. package/dist/test/runner.js +50 -3
  60. package/dist/test/suites/build/attach-log-file.test.js +102 -0
  61. package/dist/test/suites/build/theme-contract.test.js +173 -0
  62. package/dist/test/utils/extended-mode-warning.js +13 -0
  63. package/dist/utils/attach-log-file.js +70 -43
  64. package/docs/appearance.md +1 -0
  65. package/docs/assets.md +9 -0
  66. package/docs/audit.md +78 -7
  67. package/docs/build-system.md +57 -0
  68. package/docs/common-mistakes.md +15 -0
  69. package/docs/{project-structure.md → directory-structure.md} +1 -1
  70. package/docs/environment-detection.md +1 -1
  71. package/docs/javascript-libraries.md +38 -1
  72. package/docs/layouts-and-pages.md +146 -0
  73. package/docs/local-development.md +1 -8
  74. package/docs/logging.md +30 -0
  75. package/docs/migration.md +131 -0
  76. package/docs/no-inline-scripts.md +304 -0
  77. package/docs/purgecss.md +164 -0
  78. package/docs/seo.md +131 -4
  79. package/docs/templating.md +23 -0
  80. package/docs/test-boot-layer.md +1 -1
  81. package/docs/test-framework.md +56 -8
  82. package/docs/themes.md +254 -13
  83. package/logs/test.log +111 -0
  84. package/package.json +9 -8
@@ -0,0 +1,134 @@
1
+ // Newsflash 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(--nf-*) tokens, never
4
+ // the raw SCSS values, so dark mode is a single block of overrides.
5
+
6
+ // ============================================
7
+ // Light Mode (default)
8
+ // ============================================
9
+ // DOUBLED selectors (:root:root / [data-bs-theme][data-bs-theme]) on purpose:
10
+ // every theme page bundle re-emits Bootstrap's own :root/[data-bs-theme=dark]
11
+ // variable blocks (because page SCSS @uses config → Bootstrap) and those load
12
+ // AFTER the main bundle. The doubled selector (0,2,0) beats Bootstrap's
13
+ // (0,1,0) regardless of load order, so the paper/ink surfaces always win.
14
+ :root:root,
15
+ [data-bs-theme="light"][data-bs-theme="light"] {
16
+ // Paper & ink
17
+ --nf-paper: #{$nf-paper};
18
+ --nf-paper-2: #{$nf-paper-2};
19
+ --nf-ink: #{$nf-ink};
20
+ --nf-ink-soft: #{$nf-ink-soft};
21
+
22
+ // Translucent paper for the blurred sticky masthead
23
+ --nf-paper-translucent: #{rgba($nf-paper, 0.88)};
24
+
25
+ // Soft hairline for in-content dividers (feed rows, hr, table rules) —
26
+ // frames use the full-strength ink via --nf-border-color instead.
27
+ --nf-line: #{rgba($nf-ink, 0.16)};
28
+
29
+ // Accents
30
+ --nf-vermilion: #{$nf-vermilion};
31
+ --nf-blue: #{$nf-blue};
32
+ --nf-volt: #{$nf-volt};
33
+ --nf-volt-ink: #{$nf-volt-ink};
34
+
35
+ // Ink panels (ticker, footer, big-read band) — dark slabs in both modes
36
+ --nf-panel-bg: #{$nf-panel-bg};
37
+ --nf-panel-color: #{$nf-panel-color};
38
+
39
+ // Frame + shadow color follow the ink
40
+ --nf-border-color: var(--nf-ink);
41
+ --nf-shadow-color: var(--nf-ink);
42
+
43
+ // Frame + shadow recipes (used by components)
44
+ --nf-border-width: #{$nf-border-width};
45
+ --nf-border: #{$nf-border-width} solid var(--nf-border-color);
46
+ --nf-shadow-hard: #{$nf-shadow-offset} #{$nf-shadow-offset} 0 var(--nf-shadow-color);
47
+ --nf-shadow-hard-hover: #{$nf-shadow-offset-hover} #{$nf-shadow-offset-hover} 0 var(--nf-shadow-color);
48
+ --nf-shadow-pop: #{$nf-shadow-pop};
49
+
50
+ // Film grain strength (see _utilities.scss)
51
+ --nf-grain-opacity: 0.05;
52
+
53
+ // INTERACTIVE accent — the single token every hover/active fill points at
54
+ // (nav links, dropdown items, pagination). It tracks the rendered primary
55
+ // (--bs-primary), NOT the raw SCSS value, so consumer overrides flow through.
56
+ --nf-accent-interactive: var(--bs-primary);
57
+ --nf-accent-interactive-ink: #ffffff; // readable text on the interactive fill
58
+
59
+ // Map onto Bootstrap surfaces. The -rgb companions MUST be remapped too —
60
+ // Bootstrap's .bg-body-* / .text-body-* utilities paint from
61
+ // rgba(var(--bs-*-rgb), opacity), not the hex vars.
62
+ --bs-body-bg: #{$nf-paper};
63
+ --bs-body-bg-rgb: #{red($nf-paper)}, #{green($nf-paper)}, #{blue($nf-paper)};
64
+ --bs-body-color: #{$nf-ink};
65
+ --bs-body-color-rgb: #{red($nf-ink)}, #{green($nf-ink)}, #{blue($nf-ink)};
66
+ --bs-secondary-color: #{$nf-ink-soft}; // .text-body-secondary / muted metas
67
+ --bs-secondary-color-rgb: #{red($nf-ink-soft)}, #{green($nf-ink-soft)}, #{blue($nf-ink-soft)};
68
+ --bs-secondary-bg: #{$nf-paper-2};
69
+ --bs-secondary-bg-rgb: #{red($nf-paper-2)}, #{green($nf-paper-2)}, #{blue($nf-paper-2)};
70
+ --bs-tertiary-bg: #{$nf-paper-2};
71
+ --bs-tertiary-bg-rgb: #{red($nf-paper-2)}, #{green($nf-paper-2)}, #{blue($nf-paper-2)};
72
+ --bs-border-color: var(--nf-line); // soft dividers; frames opt into full ink
73
+ --bs-card-bg: #{$nf-paper};
74
+ --bs-emphasis-color: #{$nf-ink};
75
+ --bs-emphasis-color-rgb: #{red($nf-ink)}, #{green($nf-ink)}, #{blue($nf-ink)};
76
+ }
77
+
78
+ // ============================================
79
+ // Dark Mode
80
+ // ============================================
81
+ // Paper flips to deep warm near-black, ink to cream; vermilion/blue brighten
82
+ // for contrast; volt stays vibrant. Frames + hard shadows auto-flip because
83
+ // they reference var(--nf-border-color) → var(--nf-ink).
84
+ // Doubled selector: see the light-mode block note.
85
+
86
+ // Dark-mode primary derives from the COMPILE-TIME $primary so a consumer's
87
+ // brand override survives dark mode (the stock vermilion keeps its hand-tuned
88
+ // brightening; any other brand color gets a generic white-mix lift).
89
+ $nf-primary-dark-mode: if($primary == $nf-vermilion, $nf-vermilion-dark-mode, mix(white, $primary, 15%));
90
+
91
+ [data-bs-theme="dark"][data-bs-theme="dark"] {
92
+ --nf-paper: #{$nf-paper-dark};
93
+ --nf-paper-2: #{$nf-paper-2-dark};
94
+ --nf-ink: #{$nf-ink-dark};
95
+ --nf-ink-soft: #{$nf-ink-soft-dark};
96
+
97
+ --nf-paper-translucent: #{rgba($nf-paper-dark, 0.88)};
98
+ --nf-line: #{rgba($nf-ink-dark, 0.18)};
99
+
100
+ --nf-vermilion: #{$nf-vermilion-dark-mode};
101
+ --nf-blue: #{$nf-blue-dark-mode};
102
+
103
+ --nf-panel-bg: #{$nf-panel-bg-dark};
104
+ --nf-panel-color: #{$nf-panel-color-dark};
105
+
106
+ // Pop shadows barely read on dark paper; lean on a deeper, tighter blur.
107
+ --nf-shadow-pop: 0 18px 40px -18px rgba(0, 0, 0, 0.8);
108
+
109
+ --nf-grain-opacity: 0.07;
110
+
111
+ // Brighten the rendered primary so it stays vivid on dark paper
112
+ // (--bs-primary is compile-time; these runtime link/button reads cover the
113
+ // places that matter most for legibility).
114
+ --bs-primary: #{$nf-primary-dark-mode};
115
+ --bs-primary-rgb: #{red($nf-primary-dark-mode)}, #{green($nf-primary-dark-mode)}, #{blue($nf-primary-dark-mode)};
116
+ --bs-link-color: #{$nf-primary-dark-mode};
117
+ --bs-link-color-rgb: #{red($nf-primary-dark-mode)}, #{green($nf-primary-dark-mode)}, #{blue($nf-primary-dark-mode)};
118
+ --bs-link-hover-color: #{lighten($nf-primary-dark-mode, 8%)};
119
+
120
+ --bs-body-bg: #{$nf-paper-dark};
121
+ --bs-body-bg-rgb: #{red($nf-paper-dark)}, #{green($nf-paper-dark)}, #{blue($nf-paper-dark)};
122
+ --bs-body-color: #{$nf-ink-dark};
123
+ --bs-body-color-rgb: #{red($nf-ink-dark)}, #{green($nf-ink-dark)}, #{blue($nf-ink-dark)};
124
+ --bs-secondary-color: #{$nf-ink-soft-dark};
125
+ --bs-secondary-color-rgb: #{red($nf-ink-soft-dark)}, #{green($nf-ink-soft-dark)}, #{blue($nf-ink-soft-dark)};
126
+ --bs-secondary-bg: #{$nf-paper-2-dark};
127
+ --bs-secondary-bg-rgb: #{red($nf-paper-2-dark)}, #{green($nf-paper-2-dark)}, #{blue($nf-paper-2-dark)};
128
+ --bs-tertiary-bg: #{$nf-paper-2-dark};
129
+ --bs-tertiary-bg-rgb: #{red($nf-paper-2-dark)}, #{green($nf-paper-2-dark)}, #{blue($nf-paper-2-dark)};
130
+ --bs-border-color: var(--nf-line);
131
+ --bs-card-bg: #{$nf-paper-2-dark};
132
+ --bs-emphasis-color: #{$nf-ink-dark};
133
+ --bs-emphasis-color-rgb: #{red($nf-ink-dark)}, #{green($nf-ink-dark)}, #{blue($nf-ink-dark)};
134
+ }
@@ -0,0 +1,49 @@
1
+ // Newsflash Theme — Typography
2
+ // Optical-sized serif headlines over a clean grotesk body — the editorial
3
+ // voice of the theme. Fonts are loaded via the theme's `head` block in
4
+ // base.html (Google Fonts), NOT @import-ed here, to avoid render-blocking
5
+ // duplicate loads.
6
+
7
+ // NOTE: families, weights, and line-heights ship as Bootstrap vars in
8
+ // _config.scss ($headings-*, $display-*, $lead-font-weight, $line-height-base)
9
+ // — NOT as element rules here. Page bundles re-emit Bootstrap AFTER the main
10
+ // bundle, so element-rule overrides of Bootstrap-owned props would silently
11
+ // lose on any page that ships page CSS (the stock 300 display/lead weights
12
+ // would come back). Only non-Bootstrap props live below.
13
+
14
+ body {
15
+ -webkit-font-smoothing: antialiased;
16
+ }
17
+
18
+ h1, h2, h3, h4, h5, h6,
19
+ .h1, .h2, .h3, .h4, .h5, .h6 {
20
+ font-optical-sizing: auto;
21
+ letter-spacing: $nf-heading-letter-spacing;
22
+ text-wrap: balance;
23
+ }
24
+
25
+ // Display headlines: tighter tracking — the front-page splash voice
26
+ // (weight 550 + leading 1.04 come from $display-* in _config.scss).
27
+ .display-1, .display-2, .display-3, .display-4, .display-5, .display-6 {
28
+ font-family: $nf-font-display;
29
+ font-optical-sizing: auto;
30
+ letter-spacing: -0.022em;
31
+ }
32
+
33
+ // Deks (the standfirst under a headline) — .lead reads as ink-soft prose.
34
+ .lead {
35
+ color: var(--bs-secondary-color);
36
+ line-height: 1.6;
37
+ }
38
+
39
+ // Plain in-content links: vermilion with a visible underline. Buttons set
40
+ // their own text color via --bs-btn-color — guard them so labels never turn
41
+ // vermilion on hover.
42
+ a {
43
+ text-underline-offset: 0.15em;
44
+ text-decoration-thickness: 1.5px;
45
+ }
46
+
47
+ a.btn:hover {
48
+ color: var(--bs-btn-color);
49
+ }
@@ -0,0 +1,58 @@
1
+ // Newsflash Theme — Base
2
+ // Body surface, the film-grain overlay, selection color, and editorial
3
+ // treatments of utility classes the shared (Classy-derived) layouts emit.
4
+ // No theme-prefixed classes in markup: the look comes from restyling
5
+ // STANDARD classes so markup stays swappable across themes.
6
+
7
+ // Body surface
8
+ body {
9
+ background-color: var(--nf-paper);
10
+ color: var(--bs-body-color);
11
+ }
12
+
13
+ // ============================================
14
+ // Film grain — the analog print texture over everything
15
+ // ============================================
16
+ // Fixed SVG-noise overlay; pointer-events none so it never intercepts input.
17
+ // Multiply on paper, screen on dark paper (multiply would just vanish).
18
+ body::after {
19
+ content: "";
20
+ position: fixed;
21
+ inset: 0;
22
+ z-index: 999;
23
+ pointer-events: none;
24
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
25
+ opacity: var(--nf-grain-opacity);
26
+ mix-blend-mode: multiply;
27
+ }
28
+
29
+ [data-bs-theme="dark"] body::after {
30
+ mix-blend-mode: screen;
31
+ }
32
+
33
+ // Volt selection — the highlighter
34
+ ::selection {
35
+ background: var(--nf-volt);
36
+ color: var(--nf-volt-ink);
37
+ }
38
+
39
+ // ============================================
40
+ // Accent text (headline_accent spans) — italic serif vermilion
41
+ // ============================================
42
+ .text-accent {
43
+ font-family: $nf-font-display;
44
+ font-style: italic;
45
+ color: var(--bs-primary);
46
+ }
47
+
48
+ // ============================================
49
+ // Highlighter swipe — volt half-height marker behind inline text
50
+ // ============================================
51
+ mark,
52
+ .highlight {
53
+ background: linear-gradient(transparent 55%, var(--nf-volt) 55%);
54
+ color: inherit;
55
+ padding: 0 0.12em;
56
+ box-decoration-break: clone;
57
+ -webkit-box-decoration-break: clone;
58
+ }
@@ -0,0 +1,65 @@
1
+ // Newsflash Theme — Badges, Chips & Pagination
2
+ // Badges become uppercase pill chips with hairline ink frames (the "FEATURED"
3
+ // sticker from the masthead design). Pagination becomes a row of pills.
4
+
5
+ .badge {
6
+ border-radius: 50rem;
7
+ font-weight: 800;
8
+ font-size: 0.68em;
9
+ letter-spacing: 0.1em;
10
+ text-transform: uppercase;
11
+ padding: 0.55em 0.95em;
12
+ @include nf-border();
13
+ }
14
+
15
+ // Tertiary "superheadline" badges (inherited layouts emit these above
16
+ // headlines) become the volt sticker chip.
17
+ .badge.bg-body-tertiary {
18
+ background: var(--nf-volt) !important;
19
+ color: var(--nf-volt-ink) !important;
20
+ }
21
+
22
+ // Soft category chips (blog cards) keep their soft fill but read editorial
23
+ .badge[class*="-soft"] {
24
+ border-color: currentColor;
25
+ }
26
+
27
+ // ============================================
28
+ // Pagination — pill links, vermilion active
29
+ // ============================================
30
+ .pagination {
31
+ gap: 0.4rem;
32
+
33
+ .page-link {
34
+ border: var(--nf-border);
35
+ border-radius: 50rem !important; // beats Bootstrap's first/last corner rounding
36
+ background: transparent;
37
+ color: var(--bs-body-color);
38
+ font-weight: 700;
39
+ font-size: 0.9rem;
40
+ padding: 0.5rem 0.95rem;
41
+ transition: $nf-transition;
42
+
43
+ &:hover {
44
+ background: var(--nf-ink);
45
+ color: var(--nf-paper);
46
+ border-color: var(--nf-border-color);
47
+ }
48
+
49
+ &:focus {
50
+ box-shadow: 0 0 0 3px var(--nf-volt);
51
+ }
52
+ }
53
+
54
+ .page-item.active .page-link {
55
+ background: var(--nf-accent-interactive);
56
+ color: var(--nf-accent-interactive-ink);
57
+ border-color: var(--nf-border-color);
58
+ }
59
+
60
+ .page-item.disabled .page-link {
61
+ background: transparent;
62
+ border-color: var(--nf-line);
63
+ color: var(--bs-secondary-color);
64
+ }
65
+ }
@@ -0,0 +1,139 @@
1
+ // Newsflash Theme — Buttons
2
+ // Pill buttons framed in ink, resting on a small hard offset shadow that
3
+ // LIFTS on hover. This restyles Bootstrap's own .btn / .btn-* classes so all
4
+ // existing markup (nav CTAs, hero buttons, forms) inherits the look with
5
+ // zero HTML changes.
6
+
7
+ .btn {
8
+ font-family: $font-family-sans-serif;
9
+ font-weight: 700;
10
+ letter-spacing: 0.02em;
11
+ border-radius: 50rem;
12
+ @include nf-border();
13
+ @include nf-shadow-hard();
14
+ padding: 0.6rem 1.4rem;
15
+ }
16
+
17
+ // The lift interaction. Doubled `.btn.btn` selector (specificity 0,2,0) on
18
+ // purpose: every theme page bundle re-emits Bootstrap's own `.btn` rules
19
+ // (because page SCSS @forwards Bootstrap) and those load AFTER the main
20
+ // bundle — the doubled class beats them so the lift is pure transform+shadow.
21
+ // Outline and link buttons are flat — they opt out below.
22
+ .btn.btn:not([class*="btn-outline-"]):not(.btn-link) {
23
+ @include nf-lift();
24
+
25
+ // Focus shows an OUTLINE ring (outside the box, never conflicts with the
26
+ // offset shadow).
27
+ &:focus { outline: 0; }
28
+ &:focus-visible {
29
+ outline: 3px solid var(--nf-volt);
30
+ outline-offset: 2px;
31
+ }
32
+ }
33
+
34
+ .btn {
35
+ // Bootstrap adds a subtle border-color per-variant; force ink so the
36
+ // hairline frame is consistent across every color.
37
+ // (btn-adaptive / -inverse are the mode-flipping solids used by the nav
38
+ // CTA, auth buttons, etc. — they MUST be in this list or they'd keep
39
+ // Bootstrap's default "darken on hover" and feel different.)
40
+ &.btn-primary,
41
+ &.btn-secondary,
42
+ &.btn-success,
43
+ &.btn-info,
44
+ &.btn-warning,
45
+ &.btn-danger,
46
+ &.btn-light,
47
+ &.btn-dark,
48
+ &.btn-adaptive,
49
+ &.btn-adaptive-inverse {
50
+ border-color: var(--nf-border-color);
51
+ --bs-btn-hover-border-color: var(--nf-border-color);
52
+ --bs-btn-active-border-color: var(--nf-border-color);
53
+ }
54
+
55
+ // SOLID buttons: freeze hover/active fill to the resting color so the lift
56
+ // is pure transform+shadow (no color shift). Outline buttons are excluded —
57
+ // they keep their fill-on-hover.
58
+ &.btn-primary, &.btn-secondary, &.btn-success,
59
+ &.btn-info, &.btn-warning, &.btn-danger,
60
+ &.btn-light, &.btn-dark,
61
+ &.btn-adaptive, &.btn-adaptive-inverse {
62
+ --bs-btn-hover-bg: var(--bs-btn-bg);
63
+ --bs-btn-hover-color: var(--bs-btn-color);
64
+ --bs-btn-active-bg: var(--bs-btn-bg);
65
+ --bs-btn-active-color: var(--bs-btn-color);
66
+ }
67
+ }
68
+
69
+ // btn-adaptive / -inverse RESTING fill. The global _buttons-adaptive.scss sets
70
+ // these via `.btn-adaptive` (0,1,0), but Bootstrap's own re-emitted
71
+ // `.btn { --bs-btn-bg: transparent }` can tie/beat it on order. Restate the
72
+ // resting fill at `.btn.btn-adaptive` (0,2,0) so it always wins.
73
+ .btn.btn-adaptive {
74
+ --bs-btn-color: #{$nf-paper};
75
+ --bs-btn-bg: #{$nf-ink};
76
+ --bs-btn-border-color: var(--nf-border-color);
77
+ }
78
+ [data-bs-theme="dark"] .btn.btn-adaptive {
79
+ --bs-btn-color: #{$nf-paper-dark};
80
+ --bs-btn-bg: #{$nf-ink-dark};
81
+ }
82
+ .btn.btn-adaptive-inverse {
83
+ --bs-btn-color: #{$nf-paper-dark};
84
+ --bs-btn-bg: #{$nf-ink-dark};
85
+ --bs-btn-border-color: var(--nf-border-color);
86
+ }
87
+ [data-bs-theme="dark"] .btn.btn-adaptive-inverse {
88
+ --bs-btn-color: #{$nf-paper};
89
+ --bs-btn-bg: #{$nf-ink};
90
+ }
91
+
92
+ // Size variants keep the pill proportions
93
+ .btn-lg {
94
+ padding: 0.85rem 1.75rem;
95
+ font-size: 1.05rem;
96
+ }
97
+
98
+ .btn-sm {
99
+ padding: 0.35rem 0.9rem;
100
+ font-size: 0.82rem;
101
+ }
102
+
103
+ // Outline ("ghost") buttons: flat — transparent fill, ink frame, no shadow,
104
+ // no lift. Hover fills with ink + paper text, true to the editorial ghost.
105
+ // DOUBLED attribute selector (0,2,0) on purpose: page bundles re-emit
106
+ // Bootstrap's .btn / .btn-outline-* rules after the main bundle; the doubled
107
+ // selector wins regardless of load order (the variant's compile-time ink
108
+ // color is invisible on dark paper otherwise).
109
+ [class*="btn-outline-"][class*="btn-outline-"] {
110
+ box-shadow: none;
111
+ background: transparent;
112
+ border-color: var(--nf-border-color);
113
+ color: var(--bs-body-color);
114
+ --bs-btn-hover-bg: var(--nf-ink);
115
+ --bs-btn-hover-color: var(--nf-paper);
116
+ --bs-btn-hover-border-color: var(--nf-border-color);
117
+ --bs-btn-active-bg: var(--nf-ink);
118
+ --bs-btn-active-color: var(--nf-paper);
119
+ --bs-btn-active-border-color: var(--nf-border-color);
120
+
121
+ &:hover {
122
+ color: var(--nf-paper);
123
+ background: var(--nf-ink);
124
+ }
125
+ }
126
+
127
+ // Link-style button stays flat (no frame/shadow) but bold + underlined
128
+ .btn-link {
129
+ border: 0;
130
+ box-shadow: none;
131
+ font-weight: 700;
132
+ text-decoration: underline;
133
+ text-underline-offset: 0.2em;
134
+ }
135
+
136
+ // NOTE: There are intentionally NO theme-specific accent button classes.
137
+ // Themes must restyle the STANDARD Bootstrap button classes so the same
138
+ // markup works across themes (swap theme.id, done). Need a volt CTA? Use
139
+ // `.btn-warning` ($warning is volt). Vermilion? `.btn-primary`.
@@ -0,0 +1,52 @@
1
+ // Newsflash Theme — Cards
2
+ // Framed paper objects: hairline ink border, editorial radius, serif titles.
3
+ // Cards that ARE links lift gently and grow their framed image on hover.
4
+
5
+ .card {
6
+ background: var(--bs-card-bg);
7
+ @include nf-border();
8
+ border-radius: var(--bs-border-radius-lg);
9
+ transition: $nf-transition;
10
+
11
+ .card-title {
12
+ font-family: $nf-font-display;
13
+ font-optical-sizing: auto;
14
+ letter-spacing: -0.012em;
15
+ line-height: 1.22;
16
+ }
17
+
18
+ // Serif headline links read as ink until hovered — then the vermilion
19
+ // rule grows in underneath (see nf-underline-grow).
20
+ .card-title a {
21
+ color: inherit;
22
+ text-decoration: none;
23
+ @include nf-underline-grow();
24
+ }
25
+ }
26
+
27
+ // Cards that are links (editorial story cards) lift on hover
28
+ a.card {
29
+ color: inherit;
30
+ text-decoration: none;
31
+
32
+ &:hover {
33
+ transform: translateY(-5px);
34
+ }
35
+ }
36
+
37
+ // Framed images inside hovered cards/links zoom slowly (cinematic pan feel)
38
+ .card:hover .art-frame img,
39
+ a:hover > .art-frame img {
40
+ transform: scale(1.04);
41
+ }
42
+
43
+ // Card footers used as byline rows stay flush with the editorial look
44
+ .card-footer {
45
+ background: transparent;
46
+ border-top: 1px solid var(--nf-line);
47
+ }
48
+
49
+ .card-header {
50
+ background: transparent;
51
+ border-bottom: 1px solid var(--nf-line);
52
+ }
@@ -0,0 +1,182 @@
1
+ // Newsflash Theme — Editorial Primitives
2
+ // The cross-page newsroom vocabulary: kickers, section heads with rules, and
3
+ // framed images. Genuinely novel UI (no Bootstrap equivalent) → universal
4
+ // semantic class names other themes are free to style their own way.
5
+
6
+ // ============================================
7
+ // Kicker — the uppercase vermilion micro-label above headlines
8
+ // ============================================
9
+ .kicker {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ gap: 0.5em;
13
+ font-family: $font-family-sans-serif;
14
+ font-size: 0.72rem;
15
+ font-weight: 800;
16
+ letter-spacing: 0.14em;
17
+ text-transform: uppercase;
18
+ color: var(--bs-primary);
19
+
20
+ &::before {
21
+ content: "";
22
+ width: 7px;
23
+ height: 7px;
24
+ background: currentColor;
25
+ border-radius: 50%;
26
+ flex: none;
27
+ }
28
+ }
29
+
30
+ // ============================================
31
+ // Section head — uppercase label + full-width ink rule (+ optional link)
32
+ // ============================================
33
+ .section-head {
34
+ display: flex;
35
+ align-items: baseline;
36
+ gap: 1.25rem;
37
+ margin-bottom: 1.75rem;
38
+
39
+ h2, h3, .h2, .h3 {
40
+ font-family: $font-family-sans-serif;
41
+ font-size: 1.05rem;
42
+ font-weight: 800;
43
+ letter-spacing: 0.12em;
44
+ text-transform: uppercase;
45
+ line-height: 1;
46
+ margin: 0;
47
+ }
48
+
49
+ .rule {
50
+ flex: 1;
51
+ height: var(--nf-border-width);
52
+ background: var(--nf-border-color);
53
+ align-self: center;
54
+ }
55
+
56
+ a {
57
+ font-size: 0.82rem;
58
+ font-weight: 700;
59
+ color: var(--bs-primary);
60
+ text-decoration: none;
61
+ white-space: nowrap;
62
+
63
+ &:hover {
64
+ text-decoration: underline;
65
+ text-underline-offset: 0.2em;
66
+ }
67
+ }
68
+ }
69
+
70
+ // ============================================
71
+ // Art frame — the framed editorial image
72
+ // ============================================
73
+ // Hairline ink border + radius; images zoom slowly when the parent
74
+ // link/card is hovered (rule lives in _cards.scss).
75
+ .art-frame {
76
+ border: var(--nf-border);
77
+ border-radius: var(--bs-border-radius-lg);
78
+ overflow: hidden;
79
+ background: var(--nf-paper-2);
80
+
81
+ // uj_post image-tags render as <picture><img>. The wrapper must fill the
82
+ // frame or the img's percentage height resolves against the auto-height
83
+ // picture instead — leaving a blank strip inside the frame.
84
+ picture {
85
+ display: block;
86
+ width: 100%;
87
+ height: 100%;
88
+ }
89
+
90
+ img {
91
+ width: 100%;
92
+ height: 100%;
93
+ object-fit: cover;
94
+ display: block;
95
+ transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
96
+ }
97
+ }
98
+
99
+ @media (prefers-reduced-motion: reduce) {
100
+ .art-frame img { transition: none; }
101
+ }
102
+
103
+ // ============================================
104
+ // Headline links outside cards (feed rows, hero) — same grow-rule affordance
105
+ // ============================================
106
+ .headline-link {
107
+ color: inherit;
108
+ text-decoration: none;
109
+ @include nf-underline-grow();
110
+ }
111
+
112
+ // ============================================
113
+ // Story card — a whole-tile link to an article (home, blog index, read-next)
114
+ // ============================================
115
+ // Framed image + kicker + serif headline + byline meta. The tile lifts and
116
+ // its framed image zooms on hover.
117
+ .story-card {
118
+ display: block;
119
+ color: inherit;
120
+ text-decoration: none;
121
+ transition: $nf-transition;
122
+
123
+ &:hover {
124
+ color: inherit;
125
+ transform: translateY(-5px);
126
+ }
127
+
128
+ &:hover .art-frame img {
129
+ transform: scale(1.04);
130
+ }
131
+
132
+ h2, h3, .h4, .h5 {
133
+ font-optical-sizing: auto;
134
+ letter-spacing: -0.012em;
135
+ line-height: 1.22;
136
+ }
137
+
138
+ .art-frame {
139
+ aspect-ratio: 16 / 10;
140
+ }
141
+ }
142
+
143
+ // ============================================
144
+ // Feed item — an editorial list row (thumb/number + headline + dek)
145
+ // ============================================
146
+ .feed-item {
147
+ display: grid;
148
+ grid-template-columns: 200px 1fr;
149
+ gap: 1.5rem;
150
+ align-items: center;
151
+ padding: 1.6rem 0;
152
+ border-bottom: 1.5px dashed var(--nf-line);
153
+ color: inherit;
154
+ text-decoration: none;
155
+
156
+ &:first-child { padding-top: 0; }
157
+ &:last-child { border-bottom: 0; }
158
+
159
+ .art-frame {
160
+ aspect-ratio: 1 / 1;
161
+ border-radius: var(--bs-border-radius);
162
+ }
163
+ }
164
+
165
+ a.feed-item:hover {
166
+ color: inherit;
167
+
168
+ .art-frame img {
169
+ transform: scale(1.04);
170
+ }
171
+ }
172
+
173
+ @media (max-width: 767.98px) {
174
+ .feed-item {
175
+ grid-template-columns: 1fr;
176
+ gap: 0.9rem;
177
+
178
+ .art-frame {
179
+ aspect-ratio: 16 / 9;
180
+ }
181
+ }
182
+ }