/*
 * SPDX-FileCopyrightText: 2026 ALASCA e.V. <hello@alasca.cloud>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/* ==========================================================================
   ALASCA — reveal.js theme, ported from the official PowerPoint master

   Source: alasca-Powerpoint-Master.potx  (colour scheme "Alasca", theme
   "2019-CloudandHeat-REDESIGN-NEU", 8 layouts, 16:9 at 10in × 5.625in).
   Every number below is read out of that file rather than invented.

   THE ONE THING THAT MAKES THIS WORK
   The deck runs reveal at 1920 × 1080 with margin 0 — the master's canvas
   (10in × 5.625in) at 192 dpi. So a coordinate here is the coordinate in
   PowerPoint, doubled: a shape at 45.4px sits where the .potx puts it, and the
   whole thing scales as one to whatever the projector offers. Font sizes are
   the master's points × 8/3 for the same reason.

   Why 192 dpi and not 96. At 96 dpi the canvas is 960 × 540, which reveal then
   has to blow *up* — scale 1.3 to 1.75 on any normal screen — and a browser
   rasterises text once and stretches the tiles it has until it gets round to
   re-rasterising. That stretch is visible as soft type that snaps sharp a
   moment after a slide arrives, badly in Safari. At 1920 × 1080 the scale is
   0.7 to 0.9 instead: the slide is drawn slightly larger than it is shown, and
   downscaled type has nothing to blur. Doubling every number keeps the .potx
   mapping intact — halve a coordinate to read it back in PowerPoint points.

   Placeholders are absolutely positioned, as they are in the .potx, instead of
   flowing — a layout is a set of boxes, and that is what a slide inherits.
   theme/alasca.css is the other, flowing theme; the two do not mix.

   TYPE  Overpass (theme/fonts.css → fonts/Overpass) — Bold 700 for titles,
         Light 300 for copy, as the master specifies. The master also names
         Montserrat for second-level bullets, in black on the Dark Blue
         field — unreadable, and plainly a leftover: those levels are set in
         Overpass here.

   COLOUR  Dark Blue #243746 is the field, Green #51E064 is the type accent —
           the ALASCA rule, and what the master already does. The six
           secondary colours are the .potx's accent2–accent6 + lt2, for
           diagrams only.
   ========================================================================== */

:root {
  /* ---- Colour scheme "Alasca", straight from ppt/theme/theme1.xml -------- */
  --pm-navy:        #243746;  /* dk2  — the field, on every layout          */
  --pm-green:       #51E064;  /* accent1 — titles, rules, bullets, numbers  */
  --pm-white:       #FFFFFF;  /* lt1  — body copy                          */
  --pm-black:       #000000;  /* dk1                                       */

  /* Secondary — infographics and diagrams only, never a field */
  --pm-sand:        #E1E173;  /* lt2      */
  --pm-yellow:      #F5E604;  /* accent2  */
  --pm-orange:      #EC7629;  /* accent3  */
  --pm-red:         #E1646E;  /* accent4  */
  --pm-light-blue:  #7BCAEF;  /* accent5  */
  --pm-blue:        #0E85A6;  /* accent6  */

  /* ---- Type scale: the master's points, at 96 dpi (pt × 4/3) ------------ */
  --pm-title:       74.67px;  /* 28 pt — the standard title                 */
  --pm-display:     160px;    /* 60 pt — the big title on the title layouts */
  --pm-body:        29.33px;  /* 11 pt — body copy, kickers, corner label   */
  --pm-list:        50px;     /* 18.75 pt — the body's bullets, a step up   */
  --pm-quote:       34.67px;  /* 13 pt — a quote hanging under a bullet     */
  --pm-agenda:      50px;  /* 16 pt — the numbered agenda                */
  --pm-footer:      14.67px;  /*  5.5 pt — the footer line                  */
  /* The master leads 28 pt titles at 32 pt; the 60 pt titles get the same
     ratio, having no leading of their own. */
  --pm-title-lh:    1.143;
  --pm-body-lh:     1.5;      /* the master's 150% on every body level      */

  /* ---- Placeholder insets (a:bodyPr in the .potx) ----------------------- */
  --pm-tins:        9.6px;    /* tIns 45720 EMU on body placeholders        */
  --pm-bullet-gap:  53.76px;  /* marL  256050 EMU — text after the bullet   */
  --pm-bullet-x:    23.56px;  /* marL + indent — where the bullet itself is */

  /* ---- Mermaid diagrams -------------------------------------------------- */
  /* Same token names theme/alasca.css uses, so the one renderer —
     templates/template/parts/deck-mermaid.html — draws a diagram in whichever
     theme the deck is wearing. Sized for the master's 1920 x 1080 canvas. */
  --mm-font:         "Overpass", system-ui, sans-serif;
  --mm-font-size:    26px;
  --mm-height:       680px;
  --mm-node-bg:      #2C4354;                   /* the field, one step raised  */
  --mm-node-line:    var(--pm-green);
  --mm-node-text:    var(--pm-white);
  --mm-alt-bg:       #1A2A38;
  --mm-alt-line:     var(--pm-light-blue);
  --mm-line:         rgba(255, 255, 255, 0.65);
  --mm-text:         var(--pm-white);
  --mm-cluster-bg:   rgba(255, 255, 255, 0.05);
  --mm-cluster-line: rgba(255, 255, 255, 0.20);
  --mm-label-bg:     var(--pm-navy);
  --mm-note-bg:      var(--pm-sand);
  --mm-note-text:    var(--pm-navy);
  --mm-1: var(--pm-green);      /* accent1..6, the master's own scheme        */
  --mm-2: var(--pm-light-blue);
  --mm-3: var(--pm-sand);
  --mm-4: var(--pm-orange);
  --mm-5: var(--pm-blue);
  --mm-6: var(--pm-red);

  /* ---- reveal.js core variables ----------------------------------------- */
  --r-background-color: var(--pm-navy);
  --r-main-font: "Overpass", system-ui, -apple-system, sans-serif;
  --r-main-font-size: var(--pm-body);
  --r-main-color: var(--pm-white);
  --r-heading-font: "Overpass", sans-serif;
  --r-heading-color: var(--pm-green);
  --r-heading-font-weight: 700;
  --r-code-font: "Overpass", ui-monospace, monospace;
  --r-link-color: var(--pm-green);
  --r-link-color-hover: var(--pm-white);
  --r-selection-background-color: var(--pm-green);
  --r-selection-color: var(--pm-navy);
}

/* -------------------------------------------------------------------------- */
/*  The canvas — the master's "Rechteck 8": Dark Blue, full bleed, every slide */
/* -------------------------------------------------------------------------- */
.reveal-viewport { background: var(--pm-navy); }

.reveal {
  font-family: var(--r-main-font);
  font-weight: 300;                       /* Overpass Light — the body face */
  font-size: var(--pm-body);
  color: var(--pm-white);
}

.reveal .slides { text-align: left; }

/* A slide is the master's canvas, and nothing else: no padding, no centring,
   so the boxes below land on their PowerPoint coordinates. */
.reveal .slides section,
.reveal .slides section section {
  width: 1920px;
  height: 1080px;
  padding: 0;
  top: 0 !important;
  line-height: var(--pm-body-lh);
}

