/*
  McGrath Funerals client deck.

  Tokens are lifted from src/styles/tokens.css in this repository. See
  DESIGN-TOKENS.md for what was taken and where the deck deliberately differs.

  Layout model: every slide is authored on a fixed 1600 x 900 canvas and scaled
  to fit the viewport. Nothing reflows between 1920x1080, 1440x900 and a 13 inch
  laptop, so a slide that is legible in one place is legible everywhere and the
  print output matches the screen exactly.
*/

/* ---- Fonts, self hosted, same files the website uses --------------------- */
@font-face {
  font-family: 'Lora Variable';
  src: url('fonts/lora-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 400 700;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'Lora Variable';
  src: url('fonts/lora-latin-wght-italic.woff2') format('woff2-variations');
  font-weight: 400 700;
  font-style: italic;
  font-display: block;
}
@font-face {
  font-family: 'Figtree Variable';
  src: url('fonts/figtree-latin-wght-normal.woff2') format('woff2-variations');
  font-weight: 300 900;
  font-style: normal;
  font-display: block;
}

/* ---- Tokens -------------------------------------------------------------- */
/*
  Light only, and locked. A dark operating system setting or a stray theme
  toggle still gets the light deck: all three selectors carry the same values.
*/
:root,
:root[data-theme='dark'],
:root[data-theme='light'] {
  color-scheme: light;

  --sage: #9da986;
  --clay: #bf6b45;
  --clay-hover: #a95a38;
  --stone: #cdc1af;
  --cream: #f3e8c9;
  --charcoal: #38312a;
  --paper: #ece5da;
  --paper-2: #f5f0e8;

  --charcoal-80: rgba(56, 49, 42, 0.8);
  --charcoal-60: rgba(56, 49, 42, 0.6);
  --charcoal-30: rgba(56, 49, 42, 0.3);
  --charcoal-12: rgba(56, 49, 42, 0.12);
  --sage-wash: rgba(157, 169, 134, 0.16);
  --cream-60: rgba(243, 232, 201, 0.6);
  --cream-30: rgba(243, 232, 201, 0.3);

  --bg: var(--paper);
  --text: var(--charcoal);
  --muted: var(--charcoal-60);
  --accent: var(--clay);
  --rule: var(--charcoal-12);

  --font-display: 'Lora Variable', Lora, Georgia, 'Times New Roman', serif;
  --font-body: 'Figtree Variable', Figtree, system-ui, -apple-system, 'Segoe UI', sans-serif;

  /*
    Rebased against the 1600 x 900 canvas. Ratios follow the site scale.

    There is a floor under all of it. The rule is stated at 1920 x 1080, where
    the stage scales by 1.2, so the canvas figures are the 1920 ones divided by
    that: body 28px becomes 23.3, a chart label 22px becomes 18.3, a citation
    20px becomes 16.7. Nothing in this file may sit below its floor. When a
    slide will not fit, the copy comes down, never the type. capture-deck.mjs
    measures the smallest rendered text on every slide and fails the run if
    anything lands under 20px effective.
  */
  --step--1: 19px;
  --step-0: 24px;
  --step-1: 28px;
  --step-2: 37px;
  --step-3: 52px;
  --step-4: 72px;
  --step-5: 96px;

  --leading-body: 1.6;
  --leading-tight: 1.12;

  --space-2xs: 8px;
  --space-xs: 12px;
  --space-s: 16px;
  --space-m: 24px;
  --space-l: 40px;
  --space-xl: 64px;
  --space-2xl: 96px;

  /* Radii are zero on the site. Nothing here is rounded either. */
  --radius: 0;
  --shadow-soft: 0 1px 2px rgba(56, 49, 42, 0.04), 0 8px 24px rgba(56, 49, 42, 0.06);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-tile: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 200ms;
  --dur: 420ms;
  --dur-slow: 700ms;
  --dur-tile: 900ms;

  --pad: 96px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
* {
  margin: 0;
}

html,
body {
  height: 100%;
  overflow: hidden;
  background: #ded5c8;
}

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;
  text-wrap: balance;
  color: var(--charcoal);
}

strong {
  font-weight: 600;
}

/* ---- Stage --------------------------------------------------------------- */
/*
  The stage is centred by absolute positioning, not by grid or flex alignment.
  Its layout box is always 1600 x 900, which is larger than the window on any
  laptop, and an oversized item under `place-items: center` gets clamped to the
  start edge rather than centred. That silently pushed the right hand side of
  every slide off screen below 1600px wide.
*/
.viewport {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

.stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1600px;
  height: 900px;
  transform: translate(-50%, -50%) scale(var(--fit, 1));
  transform-origin: center center;
  background: var(--paper);
  overflow: hidden;
  box-shadow: 0 24px 80px rgba(56, 49, 42, 0.18);
}

.slide {
  position: absolute;
  inset: 0;
  padding: var(--pad);
  display: none;
  flex-direction: column;
  background: var(--paper);
}

.slide.is-current {
  display: flex;
}

/* Slide entry. Same curve and duration the website reveals sections with. */
@media (prefers-reduced-motion: no-preference) {
  .slide.is-current > * {
    animation: riseIn var(--dur-tile) var(--ease-tile) both;
  }
  .slide.is-current > *:nth-child(2) {
    animation-delay: 70ms;
  }
  .slide.is-current > *:nth-child(3) {
    animation-delay: 140ms;
  }
  .slide.is-current > *:nth-child(4) {
    animation-delay: 210ms;
  }
  @keyframes riseIn {
    from {
      opacity: 0;
      transform: translate3d(0, 10px, 0);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }
}

/* ---- Section backgrounds, the same five the site alternates -------------- */
.slide--paper {
  background: var(--paper);
}
.slide--paper2 {
  background: var(--paper-2);
}
.slide--cream {
  background: var(--cream);
}
.slide--sage {
  background: #e4e6da;
}
.slide--charcoal {
  background: var(--charcoal);
  color: var(--cream);
}
.slide--charcoal h1,
.slide--charcoal h2,
.slide--charcoal h3 {
  color: var(--cream);
}
.slide--charcoal .lede,
.slide--charcoal .body {
  color: var(--cream-60);
}
.slide--charcoal .rule {
  background: var(--cream-30);
}
.slide--charcoal .cite {
  color: var(--cream-60);
}

/* ---- Type ---------------------------------------------------------------- */
.kicker-free-heading,
h2.slide-title {
  font-size: var(--step-3);
  max-width: 26ch;
}

h2.slide-title--wide {
  max-width: 34ch;
}

.statement {
  font-family: var(--font-display);
  font-size: var(--step-4);
  line-height: 1.1;
  letter-spacing: -0.015em;
  max-width: 20ch;
}

.statement--big {
  /* Sized so "We don't simply remember a life." holds one line on the canvas.
     At --step-5 it wraps after "a", which reads as a mistake. */
  font-size: 82px;
}

.lede {
  font-size: var(--step-1);
  color: var(--charcoal-80);
  max-width: 52ch;
  line-height: 1.45;
}

.body {
  font-size: var(--step-0);
  color: var(--charcoal-80);
  max-width: 60ch;
}

.body + .body {
  margin-top: var(--space-s);
}

.small {
  font-size: var(--step--1);
  color: var(--muted);
}

.accent {
  color: var(--clay);
}
.slide--charcoal .accent {
  color: var(--stone);
}

.rule {
  height: 1px;
  background: var(--rule);
  border: 0;
  width: 100%;
}

.stack-s > * + * {
  margin-top: var(--space-s);
}
.stack-m > * + * {
  margin-top: var(--space-m);
}
.stack-l > * + * {
  margin-top: var(--space-l);
}

.grow {
  flex: 1;
  min-height: 0;
}

.row {
  display: flex;
  gap: var(--space-l);
  align-items: flex-start;
}
.row--center {
  align-items: center;
}
.col {
  flex: 1;
  min-width: 0;
}

/*
  The one live link in the deck. It opens in a new tab, so the deck is still
  behind it when the browser comes back. The stage click handler ignores
  anchors, so clicking it does not also advance the slide.
*/
.link-out {
  color: var(--cream);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--clay);
  text-underline-offset: 12px;
}
.link-out:hover,
.link-out:focus-visible {
  color: var(--clay);
}

/*
  Slide 3 is one button in the middle of the page. An anchor, not a button
  element, because it leaves the deck: it opens the live site in a new tab and
  the stage click handler ignores anchors, so the deck does not also advance.
*/
.site-button {
  display: inline-block;
  padding: 34px 72px;
  border: 2px solid var(--cream);
  color: var(--cream);
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1.1;
  text-decoration: none;
  transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}
.site-button:hover,
.site-button:focus-visible {
  background: var(--cream);
  border-color: var(--cream);
  color: var(--charcoal);
}

/* ---- Citations. Every number on screen carries one. ---------------------- */
.cite {
  font-size: 17px;
  line-height: 1.4;
  color: var(--muted);
  font-feature-settings: 'tnum';
  max-width: 74ch;
}

.cite--footer {
  margin-top: auto;
  padding-top: var(--space-m);
  border-top: 1px solid var(--rule);
}
.slide--charcoal .cite--footer {
  border-top-color: var(--cream-30);
}

.cite b {
  font-weight: 600;
  color: var(--charcoal-80);
}
.slide--charcoal .cite b {
  color: var(--cream-60);
}

/* A number that is modelled rather than measured is always marked. */
.projected-key {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 17px;
  color: var(--muted);
}
.projected-key i {
  width: 26px;
  height: 10px;
  display: block;
  background-image: repeating-linear-gradient(
    45deg,
    var(--clay) 0 2px,
    transparent 2px 5px
  );
  border: 1px solid var(--clay);
  opacity: 0.75;
}

/* ---- Screenshot presentation -------------------------------------------- */
/*
  Device frames are built here in CSS around the raw PNG, never baked into the
  image, so the screenshots stay crisp and can be replaced by rerunning capture.
*/
.shot {
  background: var(--paper-2);
  border: 1px solid var(--charcoal-12);
  overflow: hidden;
  position: relative;
}

.shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

/*
  Three pages as one stack, rather than a single screenshot sitting on its own.
  Uniform width and a constant offset, so it reads as a set instead of three
  things that happen to overlap. Only the front frame carries browser chrome;
  the two behind are plain, which is what gives the stack its depth. The offset
  is 95px, enough to show each hero band underneath and be read as a page.
*/
.stack-shots {
  position: relative;
  width: 640px;
  height: 500px;
  flex: none;
}
.stack-shots > * {
  position: absolute;
  width: 420px;
  box-shadow: var(--shadow-soft);
}
.stack-shots > :nth-child(1) {
  left: 0;
  top: 0;
}
.stack-shots > :nth-child(2) {
  left: 110px;
  top: 95px;
}
.stack-shots > :nth-child(3) {
  left: 220px;
  top: 190px;
}
/*
  The two behind are cropped rather than shown whole. Their lower half is under
  the next card anyway, and a crop gives them a clean bottom edge in the strip
  that does show, instead of a half line of the page's body copy.
*/
.stack-shots .shot {
  height: 240px;
}

/*
  The photographic variant of the stack, used on the direction slide. Three
  3:2 photographs instead of page captures: the backs stay cropped like the
  page stack so each shows a clean strip, and the front shows the full frame.
*/
.stack-shots--photo > :nth-child(3) {
  z-index: 1;
}
.stack-shots--photo .shot:nth-child(3) {
  height: 280px;
}
/* Photographs crop to their centre, not their top: the subject of a
   photograph sits mid frame, where a web page's subject is its top. */
.stack-shots--photo .shot img {
  object-position: center;
}
/* The middle card only shows its strip above the front card, so pull its
   crop to the lower half of the frame, where the figure stands. */
.stack-shots--photo .shot:nth-child(2) img {
  object-position: center bottom;
}

.browser {
  border: 1px solid var(--charcoal-12);
  background: #e2dacd;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}

.browser__bar {
  height: 40px;
  flex: none;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 0 12px;
  background: #ddd4c6;
  border-bottom: 1px solid var(--charcoal-12);
}
.browser__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--charcoal-30);
  flex: none;
}
.browser__url {
  margin-left: 10px;
  font-size: 17px;
  color: var(--charcoal-60);
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.browser__view {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: var(--paper);
}
.browser__view img {
  width: 100%;
  display: block;
}
.browser__view--scroll img {
  transform: translateY(var(--shot-offset, 0));
}

.phone {
  width: 250px;
  flex: none;
  border: 8px solid var(--charcoal);
  background: var(--charcoal);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.phone__view {
  height: 500px;
  overflow: hidden;
  background: var(--paper);
}
.phone__view img {
  width: 100%;
  display: block;
}

.caption {
  font-size: 19px;
  color: var(--muted);
  margin-top: var(--space-xs);
}

/* Anything not real is labelled, on the slide, where the room can see it.
   Sized so it stays above 12px on a 13 inch laptop, because these are the
   labels that must not be missed. */
.flag {
  display: inline-block;
  font-size: 16px;
  letter-spacing: 0.02em;
  color: var(--charcoal-80);
  background: rgba(191, 107, 69, 0.12);
  border: 1px solid rgba(191, 107, 69, 0.4);
  padding: 4px 9px;
}
.slide--charcoal .flag {
  color: var(--cream);
  background: rgba(243, 232, 201, 0.1);
  border-color: rgba(243, 232, 201, 0.35);
}

/* ---- Numbered points ----------------------------------------------------- */
.points {
  display: flex;
  gap: var(--space-l);
  list-style: none;
  padding: 0;
}
.point {
  flex: 1;
  min-width: 0;
}
.point__n {
  font-family: var(--font-display);
  font-size: var(--step-2);
  color: var(--clay);
  line-height: 1;
  margin-bottom: var(--space-s);
}
.slide--charcoal .point__n {
  color: var(--stone);
}
.point__h {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.2;
  margin-bottom: var(--space-2xs);
}
.point__b {
  font-size: var(--step-0);
  color: var(--charcoal-80);
  line-height: 1.5;
}
.slide--charcoal .point__b {
  color: var(--cream-60);
}

/* ---- Big figure ---------------------------------------------------------- */
.figure {
  font-family: var(--font-display);
  font-size: 88px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--clay);
  font-feature-settings: 'tnum';
}
.slide--charcoal .figure {
  color: var(--cream);
}
.figure__unit {
  font-size: 0.45em;
}
.figure__label {
  font-size: var(--step-0);
  color: var(--charcoal-80);
  max-width: 30ch;
  margin-top: var(--space-s);
  line-height: 1.45;
}
.slide--charcoal .figure__label {
  color: var(--cream-60);
}

/* ---- Charts -------------------------------------------------------------- */
/*
  Charts are authored at a fixed size and only ever shrink. They never stretch,
  because a stretched SVG scales its type down with it.
*/
.chart {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
}

.chart-box {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
}
.chart text {
  font-family: var(--font-body);
  fill: var(--charcoal-60);
  font-size: 19px;
}
.chart .chart__val {
  font-family: var(--font-display);
  fill: var(--charcoal);
  font-size: 26px;
  font-feature-settings: 'tnum';
}
.chart .chart__axis {
  stroke: var(--charcoal-12);
  stroke-width: 1;
}
.chart .chart__grid {
  stroke: var(--charcoal-12);
  stroke-width: 1;
  stroke-dasharray: 2 5;
}
.slide--charcoal .chart text {
  fill: var(--cream-60);
}
.slide--charcoal .chart .chart__val {
  fill: var(--cream);
}
.slide--charcoal .chart .chart__axis,
.slide--charcoal .chart .chart__grid {
  stroke: var(--cream-30);
}

/* Line draw on entry, using the site's slowest reveal curve. */
.draw {
  stroke-dasharray: var(--len, 1200);
  stroke-dashoffset: var(--len, 1200);
}
.is-current .draw {
  animation: draw 1500ms var(--ease-tile) forwards;
}
@keyframes draw {
  to {
    stroke-dashoffset: 0;
  }
}

.fade-in {
  opacity: 0;
}
.is-current .fade-in {
  animation: fadeIn var(--dur-slow) var(--ease) forwards;
  animation-delay: var(--delay, 600ms);
}
@keyframes fadeIn {
  to {
    opacity: 1;
  }
}

.grow-bar {
  transform: scaleY(0);
  transform-origin: bottom;
}
.is-current .grow-bar {
  animation: growBar var(--dur-tile) var(--ease-tile) forwards;
  animation-delay: var(--delay, 0ms);
}
@keyframes growBar {
  to {
    transform: scaleY(1);
  }
}

/* Zero click dot grid */
.dot {
  fill: var(--charcoal);
}
.dot--out {
  opacity: 1;
}
.is-current .dot--out {
  animation: extinguish 500ms var(--ease) forwards;
  animation-delay: var(--delay, 0ms);
}
@keyframes extinguish {
  to {
    opacity: 0.11;
    transform: scale(0.6);
  }
}
.dot--stay {
  fill: var(--clay);
}
.is-current .dot--stay {
  animation: survive 600ms var(--ease-tile) forwards;
  animation-delay: var(--delay, 900ms);
}
@keyframes survive {
  to {
    transform: scale(1.55);
  }
}

/*
  The old search path recedes as the new one builds. It does not leave. Both
  panels are read side by side while the slide is talked through, so this dims
  far enough to move the eye right and no further.
*/
.panel-old {
  transition: opacity 900ms var(--ease);
}
.is-current .panel-old {
  animation: dimOut 900ms var(--ease) forwards;
  animation-delay: 1400ms;
}
@keyframes dimOut {
  to {
    opacity: 0.72;
  }
}

@media (prefers-reduced-motion: reduce) {
  .slide.is-current > *,
  .is-current .draw,
  .is-current .fade-in,
  .is-current .grow-bar,
  .is-current .dot--out,
  .is-current .dot--stay,
  .is-current .panel-old {
    animation: none !important;
  }
  .draw {
    stroke-dashoffset: 0;
  }
  .fade-in {
    opacity: 1;
  }
  .grow-bar {
    transform: none;
  }
  .dot--out {
    opacity: 0.11;
  }
  .panel-old {
    opacity: 0.72;
  }
}

/* ---- Diagram primitives -------------------------------------------------- */
.node {
  fill: var(--paper-2);
  stroke: var(--charcoal-30);
  stroke-width: 1;
}
.node--accent {
  fill: rgba(191, 107, 69, 0.1);
  stroke: var(--clay);
}
.node--sage {
  fill: var(--sage-wash);
  stroke: var(--sage);
}
.node--dark {
  fill: var(--charcoal);
  stroke: var(--charcoal);
}
.node-title {
  font-family: var(--font-display);
  fill: var(--charcoal);
  font-size: 23px;
}
.node-title--on-dark {
  fill: var(--cream);
}
.node-line {
  fill: var(--charcoal-60);
  font-size: 19px;
}
.node-line--on-dark {
  fill: var(--cream-60);
}
.link {
  stroke: var(--charcoal-30);
  stroke-width: 1.5;
  fill: none;
}
.link--accent {
  stroke: var(--clay);
  stroke-width: 2;
}
.link-label {
  fill: var(--charcoal-60);
  font-size: 14px;
}

/* ---- Chrome: progress, index, notes, help ------------------------------- */
.progress {
  position: fixed;
  left: 0;
  bottom: 0;
  height: 3px;
  background: var(--clay);
  width: 0;
  transition: width var(--dur) var(--ease);
  z-index: 40;
}

.slide-no {
  position: absolute;
  right: var(--pad);
  bottom: 40px;
  font-size: 14px;
  color: var(--charcoal-30);
  font-feature-settings: 'tnum';
}
.slide--charcoal .slide-no {
  color: var(--cream-30);
}

.overlay {
  position: fixed;
  inset: 0;
  background: #332c26;
  color: var(--cream);
  z-index: 60;
  display: none;
  overflow: auto;
  padding: 48px;
}
.overlay.is-open {
  display: block;
}
.overlay h3 {
  color: var(--cream);
  font-size: 28px;
  margin-bottom: 24px;
}

.index-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 14px;
  max-width: 1500px;
  margin: 0 auto;
}
.index-item {
  background: rgba(243, 232, 201, 0.07);
  border: 1px solid rgba(243, 232, 201, 0.16);
  padding: 14px 16px;
  cursor: pointer;
  text-align: left;
  color: var(--cream);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.35;
  transition: background var(--dur-fast) var(--ease);
}
.index-item:hover,
.index-item:focus-visible {
  background: rgba(243, 232, 201, 0.16);
}
.index-item.is-current {
  border-color: var(--clay);
}
.index-item b {
  display: block;
  color: var(--stone);
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 5px;
  font-feature-settings: 'tnum';
}

