/* =============================================================================
   viz.css — chart tokens. No charts exist yet; this is the stylesheet Phase 1
   renders against, shipped in P0 so the palette is decided once and checked
   on both canvases before anyone writes a `d` attribute.

   The rule that makes it work: A CHART MODULE NEVER EMITS A COLOUR. A mark is
   `class="mark mark--s3"`; this file maps series index -> --viz-N. Flipping the
   theme is an attribute change on <html> with NO re-render.

   Accessibility, decided (plan.md): the <svg> is aria-hidden and a real
   <table> with the same numbers follows it, hidden with `clip-path` and NOT
   `display:none` so it stays in the accessibility tree and in print.
   `chart()` refuses to render without it.
   ========================================================================= */

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

.viz{
  position:relative;
  display:grid;
  gap:var(--sp-3);
  min-width:0;
  font-family:var(--font-text);
}
.viz__head{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:var(--sp-3); flex-wrap:wrap;
}
.viz__title{ font-size:var(--fs-sm); font-weight:var(--fw-semi); color:var(--text); }
.viz__sub{ font-size:var(--fs-xs); color:var(--text-3); }

.viz svg{
  display:block;
  width:100%;
  height:auto;
  overflow:visible;             /* labels may sit outside the plot box */
  touch-action:pan-y;
}
.viz__plot{ position:relative; min-width:0; }

/* --- axes, grid, labels ---------------------------------------------------

   Axis text is mono and tabular so a column of tick numbers lines up; mono is
   ASCII-only by design, so Armenian month names fall through to Vanik Text,
   which is exactly what we want for words.
   ---------------------------------------------------------------------- */

.viz .axis line,
.viz .axis path,
.viz .axis__rule{
  stroke:var(--viz-axis);
  stroke-width:1;
  fill:none;
  shape-rendering:crispEdges;
}
.viz .axis text,
.viz .tick text{
  fill:var(--text-3);
  font-family:var(--font-data);
  font-size:var(--fs-2xs);
  font-variant-numeric:tabular-nums lining-nums;
  letter-spacing:.01em;
}
.viz .axis__title{
  fill:var(--text-2);
  font-family:var(--font-text);
  font-size:var(--fs-xs);
  letter-spacing:var(--ls-wide);
}
.viz .grid line,
.viz .grid__line{
  stroke:var(--viz-grid);
  stroke-width:1;
  shape-rendering:crispEdges;
}
/* the zero / baseline rule reads a step stronger than the rest of the grid */
.viz .grid__zero{ stroke:var(--viz-axis); }

/* A band the reader must not cross — restricted vacation periods, weekends,
   the aging threshold past level_deadline. */
.viz .band{ fill:var(--overlay-2); }
.viz .band--warn{ fill:var(--warn-weak); }
.viz .band--bad{ fill:var(--bad-weak); }
.viz .band__label{ fill:var(--text-3); font-size:var(--fs-2xs); }

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

   `color` carries the series; every mark paints with currentColor. One
   declaration per series, and a line/area/point of the same series is
   guaranteed to match because they read the same property.
   ---------------------------------------------------------------------- */

.mark{ color:var(--viz-1); fill:currentColor; stroke:none; }
.mark--s1{ color:var(--viz-1); }
.mark--s2{ color:var(--viz-2); }
.mark--s3{ color:var(--viz-3); }
.mark--s4{ color:var(--viz-4); }
.mark--s5{ color:var(--viz-5); }
.mark--s6{ color:var(--viz-6); }
.mark--s7{ color:var(--viz-7); }
.mark--s8{ color:var(--viz-8); }

/* semantic marks — a status chart must agree with the badges next to it */
.mark--ok{ color:var(--ok); }
.mark--info{ color:var(--info); }
.mark--warn{ color:var(--warn); }
.mark--bad{ color:var(--bad); }
.mark--neutral{ color:var(--neutral); }

/* sequential ramp — heatmaps, occupancy, density */
.mark--q1{ color:var(--viz-seq-1); }
.mark--q2{ color:var(--viz-seq-2); }
.mark--q3{ color:var(--viz-seq-3); }
.mark--q4{ color:var(--viz-seq-4); }
.mark--q5{ color:var(--viz-seq-5); }