.reveal h1, .reveal h2, .reveal h3, .reveal h4 {
  font-family: var(--r-heading-font);
  color: var(--pm-green);
  text-transform: none;
  letter-spacing: normal;
  margin: 0;
}
.reveal strong { font-weight: 700; color: var(--pm-white); }
.reveal em { font-style: normal; color: var(--pm-green); }
.reveal .accent { color: var(--pm-green); }
/* The counterpart to .accent, for the half of a line that should drop back to
   body white — a green title is already the accent, so the emphasis there runs
   the other way (the closing slide's "Stay in touch."). */
.reveal .white { color: var(--pm-white); }

/* A phrase lifted out of the running text. Sand is the master's lt2, and the
   copy on it flips to Dark Blue — white on Sand is unreadable, and the .potx
   already pairs these two that way for its note boxes. The padding is in em so
   the box grows with whatever size the phrase is set at. */
.reveal mark {
  background: var(--pm-sand);
  color: var(--pm-navy);
  padding: 0.06em 0.24em;
  border-radius: 3px;
}

/* The lead-in word of a "term: what it means" bullet. Green Bold, which is the
   master's own label register — the agenda's numbers and the tile column heads
   are both Green — but without their uppercase and letter-spacing, which a
   mixed-case German term like "Kapazität" would not survive. A lighter touch
   than <mark> on purpose: Sand marks the one line worth stopping on, so
   spending it on every label would flatten that. */
.reveal .term {
  font-weight: 700;
  color: var(--pm-green);
}

.reveal a {
  color: var(--pm-green);
  text-decoration: none;
  border-bottom: 2px solid rgba(81, 224, 100, 0.5);
}
.reveal a:hover { color: var(--pm-white); border-color: var(--pm-white); }

/* -------------------------------------------------------------------------- */
/*  Placeholders                                                              */
/*                                                                            */
/*  Each one is a box out of the .potx. The default position is the master's;  */
/*  a layout further down moves it where that layout puts it.                  */
/* -------------------------------------------------------------------------- */
/* :not(section) because a vertical stack is a <section> of <section>s, and
   reveal positions those itself — absolutely positioning them here would put
   every slide of the stack on top of the first. Placeholders are what this
   rule is for. */
.reveal .slides section > *:not(section) { position: absolute; margin: 0; }

/* Title — master: 28 pt Overpass Bold, Green, x 22.7 y 21.6 w 912 */
.reveal .pm-title {
  left: 45.4px; top: 43.2px; width: 1824px;
  font-size: var(--pm-title);
  font-weight: 700;
  line-height: var(--pm-title-lh);
  color: var(--pm-green);
}

/* Body — master: 11 pt Overpass Light, white, 150% leading. Bullets take the
   16 pt step instead — see "Lists" below. */
.reveal .pm-body {
  left: 22.6px; top: 287px; width: 1824px;
  padding-top: var(--pm-tins);
  font-size: var(--pm-body);
  font-weight: 300;
  line-height: var(--pm-body-lh);
  color: var(--pm-white);
}
.reveal .pm-body > *:first-child { margin-top: 0; }
.reveal .pm-body p { margin: 0 0 0.75em 0; line-height: var(--pm-body-lh); }

/* Subtitle / kicker: 28 pt boxes on the title and start layouts. Bold by
   default (the master's own weight); .light is the Light cut the two title
   layouts ask for. */
.reveal .pm-sub,
.reveal .pm-kicker {
  font-size: var(--pm-title);
  font-weight: 700;
  line-height: var(--pm-title-lh);
  color: var(--pm-white);
}
.reveal .pm-sub.thin,
.reveal .pm-kicker.thin { font-weight: 300; }

/* The Green hairline under a title — "Gerader Verbinder", 0.75 pt accent1 */
.reveal .pm-rule {
  height: 0;
  border-top: 2px solid var(--pm-green);
}

/* Corner label — 11 pt Overpass Light Green with a slanted rule beside it,
   top right on both title layouts. The rule is the .potx connector: it runs
   from (792.4, 21.3) to (849.3, 119.8). */
.reveal .pm-tag {
  left: 1641.6px; top: 45.8px; width: 238.4px; height: 192px;
  padding-left: 23.56px;                      /* marL 112050 EMU */
  font-size: var(--pm-body);
  font-weight: 300;
  line-height: 34.67px;                       /* the master's 13 pt leading */
  color: var(--pm-green);
}
.reveal .pm-tag::before {
  content: "";
  position: absolute;
  left: -28.4px; top: -1.6px;
  width: 113.8px; height: 197px;
  /* The connector itself, drawn at the box's own size so the 0.75 pt stroke
     stays 0.75 pt. Inline, so it costs no file and no request. */
  background: url('data:image/svg+xml;utf8,\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56.9 98.5">\
<line x1="0" y1="0" x2="56.9" y2="98.5" stroke="%2351E064" stroke-width="1"/></svg>')
    no-repeat 0 0 / 100% 100%;
}

/* -------------------------------------------------------------------------- */
/*  Lists — the master's bullet levels                                        */
/* -------------------------------------------------------------------------- */
.reveal ul, .reveal ol { display: block; margin: 0; padding: 0; list-style: none; }

/* A bullet reads from the back of the room, so it takes the master's 16 pt
   step rather than the 11 pt of running copy — the agenda's size, and the only
   step the .potx has between body copy and a 28 pt title. Set in px, not em,
   so a nested list is the size of the one above it instead of compounding a
   step down at every level. */
.reveal .pm-body ul li,
.reveal .pm-body ol li {
  position: relative;
  padding-left: var(--pm-bullet-gap);
  margin: 0 0 0.28em 0;                     /* spcBef 2.2 pt between items */
  font-size: var(--pm-list);
  line-height: var(--pm-body-lh);
}
/* lvl1 · lvl3-5: a Green ● in Overpass */
.reveal .pm-body ul li::before {
  content: "\25CF";
  position: absolute;
  left: var(--pm-bullet-x);
  color: var(--pm-green);
  /* Sized against body copy rather than the enlarged list text: the bullet
     slot is a fixed master coordinate (marL), so a glyph that grew with the
     text would close the gap in front of the first word. This keeps the ●
     the size the .potx draws it. The line box is the list item's own, so the
     two still share a baseline the way PowerPoint sets a bullet character. */
  font-size: calc(var(--pm-body) * 0.8);
  line-height: calc(var(--pm-list) * var(--pm-body-lh));
}
/* Numbered levels: "1." in Green, the master's buAutoNum */
.reveal .pm-body ol { counter-reset: pm; }
.reveal .pm-body ol li { counter-increment: pm; }
.reveal .pm-body ol li::before {
  content: counter(pm) ".";
  position: absolute;
  left: var(--pm-bullet-x);
  color: var(--pm-green);
}
/* Deeper levels step in by the master's marL, and keep their own face */
.reveal .pm-body li > ul,
.reveal .pm-body li > ol { margin: 0.28em 0 0 41.8px; }
/* A sub-point steps down from the bullet above it. theme/alasca.css already
   does this (0.86em on a nested li); the master needed it once bullets grew,
   because a second level set at the full list size runs a slide of any real
   length off the bottom of the canvas. Calculated from --pm-list rather than
   written in em, so a third level does not step down again. */
.reveal .pm-body li li { font-size: calc(var(--pm-list) * 0.85); }

