datalog-theme 0.6.1 → 0.8.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +175 -0
  3. data/CITATION.cff +2 -2
  4. data/README.md +26 -19
  5. data/_data/cdn-integrity.yml +0 -30
  6. data/_includes/analytics/dashboard.html +3 -1
  7. data/_includes/components/api-function.html +20 -1
  8. data/_includes/components/author-bio.html +2 -2
  9. data/_includes/components/enhanced-code-block.html +1 -1
  10. data/_includes/components/hero.html +19 -1
  11. data/_includes/csp-meta.html +115 -11
  12. data/_includes/footer.html +19 -20
  13. data/_includes/head.html +61 -29
  14. data/_includes/header/navigation.html +12 -15
  15. data/_includes/header.html +29 -20
  16. data/_includes/layouts/default/article.html +5 -1
  17. data/_includes/meta/math-config.html +27 -1
  18. data/_includes/meta/schema.html +5 -2
  19. data/_includes/meta/scripts-loader.html +16 -31
  20. data/_includes/post/related-posts.html +4 -7
  21. data/_includes/scripts.html +1 -9
  22. data/_includes/search/index-data.json +131 -0
  23. data/_includes/search/page.html +136 -0
  24. data/_layouts/dataset.html +1 -0
  25. data/_layouts/default.html +16 -8
  26. data/_layouts/home.html +6 -0
  27. data/_layouts/notebook.html +1 -0
  28. data/_layouts/package.html +1 -0
  29. data/_layouts/portfolio.html +1 -0
  30. data/_layouts/post.html +20 -5
  31. data/_layouts/project.html +2 -1
  32. data/_plugins/analytics_dashboard.rb +9 -3
  33. data/_plugins/config_validator.rb +12 -7
  34. data/_plugins/csp_generator.rb +18 -28
  35. data/_plugins/datalog_bibliography.rb +9 -7
  36. data/_plugins/datalog_comments.rb +8 -5
  37. data/_plugins/datalog_slides.rb +9 -8
  38. data/_plugins/i18n.rb +7 -8
  39. data/_plugins/image_optimizer.rb +17 -6
  40. data/_plugins/math_preprocessor.rb +36 -3
  41. data/_plugins/notebook_converter.rb +23 -43
  42. data/_plugins/plugin_loader.rb +3 -1
  43. data/_plugins/publications_generator.rb +8 -2
  44. data/_plugins/rouge_highlight_filter.rb +42 -0
  45. data/_plugins/search_code_blocks.rb +30 -0
  46. data/_plugins/search_normalizer.rb +15 -53
  47. data/_plugins/search_pages.rb +72 -0
  48. data/_sass/_academic-dashboard.scss +262 -0
  49. data/_sass/_base.scss +19 -1
  50. data/_sass/_components.scss +77 -1144
  51. data/_sass/_features.scss +17 -0
  52. data/_sass/_font-fallbacks.scss +43 -0
  53. data/_sass/_header.scss +10 -0
  54. data/_sass/_layout.scss +18 -12
  55. data/_sass/_mathematical.scss +1 -1
  56. data/_sass/_notebooks.scss +322 -0
  57. data/_sass/_open-science-badges.scss +56 -0
  58. data/_sass/{_phase1-enhancements.scss → _post-components.scss} +46 -1
  59. data/_sass/_search-page.scss +530 -0
  60. data/_sass/_search.scss +47 -1
  61. data/_sass/_syntax-highlighting.scss +212 -97
  62. data/_sass/_theme.scss +42 -18
  63. data/_sass/_typography.scss +14 -0
  64. data/_sass/_variables.scss +7 -4
  65. data/assets/css/main.scss +14 -0
  66. data/assets/img/hero-detail-640.webp +0 -0
  67. data/assets/img/hero-detail.webp +0 -0
  68. data/assets/img/social-card.png +0 -0
  69. data/assets/js/dist/academic.js +1 -0
  70. data/assets/js/dist/analytics-dashboard.js +1 -0
  71. data/assets/js/dist/chunks/chunk-225H5YXE.js +1 -0
  72. data/assets/js/dist/core.js +1 -0
  73. data/assets/js/dist/loader.js +1 -0
  74. data/assets/js/dist/math.js +1 -0
  75. data/assets/js/dist/notebook.js +1 -0
  76. data/assets/js/dist/search.js +1 -0
  77. data/assets/js/dist/visualizations.js +11 -0
  78. data/assets/js/loader.js +3 -1
  79. data/datalog-theme.gemspec +43 -22
  80. data/lib/datalog/cli.rb +53 -15
  81. data/lib/datalog/plugin_system/dependency_resolver.rb +0 -2
  82. data/lib/datalog/theme/package.rb +57 -0
  83. data/lib/datalog/theme/repository_checkout.rb +90 -0
  84. data/lib/datalog/theme/version.rb +1 -1
  85. data/lib/datalog/warning_filter.rb +5 -11
  86. data/lib/datalog-theme.rb +21 -0
  87. metadata +75 -146
  88. data/_data/academic.yml +0 -217
  89. data/_data/config/author.yml +0 -121
  90. data/_data/config/features.yml +0 -262
  91. data/_data/config/site.yml +0 -42
  92. data/_data/config/theme.yml +0 -181
  93. data/_data/datasets.yml +0 -28
  94. data/_data/js_meta.json +0 -371
  95. data/_data/navigation.yml +0 -145
  96. data/_data/projects.yml +0 -41
  97. data/_data/publications.yml +0 -28
  98. data/_data/social.yml +0 -73
  99. data/_data/visualizations.yml +0 -51
  100. data/_includes/components/advanced-search.html +0 -682
  101. data/_includes/components/bookmark-system.html +0 -96
  102. data/_includes/components/comments.html +0 -244
  103. data/_includes/components/content-recommendations.html +0 -228
  104. data/_includes/components/email-preferences.html +0 -200
  105. data/_includes/components/enhanced-metadata.html +0 -228
  106. data/_includes/components/language-switcher.html +0 -396
  107. data/_includes/components/navigation-enhancements.html +0 -454
  108. data/_includes/components/newsletter-signup.html +0 -178
  109. data/_includes/components/popular-posts.html +0 -233
  110. data/_includes/components/reading-progress.html +0 -133
  111. data/_includes/components/reading-time.html +0 -121
  112. data/_includes/components/series-navigation.html +0 -124
  113. data/_includes/components/social-proof.html +0 -34
  114. data/_includes/components/user-preferences.html +0 -566
  115. data/_layouts/archive.html +0 -282
  116. data/_layouts/post-sidebar.html +0 -183
  117. data/_sass/_phase3-enhancements.scss +0 -874
  118. data/_sass/_phase4-enhancements.scss +0 -1214
  119. data/_sass/_phase5-enhancements.scss +0 -414
  120. data/assets/img/20220607123041_detail.001.png +0 -0
  121. data/assets/js/academic.js +0 -262
  122. data/assets/js/analytics-dashboard.js +0 -382
  123. data/assets/js/core/dark-mode.js +0 -79
  124. data/assets/js/core/github-cards.js +0 -123
  125. data/assets/js/core/language-filter.js +0 -69
  126. data/assets/js/core/navigation.js +0 -184
  127. data/assets/js/core/scroll-progress.js +0 -45
  128. data/assets/js/core/search-hotkeys.js +0 -62
  129. data/assets/js/core/skip-links.js +0 -62
  130. data/assets/js/main.js +0 -23
  131. data/assets/js/math.js +0 -818
  132. data/assets/js/notebook.js +0 -158
  133. data/assets/js/search/analytics.js +0 -91
  134. data/assets/js/search/app.js +0 -271
  135. data/assets/js/search/autocomplete.js +0 -120
  136. data/assets/js/search/engine.js +0 -260
  137. data/assets/js/search/filters.js +0 -38
  138. data/assets/js/search/render.js +0 -217
  139. data/assets/js/search/utils.js +0 -99
  140. data/assets/js/search.js +0 -354
  141. data/assets/js/visualizations.js +0 -816
  142. data/assets/publications/datalog-publications.bib +0 -8
  143. data/assets/publications/datalog-publications.ris +0 -9
  144. data/assets/publications/publications.bib +0 -30
  145. data/assets/templates/diogo-ribeiro-cv.md +0 -31
  146. data/assets/templates/diogo-ribeiro-cv.tex +0 -32
  147. data/lib/datalog/theme/theme.rb +0 -18
