/*
 * Whoop Studio charts (SPEC.md §10, SPEC-PRODUCTION §E, SPEC-INTERFACES §7). Chart
 * chrome only; every colour is a token from styles.css (§7). Data colours arrive as
 * inline styles from charts.js, so a theme switch never needs a re-render. Text never
 * wears a data colour.
 *
 * Tuned for the true-black dark theme: hairlines snap to device pixels
 * (shape-rendering: crispEdges) so they stay crisp at DPR 1.5, 1.75, 2 and 3; marks
 * stay vivid and unglowing (only the dial glows); axis text is a step brighter than
 * --ink-3 so 11px labels stay readable on OLED black and on white.
 *
 * Hooks a view may set on a container:
 *   --chart-surface   ground the chart sits on (dot rings, label halos, meter notches);
 *                     defaults to --surface. Use var(--bg) for charts on the page ground.
 */

/* ---------- root ---------- */

.chart {
  --chart-tick: color-mix(in oklab, var(--ink-3) 72%, var(--ink-2));
  --chart-track: var(--hairline);
  --chart-span: var(--surface-2);
  --chart-span-rule: var(--hairline);
  position: relative;
  width: 100%;
  min-width: 0;
  font-family: var(--font, "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif);
  font-stretch: 100%;
  font-size: 12px;
  color: var(--ink-2);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* Light theme: --surface-2 is nearly white on white, so spans take a faint ink wash. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .chart {
    --chart-span: color-mix(in oklab, var(--ink) 5%, var(--surface));
    --chart-span-rule: color-mix(in oklab, var(--ink) 11%, var(--surface));
  }
}

:root[data-theme="light"] .chart {
  --chart-span: color-mix(in oklab, var(--ink) 5%, var(--surface));
  --chart-span-rule: color-mix(in oklab, var(--ink) 11%, var(--surface));
}

/* Interactive charts: vertical swipes scroll the page (and pinch still zooms); taps and
   sideways drags reach the chart through Pointer Events. */
.chart[tabindex] {
  touch-action: pan-y pinch-zoom;
  border-radius: 8px;
  cursor: default;
}

.chart:focus {
  outline: none;
}

.chart:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.chart-stage {
  position: absolute;
  inset: 0;
}

.chart-stage.is-flow {
  position: static;
}

.chart-stage svg {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  overflow: visible;
}

.chart-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.chart-probe {
  display: none;
}

/* Reads the safe-area insets for direct-touch tooltip placement. */
.chart-inset-probe {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  padding: env(safe-area-inset-top, 0px) 0 env(safe-area-inset-bottom, 0px);
  visibility: hidden;
  pointer-events: none;
}

.chart-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  text-align: center;
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-3);
}

.chart-empty.is-flow {
  position: static;
  padding: 24px 16px;
}

/* ---------- text ---------- */

.chart text {
  font-family: inherit;
}