/* -------------------------------------------------------------------------- */
/*  Code, quotes, tables — not in the master, needed by any real talk         */
/*  Set in the master's own idiom: Green accents on the Dark Blue field.      */
/* -------------------------------------------------------------------------- */
.reveal pre { width: 100%; box-shadow: none; margin: 0; font-size: 23.4px; }
.reveal pre code {
  background: rgba(0, 0, 0, 0.28);
  border: 2px solid rgba(81, 224, 100, 0.22);
  padding: 28px 32px;
  line-height: 1.5;
  max-height: 680px;
}
.reveal code { font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; }
.reveal :not(pre) > code {
  background: rgba(0, 0, 0, 0.28);
  color: var(--pm-green);
  padding: 2px 10px;
  font-size: 0.9em;
}

.reveal blockquote {
  background: none; box-shadow: none; border: 0; padding: 0; width: 100%;
  font-size: var(--pm-title);
  font-weight: 300;
  line-height: var(--pm-title-lh);
  color: var(--pm-white);
}
.reveal blockquote cite {
  display: block;
  margin-top: 36px;
  font-size: var(--pm-body);
  font-style: normal;
  color: var(--pm-green);
}

/* A quote hanging under a bullet — the source's own words where a paraphrase
   would weaken the point. Not the pull quote above: this one lives inside a
   list item, so it steps *down* from the bullet instead of up, and takes a
   Green rule rather than a quotation mark, which would only compete with the
   ● already sitting beside it. No italic — the deck ships no italic cut, so
   slanting it would draw a synthesised face. */
.reveal .pm-body blockquote {
  width: auto;
  margin: 0.5em 0 0.7em 0;
  padding: 4px 0 4px 28px;
  border-left: 3px solid var(--pm-green);
  font-size: var(--pm-quote);
  font-weight: 300;
  line-height: var(--pm-body-lh);
  color: rgba(255, 255, 255, 0.78);
}
/* The attribution, a step down again and in Green so the eye reads it as a
   label rather than as the last line of the quote. */
.reveal .pm-body blockquote cite {
  display: block;
  margin-top: 10px;
  font-size: 0.72em;
  font-style: normal;
  color: var(--pm-green);
}

.reveal table { border-collapse: collapse; width: 100%; font-size: var(--pm-body); }
.reveal table th {
  text-align: left; font-weight: 700; color: var(--pm-green);
  padding: 14px 24px 14px 0; border-bottom: 2px solid var(--pm-green);
}
.reveal table td {
  padding: 14px 24px 14px 0;
  border-bottom: 2px solid rgba(255, 255, 255, 0.14);
}

/* -------------------------------------------------------------------------- */
/*  Artwork: the logo, the hexagon mark, the double chevron                    */
/* -------------------------------------------------------------------------- */
.reveal .logo-defs { display: none; }
.reveal .al-logo, .reveal .al-mark { display: block; width: auto; fill: currentColor; }
.reveal .al-logo { aspect-ratio: 780.8 / 642.4; }
.reveal .al-mark { aspect-ratio: 350.3 / 390.6; }

/* The hexagon mark, top right on the one-line standard layout: x 892.5 y 21.7,
   41.8 × 46.7, in Green — the .potx uses the green cut of the mark. */
.reveal .pm-mark {
  left: 1785px; top: 43.4px;
  color: var(--pm-green);
  line-height: 0;
}
.reveal .pm-mark .al-mark { height: 93.4px; }

/* The full lockup on the start layout. The .potx art carries the claim line
   under the wordmark and so is a little taller; this is the same official
   artwork from templates/template/parts/logo-sprite.html, set to the master's
   optical size inside the master's box, rather than a second copy of the file. */
.reveal .pm-logo {
  left: 637.8px; top: 93.4px; width: 644.4px; height: 593.2px;
  display: flex; align-items: center; justify-content: center;
  color: var(--pm-green);
}
.reveal .pm-logo .al-logo { height: 530px; }

/* The double chevron — "Pfeil_d" in the .potx, a heavy stroke followed by a
   hairline one, 115.5 × 212. Green on the dark field; .white is the cut the
   right-hand chevron on the 5_Titel B layout uses. */
.reveal .pm-chevron {
  width: 231px; height: 424px;
  color: var(--pm-green);
  line-height: 0;
}
.reveal .pm-chevron.white { color: var(--pm-white); }
.reveal .pm-chevron svg { display: block; width: 100%; height: 100%; }

/* Picture placeholder — full bleed behind everything, as in the .potx. Empty,
   it shows itself; drop an <img> in and the image takes over. */
.reveal .pm-photo {
  left: 0; top: 0; width: 1920px; height: 1080px;
  overflow: hidden;
  z-index: 0;
}
.reveal .pm-photo img,
.reveal .pm-photo video { width: 100%; height: 100%; object-fit: cover; display: block; }
.reveal .pm-photo:empty {
  background: rgba(255, 255, 255, 0.04);
  outline: 2px dashed rgba(81, 224, 100, 0.45);
  outline-offset: -14px;
}
/* Top left — the one corner no picture layout puts anything in, and clear of
   reveal's controls and slide number. */
.reveal .pm-photo:empty::after {
  content: "Picture placeholder — put an <img> in here";
  position: absolute; left: 52px; top: 44px;
  font-size: var(--pm-body);
  color: rgba(81, 224, 100, 0.75);
}
/* Everything else sits over the picture */
.reveal .slides section > *:not(.pm-photo) { z-index: 1; }

/* -------------------------------------------------------------------------- */
/*  The eight layouts of alasca-Powerpoint-Master.potx                        */
/*  Class names keep the master's own numbering, so a slide says which layout  */
/*  it is on and the two can be compared side by side.                         */
/* -------------------------------------------------------------------------- */

/* --- 0_Start ALASCA — logo over a centred two-line subtitle ---------------- */
.reveal .l-start .pm-sub {
  left: 37.8px; top: 787.4px; width: 1844.4px;
  text-align: center;
}

/* --- 1_Start ALASCA Bild — full-bleed picture, kicker + Green statement ---- */
.reveal .l-start-image .pm-kicker {
  left: 85.4px; top: 484.4px; width: 574.4px;
  font-size: var(--pm-body);
  font-weight: 300;
  line-height: var(--pm-body-lh);
}
.reveal .l-start-image .pm-sub {
  left: 85.4px; top: 582.6px; width: 574.4px;
  color: var(--pm-green);
}

/* --- 2_Start ALASCA Bild — the same, with a 60 pt title ------------------- */
.reveal .l-start-image-title .pm-title {
  left: 76.8px; top: 204.8px; width: 1128.6px;
  font-size: var(--pm-display);
}
.reveal .l-start-image-title .pm-sub {
  left: 85.4px; top: 582.6px; width: 574.4px;
}

/* --- 1_Standard-Einzeilig — one-line title, rule, bullets, corner mark ----- */
.reveal .l-standard .pm-title { left: 45.4px; top: 54.2px; width: 1822.2px; }
.reveal .l-standard .pm-rule  { left: 45.4px; top: 156px;   width: 1823.2px; }
/* The master parks .pm-body at one fixed y (287) for every layout, so content
   does not jump when a title runs to a second line. On this layout, whose
   title is one line, that leaves 131px of field between the rule and the first
   bullet — against the 38.4px the two-line layout gets, because its rule sits
   lower. Same gap here as there: the master's own spacing, measured from the
   rule rather than from the top of the canvas. */
