/* =============================================================================
   agSlides.css
   House stylesheet for generated slide decks.

   Layered ON TOP of a stock reveal.js theme, not instead of it. The generated
   deck links, in this order:

       reveal/dist/reset.css
       reveal/dist/reveal.css
       reveal/dist/theme/white.css      <- stock theme does the structural work
       agSlides.css                     <- this file, appearance only

   Because it loads last, plain rules here win over the stock theme without
   needing !important.

   -----------------------------------------------------------------------------
   STATUS

   Contains fit and layout (1-5b), the University brand as ported from the old
   PresentationTemplate system (1b), a LIGHT AND DARK theme switched by a
   toggle (1c), quotations with attributions (5d), the four SEMANTIC BLOCKS
   (6), and the learning-outcomes panel that opens every deck (end of 6).

   Colour is handled in two layers. Section 0 names the palette; section 1b
   names ROLES (--ag-heading, --ag-emphasis, --ag-marker and so on) pointing at
   it. Every rule below refers to a role, never to a palette colour directly -
   which is what lets section 1c switch the whole deck to dark by re-pointing
   seven variables. If you add a rule, use a role.

   The title slide is the old system's cover, ported in 1e.

   Still to be written: the slide classes (.card, .stat, .grid, .timeline,
   .team, .closing).

   Corrected 2026-09-11: this list also named the deck footer, which is in
   fact done - see the .ag-footer rules below.
   ========================================================================== */


/* -----------------------------------------------------------------------------
   0. PALETTE
   -----------------------------------------------------------------------------
   University of Sheffield colours, lifted from
   PresentationTemplate/presentation_files/pres_global.css so the two systems
   cannot drift. Defined here as one source of truth; currently only used by
   the semantic blocks in section 6.
----------------------------------------------------------------------------- */

:root {
  --ag-brand-violet:    #440099;
  --ag-dark-violet:     #24125E;
  --ag-electric-violet: #7000FF;
  --ag-powder-violet:   #A78CFA;
  --ag-pale-violet:     #C6BBFF;
  --ag-wave-white:      #F8F8F9;
  --ag-midnight-black:  #131E29;

  /* Background washes. Plain rgba rather than color-mix() so this works in
     older browsers as well as current ones. */
  --ag-tint-violet: rgba(198, 187, 255, 0.22);   /* pale violet   */
  --ag-tint-tip:    rgba(112,   0, 255, 0.07);   /* electric violet */
}


/* -----------------------------------------------------------------------------
   1. FIT
   -----------------------------------------------------------------------------
   reveal.js uses a FIXED canvas, scaled to fit the window. It does not shrink
   content to fit - anything taller than the canvas is simply clipped. So the
   only real levers are canvas size, font size and spacing.

   The canvas is set in build.html to 1280x720 (16:9, matching a lecture
   theatre projector). reveal's own default is 960x700, which is roughly 4:3.

   Base font size is the dominant lever, by a long way. Measured against
   template.md on a 1280x720 canvas:

       stock white (42px)   16 of 27 slides overflowed, worst by 715px
       30px                  1 of 27 slides overflowed, worst by 3px

   THIS IS THE ONE NUMBER TO TUNE. Raise it for a bigger room and fewer words;
   lower it if slides are running long. Everything else in reveal is sized in
   em, so changing it rescales headings, lists and code together.
----------------------------------------------------------------------------- */

:root {
  --r-main-font-size: 30px;

  /* Vertical rhythm between blocks. reveal's stock value is generous, which
     compounds with a large font to fill a slide surprisingly fast. */
  --r-block-margin: 16px;

  /* The canvas dimensions, which are SET IN build.html - repeated here because
     full-bleed slides need them in CSS and there is no way to read reveal's
     config from a stylesheet. If you change the canvas, change both. */
  --ag-canvas-w: 1280px;
  --ag-canvas-h: 720px;
}

/* Belt and braces: some stock themes set .reveal's font-size directly rather
   than through the custom property, which would override :root above. */
.reveal { font-size: var(--r-main-font-size); }


/* -----------------------------------------------------------------------------
   2. PER-SLIDE ESCAPE HATCHES
   -----------------------------------------------------------------------------
   For the occasional slide that genuinely needs more on it than the defaults
   allow. Both are used as heading attributes and need no parser support:

       ## Summary of results {.smaller}
       ## Full nomenclature {.scrollable}

   Prefer splitting a slide in two. Reach for these when you cannot.
----------------------------------------------------------------------------- */

/* Roughly 25% more content, still readable from the back of a room. */
.reveal .slides section.smaller {
  font-size: 0.78em;
}

/* Last resort: let the slide scroll rather than clip. Fine for reference and
   nomenclature slides nobody reads from the back; poor for anything you
   actually present, because the audience cannot scroll your projection. */
.reveal .slides section.scrollable {
  max-height: 100%;
  overflow-y: auto;
}


/* -----------------------------------------------------------------------------
   3. LAYOUT
   -----------------------------------------------------------------------------
   The ::: {.columns} construct emits plain divs; the widths come through as
   inline styles from the markdown. Laying them out side by side is this
   file's job - without the rule below, columns stack vertically.
----------------------------------------------------------------------------- */

.reveal .columns {
  display: flex;
  gap: 1.5em;
  align-items: flex-start;
  text-align: left;
}

/* Columns carry their own width inline, so this only stops flex shrinking
   them below it. */
.reveal .column {
  flex: 0 1 auto;
  min-width: 0;
}

/* A column's first heading should not carry reveal's usual large top margin,
   or the two columns start at visibly different heights. */
.reveal .column > :first-child {
  margin-top: 0;
}


/* -----------------------------------------------------------------------------
   4. EMBEDDED TEACHING DEMOS
   -----------------------------------------------------------------------------
   ::: {.demo src="..."} emits an iframe. Give it a sane default size so a demo
   slide is usable before anyone thinks about styling it.
----------------------------------------------------------------------------- */

.reveal iframe.demo-frame {
  display: block;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  border: 0;
  background: #fff;
}


/* -----------------------------------------------------------------------------
   5. SMALL FIT ADJUSTMENTS
   -----------------------------------------------------------------------------
   Content types that are disproportionately tall at stock sizing.
----------------------------------------------------------------------------- */