.chart-tick {
  fill: var(--chart-tick);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* Labels laid over data get a surface halo so crossing lines never cut them. */
.chart-label {
  fill: var(--ink-2);
  font-size: 11px;
  paint-order: stroke;
  stroke: var(--chart-surface, var(--surface));
  stroke-width: 3px;
  stroke-linejoin: round;
}

.chart-axis-title {
  fill: var(--chart-tick);
  font-size: 11px;
}

.chart-end-label {
  fill: var(--ink-2);
  font-size: 12px;
}

.chart-end-value {
  fill: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ---------- frame ---------- */

.chart-grid,
.chart-axis,
.chart-ref,
.chart-crosshair,
.chart-marker-line,
.chart-zero,
.chart-row-rule {
  shape-rendering: crispEdges;
}

.chart-grid {
  fill: none;
  stroke: var(--grid);
  stroke-width: 1px;
}

.chart-grid.is-on-span {
  stroke: var(--chart-span-rule);
}

.chart-axis {
  fill: none;
  stroke: var(--axis);
  stroke-width: 1px;
}

.chart-ref {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1px;
  stroke-opacity: 0.75;
}

.chart-leader {
  fill: none;
  stroke: var(--axis);
  stroke-width: 1px;
}

/* ---------- marks ---------- */

.chart-line {
  fill: none;
  stroke-width: 2px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-line.is-faint,
.chart-dot.is-faint {
  opacity: 0.45;
}

.chart-dots.is-faint {
  opacity: 0.55;
}

.chart-line-halo {
  fill: none;
  stroke: var(--chart-surface, var(--surface));
  stroke-width: 6px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-area {
  stroke: none;
  fill-opacity: 0.12;
}

.chart-band,
.chart-bar {
  stroke: none;
}

/* 2px surface ring drawn under the fill, so the mark keeps its full radius. */
.chart-ring {
  stroke: var(--chart-surface, var(--surface));
  stroke-width: 4px;
  paint-order: stroke;
}

.chart-fit {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 2px;
  stroke-linecap: round;
}

.chart-mean {
  stroke: var(--ink);
  stroke-width: 2px;
  stroke-linecap: round;
}

.chart-mean-halo {
  stroke: var(--chart-surface, var(--surface));
  stroke-width: 6px;
  stroke-linecap: round;
}

/* ---------- annotations: notes (markers) and experiments (spans) ---------- */

.chart-span {
  fill: var(--chart-span);
}

.chart-span-label {
  fill: var(--ink-2);
  font-size: 11px;
  paint-order: stroke;
  stroke: var(--chart-span);
  stroke-width: 3px;
  stroke-linejoin: round;
}

.chart-marker-line {
  stroke: var(--ink-3);
  stroke-width: 1px;
  /* Notes are context, not data: the dot at the top carries them, the hairline stays faint. */
  stroke-opacity: 0.45;
}

.chart-marker-dot {
  fill: var(--ink-3);
  stroke: var(--chart-surface, var(--surface));
  stroke-width: 2px;
  paint-order: stroke;
}

.chart-marker-line.is-active {
  stroke: var(--ink-2);
  stroke-opacity: 1;
}

.chart-marker-dot.is-active {
  fill: var(--ink);
}

/* ---------- hover layer ---------- */

.chart-hover {
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms ease;
}

.chart.is-hovering .chart-hover {
  opacity: 1;
}

.chart-hover > * {
  transition: transform 70ms ease-out;
}

/* A finger or pen moves the readout directly: no easing lag behind the hand. */
.chart.is-jump .chart-hover > *,
.chart.is-direct .chart-hover > * {
  transition: none;
}

.chart-crosshair {
  stroke: var(--ink-3);
  stroke-width: 1px;
}

.chart.is-scrubbing .chart-crosshair {
  stroke: var(--ink-2);
}

.chart-wash {
  fill: var(--ink);
  fill-opacity: 0.07;
}

.chart-focus-ring {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.5px;
}

/* ---------- tooltip ---------- */

.chart-tip {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 5;
  /* Sized by its content, never narrower than a readable tooltip on small charts, never
     wider than the screen. */
  width: max-content;
  max-width: max(100%, min(280px, calc(100vw - 16px)));
  box-sizing: border-box;
  padding: 8px 10px 7px;
  background: var(--surface-2);
  border: 1px solid var(--axis);
  border-radius: 10px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--ink-2);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms ease, transform 80ms ease-out;
}

.chart-tip.is-visible {
  opacity: 1;
}

.chart.is-jump .chart-tip,
.chart.is-direct .chart-tip {
  transition: opacity 120ms ease;
}

.chart-tip-title {
  margin-bottom: 5px;
  color: var(--ink-2);
  font-weight: 500;
}

.chart-tip-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 19px;
}

.chart-tip-key {
  flex: none;
  width: 10px;
  height: 2px;
  border-radius: 1px;
  background: var(--k, var(--ink-3));
}

.chart-tip-key.is-blank {
  background: transparent;
}

.chart-tip-label {
  flex: 1 1 auto;
  min-width: 0;
  white-space: normal;
  color: var(--ink-2);
}

.chart-tip-value {
  flex: none;
  margin-left: 12px;
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.chart-tip-notes {
  display: grid;
  gap: 3px;
}

.chart-tip-notes.has-rule {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--hairline);
}

.chart-tip-note {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.chart-tip-note .chart-tip-label {
  max-width: 240px;
  color: var(--ink);
}

.chart-tip-mark {
  flex: none;
  position: relative;
  top: -1px;
  width: 10px;
  height: 6px;
}

.chart-tip-mark::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-3);
}

/* "Tap again to open day": the action a selectable mark offers, quiet under the values. */
.chart-tip-hint {
  margin-top: 6px;
  padding-top: 5px;
  border-top: 1px solid var(--hairline);
  font-size: 11px;
  line-height: 1.3;
  color: var(--chart-tick);
}

/* A mouse over a mark that opens its day: the pointer says it can be clicked. */
.chart.is-selectable.is-hovering:not(.is-direct) {
  cursor: pointer;
}

.chart-tip-note.is-span .chart-tip-mark::before {
  left: 0;
  top: -2px;
  width: 10px;
  height: 10px;
  box-sizing: border-box;
  border: 1px solid var(--axis);
  border-radius: 3px;
  background: var(--chart-span);
}

/* ---------- dial ---------- */

.chart-dial-face {
  position: absolute;
  top: 0;
}

/* The unlit bezel: --grid disappears on OLED black and on white, so the quiet ticks use
   the hairline tone (axis tone for the longer ones every 10). */
.chart-dial-base .chart-dial-tick {
  stroke: var(--hairline);
  stroke-linecap: butt;
}

.chart-dial-base .chart-dial-tick.is-major {
  stroke: var(--axis);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .chart-dial-base .chart-dial-tick {
    stroke: var(--axis);
  }
}

:root[data-theme="light"] .chart-dial-base .chart-dial-tick {
  stroke: var(--axis);
}

.chart-dial-lit .chart-dial-tick {
  stroke: var(--dial-color, var(--ink-2));
  stroke-linecap: butt;
}

/* Glow: dark theme only (SPEC-INTERFACES §7). Static, so no reduced-motion variant. */
.chart-dial-lit.has-glow {
  filter: drop-shadow(0 0 6px color-mix(in oklab, var(--dial-color, var(--ink-2)) 60%, transparent));
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .chart-dial-lit.has-glow {
    filter: none;
  }
}

:root[data-theme="light"] .chart-dial-lit.has-glow {
  filter: none;
}

.chart-dial-ring {
  fill: none;
  stroke: var(--hairline);
  stroke-width: 1px;
}

.chart-dial-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
}