.reveal .l-standard .pm-body  { top: 194.4px; }

/* --- 2_Standard-Einzeilig — the same with room for a two-line title -------- */
.reveal .l-standard-2 .pm-title { left: 45.4px; top: 54.2px; width: 1823.2px; }
.reveal .l-standard-2 .pm-rule  { left: 45.4px; top: 248.6px; width: 1823.2px; }

/* --- 2_Agenda — chevron, title, rule, and the numbered running order ------- */
.reveal .l-agenda .pm-chevron { left: 76.6px; top: 168.4px; }
.reveal .l-agenda .pm-title   { left: 379.4px; top: 344px; width: 1131px; }
.reveal .l-agenda .pm-rule    { left: 384px; top: 445.8px; width: 1131px; }
.reveal .l-agenda .pm-body    { left: 380px; top: 493px; width: 1131px; }
/* 16 pt Overpass Bold, numbered "1." — marL 454950 EMU, indent -342900 */
.reveal .l-agenda .pm-body ol li {
  padding-left: 95.6px;
  font-size: var(--pm-agenda);
  font-weight: 700;
}
.reveal .l-agenda .pm-body ol li::before { left: var(--pm-bullet-x); }

/* --- 4_Titel A — kicker over a 60 pt title, subtitle under, corner label --- */
.reveal .l-title-a .pm-chevron { left: 76.6px; top: 310px; }
.reveal .l-title-a .pm-kicker  { left: 373.6px; top: 295.8px; width: 1450.4px; }
.reveal .l-title-a .pm-title   {
  left: 370.4px; top: 438px; width: 1438.4px;
  font-size: var(--pm-display);
}
.reveal .l-title-a .pm-sub     { left: 370.2px; top: 655.6px; width: 1467.2px; }

/* --- 5_Titel B — 60 pt title with a chevron on either side ----------------- */
.reveal .l-title-b .pm-chevron       { left: 76.6px; top: 168.4px; }
.reveal .l-title-b .pm-chevron.white { left: 1532.8px; top: 475.6px; }
.reveal .l-title-b .pm-title {
  left: 371.4px; top: 204.8px; width: 1128.6px;
  font-size: var(--pm-display);
}
.reveal .l-title-b .pm-sub { left: 372.4px; top: 584.2px; width: 1144px; }

/* -------------------------------------------------------------------------- */
/*  Tinting a flat logo                                                       */
/* -------------------------------------------------------------------------- */
/* A logo drawn in one flat colour — the ALASCA project marks in img/projects/
   are black paths with no `fill` attribute at all — is the wrong colour on
   half the slides in a deck. Rather than keep a second file per colour:

     <img class="tint-white" src="../../img/projects/ALASCA-Krake-black.svg"
          alt="Krake" />

   `brightness(0)` crushes every colour in the artwork to black whatever it
   started as, and `invert(1)` then lifts the whole thing to white. Going
   through black first is what makes it safe on artwork you have not looked at:
   plain `invert(1)` would turn a coloured logo into its opposite instead of
   into white. It only suits flat, single-colour marks — run it over a
   photograph or a two-tone lockup and you get a silhouette, which is a fine
   thing to want and a bad thing to be surprised by.

   These work on <img>, so nothing about the file or the markup changes. A
   filter cannot reach *into* an external SVG, which is also why the fills in
   those files stay unreachable from here — see .tint below for arbitrary
   colours. */
.reveal img.tint-white { filter: brightness(0) invert(1); }
.reveal img.tint-black { filter: brightness(0); }

/* Any colour, not just the two ends. The artwork becomes a mask and the
   element paints its own `color` through it, so the mark takes a brand token
   like anything else:

     <span class="tint" role="img" aria-label="Krake"
           style="mask-image: url(../../img/projects/ALASCA-Krake-black.svg);
                  -webkit-mask-image: url(../../img/projects/ALASCA-Krake-black.svg)">
     </span>

   The image goes on the element rather than into a custom property here, and
   that is not a style choice: a relative url() inside a custom property is
   resolved against the stylesheet that used it, not the page — Chrome turns
   ../../img/… into theme/img/… and the mark silently disappears. On the
   element it resolves against the deck, the same ../../ everything else on a
   slide is written with. Both spellings, because Safari wants the prefix.

   The shape comes from the file's transparency, so this wants artwork on a
   transparent ground — which the project marks are. It has no intrinsic size,
   having no content: give it a box, or drop it in one that is already sized,
   like the project slide's .project-logo. */
.reveal .tint {
  display: block;
  width: 100%; height: 100%;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}

/* -------------------------------------------------------------------------- */
/*  Link lists                                                                */
/* -------------------------------------------------------------------------- */
/* A row is icon · what it is · where it is, with the address pushed to the
   right edge so a column of them lines up as a column of addresses:

     <ul class="links">
       <li>
         <i class="fa-solid fa-globe ic" aria-hidden="true"></i>
         <span class="k">Website</span>
         <a href="https://alasca.cloud/">alasca.cloud</a>
       </li>
     </ul>

   Not a .potx thing — the master has no list like it — but the project card
   and the closing slide both want one, so it lives here rather than inside
   either layout. Same class names as theme/alasca.css uses, so the markup is
   the same in both themes. `auto auto 1fr` is what does the aligning: the icon
   and the label take what they need and the address gets the rest, right-set,
   whatever the label's length. */
.reveal .links { list-style: none; margin: 0; padding: 0; }
.reveal .links li {
  display: grid;
  grid-template-columns: auto auto 1fr;      /* icon · label · address */
  align-items: center;
  column-gap: 24px;
  margin: 0; padding: 10px 0;
  border-bottom: 2px solid rgba(255, 255, 255, 0.10);
}
.reveal .links li::before { content: none; }
.reveal .links li:last-child { border-bottom: 0; }
/* The glyph is a Font Awesome <i>, so the tile behind it is a flex box that
   centres it rather than a box sized to artwork: inline-flex overrides the
   inline-block Font Awesome sets, and the fixed width beats its 1.25em. */
.reveal .links .ic {
  width: 52px; height: 52px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 11px;
  font-size: 24px;
  color: var(--pm-green);
  background: rgba(81, 224, 100, 0.08);
  border: 2px solid rgba(81, 224, 100, 0.26);
}
.reveal .links .k {
  font-size: 26px; font-weight: 700; color: var(--pm-white);
  white-space: nowrap;
}
.reveal .links a {
  font-size: 24px;
  color: var(--pm-green);
  border-bottom: 0;
  text-align: right;
  word-break: break-all;
}
.reveal .links a:hover { color: var(--pm-white); }

/* -------------------------------------------------------------------------- */
/*  Closing slide — thank you, and where to find everything                    */
/* -------------------------------------------------------------------------- */
/* Not a .potx layout either: the master closes on 0_Start ALASCA, the lockup
   over a statement, which says goodbye but leaves the room with nothing to
   write down. `.l-closing` is the lockup at reading size over the addresses
   themselves, in two columns.

   templates/template-master/slides/11-closing-links.html is the slide; it is
   templates/template/slides/closing-links.html with the heading swapped for
   `.pm-title` + `.pm-rule`, so the two themes close the same way. */
