/* Diagram: Mermaid figures, interactive playback, step details, message dialog. */

mermaid-diagram,
interactive-diagram {
  display: block;
}

/* The whole player is one card: a playback bar on top, the diagram below, step details as a divided column.
   Children are borderless so nothing nests boxes inside boxes. */
interactive-diagram {
  position: relative;
  overflow: clip;
  border-radius: var(--radius-lg);
  background: var(--color_bg_tile);
}

interactive-diagram figure.mermaid-diagram,
interactive-diagram pre.mermaid {
  margin: 0;
  padding: var(--space-5) var(--space-4);
  border: 0;
  border-radius: 0;
  background: transparent;
}

figure.mermaid-diagram,
pre.mermaid {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  border: 1px solid var(--color_border_default);
  border-radius: var(--radius-lg);
  background: var(--color_bg_layer);
  text-align: center;
  overflow-x: auto;
}

figure.mermaid-diagram svg {
  max-width: 100%;
  height: auto;
}

/* Mermaid embeds its own light-theme styles (ID-scoped, plus presentation attributes), so these need
   !important. Everything here is paint only: fonts, sizes and geometry stay as Mermaid laid them out,
   so labels never move relative to the arrows. All colours come from the --color_diagram_* tokens, so
   one rule set serves both themes. */

figure.mermaid-diagram svg :where(
  .messageText,
  .messageText > tspan,
  .labelText,
  .labelText > tspan,
  .loopText,
  .loopText > tspan,
  .sectionTitle,
  .sectionTitle > tspan,
  .noteText,
  .noteText > tspan
) {
  fill: var(--color_diagram_text) !important;
  stroke: none !important;
}

/* Participants: quiet tile with a hairline border instead of Mermaid's lavender box. */
figure.mermaid-diagram svg rect.actor {
  fill: var(--color_diagram_actor_bg) !important;
  stroke: var(--color_diagram_actor_border) !important;
  stroke-width: 1px !important;
  rx: 8px !important;
  ry: 8px !important;
}

figure.mermaid-diagram svg text.actor > tspan,
figure.mermaid-diagram svg .actor.actor-box > tspan {
  fill: var(--color_diagram_actor_text) !important;
  stroke: none !important;
  font-weight: 500;
}

/* Lifelines recede so the messages carry the eye. */
figure.mermaid-diagram svg .actor-line {
  stroke: var(--color_diagram_lifeline) !important;
  stroke-width: 1px !important;
}

figure.mermaid-diagram svg :where(
  .messageLine0,
  .messageLine1,
  .signal,
  .innerArc,
  line[marker-end],
  path[marker-end],
  line[marker-start]:not([stroke-width='0']),
  path[marker-start],
  [id$='-arrowhead'] path,
  [id$='-crosshead'] path,
  [id$='-filled-head'] path,
  [id$='-solidTopArrowHead'] path,
  [id$='-solidBottomArrowHead'] path
) {
  fill: var(--color_diagram_line) !important;
  stroke: var(--color_diagram_line) !important;
}

/* Self-messages are an open arc: keep them unfilled (the rule above would otherwise fill the loop). */
figure.mermaid-diagram svg path[marker-end] { fill: none !important; }

figure.mermaid-diagram svg :where(.loopLine) {
  stroke: var(--color_diagram_lifeline) !important;
  fill: none !important;
}

figure.mermaid-diagram svg :where(.labelBox) {
  fill: var(--color_diagram_actor_bg) !important;
  stroke: var(--color_diagram_actor_border) !important;
}

figure.mermaid-diagram svg rect.note {
  fill: var(--color_diagram_note_bg) !important;
  stroke: var(--color_diagram_note_border) !important;
}

/* Step numbers: brand-coloured badge with readable digits. */
figure.mermaid-diagram svg [id$='-sequencenumber'],
figure.mermaid-diagram svg [id$='-sequencenumber'] circle {
  fill: var(--color_diagram_badge_bg) !important;
}

figure.mermaid-diagram svg .sequenceNumber {
  fill: var(--color_diagram_badge_text) !important;
  stroke: none !important;
  font-weight: 600;
}

/* ---- Playback controls ---- */

interactive-diagram .interactive-controls {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  /* Side padding equals the step-details panel's (--space-5), so the controls share its edges. */
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--color_border_default);
  background: var(--color_bg_tile_icon);
}

interactive-diagram .interactive-controls button {
  min-height: 2.25rem;
  padding: var(--space-1) var(--space-4);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  white-space: nowrap;
}

@media (pointer: coarse) {
  interactive-diagram .interactive-controls button { min-height: 2.75rem; }
}

interactive-diagram .interactive-controls button:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

interactive-diagram .interactive-controls button .ui-icon {
  color: currentColor;
}

interactive-diagram .interactive-toggle {
  font-weight: 600;
}

