/* ===========================================================================
   The data showcase: what Proteus sends, and what it becomes in Omni.

   Owned by web-ui, loaded after site.css. Its own file for the same reason
   hero-figure.css is: site.css is at the 500-line limit and this is a
   self-contained section that nothing else references.

   Classes are prefixed `.ds-` so nothing here can collide with site.css's
   layout classes or content.css's `.c-*` shapes.

   TABS WITHOUT JAVASCRIPT
     Four `input[type=radio]` with one `name`, and `:checked ~` selectors reveal
     the matching panel. That is the whole mechanism - there is no script for
     this section at all, so it works with JavaScript disabled, which WEBSITE.md
     requires.

     Radios rather than `:target`: `:target` writes a fragment into the URL and
     into history, so switching tabs four times puts four entries in the back
     button and a shared link reopens the page scrolled to a tab. Radios also
     hand us the correct keyboard behaviour for free - arrow keys move between
     the four, which is exactly what an ARIA tablist is supposed to do and what
     a hand-rolled JS implementation usually gets wrong.

     The inputs are positioned off-screen rather than `display: none`, because
     `display: none` removes them from the tab order and the tabs stop being
     keyboard reachable. The visible focus ring is drawn on the `<label>` via
     `:focus-visible ~`, so focus is never invisible.

   NO LAYOUT SHIFT WHEN A TAB CHANGES
     All four panels occupy the SAME grid cell (`grid-area: 1 / 1`) and inactive
     ones are `visibility: hidden` rather than `display: none`. So the panel area
     is always as tall as the tallest panel and switching tabs moves nothing.
     `display: none` was the first version and it jumped the page by up to 90px
     between metrics and traces, which on a click is excluded from CLS but is
     still the page lurching under the reader's cursor.

     `visibility: hidden` also takes the inactive panels out of the accessibility
     tree and out of the tab order, which `opacity: 0` would not.

   IT IS A REPRESENTATION, NOT A SCREENSHOT
     Nobody on this project has CloudWatch Omni access, so there is no console
     capture to show and inventing one would be a fabricated screenshot of a
     product. The right-hand panels are drawn from the same numbers as the
     payload beside them, in this page's own tokens, and every one carries a
     visible caption saying so. Do not replace them with anything that looks like
     a real console.
   =========================================================================== */

/* --- Shell --------------------------------------------------------------- */

.ds { margin-top: clamp(28px, 3vw, 44px); }

/* --- Tab strip ----------------------------------------------------------- */

/* Off-screen, NOT `display: none` - see the head comment. */
.ds-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.ds-tablist {
  display: flex;
  flex-wrap: wrap;
  gap: var(--p-space-2);
  margin-bottom: clamp(18px, 2vw, 26px);
}

.ds-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--p-space-2);
  min-height: 44px;
  padding: var(--p-space-2) var(--p-space-4);
  border: 1px solid var(--s-control-border);
  border-radius: 999px;
  background: var(--p-surface);
  color: var(--p-text);
  font: 600 14px/1.2 var(--p-mono);
  letter-spacing: 0.04em;
  cursor: pointer;
  /* Colour only. A border-width or padding change on selection would reflow the
     strip on every click, which is the same mistake the nav's aria-current
     marker was fixed for in site.css. */
  transition: background var(--p-duration), color var(--p-duration);
}
.ds-tab:hover { background: var(--p-surface-alt); }

/* The count riding on each tab is a second, non-colour cue for which signal a
   tab is, and it is real data - the projected volume from the captured
   `proteus seed --dry-run` transcript further down this page. */
.ds-tab small {
  font-size: 12px;
  font-weight: 500;
  color: var(--p-muted);
  font-variant-numeric: tabular-nums;
}

