/*!
 * Flux 2.0 — Kaptio design system
 * Deck layer — presentation surfaces
 *
 * Slides are not product UI. They are read in seconds, from the back of a room,
 * one idea at a time. The rules that keep a dense operational interface legible
 * are the same rules that make a deck boring, so this layer relaxes the ones
 * that only make sense at desk distance — scale, ground, asymmetry, full bleed —
 * and holds every one that carries the brand: tokens, Lexend at two weights,
 * JetBrains Mono as the second voice, and guaranteed contrast.
 *
 * Requires flux.css. Load after it.
 *
 * Canonical: https://flux.kaptio.com/patterns/decks/
 * Deck contract: https://flux.kaptio.com/decks/llms.txt
 */

@layer flux.deck {
  /* ==================================================================
     The document
     ================================================================== */

  /**
   * A deck is a fixed-geometry document, so the root size is derived from the
   * viewport rather than left fluid. The 80 × 45rem canvas then fits exactly,
   * and every Flux rem token — spacing, type, radius — scales with it as one
   * piece. This is the only place Flux overrides the fluid root, and it is safe
   * because a deck is a whole document and never a region inside product UI.
   */
  html:has(.flux-deck) {
    font-size: min(calc(100vw / 80), calc(100vh / 45));
    font-size: min(calc(100dvw / 80), calc(100dvh / 45));
  }

  /* The canvas arithmetic above is exact, so it cannot survive the user-agent
     body margin: eight stray pixels push the last row out of the viewport and
     the document scrolls behind the deck. The deck owns the whole window. */
  body:has(.flux-deck) {
    margin: 0;
    overflow: hidden;
  }

  /**
   * Flux ships no global reset, deliberately: it has to drop into applications
   * that already have one. A deck has no host to accommodate, and a fixed canvas
   * cannot tolerate padding being added to it, so the reset is scoped here.
   */
  .flux-deck,
  .flux-deck *,
  .flux-deck *::before,
  .flux-deck *::after {
    box-sizing: border-box;
  }

  /**
   * Slides advance to the right, which is what every presentation tool has
   * trained an audience and a presenter remote to expect. The deck is one row of
   * viewport-wide columns, snapped, so a swipe, a trackpad, the arrow keys and
   * flux-deck.js all move the same single step.
   */
  .flux-deck {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 100vw;
    grid-auto-columns: 100dvw;
    justify-items: stretch;
    align-items: stretch;
    inline-size: 100vw;
    inline-size: 100dvw;
    block-size: 100vh;
    block-size: 100dvh;
    overflow-x: scroll;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    background-color: var(--flux-surface-page);
    /* The scroll container is the deck itself, so hiding its bar keeps 100vh
       equal to the viewport and the canvas arithmetic above exact. */
    scrollbar-width: none;
  }

  .flux-deck::-webkit-scrollbar {
    display: none;
  }

  /* ------------------------------------------------------------------
     Navigation — previous / next. Injected by flux-deck.js.
     ------------------------------------------------------------------ */

  .flux-deck-nav {
    position: fixed;
    z-index: 2;
    inset-block: 0;
    inline-size: var(--flux-space-16);
    display: grid;
    place-items: center;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--flux-text-inverse);
    cursor: pointer;
  }

  .flux-deck-nav--prev {
    inset-inline-start: 0;
  }

  .flux-deck-nav--next {
    inset-inline-end: 0;
  }

  .flux-deck-nav__glyph {
    display: grid;
    place-items: center;
    width: var(--flux-space-8);
    height: var(--flux-space-8);
    border-radius: var(--flux-radius-sm);
    background: var(--flux-surface-inverse);
    color: var(--flux-text-inverse);
    transition: opacity var(--flux-duration-fast) var(--flux-ease-productive);
  }

  .flux-deck-nav:hover:not(:disabled) .flux-deck-nav__glyph {
    opacity: 0.85;
  }

  .flux-deck-nav:disabled {
    cursor: not-allowed;
  }

  .flux-deck-nav:disabled .flux-deck-nav__glyph {
    opacity: 0.35;
  }

  .flux-deck-nav svg {
    width: var(--flux-space-4);
    height: var(--flux-space-4);
  }

  /* ==================================================================
     The stage
     ================================================================== */

  .flux-slide {
    position: relative;
    display: grid;
    inline-size: 100%;
    block-size: 100%;
    /* The 80 × 45rem composition is unchanged. Extra viewport is this slide's
       ground, so a dark slide is not framed by the page behind it. */
    padding-block: calc(
      var(--flux-slide-pad-y) + max(0rem, (100vh - var(--flux-slide-height)) / 2)
    );
    padding-block: calc(
      var(--flux-slide-pad-y) + max(0rem, (100dvh - var(--flux-slide-height)) / 2)
    );
    padding-inline: calc(
      var(--flux-slide-pad-x) + max(0rem, (100vw - var(--flux-slide-width)) / 2)
    );
    padding-inline: calc(
      var(--flux-slide-pad-x) + max(0rem, (100dvw - var(--flux-slide-width)) / 2)
    );
    overflow: hidden;
    background-color: var(--flux-surface-page);
    color: var(--flux-text-primary);
    scroll-snap-align: start;
    scroll-snap-stop: always;
    align-content: center;
    gap: var(--flux-slide-gap);
  }

  /* Full-bleed content: the padding moves onto the children that still need it. */
  .flux-slide--bleed {
    padding: 0;
  }

  /* Forest: the one deck ground that is not a theme. It sits on a deep slide and
     replaces only the grounds, so deep's text, icon and border roles still apply
     and the contrast audit measures them against it. */
  .flux-slide[data-flux-theme='deep'][data-ground='forest'] {
    --flux-surface-page: var(--flux-slide-ground-forest);
    --flux-layer-01: var(--flux-slide-ground-forest-layer);
    --flux-layer-02: var(--flux-slide-ground-forest-layer);
    --flux-layer-03: var(--flux-slide-ground-forest-layer);
  }

  /* Retained for existing decks. New closing slides use the image treatment. */
  .flux-slide--cta {
    background-color: var(--flux-surface-cta);
    color: var(--flux-text-on-cta);
    --flux-text-primary: var(--flux-text-on-cta);
    --flux-text-subtle: var(--flux-text-on-cta);
    --flux-border-subtle: var(--flux-text-on-cta);
  }

  /* ==================================================================
     Furniture — the parts every slide draws from
     ================================================================== */

  /* Structural label. Mono, uppercase, and only ever at the smallest size. */
  .flux-slide__kicker {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-xs);
    letter-spacing: var(--flux-tracking-widest);
    text-transform: uppercase;
    color: var(--flux-text-subtle);
  }

  .flux-slide__title {
    font-size: var(--flux-display-sm);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-display);
    letter-spacing: var(--flux-tracking-tight);
    text-wrap: balance;
    margin: 0;
  }

  .flux-slide__lede {
    max-inline-size: var(--flux-slide-measure);
    font-size: var(--flux-text-2xl);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    color: var(--flux-text-secondary);
    text-wrap: pretty;
    margin: 0;
  }

  .flux-slide__note {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-medium);
    font-size: var(--flux-text-sm);
    color: var(--flux-text-subtle);
    margin: 0;
  }

  /* Slide number and deck name. Absolute, so it never enters the layout. */
  .flux-slide__footer {
    position: absolute;
    inset-block-end: var(--flux-slide-pad-y);
    inset-inline: var(--flux-slide-pad-x);
    display: flex;
    justify-content: space-between;
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-regular);
    font-size: var(--flux-text-xs);
    letter-spacing: var(--flux-tracking-wide);
    color: var(--flux-text-subtle);
  }

  /**
   * An oversized numeral or word bleeding off the edge. This is the deck's one
   * piece of pure decoration, and it earns its place by being typographic —
   * the same font, at a size the interface scale cannot reach.
   */
  .flux-slide__mark {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: calc(-1 * var(--flux-space-8));
    transform: translateY(-50%);
    font-size: var(--flux-display-xl);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-display);
    letter-spacing: var(--flux-tracking-tight);
    color: var(--flux-slide-accent);
    opacity: var(--flux-slide-mark-opacity);
    pointer-events: none;
    user-select: none;
  }

  /* ==================================================================
     Display type
     ================================================================== */

  /* One sentence, at the size that makes it the only thing in the room. */
  .flux-display {
    max-inline-size: var(--flux-slide-measure-display);
    font-size: var(--flux-display-md);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-display);
    letter-spacing: var(--flux-tracking-tight);
    text-wrap: balance;
    margin: 0;
  }

  .flux-display--light {
    font-weight: var(--flux-weight-light);
  }

  .flux-display--sm {
    font-size: var(--flux-display-sm);
  }

  .flux-display--lg {
    font-size: var(--flux-display-lg);
  }

  .flux-metric__figure {
    display: block;
    font-size: var(--flux-display-lg);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-display);
    letter-spacing: var(--flux-tracking-tight);
    font-variant-numeric: tabular-nums;
  }

  .flux-metric__label {
    display: block;
    margin-block-start: var(--flux-space-4);
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-xs);
    letter-spacing: var(--flux-tracking-widest);
    text-transform: uppercase;
    color: var(--flux-text-subtle);
  }

  .flux-metric__note {
    display: block;
    max-inline-size: var(--flux-measure-prose);
    margin-block-start: var(--flux-space-3);
    font-size: var(--flux-text-lg);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    color: var(--flux-text-secondary);
  }

  /* ==================================================================
     Layouts
     ================================================================== */

  /* Cover — the deck opens. Title sits on the baseline, metadata above it. */
  .flux-slide--cover {
    align-content: end;
    gap: var(--flux-space-6);
  }

  .flux-slide--cover .flux-slide__title {
    font-size: var(--flux-display-md);
  }

  .flux-slide--cover:has(.flux-slide__media)::after,
  .flux-slide--closing::after {
    position: absolute;
    z-index: 1;
    inset: 0;
    background: var(--flux-surface-backdrop);
    content: '';
  }

  .flux-slide--cover:has(.flux-slide__media) > :not(.flux-slide__media):not(.flux-slide__video-toggle) {
    position: relative;
    z-index: 2;
  }

  /* Section — a divider that gives the audience a beat. */
  .flux-slide--section {
    align-content: center;
    gap: var(--flux-space-6);
  }

  .flux-slide--section .flux-slide__title {
    font-size: var(--flux-display-md);
  }

  /* Statement — one sentence and nothing else. The most underused slide. */
  .flux-slide--statement {
    align-content: center;
    justify-items: start;
  }

  /* Metric — one number, or up to three abreast. */
  .flux-slide--metric {
    align-content: center;
  }

  .flux-slide__metrics {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--flux-slide-gap);
    align-items: end;
  }

  /**
   * The figure scales to how much room it has. One number alone is the whole
   * slide and should be the size of one, and its rule should not stretch the
   * width of the canvas to underline two characters. Three abreast step down,
   * or they collide.
   */
  .flux-slide__metrics:has(> :only-child) {
    max-inline-size: var(--flux-slide-measure);
  }

  .flux-slide__metrics:has(> :only-child) .flux-metric__figure {
    font-size: var(--flux-display-xl);
  }

  .flux-slide__metrics:has(> :nth-child(3)) .flux-metric__figure {
    font-size: var(--flux-display-sm);
  }

  /* Split — argument on one side, evidence on the other. */
  .flux-slide--split {
    grid-template-columns: 1fr 1fr;
    align-content: center;
    align-items: center;
    gap: var(--flux-slide-gap);
  }

  .flux-slide--split-wide {
    grid-template-columns: 3fr 2fr;
  }

  /**
   * Split with photo — copy and metrics on the left, editorial photography on the
   * right. The photo bleeds to the trailing edge so the slide is not a text box
   * beside a thumbnail.
   */
  .flux-slide--split-photo {
    grid-template-columns: 3fr 2fr;
    align-content: stretch;
    align-items: stretch;
    gap: var(--flux-slide-gap);
    padding-inline-end: 0;
  }

  .flux-slide--split-photo .flux-slide__pane {
    align-content: center;
  }

  .flux-slide--split-photo .flux-slide__metrics {
    grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--flux-space-6) var(--flux-space-8);
    align-items: start;
  }

  .flux-slide--split-photo .flux-metric__figure {
    font-size: var(--flux-display-sm);
  }

  .flux-slide--split-photo .flux-metric__label {
    margin-block-start: var(--flux-space-2);
  }

  .flux-slide__photo {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    min-block-size: 0;
    object-fit: cover;
    border-radius: var(--flux-radius-sm) 0 0 var(--flux-radius-sm);
  }

  .flux-slide__pane {
    display: grid;
    gap: var(--flux-space-6);
    align-content: center;
    min-inline-size: 0;
  }

  /* A figure pane fills its half rather than floating in it. */
  .flux-slide__figure {
    display: grid;
    place-items: center;
    block-size: 100%;
    margin: 0;
    padding: var(--flux-space-10);
    background-color: var(--flux-layer-01);
    border: var(--flux-hairline) solid var(--flux-border-subtle);
    border-radius: var(--flux-radius-sm);
    overflow: hidden;
  }

  .flux-slide__figure > img,
  .flux-slide__figure > svg {
    max-inline-size: 100%;
    max-block-size: 100%;
  }

  /**
   * Diagram vocabulary. A hand-drawn SVG is the one place a deck is tempted to
   * name a colour, because the shape and the styling arrive in the same file.
   * These carry the roles instead, so a diagram re-themes with its slide.
   *
   * Geometry — coordinates, stroke-width, font-size, dash patterns — stays in
   * the markup as SVG attributes. Those are user units in a viewBox rather than
   * CSS lengths, and a rem token in a viewBox resolves to the wrong thing.
   */
  .flux-figure__frame {
    fill: none;
    stroke: currentColor;
  }

  /* The one part of a diagram the slide is actually about. */
  .flux-figure__panel {
    fill: var(--flux-layer-02);
    stroke: currentColor;
  }

  .flux-figure__link {
    fill: none;
    stroke: var(--flux-border-default);
  }

  .flux-figure__label {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    letter-spacing: var(--flux-tracking-widest);
    fill: currentColor;
  }

  .flux-figure__note {
    font-family: var(--flux-font-sans);
    font-weight: var(--flux-weight-light);
    fill: var(--flux-text-secondary);
  }

  .flux-figure__value {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-regular);
    fill: var(--flux-text-subtle);
  }

  /* List — the honest bullet slide, ranked typographically. */
  .flux-slide--list {
    align-content: center;
  }

  .flux-slide__list {
    display: grid;
    gap: var(--flux-space-8);
    counter-reset: flux-slide-item;
    list-style: none;
    padding: 0;
    margin: 0;
  }

  .flux-slide__list > li {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--flux-space-6);
    align-items: baseline;
    font-size: var(--flux-text-4xl);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    counter-increment: flux-slide-item;
  }

  .flux-slide__list > li::before {
    content: counter(flux-slide-item, decimal-leading-zero);
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-xl);
    color: var(--flux-slide-accent);
    font-variant-numeric: tabular-nums;
  }

  /* Compare — two positions, side by side, separated by a seam. */
  .flux-slide--compare {
    grid-template-columns: 1fr 1fr;
    align-content: center;
    gap: 0;
  }

  .flux-slide--compare > * {
    display: grid;
    gap: var(--flux-space-5);
    align-content: start;
    padding-inline: var(--flux-space-10);
  }

  .flux-slide--compare > :first-child {
    padding-inline-start: 0;
  }

  .flux-slide--compare > :last-child {
    padding-inline-end: 0;
    border-inline-start: var(--flux-hairline) solid var(--flux-border-default);
  }

  /*
   * A compare slide has no title, so the two positions are the content rather
   * than support for it. At the lede's ordinary size they read as a caption on
   * an empty canvas — the column is half the stage, so the same size that works
   * beneath a heading is half as loud here.
   */
  .flux-slide--compare .flux-slide__lede {
    max-inline-size: none;
    font-size: var(--flux-text-4xl);
    color: var(--flux-text-primary);
  }

  /* Quote — somebody else's words, at their own scale. */
  .flux-slide--quote {
    align-content: center;
    gap: var(--flux-space-10);
  }

  .flux-slide__quote {
    max-inline-size: var(--flux-slide-measure-display);
    font-size: var(--flux-display-sm);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-tight);
    letter-spacing: var(--flux-tracking-tight);
    text-wrap: pretty;
    margin: 0;
  }

  .flux-slide__attribution {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-medium);
    font-size: var(--flux-text-sm);
    color: var(--flux-text-subtle);
  }

  /* Image — full bleed, with the words on a plate rather than floating. */
  .flux-slide--image {
    padding: 0;
    align-content: end;
    justify-items: start;
  }

  .flux-slide__media {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
  }

  .flux-slide__plate {
    position: relative;
    display: grid;
    gap: var(--flux-space-4);
    max-inline-size: var(--flux-slide-measure);
    margin: var(--flux-slide-pad-x);
    padding: var(--flux-space-10);
    background-color: var(--flux-surface-page);
    border-radius: var(--flux-radius-sm);
  }

  /* Grid — a taxonomy, four to six cells. */
  .flux-slide--grid {
    align-content: center;
  }

  .flux-slide__tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--flux-space-6);
  }

  .flux-slide__tile {
    display: grid;
    gap: var(--flux-space-3);
    align-content: start;
    padding: var(--flux-space-8);
    background-color: var(--flux-layer-01);
    border: var(--flux-hairline) solid var(--flux-border-subtle);
    border-radius: var(--flux-radius-sm);
  }

  .flux-slide__tile > h3 {
    font-size: var(--flux-text-2xl);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-tight);
    margin: 0;
  }

  .flux-slide__tile > p {
    font-size: var(--flux-text-lg);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    color: var(--flux-text-secondary);
    margin: 0;
  }

  /* ------------------------------------------------------------------
     Agenda — what the deck covers. Near the front, once.
     ------------------------------------------------------------------ */

  .flux-slide--agenda {
    align-content: center;
  }

  .flux-slide--agenda-video {
    /* The media keeps two-fifths of the canvas; shrinking it further turns the
       video into decoration too small to carry the opening beat. */
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    align-content: stretch;
    gap: 0;
    padding: 0;
  }

  .flux-slide__agenda-copy {
    position: relative;
    z-index: 1;
    display: grid;
    align-content: center;
    gap: var(--flux-space-4);
    padding-block: calc(
      var(--flux-slide-pad-y) + max(0rem, (100vh - var(--flux-slide-height)) / 2)
    );
    padding-block: calc(
      var(--flux-slide-pad-y) + max(0rem, (100dvh - var(--flux-slide-height)) / 2)
    );
    padding-inline-start: calc(
      var(--flux-slide-pad-x) + max(0rem, (100vw - var(--flux-slide-width)) / 2)
    );
    padding-inline-start: calc(
      var(--flux-slide-pad-x) + max(0rem, (100dvw - var(--flux-slide-width)) / 2)
    );
    padding-inline-end: var(--flux-space-8);
  }

  .flux-slide__agenda-media {
    position: relative;
    display: grid;
    align-items: end;
    min-inline-size: 0;
    overflow: hidden;
    background: var(--flux-surface-page);
  }

  .flux-slide__agenda-video {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: contain;
    object-position: center bottom;
    mix-blend-mode: screen;
  }

  .flux-slide__video-toggle {
    position: absolute;
    z-index: 3;
    right: var(--flux-space-6);
    bottom: var(--flux-space-6);
    padding: var(--flux-space-2) var(--flux-space-3);
    border: var(--flux-hairline) solid var(--flux-border-strong);
    border-radius: var(--flux-radius-sm);
    background: var(--flux-surface-backdrop);
    color: var(--flux-text-primary);
    font-family: var(--flux-font-mono);
    font-size: var(--flux-text-xs);
    font-weight: var(--flux-weight-mono-bold);
    cursor: pointer;
    transition:
      background-color var(--flux-duration-fast) var(--flux-ease-productive),
      border-color var(--flux-duration-fast) var(--flux-ease-productive);
  }

  .flux-slide__video-toggle:hover {
    background: var(--flux-layer-hover-01);
    border-color: var(--flux-border-interactive);
  }

  /**
   * Two columns, filled down the first before the second. An agenda is read as
   * an ordered set, and `grid-auto-flow: column` with an explicit row count is
   * what keeps 1–4 on the left and 5–8 on the right instead of alternating.
   */
  .flux-slide__agenda {
    display: grid;
    grid-auto-flow: column;
    grid-template-rows: repeat(4, auto);
    gap: var(--flux-space-6) var(--flux-space-16);
    counter-reset: flux-agenda-item;
    list-style: none;
    padding: 0;
    margin: 0;
  }

  /* Four or fewer is one column: two columns of two is a grid, not a list. */
  .flux-slide__agenda:not(:has(> :nth-child(5))) {
    grid-auto-flow: row;
    grid-template-rows: none;
  }

  .flux-slide__agenda > li {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--flux-space-5);
    align-items: baseline;
    font-size: var(--flux-text-2xl);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    counter-increment: flux-agenda-item;
  }

  .flux-slide__agenda > li::before {
    content: counter(flux-agenda-item, decimal-leading-zero);
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-sm);
    color: var(--flux-slide-accent);
    font-variant-numeric: tabular-nums;
  }

  /**
   * The item the deck is about to reach. An agenda shown twice — once at the
   * front, once as a divider — needs to say where it has got to, and dimming
   * the rest is how that reads without adding a marker.
   */
  .flux-slide__agenda > li[aria-current] {
    font-weight: var(--flux-weight-bold);
  }

  .flux-slide__agenda:has(> li[aria-current]) > li:not([aria-current]) {
    color: var(--flux-text-subtle);
  }

  .flux-slide--agenda-video .flux-slide__agenda {
    grid-auto-flow: row;
    grid-template-rows: none;
    gap: var(--flux-space-4);
    margin-block-start: var(--flux-space-4);
  }

  .flux-slide--agenda-video .flux-slide__agenda > li {
    gap: var(--flux-space-4);
    font-size: var(--flux-text-lg);
  }

  .flux-slide--agenda-video .flux-slide__agenda > li::before {
    font-size: var(--flux-text-lg);
  }

  .flux-slide__agenda-item {
    display: grid;
    gap: var(--flux-space-1);
  }

  .flux-slide__agenda-item h3,
  .flux-slide__agenda-item p {
    margin: 0;
  }

  .flux-slide__agenda-item h3 {
    color: var(--flux-text-primary);
    font-size: var(--flux-text-lg);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-snug);
  }

  .flux-slide__agenda-item p {
    color: var(--flux-text-secondary);
    font-size: var(--flux-text-sm);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
  }

  .flux-slide__agenda:has(> li[aria-current]) > li:not([aria-current]) .flux-slide__agenda-item h3,
  .flux-slide__agenda:has(> li[aria-current]) > li:not([aria-current]) .flux-slide__agenda-item p {
    color: var(--flux-text-subtle);
  }

  /* ------------------------------------------------------------------
     Timeline — when. Milestones on one axis.
     ------------------------------------------------------------------ */

  .flux-slide--timeline {
    align-content: center;
  }

  /**
   * The axis is a hairline in a border role, not the accent: it is the ground
   * the data sits on rather than the data. Each milestone hangs a tick from it,
   * so the row reads as one continuous line instead of a set of columns.
   */
  .flux-slide__timeline {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--flux-space-8);
    padding: 0;
    margin: 0;
    list-style: none;
    border-block-start: var(--flux-hairline) solid var(--flux-border-default);
  }

  .flux-slide__timeline > li {
    display: grid;
    gap: var(--flux-space-3);
    align-content: start;
    padding-block-start: var(--flux-space-6);
    position: relative;
  }

  .flux-slide__timeline > li::before {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    inline-size: var(--flux-hairline);
    block-size: var(--flux-space-4);
    background-color: var(--flux-border-default);
  }

  .flux-slide__timeline-date {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-xs);
    letter-spacing: var(--flux-tracking-widest);
    text-transform: uppercase;
    color: var(--flux-slide-accent);
  }

  .flux-slide__timeline-label {
    font-size: var(--flux-text-2xl);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-tight);
  }

  .flux-slide__timeline-note {
    font-size: var(--flux-text-md);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    color: var(--flux-text-secondary);
  }

  /**
   * Where the deck is standing. Same move as the agenda: the accent marks the
   * current milestone and the rest step back, rather than the current one
   * changing colour — a second colour reads as a second category, not as focus.
   */
  .flux-slide__timeline:has(> li[aria-current]) > li:not([aria-current]) .flux-slide__timeline-date {
    color: var(--flux-text-subtle);
  }

  .flux-slide__timeline > li[aria-current] .flux-slide__timeline-label {
    font-weight: var(--flux-weight-bold);
  }

  /* ------------------------------------------------------------------
     Journey — who, in order. Stages and their hand-offs.
     ------------------------------------------------------------------ */

  .flux-slide--journey {
    align-content: center;
  }

  /**
   * A journey is a timeline with the dates taken out and the owners put in:
   * the question is who picks the work up next, not when. Stages are separated
   * by seams rather than strung on an axis, because the gap between two stages
   * is the hand-off — the part that goes wrong.
   */
  .flux-slide__journey {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 0;
    padding: 0;
    margin: 0;
    list-style: none;
    counter-reset: flux-journey-stage;
  }

  .flux-slide__journey > li {
    display: grid;
    gap: var(--flux-space-4);
    align-content: start;
    padding-inline: var(--flux-space-8);
    border-inline-start: var(--flux-hairline) solid var(--flux-border-default);
    counter-increment: flux-journey-stage;
  }

  .flux-slide__journey > li:first-child {
    padding-inline-start: 0;
    border-inline-start: none;
  }

  .flux-slide__journey > li:last-child {
    padding-inline-end: 0;
  }

  .flux-slide__journey > li::before {
    content: counter(flux-journey-stage, decimal-leading-zero);
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-sm);
    color: var(--flux-slide-accent);
    font-variant-numeric: tabular-nums;
  }

  .flux-slide__journey-stage {
    font-size: var(--flux-text-3xl);
    font-weight: var(--flux-weight-bold);
    line-height: var(--flux-leading-tight);
  }

  .flux-slide__journey-note {
    font-size: var(--flux-text-lg);
    font-weight: var(--flux-weight-light);
    line-height: var(--flux-leading-snug);
    color: var(--flux-text-secondary);
  }

  /* Who owns the stage. Mono, because it is a label rather than language. */
  .flux-slide__journey-owner {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-medium);
    font-size: var(--flux-text-xs);
    letter-spacing: var(--flux-tracking-wide);
    color: var(--flux-text-subtle);
  }

  /* ------------------------------------------------------------------
     Chart — one series, compared.
     ------------------------------------------------------------------ */

  .flux-slide--chart {
    align-content: center;
  }

  /**
   * Bars are built from the grid rather than drawn, so they theme, scale with
   * the canvas and need no library. The value is the one thing the stylesheet
   * cannot know: each bar carries it as --flux-bar, a percentage of the plot.
   * That is data arriving as data, not a hand-placed dimension.
   */
  .flux-slide__plot {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--flux-space-6);
    block-size: var(--flux-slide-plot-height);
    /* Headroom for the value above a full-height bar. The columns align to the
       bottom, so a tall bar's label overflows upward into exactly this space. */
    padding: var(--flux-space-8) 0 0;
    margin: 0;
    list-style: none;
    border-block-end: var(--flux-hairline) solid var(--flux-border-default);
  }

  /**
   * The value rides on top of its bar rather than sitting in a row of its own:
   * a label pinned to the top of the plot is a caption, and the eye stops
   * pairing it with a short bar. Flex, because a percentage bar needs a definite
   * containing block and a flex line gives it one — an auto grid track cannot.
   */
  .flux-slide__plot > li {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: var(--flux-space-3);
    block-size: 100%;
  }

  .flux-slide__bar {
    flex: none;
    block-size: var(--flux-bar, 0%);
    background-color: var(--flux-slide-accent);
    border-start-start-radius: var(--flux-radius-sm);
    border-start-end-radius: var(--flux-radius-sm);
  }

  /* A bar that is context rather than the point: last year, the other vendor. */
  .flux-slide__bar--muted {
    background-color: var(--flux-layer-02);
  }

  .flux-slide__bar-value {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-bold);
    font-size: var(--flux-text-lg);
    font-variant-numeric: tabular-nums;
    text-align: center;
  }

  /* Axis labels sit outside the plot so the rule stays the baseline of the data. */
  .flux-slide__axis {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--flux-space-6);
    padding: 0;
    margin: 0;
    margin-block-start: var(--flux-space-4);
    list-style: none;
  }

  .flux-slide__axis > li {
    font-family: var(--flux-font-mono);
    font-weight: var(--flux-weight-mono-medium);
    font-size: var(--flux-text-xs);
    letter-spacing: var(--flux-tracking-wide);
    text-transform: uppercase;
    color: var(--flux-text-subtle);
    text-align: center;
  }

  /* ------------------------------------------------------------------
     Donut — one proportion, next to what it means.
     ------------------------------------------------------------------ */

  .flux-slide--donut {
    grid-template-columns: auto 1fr;
    align-content: center;
    align-items: center;
    gap: var(--flux-space-16);
  }

  /**
   * The radius is 15.9155 so the circumference is exactly 100: a segment is then
   * written as the percentage it represents, with no arithmetic in between. The
   * ring is drawn from the twelve o'clock position because a proportion read
   * anywhere else is read as a clock face.
   */
  .flux-donut {
    inline-size: var(--flux-slide-donut-size);
    block-size: var(--flux-slide-donut-size);
    transform: rotate(-90deg);
  }

  .flux-donut circle {
    fill: none;
    stroke-width: var(--flux-slide-donut-stroke);
  }

  .flux-donut__track {
    stroke: var(--flux-layer-02);
  }

  .flux-donut__value {
    stroke: var(--flux-slide-accent);
  }

  /* The figure the ring is a picture of. Without it the ring is a shape. */
  .flux-slide__donut-body {
    display: grid;
    gap: var(--flux-space-5);
    align-content: center;
  }

  /* ------------------------------------------------------------------
     Infographic — one figure that leads, two or three that support it.
     ------------------------------------------------------------------ */

  .flux-slide--infographic {
    align-content: center;
  }

  /**
   * Not the metric layout with more cells. There the figures are peers; here one
   * is the claim and the rest are the evidence, so the hierarchy is in the sizes
   * and the supporting figures are stacked against the lead rather than beside it.
   */
  /* The support column hugs its figures rather than taking a share of the width:
     two short numbers in a half-width column leave a hole where the eye expects
     the third thing that is not there. */
  .flux-slide__cluster {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: var(--flux-space-16);
  }

  .flux-slide__cluster-support {
    display: grid;
    gap: var(--flux-space-8);
    border-inline-start: var(--flux-hairline) solid var(--flux-border-default);
    padding-inline-start: var(--flux-space-10);
  }

  .flux-slide__cluster-support .flux-metric__figure {
    font-size: var(--flux-display-sm);
  }

  .flux-slide__cluster-support .flux-metric__label {
    margin-block-start: var(--flux-space-2);
  }

  /* Closing — the ask over a full-bleed image and a deep-teal theme overlay. */
  .flux-slide--closing {
    padding: 0;
    align-content: center;
    gap: 0;
  }

  .flux-slide--closing .flux-slide__media {
    opacity: var(--flux-slide-closing-image-opacity);
  }

  .flux-slide__closing-content {
    position: relative;
    z-index: 2;
    display: grid;
    align-content: center;
    gap: var(--flux-space-10);
    inline-size: 100%;
    block-size: 100%;
    padding-block: calc(
      var(--flux-slide-pad-y) + max(0rem, (100vh - var(--flux-slide-height)) / 2)
    );
    padding-block: calc(
      var(--flux-slide-pad-y) + max(0rem, (100dvh - var(--flux-slide-height)) / 2)
    );
    padding-inline: calc(
      var(--flux-slide-pad-x) + max(0rem, (100vw - var(--flux-slide-width)) / 2)
    );
    padding-inline: calc(
      var(--flux-slide-pad-x) + max(0rem, (100dvw - var(--flux-slide-width)) / 2)
    );
  }

  .flux-slide--closing .flux-slide__title {
    max-inline-size: var(--flux-slide-measure-display);
    font-size: var(--flux-display-md);
  }

  /* The ask is the one line anyone acts on, so its qualifier is not footnote-sized. */
  .flux-slide--closing .flux-slide__note {
    font-size: var(--flux-text-lg);
  }

  /* ==================================================================
     Accents — type and data, never decoration
     ================================================================== */

  /**
   * One accent per slide, set here and read by everything that may carry it:
   * the oversized mark, the list numerals, the bars of a chart, the filled arc
   * of a donut. A product accent has no guaranteed contrast against any ground,
   * so it never carries a word — and it never draws an edge on a card or a rule
   * beside a label, which is decoration wearing a data colour.
   */

  .flux-slide[data-accent='core'] {
    --flux-slide-accent: var(--flux-product-core);
  }
  .flux-slide[data-accent='pex'] {
    --flux-slide-accent: var(--flux-product-pex);
  }
  .flux-slide[data-accent='edge'] {
    --flux-slide-accent: var(--flux-product-edge);
  }
  .flux-slide[data-accent='agents'] {
    --flux-slide-accent: var(--flux-product-agents);
  }
  .flux-slide[data-accent='quest'] {
    --flux-slide-accent: var(--flux-product-quest);
  }
  .flux-slide[data-accent='voyage'] {
    --flux-slide-accent: var(--flux-product-voyage);
  }
  .flux-slide[data-accent='circle'] {
    --flux-slide-accent: var(--flux-product-circle);
  }

  /* ==================================================================
     Texture
     ================================================================== */

  /**
   * A hairline dot field, for slides that would otherwise be a flat plane. The
   * stops are hard, so nothing about it reads as a gradient — but a radial one
   * is the only way to draw a dot in pure CSS, and pure CSS is what lets it
   * take its colour from the theme. An image asset would have to name a colour.
   */
  .flux-slide--field {
    /* flux-ignore-next-line gradient */
    background-image: radial-gradient(var(--flux-border-subtle) var(--flux-hairline), transparent 0);
    background-size: var(--flux-space-6) var(--flux-space-6);
    background-position: center;
  }

  /* ==================================================================
     Motion
     ================================================================== */

  /**
   * Slide content settles as it arrives. Scroll-driven rather than timed, so it
   * tracks the presenter's pace instead of running on its own clock, and it is
   * opacity and transform only. The base layer already neutralises this under
   * prefers-reduced-motion.
   */
  @supports (animation-timeline: view()) {
    .flux-slide > *:not(.flux-slide__media):not(.flux-slide__photo):not(.flux-slide__mark) {
      animation: flux-slide-rise linear both;
      /* Named axis: slides arrive from the side now, and the default block axis
         would never advance, leaving every slide stuck at the from-state. */
      animation-timeline: view(inline);
      animation-range: entry 15% entry 65%;
    }
  }

  @keyframes flux-slide-rise {
    from {
      opacity: 0;
      transform: translateY(var(--flux-space-6));
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /**
   * Staged reveal — the parts of a diagram arriving in the order you explain it.
   *
   * Not scroll-driven, unlike everything above. A build sequence has to start
   * when the presenter reaches the slide, and a view() timeline would run it
   * during the swipe and finish before anyone was looking at it. flux-deck.js
   * marks the current slide instead.
   *
   * Gated on that attribute, so a deck served without the script shows every
   * stage rather than an empty figure — the sequence is an enhancement, and the
   * diagram is the content.
   */
  .flux-slide[data-flux-current] .flux-stage > * {
    animation: flux-stage-in var(--flux-duration-deliberate) var(--flux-ease-entrance) both;
    animation-delay: calc(var(--flux-stage-step) * var(--flux-stage-index, 0));
  }

  /**
   * Slower than anything in product UI, and deliberately. A build is paced to a
   * person talking over it, not to a click being acknowledged — at interface
   * speed the whole sequence is over before the first sentence is, which reads
   * as a flicker rather than an explanation.
   *
   * Six stages is the ceiling. Past that the diagram is waiting on the animation.
   */
  .flux-stage {
    --flux-stage-step: var(--flux-duration-normal);
  }

  /* The position, not the delay. A custom property survives the `animation`
     shorthand above, which resets animation-delay and outranks these selectors. */
  .flux-stage > *:nth-child(2) {
    --flux-stage-index: 1;
  }
  .flux-stage > *:nth-child(3) {
    --flux-stage-index: 2;
  }
  .flux-stage > *:nth-child(4) {
    --flux-stage-index: 3;
  }
  .flux-stage > *:nth-child(5) {
    --flux-stage-index: 4;
  }
  .flux-stage > *:nth-child(6) {
    --flux-stage-index: 5;
  }

  @keyframes flux-stage-in {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  /* ==================================================================
     Print and PDF export
     ================================================================== */

  @media print {
    @page {
      size: 1280px 720px;
      margin: 0;
    }

    html:has(.flux-deck) {
      /* Print has no viewport to derive from, so the canvas returns to the size
         it was designed at: 1280 × 720 at a 16px root.
         flux-ignore-next-line raw-dimension */
      font-size: 16px;
    }

    .flux-deck {
      display: block;
      block-size: auto;
      overflow: visible;
    }

    .flux-slide {
      inline-size: var(--flux-slide-width);
      block-size: var(--flux-slide-height);
      padding: var(--flux-slide-pad-y) var(--flux-slide-pad-x);
      break-after: page;
      break-inside: avoid;
    }

    .flux-slide--bleed,
    .flux-slide--image,
    .flux-slide--closing,
    .flux-slide--agenda-video {
      padding: 0;
    }

    .flux-slide__closing-content,
    .flux-slide__agenda-copy {
      padding: var(--flux-slide-pad-y) var(--flux-slide-pad-x);
    }

    .flux-deck-nav {
      display: none;
    }
  }
}