/* Code blocks default to a size that eats a whole slide. */
.reveal pre {
  width: 100%;
  margin: var(--r-block-margin) 0;
  font-size: 0.5em;
  line-height: 1.3;
}

/* Tables of more than a few rows are the other common overflow cause. */
.reveal table {
  font-size: 0.75em;
}
.reveal table th,
.reveal table td {
  padding: 0.25em 0.6em;
}

/* Display equations. A momentum equation written out in components is far
   wider than the 1280px canvas, and MathJax no more shrinks to fit than reveal
   does - it would simply run off the side of the slide.

   Capping the SVG width and letting the height follow scales the whole
   equation down proportionally, so a long equation gets smaller rather than
   getting cut off. Height shrinks with it, which also buys back vertical room
   on a slide carrying several equations.

   The 0.9em is a starting point rather than a law: display maths at full body
   size is larger than it needs to be on a projected slide. Lower it if a
   derivation slide is tight, raise it for a single hero equation. */
.reveal mjx-container[display="true"] {
  max-width: 100%;
  font-size: 0.9em;
}

.reveal mjx-container[display="true"] svg {
  max-width: 100%;
  height: auto;
}

/* Definition lists have no stock styling in reveal at all. */
.reveal dl { text-align: left; }
.reveal dt { font-weight: 700; margin-top: 0.6em; }
.reveal dd { margin: 0 0 0.2em 1.2em; }

/* Figures. reveal styles neither <figure> nor <figcaption>, and a bare
   <figure> carries a browser default margin that shoves the image off centre.

   -----------------------------------------------------------------------------
   SIZING, which is the whole problem with images on slides.

   reveal never shrinks content to fit. Anything taller than the 720px canvas
   is simply clipped, so an image has to be capped before it overflows - and
   how much room it actually has depends entirely on what else is on the slide.
   A single figure on a full-width slide can be large; two figures stacked in a
   half-width column cannot. A fixed cap cannot serve both, and making the
   author pick per slide is exactly the wrong answer.

   :has() lets the stylesheet count what is sharing the space and size
   accordingly, so this stays automatic:

       one figure, full width         420px
       one figure inside a column     340px
       two figures sharing a box      200px
       three or more                  120px

   The numbers come from the 720px canvas: take off the slide title, a column
   heading, a line or two of text, and one caption per figure, then divide what
   is left between the images. They are deliberately a little conservative,
   because a clipped slide is a worse failure than a slightly small image.

   px rather than vh throughout, because reveal scales a fixed canvas - a vh
   would be measured against the real browser window instead, and the same deck
   would lay out differently on every screen.

   :has() is already relied on elsewhere in this file (the title-slide footer
   rule). Where it is unsupported, images simply keep the single-figure cap:
   smaller than ideal in a crowded column, never broken. */
.reveal figure { margin: 0 auto; text-align: center; }

.reveal figure :is(img, object) {
  display: block;
  margin: 0 auto;
  max-width: 100%;
  max-height: 420px;
  width: auto;
  object-fit: contain;
}

/* Inside a column there is a slide title, a column heading and usually a line
   of text above the figure. */
.reveal .column figure :is(img, object) { max-height: 340px; }

/* Two or more figures stacked together divide the remaining space. Matching on
   sibling figures means a figure in each of two columns is NOT caught by this:
   those are not sharing a box, and each still gets the full column cap.

   A quotation is also a <figure> (figure.quote, section 5d) but holds no
   image, so it must not count - otherwise one picture and one quote on a
   slide would shrink the picture to the two-figure cap. Hence :not(.quote). */
.reveal .column:has(figure:not(.quote) ~ figure:not(.quote)) figure :is(img, object),
.reveal section:has(figure:not(.quote) ~ figure:not(.quote)) > figure :is(img, object) {
  max-height: 200px;
}

.reveal .column:has(figure:not(.quote) ~ figure:not(.quote) ~ figure:not(.quote)) figure :is(img, object),
.reveal section:has(figure:not(.quote) ~ figure:not(.quote) ~ figure:not(.quote)) > figure :is(img, object) {
  max-height: 120px;
}

.reveal figcaption {
  margin-top: 0.4em;
  font-size: 0.62em;
  line-height: 1.35;
  color: var(--ag-body-text);
  opacity: 0.75;
}


/* -----------------------------------------------------------------------------
   1b. BRAND  -  ported from the old PresentationTemplate system
   -----------------------------------------------------------------------------
   Source: PresentationTemplate/presentation_files/pres_global.css and
   pres_normal.css, light theme.

   WHAT DELIBERATELY DID NOT COME ACROSS:

   Sizes. The old system used clamp(2rem, 3.6vw, 3.2rem) and similar. "vw" is a
   fraction of the BROWSER WINDOW, but reveal renders a fixed 1280x720 canvas
   and CSS-scales it to fit - so vw-based type would resize independently of
   the slide it sits on. Sizes here stay in em against --r-main-font-size,
   which is what keeps the deck at zero overflowing slides.

   Fonts. The old system pulls Source Sans 3 and Source Serif 4 from Google
   Fonts with an @import - a third-party runtime dependency, which is exactly
   what committing reveal.js locally was meant to avoid. The stack below names
   them first so they are used if present, and falls back to Segoe UI.
   Self-hosting the woff2 files in framework/fonts/ is the proper fix.

   Dark theme. The old system had a full second theme keyed on
   [data-theme="dark"]. Not ported - reveal switches themes by swapping the
   stylesheet instead.
----------------------------------------------------------------------------- */

/* ROLE variables. Rules below refer to these rather than to raw palette
   colours, so switching to dark is a matter of re-pointing them once (see
   section 1c) instead of duplicating every rule. */