.keys {
  max-width: 620px;
  margin: 0 auto;
  font-size: 17px;
}
.keys dl {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 12px 20px;
}
.keys dt {
  color: var(--stone);
  font-feature-settings: 'tnum';
}
kbd {
  font-family: var(--font-body);
  border: 1px solid rgba(243, 232, 201, 0.4);
  padding: 1px 7px;
  font-size: 14px;
}

/* Presenter notes sit under the stage, never over the content. */
.notes {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 42vh;
  overflow: auto;
  background: var(--charcoal);
  color: var(--cream);
  padding: 22px 32px 28px;
  z-index: 50;
  display: none;
  border-top: 3px solid var(--clay);
}
.notes.is-open {
  display: block;
}
.notes h4 {
  font-family: var(--font-display);
  font-size: 19px;
  color: var(--stone);
  margin-bottom: 10px;
  font-weight: 400;
}
.notes p {
  font-size: 17px;
  line-height: 1.55;
  max-width: 100ch;
  color: rgba(243, 232, 201, 0.86);
}
.notes p + p {
  margin-top: 10px;
}

.hint {
  position: fixed;
  right: 14px;
  bottom: 12px;
  font-size: 12px;
  color: var(--charcoal-30);
  z-index: 30;
  transition: opacity var(--dur) var(--ease);
}
.hint.is-hidden {
  opacity: 0;
}