.chart-dial-label {
  font-stretch: 72%;
  font-weight: 600;
  line-height: 0.92;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.chart-dial-sub {
  margin-top: 6px;
  line-height: 1.3;
  color: var(--ink-2);
}

/* ---------- meter ---------- */

.chart-meter-track {
  fill: var(--chart-track);
}

.chart-meter-band {
  fill-opacity: 0.4;
}

.chart-meter-notch {
  stroke: var(--chart-surface, var(--surface));
  stroke-width: 1px;
}

.chart-meter-bracket {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1px;
}

.chart-meter-label {
  fill: var(--ink-2);
  font-size: 12px;
}

/* ---------- proportion bar ---------- */

.chart-prop-seg {
  transition: opacity 120ms ease;
}

.chart.is-hovering .chart-prop-seg.is-dim {
  opacity: 0.4;
}

.chart-prop-empty {
  fill: var(--chart-track);
}

.chart-prop-label {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  line-height: 1.3;
}

.chart-prop-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.chart-prop-name {
  font-size: 12px;
  color: var(--chart-tick);
}

/* ---------- calendar ---------- */

.chart-cal-empty {
  fill: var(--chart-track);
}

/* Days outside the selected range: still there for context, but clearly not what the
   takeaway and the other charts describe. */
.chart-cal-muted {
  opacity: 0.3;
}

/* ---------- interval plot ---------- */

.chart-row-rule {
  stroke: var(--grid);
  stroke-width: 1px;
}

.chart-zero {
  stroke: var(--ink-3);
  stroke-width: 1px;
}

.chart-ci {
  fill: none;
  stroke-width: 2px;
  stroke-linecap: round;
}

.chart-row-label {
  fill: var(--ink);
  font-size: 14px;
  font-weight: 500;
}

.chart-row-value {
  fill: var(--ink);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.chart-row-note {
  fill: var(--chart-tick);
  font-size: 12px;
}

/* ---------- zone track ---------- */

.chart-zone-needle {
  fill: var(--ink);
}

/* The 80% range around the 50% "most likely" range: the zone colour, faintly. */
.chart-zone-lit.is-faint {
  opacity: 0.42;
}

.chart-zone-label {
  fill: var(--chart-tick);
  font-size: 12px;
}

.chart-zone-label.is-current {
  fill: var(--ink);
  font-weight: 600;
}

/* ---------- heat table ---------- */

.chart-heat-scroll {
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--axis) transparent;
}

.chart[data-chart-kind="heat"] {
  -webkit-user-select: text;
  user-select: text;
}

.chart-heat-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 3px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.chart-heat-table th {
  padding: 4px 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--chart-tick);
  text-align: center;
  white-space: nowrap;
}

.chart-heat-table th[scope="row"] {
  width: 1%;
  padding-left: 0;
  padding-right: 12px;
  font-size: 13px;
  font-weight: 400;
  color: var(--ink-2);
  text-align: left;
}

.chart-heat-table.is-transposed thead th {
  padding-bottom: 6px;
  white-space: normal;
  vertical-align: bottom;
  line-height: 1.25;
}

.chart-heat-table td {
  min-width: 36px;
  padding: 8px 6px;
  border-radius: 6px;
  white-space: nowrap;
  color: var(--ink);
  text-align: center;
}

.chart-heat-table td.is-inverse {
  color: var(--bg);
}

.chart-heat-table td.is-empty {
  color: var(--ink-3);
}

@media (max-width: 600px) {
  .chart-heat-table {
    border-spacing: 2px;
  }

  .chart-heat-table td {
    min-width: 0;
    padding: 7px 4px;
    font-size: 12px;
  }

  .chart-heat-table th[scope="row"] {
    white-space: normal;
  }
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .chart,
  .chart * {
    transition: none !important;
    animation: none !important;
  }
}