interactive-diagram .interactive-toggle-icon {
  width: 1rem;
}

interactive-diagram .interactive-nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Previous / Next are the same width so the pair is symmetric around the step counter. */
interactive-diagram .interactive-nav button { min-width: 7rem; }

interactive-diagram .interactive-nav output {
  min-width: 7rem;
  text-align: center;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color_fg_muted);
}

/* Interactive Mode: the bar stays under the sticky site header while the diagram scrolls, so Next never leaves the screen.
   At rest it is the same flush bar as in Static Mode. Once it detaches (interactive-diagram.js sets data-stuck) it becomes a
   floating rounded bar of the same width as the site header above it (the card and the header share one container width).
   Only radius, border colour and shadow change, so nothing below it jumps.
   --pin-top is set from the site header's real height (it grows when the header wraps at large text). */
interactive-diagram[data-mode='interactive'] .interactive-controls {
  position: sticky;
  top: calc(var(--pin-top, var(--space-4)) + var(--space-2));
  z-index: 20;
  border: 1px solid transparent;
  border-bottom-color: var(--color_border_default);
  transition: border-radius var(--duration-fast), box-shadow var(--duration-fast);
}

interactive-diagram[data-stuck] .interactive-controls {
  border-color: var(--color_border_default);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow_app_bar);
}

@media (prefers-reduced-motion: reduce) {
  interactive-diagram[data-mode='interactive'] .interactive-controls { transition: none; }
}

/* Static Mode: a visible cue that the message labels open their details. It does not depend on hover, so it works on touch. */
interactive-diagram .interactive-hint {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--color_fg_muted);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-align: end;
}

interactive-diagram[data-mode] .interactive-hint { display: none; }

interactive-diagram .interactive-status {
  flex-basis: 100%;
  font-size: var(--text-sm);
  color: var(--color_fg_on_state_danger_subtle);
}

/* ---- Stage + step details ---- */

interactive-diagram .interactive-stage {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
  align-items: stretch;
  gap: 0;
}

/* Grid items default to min-width:auto, so a wide diagram would stretch the column past the card (and be clipped). */
interactive-diagram .interactive-stage > * { min-width: 0; }
interactive-diagram mermaid-diagram { max-width: 100%; }
interactive-diagram figure.mermaid-diagram { overflow-x: auto; }

interactive-diagram .step-details-panel {
  padding: var(--space-5);
  border-left: 1px solid var(--color_border_default);
  background: transparent;
  font-size: var(--text-md);   /* same size as the static-mode dialog */
  overflow: auto;
}

interactive-diagram .step-details-heading {
  display: block;
  margin-bottom: var(--space-3);
  color: var(--color_fg_muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Keep normal list behaviour inside the details <aside> and dialog body. */
interactive-diagram .step-details-body li {
  display: list-item;
  padding: 0;
}

interactive-diagram .step-details-body li a {
  display: inline;
}

/* Imagery in step details (side panel and dialog): scale to the column, centred, never scroll sideways.
   Code blocks keep their own horizontal scroll; the panel itself only scrolls vertically. */
interactive-diagram .step-details-panel {
  overflow-x: hidden;
  overflow-wrap: anywhere;
}

interactive-diagram .step-details-body img,
dialog.message-detail-dialog .message-detail-body img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: var(--space-4) auto;
  border-radius: var(--radius-md);
}

interactive-diagram .step-details-body pre,
dialog.message-detail-dialog .message-detail-body pre {
  max-width: 100%;
  overflow-x: auto;
}

/* Highlighted code in step details (built by utils/highlight.js): a small card with a language chip.
   Whitespace is preserved exactly; long lines scroll inside the block, never the panel. */
code-block { display: block; }

/* The card (Figma 457:2311): a #111 frame with a hairline ring, a header row, and a pure-black code body. */
.code-block {
  margin: var(--space-4) 0;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--color_code_frame);
  box-shadow: 0 0 0 1px var(--color_code_frame_ring);
}

.code-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  min-height: 3rem;
}

/* Title: plain muted text, nothing else (Figma 455:2019). */
.code-title {
  min-width: 0;
  color: var(--color_code_head_text);
  font-size: var(--text-sm);
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.code-actions { display: inline-flex; gap: var(--space-1); }

/* Icon buttons: quiet until hovered, like the jwt.io panel actions. */
.code-action {
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color_code_head_text);
}
.code-action:hover { background: var(--color_code_file_bg); color: var(--color_code_text); }
.code-action:focus-visible { outline: var(--focus-ring); outline-offset: 1px; }
.code-action[data-state='copied'] { color: var(--color_code_string); }

.code-action[data-state='failed'] { color: var(--color_fg_on_state_danger_subtle); }