/* mark shapes */
.mark--line{
  fill:none;
  stroke:currentColor;
  stroke-width:2;
  stroke-linejoin:round;
  stroke-linecap:round;
  vector-effect:non-scaling-stroke;
}
.mark--line-dash{ stroke-dasharray:4 4; }
.mark--area{ fill:currentColor; opacity:.15; stroke:none; }
.mark--bar{ fill:currentColor; stroke:none; }
.mark--point{ fill:currentColor; stroke:var(--surface-1); stroke-width:1.5; }
.mark--arc{ fill:currentColor; stroke:var(--surface-1); stroke-width:1.5; }
.mark--cell{ fill:currentColor; stroke:var(--surface-1); stroke-width:1; }
.mark--track{ color:var(--track); fill:currentColor; }

/* emphasis: legend toggles and hover both go through these, never inline */
.mark.is-muted{ opacity:.22; }
.mark.is-focus{ opacity:1; }
.viz.has-focus .mark:not(.is-focus){ opacity:.3; }

@media (prefers-reduced-motion: no-preference){
  .mark{ transition:opacity var(--dur-1) var(--ease); }
}

/* the donut's centre number */
.viz__center{
  position:absolute;
  inset:0;
  display:grid;
  place-content:center;
  text-align:center;
  pointer-events:none;
}

/* --- legend — real buttons, because that IS the keyboard interaction ------ */

.viz-legend{
  display:flex;
  flex-wrap:wrap;
  gap:var(--sp-2) var(--sp-4);
  align-items:center;
}
.viz-legend__item{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-2);
  padding:2px 6px;
  border:1px solid transparent;
  border-radius:var(--r-chip);
  background:none;
  color:var(--text-2);
  font-size:var(--fs-xs);
  line-height:1.4;
  cursor:pointer;
  transition:color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
             opacity var(--dur-1) var(--ease);
}
.viz-legend__item:hover{ color:var(--text); border-color:var(--line); }
.viz-legend__item[aria-pressed="false"]{ opacity:.45; }
.viz-legend__item[aria-pressed="false"] .viz-legend__swatch{ background:var(--neutral); }
.viz-legend__swatch{
  width:10px; height:10px; flex:0 0 auto;
  border-radius:3px;
  background:currentColor;
  color:var(--viz-1);
}
.viz-legend__item .mark--s1 .viz-legend__swatch{ color:var(--viz-1); }
.viz-legend__val{
  margin-inline-start:var(--sp-1);
  font-family:var(--font-data);
  font-variant-numeric:tabular-nums;
  color:var(--text-3);
}

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

.viz-tip{
  position:absolute;
  z-index:5;
  min-width:0; max-width:240px;
  padding:var(--sp-2) var(--sp-3);
  border:1px solid var(--viz-tip-line);
  border-radius:var(--r-chip-lg);
  background:var(--viz-tip-bg);
  color:var(--text);
  box-shadow:var(--shadow-2);
  font-size:var(--fs-xs);
  line-height:var(--lh-snug);
  pointer-events:none;
  opacity:0;
  transform:translate(-50%,-100%) translateY(-8px);
}
.viz-tip.is-open{ opacity:1; }
.viz-tip__title{ font-weight:var(--fw-semi); margin-block-end:2px; }
.viz-tip__row{ display:flex; align-items:center; gap:var(--sp-2); justify-content:space-between; }
.viz-tip__swatch{ width:8px; height:8px; border-radius:2px; background:currentColor; flex:0 0 auto; }
.viz-tip__val{ font-family:var(--font-data); font-variant-numeric:tabular-nums; }