@@ -0,0 +1,17 @@
1
+ // Optional features whose styles the stylesheet includes.
2
+ //
3
+ // assets/css/main.scss configures this module from the site's settings before
4
+ // it loads the theme, so a site carries only the styles of the features it
5
+ // uses. Partials read the flags and load the matching styles with
6
+ // `@if features.$flag { @include meta.load-css(...) }` at the position those
7
+ // rules always had, so turning every flag on leaves the stylesheet unchanged.
8
+ //
9
+ // Every flag defaults to true: a site that replaces main.scss with a plain
10
+ // `@use "theme"` keeps the complete stylesheet.
11
+
12
+ $search: true !default;
13
+ $visualizations: true !default;
14
+ $notebooks: true !default;
15
+ $packages: true !default;
16
+ $academic-dashboard: true !default;
17
+ $open-science-badges: true !default;
@@ -0,0 +1,43 @@
1
+ // Metric-compatible local fallbacks for the IBM Plex web fonts.
2
+ //
3
+ // The Google Fonts stylesheet loads with `display=swap`, so text first paints
4
+ // in a local font and swaps once Plex arrives. These faces scale the local
5
+ // fonts to Plex's metrics (size-adjust from the average glyph width, the
6
+ // overrides from ascent, descent and line gap), so the swap barely moves the
7
+ // layout. Values derive from the fonts' metric tables (@capsizecss/metrics).
8
+
9
+ @font-face {
10
+ font-family: 'IBM Plex Sans Fallback';
11
+ src: local('Arial'), local('Liberation Sans'), local('Helvetica Neue'), local('Helvetica');
12
+ size-adjust: 101.17%;
13
+ ascent-override: 101.32%;
14
+ descent-override: 27.18%;
15
+ line-gap-override: 0%;
16
+ }
17
+
18
+ @font-face {
19
+ font-family: 'IBM Plex Serif Fallback';
20
+ src: local('Georgia');
21
+ size-adjust: 106.1%;
22
+ ascent-override: 96.61%;
23
+ descent-override: 25.92%;
24
+ line-gap-override: 0%;
25
+ }
26
+
27
+ @font-face {
28
+ font-family: 'IBM Plex Serif Fallback Times';
29
+ src: local('Times New Roman'), local('Liberation Serif'), local('Times');
30
+ size-adjust: 116.43%;
31
+ ascent-override: 88.04%;
32
+ descent-override: 23.62%;
33
+ line-gap-override: 0%;
34
+ }
35
+
36
+ @font-face {
37
+ font-family: 'IBM Plex Mono Fallback';
38
+ src: local('Courier New'), local('Liberation Mono'), local('Courier');
39
+ size-adjust: 99.98%;
40
+ ascent-override: 102.52%;
41
+ descent-override: 27.5%;
42
+ line-gap-override: 0%;
43
+ }
data/_sass/_header.scss CHANGED
@@ -226,6 +226,16 @@ body.dark-mode .header-control {
226
226
  }