.warn {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: var(--clay);
  color: #fff;
  font-size: 14px;
  padding: 8px 16px;
  z-index: 90;
  display: none;
}
.warn.is-open {
  display: block;
}

/* ---- Print: one slide per landscape page -------------------------------- */
@page {
  size: 1600px 900px;
  margin: 0;
}

@media print {
  html,
  body {
    overflow: visible;
    background: #fff;
    height: auto;
  }
  .viewport {
    position: static;
    display: block;
    overflow: visible;
  }
  .stage {
    position: static;
    width: 1600px;
    height: 900px;
    transform: none !important;
    box-shadow: none;
    overflow: visible;
    background: none;
  }
  .slide {
    display: flex !important;
    position: relative;
    inset: auto;
    width: 1600px;
    height: 900px;
    page-break-after: always;
    break-after: page;
    overflow: hidden;
  }
  .slide:last-child {
    page-break-after: auto;
    break-after: auto;
  }
  /* Nothing may be mid animation on paper. */
  .slide > *,
  .draw,
  .fade-in,
  .grow-bar,
  .dot--out,
  .dot--stay,
  .panel-old {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    stroke-dashoffset: 0 !important;
  }
  .dot--out {
    opacity: 0.11 !important;
  }
  .panel-old {
    opacity: 0.72 !important;
  }
  .progress,
  .notes,
  .overlay,
  .hint,
  .warn {
    display: none !important;
  }
  * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}