.reveal .l-closing .pm-logo {
  left: 45.4px; top: 48px; width: auto; height: 132px;
  display: flex; align-items: center;
}
.reveal .l-closing .pm-logo .al-logo { height: 132px; }
.reveal .l-closing .pm-title { left: 45.4px; top: 224px; width: 1823.2px; }
.reveal .l-closing .pm-rule  { left: 45.4px; top: 326px; width: 1823.2px; }

.reveal .l-closing .link-groups {
  left: 45.4px; top: 378px; width: 1823.2px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 120px;
}
/* The column heading is the body face tracked out — the master has no kicker
   of its own, and this is the same treatment .l-project gives a .fact-k. */
.reveal .l-closing .link-group h3 {
  font-size: 22.4px;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
  margin: 0 0 18px 0;
}

/* -------------------------------------------------------------------------- */
/*  Project card                                                              */
/* -------------------------------------------------------------------------- */
/* One slide, one project — the slide a deck repeats once per project, so the
   room learns where to look once and then stops having to. The .potx has no
   such layout: `.l-project` borrows 1_Standard-Einzeilig's header, the 28 pt
   Green name over the hairline, and places the rest itself.

     <section class="l-project">
       <h2 class="pm-title">Yaook</h2>
       <div class="pm-rule"></div>
       <div class="project-logo"><img src="img/logo.svg" alt="Yaook" /></div>
       <p class="lede">One sentence about what it does.</p>
       <div class="project-facts">
         <div class="fact">      ...a .fact-k label and its content   </div>
         <div class="fact wide"> ...one that spans both columns       </div>
       </div>
       <figure class="qr-card">
         <div class="qr" data-qr="https://…"></div>
         <figcaption><a href="https://…">the URL, spelled out</a></figcaption>
       </figure>
     </section>

   Same class names as theme/alasca.css uses for the same slide, so a project
   is portable between the two themes — only the heading changes. Canvas px
   throughout, like every other number in this file: below the hairline the QR
   keeps the right edge for itself and the rest shares the 1400 px to its left.
   Above it nothing competes — the QR card starts at y 226 — so the heading
   takes the body's full width, which is what lets a long name and its slogan
   stay on the one line the layout is built around. */
.reveal .l-project .pm-title { left: 45.4px; top: 54.2px; width: 1823.2px; }
/* The project's own slogan, riding the title: the master has one title size
   and this is not it, so <small> steps down to the body face and drops the
   Green — two Green weights on one line read as two headings. */
.reveal .l-project .pm-title small {
  font-size: 34.67px;                       /* 13 pt, the lede's size */
  font-weight: 300;
  color: rgba(255, 255, 255, 0.62);
  white-space: nowrap;
}
.reveal .l-project .pm-rule  { left: 45.4px; top: 156px;  width: 1823.2px; }

/* The logo leads. A project is recognised by its artwork before its name, so
   the slot is sized to be read from the back of the room rather than to sit
   politely beside the heading.

   The <img> is capped on both axes and set to `contain`, which is what lets a
   wide lockup and a square mark share one slot: whichever dimension binds
   first wins, and neither is ever stretched. */
.reveal .l-project .project-logo {
  left: 45.4px; top: 186px; width: 280px; height: 244px;
  display: flex; align-items: center; justify-content: flex-start;
}
.reveal .l-project .project-logo img,
.reveal .l-project .project-logo svg {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
}

/* The one sentence, beside the logo. 13 pt Light rather than the master's 11 pt
   body: this is the only prose on the slide and the thing the room reads while
   you say the project's name, so it wants to be a step up from a caption.

   It starts close to the logo because the marks are square — every ALASCA
   project mark is a 1000 x 1000 viewBox — so a slot sized for a wide lockup
   left 300 px of empty field between the two. The slot is square now and the
   sentence takes the width that frees up. A wide lockup still fits; it scales
   to the slot's width instead of its height. */
.reveal .l-project .lede {
  left: 360px; top: 196px; width: 1100px;
  font-size: 34.67px;                       /* 13 pt */
  font-weight: 300;
  line-height: var(--pm-body-lh);
  color: rgba(255, 255, 255, 0.78);
}

/* The facts, two across, with the link list spanning both — it is the widest
   thing on the slide, and splitting a URL over two columns helps nobody. */
/* The facts, two across, with the link list spanning both — it is the widest
   thing on the slide, and splitting a URL over two columns helps nobody.

   Three columns, not two, and that is what keeps the licence free: it rides
   the first row beside the names and the languages instead of opening a second
   row, which on a project with three representatives would have pushed the
   links into the footer. Widths are ratios rather than thirds because the
   three carry very different amounts — names are the widest, a licence is one
   short token.

   The vertical numbers are set by the worst case rather than the typical one:
   three representatives and three links is the tallest a project has come out
   — Tarook — and that has to clear the footer without the slide being told.
   Measured, not guessed: at three of each the last link now ends around 960
   against a footer that starts at 1028. Two of each simply leaves more air. */
.reveal .l-project .project-facts {
  left: 45.4px; top: 480px; width: 1400px;
  display: grid;
  grid-template-columns: 1.3fr 1fr 0.7fr;
  gap: 28px 56px;
  align-items: start;
}
.reveal .l-project .fact.wide { grid-column: 1 / -1; }

/* The label above a block. The master has no kicker of its own at this size,
   so it is the body face tracked out and set in Green — the .potx's own way of
   marking something as a label rather than as copy. */
.reveal .l-project .fact-k {
  font-size: 22.4px;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pm-green);
  margin: 0 0 14px 0;
}

/* Who is answerable. A name is the thing being looked up, so it carries the
   weight; the role sits under it, muted. No bullets — these are a set of
   names, not a sequence of points, and the master's Green ● would read as one. */
.reveal .l-project .people { list-style: none; margin: 0; padding: 0; }
/* Three or more names go two abreast. A stacked list of three is the one thing
   on this slide tall enough to push the links into the footer — the grid row
   is as tall as its tallest cell, and that cell is always this one — and the
   fact column is wide enough for two names side by side anyway. Two names or
   one stay in a single column, where a second would just look like a gap. */
.reveal .l-project .people:has(li:nth-child(3)) {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 32px;
}
.reveal .l-project .people li {
  display: flex; flex-direction: column;
  margin: 0 0 8px 0;
  padding-left: 0;
  line-height: 1.25;
}
.reveal .l-project .people li::before { content: none; }
.reveal .l-project .people li:last-child { margin-bottom: 0; }
.reveal .l-project .people .who {
  font-size: 29.33px; font-weight: 700; color: var(--pm-white);
}
.reveal .l-project .people .role {
  font-size: 22.4px; font-weight: 300; color: rgba(255, 255, 255, 0.62);
}

/* Languages as badges rather than a comma list: the count is the information
   as much as the names are, and badges make it countable at a glance. */
.reveal .l-project .langs {
  display: flex; flex-wrap: wrap; gap: 12px;
  margin: 0;
}
/* The licence is metadata like the languages beside it, so it takes the same
   pill — but in white rather than Green, or the eye reads it as one more
   language in the list next door. */
.reveal .l-project .lang.lic {
  color: var(--pm-white);
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.22);
}
.reveal .l-project .lang {
  font-size: 22.4px;
  font-weight: 400;
  line-height: 1;
  padding: 12px 20px;
  border-radius: 999px;
  color: var(--pm-green);
  background: rgba(81, 224, 100, 0.08);
  border: 2px solid rgba(81, 224, 100, 0.26);
  white-space: nowrap;
}