@media (prefers-reduced-motion: no-preference){
  .viz-tip{ transition:opacity var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
}

/* the crosshair that follows the pointer along a time axis */
.viz .crosshair{ stroke:var(--line-2); stroke-width:1; stroke-dasharray:3 3; }

/* --- the mandatory accessible table --------------------------------------

   clip-path, NOT display:none. `display:none` removes it from the
   accessibility tree AND from print, which defeats the entire point. This
   keeps it announced by a screen reader, reachable by "show data", and on the
   page when a manager prints the report.
   ---------------------------------------------------------------------- */

.viz-table{
  position:absolute;
  width:1px; height:1px;
  margin:-1px;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}
.viz-table.is-shown,
.viz[data-show-data="true"] .viz-table{
  position:static;
  width:100%; height:auto;
  margin:0;
  overflow:visible;
  clip-path:none;
  white-space:normal;
}
/* "Show data" is a plain toggle, so the table is exercised, not left to rot. */
.viz__showdata{
  justify-self:start;
  font-size:var(--fs-xs);
  color:var(--text-3);
  text-decoration:underline;
  text-underline-offset:.2em;
  cursor:pointer;
}
.viz__showdata:hover{ color:var(--text-2); }

@media print{
  .viz-table{
    position:static !important;
    width:100% !important; height:auto !important;
    margin:0 !important;
    overflow:visible !important;
    clip-path:none !important;
    white-space:normal !important;
  }
  .viz__showdata,.viz-tip{ display:none !important; }
}

/* --- draw-in --------------------------------------------------------------

   OPT-IN: a chart animates only when the author adds `.reveal` to the .viz.
   A chart without it renders finished, so a failed IntersectionObserver can
   never leave a dashboard of invisible bars. The failsafe keyframe covers the
   opted-in case for the same reason.

   Lines draw with stroke-dashoffset; the module sets --draw-len from
   getTotalLength(). Bars and cells scale from their own baseline via
   transform-box:fill-box, which is what makes an SVG transform-origin behave.
   ---------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference){
  .viz.reveal .mark--line{
    stroke-dasharray:var(--draw-len,2000);
    stroke-dashoffset:var(--draw-len,2000);
    animation:vk-viz-failsafe 1ms linear 3s forwards;
  }
  .viz.reveal.is-revealed .mark--line{
    stroke-dashoffset:0;
    transition:stroke-dashoffset var(--dur-4) var(--ease-out);
    animation:none;
  }

  .viz.reveal .mark--bar,
  .viz.reveal .mark--area{
    transform:scaleY(.001);
    transform-origin:bottom;
    transform-box:fill-box;
    animation:vk-viz-failsafe 1ms linear 3s forwards;
  }
  .viz.reveal.is-revealed .mark--bar,
  .viz.reveal.is-revealed .mark--area{
    transform:none;
    transition:transform var(--dur-3) var(--ease-out);
    transition-delay:calc(var(--i,0) * 35ms);
    animation:none;
  }

  .viz.reveal .mark--point,
  .viz.reveal .mark--arc,
  .viz.reveal .mark--cell{
    opacity:0;
    animation:vk-viz-failsafe 1ms linear 3s forwards;
  }
  .viz.reveal.is-revealed .mark--point,
  .viz.reveal.is-revealed .mark--arc,
  .viz.reveal.is-revealed .mark--cell{
    opacity:1;
    transition:opacity var(--dur-2) var(--ease);
    transition-delay:calc(var(--i,0) * 25ms);
    animation:none;
  }
}
@keyframes vk-viz-failsafe{
  to{ opacity:1; transform:none; stroke-dashoffset:0; }
}

/* count-up: format.js writes the FINAL value into the DOM first, then
   animates from zero, so no-JS, print and a failed observer all show the real
   number. All this rule does is stop the digits jittering the layout. */
.countup{ font-variant-numeric:tabular-nums lining-nums; font-feature-settings:"tnum" 1; }

/* --- sparkline — inline, no axes, no legend ------------------------------- */

.spark{ display:inline-block; width:80px; height:20px; vertical-align:middle; }
.spark .mark--line{ stroke-width:1.5; }
.spark .mark--area{ opacity:.2; }

/* --- empty / loading chart ------------------------------------------------ */

.viz--empty{
  display:grid;
  place-items:center;
  min-height:140px;
  border:1px dashed var(--line);
  border-radius:var(--r-chip-lg);
  color:var(--text-3);
  font-size:var(--fs-sm);
}
.viz--loading{ min-height:140px; }