:root {
  --ag-surface:    var(--ag-wave-white);      /* slide background         */
  --ag-heading:    var(--ag-midnight-black);  /* h1, h2                   */
  --ag-subheading: var(--ag-brand-violet);    /* h3                       */
  --ag-body-text:  var(--ag-dark-violet);     /* paragraphs, list items   */
  --ag-emphasis:   var(--ag-brand-violet);    /* strong, em, kicker       */
  --ag-accent:     var(--ag-electric-violet); /* second-string accent     */
  --ag-marker:     var(--ag-brand-violet);    /* bullet and number markers*/
  --ag-rule:       rgba(68, 0, 153, 0.12);    /* the line under a title   */

  /* Labelled panels - a box with a coloured header band, currently only
     .learning-outcomes (section 6). Modelled on the MEE Labs 2.0 callouts so
     a student moving between a lab sheet and a lecture sees the same thing. */
  --ag-panel-head:      var(--ag-powder-violet);  /* header band and border */
  --ag-panel-head-text: var(--ag-midnight-black); /* ~7:1 on powder violet  */
  --ag-panel-body:      #F1EFF7;                  /* a touch darker than the
                                                     slide so the box reads */

  /* Section dividers (1f) - ported from the old pres_section.css. */
  --ag-section-bg:    linear-gradient(135deg, var(--ag-wave-white) 0%, var(--ag-pale-violet) 60%, var(--ag-powder-violet) 100%);
  --ag-section-label: var(--ag-brand-violet);
  --ag-section-sub:   var(--ag-dark-violet);
}

:root {
  --r-background-color: var(--ag-surface);
  --r-main-color:       var(--ag-body-text);
  --r-heading-color:    var(--ag-heading);
  --r-link-color:       var(--ag-electric-violet);
  --r-link-color-hover: var(--ag-brand-violet);
  --r-selection-background-color: var(--ag-pale-violet);

  /* Named first so they are used when installed; Segoe UI otherwise. */
  --r-main-font:    "Source Sans 3", "Source Sans Pro", "Segoe UI", system-ui, sans-serif;
  --r-heading-font: "Source Sans 3", "Source Sans Pro", "Segoe UI", system-ui, sans-serif;

  /* The stock white theme uppercases every heading. The old system did not. */
  --r-heading-text-transform: none;
  --r-heading-font-weight: 600;
  --r-heading-line-height: 1.05;
  --r-heading-letter-spacing: -0.02em;
}

/* -- Headings -------------------------------------------------------------- */
.reveal h1,
.reveal h2,
.reveal h3 {
  text-wrap: balance;          /* avoids a lonely last word on a wrapped title */
}

.reveal h3 {
  color: var(--ag-subheading);
  letter-spacing: -0.01em;
  line-height: 1.2;
}

/* The rule under a slide title. In the old system this was a full-width
   1px border rather than the short gradient bar used elsewhere. */
.reveal .slides section > h2 {
  padding-bottom: 0.42em;
  margin-bottom: 0.58em;
  border-bottom: 1px solid var(--ag-rule);
}

/* Section dividers should not carry the rule - they are signposts, not slides
   with content under a heading. */
.reveal .slides section.section-slide > h1 {
  border-bottom: none;
}

/* -- Body and inline emphasis ---------------------------------------------- */
.reveal p,
.reveal li {
  color: var(--ag-body-text);
  text-wrap: pretty;
}

.reveal li::marker {
  color: var(--ag-marker);
  font-variant-numeric: tabular-nums;
}

/* Both emphases are violet in the old system - strong carries weight, em
   carries slant, and colour marks them both as emphasis. */
.reveal strong {
  color: var(--ag-emphasis);
  font-weight: 700;
  font-style: normal;
}

.reveal em {
  color: var(--ag-emphasis);
}

/* -- Kicker ---------------------------------------------------------------- */
/* Small uppercase label above a slide title. Used as ::: {.kicker} or on any
   element with the class. */
.reveal .kicker {
  display: block;
  font-size: 0.5em;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ag-emphasis);
  margin-bottom: 0.5em;
}


/* -----------------------------------------------------------------------------
   1c. DARK THEME
   -----------------------------------------------------------------------------
   Switched by data-theme="dark" on <html>, set by the toggle in the corner of
   every deck and remembered in localStorage. Light is the default: no
   attribute, no stored preference, light.

   NOT auto-detected from the OS. Deliberate - these decks are read by students
   on their own devices, and an explicit control they can see beats inferring
   what they want.

   Ported from pres_global.css and pres_normal.css. Note it is NOT an
   inversion: emphasis moves from brand violet to POWDER violet, because brand
   violet on a dark ground is close to unreadable. That distinction is the
   whole reason a dark theme needs designing rather than computing.
----------------------------------------------------------------------------- */

:root[data-theme="dark"] {
  --ag-surface:    var(--ag-midnight-black);
  --ag-heading:    var(--ag-wave-white);
  --ag-subheading: var(--ag-powder-violet);
  --ag-body-text:  var(--ag-wave-white);
  --ag-emphasis:   var(--ag-powder-violet);
  --ag-accent:     var(--ag-pale-violet);
  --ag-marker:     var(--ag-pale-violet);
  --ag-rule:       rgba(198, 187, 255, 0.12);

  --r-link-color:       var(--ag-powder-violet);
  --r-link-color-hover: var(--ag-pale-violet);
  --r-selection-background-color: var(--ag-brand-violet);

  /* Washes behind the semantic blocks have to lift off a dark ground rather
     than sit on a light one. */
  --ag-tint-violet: rgba(198, 187, 255, 0.10);
  --ag-tint-tip:    rgba(167, 140, 250, 0.13);

  /* The panel header stays powder violet with dark text in BOTH themes - it
     reads as a solid label either way. Only the body has to change, from a
     light grey that sits on white to a wash that lifts off black. */
  --ag-panel-body:  rgba(198, 187, 255, 0.08);

  --ag-section-bg:    linear-gradient(135deg, var(--ag-dark-violet) 0%, var(--ag-brand-violet) 55%, var(--ag-electric-violet) 100%);
  --ag-section-label: var(--ag-pale-violet);
  --ag-section-sub:   var(--ag-pale-violet);
}

/* Code blocks: the stock monokai highlight theme is already dark, so it only
   needs its surround toning down. */
:root[data-theme="dark"] .reveal pre {
  box-shadow: none;
}

