/*
 * steps.css
 * Steps — the multi-stage flow indicator. Onboarding, checkout, a wizard,
 * an approval chain.
 *
 * ── Structure ────────────────────────────────────────────────────────
 *
 *   <ol class="steps" aria-label="Checkout progress">
 *     <li class="step complete">
 *       <span class="step-marker"></span>
 *       <span class="step-label">Cart<span class="visually-hidden"> — completed</span></span>
 *     </li>
 *     <li class="step" aria-current="step">
 *       <span class="step-marker"></span>
 *       <span class="step-label">Shipping</span>
 *       <span class="step-hint">Address & delivery</span>
 *     </li>
 *     <li class="step">
 *       <span class="step-marker"></span>
 *       <span class="step-label">Payment</span>
 *     </li>
 *   </ol>
 *
 * <ol> because the sequence *is* the meaning — a screen reader announcing
 * "list of 3 items" and a position is most of what a stepper communicates.
 * <li> per step, so each is a Row in the vocabulary's sense, not a Card.
 *
 * ── The current step comes from ARIA ─────────────────────────────────
 *
 * `aria-current="step"` is a real ARIA token and exactly this case, so it
 * drives the styling — the same rule tabs, breadcrumbs and pagination
 * follow. A `.current` class would let the highlighted step and the
 * announced step drift apart.
 *
 * ── Completion is a class, and that is a real gap ────────────────────
 *
 * There is no ARIA token for "done". `.complete` is therefore a styling
 * hook with nothing behind it, which means the checkmark is *invisible to
 * a screen reader*: a sighted user sees three states, a screen reader user
 * hears two.
 *
 * So a completed step owes assistive tech a word. Put it in the label:
 *
 *   <span class="visually-hidden"> — completed</span>
 *
 * This is the one place in the package where the visual state cannot be
 * derived from the markup, so it is the one place the markup has to say it
 * twice. Do not skip it.
 *
 * ── Numbering ────────────────────────────────────────────────────────
 *
 * An empty .step-marker numbers itself with a CSS counter, so the markup
 * does not carry indices that go stale when a step is inserted. Put
 * anything inside the marker — a checkmark, an icon — and that wins
 * instead. The marker is decorative either way; the label is what is read.
 */

.steps {
  --step-accent:      var(--bg-mix, var(--color-primary));
  --step-marker-size: 1.75rem;

  display:     flex;
  align-items: flex-start;
  gap:         var(--space-sm);

  list-style: none;
  margin:     0;
  padding:    0;

  counter-reset: fjs-step;
  font-family:   var(--font-primary);
}

.step {
  /* The connector is positioned against this. */
  position: relative;

  flex:  1;
  /* Equal tracks regardless of label length, so the markers stay evenly
     spaced and the connectors all come out the same width. */
  min-inline-size: 0;

  display:        flex;
  flex-direction: column;
  align-items:    center;
  gap:            var(--space-xs);
  text-align:     center;

  color: var(--ink-mute);
}

/*
 * ── Connector ────────────────────────────────────────────────────────
 *
 * One rule, drawn by each step except the first, reaching back to the
 * previous marker. Because every .step is an equal flex track, "half my
 * width plus half the previous one" is just 100% of one track ending at
 * my own center — no per-step geometry, and nothing to retune when the
 * marker size changes.
 *
 * Contrast this with the feed timeline, whose connector is pinned to
 * hardcoded offsets and has to be re-eyeballed when entry heights change.
 */
.step + .step::before {
  content:  "";
  position: absolute;
  z-index:  0;

  inset-inline-end: 50%;
  inline-size:      100%;
  inset-block-start: calc(var(--step-marker-size) / 2);

  block-size:  2px;
  translate:   0 -1px;
  background:  var(--rule);
}

/* The line entering a completed step is part of the completed run. */
.step.complete::before {
  background: var(--step-accent);
}

/* ── Marker ──────────────────────────────────────────────────────── */

/*
 * The marker is in the chip lineage (see chip.css), which is where the
 * inline-flex centering comes from and, more importantly, the auto-contrast
 * pair: --fill is --step-accent capped so text on it clears AA, --on-fill
 * is that text.
 *
 * Deriving it here instead produced 14 AA failures across the tone × theme
 * grid, because picking white-or-black text is only half the job — the
 * fill has to be luminance-capped too, or a mid-blue takes white text at
 * 2.95:1. The lineage already knows that.
 */
.step-marker {
  --tone-fill: var(--step-accent);

  /* Above the connector, and opaque, so the line stops at the circle. */
  position: relative;
  z-index:  1;

  flex-shrink: 0;

  inline-size:   var(--step-marker-size);
  block-size:    var(--step-marker-size);
  border-radius: 999px;

  background:  var(--surface);
  border:      2px solid var(--rule);
  color:       var(--ink-mute);
  font-size:   var(--text-sm);
  font-weight: 600;
  line-height: 1;

  transition: background var(--motion-fast), border-color var(--motion-fast),
              color var(--motion-fast);
}