/* The QR patch, on the right edge. Its own light field, never inverted —
   parts/deck-qr.html says why. --qr-bg and --qr-fg are what the renderer
   reads; setting them here rather than in the script is what lets the two
   themes colour a code differently without touching the code that draws it. */
.reveal .l-project .qr-card {
  --qr-bg: var(--pm-white);
  --qr-fg: var(--pm-navy);
  left: 1520px; top: 226px; width: 354px;
  display: flex; flex-direction: column; align-items: center; gap: 20px;
}
.reveal .qr {
  width: 100%;
  aspect-ratio: 1;
  background: var(--qr-bg);
  border-radius: 14px;
  padding: 18px;
  box-sizing: border-box;
}
.reveal .qr svg { display: block; width: 100%; height: 100%; }
.reveal .l-project .qr-card figcaption {
  font-size: 24px;
  letter-spacing: 0.04em;
  color: var(--pm-green);
  text-align: center;
}

/* What the project is *about*, under the code. A controlled vocabulary — the
   same handful of terms across every project slide — so the room can place a
   project in the stack before it has heard a word about it, and so two
   projects that share a context visibly share a tag. A term that appears on
   one slide only classifies nothing; if a new project needs one, it is worth
   asking whether an existing term covers it first.

   They ride the QR's column rather than joining the facts because they answer
   the same question the logo does — what am I looking at — while the facts
   below answer who and where. Filled Green, the only solid shape on the slide
   besides the QR patch: these are meant to be read at a glance from the back
   of the room, which the outlined pills in "Geschrieben in" are not, and the
   fill is what keeps the eye from filing them as one more language list.

     <div class="project-tags">
       <p class="fact-k">Kontext</p>
       <ul class="ptags"><li>Kubernetes</li>…</ul>
     </div>

   Four or five terms. Six starts a fourth row, and the block has the field
   between the QR caption at ~634 and the footer at 1028 to live in. */
/* Left, not centred, and a clear field under the URL: ragged-right tags read
   as a list to be scanned down, and they hang off the same 1520 line as the QR
   patch above them, which is one edge instead of two. The gap to the caption
   is deliberate — pulled up close, the tags read as part of the link. */
.reveal .l-project .project-tags {
  left: 1520px; top: 716px; width: 354px;
}
.reveal .l-project .project-tags .fact-k { margin-bottom: 18px; }
.reveal .l-project .ptags {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 12px;
}
/* The master's Green ● would read as a sixth tag. */
.reveal .l-project .ptags li::before { content: none; }
.reveal .l-project .ptags li {
  margin: 0; padding: 11px 20px;
  font-size: 24px; font-weight: 400; line-height: 1;
  border-radius: 999px;
  color: var(--pm-navy);
  background: var(--tag-accent, var(--pm-green));
  white-space: nowrap;
}
/* Four families, out of the master's own accents, so that a colour means the
   same thing on every project slide — the tags are only worth reading across
   slides if the eye can group them without reading them:

     Green   the platform it is built on  Kubernetes, OpenStack, Bare Metal,
                                         Gardener, IaaS
     Blue    the terrain it spans        Multi-Cloud, Hybrid Cloud, Netzwerk,
                                         Internet Exchange, Multi-Tenancy
     Sand    how it is operated          GitOps, Lifecycle Management,
                                         Automatisierung, Scheduling
     Orange  the discipline it is in     Monitoring, Observability, Alerting,
                                         Sicherheit

   Navy text throughout: all four accents are light enough to carry it, and a
   pill that changed its text colour with its fill would stop being one shape.
   Same class names the tiles use for their accents, a few sections up. */
.reveal .l-project .ptags .c-blue   { --tag-accent: var(--pm-light-blue); }
.reveal .l-project .ptags .c-sand   { --tag-accent: var(--pm-sand); }
.reveal .l-project .ptags .c-orange { --tag-accent: var(--pm-orange); }

/* -------------------------------------------------------------------------- */
/*  Screenshots                                                               */
/* -------------------------------------------------------------------------- */
/* A picture that has to be *read* rather than looked at — a dashboard, a
   terminal, a diagram someone else drew. Unlike .pm-photo, which is the
   master's full-bleed field and crops with `cover`, this one is contained: a
   screenshot loses its point the moment an edge is cut off.

     <section class="l-standard">
       <h2 class="pm-title">Level 1<small> — the cluster</small></h2>
       <div class="pm-rule"></div>
       <figure class="shot">
         <img src="img/dashboard.png" alt="…" />
         <figcaption>What to look at, in one line.</figcaption>
       </figure>
     </section>

   The box takes everything between the hairline and the footer, and the image
   takes everything the caption does not. `object-position: top` because a
   dashboard puts its alerts at the top: if something has to fall off the
   bottom, that is the half to lose. */
.reveal .l-standard .shot {
  left: 45.4px; top: 206px; width: 1823.2px; height: 790px;
  display: flex; flex-direction: column; gap: 18px;
  margin: 0;
}
/* No frame around the picture. An outline was here once, on the theory that a
   dark dashboard needs an edge or it bleeds into the slide; in practice it read
   as a border someone forgot to take off, on screenshots as much as on photos.
   A picture that ends in its own subject does not need help ending. */
.reveal .shot img {
  flex: 1; min-height: 0;
  width: 100%;
  object-fit: contain;
  object-position: center top;
}

/* Centred, not left-aligned on the body edge: `contain` centres the picture in
   the box, and a caption belongs under the middle of what it is about — whether
   it credits a photograph or says what to look at in a dashboard. */
.reveal .shot figcaption {
  flex: none;
  font-size: 25.6px;
  font-weight: 300;
  line-height: var(--pm-body-lh);
  color: rgba(255, 255, 255, 0.78);
  text-align: center;
}

/* The photo credit under a caption: the same line, one step quieter, so the
   attribution reads as a footnote to the caption rather than as more caption. */
.reveal .shot figcaption small {
  display: inline-block;
  font-size: 20px;
  color: rgba(255, 255, 255, 0.55);
}

/* -------------------------------------------------------------------------- */
/*  Icon tiles                                                                */
/* -------------------------------------------------------------------------- */
/* A grid of small boxes, each an icon over a name and a line about it — the
   slide for "here is the whole set at once". The .potx has no such layout, so
   this is 1_Standard-Einzeilig with the grid where the body placeholder goes:

     <section class="l-standard">
       <h2 class="pm-title">Four across</h2>
       <div class="pm-rule"></div>
       <div class="tiles t4"> ...four .tile blocks... </div>
     </section>

   Same class names as theme/alasca.css uses, so the grid itself is portable
   between the two themes — only the heading above it changes. The count is a
   class because the grid has to know it: `.t4` is four across, `.t6` three
   across in two rows, `.t8` four across in two rows. Six in a four-column grid
   leaves two orphans on the second row, which is the one arrangement that
   always looks like a mistake.

   Canvas px throughout, like every other number in this file: the grid spans
   the body's full width (x 45.4, w 1823.2) and starts below the hairline, and
   the two-row densities step their type down so both rows clear the footer. */
