/*
 * Copyright (c) 2026 Apurva Nakade. All rights reserved.
 * Released under Apache 2.0 license as described in the file LICENSE.
 * Authors: Apurva Nakade
 */

/* ── Flow diagram ────────────────────────────────────────────────── */
/* A flowchart written as plain markup: a column of boxes joined by down
 * arrows, with optional boxes feeding a step from the right
 * (.vm-flow-in), read out of it to the left (.vm-flow-out), and a loop up
 * the left edge from one step back to an earlier one. HTML rather than an
 * SVG drawing so the boxes can hold MathJax equations and wrap prose.
 *
 *   .vm-flow                       the diagram
 *     .vm-flow-step                one row; a down arrow joins it to the next
 *       .vm-flow-box.vm-flow-in    optional input, to the right
 *       .vm-flow-box               the step itself, in the center column
 *       .vm-flow-box.vm-flow-out   optional output, to the left
 *
 * .vm-flow-loop-to and .vm-flow-loop-from on two steps draw the loop from
 * the second back into the first. Its label is real markup, a
 * .vm-flow-loop-label div in the -from step ("back to Predict"), so a
 * screen reader hears where the loop goes; the lines and arrows are
 * decoration, and every arrow glyph is hidden from assistive technology
 * with content's alt-text form (`"\2193" / ""`), each after a plain
 * declaration for a browser without that syntax.
 *
 * The markup is in reading order -- an input before the box it feeds, an
 * output after -- because that is the order the boxes stack in on a narrow
 * screen, where the side columns don't fit. On a wide one, grid columns
 * place each box, so the source order doesn't have to match the picture.
 *
 * .vm-flow-phase on a run of consecutive steps groups them into a phase
 * ("Predict", "Update"), named by a .vm-flow-phase-label div at the start
 * of the run's first step. A wrapper div around the run would have been the
 * obvious markup, but the arrows and the loop are drawn with sibling
 * combinators between steps, which a wrapper breaks; a class on each step
 * leaves them all siblings. The label is what starts a phase, so two
 * phases can sit back to back.
 *
 * Every arrow and line is drawn by the stylesheet, from pseudo-elements and
 * background gradients, so a page writes boxes and nothing else. */

.vm-flow {
  margin: 1rem 0 1.25rem;
  color: var(--vm-text);
}

.vm-flow-box {
  position: relative;
  min-width: 0;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--vm-border);
  border-radius: var(--vm-radius);
  background: var(--vm-surface);
  font-size: 0.9rem;
  line-height: 1.4;
}

/* Pandoc wraps a fenced div's lines in <p>s; tighten them into a box. */
.vm-flow-box > p { margin: 0.2rem 0 0; }
.vm-flow-box > p:first-child { margin-top: 0; }

.vm-flow-label { font-weight: 600; }

.vm-flow-loop-label {
  color: var(--vm-text-soft);
  font-size: 0.8rem;
}
/* Inline, so the narrow layout's ↺ shares the label's line. */
.vm-flow-loop-label > p { display: inline; margin: 0; }

/* An equation that must not wrap. MathJax output is inline, so the browser
 * breaks it at any space inside; as an inline-block it moves as one piece. */
.vm-flow-nowrap { white-space: nowrap; }
.vm-flow-nowrap > * { display: inline-block; }

/* A phase's name: small caps, quieter than a box title, since it names
 * the group rather than a step. */
.vm-flow-phase-label {
  position: relative;
  color: var(--vm-text-soft);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1.2;
  text-transform: uppercase;
}
.vm-flow-phase-label > p { display: inline; margin: 0; }