/* SELECTED STATE. Reached by id through `~ .ds-tablist`, and it has to be: the
   four inputs are NOT adjacent siblings of their labels. They sit before
   `.ds-panels` as a block of four, because the panel-reveal selectors below need
   them as siblings of `.ds-panels`, and the labels live inside `.ds-tablist`.

   This was `.ds-radio:checked + .ds-tab` first, which matches nothing at all -
   there is no `.ds-tab` adjacent to any `.ds-radio`. The failure was invisible in
   review and nearly invisible on screen: the panels switched correctly, so the
   tabs "worked", and the only symptom was that none of the four ever looked
   selected. A contrast probe caught it by returning `missing` for the selector,
   not by returning a bad ratio.

   Fill AND text weight change together; the reader also has the panel content
   itself as a cue, so selection is never carried by colour alone.

   `font-weight: 700` here costs no reflow, and that is measured rather than
   hoped: the label is set in `--p-mono`, so 600 and 700 have the same advance.
   All four label widths are byte-identical in all four selection states -
   190.55 / 163.59 / 173.79 / 154.60 px, unchanged whichever tab is checked. If
   this ever moves to a proportional face, drop the weight change rather than
   letting the strip reflow on click. */
#ds-metrics:checked ~ .ds-tablist [for="ds-metrics"],
#ds-logs:checked    ~ .ds-tablist [for="ds-logs"],
#ds-traces:checked  ~ .ds-tablist [for="ds-traces"],
#ds-rum:checked     ~ .ds-tablist [for="ds-rum"] {
  background: var(--p-accent);
  border-color: transparent;
  color: var(--p-on-accent);
  font-weight: 700;
}
#ds-metrics:checked ~ .ds-tablist [for="ds-metrics"] small,
#ds-logs:checked    ~ .ds-tablist [for="ds-logs"] small,
#ds-traces:checked  ~ .ds-tablist [for="ds-traces"] small,
#ds-rum:checked     ~ .ds-tablist [for="ds-rum"] small {
  color: var(--p-on-accent);
}

/* Focus must be visible even though the input itself is off-screen, or a keyboard
   user arrowing through the four has no idea where they are. */
#ds-metrics:focus-visible ~ .ds-tablist [for="ds-metrics"],
#ds-logs:focus-visible    ~ .ds-tablist [for="ds-logs"],
#ds-traces:focus-visible  ~ .ds-tablist [for="ds-traces"],
#ds-rum:focus-visible     ~ .ds-tablist [for="ds-rum"] {
  outline: 3px solid var(--p-focus);
  outline-offset: 3px;
}

/* --- Panels -------------------------------------------------------------- */

.ds-panels { display: grid; }

.ds-panel {
  grid-area: 1 / 1;
  visibility: hidden;
  display: grid;
  gap: clamp(20px, 2.5vw, 32px);
}
@media (min-width: 62rem) {
  /* Payload left, representation right. The payload column is the narrower of
     the two: JSON wraps gracelessly and the charts need the width. */
  .ds-panel { grid-template-columns: minmax(0, 0.95fr) minmax(0, 1fr); align-items: start; }
}

/* One selector per tab. Written out rather than generated because there is no
   build step here and four lines are clearer than any trick that would shorten
   them. The `~` reaches from the input to `.ds-panels`, so every input must stay
   a sibling of `.ds-panels` in the markup. */
#ds-metrics:checked ~ .ds-panels > .ds-panel--metrics,
#ds-logs:checked    ~ .ds-panels > .ds-panel--logs,
#ds-traces:checked  ~ .ds-panels > .ds-panel--traces,
#ds-rum:checked     ~ .ds-panels > .ds-panel--rum {
  visibility: visible;
}

/* WITHOUT CSS AT ALL every panel is visible and every payload is readable, in
   source order. That is the correct degradation and it needs no rule; it is
   recorded here so nobody "fixes" it with a `hidden` attribute in the markup,
   which would hide three quarters of this section from a reader with no CSS. */

.ds-col { min-width: 0; }

.ds-col-head {
  display: block;
  font: 600 11px/1.6 var(--p-mono);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--p-accent);
  margin-bottom: var(--p-space-3);
}

/* --- The payload --------------------------------------------------------- */

