blob: e833b8f8a624be729925d641b7a9041452f5456b [file] [log] [blame]
/**
* IDS theme for reveal.js
*
* By Marc Kupietz
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
// NB: https://korap.ids-mannheim.de/font/{fira-condensed,libertinus}.css both
// return 404, so the condensed and bold faces never loaded and headings fell
// back to a regular-width, regular-weight face. Google Fonts serves the real
// Fira Sans Condensed incl. weights 700/800 (this is where the IDS reference
// decks get it from too); the others are kept for locally installed copies.
@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');
@import url('https://code.cdn.mozilla.net/fonts/fira.css');
// Fira Code: the monospaced Fira Sans variant for highlighted/code text (as
// in the IDS reference decks; falls back to Fira Mono from the Mozilla CSS
// above, then DejaVu Sans Mono)
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap');
@import url('https://korap.ids-mannheim.de/font/libertinus.css');
$idsOrange: #f6a800;
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #fff;
$mainColor: #222;
$headingColor: $idsOrange;
$mainFontSize: 42px;
$mainFont: 'Libertinus Serif', Helvetica, sans-serif;
$headingFont: 'Fira Sans Extra Condensed', 'Fira Sans Condensed', 'Fira Sans', Helvetica, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: 0.05ex;
$headingTextTransform: uppercase;
$headingFontWeight: 700;
$linkColor: #2a76dd;
$linkColorHover: lighten( $linkColor, 15% );
$selectionBackgroundColor: lighten( $linkColor, 25% );
$heading1Size: 2em;
$heading2Size: 1.35em;
$heading3Size: 0.9em;
$heading4Size: 0.7em;
$listBulletColor: $idsOrange;
// --r-code-font (template emits #{$codeFont} as-is)
$codeFont: "Fira Code", "Fira Mono", "DejaVu Sans Mono", "Source Code Pro", monospace;
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
// Bar/logo sizes, expressed as fractions of the slide's own height (reveal.js
// exposes the configured slide size as --slide-width / --slide-height custom
// properties). Sizing relative to the slide rather than the raw viewport (vh
// units) keeps things pinned to the true slide edges instead of drifting
// into the letter-/pillarboxed margins when the window's aspect ratio
// doesn't exactly match the configured one.
$idsBarWidthRatio: 0.05;
$idsLogoWidthRatio: 0.25;
// Partner (second institution) logo: shown next to the IDS logo on every
// slide when the document sets the `partner_logo` yaml entry (the template
// then publishes the URL as the --partner-logo custom property).
$idsPartnerGap: 16px;
$idsPartnerHeightRatio: 0.085;
$idsBarWidth: calc(var(--slide-height) * #{$idsBarWidthRatio});
$idsHeadingGap: 24px;
// Vertical gap between the title and the subtitle. The subtitle's bar segment
// reaches up by this much to bridge it, so the two segments read as one bar.
$idsHeadingSpacing: 8px;
// Rendered height of one subtitle line. Slides without a subtitle reserve
// exactly this much, so the bar and the start of the body content stay put
// from slide to slide instead of jumping. Must stay in sync with
// $heading3Size (0.9em) and $headingLineHeight (1.2, from template/settings).
$idsSubtitleHeight: 0.9 * $mainFontSize * 1.2;
// The two bar segments abut at a fractional pixel, which browsers round into a
// visible hairline. Overlapping them slightly makes the join seamless.
$idsBarOverlap: 2px;
// reveal.js centres the scaled slide in the viewport, so whenever the window's
// aspect ratio does not match the deck's, an empty band is left beside (or
// above) the slide and the bar would not reach the window's physical edge.
// Working out how wide that band is needs viewport / scale, and CSS cannot
// divide a length by a length -- which is why the hand-written IDS decks solve
// this in JavaScript. revealjs_presentation()'s template therefore publishes
// the band widths, in slide coordinates, as --ids-band-left / --ids-band-top,
// and the bar simply shifts out by that much. Falling back to 0px keeps this
// correct whenever the aspect ratios do match, and if the script never runs.
$idsBandLeft: var(--ids-band-left, 0px);
// revealjs_presentation() sets reveal.js' own `margin` option to 0, so that the
// slide box is the whole viewport and the orange bar can sit flush in its top
// left corner. That would otherwise leave the body content running edge to
// edge, so the breathing room reveal.js' margin used to provide is added back
// here as slide padding; the bar and the headings reach back out to the edge
// with matching negative margins below. The inset is the bar plus its gap, so
// body content lines up with the heading text rather than with the bar.
$idsContentInset: calc(#{$idsBarWidth} + #{$idsHeadingGap});
// The html prefix is solely about specificity: reveal's print styles
// (html.reveal-print .reveal .slides section { padding: 0 !important }) would
// otherwise beat this rule and flatten the inset on ?print-pdf pages. An html
// prefix ties that specificity, and since the theme is loaded after
// reveal.css, this rule wins both on screen and in print.
html .reveal .slides section:not(.stack) {
box-sizing: border-box !important;
padding-left: #{$idsContentInset} !important;
padding-right: #{$idsContentInset} !important;
}
// Body content is left aligned with the headings; the title frame keeps its
// own centered layout.
.reveal .slides section:not(.stack):not(.title-frame) {
text-align: left !important;
}
// reveal.js centers lists by making them inline-block; make them ordinary
// blocks so they line up with the headings.
//
// The markers are NOT native ::marker glyphs: browsers anchor outside-position
// markers at slightly different offsets per engine (and per scale), and even
// ::before font glyphs carry font-specific side bearings, so a padding(text)-
// based alignment of the bullet column with the heading text can never be
// pixel-exact everywhere. Instead we DRAW the markers as CSS boxes in
// absolutely positioned li::before rules. Geometry (all values in the item's
// own font size, so the hierarchy scales with the 0.8em per-level sizing from
// the NESTED LISTS section below):
//
// - item text starts at (list left edge) + 0.65em
// - the marker box starts exactly at the list's left edge; on content
// slides that edge coincides with the heading text's left edge, i.e. the
// bullet column is flush with the slide title, deterministically in every
// browser and at every window size
//
// For nested lists the ::before offset has to be divided by the 0.8 font-size
// factor, because the list's padding is computed in the PARENT item's font
// size while the ::before offset is computed in the (smaller) child size.
$idsListIndent: 0.65em;
$idsListShrink: 0.8;
$idsMarkerSize: 0.22em;
$idsMarkerTop: calc((1.3em - #{$idsMarkerSize}) / 2);
.reveal .slides section:not(.title-frame) ul,
.reveal .slides section:not(.title-frame) ol {
display: block !important;
text-align: left !important;
margin-left: 0 !important;
padding-left: $idsListIndent !important;
list-style: none !important;
}
.reveal .slides section:not(.title-frame) li {
position: relative !important;
}
.reveal .slides section:not(.title-frame) li::before {
position: absolute !important;
left: calc(-1 * #{$idsListIndent}) !important;
color: var(--r-list-bullet-color) !important;
}
.reveal .slides section:not(.title-frame) li li::before {
left: calc(-1 * #{$idsListIndent} / #{$idsListShrink}) !important;
}
// Unordered-list markers: drawn boxes (round dot, square, ring for deeper
// levels), vertically centered on the item's first line.
.reveal .slides section:not(.title-frame) ul > li::before {
content: "" !important;
top: $idsMarkerTop !important;
width: $idsMarkerSize !important;
height: $idsMarkerSize !important;
box-sizing: border-box !important;
border-radius: 50% !important;
background: var(--r-list-bullet-color) !important;
}
.reveal .slides section:not(.title-frame) ul ul > li::before {
border-radius: 0 !important; // square
}
.reveal .slides section:not(.title-frame) ul ul ul > li::before {
background: transparent !important; // ring
border: 0.055em solid var(--r-list-bullet-color) !important;
border-radius: 50% !important;
}
// Ordered lists: the CSS list-item counter honours the HTML start/value
// attributes, so pandoc's `start`/`value` lists keep their numbers. Numbers
// are anchored with their right edge $idsNumberGap away from the item text
// (a shrink-to-fit box; anchoring from the right instead of a fixed-width,
// right-aligned box, because over-wide numbers would otherwise overflow
// INTO the text). Longer numbers like "10." grow to the left.
$idsNumberGap: 0.3em;
.reveal .slides section:not(.title-frame) ol > li::before {
content: counter(list-item, decimal) "." !important;
left: auto !important;
right: 100% !important;
margin-right: $idsNumberGap !important;
}
// Checkbox (pandoc task) lists keep their checkboxes, no markers on top.
.reveal .slides section:not(.title-frame) ul.task-list li::before {
content: none !important;
}
// reveal.js centres code blocks (width: 90%; margin: auto); make them fill the
// slide's text column so they start on the same left edge as the headings.
.reveal .slides section:not(.title-frame) pre {
width: auto !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
// The IDS logo stays a slide-wide watermark (top right of every slide,
// including the title page). The SVG carries no internal padding of its own,
// so it needs an explicit inset from the slide's edges. That inset is shared
// by everything that sits in a corner of the slide -- IDS (+ partner) logo
// top right, website QR top left, funder logo bottom left, WGL membership
// logo bottom right -- and is used for both edges of each corner, so all
// four keep exactly the same distance to the slide's borders.
$idsLogoInset: 8px;
.reveal .slides {
// Second layer: the optional partner institution logo (--partner-logo is
// supplied by the template from the document's `partner_logo` yaml entry);
// paints as "none" without it, leaving a harmless empty layer.
background-image: url('https://corpora.ids-mannheim.de/slides/reveal.js.ids/images/IDS-Logo-2019.svg'),
var(--partner-logo, none);
background-repeat: no-repeat;
background-position: top #{$idsLogoInset} right #{$idsLogoInset},
top #{$idsLogoInset} right calc(#{$idsLogoInset} + var(--slide-height) * #{$idsLogoWidthRatio} + #{$idsPartnerGap});
background-size: calc(var(--slide-height) * #{$idsLogoWidthRatio}) auto,
auto calc(var(--slide-height) * #{$idsPartnerHeightRatio});
}
// The orange bar is drawn as a ::before on the headings rather than on the
// slide, in two segments: one behind the title and one behind the subtitle.
// Because each segment is sized as a percentage of its own heading's box, the
// bar always ends exactly at the bottom of the last heading -- it follows a
// subtitle when there is one, stops at the title when there isn't, and grows
// by itself when a heading wraps onto a second line. No fixed heights, and no
// JavaScript. Headings carry no vertical padding, so they sit as high on the
// slide as the bar does. Every rule is !important because this theme has to
// win against plugin- and document-level CSS loaded after it.
.reveal .slides section:not(.title-frame) > h1:first-child,
.reveal .slides section:not(.title-frame) > h2:first-child {
position: relative !important;
display: block !important;
text-align: left !important;
margin: 0 calc(-1 * #{$idsContentInset}) #{$idsHeadingSpacing} calc(-1 * #{$idsContentInset}) !important;
padding: 0 0 0 #{$idsContentInset} !important;
font-weight: var(--r-heading-font-weight) !important;
}
.reveal .slides section:not(.title-frame) > h1:first-child::before,
.reveal .slides section:not(.title-frame) > h2:first-child::before,
.reveal .slides section:not(.title-frame) > h2:first-child + h3::before {
content: "" !important;
position: absolute !important;
width: #{$idsBarWidth} !important;
// A flat fill rather than orange_bar.png: that image is two-toned (a lighter
// band across its top), so stretching it over each segment separately left a
// pale seam where the two met. The IDS reference decks draw a flat #f6a800.
background: #{$idsOrange} !important;
}
// Title segment: pulled out to the window's physical left edge.
.reveal .slides section:not(.title-frame) > h1:first-child::before,
.reveal .slides section:not(.title-frame) > h2:first-child::before {
top: 0 !important;
left: calc(-1 * #{$idsBandLeft}) !important;
height: 100% !important;
}
// A slide without a subtitle reserves the room one would have taken, so the
// bar keeps the same height and the body content starts at the same place on
// every slide. :has() is what lets us ask "is a subtitle coming?" in CSS; where
// it is unsupported such slides simply keep a title-height bar.
//
// The lone title is vertically CENTRED in its reserved bar: half of the
// reservation goes above the text as top padding (the bar segment, anchored
// to the heading box, moves up with it), and the bottom half stays in the bar
// extension plus margin. The space consumed below the bar is reduced by the
// same half, so body content starts where it always did.
.reveal .slides section:not(.title-frame) > h1:first-child:not(:has(+ h3)),
.reveal .slides section:not(.title-frame) > h2:first-child:not(:has(+ h3)) {
padding-top: calc((#{$idsHeadingSpacing} + #{$idsSubtitleHeight}) / 2) !important;
margin-bottom: calc((#{$idsHeadingSpacing} + #{$idsSubtitleHeight}) / 2 + #{$blockMargin}) !important;
}
.reveal .slides section:not(.title-frame) > h1:first-child:not(:has(+ h3))::before,
.reveal .slides section:not(.title-frame) > h2:first-child:not(:has(+ h3))::before {
height: calc(100% + (#{$idsHeadingSpacing} + #{$idsSubtitleHeight}) / 2) !important;
}
// Vertical balance when a subtitle follows: the orange strip between the
// title's baseline and the subtitle's cap height used to be title descent (16)
// + segment spacing (8) + subtitle leading (3) ≈ 27px, against only ≈ 11px of
// orange above the title's cap height. Moving the title 8px DOWN inside its
// box while REMOVING the 8px segment spacing makes the two margins equal
// (19px each) AND keeps the bar's total height and the body content's start
// position pixel-identical: box grows by 8, spacing drops by 8. The subtitle
// segment still rises (#{$idsHeadingSpacing} + #{$idsBarOverlap}) above its
// own box, so the bar stays seamless.
.reveal .slides section:not(.title-frame) > h1:first-child:has(+ h3),
.reveal .slides section:not(.title-frame) > h2:first-child:has(+ h3) {
padding-top: #{$idsHeadingSpacing} !important;
margin-bottom: 0 !important;
}
// The subtitle sits in the slide's normal text column, so its segment has to
// reach back out to the slide edge, and up over the gap to the title.
.reveal .slides section:not(.title-frame) > h2:first-child + h3 {
position: relative !important;
text-align: left !important;
margin-top: 0 !important;
margin-left: 0 !important;
margin-bottom: $blockMargin !important;
}
.reveal .slides section:not(.title-frame) > h2:first-child + h3::before {
top: calc(-1 * (#{$idsHeadingSpacing} + #{$idsBarOverlap})) !important;
left: calc(-1 * (#{$idsContentInset} + #{$idsBandLeft})) !important;
height: calc(100% + #{$idsHeadingSpacing} + #{$idsBarOverlap}) !important;
}
// Section-divider slides: a level 1 heading alone on a slide (pandoc marks
// these .level1). The IDS reference decks centre that title on the slide while
// the bar stays in its usual top left corner, so here the bar cannot hang off
// the heading -- it is painted on the slide itself, at the height it has on
// every other slide, and the heading gets none of the top-left treatment.
$idsTitleHeight: 1.35 * $mainFontSize * 1.2;
$idsBarBlockHeight: $idsTitleHeight + $idsHeadingSpacing + $idsSubtitleHeight;
.reveal .slides section.level1:not(.title-frame) {
height: 100% !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
}
.reveal .slides section.level1:not(.title-frame)::before {
content: "" !important;
position: absolute !important;
top: 0 !important;
left: calc(-1 * #{$idsBandLeft}) !important;
width: #{$idsBarWidth} !important;
height: #{$idsBarBlockHeight} !important;
background: #{$idsOrange} !important;
}
.reveal .slides section.level1:not(.title-frame) > h1:first-child {
text-align: center !important;
margin: 0 !important;
padding: 0 !important;
}
.reveal .slides section.level1:not(.title-frame) > h1:first-child::before {
content: none !important;
}
// Define additional color effects based on Dracula spec
// https://spec.draculatheme.com/
:root {
--r-bold-color: #{$idsOrange};
--r-list-bullet-color: #{$listBulletColor};
}
.reveal {
// Bold ("highlighted") text gets the orange colour AND the condensed Fira
// Sans face, as in the IDS reference decks -- the lighter weight and 90%
// size keep it from dominating the serif body text.
strong, b {
font-family: "Fira Sans Condensed", sans-serif;
font-weight: 600;
font-size: 90%;
color: var(--r-bold-color);
}
// Dracula colored list bullets and numbers
ul, ol {
li::marker {
color: var(--r-list-bullet-color) !important;
}
}
}
// Nested list items are set progressively smaller, both to emphasise the
// hierarchy and to keep deeply nested lists from visually competing with the
// first level. The em size compounds down the nesting levels, so each deeper
// level is 80% of its parent (level 2: 80%, level 3: 64%, level 4: 51%).
// Markers and the hanging indentation (padding-left: 0.7em above) scale with
// the text automatically.
.reveal li li {
font-size: 0.8em;
}
// Description lists: dt in orange Fira Sans Condensed, dd indented.
.reveal dl {
font-size: 0.62em;
line-height: 1.25;
}
.reveal dt {
font-weight: 700;
margin-top: 0.35em;
font-family: "Fira Sans Condensed", sans-serif;
color: $idsOrange;
}
.reveal dd {
margin: 0 0 0 1.2em;
color: #444;
}
/*********************************************
* FOOTER
*********************************************/
#ids-footer:not(title-slide) {
opacity: 1;
background: white;
color: #444444;
border-top: dotted orange 2px;
transition: opacity 800ms ease-in-out;
position: fixed;
height: 6%;
line-height: 6%;
z-index: -20;
width: 100%;
letter-spacing: 0em;
text-align: center;
display: table;
}
#ids-footer span {
height: 100%;
line-height: 100%;
z-index: -20;
font-size: 1.8vh;
font-family: "Fira Sans Condensed", "Fira Sans", "Roboto Condensed", "League Gothic", Impact, sans-serif;
display: inline-block;
display: table-cell;
vertical-align: middle;
}
/* Bottom position for the IDS-Footer footer when both progress bar and TOC-Progress are visible */
div.progress[style="display: block;"] ~ #ids-footer {
bottom: calc(3px + 0vh);
}
/* Bottom position for the IDS-Footer footer when TOC-Progress is visible */
#ids-footer {
bottom: 3px;
}
#ids-footer a {
color: #555555;
}
/* Bottom position for the IDS-Footer footer when progress bar is visible */
div.progress[style="display: block;"] ~ footer:last-of-type#ids-footer {
bottom: 3px;
}
/* Bottom position for the IDS-Footer footer when neither progress bar nor TOC-Progress are visible */
footer:last-of-type#ids-footer {
bottom: 0px;
}
/* Make IDS-Footer invisible if explicitly indicated */
.no-ids-footer #ids-footer {
opacity: 0;
transition: opacity 800ms ease-in-out;
}
.title-frame #ids-footer {
opacity: 0;
transition: opacity 800ms ease-in-out;
}
.no-toc-progress #ids-footer {
opacity: 0;
transition: opacity 800ms ease-in-out;
}
/* Make IDS-Footer invisible in overview mode */
.overview #ids-footer {
opacity: 0;
transition: opacity 800ms ease-in-out;
}
/* In print, the footer's negative stacking drops it behind the .pdf-page
* backgrounds (z-index 1); lift it above them. position: fixed repeats it at
* the bottom of every printed page. */
html.reveal-print #ids-footer {
z-index: 100 !important;
}
// reveal's print CSS gives every .pdf-page z-index:1, which forms a separate
// stacking context per page. The slide-number-pdf lives INSIDE such a page, so
// its own z-index only competes within the page: the footer (z-index 100 at
// root level) always paints over it, and raising the number's z-index alone
// cannot help. Remove the per-page stacking context in print (the pages are
// separated by page-break-after:always anyway, so nothing needs stacking), and
// the number's z-index 200 wins against the footer globally. Position stays
// the theme's screen rule (right:29px / bottom:22px), which puts the number
// inside the footer band with its white background cutting the dotted line --
// the same look as on screen.
html.reveal-print .reveal .slides .pdf-page {
z-index: auto !important;
}
// On screen the number is flanked by the arrow buttons, so its slightly raised
// baseline reads as deliberate; in print it shares the footer band with the
// author/title/date line, whose vertically centered text has its baseline
// ~19px above the page bottom. The number's screen offset (bottom:22px, 14px
// font from reveal's print rule) puts its baseline ~25px up. 15px aligns the
// two baselines. Print-only: the screen rule keeps its 22px.
html.reveal-print div.slide-number-pdf {
z-index: 200 !important;
bottom: 15px !important;
}
// On screen the bar segments shift left by --ids-band-left so the bar reaches
// the window's physical edge when the slide is pillarboxed. In print there are
// no bands (.pdf-page == slide box), and if the band values are ever stale
// (e.g. an outdated template script), a nonzero band-left would push the
// segments outside the pdf-page, whose overflow:hidden then clips them.
// Pin the geometry explicitly for print instead of trusting the custom
// property: title segments start at the heading's (== pdf-page's) left edge,
// the subtitle segment (which lives in the text column, inset by
// $idsContentInset) reaches back out by exactly the inset, and the level1
// divider bar starts at the section's left edge. Widths stay the normal bar
// width, so the visible result is pixel-identical to the on-screen bar.
html.reveal-print .reveal .slides section:not(.title-frame) > h1:first-child::before,
html.reveal-print .reveal .slides section:not(.title-frame) > h2:first-child::before {
left: 0 !important;
}
html.reveal-print .reveal .slides section:not(.title-frame) > h2:first-child + h3::before {
left: calc(-1 * #{$idsContentInset}) !important;
}
html.reveal-print .reveal .slides section.level1:not(.title-frame)::before {
left: 0 !important;
}
// The WGL membership logo sits at bottom:10px of the title frame -- inside
// the footer's ~46px band on print pages (the footer is force-shown on every
// page in print view and cannot be hidden per page, position:fixed). Lift the
// logo above the footer in print only; the screen layout stays put.
html.reveal-print .reveal .slides section.title-frame {
background-position: right #{$idsLogoInset} bottom 55px;
}
// Like the orange bar/IDS logo above, this is painted on the slide itself
// (rather than on .slide-background-content, which spans the raw,
// unscaled viewport) so it stays pinned to the title slide's true
// bottom-right corner instead of the browser window's. Its margin mirrors
// the IDS logo's, so the two sit on one shared inset.
.reveal .slides section.title-frame {
background-image: url("https://corpora.ids-mannheim.de/slides/reveal.js.ids/images/Mitglied_WGL_transparent.svg");
background-repeat: no-repeat;
background-position: right #{$idsLogoInset} bottom #{$idsLogoInset};
background-size: calc(var(--slide-height) * 0.1) auto;
/* full slide height, so "bottom" really is the slide's bottom edge */
height: 100%;
}
// qrlink() codes placed anywhere else in a deck: qr_svg_fit() crops the svg
// to the dark modules, so the quiet zone the code needs to stay scannable is
// this padding (which also keeps a code readable on a dark background).
.reveal a.qrcode {
display: inline-block;
padding: 0.5em;
background: #fff;
}
// Website QR code and funder logo on the title slide (document options
// `website` and `funder_logo`): top-left and bottom-left corners. Like the
// two logos on the right, they keep $idsLogoInset to both slide edges --
// measured to the visible ink, so that all four corners look alike. Both are
// DOM elements injected into the title frame by the pandoc template (the QR
// itself is generated in R by qrlink()); absolute positioning sticks to the
// slide, because reveal.js positions the sections themselves.
//
// qrlink() crops the svg to the dark modules, so the quiet zone the code
// needs to stay scannable is this white plate's padding -- which is also
// what puts the modules themselves at $idsLogoInset from the slide's edges,
// the plate sitting flush in the corner (invisible on the white slide).
.reveal .slides section.title-frame .title-qr {
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
width: calc(var(--slide-height) * 0.28);
padding: #{$idsLogoInset};
background: #fff;
}
.reveal .slides section.title-frame .title-qr a.qrcode,
.reveal .slides section.title-frame .title-qr svg {
display: block;
width: 100%;
height: auto;
margin: 0;
// the quiet zone comes from the plate around it here
padding: 0;
}
.reveal .slides section.title-frame img.funder-logo {
position: absolute;
left: #{$idsLogoInset};
bottom: #{$idsLogoInset};
height: calc(var(--slide-height) * 0.07);
// reveal.js gives images a vertical margin, which for an absolutely
// positioned one would add itself to the inset above.
margin: 0;
width: auto;
}
// Lift the funder logo above the print footer band, like the WGL logo above
html.reveal-print .reveal .slides section.title-frame img.funder-logo {
bottom: 55px;
}
// The navigation chrome is hidden on the title slide (the template toggles
// the ids-title-plain class when the title frame is the current slide). Use
// opacity/visibility rather than display:none so the transition out of the
// title slide fades the chrome in instead of popping it up, and so reveal.js'
// own controls bookkeeping keeps working underneath.
html.ids-title-plain .reveal .controls,
html.ids-title-plain .reveal .slide-number,
html.ids-title-plain .reveal .slide-menu-button {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
.reveal .controls,
.reveal .slide-number,
.reveal .slide-menu-button {
transition: opacity 0.4s;
}
/*********************************************
* SLIDES MENU
*********************************************/
// The menu plugin copies .reveal's computed font-family onto .slide-menu as an
// inline style (and its own CSS is loaded after the theme), so without
// !important here the menu would come out in the Libertinus serif body face.
// Fira Sans Condensed is the IDS sans for navigation/UI text, and its narrow
// glyphs keep long (German) slide titles on one line.
.slide-menu-wrapper .slide-menu {
font-family: "Fira Sans Condensed", sans-serif !important;
}
// Widen the menu a little over the plugin's 300px default -- but only the
// default: a width the user picked via the menu-width option maps to one of
// the plugin's width classes (or an inline style), which must keep winning.
.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) {
width: 372px !important;
}
// Tighter, less wasteful rows than the plugin's 10px 18px padding with a 12px
// icon gap: the icon column and generous side padding eat exactly the width
// the titles need.
.slide-menu-wrapper .slide-menu-item,
.slide-menu-wrapper .slide-menu-item-vertical {
padding: 6px 12px !important;
line-height: 1.3 !important;
}
.slide-menu-wrapper .slide-menu-item-vertical {
padding-left: 26px !important;
}
// Wrapped titles: make the row a flex line so the second line aligns with the
// first instead of sliding under the bullet/circle icon. The icon sits on the
// first line's text baseline; the title column takes the remaining width and
// wraps within itself.
.slide-menu-wrapper .slide-menu-item,
.slide-menu-wrapper .slide-menu-item-vertical {
display: flex !important;
align-items: baseline !important;
}
.slide-menu-wrapper .slide-menu-item-title {
flex: 1 !important;
min-width: 0 !important;
}
.slide-menu-wrapper .slide-menu-item i.far,
.slide-menu-wrapper .slide-menu-item i.fas,
.slide-menu-wrapper .slide-menu-item-vertical i.far,
.slide-menu-wrapper .slide-menu-item-vertical i.fas,
.slide-menu-wrapper .slide-menu-item svg.svg-inline--fa,
.slide-menu-wrapper .slide-menu-item-vertical svg.svg-inline--fa {
padding-right: 8px !important;
}
// Top-level (section) entries in bold, marking the hierarchy as the indented
// sub-slides alone do now. Note the Google Fonts import only ships Fira Sans
// Condensed in 300/400/700/800 -- there is no 600.
.slide-menu-wrapper .slide-menu-item {
font-weight: 700 !important;
}
// Current slide in the IDS accent colour, matching the slide-number and the
// orange bar.
.slide-menu-wrapper .active-menu-panel li.active {
color: #{$idsOrange} !important;
}
/*
* Menu controls
*/
body .reveal .slide-menu-button {
color: #aaaaaa !important;
position: fixed;
left: 30px;
bottom: 2%;
vertical-align: middle;
z-index: 30;
font-size: 2vh;
}
#customcontrols > ul {
color: #aaaaaa !important;
position: fixed;
left: 50px;
bottom: 2% !important;
vertical-align: middle;
z-index: 30;
font-size: 2vh;
}
@media only screen and (min-width: 500px) {
#customcontrols > ul {
bottom: 2% !important;
}
}
.reveal .controls .controls-arrow {
position: relative;
width: 3.6em;
height: 3.6em;
bottom: -12px;
right: -4px;
}
.reveal h3, h4, h5, h6 {
text-transform: none !important;
}
.reveal h3, h4, h5, h6 {
text-transform: none !important;
}
.reveal h2 + h3 {
margin-top: -0.5em !important;
}
.title-frame h1,
.title-frame h2 {
margin: 0 0 0 0;
background: rgb(246, 168, 0);
color: white;
font-family: "Fira Sans Condensed", "Roboto Condensed", Impact, sans-serif;
font-weight: 600;
line-height: 1.2;
letter-spacing: 0.05ex;
text-transform: uppercase;
width: 100%;
margin-top: .5em;
padding-top: .5em;
font-size: 1.75em;
margin-left: 0;
text-align: center;
text-shadow: none;
word-wrap: break-word;
}
.title-frame .author {
font-family: "Fira Sans Condensed", sans-serif;
font-weight: 400;
color: #657b83;
margin-top: 10vh;
}
.title-frame .place {
font-family: "Fira Sans Condensed", sans-serif;
margin-top: 40px;
font-weight: 400;
color: #657b83;
}
.title-frame h2 {
margin-top: -3px;
margin-bottom: 1em;
padding-bottom: .5em;
font-size: 1em;
}
/*********************************************
* TABLES
*********************************************/
th {
color: rgb(246, 168, 0);
}
table {
font-family: 'Fira Sans Condensed', sans-serif;
font-weight: 400;
font-size: 16px;
// Fira Sans Condensed ships proportional figures by default, so the digits
// in neighbouring rows do not line up; tabular numbers (tnum) fix the digit
// widths and align numeric table columns vertically.
font-variant-numeric: tabular-nums;
}
.reveal table.dataTable {
border: #aaaaaa 1px solid;
border-collapse: collapse;
}
.reveal table.dataTable td {
border: #aaaaaa 1px solid;
border-collapse: collapse;
}
.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 {
display: none;
}
.caption {
font-family: 'Fira Sans Condensed', sans-serif;
font-weight: 400;
font-size: 16px;
text-align: center;
}
/*
table.display td { white-space: nowrap; }
*/
.dt-buttons, .dataTables_filter {
margin-top: 10pt;
}
/* Sort Arrows in DataTables */
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 {
right: 0 !important;
line-height: 80% !important;
}
/*********************************************
* BIBLIOGRAPHY
*********************************************/
.reveal .references {
font-family: "Fira Sans Condensed", sans-serif;
font-size: 16px;
text-align: left;
margin-top: 10px;
max-height: 510px;
font-weight: 400;
color: #253b43;
overflow-y: auto;
}
.hanging-indent > .csl-entry {
padding-left: 22px ;
text-indent: -22px ;
}
// .references scopes these above pandoc's CSL defaults (div.csl-entry), which
// otherwise win on specificity and pin margin-bottom to 0em.
.references .csl-entry {
color: #888888;
margin-bottom: 0.5em;
}
// "Authors (Year):" as a bold dark first line; the theme template's JS wraps
// the leading text of each entry in .csl-authors-year (see default.html) --
// which part of an entry citeproc wraps in spans depends on the entry type, so
// a CSS-only break cannot place it reliably.
.csl-entry .csl-authors-year {
display: block;
font-weight: bold;
color: #4d616b;
}
.reveal code.sourceCode:last-child + pre {
height: 800px !important;
}
/*********************************************
* FULLSCREEN TOGGLE
*********************************************/
// Small fixed toggle for touch devices (script injected by default.html):
// phones have no F11 and the browser chrome eats slide pixels. Hidden on
// pointer devices (F11 exists there) and whenever the Fullscreen API is
// unavailable -- the script also removes it then. Same muted look and column
// as the slide menu button, one slot above it.
#ids-fullscreen {
display: none;
position: fixed;
left: 30px;
bottom: 6%;
z-index: 30;
width: 28px;
height: 28px;
border: 0;
padding: 0;
cursor: pointer;
opacity: 0.55;
// Feather-style corner brackets; gray idle, IDS orange while fullscreen
// (the two data URIs differ only in the stroke colour).
background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 3H5a2 2 0 0 0-2 2v3'/%3E%3Cpath d='M16 3h3a2 2 0 0 1 2 2v3'/%3E%3Cpath d='M8 21H5a2 2 0 0 1-2-2v-3'/%3E%3Cpath d='M16 21h3a2 2 0 0 0 2-2v-3'/%3E%3C/svg%3E") center / contain no-repeat;
&:active,
&:focus-visible {
opacity: 0.9;
}
&.is-fullscreen {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f6a800' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 3H5a2 2 0 0 0-2 2v3'/%3E%3Cpath d='M16 3h3a2 2 0 0 1 2 2v3'/%3E%3Cpath d='M8 21H5a2 2 0 0 1-2-2v-3'/%3E%3Cpath d='M16 21h3a2 2 0 0 0 2-2v-3'/%3E%3C/svg%3E");
}
}
// Only touch devices get the button; desktops keep their F11.
@media (hover: none) and (pointer: coarse) {
#ids-fullscreen {
display: block;
}
}
// position:fixed elements repeat on every printed page -- never print it.
html.reveal-print #ids-fullscreen {
display: none !important;
}
.reveal .controls .controls-arrow:after, .reveal .controls .controls-arrow:before {
width: 13px !important; /* size */
height: 4px; /* line width */
}
.reveal .controls {
display: none;
position: absolute;
top: auto;
bottom: -8px;
right: 16px;
left: auto;
z-index: 11;
/* color: #000;*/
pointer-events: none;
font-size: 8px;
}
.reveal .controls .controls-arrow {
position: relative;
height: 3.6em;
width: 1.2em; /* distance betwee arrows */
bottom: 0;
right: 0;
}
.reveal div.slide-number {
text-align: center;
width: 2em;
position: absolute;
display: block;
right: 29px;
bottom: 22px;
z-index: 31;
font-family: "Fira Sans Condensed", sans-serif;
font-size: 18px;
line-height: 1;
background-color: white;
color: #666;
padding: 0;
}
/*********************************************
* SPEAKER NOTES OVERLAY (touch devices)
*********************************************/
#ids-notes {
display: none;
position: fixed;
left: 70px;
bottom: 6%;
z-index: 30;
width: 28px;
height: 28px;
border: 0;
padding: 0;
cursor: pointer;
opacity: 0.55;
background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'/%3E%3C/svg%3E") center/contain no-repeat;
}
#ids-notes:active, #ids-notes:focus-visible {
opacity: 0.9;
}
#ids-notes.is-open {
opacity: 0.9;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f6a800' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'/%3E%3C/svg%3E");
}
#ids-transcript-btn {
display: none;
position: fixed;
left: 110px;
bottom: 6%;
z-index: 30;
width: 28px;
height: 28px;
border: 0;
padding: 0;
cursor: pointer;
opacity: 0.55;
background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='8' y1='6' x2='21' y2='6'/%3E%3Cline x1='8' y1='12' x2='21' y2='12'/%3E%3Cline x1='8' y1='18' x2='21' y2='18'/%3E%3Cline x1='3' y1='6' x2='3.01' y2='6'/%3E%3Cline x1='3' y1='12' x2='3.01' y2='12'/%3E%3Cline x1='3' y1='18' x2='3.01' y2='18'/%3E%3C/svg%3E") center/contain no-repeat;
}
#ids-transcript-btn:active, #ids-transcript-btn:focus-visible, #ids-transcript-btn.is-open {
opacity: 0.9;
}
#ids-transcript-btn.is-open {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f6a800' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='8' y1='6' x2='21' y2='6'/%3E%3Cline x1='8' y1='12' x2='21' y2='12'/%3E%3Cline x1='8' y1='18' x2='21' y2='18'/%3E%3Cline x1='3' y1='6' x2='3.01' y2='6'/%3E%3Cline x1='3' y1='12' x2='3.01' y2='12'/%3E%3Cline x1='3' y1='18' x2='3.01' y2='18'/%3E%3C/svg%3E");
}
@media (hover: none) and (pointer: coarse) {
#ids-notes, #ids-transcript-btn {
display: block;
}
}
html.reveal-print #ids-notes, html.reveal-print #ids-transcript-btn {
display: none !important;
}
#ids-notes-overlay {
position: fixed;
inset: 0;
z-index: 100;
background: #fff;
color: #444444;
font-family: "Fira Sans", "Fira Sans Condensed", sans-serif;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right))
max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));
}
#ids-notes-overlay[hidden] {
display: none;
}
#ids-notes-header {
display: flex;
align-items: baseline;
gap: 12px;
border-bottom: 1px solid #e0e0e0;
margin-bottom: 16px;
padding-bottom: 8px;
}
#ids-notes-timing {
flex-shrink: 0;
color: #f6a800;
font-weight: bold;
white-space: nowrap;
}
#ids-notes-title {
flex-grow: 1;
margin: 0;
font-size: 1.1em;
}
#ids-notes-close {
flex-shrink: 0;
border: 0;
background: none;
color: #888888;
font-size: 1.2em;
cursor: pointer;
padding: 8px;
margin: -8px;
}
#ids-notes-content {
font-size: 20px;
line-height: 1.5;
}
#ids-notes-content em {
color: #888888;
}
/*********************************************
* OVERVIEW / TOC SLIDES
*********************************************/
/* The auto-generated TOC lists the chapters with their numbers as
.ids-toc-number spans in the marker colour, prepended to the entry
titles: the enumeration therefore starts flush with the slide heading
(the drawn ol/ul markers are suppressed for the top-level entries;
sub-headings below their chapters keep their bullets). Entries stay at
the normal slide body size and keep the theme's link colour, so they
read as the navigation links they are. Only the denser two-column
variant with sub-headings is scaled down. */
.reveal .slides section:not(.title-frame) .ids-overview-toc {
padding-left: 0 !important;
}
.reveal .slides section:not(.title-frame) .ids-overview-toc > li::before {
content: none !important;
}
.reveal .ids-overview-toc .ids-toc-number {
color: var(--r-list-bullet-color);
}
.reveal .ids-overview-toc {
list-style: none;
margin: 0.2em 0 0 0;
padding: 0;
line-height: 1.35;
}
.reveal .ids-overview-toc > li {
margin: 0.45em 0;
font-weight: bold;
}
.reveal .ids-overview-toc ul {
list-style: none;
margin: 0.1em 0 0.2em 0;
padding: 0 0 0 1.1em;
font-weight: normal;
}
.reveal .ids-overview-toc.with-subheadings {
columns: 2;
column-gap: 2.5em;
font-size: 0.8em;
}
.reveal .ids-overview-toc.with-subheadings > li {
break-inside: avoid;
}
.reveal .ids-overview-toc ul li {
margin: 0.18em 0;
}
/*********************************************
* TRANSCRIPT / READ-ALOUD VIEW ('r')
*********************************************/
#ids-transcript {
position: fixed;
inset: 0;
z-index: 90;
background: #fff;
color: #444444;
font-family: "Fira Sans", "Fira Sans Condensed", sans-serif;
font-size: 18px;
line-height: 1.5;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: max(32px, env(safe-area-inset-top)) max(40px, env(safe-area-inset-right))
max(32px, env(safe-area-inset-bottom)) max(40px, env(safe-area-inset-left));
}
#ids-transcript[hidden] {
display: none;
}
#ids-transcript .ids-transcript-slide {
max-width: 900px;
margin: 0 auto 2.5em auto;
}
#ids-transcript h1, #ids-transcript h2 {
color: var(--r-heading-color);
margin: 0 0 0.4em 0;
}
#ids-transcript h1 { font-size: 1.4em; }
#ids-transcript h2 { font-size: 1.2em; }
#ids-transcript .fragment {
opacity: 1;
visibility: visible;
}
#ids-transcript .ids-transcript-notes {
border-left: 3px solid #f6a800;
padding: 0.2em 0 0.2em 0.8em;
margin-top: 0.8em;
color: #666;
}
#ids-transcript .ids-transcript-notes:empty {
display: none;
}
#ids-transcript img, #ids-transcript video, #ids-transcript iframe {
max-width: 100%;
}
// The title slide's branding is cloned into the transcript along with the
// rest of the slide, but outside .reveal, where neither the title frame's
// sizing rules nor the svg's own (absent) intrinsic dimensions constrain it
// -- both would fill the transcript's whole width. Give them a size that
// suits a page one reads rather than presents: the QR stays tappable and
// scannable, the funder logo shrinks to a line of text.
#ids-transcript .title-qr {
box-sizing: border-box;
width: 140px;
max-width: 40%;
padding: #{$idsLogoInset};
background: #fff;
}
#ids-transcript .title-qr a.qrcode,
#ids-transcript .title-qr svg {
display: block;
width: 100%;
height: auto;
padding: 0;
}
#ids-transcript img.funder-logo {
height: 2.5em;
width: auto;
margin: 0.6em 0;
}