blob: de961f584cd88159db00bcf3b535117e028676a3 [file] [log] [blame]
Marc Kupietza737b1b2023-10-07 09:32:20 +02001/**
2 * IDS theme for reveal.js
3 *
4 * By Marc Kupietz
5 */
6
7
8// Default mixins and settings -----------------
9@import "../template/mixins";
10@import "../template/settings";
11// ---------------------------------------------
12
13
14// Include theme-specific fonts
Marc Kupietza0f8f682026-08-08 14:13:11 +020015// NB: https://korap.ids-mannheim.de/font/{fira-condensed,libertinus}.css both
16// return 404, so the condensed and bold faces never loaded and headings fell
17// back to a regular-width, regular-weight face. Google Fonts serves the real
18// Fira Sans Condensed incl. weights 700/800 (this is where the IDS reference
19// decks get it from too); the others are kept for locally installed copies.
20@import url('https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:wght@300;400;700;800&family=Fira+Sans:wght@200;300;400;700&family=Fira+Sans+Extra+Condensed:wght@300;700&display=swap');
Marc Kupietza737b1b2023-10-07 09:32:20 +020021@import url('https://code.cdn.mozilla.net/fonts/fira.css');
Marc Kupietzc22be152026-08-18 15:54:55 +020022// Fira Code: the monospaced Fira Sans variant for highlighted/code text (as
23// in the IDS reference decks; falls back to Fira Mono from the Mozilla CSS
24// above, then DejaVu Sans Mono)
25@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap');
Marc Kupietza737b1b2023-10-07 09:32:20 +020026@import url('https://korap.ids-mannheim.de/font/libertinus.css');
27
28$idsOrange: #f6a800;
29
30// Override theme settings (see ../template/settings.scss)
31$backgroundColor: #fff;
32
33$mainColor: #222;
34$headingColor: $idsOrange;
35
36$mainFontSize: 42px;
37$mainFont: 'Libertinus Serif', Helvetica, sans-serif;
Marc Kupietza0f8f682026-08-08 14:13:11 +020038$headingFont: 'Fira Sans Extra Condensed', 'Fira Sans Condensed', 'Fira Sans', Helvetica, sans-serif;
Marc Kupietza737b1b2023-10-07 09:32:20 +020039$headingTextShadow: none;
40$headingLetterSpacing: 0.05ex;
41$headingTextTransform: uppercase;
Marc Kupietza0f8f682026-08-08 14:13:11 +020042$headingFontWeight: 700;
Marc Kupietza737b1b2023-10-07 09:32:20 +020043$linkColor: #2a76dd;
44$linkColorHover: lighten( $linkColor, 15% );
45$selectionBackgroundColor: lighten( $linkColor, 25% );
46
47$heading1Size: 2em;
48$heading2Size: 1.35em;
Marc Kupietz3fdee732023-10-07 18:52:20 +020049$heading3Size: 0.9em;
50$heading4Size: 0.7em;
Marc Kupietza737b1b2023-10-07 09:32:20 +020051
52$listBulletColor: $idsOrange;
53
Marc Kupietzc22be152026-08-18 15:54:55 +020054// --r-code-font (template emits #{$codeFont} as-is)
55$codeFont: "Fira Code", "Fira Mono", "DejaVu Sans Mono", "Source Code Pro", monospace;
56
Marc Kupietza737b1b2023-10-07 09:32:20 +020057// Change text colors against dark slide backgrounds
58@include dark-bg-text-color(#fff);
59
60
61// Theme template ------------------------------
62@import "../template/theme";
63// ---------------------------------------------
64
Marc Kupietza0f8f682026-08-08 14:13:11 +020065// Bar/logo sizes, expressed as fractions of the slide's own height (reveal.js
66// exposes the configured slide size as --slide-width / --slide-height custom
67// properties). Sizing relative to the slide rather than the raw viewport (vh
68// units) keeps things pinned to the true slide edges instead of drifting
69// into the letter-/pillarboxed margins when the window's aspect ratio
70// doesn't exactly match the configured one.
71$idsBarWidthRatio: 0.05;
72$idsLogoWidthRatio: 0.25;
73$idsBarWidth: calc(var(--slide-height) * #{$idsBarWidthRatio});
74$idsHeadingGap: 24px;
75
76// Vertical gap between the title and the subtitle. The subtitle's bar segment
77// reaches up by this much to bridge it, so the two segments read as one bar.
78$idsHeadingSpacing: 8px;
79
80// Rendered height of one subtitle line. Slides without a subtitle reserve
81// exactly this much, so the bar and the start of the body content stay put
82// from slide to slide instead of jumping. Must stay in sync with
83// $heading3Size (0.9em) and $headingLineHeight (1.2, from template/settings).
84$idsSubtitleHeight: 0.9 * $mainFontSize * 1.2;
85
86// The two bar segments abut at a fractional pixel, which browsers round into a
87// visible hairline. Overlapping them slightly makes the join seamless.
88$idsBarOverlap: 2px;
89
90// reveal.js centres the scaled slide in the viewport, so whenever the window's
91// aspect ratio does not match the deck's, an empty band is left beside (or
92// above) the slide and the bar would not reach the window's physical edge.
93// Working out how wide that band is needs viewport / scale, and CSS cannot
94// divide a length by a length -- which is why the hand-written IDS decks solve
95// this in JavaScript. revealjs_presentation()'s template therefore publishes
96// the band widths, in slide coordinates, as --ids-band-left / --ids-band-top,
97// and the bar simply shifts out by that much. Falling back to 0px keeps this
98// correct whenever the aspect ratios do match, and if the script never runs.
99$idsBandLeft: var(--ids-band-left, 0px);
100
101// revealjs_presentation() sets reveal.js' own `margin` option to 0, so that the
102// slide box is the whole viewport and the orange bar can sit flush in its top
103// left corner. That would otherwise leave the body content running edge to
104// edge, so the breathing room reveal.js' margin used to provide is added back
105// here as slide padding; the bar and the headings reach back out to the edge
106// with matching negative margins below. The inset is the bar plus its gap, so
107// body content lines up with the heading text rather than with the bar.
108$idsContentInset: calc(#{$idsBarWidth} + #{$idsHeadingGap});
109
Marc Kupietz61c8ec72026-08-20 20:47:45 +0200110// The html prefix is solely about specificity: reveal's print styles
111// (html.reveal-print .reveal .slides section { padding: 0 !important }) would
112// otherwise beat this rule and flatten the inset on ?print-pdf pages. An html
113// prefix ties that specificity, and since the theme is loaded after
114// reveal.css, this rule wins both on screen and in print.
115html .reveal .slides section:not(.stack) {
Marc Kupietza0f8f682026-08-08 14:13:11 +0200116 box-sizing: border-box !important;
117 padding-left: #{$idsContentInset} !important;
118 padding-right: #{$idsContentInset} !important;
119}
120
121// Body content is left aligned with the headings; the title frame keeps its
122// own centered layout.
123.reveal .slides section:not(.stack):not(.title-frame) {
124 text-align: left !important;
125}
126
127// reveal.js centers lists by making them inline-block; make them ordinary
Marc Kupietze0826862026-08-11 16:34:54 +0200128// blocks so they line up with the headings.
129//
130// The markers are NOT native ::marker glyphs: browsers anchor outside-position
131// markers at slightly different offsets per engine (and per scale), and even
132// ::before font glyphs carry font-specific side bearings, so a padding(text)-
133// based alignment of the bullet column with the heading text can never be
134// pixel-exact everywhere. Instead we DRAW the markers as CSS boxes in
135// absolutely positioned li::before rules. Geometry (all values in the item's
136// own font size, so the hierarchy scales with the 0.8em per-level sizing from
137// the NESTED LISTS section below):
138//
139// - item text starts at (list left edge) + 0.65em
140// - the marker box starts exactly at the list's left edge; on content
141// slides that edge coincides with the heading text's left edge, i.e. the
142// bullet column is flush with the slide title, deterministically in every
143// browser and at every window size
144//
145// For nested lists the ::before offset has to be divided by the 0.8 font-size
146// factor, because the list's padding is computed in the PARENT item's font
147// size while the ::before offset is computed in the (smaller) child size.
148$idsListIndent: 0.65em;
149$idsListShrink: 0.8;
150$idsMarkerSize: 0.22em;
151$idsMarkerTop: calc((1.3em - #{$idsMarkerSize}) / 2);
152
Marc Kupietza0f8f682026-08-08 14:13:11 +0200153.reveal .slides section:not(.title-frame) ul,
154.reveal .slides section:not(.title-frame) ol {
155 display: block !important;
156 text-align: left !important;
157 margin-left: 0 !important;
Marc Kupietze0826862026-08-11 16:34:54 +0200158 padding-left: $idsListIndent !important;
159 list-style: none !important;
160}
161
162.reveal .slides section:not(.title-frame) li {
163 position: relative !important;
164}
165
166.reveal .slides section:not(.title-frame) li::before {
167 position: absolute !important;
168 left: calc(-1 * #{$idsListIndent}) !important;
169 color: var(--r-list-bullet-color) !important;
170}
171
172.reveal .slides section:not(.title-frame) li li::before {
173 left: calc(-1 * #{$idsListIndent} / #{$idsListShrink}) !important;
174}
175
176// Unordered-list markers: drawn boxes (round dot, square, ring for deeper
177// levels), vertically centered on the item's first line.
178.reveal .slides section:not(.title-frame) ul > li::before {
179 content: "" !important;
180 top: $idsMarkerTop !important;
181 width: $idsMarkerSize !important;
182 height: $idsMarkerSize !important;
183 box-sizing: border-box !important;
184 border-radius: 50% !important;
185 background: var(--r-list-bullet-color) !important;
186}
187
188.reveal .slides section:not(.title-frame) ul ul > li::before {
189 border-radius: 0 !important; // square
190}
191
192.reveal .slides section:not(.title-frame) ul ul ul > li::before {
193 background: transparent !important; // ring
194 border: 0.055em solid var(--r-list-bullet-color) !important;
195 border-radius: 50% !important;
196}
197
198// Ordered lists: the CSS list-item counter honours the HTML start/value
199// attributes, so pandoc's `start`/`value` lists keep their numbers. Numbers
200// are right-aligned into the indent, ending just before the item text.
201.reveal .slides section:not(.title-frame) ol > li::before {
202 content: counter(list-item, decimal) "." !important;
203 width: calc(#{$idsListIndent} - 0.12em) !important;
204 text-align: right !important;
205}
206
207// Checkbox (pandoc task) lists keep their checkboxes, no markers on top.
208.reveal .slides section:not(.title-frame) ul.task-list li::before {
209 content: none !important;
Marc Kupietza0f8f682026-08-08 14:13:11 +0200210}
211
212// reveal.js centres code blocks (width: 90%; margin: auto); make them fill the
213// slide's text column so they start on the same left edge as the headings.
214.reveal .slides section:not(.title-frame) pre {
215 width: auto !important;
216 margin-left: 0 !important;
217 margin-right: 0 !important;
218}
219
220// The IDS logo stays a slide-wide watermark (top right of every slide,
Marc Kupietz28822cd2026-08-20 14:10:18 +0200221// including the title page). The SVG carries no internal padding of its own,
222// so it needs an explicit inset from the slide's right edge; the top offset is
223// chosen so the logo's cap line meets the top of the heading text.
224$idsLogoTop: 6px;
Marc Kupietza0f8f682026-08-08 14:13:11 +0200225$idsLogoRight: 8px;
226
227.reveal .slides {
228 background-image: url('https://corpora.ids-mannheim.de/slides/reveal.js.ids/images/IDS-Logo-2019.svg');
229 background-repeat: no-repeat;
230 background-position: top #{$idsLogoTop} right #{$idsLogoRight};
231 background-size: calc(var(--slide-height) * #{$idsLogoWidthRatio}) auto;
232}
233
234// The orange bar is drawn as a ::before on the headings rather than on the
235// slide, in two segments: one behind the title and one behind the subtitle.
236// Because each segment is sized as a percentage of its own heading's box, the
237// bar always ends exactly at the bottom of the last heading -- it follows a
238// subtitle when there is one, stops at the title when there isn't, and grows
239// by itself when a heading wraps onto a second line. No fixed heights, and no
240// JavaScript. Headings carry no vertical padding, so they sit as high on the
241// slide as the bar does. Every rule is !important because this theme has to
242// win against plugin- and document-level CSS loaded after it.
243.reveal .slides section:not(.title-frame) > h1:first-child,
244.reveal .slides section:not(.title-frame) > h2:first-child {
245 position: relative !important;
246 display: block !important;
247 text-align: left !important;
248 margin: 0 calc(-1 * #{$idsContentInset}) #{$idsHeadingSpacing} calc(-1 * #{$idsContentInset}) !important;
249 padding: 0 0 0 #{$idsContentInset} !important;
250 font-weight: var(--r-heading-font-weight) !important;
251}
252
253.reveal .slides section:not(.title-frame) > h1:first-child::before,
254.reveal .slides section:not(.title-frame) > h2:first-child::before,
255.reveal .slides section:not(.title-frame) > h2:first-child + h3::before {
256 content: "" !important;
257 position: absolute !important;
258 width: #{$idsBarWidth} !important;
259 // A flat fill rather than orange_bar.png: that image is two-toned (a lighter
260 // band across its top), so stretching it over each segment separately left a
261 // pale seam where the two met. The IDS reference decks draw a flat #f6a800.
262 background: #{$idsOrange} !important;
263}
264
265// Title segment: pulled out to the window's physical left edge.
266.reveal .slides section:not(.title-frame) > h1:first-child::before,
267.reveal .slides section:not(.title-frame) > h2:first-child::before {
268 top: 0 !important;
269 left: calc(-1 * #{$idsBandLeft}) !important;
270 height: 100% !important;
271}
272
273// A slide without a subtitle reserves the room one would have taken, so the
274// bar keeps the same height and the body content starts at the same place on
275// every slide. :has() is what lets us ask "is a subtitle coming?" in CSS; where
276// it is unsupported such slides simply keep a title-height bar.
Marc Kupietz6acbd662026-08-20 14:41:00 +0200277//
278// The lone title is vertically CENTRED in its reserved bar: half of the
279// reservation goes above the text as top padding (the bar segment, anchored
280// to the heading box, moves up with it), and the bottom half stays in the bar
281// extension plus margin. The space consumed below the bar is reduced by the
282// same half, so body content starts where it always did.
Marc Kupietza0f8f682026-08-08 14:13:11 +0200283.reveal .slides section:not(.title-frame) > h1:first-child:not(:has(+ h3)),
284.reveal .slides section:not(.title-frame) > h2:first-child:not(:has(+ h3)) {
Marc Kupietz6acbd662026-08-20 14:41:00 +0200285 padding-top: calc((#{$idsHeadingSpacing} + #{$idsSubtitleHeight}) / 2) !important;
286 margin-bottom: calc((#{$idsHeadingSpacing} + #{$idsSubtitleHeight}) / 2 + #{$blockMargin}) !important;
Marc Kupietza0f8f682026-08-08 14:13:11 +0200287}
288
289.reveal .slides section:not(.title-frame) > h1:first-child:not(:has(+ h3))::before,
290.reveal .slides section:not(.title-frame) > h2:first-child:not(:has(+ h3))::before {
Marc Kupietz6acbd662026-08-20 14:41:00 +0200291 height: calc(100% + (#{$idsHeadingSpacing} + #{$idsSubtitleHeight}) / 2) !important;
Marc Kupietza0f8f682026-08-08 14:13:11 +0200292}
293
Marc Kupietzd023f072026-08-20 15:27:37 +0200294// Vertical balance when a subtitle follows: the orange strip between the
295// title's baseline and the subtitle's cap height used to be title descent (16)
296// + segment spacing (8) + subtitle leading (3) ≈ 27px, against only ≈ 11px of
297// orange above the title's cap height. Moving the title 8px DOWN inside its
298// box while REMOVING the 8px segment spacing makes the two margins equal
299// (19px each) AND keeps the bar's total height and the body content's start
300// position pixel-identical: box grows by 8, spacing drops by 8. The subtitle
301// segment still rises (#{$idsHeadingSpacing} + #{$idsBarOverlap}) above its
302// own box, so the bar stays seamless.
303.reveal .slides section:not(.title-frame) > h1:first-child:has(+ h3),
304.reveal .slides section:not(.title-frame) > h2:first-child:has(+ h3) {
305 padding-top: #{$idsHeadingSpacing} !important;
306 margin-bottom: 0 !important;
307}
308
Marc Kupietza0f8f682026-08-08 14:13:11 +0200309// The subtitle sits in the slide's normal text column, so its segment has to
310// reach back out to the slide edge, and up over the gap to the title.
311.reveal .slides section:not(.title-frame) > h2:first-child + h3 {
312 position: relative !important;
313 text-align: left !important;
314 margin-top: 0 !important;
315 margin-left: 0 !important;
316 margin-bottom: $blockMargin !important;
317}
318
319.reveal .slides section:not(.title-frame) > h2:first-child + h3::before {
320 top: calc(-1 * (#{$idsHeadingSpacing} + #{$idsBarOverlap})) !important;
321 left: calc(-1 * (#{$idsContentInset} + #{$idsBandLeft})) !important;
322 height: calc(100% + #{$idsHeadingSpacing} + #{$idsBarOverlap}) !important;
Marc Kupietza737b1b2023-10-07 09:32:20 +0200323}
324
Marc Kupietz55c9cef2026-08-08 16:03:06 +0200325// Section-divider slides: a level 1 heading alone on a slide (pandoc marks
326// these .level1). The IDS reference decks centre that title on the slide while
327// the bar stays in its usual top left corner, so here the bar cannot hang off
328// the heading -- it is painted on the slide itself, at the height it has on
329// every other slide, and the heading gets none of the top-left treatment.
330$idsTitleHeight: 1.35 * $mainFontSize * 1.2;
331$idsBarBlockHeight: $idsTitleHeight + $idsHeadingSpacing + $idsSubtitleHeight;
332
333.reveal .slides section.level1:not(.title-frame) {
334 height: 100% !important;
335 display: flex !important;
336 flex-direction: column !important;
337 justify-content: center !important;
338}
339
340.reveal .slides section.level1:not(.title-frame)::before {
341 content: "" !important;
342 position: absolute !important;
343 top: 0 !important;
344 left: calc(-1 * #{$idsBandLeft}) !important;
345 width: #{$idsBarWidth} !important;
346 height: #{$idsBarBlockHeight} !important;
347 background: #{$idsOrange} !important;
348}
349
350.reveal .slides section.level1:not(.title-frame) > h1:first-child {
351 text-align: center !important;
352 margin: 0 !important;
353 padding: 0 !important;
354}
355
356.reveal .slides section.level1:not(.title-frame) > h1:first-child::before {
357 content: none !important;
358}
359
Marc Kupietza737b1b2023-10-07 09:32:20 +0200360// Define additional color effects based on Dracula spec
361// https://spec.draculatheme.com/
362:root {
363 --r-bold-color: #{$idsOrange};
364 --r-list-bullet-color: #{$listBulletColor};
365}
366
367.reveal {
Marc Kupietz9b795bd2026-08-19 06:58:44 +0200368 // Bold ("highlighted") text gets the orange colour AND the condensed Fira
369 // Sans face, as in the IDS reference decks -- the lighter weight and 90%
370 // size keep it from dominating the serif body text.
Marc Kupietza737b1b2023-10-07 09:32:20 +0200371 strong, b {
Marc Kupietz9b795bd2026-08-19 06:58:44 +0200372 font-family: "Fira Sans Condensed", sans-serif;
373 font-weight: 600;
374 font-size: 90%;
Marc Kupietza737b1b2023-10-07 09:32:20 +0200375 color: var(--r-bold-color);
376 }
377
378 // Dracula colored list bullets and numbers
379 ul, ol {
380 li::marker {
381 color: var(--r-list-bullet-color) !important;
382 }
383 }
384}
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200385
Marc Kupietz281ba9c2026-08-11 15:37:48 +0200386// Nested list items are set progressively smaller, both to emphasise the
387// hierarchy and to keep deeply nested lists from visually competing with the
388// first level. The em size compounds down the nesting levels, so each deeper
389// level is 80% of its parent (level 2: 80%, level 3: 64%, level 4: 51%).
390// Markers and the hanging indentation (padding-left: 0.7em above) scale with
391// the text automatically.
392.reveal li li {
393 font-size: 0.8em;
394}
395
Marc Kupietzf4945eb2026-08-19 17:48:41 +0200396// Description lists: dt in orange Fira Sans Condensed, dd indented.
397.reveal dl {
398 font-size: 0.62em;
399 line-height: 1.25;
400}
401.reveal dt {
402 font-weight: 700;
403 margin-top: 0.35em;
404 font-family: "Fira Sans Condensed", sans-serif;
405 color: $idsOrange;
406}
407.reveal dd {
408 margin: 0 0 0 1.2em;
409 color: #444;
410}
411
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200412
413/*********************************************
414 * FOOTER
415 *********************************************/
Marc Kupietzc0b272d2023-10-08 14:24:18 +0200416 #ids-footer:not(title-slide) {
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200417 opacity: 1;
418 background: white;
419 color: #444444;
420 border-top: dotted orange 2px;
421 transition: opacity 800ms ease-in-out;
422 position: fixed;
423 height: 6%;
424 line-height: 6%;
425 z-index: -20;
426 width: 100%;
427 letter-spacing: 0em;
428 text-align: center;
429 display: table;
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200430}
431
432#ids-footer span {
433 height: 100%;
434 line-height: 100%;
435 z-index: -20;
Marc Kupietz61ad0262024-05-14 22:07:50 +0200436 font-size: 1.8vh;
Marc Kupietzc0b272d2023-10-08 14:24:18 +0200437 font-family: "Fira Sans Condensed", "Fira Sans", "Roboto Condensed", "League Gothic", Impact, sans-serif;
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200438 display: inline-block;
439 display: table-cell;
440 vertical-align: middle;
441}
442
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200443/* Bottom position for the IDS-Footer footer when both progress bar and TOC-Progress are visible */
Marc Kupietzc0b272d2023-10-08 14:24:18 +0200444div.progress[style="display: block;"] ~ #ids-footer {
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200445 bottom: calc(3px + 0vh);
446}
447
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200448/* Bottom position for the IDS-Footer footer when TOC-Progress is visible */
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200449#ids-footer {
450 bottom: 3px;
451}
452
453#ids-footer a {
454 color: #555555;
455}
456
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200457/* Bottom position for the IDS-Footer footer when progress bar is visible */
Marc Kupietzc0b272d2023-10-08 14:24:18 +0200458div.progress[style="display: block;"] ~ footer:last-of-type#ids-footer {
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200459 bottom: 3px;
460}
461
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200462/* Bottom position for the IDS-Footer footer when neither progress bar nor TOC-Progress are visible */
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200463footer:last-of-type#ids-footer {
464 bottom: 0px;
465}
466
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200467/* Make IDS-Footer invisible if explicitly indicated */
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200468.no-ids-footer #ids-footer {
469 opacity: 0;
470 transition: opacity 800ms ease-in-out;
471}
472
473.title-frame #ids-footer {
474 opacity: 0;
475 transition: opacity 800ms ease-in-out;
476}
477
478.no-toc-progress #ids-footer {
479 opacity: 0;
480 transition: opacity 800ms ease-in-out;
481}
482
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200483/* Make IDS-Footer invisible in overview mode */
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200484.overview #ids-footer {
485 opacity: 0;
486 transition: opacity 800ms ease-in-out;
487}
488
Marc Kupietz61c8ec72026-08-20 20:47:45 +0200489/* In print, the footer's negative stacking drops it behind the .pdf-page
490 * backgrounds (z-index 1); lift it above them. position: fixed repeats it at
491 * the bottom of every printed page. */
492html.reveal-print #ids-footer {
493 z-index: 100 !important;
494}
495
496// reveal's print CSS gives every .pdf-page z-index:1, which forms a separate
497// stacking context per page. The slide-number-pdf lives INSIDE such a page, so
498// its own z-index only competes within the page: the footer (z-index 100 at
499// root level) always paints over it, and raising the number's z-index alone
500// cannot help. Remove the per-page stacking context in print (the pages are
501// separated by page-break-after:always anyway, so nothing needs stacking), and
502// the number's z-index 200 wins against the footer globally. Position stays
503// the theme's screen rule (right:29px / bottom:22px), which puts the number
504// inside the footer band with its white background cutting the dotted line --
505// the same look as on screen.
506html.reveal-print .reveal .slides .pdf-page {
507 z-index: auto !important;
508}
509
510// On screen the number is flanked by the arrow buttons, so its slightly raised
511// baseline reads as deliberate; in print it shares the footer band with the
512// author/title/date line, whose vertically centered text has its baseline
513// ~19px above the page bottom. The number's screen offset (bottom:22px, 14px
514// font from reveal's print rule) puts its baseline ~25px up. 15px aligns the
515// two baselines. Print-only: the screen rule keeps its 22px.
516html.reveal-print div.slide-number-pdf {
517 z-index: 200 !important;
518 bottom: 15px !important;
519}
520
521// On screen the bar segments shift left by --ids-band-left so the bar reaches
522// the window's physical edge when the slide is pillarboxed. In print there are
523// no bands (.pdf-page == slide box), and if the band values are ever stale
524// (e.g. an outdated template script), a nonzero band-left would push the
525// segments outside the pdf-page, whose overflow:hidden then clips them.
526// Pin the geometry explicitly for print instead of trusting the custom
527// property: title segments start at the heading's (== pdf-page's) left edge,
528// the subtitle segment (which lives in the text column, inset by
529// $idsContentInset) reaches back out by exactly the inset, and the level1
530// divider bar starts at the section's left edge. Widths stay the normal bar
531// width, so the visible result is pixel-identical to the on-screen bar.
532html.reveal-print .reveal .slides section:not(.title-frame) > h1:first-child::before,
533html.reveal-print .reveal .slides section:not(.title-frame) > h2:first-child::before {
534 left: 0 !important;
535}
536
537html.reveal-print .reveal .slides section:not(.title-frame) > h2:first-child + h3::before {
538 left: calc(-1 * #{$idsContentInset}) !important;
539}
540
541html.reveal-print .reveal .slides section.level1:not(.title-frame)::before {
542 left: 0 !important;
543}
544
545// The WGL membership logo sits at bottom:10px of the title frame -- inside
546// the footer's ~46px band on print pages (the footer is force-shown on every
547// page in print view and cannot be hidden per page, position:fixed). Lift the
548// logo above the footer in print only; the screen layout stays put.
549html.reveal-print .reveal .slides section.title-frame {
550 background-position: right 8px bottom 55px;
551}
552
Marc Kupietza0f8f682026-08-08 14:13:11 +0200553// Like the orange bar/IDS logo above, this is painted on the slide itself
554// (rather than on .slide-background-content, which spans the raw,
555// unscaled viewport) so it stays pinned to the title slide's true
Marc Kupietz67715592026-08-15 14:55:18 +0200556// bottom-right corner instead of the browser window's. Its margin mirrors
Marc Kupietz28822cd2026-08-20 14:10:18 +0200557// the IDS logo's (top 6px / right 8px of the slide), so the two sit on
Marc Kupietz67715592026-08-15 14:55:18 +0200558// one shared inset.
Marc Kupietza0f8f682026-08-08 14:13:11 +0200559.reveal .slides section.title-frame {
560 background-image: url("https://corpora.ids-mannheim.de/slides/reveal.js.ids/images/Mitglied_WGL_transparent.svg");
Marc Kupietzf0ce0322023-10-07 15:33:47 +0200561 background-repeat: no-repeat;
Marc Kupietz67715592026-08-15 14:55:18 +0200562 background-position: right 8px bottom 10px;
563 background-size: calc(var(--slide-height) * 0.1) auto;
564 /* full slide height, so "bottom" really is the slide's bottom edge */
565 height: 100%;
Marc Kupietze9ace292024-05-14 22:11:15 +0200566}
567
568
Marc Kupietz903104a2026-08-20 10:10:41 +0200569/*********************************************
570 * SLIDES MENU
571 *********************************************/
572
573// The menu plugin copies .reveal's computed font-family onto .slide-menu as an
574// inline style (and its own CSS is loaded after the theme), so without
575// !important here the menu would come out in the Libertinus serif body face.
576// Fira Sans Condensed is the IDS sans for navigation/UI text, and its narrow
577// glyphs keep long (German) slide titles on one line.
578.slide-menu-wrapper .slide-menu {
579 font-family: "Fira Sans Condensed", sans-serif !important;
580}
581
582// Widen the menu a little over the plugin's 300px default -- but only the
583// default: a width the user picked via the menu-width option maps to one of
584// the plugin's width classes (or an inline style), which must keep winning.
585.slide-menu-wrapper .slide-menu:not(.slide-menu--wide):not(.slide-menu--half):not(.slide-menu--third):not(.slide-menu--full):not(.slide-menu--custom) {
Marc Kupietz7427cca2026-08-20 10:53:03 +0200586 width: 372px !important;
Marc Kupietz903104a2026-08-20 10:10:41 +0200587}
588
589// Tighter, less wasteful rows than the plugin's 10px 18px padding with a 12px
590// icon gap: the icon column and generous side padding eat exactly the width
591// the titles need.
592.slide-menu-wrapper .slide-menu-item,
593.slide-menu-wrapper .slide-menu-item-vertical {
594 padding: 6px 12px !important;
595 line-height: 1.3 !important;
596}
597
598.slide-menu-wrapper .slide-menu-item-vertical {
599 padding-left: 26px !important;
600}
601
602// Wrapped titles: make the row a flex line so the second line aligns with the
603// first instead of sliding under the bullet/circle icon. The icon sits on the
604// first line's text baseline; the title column takes the remaining width and
605// wraps within itself.
606.slide-menu-wrapper .slide-menu-item,
607.slide-menu-wrapper .slide-menu-item-vertical {
608 display: flex !important;
609 align-items: baseline !important;
610}
611
612.slide-menu-wrapper .slide-menu-item-title {
613 flex: 1 !important;
614 min-width: 0 !important;
615}
616
617.slide-menu-wrapper .slide-menu-item i.far,
618.slide-menu-wrapper .slide-menu-item i.fas,
619.slide-menu-wrapper .slide-menu-item-vertical i.far,
620.slide-menu-wrapper .slide-menu-item-vertical i.fas,
621.slide-menu-wrapper .slide-menu-item svg.svg-inline--fa,
622.slide-menu-wrapper .slide-menu-item-vertical svg.svg-inline--fa {
623 padding-right: 8px !important;
624}
625
Marc Kupietz7427cca2026-08-20 10:53:03 +0200626// Top-level (section) entries in bold, marking the hierarchy as the indented
627// sub-slides alone do now. Note the Google Fonts import only ships Fira Sans
628// Condensed in 300/400/700/800 -- there is no 600.
629.slide-menu-wrapper .slide-menu-item {
630 font-weight: 700 !important;
631}
632
Marc Kupietz903104a2026-08-20 10:10:41 +0200633// Current slide in the IDS accent colour, matching the slide-number and the
634// orange bar.
635.slide-menu-wrapper .active-menu-panel li.active {
636 color: #{$idsOrange} !important;
Marc Kupietzf0ce0322023-10-07 15:33:47 +0200637}
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200638
639/*
640 * Menu controls
641 */
Marc Kupietzc0b272d2023-10-08 14:24:18 +0200642body .reveal .slide-menu-button {
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200643 color: #aaaaaa !important;
644 position: fixed;
645 left: 30px;
646 bottom: 2%;
647 vertical-align: middle;
648 z-index: 30;
649 font-size: 2vh;
650}
651
652#customcontrols > ul {
653 color: #aaaaaa !important;
654 position: fixed;
Marc Kupietzf51e9152023-10-07 15:32:33 +0200655 left: 50px;
Marc Kupietz7c8f7de2023-10-07 11:42:29 +0200656 bottom: 2% !important;
657 vertical-align: middle;
658 z-index: 30;
659 font-size: 2vh;
660}
661
662@media only screen and (min-width: 500px) {
663 #customcontrols > ul {
664 bottom: 2% !important;
665 }
666}
Marc Kupietz3fdee732023-10-07 18:52:20 +0200667
Marc Kupietzc7249f92023-10-10 07:16:50 +0200668.reveal .controls .controls-arrow {
669 position: relative;
670 width: 3.6em;
671 height: 3.6em;
672 bottom: -12px;
673 right: -4px;
674}
675
Marc Kupietz3fdee732023-10-07 18:52:20 +0200676.reveal h3, h4, h5, h6 {
677 text-transform: none !important;
678}
679
680.reveal h3, h4, h5, h6 {
681 text-transform: none !important;
682}
683
684.reveal h2 + h3 {
685 margin-top: -0.5em !important;
686}
Marc Kupietzdf0eda92023-10-07 20:50:00 +0200687
688.title-frame h1,
689.title-frame h2 {
690 margin: 0 0 0 0;
691 background: rgb(246, 168, 0);
692 color: white;
693 font-family: "Fira Sans Condensed", "Roboto Condensed", Impact, sans-serif;
694 font-weight: 600;
695 line-height: 1.2;
696 letter-spacing: 0.05ex;
697 text-transform: uppercase;
698 width: 100%;
699 margin-top: .5em;
700 padding-top: .5em;
701 font-size: 1.75em;
702 margin-left: 0;
703 text-align: center;
704 text-shadow: none;
705 word-wrap: break-word;
706}
707
708
709.title-frame .author {
710 font-family: "Fira Sans Condensed", sans-serif;
711 font-weight: 400;
712 color: #657b83;
713 margin-top: 10vh;
714}
715
716.title-frame .place {
717 font-family: "Fira Sans Condensed", sans-serif;
718 margin-top: 40px;
719 font-weight: 400;
720 color: #657b83;
721}
722
723.title-frame h2 {
724 margin-top: -3px;
725 margin-bottom: 1em;
726 padding-bottom: .5em;
727 font-size: 1em;
728}
Marc Kupietz0a3c2e52023-10-08 20:20:43 +0200729
730/*********************************************
731 * TABLES
732 *********************************************/
733
734 th {
735 color: rgb(246, 168, 0);
736}
737
738table {
739 font-family: 'Fira Sans Condensed', sans-serif;
740 font-weight: 400;
741 font-size: 16px;
742}
743
744.reveal table.dataTable {
745 border: #aaaaaa 1px solid;
746 border-collapse: collapse;
747}
748
749.reveal table.dataTable td {
750 border: #aaaaaa 1px solid;
751 border-collapse: collapse;
752}
753
754.dataTables_wrapper .dataTables_length, .dataTables_wrapper .dataTables_filter, .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_processing, .dataTables_wrapper .dataTables_paginate, table.dataTable thead > tr > th.sorting::before, table.dataTable thead > tr > th.sorting::after, table.dataTable thead > tr > th.sorting_asc::before, table.dataTable thead > tr > th.sorting_asc::after, table.dataTable thead > tr > th.sorting_desc::before, table.dataTable thead > tr > th.sorting_desc::after, table.dataTable thead > tr > th.sorting_asc_disabled::before, table.dataTable thead > tr > th.sorting_asc_disabled::after, table.dataTable thead > tr > th.sorting_desc_disabled::before, table.dataTable thead > tr > th.sorting_desc_disabled::after, table.dataTable thead > tr > td.sorting::before, table.dataTable thead > tr > td.sorting::after, table.dataTable thead > tr > td.sorting_asc::before, table.dataTable thead > tr > td.sorting_asc::after, table.dataTable thead > tr > td.sorting_desc::before, table.dataTable thead > tr > td.sorting_desc::after, table.dataTable thead > tr > td.sorting_asc_disabled::before, table.dataTable thead > tr > td.sorting_asc_disabled::after, table.dataTable thead > tr > td.sorting_desc_disabled::before, table.dataTable thead > tr > td.sorting_desc_disabled::after {
755 display: none;
756}
757
758.caption {
759 font-family: 'Fira Sans Condensed', sans-serif;
760 font-weight: 400;
761 font-size: 16px;
762 text-align: center;
763}
764
765/*
766table.display td { white-space: nowrap; }
767*/
768
769.dt-buttons, .dataTables_filter {
770 margin-top: 10pt;
771}
772
Marc Kupietz069f1e42023-10-11 10:26:16 +0200773/* Sort Arrows in DataTables */
774table.dataTable thead>tr>th.sorting:before, table.dataTable thead>tr>th.sorting:after, table.dataTable thead>tr>th.sorting_asc:before, table.dataTable thead>tr>th.sorting_asc:after, table.dataTable thead>tr>th.sorting_desc:before, table.dataTable thead>tr>th.sorting_desc:after, table.dataTable thead>tr>th.sorting_asc_disabled:before, table.dataTable thead>tr>th.sorting_asc_disabled:after, table.dataTable thead>tr>th.sorting_desc_disabled:before, table.dataTable thead>tr>th.sorting_desc_disabled:after, table.dataTable thead>tr>td.sorting:before, table.dataTable thead>tr>td.sorting:after, table.dataTable thead>tr>td.sorting_asc:before, table.dataTable thead>tr>td.sorting_asc:after, table.dataTable thead>tr>td.sorting_desc:before, table.dataTable thead>tr>td.sorting_desc:after, table.dataTable thead>tr>td.sorting_asc_disabled:before, table.dataTable thead>tr>td.sorting_asc_disabled:after, table.dataTable thead>tr>td.sorting_desc_disabled:before, table.dataTable thead>tr>td.sorting_desc_disabled:after {
775 right: 0 !important;
776 line-height: 80% !important;
777}
778
Marc Kupietz0a3c2e52023-10-08 20:20:43 +0200779/*********************************************
780 * BIBLIOGRAPHY
781 *********************************************/
782
783.reveal .references {
784 font-family: "Fira Sans Condensed", sans-serif;
785 font-size: 16px;
786 text-align: left;
Marc Kupietzbfab8a12026-08-19 14:42:42 +0200787 margin-top: 10px;
788 max-height: 510px;
Marc Kupietz0a3c2e52023-10-08 20:20:43 +0200789 font-weight: 400;
790 color: #253b43;
791 overflow-y: auto;
792}
793
794.hanging-indent > .csl-entry {
795 padding-left: 22px ;
796 text-indent: -22px ;
797}
798
Marc Kupietz21f526c2026-08-14 12:32:56 +0200799// .references scopes these above pandoc's CSL defaults (div.csl-entry), which
800// otherwise win on specificity and pin margin-bottom to 0em.
801.references .csl-entry {
Marc Kupietz0a3c2e52023-10-08 20:20:43 +0200802 color: #888888;
Marc Kupietz21f526c2026-08-14 12:32:56 +0200803 margin-bottom: 0.5em;
Marc Kupietz0a3c2e52023-10-08 20:20:43 +0200804}
805
Marc Kupietz21f526c2026-08-14 12:32:56 +0200806// "Authors (Year):" as a bold dark first line; the theme template's JS wraps
807// the leading text of each entry in .csl-authors-year (see default.html) --
808// which part of an entry citeproc wraps in spans depends on the entry type, so
809// a CSS-only break cannot place it reliably.
810.csl-entry .csl-authors-year {
811 display: block;
812 font-weight: bold;
813 color: #4d616b;
Marc Kupietz0a3c2e52023-10-08 20:20:43 +0200814}
Marc Kupietz11797162023-10-09 23:17:36 +0200815
816.reveal code.sourceCode:last-child + pre {
817 height: 800px !important;
Marc Kupietzc7249f92023-10-10 07:16:50 +0200818}
819
Marc Kupietz589d1b82023-10-10 12:31:33 +0200820
821/*********************************************
822 * ARROWS and SLIDE NUMBERS
823 *********************************************/
824
825 .reveal .controls .controls-arrow:after, .reveal .controls .controls-arrow:before {
826 width: 13px !important; /* size */
827 height: 4px; /* line width */
828}
829
830.reveal .controls {
831 display: none;
832 position: absolute;
833 top: auto;
834 bottom: -8px;
835 right: 16px;
836 left: auto;
837 z-index: 11;
838 /* color: #000;*/
839 pointer-events: none;
840 font-size: 8px;
841}
842
843.reveal .controls .controls-arrow {
844 position: relative;
845 height: 3.6em;
846 width: 1.2em; /* distance betwee arrows */
847 bottom: 0;
848 right: 0;
849}
850
851.reveal div.slide-number {
852 text-align: center;
853 width: 2em;
854 position: absolute;
855 display: block;
856 right: 29px;
857 bottom: 22px;
858 z-index: 31;
859 font-family: "Fira Sans Condensed", sans-serif;
860 font-size: 18px;
861 line-height: 1;
862 background-color: white;
863 color: #666;
864 padding: 0;
865}
866