/* -- The toggle ------------------------------------------------------------ */
/* Quiet by default: a projected slide should not carry a bright control in the
   corner. At rest it is a small circle showing the CURRENT theme. On hover or
   keyboard focus it widens into a pill, revealing both ends, with the knob
   sitting over the active one - so the control reads as a switch rather than
   as a button whose effect you have to guess.
   The visible glyph shows the current state; the aria-label describes the
   action. Those are deliberately different. */

#ag-theme-toggle {
  position: fixed;
  top: 14px;
  right: 14px;
  z-index: 60;
  width: 38px;                 /* grows to 78px on hover */
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--ag-rule);
  background: var(--ag-surface);
  padding: 0;
  cursor: pointer;
  opacity: 0.28;
  overflow: hidden;
  transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.2s ease,
              background 0.2s ease;
}

#ag-theme-toggle:hover,
#ag-theme-toggle:focus-visible {
  width: 78px;
  opacity: 1;
}

#ag-theme-toggle:focus-visible {
  outline: 2px solid var(--ag-accent);
  outline-offset: 2px;
}

/* The two ends. Hidden while collapsed - there is no room for them - and
   faded in as the pill opens. */
.ag-toggle-track {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  font-size: 13px;
  line-height: 1;
  color: var(--ag-emphasis);
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}

#ag-theme-toggle:hover .ag-toggle-track,
#ag-theme-toggle:focus-visible .ag-toggle-track {
  opacity: 0.5;
}

/* The sliding knob, carrying the current theme's glyph.
   Positioned with calc() against the button's own width rather than a fixed
   translate, so it stays correctly placed at BOTH widths - and slides across
   on its own as the pill opens. */
.ag-toggle-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--ag-emphasis);
  color: var(--ag-surface);
  font-size: 15px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1),
              background 0.2s ease;
  pointer-events: none;
}

:root[data-theme="dark"] .ag-toggle-knob {
  left: calc(100% - 33px);
}

/* Per the repo motion policy: this animation is decorative, not information,
   so it goes away for anyone who has asked for less movement. The control
   still works identically - it just arrives instead of sliding. */
@media (prefers-reduced-motion: reduce) {
  #ag-theme-toggle,
  .ag-toggle-track,
  .ag-toggle-knob {
    transition: none;
  }
}


/* -----------------------------------------------------------------------------
   1d. FOOTER
   -----------------------------------------------------------------------------
   Ported from pres_global.css, with the layout changed: in the old system the
   crest sat left and the title/author sat RIGHT. Here everything is pushed to
   the left, leaving the right-hand end of the bar free for reveal's own
   controls and slide counter - which are reveal's to maintain, not ours.

   Also dropped: the "Centre for Engineering Education" line and the vertical
   separator rule that went with it.

   The gradient hairline is kept EXACTLY as it was - same stops, same 45%
   midpoint, same per-theme opacities.
----------------------------------------------------------------------------- */

.ag-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 62px;                 /* ~15% taller, so the text clears reveal's controls */
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0 34px;
  z-index: 20;
  pointer-events: none;         /* never steals a click from the slide */
  overflow: hidden;
}

/* The gradient hairline. Identical to the old system. */
.ag-footer::before {
  content: '';
  position: absolute;
  top: 0;
  left: 34px;
  right: 34px;
  height: 1px;
  background: linear-gradient(
    90deg,
    var(--ag-brand-violet) 0%,
    var(--ag-electric-violet) 45%,
    transparent 100%
  );
  opacity: 0.28;
}

:root[data-theme="dark"] .ag-footer::before {
  background: linear-gradient(
    90deg,
    var(--ag-powder-violet) 0%,
    var(--ag-electric-violet) 45%,
    transparent 100%
  );
  opacity: 0.45;
}

.ag-footer__logo {
  height: 30px;
  width: auto;
  flex-shrink: 0;
  display: block;
}

/* One crest per theme, swapped rather than recoloured - the violet and white
   marks are separate official files. */
:root[data-theme="dark"] .ag-footer__logo--light,
.ag-footer__logo--dark { display: none; }
:root[data-theme="dark"] .ag-footer__logo--dark { display: block; }

.ag-footer__text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.1rem;
  min-width: 0;                 /* lets the title ellipsis rather than push */
}

.ag-footer__title {
  font-size: 12.5px;
  font-weight: 300;
  letter-spacing: 0.04em;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ag-body-text);
  opacity: 0.55;
}

.ag-footer__author {
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.03em;
  line-height: 1.3;
  white-space: nowrap;
  color: var(--ag-emphasis);
}

/* The old system hid the footer on title, section, full-bleed and closing
   slides. :has() lets a fixed footer react to whichever slide is showing,
   with no JavaScript. If a browser lacks :has() the footer simply stays
   visible, which is a tolerable way to fail. */
body:has(.slides section.present.title-slide) .ag-footer,
body:has(.slides section.present.section-slide) .ag-footer,
body:has(.slides section.present.full-bleed) .ag-footer,
body:has(.slides section.present.closing) .ag-footer {
  opacity: 0;
}

.ag-footer { transition: opacity 0.3s ease; }

@media print {
  .ag-footer { position: absolute; }
}

/* -----------------------------------------------------------------------------
   1e. TITLE SLIDE (COVER)
   -----------------------------------------------------------------------------
   Ported from PresentationTemplate/presentation_files/pres_title.css - the
   cover Andrew designed for the old system - and kept deliberately close to
   it: kicker and crest along the top, a large title with a serif italic
   subtitle and a short violet rule, Presenter and Details cards along the
   bottom, and the Diamond photograph fading in from the right behind a
   brand-violet wash. build.html emits the markup from front matter (see
   titleSlide there for the fields).

   TRANSLATION, not a copy. The old sizes were clamp()/vw values, which here
   would track the browser window rather than reveal's fixed 1280x720 canvas
   (the same reason given in 1b). Each was evaluated at 1280px wide - where
   the old deck was designed to be seen - and rewritten: type in em against
   the 30px base, layout in px against the canvas. So the cover renders at
   the size it was designed at, and scales with the canvas like every slide.

   The photo and crest are theme-specific image treatments (the photo is
   darkened for dark, washed out for light), so they are switched on
   [data-theme] like the footer crest. Text colours all use roles.
----------------------------------------------------------------------------- */