/* Expanded view: a modal that fits the code instead of the narrow column. */
/* overflow: visible - a <dialog> clips to its own box by default, which cut the card's outer hairline ring along
   the straight edges but left it showing in the gap at each rounded corner (a stray arc). The card clips itself. */
dialog.code-dialog { width: min(92vw, 70rem); max-height: 90vh; margin: auto; overflow: visible; }
dialog.code-dialog > article.code-block {
  display: flex;
  flex-direction: column;
  max-height: 90vh;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  background: var(--color_code_frame);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
dialog.code-dialog .code-block pre { flex: 1; min-height: 0; padding: var(--space-5); font-size: var(--text-md); overflow: auto; }

/* The code body: pure black inside the frame, numbered lines. */
.code-block pre,
interactive-diagram .step-details-body .code-block pre,
dialog.message-detail-dialog .message-detail-body .code-block pre {
  margin: 0;
  padding: var(--space-4);
  border: 0;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  background: var(--color_code_bg);
  box-shadow: 0 0 0 1px var(--color_code_frame_ring);
  color: var(--color_code_text);
  font-size: var(--text-sm);
  line-height: 1.75;
  white-space: pre;
  word-break: normal;
  overflow-x: auto;
  counter-reset: ln;
}

/* Line numbers: a CSS counter on each .line, so selecting or copying the code never includes them. The
   gutter is as wide as the largest number (ln-d2 for up to 99 lines, ln-d3 beyond). */
.code-block .line { display: block; padding-left: var(--ln-w, 3.25rem); position: relative; counter-increment: ln; min-height: 1.75em; }
.code-block .line::before {
  content: counter(ln);
  position: absolute;
  left: 0;
  width: calc(var(--ln-w, 3.25rem) - 1rem);
  color: var(--color_code_lineno);
  text-align: right;
  user-select: none;
}
.code-block pre.ln-d2 { --ln-w: 2.75rem; }
.code-block pre.ln-d3 { --ln-w: 3.25rem; }
.code-block pre.ln-d4 { --ln-w: 3.75rem; }

.code-block code { color: inherit; }

.tok-string { color: var(--color_code_string); }
.tok-number { color: var(--color_code_number); }
.tok-keyword { color: var(--color_code_keyword); }
.tok-tag { color: var(--color_code_tag); }
.tok-url { color: var(--color_code_string); }
.tok-attr,
.tok-key { color: var(--color_code_attr); }
.tok-punct { color: var(--color_code_punct); }
.tok-comment { color: var(--color_code_comment); }

/* ---- Per-arrow message details ---- */

interactive-diagram [data-details-ordinal] {
  cursor: pointer;
}

/* The label is the thing to select: a dotted underline marks it, next to the leading ⓘ. */
interactive-diagram text.messageText[data-details-ordinal] {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
}

/* Invisible click area behind each label (added by interactive-diagram.js), so the target is at least 24px tall for a mouse
   and 44px on touch, instead of the 17px of the text itself. */
interactive-diagram rect.message-hit {
  fill: transparent;
  stroke: none;
  cursor: pointer;
}

interactive-diagram text.messageText[data-details-ordinal]:hover,
interactive-diagram text.messageText[data-details-ordinal]:focus-visible {
  fill: var(--color_fg_link);
  outline: none;
}

interactive-diagram line[data-details-ordinal]:focus-visible,
interactive-diagram path[data-details-ordinal]:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

interactive-diagram .message-detail-hint {
  position: absolute;
  z-index: 5;
  pointer-events: none;
  padding: 0.15rem 0.45rem;
  border-radius: var(--radius-sm);
  background: var(--color_fg_bold);
  color: var(--color_bg_page);
  font-size: var(--text-xs);
  line-height: 1.2;
  box-shadow: var(--shadow_card_hover);
}

interactive-diagram .message-detail-hint[hidden] {
  display: none;
}

/* ---- Message details dialog ---- */

dialog.message-detail-dialog article {
  width: 100%;
  max-width: min(90vw, 720px);
}

dialog.message-detail-dialog header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

dialog.message-detail-dialog header h3 {
  margin: 0;
  font-size: var(--text-lg);
}

dialog.message-detail-dialog .message-detail-body {
  max-height: 60vh;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color_bg_layer_alternate);
  font-size: var(--text-md);   /* body size: the step text is the content of this dialog, so it reads at 16px */
  overflow: auto;
}

dialog.message-detail-dialog .message-detail-body > :first-child { margin-top: 0; }
dialog.message-detail-dialog .message-detail-body > :last-child { margin-bottom: 0; }

dialog.message-detail-dialog .message-detail-body pre {
  padding: var(--space-3);
  background: var(--color_bg_layer);
  font-size: var(--text-sm);
  white-space: pre-wrap;
  word-break: break-word;
}