/* ── Wide: the grid ── */
@media (min-width: 761px) {
  /* Columns: loop | output | arrow | main | arrow | input. The loop column
   * is a fixed width so the loop's vertical line sits at a known x (2rem)
   * that every piece drawing it can share. Each step is a subgrid, so its
   * boxes line up with every other step's. */
  .vm-flow {
    display: grid;
    grid-template-columns:
      [loop-start] 2.75rem [loop-end out-start] minmax(0, 1fr) [out-end]
      2rem [main-start] minmax(0, 1.6fr) [main-end]
      2rem [in-start] minmax(0, 1fr) [in-end];
  }

  /* Nothing beside the main column: one centered column of steps. */
  .vm-flow:not(:has(.vm-flow-in, .vm-flow-out, .vm-flow-loop-to)) {
    grid-template-columns: [main-start] minmax(0, 30rem) [main-end];
    justify-content: center;
  }

  .vm-flow-step {
    position: relative;
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: center;
  }

  /* The down arrow between steps, in the space above every step but the
   * first. An absolutely positioned grid child whose row is "auto / 1"
   * spans from the step's top padding edge to its first row line -- the
   * padding -- and the main column. */
  /* --vm-flow-gap is the space above a step, where its down arrow sits;
   * a phase's edges widen it (below) so the arrow clears the outline. */
  .vm-flow-step + .vm-flow-step { padding-top: var(--vm-flow-gap, 1.6rem); }
  .vm-flow-step + .vm-flow-step::before {
    content: "\2193";
    content: "\2193" / "";
    position: absolute;
    inset: 0;
    grid-column: main;
    grid-row: auto / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--vm-text-soft);
  }

  .vm-flow-box {
    grid-column: main;
    grid-row: 1;
    align-self: stretch;
  }

  /* Side boxes center on their step, and so on its main box, which
   * stretches to the row; their arrows sit in the 2rem gap columns. */
  .vm-flow-in { grid-column: in; align-self: center; }
  .vm-flow-out { grid-column: out; align-self: center; }
  .vm-flow-in::before,
  .vm-flow-out::before {
    content: "\2190";
    content: "\2190" / "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--vm-text-soft);
  }
  .vm-flow-in::before { right: 100%; }
  .vm-flow-out::before { left: 100%; }

  /* The loop. Its vertical line runs at x = 2rem: from the middle of the
   * loop-from step up to the middle of the loop-to step, where it turns
   * right into the target box's arrowhead. Each step draws its own piece
   * with background gradients: the two end steps through an ::after placed
   * in the loop and output columns, the steps between through their own
   * background, which also covers the arrow gap above them. */
  .vm-flow-loop-to::after,
  .vm-flow-loop-from::after {
    content: "";
    grid-column: loop-start / main-start;
    grid-row: 1;
    align-self: stretch;
    pointer-events: none;
    background-image:
      linear-gradient(var(--vm-text-soft), var(--vm-text-soft)),
      linear-gradient(var(--vm-text-soft), var(--vm-text-soft));
    background-repeat: no-repeat;
  }
  /* Into the target: across from the line to the arrowhead, and down from
   * the middle. */
  .vm-flow-loop-to::after {
    background-position: 2rem 50%, 2rem 100%;
    background-size: calc(100% - 2.75rem) 1.5px, 1.5px 50%;
  }
  /* Out of the source: across from the box to the line, and up from the
   * middle. */
  .vm-flow-loop-from::after {
    background-position: 2rem 50%, 2rem 0;
    background-size: calc(100% - 2rem) 1.5px, 1.5px 50%;
  }
  /* The label, under the return line: the same columns as the line, with
   * top padding that drops its text just below the line's 50% height. */
  .vm-flow-loop-from > .vm-flow-loop-label {
    grid-column: loop-start / main-start;
    grid-row: 1;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.7em 0.75rem 0 2rem;
  }
  /* The steps strictly between, and the gap above the source. */
  .vm-flow-loop-to ~ .vm-flow-step:not(.vm-flow-loop-from ~ *) {
    background: no-repeat 2rem 0 / 1.5px 100%
      linear-gradient(var(--vm-text-soft), var(--vm-text-soft));
  }
  .vm-flow-loop-to ~ .vm-flow-step.vm-flow-loop-from {
    background-size: 1.5px var(--vm-flow-gap, 1.6rem);
  }
  /* The arrowhead, at the target box's left edge. */
  .vm-flow-loop-to > .vm-flow-box:not(.vm-flow-in, .vm-flow-out)::before {
    content: "\25B6";
    content: "\25B6" / "";
    position: absolute;
    right: 100%;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.85rem;
    line-height: 1;
    color: var(--vm-text-soft);
  }
}

/* ── Wide: phases ── */
/* A dashed outline around the main boxes of a phase's steps, drawn in
 * pieces by each main box's ::after: the sides through every step, meeting
 * halfway across the 1.6rem gap between two steps of the phase, plus the
 * top edge on the first step and the bottom edge on the last. The label
 * sits just above the top edge. (On the edge, like a fieldset legend,
 * needs a background to mask the dashes, and no token is guaranteed to
 * match the page's: a host theme sets its own.) Side boxes stay outside:
 * an input feeds the phase, an output is read from it. */