.reveal .slides section.title-slide {
  padding: 0;
  text-align: left;
}

.reveal .ag-cover {
  position: relative;
  box-sizing: border-box;
  width: var(--ag-canvas-w);
  height: var(--ag-canvas-h);
  padding: 48px 90px;                 /* the old slide padding at 1280px */
  display: grid;
  grid-template-rows: auto 1fr auto;
}

/* Everything except the photo sits above it. */
.reveal .ag-cover > :not(.ag-cover__accent) { position: relative; z-index: 2; }

/* -- The photograph, fading in from the right ------------------------------ */
/* ON SCREEN the photo is .ag-cover-bg, which build.html puts inside .reveal
   but OUTSIDE .slides - so it is pinned to the browser window, not to the
   1280x720 canvas. As in the original, it fills the right 65% of the window
   edge to edge whatever the window's shape, cropped (background-size: cover)
   and never stretched. Inside the canvas it was letterboxed along with the
   rest of the slide whenever the window was not 16:9, leaving white bands.
   It fades in only while the title slide is the current slide.

   IN PRINT that window-pinned layer means nothing, so the copy inside the
   slide (.ag-cover__accent) is used instead, and each is hidden in the other
   medium. The two share every rule below except their placement.

   Two masks intersected: a left-to-right fade so the photo never meets the
   title with a hard edge, and a soft ellipse so its other edges dissolve too.
   Values exactly as in the original. */
.reveal .ag-cover-bg {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 65%;
  z-index: 0;                          /* .slides is z-index 1, so text sits above */
  opacity: 0;
  transition: opacity 0.4s ease;
}

.reveal:has(.slides > section.title-slide.present):not(.overview) .ag-cover-bg {
  opacity: 1;
}

/* The in-slide copy, for print only. */
.reveal .ag-cover__accent {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 65%;
}

@media screen { .reveal .ag-cover__accent { display: none; } }
@media print  { .reveal .ag-cover-bg      { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .reveal .ag-cover-bg { transition: none; }
}

.reveal .ag-cover-bg,
.reveal .ag-cover__accent {
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 12%),
                      radial-gradient(ellipse 80% 75% at 65% 50%, #000 30%, rgba(0,0,0,0.7) 52%, rgba(0,0,0,0.25) 76%, transparent 100%);
  -webkit-mask-composite: destination-in;
          mask-image: linear-gradient(to right, transparent 0%, black 12%),
                      radial-gradient(ellipse 80% 75% at 65% 50%, #000 30%, rgba(0,0,0,0.7) 52%, rgba(0,0,0,0.25) 76%, transparent 100%);
          mask-composite: intersect;
}

/* The image itself comes from an inline style set by build.html, so a deck
   can swap it with "cover:" in front matter. */
.reveal .ag-cover__photo {
  position: absolute;
  inset: 0;
  background-position: center 45%;
  background-size: cover;
  background-repeat: no-repeat;
  filter: saturate(0.6) contrast(0.95) brightness(0.85);
}

/* Brand-tinted wash over the photo, so any picture sits in the palette. */
.reveal .ag-cover-bg::after,
.reveal .ag-cover__accent::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 75% 45%, rgba(112, 0, 255, 0.12) 0%, transparent 60%),
    linear-gradient(135deg, rgba(167, 140, 250, 0.25) 0%, rgba(198, 187, 255, 0.1) 50%, rgba(36, 18, 94, 0.25) 100%);
  mix-blend-mode: multiply;
}

:root[data-theme="dark"] .reveal .ag-cover__photo {
  filter: saturate(0.7) contrast(1.05) brightness(0.55);
}
:root[data-theme="dark"] .reveal .ag-cover-bg::after,
:root[data-theme="dark"] .reveal .ag-cover__accent::after {
  background:
    radial-gradient(ellipse at 75% 45%, rgba(112, 0, 255, 0.22) 0%, transparent 60%),
    linear-gradient(135deg, rgba(36, 18, 94, 0.5) 0%, rgba(19, 30, 41, 0.2) 50%, rgba(19, 30, 41, 0.7) 100%);
}

/* -- Top row: kicker and crest --------------------------------------------- */
.reveal .ag-cover__top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding-top: 8px;
}

.reveal .ag-cover__kicker {
  font-size: 0.47em;                  /* 14px */
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ag-emphasis);
}

.reveal .ag-cover__logo {
  height: 54px;
  width: auto;
  margin: 0;
  opacity: 0.92;
}

:root[data-theme="dark"] .reveal .ag-cover__logo--light,
.reveal .ag-cover__logo--dark { display: none; }
:root[data-theme="dark"] .reveal .ag-cover__logo--dark { display: block; }

/* -- Middle: title, subtitle, rule ----------------------------------------- */
.reveal .ag-cover__mid {
  align-self: center;
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 32px 0;
}

.reveal .ag-cover h1.title {
  margin: 0;
  font-size: 1.92em;                  /* 57.6px */
  max-width: 24ch;
  color: var(--ag-heading);
  text-align: left;
}

/* Serif italic, as in the original. The stylesheet does not fetch web fonts
   (see 1b), so Source Serif 4 is used where installed and Georgia otherwise. */
.reveal .ag-cover .subtitle {
  margin: 0;
  font-family: "Source Serif 4", Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 0.85em;                  /* 25.6px */
  max-width: 40ch;
  color: var(--ag-emphasis);
}

.reveal .ag-cover__rule {
  width: 120px;
  height: 2px;
  background: var(--ag-emphasis);
}

/* -- Bottom row: Presenter and Details cards --------------------------------- */
.reveal .ag-cover__bot {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 32px;
  padding-bottom: 8px;
}

/* Frosted cards with a violet gradient top edge. They exist to keep the
   text readable where the photo runs behind it. */
.reveal .ag-cover__card {
  position: relative;
  font-size: 0.49em;                  /* 14.7px */
  line-height: 1.5;
  color: var(--ag-body-text);
  background: rgba(248, 248, 249, 0.88);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  border-radius: 6px;
  padding: 0.5em 0.8em;
  box-shadow: 0 2px 16px rgba(68, 0, 153, 0.09);
}