/* Same dark surface as `.code-block` in site.css, in both themes, because a
   wire payload is a transcript and the page already treats transcripts that
   way. The tokens are site.css's `--s-code-*`, not new values. */
.ds-payload {
  margin: 0;
  font: 12px/1.75 var(--p-mono);
  background: var(--s-code-bg);
  color: var(--s-code-fg);
  border: 1px solid var(--s-code-border);
  border-radius: var(--p-radius-md);
  padding: clamp(14px, 1.6vw, 20px);
  /* Scroll, not wrap. A wrapped JSON payload loses its indentation, and the
     indentation is how a reader sees the nesting that the attribute highlight
     below is pointing at. `.code-block` wraps because a clone URL must stay
     copyable in one piece; this is the opposite case. */
  overflow-x: auto;
  overflow-y: auto;
  white-space: pre;
  tab-size: 2;
  /* 42em OF THIS ELEMENT'S OWN FONT, and both halves of that are deliberate.
     42 rather than a rounder number because it is a line count in disguise: at
     12px/1.75 the box shows 22 lines, and the four `<mark>`ed resource
     attributes land on lines 8, 9, 17 and 18 of every OTLP payload here - the
     attribute array is alphabetically sorted by the protobuf serialiser, so
     those positions are fixed rather than lucky. A shorter box put
     `service.name` below the fold, which hides the one thing this panel exists
     to point at.

     `em`, not `rem`: a `rem` here would be measured against the root font size,
     which is not reliably 16px - the browser this was verified in computes the
     root at 12px, so `24rem` rendered as 288px and showed eleven lines. `em`
     resolves against this element's own declared size, so the box is a fixed
     number of lines of the text inside it whatever the root is, and it still
     grows if the reader scales text up. */
  max-height: 42em;
}

/* THE RESOURCE ATTRIBUTES, highlighted. They are how an OTLP record states its
   own identity, and they are marked because that is what the section is about.

   This comment used to say Omni builds its service map from these and that a
   `PutMetricData` datapoint carries none of them. The second clause was false -
   `PutMetricData` accepts an `Entity` with `KeyAttributes` - and the first was
   never verifiable without Omni access. The durable point is that a metric names
   one entity while a span names a pair.

   Marked up as `<mark>` rather than coloured text, because the point is that
   these four lines are the ones that matter - and a `<mark>` still says so when
   the CSS does not load. The default UA `mark` background is a yellow that
   belongs to no theme here, so both are overridden.

   `--p-accent` at 14% over `--s-code-bg` rather than a flat fill: the payload's
   own foreground has to stay legible through it, and a solid accent block
   would drop `--s-code-fg` under 3:1. Measured, not assumed - see the report. */
.ds-payload mark {
  background: color-mix(in srgb, var(--p-accent) 22%, transparent);
  color: var(--p-mint-100);
  border-radius: 3px;
  padding: 1px 2px;
}
/* 22% was 14% first and the highlight barely read: the payload's own foreground
   (--s-code-fg, #b4eacd) and the mark's (--p-mint-100, #d7f8e6) are close by
   design, so the background is doing all the work. Measured the marked text
   against its real composited background rather than against --s-code-bg, which
   is what `color-mix(..., transparent)` makes necessary - see the report for both
   themes' ratios. --p-mint-100 is the mark foreground in BOTH themes, which is
   why there is no dark-theme override: the surface underneath is the code
   surface, and that does not switch. */

/* The one-line statement of what this tab's request IS, above the payload. Every
   one of the four says something about the request a reader would otherwise find
   out by having it fail on them - the reserved `AWS/` namespace, the log-stream
   headers, Transaction Search, whole-second RUM timestamps. */
.ds-blurb {
  margin: 0 0 var(--p-space-3);
  font-size: 13px;
  line-height: 1.55;
  color: var(--p-muted);
}