@media (min-width: 761px) {
  /* Room above a phase for its label, and for the arrow above that. */
  .vm-flow-step + .vm-flow-phase:has(> .vm-flow-phase-label) { --vm-flow-gap: 3.1rem; }
  .vm-flow-phase:first-child:has(> .vm-flow-phase-label) { padding-top: 2rem; }
  /* Room below a phase, so the arrow out of it clears the outline. */
  .vm-flow-phase + .vm-flow-step:not(.vm-flow-phase) { --vm-flow-gap: 2.2rem; }

  /* Keep those arrows off the outline: below the edge of the phase above,
   * above the edge of the phase they enter. */
  .vm-flow-phase + .vm-flow-step:not(.vm-flow-phase)::before,
  .vm-flow-phase + .vm-flow-phase:has(> .vm-flow-phase-label)::before { top: 0.7rem; }
  .vm-flow-step + .vm-flow-phase:has(> .vm-flow-phase-label)::before { bottom: 1rem; }

  .vm-flow-phase > .vm-flow-box:not(.vm-flow-in, .vm-flow-out)::after {
    content: "";
    position: absolute;
    top: -0.8rem;
    right: -0.55rem;
    bottom: -0.8rem;
    left: -0.55rem;
    border-inline: 1px dashed var(--vm-text-soft);
    pointer-events: none;
  }
  .vm-flow-phase:has(> .vm-flow-phase-label) > .vm-flow-box:not(.vm-flow-in, .vm-flow-out)::after {
    top: -0.9rem;
    border-top: 1px dashed var(--vm-text-soft);
    border-start-start-radius: var(--vm-radius);
    border-start-end-radius: var(--vm-radius);
  }
  /* The last step: the next one isn't in a phase, or starts a new one. */
  .vm-flow-phase:not(:has(+ .vm-flow-phase)) > .vm-flow-box:not(.vm-flow-in, .vm-flow-out)::after,
  .vm-flow-phase:has(+ .vm-flow-phase > .vm-flow-phase-label) > .vm-flow-box:not(.vm-flow-in, .vm-flow-out)::after {
    bottom: -0.6rem;
    border-bottom: 1px dashed var(--vm-text-soft);
    border-end-start-radius: var(--vm-radius);
    border-end-end-radius: var(--vm-radius);
  }

  /* The label: in the gap above the step, like its arrow, resting on the
   * outline's top edge 0.9rem above the box, aligned with its left side.
   * The arrow is centered, so the two share the gap side by side. */
  .vm-flow-phase > .vm-flow-phase-label {
    position: absolute;
    grid-column: main;
    grid-row: auto / 1;
    bottom: 1.1rem;
    left: -0.55rem;
  }
}

/* ── Narrow: one column ── */
/* Every box in markup order, a down arrow above each but the first, and the
 * loop as a line of text under its source step. */
@media (max-width: 760px) {
  .vm-flow-box { font-size: 0.82rem; }
  .vm-flow-step + .vm-flow-step > .vm-flow-box:first-child,
  .vm-flow-box + .vm-flow-box {
    margin-top: 1.4rem;
  }
  .vm-flow-step + .vm-flow-step > .vm-flow-box:first-child::before,
  .vm-flow-box + .vm-flow-box::before {
    content: "\2193";
    content: "\2193" / "";
    position: absolute;
    bottom: 100%;
    left: 1.2rem;
    padding-bottom: 0.2rem;
    color: var(--vm-text-soft);
  }
  .vm-flow-loop-label { margin-top: 0.4rem; }
  .vm-flow-loop-label::before {
    content: "\21BA\00A0";
    content: "\21BA\00A0" / "";
  }

  /* A phase is a rule down its steps' left edge, under its label. The
   * label takes the first box's place in the arrow chain: the arrow comes
   * down onto the label, and the box sits right under it. */
  /* flow-root, so the boxes' top margins (the arrow gaps) stay inside the
   * step instead of collapsing through it, and the rule runs unbroken. */
  .vm-flow-phase {
    display: flow-root;
    border-left: 2px solid var(--vm-border);
    padding-left: 0.6rem;
  }
  /* The gap above a phase is the step's own margin, outside the rule, so
   * the arrow into the phase sits above it and two phases in a row get two
   * rules. */
  .vm-flow-step + .vm-flow-phase:has(> .vm-flow-phase-label) {
    margin-top: 1.4rem;
  }
  .vm-flow-step + .vm-flow-step > .vm-flow-phase-label:first-child::before {
    content: "\2193";
    content: "\2193" / "";
    position: absolute;
    bottom: 100%;
    left: 1.2rem;
    padding-bottom: 0.2rem;
    font-size: 0.82rem;
    letter-spacing: 0;
  }
  .vm-flow-phase-label + .vm-flow-box { margin-top: 0.3rem; }
}
