/* ==========================================================================
   CareerStart.ai — presentation build
   Slide images, deck header, narration panel, and reveal.js plugin skinning.

   Everything visual comes from the tokens in theme/dmws.css, which in turn
   come from assets/css/styles.css. Nothing here hard-codes a brand colour.

   Sections:
     1. Slide images (the inline SVG that is the slide)
     2. Deck header (brand, deck nav, view switch) and no-JS fallback
     3. Narration panel (speaker notes) and .line highlighting
     4. reveal.js plugin skinning — menu, custom controls, audio player
     5. Icons (CSS masks — no icon font, no icon library)
     6. Reduced motion and print
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Slide images

   A slide is one inline <svg>, not a tree of HTML elements. The markup is the
   same graphics as assets/img/slides/<deck>/slideN.svg, which the web pages
   inline as well — neither consumer uses an img element, see
   docs/slide-images.md. Two differences, both made when the file is inlined:

     - the per-file <defs> and <style> are dropped, because 37 copies of the
       same stylesheet in one page is waste. Their rules live below instead,
       scoped to .slide-svg, and the two gradients are declared once per page
       in the .slide-defs block at the top of <body>.
     - width/height come off, so the slide scales to reveal's canvas.

   Reveal's canvas is 1280x800 with a 6% margin, which is exactly the SVG's
   own 1280x800 viewBox — so the slide fills the frame with no letterboxing.
   -------------------------------------------------------------------------- */

/* One copy of the gradients per page. Hidden, but it must stay in the layout
   tree: display:none in a parent makes a referenced gradient unresolvable in
   some engines. */
.slide-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.reveal .slides section > svg.slide-svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The slide's own type and colour. These mirror the --d-* tokens in
   theme/dmws.css, and the standalone .svg files repeat them verbatim in their
   own <style> block so the file still typesets on its own. Change
   one, change the other — docs/slide-images.md has the check that catches a
   drift. */
.slide-svg text {
  font-family: var(--r-main-font);
  fill: var(--d-text);
}

/* The stops are in the deck's .slide-defs block, not inside a slide. Scoping
   these to .slide-svg matched nothing and .grad text rendered black. */