/* The wire facts under each payload: format, byte count, target URL. All three
   come from `payloads.js`, and they are the disclosure that keeps showing JSON
   honest - the reader is told in the same breath that the wire is gzipped
   protobuf and how many bytes it came to. The byte count is the PROTOBUF size
   and is smaller than the JSON above it in three of the four cases, which is why
   it is labelled "on the wire" rather than left to be read as the size of what is
   on screen. */
.ds-wire {
  margin: var(--p-space-3) 0 0;
  font: 12px/1.6 var(--p-mono);
  color: var(--p-muted);
  overflow-wrap: anywhere;
}

/* The two "this looks like a bug and is correct" notes. Quieter than `.ds-blurb`:
   a reader who has not noticed quoted 64-bit integers does not need to, and one
   who has needs the answer immediately. OTLP tabs only - neither applies to the
   RUM body, which is genuine JSON. */
.ds-note {
  margin: var(--p-space-3) 0 0;
  padding-left: var(--p-space-3);
  /* `--p-accent`, not `--p-border`. This rule is the only thing marking the note
     as a block - there is no fill behind it - so it is a meaning-bearing graphic
     and needs 3:1. `--p-border` measured 1.27:1 in light and 1.59:1 in dark.
     Accent measures 4.73:1 and 8.00:1 on these surfaces, and matches what
     `.panel` in site.css and `.cf-rule` in compose-figure.css already do with
     the same problem. */
  border-left: 2px solid var(--p-accent);
  font-size: 12px;
  line-height: 1.6;
  color: var(--p-muted);
}

/* A sub-heading inside a panel, for the logs tab's two request groups. Mono and
   small: it is a label on a group of records, not a section heading, and it must
   not compete with `.ds-view-title`. */
.ds-group-head {
  margin: var(--p-space-4) 0 var(--p-space-2);
  font: 600 11px/1.6 var(--p-mono);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--p-muted);
  overflow-wrap: anywhere;
}
.ds-group-head:first-child { margin-top: 0; }
.ds-group-head code { text-transform: none; letter-spacing: 0; }

/* --- The representation -------------------------------------------------- */

.ds-view {
  background: var(--p-surface);
  border: 1px solid var(--p-border);
  border-radius: var(--p-radius-md);
  padding: clamp(16px, 1.8vw, 24px);
}
.ds-view > :last-child { margin-bottom: 0; }

.ds-view-title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--p-space-2) var(--p-space-3);
  margin-bottom: var(--p-space-4);
}
.ds-view-title strong { font: 650 15px/1.3 var(--p-font); }
.ds-view-title span { font: 500 12px/1.3 var(--p-mono); color: var(--p-muted); }

/* Charts: fixed viewBox, `width: 100%; height: auto`, so the box is final on
   first paint exactly as the hero figure's is. */
.ds-chart { display: block; width: 100%; height: auto; }

/* The sentence that says what a chart is. Above the chart rather than below it:
   the metrics panel holds two charts and the whole point is the comparison
   between them, so each needs its claim stated before the reader looks. */
.ds-chart-caption {
  margin: 0 0 var(--p-space-3);
  font-size: 13px;
  line-height: 1.55;
  color: var(--p-muted);
}
.ds-chart + .ds-chart-caption { margin-top: var(--p-space-4); }

.ds-chart-line { fill: none; stroke: var(--p-accent); stroke-width: 2; stroke-linejoin: round; }
.ds-chart-area { fill: color-mix(in srgb, var(--p-accent) 12%, transparent); stroke: none; }
.ds-chart-grid { stroke: var(--p-border); stroke-width: 1; }
.ds-chart-axis { font-family: var(--p-mono); font-size: 10px; fill: var(--p-muted); }
/* The stretch a fault is active for. Amber, matching the degraded node in the
   hero figure, and labelled in text beside it - never colour alone. */
.ds-chart-fault { fill: color-mix(in srgb, var(--p-warning) 16%, transparent); stroke: none; }
.ds-chart-peak { fill: var(--p-warning); }