.reveal .ag-cover__card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  border-radius: 6px 6px 0 0;
  background: linear-gradient(90deg, var(--ag-brand-violet) 0%, var(--ag-electric-violet) 60%, transparent 100%);
}

.reveal .ag-cover__card--right { text-align: right; }

.reveal .ag-cover__label {
  display: block;
  font-size: 0.76em;                  /* ~11px */
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-bottom: 0.35em;
  opacity: 0.65;
}

/* The original dark cover has no cards - the text sits straight on the
   dark ground, in powder violet. */
:root[data-theme="dark"] .reveal .ag-cover__card {
  background: none;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  box-shadow: none;
  padding: 0;
  color: var(--ag-emphasis);
}
:root[data-theme="dark"] .reveal .ag-cover__card::before { display: none; }


/* -----------------------------------------------------------------------------
   1f. SECTION DIVIDERS
   -----------------------------------------------------------------------------
   Ported from PresentationTemplate/presentation_files/pres_section.css. A
   "#" heading makes a section divider; build.html gives it the class
   section-slide. It becomes:

       ———  Part One                    <- automatic label
       The section title                <- the # heading, very large
       An optional italic sub-heading.  <- any paragraph under the heading

   over a diagonal violet gradient that fills the WHOLE WINDOW.

   The LABEL is numbered by build.html ("Part One", "Part Two"...) and put on
   the heading as data-kicker, so it needs no typing and stays right when
   sections are reordered. NOT a CSS counter: reveal sets display:none on
   slides away from the current one, and counters skip hidden elements, so
   every divider came out "Part One". For a divider that should say
   something else, give the heading an attribute:

       # Worked example {kicker="Interlude"}

   An interlude still advances the count, so numbering stays in step with
   the "#" headings in the file.

   The GRADIENT is a pseudo-element on .reveal, not the slide's background,
   for the same reason as the cover photo: the slide is the 1280x720 canvas,
   which letterboxes in any window that is not 16:9, and the original filled
   the window edge to edge. It fades in while a section slide is current.
   In print it goes onto the slide itself instead.

   Sizes are the originals evaluated at 1280px wide, as for the cover.
----------------------------------------------------------------------------- */

.reveal::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;                         /* under .slides (z-index 1) */
  background: var(--ag-section-bg);
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

.reveal:has(.slides > section.section-slide.present):not(.overview)::before {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .reveal::before { transition: none; }
}

@media print {
  .reveal::before { display: none; }
  .reveal .slides > section.section-slide { background: var(--ag-section-bg); }
}

/* Vertically centred on the canvas, as the original was. align-content on
   a block container is 2024 CSS; older browsers top-align it instead, which
   the padding keeps presentable. Deliberately not display:flex - reveal
   writes display inline on sections to show and hide them. */
.reveal .slides > section.section-slide {
  box-sizing: border-box;
  height: var(--ag-canvas-h);
  padding: 48px 90px;
  align-content: center;
  text-align: left;
}

/* The label, carried by the title's ::before and read from data-kicker. The
   hairline in front of it is a background gradient, because the pseudo-
   element that would normally draw it is already this label. */
.reveal .slides > section.section-slide > h1[data-kicker]::before {
  content: attr(data-kicker);
  display: block;
  margin-bottom: 32px;
  padding-left: 68px;                 /* 48px line + 20px gap */
  background: linear-gradient(currentColor, currentColor) left center / 48px 1px no-repeat;
  font-family: "Source Serif 4", Georgia, serif;
  font-size: 0.29em;                  /* 25.6px, against the title's 89.6px */
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.08em;
  color: var(--ag-section-label);
}

.reveal .slides > section.section-slide > h1 {
  margin: 0 0 24px;
  font-size: 2.99em;                  /* 89.6px */
  line-height: 1;
  letter-spacing: -0.03em;
  max-width: 16ch;
  color: var(--ag-heading);
  text-align: left;
}

.reveal .slides > section.section-slide > p {
  margin: 24px 0 0;
  max-width: 48ch;
  font-family: "Source Serif 4", Georgia, serif;
  font-style: italic;
  font-size: 0.85em;                  /* 25.6px */
  color: var(--ag-section-sub);
}


/* -- Print ----------------------------------------------------------------- */
/* A dark deck sent to PDF wastes toner and reads badly, so printing is always
   light regardless of the toggle. */
@media print {
  #ag-theme-toggle { display: none !important; }

  :root[data-theme="dark"] {
    --ag-surface:    var(--ag-wave-white);
    --ag-heading:    var(--ag-midnight-black);
    --ag-subheading: var(--ag-brand-violet);
    --ag-body-text:  var(--ag-dark-violet);
    --ag-emphasis:   var(--ag-brand-violet);
    --ag-marker:     var(--ag-brand-violet);
    --ag-rule:       rgba(68, 0, 153, 0.12);
    --ag-tint-violet: rgba(198, 187, 255, 0.22);
    --ag-tint-tip:    rgba(112, 0, 255, 0.07);
  }
}


/* -----------------------------------------------------------------------------
   5b. LISTS
   -----------------------------------------------------------------------------
   The stock themes set lists to display:inline-block:

       .reveal ol, .reveal dl, .reveal ul { display: inline-block }

   which makes every list shrink-wrap to its own content and centre itself
   independently of any other. Two lists on one slide therefore get different
   left edges, and land on fractional pixel positions - which is what makes the
   text look faintly blurred.

   This bites hardest with ". . .", because a pause necessarily ENDS one list
   and starts another. Measured on a real slide: two lists 53px apart, the
   second sitting at x=2125.18.

   Block-level lists share a left edge and sit on whole pixels.

   TRADE-OFF: lists now align left within the content area rather than being
   centred under the heading. That is usually what you want on a teaching
   slide - a stable left margin the eye can track down. If you prefer the
   centred look, delete this block and split lists across slides instead of
   pausing inside them.
----------------------------------------------------------------------------- */

.reveal .slides ul,
.reveal .slides ol,
.reveal .slides dl {
  display: block;
  margin-left: 1.2em;
}

/* Nested lists are already block in the stock theme; keep their indent
   consistent with the four-space rule used in the markdown. */