.slide-defs .gs-a { stop-color: var(--d-blue); }
.slide-defs .gs-b { stop-color: var(--d-purple); }
.slide-svg .grad { fill: url(#g-slide); }

/* Flowing prose inside a slide.

   A line too wide for the stacked layout the web pages use is not <text> at
   all: it is a <switch><foreignObject> block of real HTML, with a hand-broken
   <text> fallback behind it that only the PowerPoint export ever reads. See
   docs/responsive-slides.md.

   A deck never stacks — reveal.js owns a fixed 1280x800 canvas and there is
   no .slide-track here for the observer in assets/js/site.js to find — so
   none of the narrow rules from section 7a of assets/css/styles.css are
   mirrored. What is mirrored is the part that a deck does need: the flow has
   to be typeset at all, and an HTML box takes `color`, not `fill`, which is
   why every colour class below now sets both. */
.slide-svg foreignObject {
  overflow: visible;
}

/* The reset is load-bearing, not tidiness: a flow is an HTML box inside the
   deck, so any rule here or in reveal's own stylesheet that matches it
   applies. reveal.js sets type on nearly everything it contains. The box
   declares what it is rather than hoping nothing reaches it — the same reason
   section 7a of assets/css/styles.css does. */
.slide-svg .flow {
  max-width: none;
  min-width: 0;
  margin: 0;
  padding: 0;
  text-align: left;
  font-family: var(--r-main-font);
  line-height: 1.45;
  color: var(--d-text);
  -webkit-hyphens: none;
  hyphens: none;
}

/* No text-wrap here on purpose. A flow's box is exactly as wide as the longest
   line the copy was hand-broken at, which is what makes the browser break it
   where the writer did; `balance` and `pretty` both override that. A deck is
   only ever the wide layout, so it never wants either. Section 7a of
   assets/css/styles.css has the longer version. */

/* The line pitches the slides were already hand-broken at, so a block that
   becomes a flow keeps the vertical rhythm it had. Mirrors section 7a of
   assets/css/styles.css, which explains where the numbers come from. */
.slide-svg .flow.h1 { line-height: 1.1; }
.slide-svg .flow.h2 { line-height: 1.15; }
.slide-svg .flow.lede { line-height: 1.38; }
.slide-svg .flow.punch { line-height: 1.6; }

/* The flow equivalent of text-anchor="middle": a centred <text> is anchored
   at its midpoint, a flow is centred inside a box that straddles it. */
.slide-svg .flow.mid { text-align: center; }

.slide-svg .flow strong { font-weight: 700; color: var(--d-heading); }
.slide-svg .flow em { font-style: italic; }

/* An HTML box cannot reference an SVG paint server, so the brand ramp is
   re-declared as a CSS gradient clipped to the glyphs. Same two tokens the
   .slide-defs stops use, so the colour is the same one either way. */
.slide-svg .flow.grad,
.slide-svg .flow .grad {
  background-image: linear-gradient(90deg, var(--d-blue), var(--d-purple));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

@media (forced-colors: active) {
  .slide-svg .flow.grad,
  .slide-svg .flow .grad {
    background-image: none;
    color: CanvasText;
  }
}

.slide-svg .eyebrow {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  fill: var(--d-accent-alt);
  color: var(--d-accent-alt);
}

.slide-svg .head {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  fill: var(--d-muted);
  color: var(--d-muted);
}

.slide-svg .h1 {
  font-size: 60px;
  font-weight: 700;
  letter-spacing: -1.2px;
  fill: var(--d-heading);
  color: var(--d-heading);
}

.slide-svg .h2 {
  font-size: 42px;
  font-weight: 700;
  letter-spacing: -0.8px;
  fill: var(--d-heading);
  color: var(--d-heading);
}

.slide-svg .h3 {
  font-size: 23px;
  font-weight: 700;
  fill: var(--d-heading);
  color: var(--d-heading);
}

.slide-svg .lede { font-size: 24px; fill: var(--d-muted); color: var(--d-muted); }
.slide-svg .body { font-size: 19px; }
.slide-svg .sm { font-size: 17px; }
.slide-svg .xs { font-size: 15px; }
.slide-svg .muted { fill: var(--d-muted); color: var(--d-muted); }
.slide-svg .b { font-weight: 700; fill: var(--d-heading); color: var(--d-heading); }
.slide-svg .i { font-style: italic; }

.slide-svg .punch {
  font-size: 22px;
  font-weight: 700;
  fill: var(--d-heading);
  color: var(--d-heading);
}

.slide-svg .num {
  font-size: 52px;
  font-weight: 700;
  fill: var(--d-accent-alt);
  color: var(--d-accent-alt);
}

.slide-svg .card {
  fill: var(--d-surface);
  stroke: var(--d-border);
  stroke-width: 1.5;
}

.slide-svg .panel {
  fill: var(--d-bg-alt);
  stroke: var(--d-border);
  stroke-width: 1.5;
}

/* The icon tile in the top-right of a card. Same two classes as
   assets/css/styles.css section 8, pointing at the deck's --d-* tokens.
   The glyphs are built from <line> and <circle> only -- no slide contains a
   <path>, and tools/svg-to-pptx.ps1 reads no other shape. */
.slide-svg .tile { fill: url(#g-slide-tile); stroke: none; }

.slide-svg .tile-glyph {
  fill: none;
  stroke: var(--d-accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Exactly one featured tier per deck, as on the web pages. */
.slide-svg .feature { stroke: var(--d-purple); stroke-width: 3; }

.slide-svg .rule { stroke: var(--d-blue); stroke-width: 5; stroke-linecap: round; }
.slide-svg .hair { stroke: var(--d-border); stroke-width: 1.5; }
.slide-svg .good { fill: var(--d-good); color: var(--d-good); }
.slide-svg .warn { fill: var(--d-warn); color: var(--d-warn); }
.slide-svg .accent { fill: var(--d-accent); color: var(--d-accent); }
.slide-svg .qbar { fill: var(--d-purple); }
.slide-svg .tbl { font-size: 14px; }
.slide-svg .tblhead { font-size: 14px; font-weight: 700; fill: var(--d-heading); color: var(--d-heading); }

.slide-svg .pill-live { fill: none; stroke: var(--d-good); stroke-width: 1.5; }
.slide-svg .pill-soon { fill: none; stroke: var(--d-warn); stroke-width: 1.5; }

.slide-svg .pill-text-live {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.8px;
  fill: var(--d-good);
  color: var(--d-good);
}

.slide-svg .pill-text-soon {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.8px;
  fill: var(--d-warn);
  color: var(--d-warn);
}

/* The call-to-action shapes. The gradient is the -700 shades and does not
   move between themes: white clears 4.5:1 at both ends only on those. Same
   reasoning as .btn--primary on the web pages — see docs/brand-guidelines.md. */
.slide-svg .btn-fill { fill: url(#g-slide-btn); }

.slide-svg .btn-ghost {
  fill: none;
  stroke: var(--d-border-strong);
  stroke-width: 1.5;
}

.slide-svg .btn-label { font-size: 20px; font-weight: 700; fill: #ffffff; color: #ffffff; }
.slide-svg .btn-label-ghost { font-size: 20px; font-weight: 700; fill: var(--d-accent); color: var(--d-accent); }

/* Available to screen readers, absent from the slide. */
.reveal .visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Links inside a slide.
   The web pages inline the same SVG and carry the same links -- there is no
   prose version of the site any more -- so these rules exist twice, here and
   in assets/css/styles.css section 8. The <text> inside gives each link its
   accessible name.
   `.reveal a` is set to `position: relative` by reveal.css and coloured by the
   theme, both of which outrank a bare class — hence `a.deck-link` is avoided
   entirely and these are matched through the slide instead. */
.slide-svg a {
  cursor: pointer;
}

.slide-svg a:focus-visible {
  outline: 3px solid var(--d-accent-alt);
  outline-offset: 3px;
  border-radius: 4px;
}

.slide-svg a:hover .btn-label-ghost,
.slide-svg a:focus-visible .btn-label-ghost {
  fill: var(--r-link-color-hover);
}

.slide-svg a:hover .btn-ghost,
.slide-svg a:focus-visible .btn-ghost {
  stroke: var(--d-accent-alt);
}

/* Windows High Contrast / forced-colors.
   The web pages carry this same block (the end of assets/css/styles.css) and
   a deck needs it for the same reason: the slides are inline SVG, so the
   forced palette does reach into them -- but `fill` and `stroke` are not
   properties it forces, so every role the slides use is re-pointed by hand.
   Without this the decks kept their authored colours in High Contrast while
   the identical slides on the pages adapted. The deck chrome has its own
   forced-colors rules in section 2. */
@media (forced-colors: active) {
  .slide-svg text,
  .slide-svg .b,
  .slide-svg .h1,
  .slide-svg .h2,
  .slide-svg .h3,
  .slide-svg .punch,
  .slide-svg .tblhead {
    fill: CanvasText;
  }

  .slide-svg .muted,
  .slide-svg .lede,
  .slide-svg .head,
  .slide-svg .eyebrow,
  .slide-svg .num,
  .slide-svg .accent,
  .slide-svg .good,
  .slide-svg .warn,
  .slide-svg .grad,
  .slide-svg .pill-text-live,
  .slide-svg .pill-text-soon {
    fill: CanvasText;
  }

  /* Flowing text is HTML, so the `fill` above never reaches it. Without this
     a slide's prose keeps its own colour in a forced-colours theme, which is
     the failure the mode exists to prevent. */
  .slide-svg .flow,
  .slide-svg .flow strong,
  .slide-svg .flow em {
    color: CanvasText;
  }

  /* Surfaces keep their outline so a card is still a card. */
  .slide-svg .card,
  .slide-svg .panel {
    fill: Canvas;
    stroke: CanvasText;
  }

  .slide-svg .rule,
  .slide-svg .hair,
  .slide-svg .qbar,
  .slide-svg .feature,
  .slide-svg .pill-live,
  .slide-svg .pill-soon {
    stroke: CanvasText;
    fill: CanvasText;
  }

  /* The tile loses its gradient the way the CTA shapes do; an outline is what
     keeps it reading as a tile, and the glyph inside it as a glyph. */
  .slide-svg .tile {
    fill: Canvas;
    stroke: CanvasText;
    stroke-width: 1.5;
  }

  .slide-svg .tile-glyph {
    stroke: CanvasText;
  }

  /* The call-to-action shapes lose their gradient; the outline carries them. */
  .slide-svg .btn-fill {
    fill: ButtonFace;
    stroke: ButtonText;
    stroke-width: 1.5;
  }

  .slide-svg .btn-ghost {
    stroke: ButtonText;
  }

  .slide-svg .btn-label,
  .slide-svg .btn-label-ghost {
    fill: ButtonText;
  }
}

/* --------------------------------------------------------------------------
   2. Deck header and no-JS fallback
   -------------------------------------------------------------------------- */

/* The decks carry the same header as the web pages, so you move between them
   the same way you move between pages.

   It is a sibling of .reveal, not a child, because .reveal.show-notes narrows
   to 75% and a child would be pinned inside that.

   It also takes real space rather than floating over the slide. Reveal works
   out its scale from .reveal's own offsetHeight, so shortening .reveal makes
   the slides scale to fit what is left instead of sliding under the bar.
   Reveal re-lays-out on resize, so the shorter header at the phone breakpoint
   is picked up too. */
:root {
  --deck-header-h: 4.25rem;
}

@media (max-width: 40rem) {
  :root {
    --deck-header-h: 3.5rem;
  }
}

.reveal {
  margin-top: calc(var(--deck-header-h) + 1px);
  height: calc(100% - var(--deck-header-h) - 1px);
}

/* Everything below mirrors the web header in assets/css/styles.css section 4,
   rule for rule, so the two views look like one site. The deck has its own
   token names, so the mapping is:

     --bg          -> --r-background-color      --text        -> --r-main-color
     --border      -> --d-border                --text-muted  -> --d-muted
     --border-strong -> --d-border-strong       --accent-alt  -> --d-accent-alt
     --bg-sunken   -> --d-bg-sunken             --link-hover  -> --r-link-color-hover
     --surface     -> --d-surface               --shadow-color-> --d-shadow

   Sizes are the literal values of the site's --sp-*, --fs-* and --radius-*
   tokens. If you change a header value on one side, change it on both. */

.deck-header {
  position: fixed;
  box-sizing: border-box;
  inset: 0 0 auto 0;
  z-index: 60;
  /* --deck-header-h is the inner height, matching .site-header__inner's
     min-height; the +1px is the bottom border, so the bar totals the same as
     the web one. */
  height: calc(var(--deck-header-h) + 1px);
  /* The web header inherits the body line-height; reveal sets 1 on its
     viewport, which would make every nav link 10px shorter than the web one. */
  line-height: 1.65;
  /* Same translucent treatment as .site-header. Nothing scrolls under it here,
     but it keeps the two headers the same colour in both schemes — .deck-surface
     would be a shade lighter than --bg in dark mode. */
  background: color-mix(in srgb, var(--r-background-color) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--d-border);
  font-family: var(--r-main-font);
  color: var(--r-main-color);
}

/* Mirrors .container + .site-header__inner. The 1140px cap is what keeps the
   switch in the same place on screen as it is on the web pages — without it the
   header spreads to the full window and the control drifts right. */
.deck-header__inner {
  box-sizing: border-box;
  width: 100%;
  max-width: 1140px;
  height: 100%;
  margin-inline: auto;
  padding-inline: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

/* The brand box stays bar-height whatever the logo does, so --deck-header-h is
   unchanged: reveal subtracts it from its own height to derive the slide
   scale, and a taller bar would shrink every slide. Overflow does not count
   towards layout, so the mascot's box can hang over the top of the deck. */
.deck-brand {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: none;
  height: var(--deck-header-h);
}

/* The mark is a 28-unit square, not the wide raster lockup this file was
   ported from. So it is sized in absolute pixels and the wordmark beside it
   is HTML text, exactly as in the web header - which is what lets it follow
   dark mode, forced colours, and text scaling, and stay selectable.
   The 3rem / 6rem overhang the source repo needed does not apply and is
   deliberately absent below. */
.deck-brand {
  gap: 0.5rem;
}

.deck-brand img {
  display: block;
  width: 28px;
  height: 28px;
}

.deck-brand span {
  font-family: var(--r-heading-font);
  font-weight: 800;
  font-size: 1.03rem;
  line-height: 1;
  color: var(--d-accent);
  white-space: nowrap;
}

@media (max-width: 40rem) {
  .deck-brand span {
    /* The mark alone carries the brand below this width; the bar has to hold
       the view switch and the menu button as well. */
    display: none;
  }
}

/* Three zones, mirroring .site-header__inner at the same measured 82rem
   threshold. See the note there before changing any of these numbers. */
@media (min-width: 82rem) {
  .deck-header__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    max-width: none;
  }

  .deck-brand {
    justify-self: start;
  }

  /* No size change at this breakpoint. The repo this was ported from grew its
     logo to 6rem here and let it overhang the bar; that only worked because
     its artwork was a wide strip with transparent padding. A 28-unit square
     scaled to 96px is just a large square. */

  .deck-nav {
    justify-self: end;
  }

  .deck-header .view-switch {
    justify-self: center;
    margin-left: 0;
  }
}

.deck-nav a {
  white-space: nowrap;
}
.deck-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.deck-nav a {
  display: block;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--r-main-color);
  text-decoration: none;
}

.deck-nav a:hover {
  background: var(--d-bg-sunken);
  color: var(--r-link-color-hover);
}

/* Mirrors .site-nav .btn:hover -- the gradient drops away and the shared nav
   hover takes over, so the CTA becomes a light chip like the other links. */
.deck-header .btn:hover {
  background-image: none;
}

/* The web header marks the current page with the accent colour and an
   underline rule, not a filled pill. Keep them identical. */
.deck-nav a[aria-current="page"] {
  color: var(--d-accent-alt);
  box-shadow: inset 0 -2px 0 var(--d-accent-alt);
}

/* Mirrors .btn + .btn--primary + .site-nav .btn. The header is outside .reveal,
   so it cannot use the slide button rules -- those are sized in em against the
   30px slide font. */
.deck-header .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 0.5rem;
  padding: 0.75rem 1.35rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 650;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  color: #ffffff;
  background-image: linear-gradient(
    100deg,
    #176331 0%,
    #1e7e3e 100%
  );
  box-shadow: 0 6px 18px -8px rgb(var(--d-shadow) / 0.5);
}

/* Article / Slides switch. Identical to the one on the web pages, with the
   halves the other way round: here "Slides" is the current view.

   margin-left: auto rather than relying on justify-content -- without it the
   switch would be spread into the middle of the bar instead of sitting next to
   the nav. */
.view-switch {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: auto;
  border: 1px solid var(--d-border-strong);
  border-radius: 999px;
  padding: 3px;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1;
}

/* Matches .view-switch__opt on the web pages -- --fs-sm and --sp-3/--sp-4 as
   literals. Keep the two in step. */
.view-switch__opt {
  display: block;
  padding: 0.75rem 1rem;
  border-radius: 999px;
  color: var(--d-muted);
  text-decoration: none;
  white-space: nowrap;
}

a.view-switch__opt:hover,
a.view-switch__opt:focus-visible {
  color: var(--r-link-color-hover);
  background: var(--d-bg-sunken);
}

/* Same gradient as the primary button: white clears 4.5:1 at both ends because
   it uses the -700 shades. See docs/brand-guidelines.md. */
.view-switch__opt[aria-current] {
  color: #ffffff;
  background-image: linear-gradient(
    100deg,
    #176331 0%,
    #1e7e3e 100%
  );
}

@media (forced-colors: active) {
  .view-switch__opt[aria-current],
  .deck-header .btn {
    background-image: none;
    background: ButtonFace;
    color: ButtonText;
    border: 1px solid ButtonText;
    forced-color-adjust: none;
  }
}

.deck-nav-toggle {
  display: none;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--r-main-color);
  background: transparent;
  border: 1px solid var(--d-border-strong);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  cursor: pointer;
}

.deck-nav-toggle__bars {
  display: grid;
  gap: 3px;
  width: 1rem;
}

.deck-nav-toggle__bars span {
  display: block;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}

/* Same 56rem breakpoint, drawer and spacing as the web header. Reveal always
   has JavaScript, so there is no `.js` gating to mirror here. */
@media (max-width: 55.99rem) {
  .deck-nav-toggle {
    display: inline-flex;
  }

  .deck-nav {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    background: var(--d-surface);
    border-bottom: 1px solid var(--d-border);
    box-shadow: 0 12px 24px -12px rgb(var(--d-shadow) / 0.28);
    padding: 0.75rem 1.5rem 1.5rem;
    display: none;
  }

  .deck-nav[data-open="true"] {
    display: block;
  }

  .deck-nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0.25rem;
  }

  .deck-nav a {
    padding: 0.75rem;
    font-size: 1rem;
  }

  .deck-header .btn {
    margin: 0.75rem 0 0;
    justify-content: center;
  }
}


/* Every page of the main site works with JavaScript disabled. A reveal.js
   deck cannot, so it says so and hands the reader the page it was built
   from. See CLAUDE.md rule 8. */
.noscript-fallback {
  max-width: 40rem;
  margin: 4rem auto;
  padding: 0 1.5rem;
  font: 400 17px/1.6 var(--r-main-font);
  color: var(--r-main-color);
}

.noscript-fallback h1 {
  font-size: 1.6rem;
  color: var(--r-heading-color);
}

.noscript-fallback a {
  color: var(--r-link-color);
}

/* --------------------------------------------------------------------------
   3. Narration panel
   showNotes: true renders <aside class="notes"> into .speaker-notes. That
   panel is the narration script, so it is styled as content rather than as
   reveal's default grey utility box.
   -------------------------------------------------------------------------- */

.reveal .speaker-notes {
  color: var(--r-main-color);
  background-color: var(--d-bg-alt);
  border-color: var(--d-border);
  font-family: var(--r-main-font);
  font-size: 15px;
  line-height: 1.55;
}

@media screen and (min-width: 1600px) {
  .reveal .speaker-notes {
    font-size: 17px;
  }
}

.reveal .speaker-notes:before {
  content: "Narration";
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 0.78em;
  color: var(--d-accent-alt);
  opacity: 1;
}

/* One narration line. Each maps to one fragment on the slide, and — once
   audio exists — to one data-start/data-end range in the deck's mp3.
   Click a line to jump the slide (and the audio) to that point. */
.reveal .speaker-notes .line {
  display: inline;
  padding: 1px 3px;
  border-radius: 4px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.reveal .speaker-notes .line:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
}

/* The line the audio is currently speaking. Brand blue at 22% keeps the
   text contrast well above 4.5:1 in both schemes, which a flat yellow
   highlight would not. */
.reveal .speaker-notes .currentLine {
  background-color: rgba(79, 129, 189, 0.22);
  border-color: var(--d-blue);
}

.reveal .speaker-notes .mouseOverLine {
  background-color: rgba(128, 100, 162, 0.16);
  border-color: var(--d-purple);
}

.reveal .speaker-notes .mouseLeaveLine {
  background-color: transparent;
}

/* --------------------------------------------------------------------------
   10. reveal.js plugin skinning
   -------------------------------------------------------------------------- */

/* SCOPING NOTE: the menu plugin appends .slide-menu-wrapper to .reveal's
   *parent* — i.e. to <body> — so a `.reveal .slide-menu…` selector would never
   match. Only the hamburger (.slide-menu-button) lives inside .reveal.

   The menu ships styled for a dark deck (#333 panels, #aaa text). Everything
   below re-points it at the deck tokens so it works in both schemes. Each
   override matches the plugin's own specificity and wins on order, because
   styles.css is linked after menu.css in every deck. */
.slide-menu-wrapper {
  font-family: var(--r-main-font);
}

.slide-menu-wrapper .slide-menu {
  background-color: var(--d-surface);
  color: var(--r-main-color);
  border-right: 1px solid var(--d-border);
}

.slide-menu-wrapper .slide-menu-items {
  border-bottom-color: var(--d-border);
}

.slide-menu-wrapper .slide-menu-item,
.slide-menu-wrapper .slide-menu-item-vertical {
  color: var(--r-main-color);
  border-top-color: var(--d-border);
}

.slide-menu-wrapper .slide-menu-item:hover,
.slide-menu-wrapper .slide-menu-item-vertical:hover {
  background-color: var(--d-bg-alt);
  color: var(--r-link-color);
}

.slide-menu-wrapper .slide-menu-item-number {
  color: var(--d-muted);
}

/* .selected is the keyboard cursor; .active is the slide you're on. */
.slide-menu-wrapper .active-menu-panel li.selected {
  background-color: var(--d-bg-alt);
  color: var(--r-link-color);
}

.slide-menu-wrapper .active-menu-panel li.active {
  color: var(--r-link-color);
  font-weight: 700;
}

.slide-menu-wrapper .slide-menu-toolbar {
  border-bottom-color: var(--d-border-strong);
}

.slide-menu-wrapper .slide-menu-toolbar > li {
  color: var(--d-muted);
}

.slide-menu-wrapper .slide-menu-toolbar > li.toolbar-panel-button:hover {
  color: var(--r-link-color-hover);
}

.slide-menu-wrapper .slide-menu-toolbar > li.active-toolbar-button {
  color: var(--r-link-color);
  text-shadow: none;
}

.slide-menu-wrapper .slide-menu-panel {
  color: var(--r-main-color);
}

.reveal .slide-menu-button {
  color: var(--r-link-color);
}

/* Custom deck-navigation panel (decks.htm). */
.slide-menu-wrapper .deck-links {
  list-style: none;
  margin: 0;
  padding: 0;
}

.slide-menu-wrapper .deck-links a {
  display: block;
  padding: 10px 18px;
  border-bottom: 1px solid var(--d-border);
  color: var(--r-main-color);
  text-decoration: none;
  font-size: 15px;
  line-height: 1.35;
}

.slide-menu-wrapper .deck-links a:hover,
.slide-menu-wrapper .deck-links a:focus-visible {
  background-color: var(--d-bg-alt);
  color: var(--r-link-color);
}

.slide-menu-wrapper .deck-links a[aria-current="page"] {
  border-left: 4px solid var(--d-purple);
  padding-left: 14px;
  font-weight: 700;
}

.slide-menu-wrapper .deck-links small {
  display: block;
  font-size: 12px;
  color: var(--d-muted);
  margin-top: 2px;
}

/* Custom controls sit bottom-left, clear of reveal's own arrows. */
#customcontrols > ul {
  background-color: transparent;
}

#customcontrols button {
  line-height: 0;
}

/* The narration player.

   The plugin gives its container an inline style from the `playerStyle` config
   in scripts.js, so geometry is set there -- an inline style beats a rule here.
   What is left for CSS is the pointer-events split: the container is switched
   off there because it is mostly empty space that would otherwise swallow
   clicks meant for whatever is behind it, and the <audio> itself is switched
   back on here so it stays usable. */
.reveal .audio-controls audio {
  pointer-events: auto;
}

/* Reveal own arrows must sit above the plugin furniture. The audio container
   is z-index 33 and the custom controls 40; the arrows shipped at 11, which is
   how they ended up unclickable. .controls itself is pointer-events: none --
   only the arrows inside it take clicks -- so raising it blocks nothing. */
.reveal .controls {
  z-index: 45;
}

/* On a phone there is no room for a centred bar between the two control
   clusters, so it moves above them and goes full width. These need !important
   to beat the inline style the plugin writes. */
@media (max-width: 700px) {
  .reveal .audio-controls {
    left: 4% !important;
    width: 92% !important;
    max-width: none !important;
    transform: none !important;
    bottom: 60px !important;
  }
}

/* --------------------------------------------------------------------------
   11. Icons
   The menu plugin runs with loadIcons: false, so no icon font is loaded.
   Its <i> elements are painted here with CSS masks over inline SVG data URIs
   — the same 24×24, stroke-based icon language the web pages use, and the
   same reason: no icon library. See docs/brand-guidelines.md.
   -------------------------------------------------------------------------- */

/* Paint. Deliberately does NOT set `display`: each menu item carries all
   three state markers (past / active / future) at once, and menu.css shows
   exactly one of them by toggling display. Forcing display here would reveal
   all three on every row. */
.slide-menu-wrapper i[class*="fa-"],
.slide-menu-wrapper i[data-icon],
.reveal .slide-menu-button i[class*="fa-"],
#customcontrols i[data-icon] {
  width: 1em;
  height: 1em;
  vertical-align: -0.14em;
  background-color: currentColor;
  -webkit-mask: center / contain no-repeat var(--icon);
  mask: center / contain no-repeat var(--icon);
}

/* Layout, for every icon except those three state markers. */
.slide-menu-wrapper i[class*="fa-"]:not(.past):not(.active):not(.future),
.slide-menu-wrapper i[data-icon],
.reveal .slide-menu-button i[class*="fa-"],
#customcontrols i[data-icon] {
  display: inline-block;
}

/* fa-fw is a width utility with no glyph of its own; it must not blank out
   the glyph class sitting next to it. */
.slide-menu-wrapper i.fa-fw {
  width: 1.25em;
}

/* The glyphs. Unscoped because no icon font is loaded, so these class names
   appear nowhere else in the project. */
i.fa-bars {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3 6h18M3 12h18M3 18h18'/%3E%3C/svg%3E");
}

i.fa-times {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E");
}

i.fa-images {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'%3E%3Crect x='2.5' y='7' width='14' height='11' rx='2'/%3E%3Cpath d='M7.5 3h12a2 2 0 0 1 2 2v9'/%3E%3C/svg%3E");
}

i.fa-check-circle {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M8 12.4l2.6 2.6L16 9.6'/%3E%3C/svg%3E");
}

i.fa-arrow-alt-circle-right {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M9 8.5l4 3.5-4 3.5'/%3E%3C/svg%3E");
}

i.fa-circle {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='8'/%3E%3C/svg%3E");
}

i[data-icon="decks"] {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='4' width='20' height='13' rx='2'/%3E%3Cpath d='M8 21h8M12 17v4'/%3E%3C/svg%3E");
}

#customcontrols i[data-icon="toggle-off"] {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2'%3E%3Crect x='2' y='6' width='20' height='12' rx='6'/%3E%3Ccircle cx='8' cy='12' r='3' fill='%23000'/%3E%3C/svg%3E");
}

#customcontrols i[data-icon="toggle-on"] {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2'%3E%3Crect x='2' y='6' width='20' height='12' rx='6'/%3E%3Ccircle cx='16' cy='12' r='3' fill='%23000'/%3E%3C/svg%3E");
}

#customcontrols i[data-icon="notes"] {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='3' width='16' height='18' rx='2'/%3E%3Cpath d='M8 8h8M8 12h8M8 16h5'/%3E%3C/svg%3E");
}

#customcontrols i[data-icon="chevron-down"] {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

#customcontrols i[data-icon="chevron-up"] {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 15l-6-6-6 6'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   12. Reduced motion and print
   -------------------------------------------------------------------------- */

/* scripts.js also switches reveal's own transition to 'none'. This covers the
   fragment and CSS animations reveal applies directly. */
@media (prefers-reduced-motion: reduce) {
  .reveal .fragment,
  .reveal .slides section,
  .deck-header .btn,
  .reveal .speaker-notes .line {
    transition: none !important;
  }

  .reveal .slides section {
    animation: none !important;
  }
}

@media print {
  .deck-header,
  #customcontrols {
    display: none !important;
  }

  /* The header only takes vertical space on screen. */
  .reveal {
    margin-top: 0;
    height: 100%;
  }
}

html.reveal-print .deck-header {
  display: none;
}

html.reveal-print .reveal {
  margin-top: 0;
}