/* Log rows. A table shape, because it is tabular, but rendered as a grid so a
   long message wraps under itself instead of widening the timestamp column. */
.ds-logs { display: grid; gap: 1px; margin: 0; padding: 0; list-style: none; }
.ds-logs li {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: var(--p-space-2) var(--p-space-3);
  align-items: baseline;
  padding: var(--p-space-2) 0;
  border-bottom: 1px solid var(--p-border);
  font: 12px/1.6 var(--p-mono);
}
.ds-logs li:last-child { border-bottom: 0; }
.ds-log-time { color: var(--p-muted); font-variant-numeric: tabular-nums; }
/* The level is a word, so severity never depends on the colour reaching anyone. */
.ds-log-level { font-weight: 600; letter-spacing: 0.06em; }
.ds-log-level[data-level="INFO"]  { color: var(--p-info); }
.ds-log-level[data-level="WARN"]  { color: var(--p-warning); }
.ds-log-level[data-level="ERROR"] { color: var(--p-danger); }
.ds-log-msg { color: var(--p-text); overflow-wrap: anywhere; }

/* The RUM panel's list of event types is a two-column variant - a type and its
   attributes, with no timestamp or level to show. */
.ds-logs--kinds li { grid-template-columns: auto minmax(0, 1fr); }
.ds-logs--kinds .ds-log-time { color: var(--p-accent); }

/* Span waterfall. Each row is a label plus a bar whose offset and width are
   passed in as percentages from the markup, so the geometry is data. */
.ds-spans { display: grid; gap: var(--p-space-2); margin: 0; padding: 0; list-style: none; }
.ds-span { display: grid; gap: 2px; }
.ds-span-head {
  display: flex;
  justify-content: space-between;
  gap: var(--p-space-3);
  font: 12px/1.5 var(--p-mono);
  color: var(--p-muted);
}
.ds-span-head b { font-weight: 600; color: var(--p-text); overflow-wrap: anywhere; }
.ds-span-head i { font-style: normal; font-variant-numeric: tabular-nums; flex: none; }
/* `--p-surface-alt` on `--p-surface`, which is what `.ds-view` is. In a
   `section--alt` the view is still `--p-surface`, so the track needs no variant -
   it is scoped to its own card, not to the section.

   `display: block` on BOTH, and it is not optional: the track and the bar are
   `<span>`s (a `<div>` is not allowed inside the `<li>`'s inline content here
   without reshaping the row), and `height`, `width` and `margin-left` all do
   nothing on an inline box. The first version left every bar invisible while the
   tracks still looked plausible, so the panel appeared to render and simply had
   no data in it. */
.ds-span-track {
  display: block;
  height: 10px;
  border-radius: 999px;
  background: var(--p-surface-alt);
}
.ds-span-bar {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--p-accent);
  /* `margin-left`/`width` from the markup. Static - nothing animates here, so no
     layout property is being animated. */
  margin-left: var(--ds-at, 0%);
  width: var(--ds-of, 100%);
}
.ds-span--slow .ds-span-bar { background: var(--p-warning); }
.ds-span--slow .ds-span-head b { color: var(--p-warning); }

/* Key/value figures, for the RUM panel and anywhere a number is the whole
   answer. `auto-fit` so three or four reflow without a breakpoint each. */
.ds-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: var(--p-space-4);
  margin: 0 0 var(--p-space-4);
  padding: 0;
  list-style: none;
}
.ds-figures div { display: grid; gap: 2px; }
.ds-figure-value {
  font: 700 clamp(1.25rem, 2.2vw, 1.6rem)/1.1 var(--p-font);
  letter-spacing: -0.02em;
  color: var(--p-accent);
  font-variant-numeric: tabular-nums;
}
.ds-figure-label { font: 12px/1.4 var(--p-mono); color: var(--p-muted); }

/* --- The caption that must never be dropped ----------------------------- */

.ds-caption {
  margin: clamp(18px, 2vw, 26px) 0 0;
  font-size: 14px;
  color: var(--p-muted);
}