.reveal .slides ul ul,
.reveal .slides ul ol,
.reveal .slides ol ol,
.reveal .slides ol ul {
  margin-left: 1.4em;
}


/* -----------------------------------------------------------------------------
   5c. FULL-BLEED IMAGE SLIDES
   -----------------------------------------------------------------------------
   Used as a heading attribute, so it needs no parser support:

       ## The Fluent story {.full-bleed}

       ![...](/images/joe-scarborough-fluent.png)
       : Joe Scarborough's painting of Fluent's Sheffield

   One image, edge to edge, no margins - for the slide where the picture IS the
   point and any framing around it only weakens it.

   The image fills the canvas and is CROPPED to fit, via object-fit: cover. That
   is the deliberate choice: letterboxing would put the margins back and defeat
   the whole purpose of the class. Cropping is from the centre, so an image
   whose subject sits hard against one edge will lose some of it - which is a
   reason to pick the picture for the slide rather than the slide for the
   picture.

   Title and caption are laid OVER the image on soft gradient scrims. The scrim
   is not decoration: white text straight onto a photograph becomes unreadable
   the moment the picture has a light area behind it, and a busy painting has
   light areas everywhere. Both are optional - a full-bleed slide carrying
   nothing but the image is a legitimate and often stronger choice.
----------------------------------------------------------------------------- */

.reveal .slides section.full-bleed { padding: 0; }

.reveal section.full-bleed figure {
  position: relative;
  width: var(--ag-canvas-w);
  height: var(--ag-canvas-h);
  margin: 0;
}

/* max-width and max-height are reset because the contextual caps from the
   figure rules above would otherwise stop the image reaching the edges. */
.reveal section.full-bleed figure :is(img, object) {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
}

.reveal .slides section.full-bleed > h1,
.reveal .slides section.full-bleed > h2 {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  margin: 0;
  padding: 0.5em 0.7em 0.8em;
  color: #fff;
  text-align: left;
  border-bottom: 0;                 /* the usual title rule would cut the picture */
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0));
}

.reveal section.full-bleed figcaption {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 2;
  margin: 0;
  padding: 1.4em 1em 0.7em;
  color: #fff;
  opacity: 1;                       /* the muted body caption would vanish here */
  text-align: left;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0));
}


/* -----------------------------------------------------------------------------
   5d. QUOTATIONS
   -----------------------------------------------------------------------------
   A plain markdown blockquote, with an optional attribution as its last line:

       > The words being quoted.
       >
       > — Who said it, where

   build.html lifts that last line out and emits

       <figure class="quote"><blockquote>...</blockquote>
                             <figcaption>Who said it, where</figcaption></figure>

   so the source sits beside the quote rather than inside it (see
   quoteAttributions in build.html for why). A blockquote with no attribution
   stays a bare <blockquote> and gets the same look minus the source line.

   Design, revised 2026-09-28 at the user's request (the first version was
   left-aligned and unboxed, with an opening mark only):

   - Always CENTRED, both the box on the slide and the quoted text inside it.
     The attribution alone stays right-aligned, reading as a signature.
   - A soft BOX, so a quote stands out from the body text around it. It is a
     full rounded box with no left rule, deliberately unlike the left-ruled
     definition and top-tip blocks in section 6 - those mark the lecturer's
     OWN argument, a quote is somebody else's words. Its fill is the
     --ag-panel-body role, shared with the learning-outcomes panel, so dark
     mode is already handled.
   - The box shrinks to fit (fit-content), up to 85% of the slide, so a
     one-line quote gets a small box rather than a wide empty band.
   - Opening AND closing marks, large and in the accent colour, hung in the
     box's side padding so they frame the text without pushing it about.
   - Italic quote; the attribution is upright, smaller, in the emphasis
     colour, with its dash drawn here so every deck shows the same one.

   The box sits on the <figure> when there is an attribution (so the source
   is inside it too) and on the bare <blockquote> when there is not.
----------------------------------------------------------------------------- */

/* The box - on whichever element is outermost. */
.reveal figure.quote,
.reveal blockquote {
  box-sizing: border-box;
  width: fit-content;
  max-width: 85%;
  margin: var(--r-block-margin) auto;
  padding: 0.7em 1em;
  background: var(--ag-panel-body);
  border-radius: 12px;
  box-shadow: none;                  /* the stock theme's drop shadow */
}

.reveal blockquote {
  position: relative;
  padding-left: 1.9em;               /* room for the hanging marks */
  padding-right: 1.9em;
  font-style: italic;
  text-align: center;
}

/* Inside a figure, the figure is the box; the quote just fills it. */
.reveal figure.quote blockquote {
  width: auto;
  max-width: none;
  margin: 0;
  padding-top: 0;
  padding-bottom: 0;
  background: none;
  border-radius: 0;
}

/* The marks. Generated content CAN be read aloud by screen readers, so the
   second content line gives each one empty alt text ("/ ''") - they are pure
   decoration, and the blockquote element already announces "quote". Browsers
   that do not understand the alt-text form ignore that line and keep the
   first, so they still show the marks. */
.reveal blockquote::before,
.reveal blockquote::after {
  position: absolute;
  font-size: 2.6em;
  line-height: 1;
  font-style: normal;
  color: var(--ag-accent);
  opacity: 0.55;
}

.reveal blockquote::before {
  content: "\201C";                  /* left double quotation mark */
  content: "\201C" / "";
  left: 0.12em;
  top: -0.05em;
}

.reveal blockquote::after {
  content: "\201D";                  /* right double quotation mark */
  content: "\201D" / "";
  right: 0.12em;
  bottom: -0.55em;                   /* the glyph sits high in its line box */
}

.reveal blockquote > :first-child { margin-top: 0; }
.reveal blockquote > :last-child  { margin-bottom: 0; }

.reveal figure.quote figcaption {
  margin-top: 0.6em;
  padding-right: 1.9em;              /* line up with the quote's text edge */
  font-size: 0.7em;
  text-align: right;
  color: var(--ag-emphasis);
  opacity: 1;                        /* the muted image-caption look is too faint here */
}

.reveal figure.quote figcaption::before {
  content: "\2014\00A0";             /* em dash + non-breaking space */
}