.reveal .l-standard .tiles {
  left: 45.4px; top: 232px; width: 1823.2px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 40px;
  align-items: stretch;
}
.reveal .tiles.t4 { grid-template-columns: repeat(4, 1fr); }
.reveal .tiles.t6 { grid-template-columns: repeat(3, 1fr); gap: 34px; }
.reveal .tiles.t8 { grid-template-columns: repeat(4, 1fr); gap: 28px; }
/* Two across, two down. Rows are pinned rather than left to the content so the
   four boxes form one square block whatever the lines inside them run to: the
   field between the grid's top (232) and the footer (~1000) is 768px, which is
   two 364px rows and the gap. */
.reveal .tiles.t2x2 {
  grid-template-columns: repeat(2, 1fr);
  /* The field between the grid's top (232) and the footer (~1000) is 768px.
     Pinning the height and splitting it in two equal rows is what keeps the
     four boxes a square block: rows sized to their content would leave the
     two halves different heights the moment one tile carries a line more.
     768 less the 40px gap is two 364px rows, which holds an icon, a name and
     two lines of copy — a third line is where a tile starts to spill. */
  height: 768px;
  grid-template-rows: repeat(2, minmax(0, 1fr));
}

.reveal .tile {
  --tile-accent: var(--pm-green);
  /* The field, one step raised — the same value the diagrams use for a node,
     so a tile and a Mermaid box read as the same surface. */
  background: #2C4354;
  border: 2px solid rgba(255, 255, 255, 0.14);
  border-radius: 8px;
  padding: 44px 40px 48px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* The glyph is a Font Awesome <i>, so the tile behind it is a flex box that
   centres it rather than a box sized to artwork: inline-flex overrides the
   inline-block Font Awesome sets, and the fixed width beats its 1.25em. */
.reveal .tile .ic {
  width: 88px; height: 88px;
  /* Never let the column's flex shrink it: a squeezed icon stops being a
     square and reads as a pill, which is worse than the text running long. */
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 18px;
  font-size: 40px;
  color: var(--tile-accent);
  background: color-mix(in srgb, var(--tile-accent) 10%, transparent);
  border: 2px solid color-mix(in srgb, var(--tile-accent) 26%, transparent);
  margin-bottom: 32px;
}
/* The name sits at the master's 16 pt Bold — the agenda's size, which is the
   only step the .potx has between 11 pt copy and a 28 pt title. */
.reveal .tile h3 {
  font-size: var(--pm-agenda);
  font-weight: 700;
  line-height: 1.15;
  color: var(--pm-white);
  margin: 0 0 16px 0;
}
.reveal .tile p {
  font-size: var(--pm-body);
  font-weight: 300;
  line-height: var(--pm-body-lh);
  color: rgba(255, 255, 255, 0.78);
  margin: 0;
}
.reveal .tile > *:last-child { margin-bottom: 0; }

/* Denser grids: the box loses width, so the icon and the type come down with
   it rather than the text wrapping to five lines and the second row running
   into the footer. */
.reveal .tiles.t6 .tile { padding: 34px 32px 36px; }
.reveal .tiles.t6 .ic {
  width: 72px; height: 72px; border-radius: 15px; font-size: 33px; margin-bottom: 24px;
}
.reveal .tiles.t6 .tile h3 { font-size: 36px; margin-bottom: 13px; }
.reveal .tiles.t6 .tile p  { font-size: 25.6px; }

.reveal .tiles.t8 .tile { padding: 28px 26px 30px; }
.reveal .tiles.t8 .ic {
  width: 60px; height: 60px; border-radius: 13px; font-size: 27px; margin-bottom: 20px;
}
.reveal .tiles.t8 .tile h3 { font-size: 30px; margin-bottom: 11px; }
.reveal .tiles.t8 .tile p  { font-size: 22.4px; }

/* The 2x2 runs the other way: half as many boxes as .t4 across the same width,
   so the type goes up rather than down. Without this the default sizes read as
   a caption stranded in the corner of a very large box. */
.reveal .tiles.t2x2 .tile { padding: 40px 44px 44px; }
.reveal .tiles.t2x2 .ic {
  width: 88px; height: 88px; border-radius: 18px; font-size: 42px; margin-bottom: 26px;
}
.reveal .tiles.t2x2 .tile h3 { font-size: 46px; margin-bottom: 16px; }

/* An optional heading per column. They are direct children of the grid, one
   per column, ahead of the tiles — grid auto-flow then fills the first row
   with them and the tiles start on the second:

     <div class="tiles t6">
       <p class="col-head">Today</p>
       <p class="col-head">With Yaook</p>
       <p class="col-head">What it costs</p>
       ...six .tile blocks
     </div>

   So the count has to match the column count: three for .t6, four for .t4 and
   .t8. Fewer and the tiles shuffle up into the gap, which is the one way to
   get this wrong and is visible immediately.

   `align-self: end` sits the label on the tiles below it rather than floating
   in the middle of a row stretched to the tallest heading. */
.reveal .tiles .col-head {
  align-self: end;
  margin: 0 0 6px 0;
  font-size: 22.4px;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pm-green);
}
/* The heading row should sit close to what it labels, closer than the tiles
   sit to each other. */
.reveal .tiles:has(.col-head) { row-gap: 16px; }

/* Filling down instead of across. By default the grid is row-major — the
   tiles run left to right and wrap onto the second row — which is right when
   the set is just a set. When the columns *mean* something, and especially
   when they carry a .col-head, the two tiles under a heading should be the
   two that belong to it. `.flow-down` turns the grid column-major:

     <div class="tiles t6 flow-down">
       <p class="col-head">Runs it</p>
       <div class="tile">…</div>          first two go under "Runs it"
       <div class="tile">…</div>
       <p class="col-head">Keeps it running</p>
       <div class="tile">…</div>
       <div class="tile">…</div>
       …
     </div>

   Note the source order changes with the class, and this is the one thing to
   get right: row-major wants every .col-head first, then all the tiles;
   column-major wants each column's heading followed by that column's tiles.
   Writing one order with the other class puts a heading in the middle of the
   grid, which is at least obvious.

   Fragments follow source order, so a `.flow-down` grid whose tiles carry
   `class="fragment"` also *reveals* down each column and then across, without
   a single data-fragment-index.

   Explicit rows are what make column flow work at all — grid needs to know
   when to start the next column. Two, because that is what .t6 and .t8 are;
   .t4 is a single row and the class does nothing there. */
.reveal .tiles.flow-down {
  grid-auto-flow: column;
  grid-template-rows: repeat(2, auto);
}
.reveal .tiles.flow-down:has(.col-head) {
  grid-template-rows: auto repeat(2, auto);
}

/* The secondary colours, on the icon only — the one place a tile is allowed
   colour, and the .potx's own rule for accent2-6: infographics, never a field. */
.reveal .tile.c-blue   { --tile-accent: var(--pm-light-blue); }
.reveal .tile.c-orange { --tile-accent: var(--pm-orange); }
.reveal .tile.c-sand   { --tile-accent: var(--pm-sand); }
.reveal .tile.c-red    { --tile-accent: var(--pm-red); }