/* ==========================================================================
   The two working demonstrations, and the closing collage
   ========================================================================== */
/*
  Dense interface text sits at the chart label floor, 19px on the canvas, not at
  the body size. A register with 24px rows would hold four providers and stop
  being a register. Nothing here goes below 19.

  Everything clickable is a <button>, because the stage advances the slide on
  any click that is not an anchor or a button.
*/

.app {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  height: 100%;
  min-height: 0;
}

/* ---- Shared chips -------------------------------------------------------- */
.chip {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1;
  padding: 9px 14px;
  border: 1px solid var(--charcoal-12);
  background: transparent;
  color: var(--charcoal-60);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.chip:hover {
  border-color: var(--charcoal-30);
  color: var(--charcoal);
}
.chip.is-on {
  background: rgba(191, 107, 69, 0.14);
  border-color: var(--clay);
  color: var(--charcoal);
}
.chip--static {
  background: rgba(191, 107, 69, 0.12);
  border-color: rgba(191, 107, 69, 0.4);
  color: var(--charcoal);
  cursor: default;
}

/* ---- The provider registry ---------------------------------------------- */
.app__bar {
  display: flex;
  align-items: center;
  gap: var(--space-m);
}
.app__search {
  flex: 1;
  font-family: var(--font-body);
  font-size: 21px;
  color: var(--charcoal);
  background: var(--paper-2);
  border: 1px solid var(--charcoal-12);
  padding: 14px 18px;
}
.app__search::placeholder {
  color: var(--charcoal-30);
}
.app__search:focus {
  outline: 2px solid var(--clay);
  outline-offset: -2px;
}
.app__count {
  font-size: 19px;
  color: var(--muted);
  white-space: nowrap;
}
.app__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.app__body {
  display: flex;
  gap: var(--space-m);
  flex: 1;
  min-height: 0;
}
.app__list {
  width: 520px;
  flex: none;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.app__empty {
  font-size: 21px;
  color: var(--muted);
  padding: var(--space-m) 0;
  max-width: 34ch;
}

.prov {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  width: 100%;
  text-align: left;
  font-family: var(--font-body);
  padding: 7px 14px;
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.prov:hover {
  background: var(--paper-2);
}
.prov.is-selected {
  background: var(--sage-wash);
  border-color: var(--sage);
}
/*
  The monogram sits under the portrait. If the photograph is missing the image
  removes itself and the initials are what is left, which reads as a considered
  placeholder rather than a broken record.
*/
.face {
  position: relative;
  display: block;
  flex: none;
  background: var(--sage-wash);
  border: 1px solid rgba(157, 169, 134, 0.5);
  font-family: var(--font-display);
  color: var(--charcoal-60);
  text-align: center;
  overflow: hidden;
}
.face::before {
  content: attr(data-initials);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.face img {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(0.35);
}
.face--sm {
  width: 46px;
  height: 46px;
  font-size: 19px;
}
.face--lg {
  width: 116px;
  height: 116px;
  font-size: var(--step-2);
}
.prov__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.prov__name {
  font-size: 21px;
  color: var(--charcoal);
}
/* One line, clipped. A wrapped second line makes the rows uneven and pushes
   the last provider off the bottom of the panel. */
.prov__biz,
.prov__caps {
  font-size: 19px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prov__name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prov__radius {
  margin-left: auto;
  font-size: 19px;
  color: var(--muted);
  white-space: nowrap;
}

.app__detail {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  background: var(--paper-2);
  border: 1px solid var(--charcoal-12);
  padding: var(--space-m) var(--space-l);
}
.rec__head {
  display: flex;
  align-items: center;
  gap: var(--space-m);
}
.rec__name {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.1;
}
.rec__biz {
  font-size: 21px;
  color: var(--charcoal-80);
  margin-top: 4px;
}
.rec__radius {
  font-size: 19px;
  color: var(--muted);
  margin-top: 6px;
}
.rec__caps {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: var(--space-s) 0;
}
.rec__grid {
  display: flex;
  gap: var(--space-xl);
  margin-top: var(--space-xs);
}
.rec__label {
  font-size: 19px;
  color: var(--muted);
  margin-bottom: 6px;
}
.rec__val {
  font-size: 21px;
  color: var(--charcoal);
}
.rec__val--quiet {
  color: var(--charcoal-60);
}
.rec__val--flag {
  color: var(--clay);
}
.rec__season {
  font-size: 19px;
  color: var(--charcoal-60);
  margin-top: var(--space-s);
  max-width: 60ch;
}
.rec__note {
  font-family: var(--font-display);
  font-size: 21px;
  line-height: 1.4;
  color: var(--charcoal);
  margin-top: var(--space-s);
  max-width: 58ch;
}
.rec__from {
  font-size: 19px;
  color: var(--muted);
  margin-top: 8px;
}

/* ---- The service type workflow ------------------------------------------ */
.wf__head {
  display: flex;
  align-items: center;
  gap: var(--space-l);
  flex: none;
}
.wf__title {
  font-family: var(--font-display);
  font-size: var(--step-1);
}
.wf__next {
  font-size: 19px;
  color: var(--clay);
  margin-top: 4px;
}
.wf__meter {
  margin-left: auto;
  width: 300px;
  flex: none;
}
.wf__bar {
  height: 8px;
  background: var(--charcoal-12);
  margin-bottom: 8px;
}
.wf__bar i {
  display: block;
  height: 100%;
  background: var(--clay);
  transition: width var(--dur) var(--ease);
}
.wf__progress {
  font-size: 19px;
  color: var(--muted);
}
.wf__toggle {
  flex: none;
  font-family: var(--font-body);
  font-size: 19px;
  padding: 10px 16px;
  border: 1px solid var(--charcoal-30);
  background: transparent;
  color: var(--charcoal-60);
  cursor: pointer;
}
.wf__toggle.is-on {
  border-color: var(--clay);
  background: rgba(191, 107, 69, 0.14);
  color: var(--charcoal);
}
.wf__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 1fr;
  gap: var(--space-s);
  flex: 1;
  min-height: 0;
}
.wf__card {
  background: var(--paper-2);
  border: 1px solid var(--charcoal-12);
  padding: var(--space-xs) var(--space-s) var(--space-s);
}
.wf__phase {
  font-family: var(--font-display);
  font-size: 21px;
  color: var(--clay);
  margin-bottom: 4px;
  padding-left: 6px;
}
.step {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  text-align: left;
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.25;
  color: var(--charcoal);
  background: transparent;
  border: 0;
  padding: 5px 6px;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.step:hover {
  background: rgba(56, 49, 42, 0.05);
}
.step__box {
  width: 22px;
  height: 22px;
  flex: none;
  border: 1px solid var(--charcoal-30);
  font-size: 19px;
  line-height: 20px;
  text-align: center;
  color: transparent;
}
.step.is-done .step__box {
  background: var(--sage);
  border-color: var(--sage);
  color: var(--charcoal);
}
.step.is-done .step__t {
  color: var(--charcoal-30);
}
.step.is-next {
  background: rgba(191, 107, 69, 0.12);
}
.step__who {
  color: var(--muted);
}
.step.is-done .step__who {
  color: var(--charcoal-30);
}

/* ---- The closing collage ------------------------------------------------- */
/*
  Every face on the delivery side, washed back to brown so it reads as one
  surface rather than a wall of photographs. The type sits above it and has to
  stay the loudest thing on the slide.

  Seventy eight faces in six rows of thirteen, and the rows drift: the top row
  to the right, the next to the left, alternating down the slide. Each track
  holds its thirteen faces twice, so a half-track translate lands exactly on
  the start and the loop never shows a seam. The speeds differ a little from
  row to row so the crowd breathes instead of marching.
*/
.collage {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.collage__row {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
.collage__track {
  display: flex;
  height: 100%;
  width: max-content;
  animation: collage-left 110s linear infinite;
}
.collage__row:nth-child(odd) .collage__track {
  animation-name: collage-right;
}
.collage__row:nth-child(1) .collage__track { animation-duration: 118s; }
.collage__row:nth-child(2) .collage__track { animation-duration: 96s; }
.collage__row:nth-child(3) .collage__track { animation-duration: 128s; }
.collage__row:nth-child(4) .collage__track { animation-duration: 104s; }
.collage__row:nth-child(5) .collage__track { animation-duration: 122s; }
.collage__row:nth-child(6) .collage__track { animation-duration: 100s; }
.collage img {
  width: 123.08px; /* 1600 / 13, so a full set spans the canvas exactly */
  height: 100%;
  object-fit: cover;
  flex: none;
  filter: grayscale(1) contrast(1.06);
}
@keyframes collage-left {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@keyframes collage-right {
  from { transform: translateX(-50%); }
  to { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .collage__track {
    animation: none;
    transform: translateX(-25%);
  }
}
.collage__wash {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 18% 42%, rgba(56, 49, 42, 0.94) 0%, rgba(56, 49, 42, 0.86) 45%, rgba(56, 49, 42, 0.9) 100%),
    linear-gradient(rgba(191, 107, 69, 0.22), rgba(191, 107, 69, 0.22));
}
.collage-text {
  position: relative;
}