/* -----------------------------------------------------------------------------
   6. SEMANTIC BLOCKS
   -----------------------------------------------------------------------------
   These name a ROLE, not an appearance. The markdown says what a thing is;
   this file decides what that looks like. Change the look here and every deck
   follows - no source file needs editing.

       ::: {.keypoint}
       Strategic decisions to make in order to succeed
       :::

   Four roles, deliberately. More than about six and nobody remembers which is
   which:

       keypoint     the thing to remember. Maximum prominence.
       question     something you are actually asking the room.
       definition   a formal definition.
       top-tip      a practical aside, off the main line of argument.

   Design: keypoint is bare and centred, because a box would reduce rather
   than increase its prominence. The other three are boxed with a left rule,
   which reads as "this is set apart from the argument" rather than "this IS
   the argument".
----------------------------------------------------------------------------- */

/* The converter wraps block content in <p>, so collapse the outer margins or
   every block gains a stray gap top and bottom. */
.reveal .keypoint > :first-child,
.reveal .question > :first-child,
.reveal .definition > :first-child,
.reveal .top-tip > :first-child { margin-top: 0; }

.reveal .keypoint > :last-child,
.reveal .question > :last-child,
.reveal .definition > :last-child,
.reveal .top-tip > :last-child { margin-bottom: 0; }


/* -- keypoint: a standalone statement, raised above everything around it -- */
.reveal .keypoint {
  margin: 1.1em auto;
  max-width: 88%;
  text-align: center;
  font-weight: 700;
  font-size: 1.05em;
  line-height: 1.3;
  color: var(--ag-emphasis);
}

/* -- question: put to the room, not rhetorical -- */
.reveal .question {
  margin: 1.1em auto;
  max-width: 88%;
  text-align: center;
  font-style: italic;
  font-size: 1.05em;
  line-height: 1.35;
  color: var(--ag-accent);
}

/* -- definition: formal, and worth returning to -- */
.reveal .definition {
  margin: 0.9em 0;
  padding: 0.55em 1em;
  text-align: left;
  border-left: 5px solid var(--ag-emphasis);
  background: var(--ag-tint-violet);
}

/* -- top-tip: useful, but off the main line of argument -- */
.reveal .top-tip {
  margin: 0.9em 0;
  padding: 0.55em 1em;
  text-align: left;
  border-left: 5px solid var(--ag-accent);
  background: var(--ag-tint-tip);
}

/* Labelled, because an aside needs to announce that it is one. Delete this
   rule if the label ever feels like clutter - the block still works. */
.reveal .top-tip::before {
  content: "Top tip";
  display: block;
  margin-bottom: 0.2em;
  font-size: 0.55em;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ag-accent);
}


/* -- learning-outcomes: what the session is for ----------------------------
   A different KIND of block from the four above. Those mark something inside
   the argument; this one frames the whole session, and is meant to appear in
   every deck (the repo's CLAUDE.md asks every presentation to state its
   learning outcomes). So it gets the most formal treatment available: a
   bordered box with a solid header band, deliberately matching the MEE Labs
   2.0 learning-outcomes callout so the lab sheets and lectures agree.

       ::: {.learning-outcomes}
       By the end of this lecture you will be able to

       1. Explain ...
       2. Calculate ...
       :::

   HOW IT IS BUILT. The header band is the box's ::before - the label text is
   supplied here, so the markdown only carries the outcomes themselves and
   the wording of the label is one decision for every deck. The target icon is
   ::after, positioned over the left of the band. It is a CSS MASK rather than
   a background image: a mask takes its colour from background-color, so the
   icon follows the --ag-panel-head-text role like the text beside it, instead
   of having a colour baked into the SVG. Browsers without mask support show
   no icon and lose nothing else.

   The box itself has no padding, so the band can run edge to edge; the
   content gets its side margins from the rules below instead.
   -------------------------------------------------------------------------- */
.reveal .learning-outcomes {
  position: relative;               /* anchors the ::after icon            */
  margin: 0.6em 0;
  padding: 0 0 0.5em;
  text-align: left;
  border: 2px solid var(--ag-panel-head);
  border-radius: 4px;
  background: var(--ag-panel-body);
  overflow: hidden;                 /* clips the band to the rounded corners */
}

.reveal .learning-outcomes::before {
  content: "Learning outcomes";
  display: block;
  margin-bottom: 0.45em;
  padding: 0.3em 0.8em 0.3em 2.2em; /* left room is for the icon           */
  font-family: var(--r-heading-font);
  font-size: 0.8em;
  font-weight: 700;
  color: var(--ag-panel-head-text);
  background: var(--ag-panel-head);
}

/* The icon: a target with an arrow in it. Sized and placed in em against the
   band's font, so it scales with the deck's base font like everything else.
   The top offset centres it on the band's first line. */
.reveal .learning-outcomes::after {
  content: "";
  position: absolute;
  top: 0.34em;
  left: 0.55em;
  width: 0.8em;
  height: 0.8em;
  background-color: var(--ag-panel-head-text);
  -webkit-mask: var(--ag-icon-target) center / contain no-repeat;
          mask: var(--ag-icon-target) center / contain no-repeat;
}

:root {
  /* Drawn for this file: two rings, a bullseye, and an arrow flying in from
     the top right. Stroke colour inside the SVG is irrelevant - only its
     SHAPE is used, as a mask. */
  --ag-icon-target: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M20 11.5A8.5 8.5 0 1 1 12.5 3.5'/%3E%3Cpath d='M15.5 11.8A3.8 3.8 0 1 1 12.2 8.2'/%3E%3Ccircle cx='12' cy='12' r='0.6' fill='black'/%3E%3Cpath d='M12 12L21 3M17 3h4v4'/%3E%3C/svg%3E");
}

/* Side margins for everything inside, since the box has no padding of its
   own. Lists need more on the left, because reveal draws their markers in
   the margin. */
.reveal .learning-outcomes > * {
  margin-left: 0.9em;
  margin-right: 0.9em;
}
.reveal .learning-outcomes > ol,
.reveal .learning-outcomes > ul {
  margin-left: 2em;
}
.reveal .learning-outcomes > :last-child { margin-bottom: 0; }