/* -------------------------------------------------------------------------- */
/*  Fixed chrome: the footer the master puts on every slide                    */
/* -------------------------------------------------------------------------- */
/* .pm-footer is a sibling of .slides, so reveal's transform never reaches it —
   yet the master puts it on the canvas, at the canvas's own size. Every number
   below is therefore a canvas px scaled by hand: reveal publishes its fitting
   factor as --slide-scale on .reveal-viewport, and multiplying by it puts the
   line exactly where the .potx has it, at whatever size the room gets.

   Doing this by hand is what fixes the soft footer. The box used to be sized
   in raw screen px at 96 dpi (5.5 pt = 7.33px) and was left alone when the
   canvas doubled, so it drew at half the master's size — 7px of Overpass
   Light, below the size at which antialiasing can hold an edge, which reads as
   blur rather than as small type.

   The bottom offset has to clear the letterbox: reveal centres the canvas, so
   half of whatever height is left over sits under it before the master's own
   15.6 pt margin starts. --viewport-height is reveal's own measure of the
   space it was given.

   The width is the one number here that is not the .potx's. That box is 90.7 pt
   — sized for the word "ALASCA" and little else — and a real deck puts its own
   title in this line, which wrapped to two. Centred text does not care how wide
   its box is as long as it fits, so the box is simply given the middle half of
   the canvas and any realistic footer stays on one line. Long ones still wrap
   rather than run off the edge. */
.reveal .pm-footer {
  --pm-s: var(--slide-scale, 1);
  position: fixed;
  left: 50%;
  margin-left: calc(-480px * var(--pm-s));    /* half the box, pre-scaled     */
  bottom: calc(
    (var(--viewport-height, 100vh) - 1080px * var(--pm-s)) / 2
    + 31.2px * var(--pm-s)                    /* y 518.7 + the box's height   */
  );
  width: calc(960px * var(--pm-s));           /* the middle half of the canvas */
  font-size: calc(var(--pm-footer) * var(--pm-s));
  font-weight: 400;
  line-height: 1.4;
  text-align: center;
  color: var(--pm-white);
  z-index: 40;
  pointer-events: none;
}
/* Overview (Esc) tiles the slides; fixed chrome only gets in the way there. */
.reveal.overview .pm-footer { opacity: 0; }

/* Back to the landing page that lists every deck — the same link the house
   theme carries, in the master's colours. Site navigation rather than part of
   the master, so it stays muted until the pointer finds it, and it sits in the
   bottom-left corner, the one strip no layout in the .potx writes into.

   Screen px on purpose, unlike the footer above: this is browser chrome, not a
   placeholder, so it should stay the same size a scrollbar or a cursor does
   rather than shrink with the slide. */
.reveal .deck-home,
.reveal .deck-lang,
.reveal .deck-frags {
  position: fixed; left: 22px; bottom: 30px;   /* clear of .progress at the sill */
  display: inline-flex; align-items: center; gap: 8px;
  font-family: "Overpass", system-ui, sans-serif;
  font-size: 11px; font-weight: 400;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--pm-white); opacity: 0.45;
  /* .reveal a underlines every link in the copy; this one is chrome. */
  text-decoration: none; border-bottom: 0;
  z-index: 41; pointer-events: auto;
  transition: opacity 0.18s ease, color 0.18s ease;
}
.reveal .deck-home svg {
  width: 14px; height: 14px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.reveal .deck-home:hover,
.reveal .deck-lang:hover,
.reveal .deck-frags:hover { opacity: 1; color: var(--pm-green); border-bottom: 0; }

/* The fragment switch. Bottom right rather than beside "All decks", because
   the language chips already grow rightwards from there; 150px clears the
   nav arrows reveal parks in the corner. A button, not a link — it changes
   the view, it does not go anywhere. */
.reveal .deck-frags {
  left: auto; right: 150px;
  background: none; border: 0; cursor: pointer;
  font-family: inherit;
}
/* Drawn with the same pen as the home icon, so the two bits of chrome match:
   an empty box while fragments are off, a ticked one while they step. */
.reveal .deck-frags svg {
  width: 14px; height: 14px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.reveal .deck-frags .tick { opacity: 0; transition: opacity 0.18s ease; }
.reveal.frags-on .deck-frags .tick { opacity: 1; }
/* Lit while it is on, so the state is readable without pressing it. */
.reveal.frags-on .deck-frags { opacity: 1; color: var(--pm-green); }
.reveal.overview .deck-frags { opacity: 0; pointer-events: none; }

.reveal.overview .deck-home,
.reveal.overview .deck-langs { opacity: 0; pointer-events: none; }

/* The same talk in another language: one chip per twin deck, written by
   ci/build.py only for the languages that actually exist. The row sits beside
   the home link — its offset only has to clear "All decks" — and grows to the
   right, so a third language costs no layout. */
.reveal .deck-langs {
  position: fixed; left: 150px; bottom: 30px;
  display: flex; align-items: center; gap: 20px;
  z-index: 41; pointer-events: auto;
  transition: opacity 0.18s ease;
}
/* The chip is muted by its colour, not by opacity: opacity would take the
   flag down with the text, and a washed-out flag stops being a flag. */
.reveal .deck-lang {
  position: static;
  opacity: 1;
  color: rgba(255, 255, 255, 0.5);
}
.reveal .deck-lang:hover { color: var(--pm-green); }
/* The flag is artwork, not an icon, so it keeps its own colours — hence a box
   of its own rather than the stroked <svg> the home link uses. The hairline
   is what keeps a white stripe from bleeding into the navy behind it. */
.reveal .deck-lang .flag {
  width: 21px; height: 14px; flex: none;
  opacity: 0.92;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.28);
}

/* Navigation chrome in the brand Green, clear of the footer */
.reveal .progress { color: var(--pm-green); height: 3px; }
.reveal .controls { color: var(--pm-green); right: 14px; bottom: 10px; }
.reveal .slide-number {
  background: transparent;
  color: rgba(255, 255, 255, 0.55);
  font-size: 10px;
  right: 20px; bottom: 108px;                /* above the arrow cluster */
}
.reveal .slide-number a { border: 0; color: inherit; }

/* Mermaid — the box the SVG lands in; the colours are the --mm-* tokens above.
   Inside a placeholder, so it fills the width it is given. */
.reveal .mermaid {
  display: block;
  margin: 0 auto;
  text-align: center;
  line-height: 1;
  white-space: normal;
}
.reveal .mermaid svg { max-width: 100%; height: auto; max-height: var(--mm-height, 680px); }
.mermaid-pending .reveal .mermaid { visibility: hidden; }

/* Crisp type, second half. The 192 dpi canvas above stops reveal from blowing
   the slide up; these two rules stop it from keeping stale rasters of it. Both
   layers reveal makes here are pure cost — the `perspective` only the 3D
   transitions use (this deck runs `fade`, which is opacity and nothing else)
   and the `will-change: opacity` that promotes every fragment at load time,
   before the stage is even scaled. Same rules as theme/alasca.css, where the
   reasoning is written out in full. */
.reveal.fade .slides,
.reveal.fade .slides > section { perspective: none; }
.reveal .fragment:not(.custom) { will-change: auto; }

.reveal .fragment.highlight-green.visible { color: var(--pm-green); }
.reveal :focus-visible { outline: 4px solid var(--pm-green); outline-offset: 6px; }

@media (prefers-reduced-motion: reduce) {
  .reveal .slides section { transition: none !important; }
}
@media print {
  .reveal .pm-photo:empty { outline: 0; }
}