dialog.message-detail-dialog .message-detail-body pre code {
  background: none;
  padding: 0;
}

/* Tablet and down: details drop below the diagram (a 30% column is too narrow under ~960px). */
@media (max-width: 959px) {
  interactive-diagram .interactive-stage { grid-template-columns: minmax(0, 1fr); }

  interactive-diagram .step-details-panel {
    border-left: 0;
    border-top: 1px solid var(--color_border_default);
  }
}

@media (max-width: 768px) {
  interactive-diagram .interactive-controls {
    align-items: stretch;
    gap: var(--space-2);
    padding-inline: var(--space-4);
  }

  interactive-diagram .interactive-toggle { width: 100%; }
  interactive-diagram .interactive-hint { text-align: start; }

  /* Counter on its own line above two equal buttons, so nothing is squeezed. */
  interactive-diagram .interactive-nav {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
    width: 100%;
  }

  interactive-diagram .interactive-nav output {
    grid-column: 1 / -1;
    grid-row: 1;
    min-width: 0;
    white-space: nowrap;
  }

  interactive-diagram .interactive-nav button { min-width: 0; }
}

@media (max-width: 399px) {
  interactive-diagram .interactive-controls button {
    padding-inline: var(--space-3);
  }
}

/* Pinned bar. One row at every width, so its height never changes while the page scrolls:
   [mode] ............ [Previous] STEP n OF N [Next]
   On a phone the mode button is an icon. When the labels no longer fit (narrow screens, large text) interactive-diagram.js
   sets data-tight: Previous / Next become 44px arrow buttons and the counter shortens to n/N. Their names stay available
   to assistive technology. 44px is a touch target, so it is deliberately not scaled with the text size. */
interactive-diagram[data-mode='interactive'] .interactive-controls {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
}

interactive-diagram[data-mode='interactive'] .interactive-toggle { flex: none; width: auto; }

interactive-diagram[data-mode='interactive'] .interactive-nav {
  display: flex;
  flex: 1;
  min-width: 0;
  justify-content: flex-end;
  gap: var(--space-2);
  width: auto;
}

interactive-diagram[data-mode='interactive'] .interactive-nav[hidden] { display: none; }

interactive-diagram .interactive-step-short { display: none; }

@media (max-width: 768px) {
  interactive-diagram[data-mode='interactive'] .interactive-toggle {
    width: 2.75rem;
    min-height: 2.75rem;
    padding-inline: 0;
    justify-content: center;
  }

  interactive-diagram[data-mode='interactive'] .interactive-toggle-label,
  interactive-diagram[data-tight] .interactive-nav-label,
  interactive-diagram[data-tight] .interactive-step-long {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  interactive-diagram[data-mode='interactive'] .interactive-nav button { min-width: 0; padding-inline: var(--space-3); }
  interactive-diagram[data-mode='interactive'] .interactive-nav output { min-width: 0; }
}

interactive-diagram[data-tight] .interactive-toggle,
interactive-diagram[data-tight] .interactive-nav button {
  width: 44px;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  justify-content: center;
}

interactive-diagram[data-tight][data-mode='interactive'] .interactive-controls { gap: var(--space-1); padding-inline: var(--space-2); }
interactive-diagram[data-tight] .interactive-nav { justify-content: space-between; gap: var(--space-1); }
interactive-diagram[data-tight] .interactive-nav output { min-width: 0; padding-inline: 0; white-space: nowrap; }
interactive-diagram[data-tight] .interactive-step-short { display: inline; }

/* Last resort (a very narrow screen at large text): the counter is hidden visually but stays in the live region, so the
   step is still announced. */
interactive-diagram[data-tight='min'] .interactive-step-short {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* ---- Small screens ---- */

@media (max-width: 767px) {
  /* Sequence diagrams keep a readable size and scroll sideways inside their card, instead of shrinking
     to ~25% scale where the labels are illegible. */
  figure.mermaid-diagram svg,
  pre.mermaid { min-width: 40rem; }
  figure.mermaid-diagram { -webkit-overflow-scrolling: touch; }

  .code-block pre,
  interactive-diagram .step-details-body .code-block pre { padding: var(--space-3) var(--space-4); }
  interactive-diagram .step-details-panel { padding: var(--space-4); }
}

/* Touch: icon buttons meet the 44px target. */
@media (pointer: coarse) {
  .code-action { width: 2.75rem; height: 2.75rem; }
}

/* Diagram text size. Mermaid text is drawn at 12px, which is already the floor, so a diagram must never be scaled
   below 1:1. Under desktop width it keeps its natural width (--diagram-w, set from the viewBox) and scrolls
   sideways inside its card; at desktop it fits the card as before. Without the property it simply fits. */
@media (max-width: 1199px) {
  figure.mermaid-diagram svg { min-width: var(--diagram-w, 0); }
}
