/* Timestral forecasting widget.
 *
 * Every colour here is a token from /assets/widget-shared.css, so light, dark and the host's theme
 * sync work without anything in this file knowing about them. There is no categorical palette: the
 * forecast uses Visual Intelligence's highlight orange (#FF8204), the series is the ink, and the
 * covariate lanes are told apart by their names, not by hue.
 *
 * Structure: a pale cream frame (--widget-surface) with the chart filling it. Dataset chips sit on
 * the chart, vertically aligned with the snap dots.
 */
.ts-frame {
  /* Same highlight as Visual Intelligence grounding marks / selected prompts. */
  --widget-orange: #FF8204;
  /* Series / snaps / handle / switch-on — CTF navy; flips with html.dark like --ink-navy. */
  --ts-ink: #343446;
  /* Grip + on-thumb: cream on ink in light, invert on light ink in dark. */
  --ts-cream: #FBFBF8;
  /* CTF --px-other hover wash. */
  --ts-wash: #56566c;
  /* Concentric with --widget-radius (20px) and .ts-chips radius (8px): 20 − 8. */
  --ts-corner-inset: 12px;
  --ts-edge-inset: 20px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Height follows the plot (chart min-height is set in JS from the tallest dataset). */
  color: var(--color-text-primary);
  background: var(--widget-surface);
  border: 1px solid var(--color-border-primary);
  border-radius: var(--widget-radius);
  font-family: var(--widget-font);
  /* Text rendering as on CTF Speedrun (its <body>): grayscale anti-aliasing, which draws the same glyphs
     visibly thinner than the default on macOS, and no mobile font inflation. Inherited by every label,
     tick, tooltip and button in the card. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-size-adjust: 100%;
  overflow: hidden;
}
/* Same dark remap as CTF .ctf-race: ink → off-white, cream → steel invert, wash → navy-500. */
html.dark .ts-frame {
  --ts-ink: var(--color-text-primary);
  --ts-cream: var(--color-text-invert);
  --ts-wash: #88889c;
}

/* ---- plot ----------------------------------------------------------------------------------- */
.ts-plot {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: transparent;
  box-sizing: border-box;
}
/* Future region behind the cut; bleeds to frame edges. */
.ts-heldout {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 50%;
  z-index: 0;
  pointer-events: none;
  /* Brand primary: cream in light, darker steel in dark — sits under the cut. */
  background: var(--color-surface-brand-primary);
}
/* Past/future separator — same stroke as .ts-frame outline. Under .ts-chart so x-axis
   labels paint over it; handle stays above via .ts-cut-layer. */
.ts-cut-rule {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  z-index: 0;
  width: 0;
  border-left: 1px solid var(--color-border-primary);
  pointer-events: none;
}

/* ---- dataset switcher (CTF .cr-seg 1:1) ----------------------------------------------------- */
.ts-controls {
  position: absolute;
  z-index: 6; /* above cut overlay so the source line stays visible */
  left: var(--ts-corner-inset);
  top: var(--ts-corner-inset);
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 6px;
  flex: none;
  min-width: 0;
  width: calc(100% - 2 * var(--ts-corner-inset));
  max-width: calc(100% - 2 * var(--ts-corner-inset));
  pointer-events: none;
  box-sizing: border-box;
}
/* Chips + optional mobile Forecast pin on one row (pin baseline-matches chip labels). */
.ts-controls-row {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
}
.ts-forecast-pin {
  display: none;
  flex: none;
  margin-left: auto;
  font: 500 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  color: var(--widget-orange);
  white-space: nowrap;
  user-select: none;
  opacity: 1;
  filter: blur(0);
  transform: scale(1);
  transition:
    opacity 0.28s ease,
    filter 0.28s ease,
    transform 0.28s cubic-bezier(0.22, 1.1, 0.36, 1);
}
.ts-frame.is-compact .ts-forecast-pin { display: inline-block; }
.ts-frame.is-compact .ts-cut-layer .ts-forecast-label { display: none; }
/* Right inset = EDGE_INSET so it matches the pin's top inset (centred in the chip track). */
.ts-frame.is-compact .ts-controls {
  width: calc(100% - var(--ts-corner-inset) - var(--ts-edge-inset));
  max-width: calc(100% - var(--ts-corner-inset) - var(--ts-edge-inset));
}
.ts-frame.is-compact .ts-chips { max-width: calc(100% - 4.75rem); }
.ts-frame.dragging .ts-forecast-pin {
  opacity: 0;
  filter: blur(5px);
  transform: scale(0.88);
}
/* Source + unit under the dataset switch — same type as .ts-cov-head-title ("Covariates").
   Left inset matches the first chip label (track border + pad + chip pad). */
.ts-info {
  margin: 0;
  margin-left: calc(1px + 0.25rem + 0.625rem);
  max-width: 100%;
  font: 500 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  color: var(--color-text-primary);
  opacity: 0.5;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
  user-select: none;
}
/* 0.5 × parent 0.5 → 25% effective for the unit / currency. */
.ts-info-unit { opacity: 0.5; }
/* .cr-seg — cream track, sliding white thumb, 28px buttons. */
.ts-chips {
  position: relative;
  display: inline-flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  flex: none;
  max-width: 100%;
  padding: 0.25rem;
  border: 1px solid var(--widget-border);
  border-radius: 0.5rem;
  background: var(--widget-surface);
  box-sizing: border-box;
  overflow: visible;
  pointer-events: auto;
}
/* Sliding selection pill — same motion as CTF .cr-seg-thumb. */
.ts-seg-thumb {
  position: absolute;
  top: 0.25rem;
  bottom: 0.25rem;
  left: 0;
  width: 0;
  border-radius: 0.25rem;
  background: var(--color-surface-card);
  outline: 1px solid var(--widget-border);
  pointer-events: none;
  z-index: 0;
  transition: transform 0.35s cubic-bezier(0.22, 1.1, 0.36, 1), width 0.35s cubic-bezier(0.22, 1.1, 0.36, 1);
}
@media (prefers-reduced-motion: reduce) {
  .ts-seg-thumb { transition: none; }
}
.ts-chip {
  appearance: none;
  cursor: pointer;
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1.75rem;
  padding: 0 0.625rem;
  border: 0;
  border-radius: 0.25rem;
  background: transparent;
  color: var(--color-text-primary);
  font: 500 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  opacity: 0.5;
  transition: opacity 0.2s ease;
  white-space: nowrap;
}
.ts-chip:hover { opacity: 0.75; }
.ts-chip.on { opacity: 1; }
.ts-chip:focus-visible { outline: 2px solid var(--widget-orange); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) {
  .ts-chip { transition: none; }
}
.ts-chart:focus,
.ts-chart:focus-visible { outline: none; }

/* While the cut handle is dragged: no focus rings or hover chrome. Keep the seg thumb outline. */
.ts-frame.dragging,
.ts-frame.dragging *:not(.ts-seg-thumb) {
  outline: none !important;
  -webkit-tap-highlight-color: transparent;
}
.ts-frame.dragging {
  user-select: none;
  -webkit-user-select: none;
}
.ts-frame.dragging .ts-chip:hover { opacity: 0.5; }
.ts-frame.dragging .ts-chip.on:hover { opacity: 1; }

/* ---- chart ---------------------------------------------------------------------------------- */
.ts-chart {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  width: 100%;
  /* Floor before JS runs; JS then sets the exact min-height from the tallest dataset. */
  min-height: 280px;
  touch-action: pan-y;   /* a horizontal drag moves the cut; a vertical one still scrolls the page */
  user-select: none;
  -webkit-user-select: none;
  border-radius: 0;
}
.ts-svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* Handle + snaps on the plot above .ts-cut-rule so the thumb sits on the separator. Sized in JS
   to the chart box. */
.ts-cut-layer {
  position: absolute;
  z-index: 5;
  pointer-events: none;
  overflow: visible;
}
/* SVG must not swallow chart clicks; only the handle is a hit target. */
.ts-cut-svg { display: block; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.ts-cut-layer .ts-handle,
.ts-cut-layer .ts-handle * { pointer-events: auto; cursor: ew-resize; }
/* Outer: position only. Inner: fade / blur / scale so drag position updates don't kill the motion. */
.ts-forecast-label {
  position: absolute;
  z-index: 2;
  transform: translateY(-50%);
  pointer-events: none;
  user-select: none;
}
.ts-forecast-label-inner {
  display: inline-block;
  font: 500 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  color: var(--widget-orange);
  white-space: nowrap;
  opacity: 1;
  filter: blur(0);
  transform: scale(1);
  transition:
    opacity 0.28s ease,
    filter 0.28s ease,
    transform 0.28s cubic-bezier(0.22, 1.1, 0.36, 1);
}
.ts-frame.dragging .ts-forecast-label-inner {
  opacity: 0;
  filter: blur(5px);
  transform: scale(0.88);
}
.ts-snap {
  fill: var(--ts-ink);
  transition: opacity 0.28s ease;
}
@media (prefers-reduced-motion: reduce) {
  .ts-forecast-label-inner,
  .ts-forecast-pin,
  .ts-snap { transition: none; }
  .ts-frame.dragging .ts-forecast-label-inner,
  .ts-frame.dragging .ts-forecast-pin { filter: none; }
}

.ts-ylabels,
.ts-axis { opacity: 0.5; }
/* Same stroke as .ts-frame / covariate row borders. */
.ts-zero { stroke: var(--color-border-primary); stroke-width: 1; shape-rendering: crispEdges; }
.ts-hist, .ts-held { fill: none; stroke: var(--ts-ink); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
.ts-held { opacity: 0.18; }
.ts-median { fill: none; stroke: var(--widget-orange); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* Widest prediction interval (q10–q90). */
.ts-band { fill: var(--widget-orange); opacity: 0.18; }
/* Covariate area wash under the series — ink token so it themes with html.dark. */
#ts-cov-fill-grad stop { stop-color: var(--ts-ink); }

/* Covariates header row: HTML flex bar so title, metric and master switch share one midline. */
.ts-cov-head-bar {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 var(--ts-edge-inset);
  box-sizing: border-box;
  pointer-events: auto;
  cursor: pointer;
  /* Same stroke as .ts-frame */
  border-bottom: 1px solid var(--color-border-primary);
}
/* CTF .cr-col.is-hl wash, from the bottom (header + each covariate row). */
.ts-cov-head-bar:hover,
.ts-lane-hit:hover {
  background: linear-gradient(to top, color-mix(in srgb, var(--ts-wash) 3%, transparent), transparent);
}
.ts-cov-head-title {
  flex: none;
  font: 500 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  color: var(--color-text-primary);
}
.ts-cov-head-end {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-left: auto;
  min-width: 0;
}
.ts-cov-head-metric {
  font: 500 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  color: var(--color-text-primary);
  white-space: nowrap;
}
.ts-cov-head-pct { color: var(--widget-orange); }
.ts-cov-head-muted { color: var(--color-text-muted); }
.ts-cov-head-bar .ts-lane-switch {
  position: relative;
  left: auto;
  top: auto;
  transform: none;
  flex: none;
}

/* Covariate titles: 14/20 regular ALTMistral, +0.02em. */
.ts-lane-label {
  font: 400 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  fill: var(--color-text-primary);
  dominant-baseline: central;
}
/* x/y axis labels — same size as the section head, regular weight. */
.ts-axis-label {
  font: 400 0.875rem/1.25rem var(--widget-font);
  letter-spacing: 0.02em;
  fill: var(--color-text-primary);
}
.ts-lane { --c: var(--color-text-muted); }
.ts-cov-line { fill: none; stroke: var(--c); stroke-width: 1.25; stroke-linejoin: round; opacity: 0.9; }
.ts-cov-fill { stroke: none; }
/* 0/1 flags: a continuous bar while the flag is on; omitted when it is off */
.ts-cov-bar { stroke: var(--c); stroke-width: 2; stroke-linecap: round; fill: none; opacity: 0.9; }

/* per-lane hit target (hover + click to toggle) and pill switch on the right. */
.ts-lane-layer { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.ts-lane-hit {
  position: absolute;
  left: 0;
  right: 0;
  box-sizing: border-box;
  pointer-events: auto;
  cursor: pointer;
  /* Same stroke as .ts-frame */
  border-bottom: 1px solid var(--color-border-primary);
}
.ts-lane-switch {
  appearance: none;
  position: absolute;
  transform: translateX(-100%);
  box-sizing: border-box;
  width: 28px;
  height: 16px;
  padding: 0;
  border: 1px solid var(--color-border-secondary);
  border-radius: 999px;
  background: var(--color-border-secondary);
  cursor: pointer;
  opacity: 1;
  pointer-events: auto;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.ts-lane-switch-thumb {
  position: absolute;
  top: 1px;
  left: 1px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--ts-cream);
  transition: transform 0.15s ease;
}
/* Off-track in dark: light thumb on steel (cream token is invert for on-state). */
html.dark .ts-lane-switch:not(.is-on) .ts-lane-switch-thumb {
  background: var(--color-text-primary);
}
.ts-lane-switch.is-on {
  background: var(--ts-ink);
  border-color: var(--ts-ink);
}
.ts-lane-switch.is-on .ts-lane-switch-thumb { transform: translateX(12px); }
.ts-lane-switch:focus-visible { outline: 2px solid var(--ts-ink); outline-offset: 2px; }
@media (pointer: coarse) { .ts-lane-switch::after { content: ""; position: absolute; inset: -9px -8px; } }
/* the cut: full-height rule is .ts-cut-rule; handle/snaps stay in .ts-cut-layer. */
.ts-handle rect {
  fill: var(--ts-ink);
  stroke: var(--widget-surface);
  stroke-width: 1.5;
}
.ts-grip { stroke: var(--ts-cream); stroke-width: 2.5; stroke-linecap: round; fill: none; }

@media (max-width: 700px) {
  /* three dataset tabs have to share one row at 360px */
  .ts-chip { padding: 0 0.5rem; letter-spacing: 0.01em; }
  .ts-info { margin-left: calc(1px + 0.25rem + 0.5rem); }
}