/*
 * Self-numbering, unless the marker has content of its own.
 *
 * The increment lives on the marker, NOT on its ::before. Putting it on
 * the pseudo-element looks equivalent and is not: a marker with its own
 * content sets `content: none`, the pseudo-element is then never
 * generated, and the increment never runs — so one hand-written checkmark
 * silently renumbers every step after it. (Observed: a three-step list
 * reading ✓, 1, 2.)
 *
 * `:empty` does not match an element containing whitespace in every engine
 * this package targets, so write the marker as <span class="step-marker">
 * </span> with nothing between the tags — not across two lines.
 */
.step-marker {
  counter-increment: fjs-step;
}
.step-marker::before {
  content: counter(fjs-step);
}
.step-marker:not(:empty)::before {
  content: none;
}

/* ── Labels ──────────────────────────────────────────────────────── */

.step-label {
  font-size:   var(--text-md);
  font-weight: 500;
  line-height: 1.3;
}

.step-hint {
  font-size:   var(--text-xs);
  color:       var(--ink-mute);
  line-height: 1.3;
}

/* ── States ──────────────────────────────────────────────────────── */

.step.complete {
  color: var(--ink-soft);
}
/* A completed marker is a solid fill; the lineage supplies both colors. */
.step.complete .step-marker {
  background:   var(--fill);
  border-color: var(--fill);
  color:        var(--on-fill);
}

.step[aria-current="step"] {
  color: var(--ink);
}
.step[aria-current="step"] .step-label {
  font-weight: 600;
}
/*
 * The current marker is a ring, not a fill: accent border, --ink number.
 *
 * The number is deliberately NOT drawn in the accent. Accent-colored text
 * on a surface is a different contrast problem from text on an accent fill
 * — the fill can be capped, but a light brand hue as *text* on white
 * cannot be without changing the hue. --ink is unconditionally safe, and
 * the accent ring is what carries the state visually.
 */
.step[aria-current="step"] .step-marker {
  border-color: var(--step-accent);
  color:        var(--ink);
  background:   var(--surface);
}

/*
 * ── Vertical ─────────────────────────────────────────────────────────
 *
 * Long labels, hints on every step, or a narrow column. The connector
 * turns with it: same "reach back to the previous marker" idea, now on
 * the block axis, where the tracks are not equal heights — so it spans
 * from the previous marker's center to this one's rather than a fixed
 * 100%.
 */
.steps.vertical {
  flex-direction: column;
  align-items:    stretch;
  gap:            0;
}

.steps.vertical .step {
  flex-direction: row;
  align-items:    flex-start;
  gap:            var(--space-lg);
  text-align:     start;
  /* No top padding: the marker sits flush with the step's top edge, which
     is what lets the connector below land exactly on the next marker. */
  padding-block:  0 var(--space-3xl);
}
.steps.vertical .step:last-child {
  padding-block-end: 0;
}

/*
 * The vertical connector runs DOWNWARD from each step's own marker to the
 * bottom of that step — which, with steps stacked and no gap, is exactly
 * the top of the next marker.
 *
 * The horizontal version reaches backward instead, and can, because every
 * .step is an equal-width flex track so "one track back" is a constant.
 * Vertically the tracks are whatever height their content needs: a step
 * with a hint is taller than one without. A fixed reach-back leaves a
 * visible gap on exactly those steps (observed on the one step carrying a
 * hint). Reaching forward to a known edge has no such assumption.
 *
 * Drawn with ::after so it does not fight the horizontal ::before.
 */
.steps.vertical .step + .step::before {
  content: none;
}

.steps.vertical .step:not(:last-child)::after {
  content:  "";
  position: absolute;
  z-index:  0;

  inset-inline-start: calc(var(--step-marker-size) / 2);
  translate:          -1px 0;
  inline-size:        2px;

  inset-block-start: calc(var(--step-marker-size) / 2);
  inset-block-end:   0;

  background: var(--rule);
}

/* The line leaving a completed step is part of the completed run. */
.steps.vertical .step.complete::after {
  background: var(--step-accent);
}

/*
 * Label and hint are separate flex children, so in a row they would sit
 * side by side. Wrapping puts the hint on its own line, indented past the
 * marker so it aligns with the label above it.
 */
.steps.vertical .step {
  flex-wrap: wrap;
}
.steps.vertical .step-label {
  flex: 1;
  /* Optically center the first line of the label against the marker. */
  padding-block-start: 0.3125rem;
}
.steps.vertical .step-hint {
  flex-basis:          100%;
  margin-inline-start: calc(var(--step-marker-size) + 0.75rem);
  padding-block-start: var(--space-3xs);
}