227
227
  }
228
228
 
229
+ // The menu is collapsed in the markup so the page does not reflow (and animate
230
+ // the reflow) when the navigation script initialises. Without JavaScript
231
+ // nothing could open it, so keep it visible in that case; head.html adds the
232
+ // `js` class before the body renders.
233
+ html:not(.js) .site-nav {
234
+ max-height: none;
235
+ opacity: 1;
236
+ pointer-events: auto;
237
+ }
238
+
229
239
  .nav-list {
230
240
  display: flex;
231
241
  flex-direction: column;
data/_sass/_layout.scss CHANGED
@@ -259,7 +259,7 @@ body.dark-mode .footer {
259
259
  font-size: map.get($font-size-scale, sm);
260
260
  line-height: $line-height-base;
261
261
 
262
- h3 {
262
+ h2 {
263
263
  color: #fff;
264
264
  font-size: map.get($font-size-scale, sm);
265
265
  font-weight: 700;
@@ -278,6 +278,12 @@ body.dark-mode .footer {
278
278
  }
279
279
  }
280
280
 
281
+ // body.dark-mode a outranks the rule above; on the navy footer the dark
282
+ // accent needs the lighter shade to reach 4.5:1 through the muted paragraphs.
283
+ body.dark-mode & a {
284
+ color: #93c5fd;
285
+ }
286
+
281
287
  p {
282
288
  margin: 0 0 map.get($spacing, 2);
283
289
  }
@@ -359,7 +365,7 @@ body.dark-mode .footer {
359
365
 
360
366
  .footer-privacy-note {
361
367
  font-size: map.get($font-size-scale, xs);
362
- opacity: 0.5;
368
+ opacity: 0.8;
363
369
  margin-top: map.get($spacing, 1);
364
370
  }
365
371
 
@@ -369,7 +375,7 @@ body.dark-mode .footer {
369
375
 
370
376
  .footer-affiliation {
371
377
  display: block;
372
- opacity: 0.65;
378
+ opacity: 0.85;
373
379
  font-size: map.get($font-size-scale, xs);
374
380
  }
375
381
 
@@ -377,12 +383,12 @@ body.dark-mode .footer {
377
383
  .footer-orcid,
378
384
  .footer-contact {
379
385
  font-size: map.get($font-size-scale, xs);
380
- opacity: 0.65;
386
+ opacity: 0.85;
381
387
  }
382
388
 
383
389
  .footer-tagline {
384
390
  font-style: italic;
385
- opacity: 0.7;
391
+ opacity: 0.85;
386
392
  }
387
393
 
388
394
  .footer-feeds {
@@ -395,7 +401,7 @@ body.dark-mode .footer {
395
401
  border-top: 1px solid rgba(#fff, 0.1);
396
402
  text-align: center;
397
403
  font-size: map.get($font-size-scale, xs);
398
- opacity: 0.5;
404
+ opacity: 0.8;
399
405
 
400
406
  p { margin: 0; }
401
407
  }
@@ -470,7 +476,7 @@ body.dark-mode .research-metrics {
470
476
  transition: border-color $transition-base;
471
477
 
472
478
  h3 {
473
- color: $color-accent-secondary;
479
+ color: $color-accent-secondary-text;
474
480
  margin: 0;
475
481
  }
476
482
 
@@ -480,7 +486,7 @@ body.dark-mode .research-metrics {
480
486
 
481
487
  &:hover {
482
488
  border-color: rgba($color-accent-secondary, 0.4);
483
- h3 { color: $color-accent-secondary; }
489
+ h3 { color: $color-accent-secondary-text; }
484
490
  }
485
491
  }
486
492
 
@@ -640,7 +646,7 @@ body.dark-mode .author-profile__bio {
640
646
 
641
647
  .skill-tag--framework {
642
648
  background: rgba($color-accent-secondary, 0.08);
643
- color: $color-accent-secondary;
649
+ color: $color-accent-secondary-text;
644
650
  }
645
651
 
646
652
  .skill-tag--tool {
@@ -926,7 +932,7 @@ body.dark-mode .post-meta {
926
932
  padding: 0.1rem 0.5rem;
927
933
  border-radius: map.get($radius, sm);
928
934
  background: rgba($color-accent-secondary, 0.1);
929
- color: $color-accent-secondary;
935
+ color: $color-accent-secondary-text;
930
936
  }
931
937
 
932
938
  body.dark-mode .post-meta__badge {
@@ -1066,7 +1072,7 @@ body.dark-mode .post-tag {
1066
1072
 
1067
1073
  .post-category {
1068
1074
  background: rgba($color-accent-secondary, 0.08);
1069
- color: $color-accent-secondary;
1075
+ color: $color-accent-secondary-text;
1070
1076
 
1071
1077
  &:hover { background: rgba($color-accent-secondary, 0.15); }
1072
1078
  }
@@ -1166,7 +1172,7 @@ body.dark-mode .code-block-meta {
1166
1172
  .code-language {
1167
1173
  font-family: $font-family-mono;
1168
1174
  font-weight: 600;
1169
- color: $color-accent-secondary;
1175
+ color: $color-accent-secondary-text;
1170
1176
  letter-spacing: 0.03em;
1171
1177
  }
1172
1178
 
@@ -267,7 +267,7 @@
267
267
  &:focus-visible {
268
268
  background: rgba($color-accent-secondary, 0.12);
269
269
  border-color: rgba($color-accent-secondary, 0.4);
270
- color: $color-accent-secondary;
270
+ color: $color-accent-secondary-text;
271
271
  }
272
272
  }
273
273
 
@@ -0,0 +1,322 @@
1
+ // Notebook pages: _layouts/notebook.html and the cell and output markup that
2
+ // _plugins/notebook_converter.rb generates. _components.scss loads this only when
3
+ // the site has notebook pages.
4
+
5
+ @use 'sass:map';
6
+ @use "sass:color";
7
+
8
+ @use 'variables' as *;
9
+ @use 'mixins' as *;
10
+
11
+ .notebook-article {
12
+ display: grid;
13
+ gap: map.get($spacing, 5);
14
+ margin: map.get($spacing, 6) auto;
15
+ max-width: 1200px;
16
+ }
17
+
18
+ .notebook-article__header {
19
+ background: rgba($color-surface-100, 0.8);
20
+ padding: map.get($spacing, 6);
21
+ border-radius: 1.25rem;
22
+ box-shadow: 0 20px 60px rgba($color-ink-900, 0.08);
23
+ position: relative;
24
+ overflow: hidden;
25
+ }
26
+
27
+ .notebook-article__header::after {
28
+ content: '';
29
+ position: absolute;
30
+ inset: auto -30% -45% auto;
31
+ width: 45%;
32
+ height: 45%;
33
+ background: radial-gradient(circle at center, rgba($color-accent-primary, 0.35), transparent 65%);
34
+ pointer-events: none;
35
+ }
36
+
37
+ .notebook-article__label {
38
+ text-transform: uppercase;
39
+ letter-spacing: 0.12em;
40
+ font-size: map.get($font-size-scale, xs);
41
+ color: $color-accent-primary;
42
+ margin-bottom: map.get($spacing, 2);
43
+ }
44
+
45
+ .notebook-article__title {
46
+ font-size: clamp(2.4rem, 4vw, 3.2rem);
47
+ margin: 0 0 map.get($spacing, 3);
48
+ }
49
+
50
+ .notebook-article__summary {
51
+ font-size: map.get($font-size-scale, md);
52
+ color: $color-ink-600;
53
+ max-width: 65ch;
54
+ margin-bottom: map.get($spacing, 4);
55
+ }
56
+
57
+ .notebook-article__meta {
58
+ list-style: none;
59
+ padding: 0;
60
+ margin: 0 0 map.get($spacing, 4);
61
+ display: flex;
62
+ flex-wrap: wrap;
63
+ gap: map.get($spacing, 3);
64
+ color: $color-ink-600;
65
+ }
66
+
67
+ .notebook-article__meta li {
68
+ display: flex;
69
+ gap: map.get($spacing, 1);
70
+ align-items: baseline;
71
+ }
72
+
73
+ .notebook-article__meta span {
74
+ font-weight: 600;
75
+ color: $color-ink-800;
76
+ }
77
+
78
+ .notebook-article__actions {
79
+ display: flex;
80
+ flex-wrap: wrap;
81
+ gap: map.get($spacing, 3);
82
+ margin-bottom: map.get($spacing, 4);
83
+ }
84
+
85
+ .notebook-article__actions .btn {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ gap: map.get($spacing, 2);
89
+ }
90
+
91
+ .notebook-article__tags {
92
+ display: flex;
93
+ flex-wrap: wrap;
94
+ gap: map.get($spacing, 2);
95
+ padding: 0;
96
+ margin: 0;
97
+ list-style: none;
98
+ }
99
+
100
+ .notebook-article__tags li {
101
+ background: rgba($color-accent-tertiary, 0.18);
102
+ color: $color-accent-tertiary;
103
+ border-radius: 999px;
104
+ padding: map.get($spacing, 1) map.get($spacing, 3);
105
+ font-size: map.get($font-size-scale, xs);
106
+ letter-spacing: 0.04em;
107
+ }
108
+
109
+ .notebook-article__layout {
110
+ display: grid;
111
+ gap: map.get($spacing, 5);
112
+ }
113
+
114
+ @media (min-width: 960px) {
115
+ .notebook-article__layout {
116
+ grid-template-columns: minmax(0, 2.3fr) minmax(280px, 1fr);
117
+ gap: map.get($spacing, 6);
118
+ }
119
+ }
120
+
121
+ .notebook-article__content {
122
+ display: flex;
123
+ flex-direction: column;
124
+ gap: map.get($spacing, 4);
125
+ }
126
+
127
+ .notebook-article__sidebar {
128
+ position: sticky;
129
+ top: calc(var(--header-height, 96px) + map.get($spacing, 4));
130
+ align-self: start;
131
+ display: flex;
132
+ flex-direction: column;
133
+ gap: map.get($spacing, 4);
134
+ }
135
+
136
+ .notebook-sidebar__section {
137
+ background: rgba($color-surface-100, 0.8);
138
+ border-radius: 1rem;
139
+ padding: map.get($spacing, 4);
140
+ box-shadow: 0 12px 30px rgba($color-ink-900, 0.04);
141
+ }
142
+
143
+ .notebook-sidebar__section h2 {
144
+ font-size: map.get($font-size-scale, sm);
145
+ text-transform: uppercase;
146
+ letter-spacing: 0.08em;
147
+ margin-bottom: map.get($spacing, 3);
148
+ }
149
+
150
+ .notebook-sidebar__stats {
151
+ list-style: none;
152
+ padding: 0;
153
+ margin: 0;
154
+ display: grid;
155
+ gap: map.get($spacing, 2);
156
+ }
157
+
158
+ .notebook-sidebar__stats li {
159
+ font-size: map.get($font-size-scale, sm);
160
+ color: $color-ink-700;
161
+ }
162
+
163
+ .notebook-sidebar__metadata {
164
+ margin: 0;
165
+ display: grid;
166
+ gap: map.get($spacing, 2);
167
+ }
168
+
169
+ .notebook-sidebar__metadata div {
170
+ display: grid;
171
+ gap: map.get($spacing, 1);
172
+ }
173
+
174
+ .notebook-sidebar__metadata dt {
175
+ font-size: map.get($font-size-scale, xs);
176
+ text-transform: uppercase;
177
+ letter-spacing: 0.06em;
178
+ color: $color-ink-500;
179
+ }
180
+
181
+ .notebook-sidebar__metadata dd {
182
+ margin: 0;
183
+ font-size: map.get($font-size-scale, sm);
184
+ color: $color-ink-700;
185
+ word-break: break-word;
186
+ }
187
+
188
+ .notebook-sidebar__clone {
189
+ background: rgba($color-ink-900, 0.08);
190
+ border-radius: 0.75rem;
191
+ padding: map.get($spacing, 3);
192
+ font-family: $font-stack-code;
193
+ overflow-x: auto;
194
+ }
195
+
196
+ .notebook-sidebar__links {
197
+ list-style: none;
198
+ padding: 0;
199
+ margin: 0;
200
+ display: grid;
201
+ gap: map.get($spacing, 2);
202
+ }
203
+
204
+ .notebook-sidebar__link {
205
+ font-weight: 600;
206
+ color: $color-accent-primary;
207
+ }
208
+
209
+ .notebook-cell {
210
+ border-left: 4px solid $color-accent-primary;
211
+ padding: map.get($spacing, 4);
212
+ border-radius: 1rem;
213
+ background: rgba($color-accent-primary, 0.06);
214
+ margin: map.get($spacing, 3) 0;
215
+ box-shadow: inset 0 0 0 1px rgba($color-ink-900, 0.04);
216
+ }
217
+
218
+ .notebook-cell--input {
219
+ border-left-color: $color-accent-secondary;
220
+ }
221
+
222
+ .notebook-cell--output {
223
+ border-left-color: $color-accent-tertiary;
224
+ }
225
+
226
+ .notebook-cell__header {
227
+ display: flex;
228
+ align-items: center;
229
+ justify-content: space-between;
230
+ font-size: map.get($font-size-scale, xs);
231
+ color: $color-ink-500;
232
+ margin-bottom: map.get($spacing, 2);
233
+ text-transform: uppercase;
234
+ letter-spacing: 0.08em;
235
+ }
236
+
237
+ .notebook-cell__code {
238
+ margin: 0;
239
+ overflow: auto;
240
+ border-radius: 0.75rem;
241
+ background: rgba($color-ink-900, 0.08);
242
+ padding: map.get($spacing, 3);
243
+ }
244
+
245
+ .notebook-cell__outputs {
246
+ display: grid;
247
+ gap: map.get($spacing, 3);
248
+ }
249
+
250
+ .notebook-output {
251
+ border-radius: 0.75rem;
252
+ padding: map.get($spacing, 3);
253
+ font-family: $font-stack-code;
254
+ background: rgba($color-ink-900, 0.04);
255
+ overflow-x: auto;
256
+ margin: 0;
257
+ }
258
+
259
+ .notebook-output--stream {
260
+ color: $color-ink-700;
261
+ }
262
+
263
+ .notebook-output--error {
264
+ color: $color-critical-600;
265
+ background: rgba($color-critical-200, 0.35);
266
+ border: 1px solid rgba($color-critical-400, 0.6);
267
+ }
268
+
269
+ .notebook-output__trace {
270
+ margin-top: map.get($spacing, 2);
271
+ white-space: pre-wrap;
272
+ }
273
+
274
+ .notebook-output__figure {
275
+ margin: 0;
276
+ }
277
+
278
+ .notebook-output__figure img {
279
+ width: 100%;
280
+ height: auto;
281
+ border-radius: 0.75rem;
282
+ box-shadow: 0 10px 30px rgba($color-ink-900, 0.15);
283
+ }
284
+
285
+ .notebook-output-plotly,
286
+ .notebook-output-vega {
287
+ min-height: 320px;
288
+ border-radius: 0.75rem;
289
+ background: rgba($color-ink-900, 0.04);
290
+ display: grid;
291
+ place-items: center;
292
+ padding: map.get($spacing, 3);
293
+ }
294
+
295
+ .notebook-output__warning {
296
+ font-size: map.get($font-size-scale, sm);
297
+ color: $color-ink-600;
298
+ text-align: center;
299
+ margin: 0;
300
+ }
301
+
302
+ .notebook-output--widget {
303
+ font-style: italic;
304
+ color: $color-accent-secondary-text;
305
+ }
306
+
307
+ .notebook-segment {
308
+ display: grid;
309
+ gap: map.get($spacing, 2);
310
+ }
311
+
312
+ .notebook-segment__label {
313
+ font-size: map.get($font-size-scale, xs);
314
+ letter-spacing: 0.1em;
315
+ text-transform: uppercase;
316
+ color: $color-ink-400;
317
+ }
318
+
319
+ .notebook-segment__body {
320
+ display: grid;
321
+ gap: map.get($spacing, 3);
322
+ }
@@ -0,0 +1,56 @@
1
+ // Open science badges (_includes/components/open-science-badges.html), which render
2
+ // only when _data/academic.yml defines badges; _components.scss loads this only then.
3
+
4
+ @use 'sass:map';
5
+ @use "sass:color";
6
+
7
+ @use 'variables' as *;
8
+ @use 'mixins' as *;
9
+
10
+ .open-science-badges {
11
+ margin-block: 3rem;
12
+ padding: 1.5rem;
13
+ border-radius: 1rem;
14
+ background: linear-gradient(135deg, rgba(12, 35, 64, 0.05), rgba(50, 119, 246, 0.08));
15
+ }
16
+
17
+ .open-science-badges__intro {
18
+ margin-bottom: 1rem;
19
+ color: var(--muted-foreground, #4a5568);
20
+ }
21
+
22
+ .open-science-badges__list {
23
+ display: flex;
24
+ flex-wrap: wrap;
25
+ gap: 1rem;
26
+ padding: 0;
27
+ margin: 0;
28
+ list-style: none;
29
+ }
30
+
31
+ .open-science-badge {
32
+ display: grid;
33
+ gap: 0.25rem;
34
+ padding: 0.85rem 1rem;
35
+ min-width: 10rem;
36
+ border-radius: 0.75rem;
37
+ background: rgba(12, 35, 64, 0.08);
38
+ border: 1px solid rgba(12, 35, 64, 0.12);
39
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
40
+ }
41
+
42
+ .open-science-badge:focus-within,
43
+ .open-science-badge:hover {
44
+ transform: translateY(-2px);
45
+ box-shadow: 0 8px 24px rgba(12, 35, 64, 0.12);
46
+ }
47
+
48
+ .open-science-badge__label {
49
+ font-weight: 600;
50
+ }
51
+
52
+ .open-science-badge__description,
53
+ .open-science-badge__criteria {
54
+ font-size: 0.85rem;
55
+ color: var(--muted-foreground, #4a5568);
56
+ }
@@ -1,5 +1,5 @@
1
1
  // ============================================================================
2
- // Phase 1 Enhancements - New Features Styles
2
+ // Post components: what _layouts/post.html adds to every post
3
3
  // ============================================================================
4
4
  // - Social sharing buttons
5
5
  // - Breadcrumb navigation
@@ -545,6 +545,51 @@
545
545
  }
546
546
  }
547
547
 
548
+ // Dark mode previously darkened only the badge background, leaving the level
549
+ // colours (dark blue, dark green, dark red) on a near-black pill: the
550
+ // intermediate badge measured 1.93:1. These invert the pairing instead.
551
+ body.dark-mode .difficulty-badge {
552
+ &--beginner {
553
+ background-color: rgba(16, 185, 129, 0.15);
554
+ color: #6ee7b7;
555
+ border-color: rgba(16, 185, 129, 0.4);
556
+
557
+ &:hover {
558
+ background-color: rgba(16, 185, 129, 0.25);
559
+ }
560
+ }
561
+
562
+ &--intermediate {
563
+ background-color: rgba(59, 130, 246, 0.15);
564
+ color: #93c5fd;
565
+ border-color: rgba(59, 130, 246, 0.4);
566
+
567
+ &:hover {
568
+ background-color: rgba(59, 130, 246, 0.25);
569
+ }
570
+ }
571
+
572
+ &--advanced {
573
+ background-color: rgba(249, 115, 22, 0.15);
574
+ color: #fdba74;
575
+ border-color: rgba(249, 115, 22, 0.4);
576
+
577
+ &:hover {
578
+ background-color: rgba(249, 115, 22, 0.25);
579
+ }
580
+ }
581
+
582
+ &--expert {
583
+ background-color: rgba(239, 68, 68, 0.15);
584
+ color: #fca5a5;
585
+ border-color: rgba(239, 68, 68, 0.4);
586
+
587
+ &:hover {
588
+ background-color: rgba(239, 68, 68, 0.25);
589
+ }
590
+ }
591
+ }
592
+
548
593
  // ============================================================================
549
594
  // Print Styles
550
595
  // ============================================================================