/* KB Field Report — light, print-neutral, one accent.
   Deliberately no dark theme: this is read in meetings, projected, and
   exported to slides, where a dark surface is the odd one out. */

*, *::before, *::after { box-sizing: border-box; }
html { color-scheme: light; }
body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Khmer", sans-serif;
  font-size: 14px;
  /* 1.62, not 1.5: most labels here are Khmer, whose stacked vowel signs and
     subscript consonants need vertical room a Latin-tuned leading denies them. */
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

:root {
  /* Neutrals carry a faint warm cast rather than the default blue-grey: this is
     read off a projector in a meeting room, where a cool ground goes flat and
     grey-blue chrome competes with the blue data marks. */
  --page:      #f5f4f1;
  --surface:   #ffffff;
  --ink:       #1a1a17;
  --ink-2:     #56564f;
  --ink-3:     #85857c;
  --line:      #e7e5e0;
  --line-2:    #d0cec7;

  /* Two blues doing two different jobs. Before, one token painted both the bars
     and every button, so "this is a quantity" and "this is a control" looked
     identical. --data is recessive and never interactive; --accent is only ever
     interactive; a mark you are pointing at borrows --accent to connect them. */
  --data:      #4c6d9a;
  --accent:    #1b4fa8;
  --accent-sf: #eaf0fa;

  /* Reserved for state, never for a series. --warn moved #b4451f -> #c2410c:
     against --ok the old pair separated by only deutan dE 7.6, below the 8
     floor, and the outlet map encodes Closed/Pending in colour. The new pair
     clears at 8.7, and the map now also differs in shape. */
  --ok:        #1e7a4d;
  --warn:      #c2410c;
  --amber:     #c77700;
  --amber-lt:  #f0c27a;

  /* Sequential ramp for the Overview map: one hue, light to dark, verified
     monotonic (rel. luminance .811 -> .058). Red because this map encodes
     PROBLEM DENSITY, not a neutral quantity - "more here" and "worse here" are
     the same statement, so the ramp should say it. Distinct in job from the
     reserved status colours: those mark a state, this measures a magnitude. */
  --seq-1: #fce4d8; --seq-2: #f8c0a2; --seq-3: #f0946a;
  --seq-4: #dd6434; --seq-5: #b93d0e; --seq-6: #7d2707;

  /* Reserved for real fixed-identity categories only (Modern Trade / Traditional
     / HORECA today) - not decoration. Assigned in this order, never cycled or
     picked per-chart: most bars here are open-ended RANKINGS (65 possible
     dealers, an unbounded issue list), and colouring an open-ended ranking by
     hue implies each bar is a different kind of thing, which is false - they
     differ only in size. A ranking earns emphasis by RANK (see .hb.rank0
     below), a fixed small category earns a colour. */
  --cat-1: #4a3aa7;
  --cat-2: #c23b74;

  /* One deeper step of --data itself, for the #1 row in a ranking (rank0
     below) - NOT red. Red already means "problem" on the map and heatmap;
     reusing it on every top-ranked bar (including neutral ones, like the
     reporter who filed the most recaps) would silently claim "this is bad"
     on charts where the top item isn't bad at all. */
  --data-deep: #264061;

  --radius: 8px;
  --shadow: 0 1px 2px rgba(26, 26, 23, .05);
}

.wrap { max-width: 1400px; margin: 0 auto; padding: 0 20px 64px; }

/* ------------------------------------------------------------------ head */
.topbar { background: var(--surface); border-bottom: 1px solid var(--line); }
.topbar .wrap { padding-top: 18px; padding-bottom: 0; }
.brand { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.brand h1 { font-size: 19px; font-weight: 640; margin: 0; letter-spacing: -.01em; }
.brand .meta { font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

.tabs { display: flex; gap: 4px; margin-top: 16px; }
.tab {
  appearance: none; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 13.5px; font-weight: 550; color: var(--ink-2);
  padding: 9px 14px; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tab:hover { color: var(--ink); }
.tab[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }
.tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 4px 4px 0 0; }

/* ----------------------------------------------------------- step blocks */
/* Explore reads top to bottom as the order you actually work in:
   filter -> search -> choose columns -> read -> export. */
.step { margin-bottom: 14px; }
.step-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.step-head h2 { font-size: 13px; font-weight: 650; margin: 0; letter-spacing: .01em; }
.step-head .hint { font-size: 12px; color: var(--ink-3); }
.step-head .spacer { margin-left: auto; }

.panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px 16px;
}

/* --------------------------------------------------------------- filters */
.filter-grid {
  display: grid; gap: 10px 12px;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
}
.fgroup { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.fgroup label {
  font-size: 11px; font-weight: 600; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: .045em;
}
.fgroup select, .fgroup input {
  font: inherit; font-size: 13px; padding: 7px 9px; min-height: 36px;
  width: 100%; min-width: 0; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-2); border-radius: 6px;
}
.fgroup select { cursor: pointer; }
.fgroup select:focus-visible, .fgroup input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent);
}
.filter-foot {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--ink-2); flex-wrap: wrap;
}
.filter-foot .spacer { margin-left: auto; }

.quickdates { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }

/* Three states, three jobs: at rest a button should read as clickable without
   shouting; on hover it previews the one interactive colour so the preview is
   consistent everywhere in the app; when aria-pressed is true it is SOLID -
   a quick-date pill or category chip sits in a row of identical siblings, and
   "which one is on" has to be readable at a glance, not by squinting at a
   faint tint. Previously every state but hover was colourless. */
.btn {
  appearance: none; font: inherit; font-size: 13px; font-weight: 550;
  padding: 8px 14px; min-height: 36px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--page); color: var(--ink-2);
  transition: background-color .12s, border-color .12s, color .12s;
}
.btn:hover { background: var(--accent-sf); border-color: var(--accent); color: var(--accent); }
.btn:active { background: var(--accent-sf); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: #163f87; border-color: #163f87; color: #fff; }
.btn-sm { font-size: 12.5px; padding: 5px 11px; min-height: 30px; }
.btn[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 650;
}
.btn[aria-pressed="true"]:hover { background: #163f87; border-color: #163f87; }

/* ----------------------------------------------------------------- tiles */
.tiles {
  display: grid; gap: 12px; margin-bottom: 16px;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
}
.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px 16px;
}
.tile .k {
  font-size: 11px; font-weight: 600; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: .045em;
}
.tile .v {
  font-size: 30px; font-weight: 650; line-height: 1.1; margin-top: 6px;
  letter-spacing: -.025em; font-variant-numeric: tabular-nums;
}
.tile .sub { font-size: 12px; color: var(--ink-2); margin-top: 2px; }

/* ------------------------------------------------ outlet weekly report */
.rkpis { display: grid; gap: 10px; margin-bottom: 10px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.rkpi {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 12px 14px; text-align: center;
}
.rkpi .v { font-size: 26px; font-weight: 650; line-height: 1.1; font-variant-numeric: tabular-nums; }
.rkpi .k { font-size: 11.5px; color: var(--ink-2); margin-top: 3px; }
.rdelta { display: block; font-size: 11.5px; font-weight: 600; margin-top: 4px; }
.rdelta.good { color: var(--ok); }
.rdelta.bad  { color: var(--warn); }
.rdelta.flat { color: var(--ink-3); font-weight: 500; }

.late-amber { color: var(--amber); }
.late-bad   { color: var(--warn); }
.late-flat  { color: var(--ink-3); }

table.rtable { font-size: 12.5px; }
table.rtable th.n, table.rtable td.n { text-align: right; }
table.rtable td.reg { font-weight: 650; }
table.rtable tbody.static tr { cursor: default; }
table.rtable tbody.static tr:hover td { background: none; }
table.rtable tbody tr.hi td { background: var(--accent-sf); font-weight: 600; }
table.rtable td.barcell { display: flex; align-items: center; gap: 8px; }

/* heatmap — plain tint by default; upgraded to a real gradient where the
   browser supports color-mix() so it degrades gracefully rather than breaking.
   .heat-cell (not td-scoped) so the same rule can double as a legend swatch.
   Red, not accent-blue: this is problem DENSITY (share of a region's open
   issues), same language as the Overview map's red ramp - once a reader
   learns "red = trouble" here, it means the same thing everywhere.
   The mix is capped at 64% of the way to --seq-6, not the full 100%: at true
   full-red, dark ink text drops to 1.8:1 contrast (unreadable), which is why
   this used to switch to white past a threshold - but a reader compared a
   white "100%" against black everywhere else and read it as a different,
   inconsistent style, not "this one cell is worse". Capping the darkness
   keeps every cell legible in ONE colour instead - same text colour
   throughout, gradient still reads correctly (a capped dark red is still the
   darkest mark on the table), just no cell ever gets dark enough to need
   white. See scripts/validate_palette.js-style contrast math in
   renderOutletHeatmap's history for how 64% was picked (>=4.5:1 at 100%). */
th.heat-region, td.heat-cell {
  text-align: center; font-variant-numeric: tabular-nums; font-weight: 600;
}
.heat-cell { background: var(--seq-2); color: var(--ink); }
@supports (background: color-mix(in srgb, red, blue)) {
  .heat-cell { background: color-mix(in srgb, var(--seq-6) calc(var(--pct, 0) * 0.64%), var(--surface)); color: var(--ink); }
}
td.heat-cell, th.heat-region { cursor: pointer; }
td.heat-cell:hover, th.heat-region:hover { outline: 2px solid var(--seq-5); outline-offset: -2px; }
.pbar-wrap { flex: 1; min-width: 60px; height: 8px; background: var(--line); border-radius: 4px; overflow: hidden; }
.pbar-wrap .pbar { height: 100%; background: var(--warn); border-radius: 4px; }
.pbar-pct { font-size: 11.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ----------------------------------------------------------------- cards */
.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); margin-bottom: 14px; }
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 16px 18px 14px; min-width: 0;
}
.card.wide { grid-column: 1 / -1; }
.card h2 { font-size: 14px; font-weight: 650; margin: 0 0 2px; letter-spacing: -.005em; }
.card .cap { font-size: 12px; color: var(--ink-2); margin: 0 0 14px; }
.card .note { font-size: 11.5px; color: var(--ink-3); margin-top: 10px; }
.scroll { overflow-x: auto; }

svg { display: block; max-width: 100%; }
.gridline { stroke: var(--line); stroke-width: 1; }
.gridline:first-of-type { stroke: var(--line-2); }
.axisline { stroke: var(--line-2); stroke-width: 1; }
.tick { fill: var(--ink-3); font-size: 11px; font-variant-numeric: tabular-nums; }
.barlabel { fill: var(--ink-2); font-size: 11px; font-variant-numeric: tabular-nums; }
.catlabel { fill: var(--ink); font-size: 12.5px; }
/* Chart marks are recessive by default and borrow the interactive colour only
   under the pointer, so hover reads as "you are here" rather than decoration. */
.hb, .bar-m { fill: var(--data); transition: fill .12s, opacity .12s; }
.hb.on, .bar-m.on { fill: var(--accent); }
/* The #1 row in a ranking (opts.rankTop) gets the deep end of the same hue,
   not a different one - "this is the biggest bar" is still a magnitude
   statement, so it stays in the same colour family and just goes darker,
   the way a headline is the same typeface as the body, only bolder. */
.hb.rank0 { fill: var(--data-deep); }
.hb.rank0.on { fill: var(--accent); }
.barlabel.rank0 { fill: var(--ink); font-weight: 700; }
/* Small fixed categories (channel today) - assigned, not decorative. */
.hb.cat-1 { fill: var(--cat-1); }
.hb.cat-2 { fill: var(--cat-2); }
.hb.cat-1.on, .hb.cat-2.on { filter: brightness(1.12); }
/* New vs Fixed, monthly - the map's own vocabulary (see .heat-cell block
   above), not a new pair: warn = arriving/pending, ok = resolved. */
.hb.warn { fill: var(--warn); }
.hb.ok { fill: var(--ok); }
.hit { fill: transparent; cursor: default; }
.hit.clickable { cursor: pointer; }
.mark { transition: opacity .12s; }
.dim { opacity: .32; }
.province { stroke-linejoin: round; }

.ramp { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink-3); margin-top: 10px; }
.ramp i { width: 22px; height: 9px; border-radius: 2px; display: inline-block; }

/* ------------------------------------------------------- donut + legend */
.donut-total { fill: var(--ink); font-size: 26px; font-weight: 640; font-variant-numeric: tabular-nums; }
.donut-sub   { fill: var(--ink-3); font-size: 11.5px; }
.seg { transition: opacity .12s; }

/* Text keeps ink tokens; the swatch beside it carries the identity.
   Capped to the donut's own width and centred under it — left to fill the
   card, the value ends up hundreds of px from the label it belongs to. */
.legend { margin: 12px auto 0; max-width: 320px; display: flex; flex-direction: column; gap: 5px; }
.legend .lg-row { display: flex; align-items: center; gap: 10px; font-size: 12.5px; flex-wrap: wrap; }
.legend .lg-key { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; color: var(--ink); }
.legend .lg-key i { width: 11px; height: 11px; border-radius: 2px; display: inline-block; }
.legend .lg-key i:first-of-type { margin-right: 1px; }
.legend .lg-val { color: var(--ink-2); font-variant-numeric: tabular-nums; margin-left: auto; }

/* ------------------------------------------------------------- map zoom */
.mapbar { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }
.mapbar .hint { margin-left: 4px; }
svg.omap { cursor: grab; touch-action: none; }
svg.omap.grabbing { cursor: grabbing; }

/* --------------------------------------------------------------- tooltip */
#tip {
  position: fixed; pointer-events: none; z-index: 90; opacity: 0;
  transition: opacity .1s; max-width: 320px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-2); border-radius: 7px;
  box-shadow: 0 8px 24px rgba(20, 24, 31, .14);
  padding: 9px 11px; font-size: 12px; line-height: 1.6;
}
#tip b { font-weight: 620; }
#tip .t-sub { color: var(--ink-2); }

/* ------------------------------------------------------- column manager */
.colmgr { display: grid; grid-template-columns: 1fr 1.15fr; gap: 14px; }
.colcol { min-width: 0; }
.colcol h3 {
  font-size: 11px; font-weight: 650; color: var(--ink-3); margin: 0 0 7px;
  text-transform: uppercase; letter-spacing: .045em;
}
.colbox {
  border: 1px solid var(--line); border-radius: 7px; padding: 8px;
  min-height: 96px; max-height: 210px; overflow: auto; background: #fbfbfc;
}
.colbox.drop-active { border-color: var(--accent); background: var(--accent-sf); }
.colgroup-label {
  font-size: 10.5px; font-weight: 650; color: var(--ink-3); letter-spacing: .04em;
  text-transform: uppercase; margin: 6px 2px 4px;
}
.colgroup-label:first-child { margin-top: 0; }

.chip {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12.5px; padding: 5px 10px; margin: 0 4px 4px 0; border-radius: 6px;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink-2);
  user-select: none;
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.chip .plus { color: var(--ink-3); font-weight: 600; }
.chip:hover .plus { color: var(--accent); }

.selchip {
  display: flex; align-items: center; gap: 8px; width: 100%;
  font-size: 12.5px; padding: 6px 8px; margin-bottom: 4px; border-radius: 6px;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink);
  cursor: grab; user-select: none;
}
.selchip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.selchip.dragging { opacity: .4; }
.selchip.drop-before { box-shadow: 0 -2px 0 0 var(--accent); }
.selchip.drop-after  { box-shadow: 0  2px 0 0 var(--accent); }
.selchip .grip { color: var(--line-2); letter-spacing: -2px; cursor: grab; }
.selchip .ord {
  font-size: 10.5px; font-variant-numeric: tabular-nums; color: var(--ink-3);
  min-width: 15px; text-align: right;
}
.selchip .nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.selchip .x {
  appearance: none; border: 0; background: none; cursor: pointer; color: var(--ink-3);
  font-size: 15px; line-height: 1; padding: 2px 4px; border-radius: 4px;
}
.selchip .x:hover { color: var(--warn); background: #fdf0eb; }

/* ----------------------------------------------------------------- table */
.tablewrap {
  overflow: auto; max-height: 640px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
}
table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 12.5px; }
thead th {
  position: sticky; top: 0; z-index: 1; text-align: left; white-space: nowrap;
  background: #fafbfc; color: var(--ink-2);
  font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: .04em;
  padding: 9px 12px; border-bottom: 1px solid var(--line-2); cursor: pointer;
  user-select: none;
}
thead th:hover { color: var(--ink); }
thead th .arrow { color: var(--accent); font-size: 10px; }
tbody td { padding: 9px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr { cursor: pointer; }
tbody tr:hover td { background: #fafbfc; }
td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
td.text-cell { min-width: 220px; }
td.long-cell { min-width: 280px; max-width: 460px; color: var(--ink-2); }
.nonote { color: var(--ink-3); font-style: italic; }
.empty { padding: 40px; text-align: center; color: var(--ink-3); }

.prio { display: inline-block; white-space: nowrap; font-size: 11.5px;
        padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line-2); color: var(--ink-2); }
.prio.p3 { border-color: var(--warn); color: var(--warn); font-weight: 600; }
.prio.p2 { border-color: var(--line-2); color: var(--ink); }
.pill { display: inline-block; font-size: 11.5px; padding: 2px 8px; border-radius: 999px;
        border: 1px solid var(--line-2); color: var(--ink-2); white-space: nowrap; }
.pill.pending { border-color: var(--warn); color: var(--warn); }
.pill.closed  { border-color: var(--line-2); color: var(--ok); }

/* ------------------------------------------------------------ pagination */
.pager { display: flex; align-items: center; gap: 10px; margin-top: 12px; flex-wrap: wrap;
         font-size: 12.5px; color: var(--ink-2); }
.pager .spacer { margin-left: auto; }
.pager select { font: inherit; font-size: 12.5px; padding: 5px 8px; border-radius: 6px;
                border: 1px solid var(--line-2); background: var(--surface); color: var(--ink); }

/* ----------------------------------------------------------- detail pane */
.drawer-back {
  position: fixed; inset: 0; background: rgba(20, 24, 31, .3); z-index: 100;
  opacity: 0; pointer-events: none; transition: opacity .15s;
}
.drawer-back.open { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(520px, 94vw); z-index: 101;
  background: var(--surface); border-left: 1px solid var(--line);
  box-shadow: -8px 0 28px rgba(20, 24, 31, .12);
  transform: translateX(100%); transition: transform .18s ease-out;
  display: flex; flex-direction: column;
}
.drawer.open { transform: none; }
.drawer-head {
  display: flex; align-items: center; gap: 12px; padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.drawer-head h3 { font-size: 14px; font-weight: 640; margin: 0; flex: 1; }
.drawer-body { padding: 16px 18px 28px; overflow: auto; }
.drawer dl { margin: 0; display: grid; grid-template-columns: 128px 1fr; gap: 9px 14px; }
.drawer dt { font-size: 11px; font-weight: 600; color: var(--ink-3);
             text-transform: uppercase; letter-spacing: .04em; padding-top: 2px; }
.drawer dd { margin: 0; font-size: 13px; word-break: break-word; }
.drawer .orig-block {
  margin-top: 16px; padding: 12px 14px; background: #fafbfc;
  border: 1px solid var(--line); border-radius: 7px;
  white-space: pre-wrap; font-size: 13px; line-height: 1.6;
}
.drawer .orig-label { font-size: 11px; font-weight: 600; color: var(--ink-3);
                      text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px; }

footer.ft { margin-top: 24px; font-size: 12px; color: var(--ink-3); line-height: 1.65; }
footer.ft b { color: var(--ink-2); font-weight: 600; }
footer.ft code { font-size: 11.5px; background: #eef0f3; padding: 1px 5px; border-radius: 4px; }

.hidden { display: none !important; }
.hint { font-size: 12px; color: var(--ink-3); }

@media (max-width: 860px) {
  .colmgr { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .wrap { padding: 0 12px 40px; }
  .grid { grid-template-columns: 1fr; }
  .filter-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .drawer dl { grid-template-columns: 1fr; gap: 3px 0; }
  .drawer dd { margin-bottom: 8px; }
}

/* ==========================================================================
   Responsive, motion and mobile patterns
   ========================================================================== */

/* Every animation below is opt-out. A data tool that ignores this setting
   is unusable for anyone with vestibular sensitivity. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
}

/* -------------------------------------------------------------- motion */
@keyframes fadeUp   { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes growX    { from { transform: scaleX(0); }  to { transform: scaleX(1); } }
@keyframes growY    { from { transform: scaleY(0); }  to { transform: scaleY(1); } }
@keyframes popIn    { from { opacity: 0; transform: scale(.9); } to { opacity: 1; transform: none; } }
@keyframes shimmer  { from { background-position: -420px 0; } to { background-position: 420px 0; } }

.anim-in { animation: fadeUp .22s ease-out both; }
.bar-h { transform-origin: left center; animation: growX .32s cubic-bezier(.22,.7,.3,1) both; }
.bar-v { transform-origin: center bottom; animation: growY .32s cubic-bezier(.22,.7,.3,1) both; }
.pt-in { animation: popIn .3s ease-out both; }

.tile { transition: border-color .15s, box-shadow .15s; }
.tile:hover { border-color: var(--line-2); }
.tile .v { font-variant-numeric: tabular-nums; }

.delta { font-size: 12px; font-weight: 600; margin-left: 6px; white-space: nowrap; }
.delta.up   { color: var(--warn); }   /* more issues is not good news */
.delta.down { color: var(--ok); }
.delta.flat { color: var(--ink-3); font-weight: 500; }

/* clickable marks ---------------------------------------------------- */
.mark.clickable { cursor: pointer; }
.chart-hint { font-size: 11.5px; color: var(--ink-3); margin-top: 8px; }

/* crumbs ------------------------------------------------------------- */
.crumbs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; font-size: 12.5px; }
.crumb {
  appearance: none; font: inherit; font-size: 12.5px; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink-2);
  padding: 4px 10px; border-radius: 999px;
}
.crumb:hover { border-color: var(--accent); color: var(--accent); }
.crumb[aria-current="true"] { background: var(--accent-sf); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.crumb-sep { color: var(--ink-3); }

/* skeleton ----------------------------------------------------------- */
.skel {
  background: linear-gradient(90deg, #eceae5 25%, #f6f5f2 50%, #eceae5 75%);
  background-size: 420px 100%; animation: shimmer 1.1s linear infinite;
  border-radius: 6px; height: 13px; margin: 0 0 9px;
}
.skel.row { height: 34px; margin-bottom: 6px; }

/* toasts ------------------------------------------------------------- */
.toasts {
  position: fixed; z-index: 200; right: 18px; bottom: 18px;
  display: flex; flex-direction: column; gap: 8px; pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: 9px;
  background: var(--ink); color: #fff; border-radius: 8px;
  padding: 10px 14px; font-size: 13px; box-shadow: 0 8px 24px rgba(20,24,31,.22);
  animation: fadeUp .18s ease-out both; max-width: min(420px, 92vw);
}
.toast.err { background: var(--warn); }
.toast .ic { font-weight: 700; }

/* ------------------------------------------------- mobile filter sheet */
.sheet-trigger { display: none; }
.sheet-back {
  position: fixed; inset: 0; background: rgba(20,24,31,.34); z-index: 110;
  opacity: 0; pointer-events: none; transition: opacity .16s;
}
.sheet-back.open { opacity: 1; pointer-events: auto; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 111;
  background: var(--surface); border-radius: 16px 16px 0 0;
  max-height: 88vh; display: flex; flex-direction: column;
  transform: translateY(100%); transition: transform .2s cubic-bezier(.22,.7,.3,1);
  box-shadow: 0 -8px 28px rgba(20,24,31,.16);
}
.sheet.open { transform: none; }
.sheet-head {
  display: flex; align-items: center; gap: 12px;
  padding: 4px 18px 14px; border-bottom: 1px solid var(--line);
}
.sheet-head h3 { font-size: 15px; font-weight: 640; margin: 0; flex: 1; }
.sheet-grab { width: 38px; height: 4px; border-radius: 2px; background: var(--line-2); margin: 8px auto 6px; }
.sheet-body { padding: 14px 18px; overflow: auto; -webkit-overflow-scrolling: touch; }
.sheet-foot {
  padding: 12px 18px calc(12px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); display: flex; gap: 10px;
}
.sheet-foot .btn { flex: 1; min-height: 46px; }

/* --------------------------------------------------- mobile card list */
.cardlist { display: none; }
.icard {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; margin-bottom: 8px; box-shadow: var(--shadow);
  animation: fadeUp .18s ease-out both;
}
.icard:active { background: #fafbfc; }
.icard .top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.icard .date { font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.icard .place { font-size: 12px; color: var(--ink-2); }
.icard .std { font-size: 13.5px; font-weight: 550; line-height: 1.45; }
.icard .foot { margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap; }

/* ------------------------------------------------- column reorder btns */
/* HTML5 drag never fires on touch, so ordering has to work without it.
   These buttons are the mechanism; dragging is a desktop convenience. */
.selchip .moves { display: flex; gap: 2px; }
.selchip .mv {
  appearance: none; border: 1px solid var(--line-2); background: var(--surface);
  color: var(--ink-2); cursor: pointer; border-radius: 5px;
  width: 26px; height: 26px; line-height: 1; font-size: 12px; padding: 0;
}
.selchip .mv:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.selchip .mv:disabled { opacity: .35; cursor: default; }

/* ============================================================== tablet */
@media (max-width: 1024px) {
  .grid { grid-template-columns: 1fr; }
  .wrap { padding: 0 16px 56px; }
}

/* ============================================================== mobile */
@media (max-width: 720px) {
  body { font-size: 15px; }
  .wrap { padding: 0 12px 84px; }

  .brand h1 { font-size: 17px; }
  .tab { padding: 12px 14px; font-size: 14px; min-height: 46px; }

  /* filters collapse behind one full-width control. Scoped to the panel's
     INLINE position: the same node is moved into the sheet, and an
     unscoped rule would hide it there too - opening an empty sheet. */
  .sheet-trigger { display: flex; width: 100%; justify-content: space-between; align-items: center; min-height: 46px; }
  #filterStep > #filterPanel { display: none; }
  #filterStep > .step-head #moreFilters,
  #filterStep > .step-head #reset { display: none; }
  .step-head .btn { min-height: 42px; }

  .tiles { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .tile { padding: 12px 13px; }
  .tile .v { font-size: 22px; }
  .tile .k { font-size: 10.5px; }

  .card { padding: 14px 14px 12px; }

  /* the table becomes a card list - 7 columns at 375px is unreadable */
  .tablewrap { display: none; }
  .cardlist { display: block; }
  .pager { gap: 8px; }
  .pager .btn { flex: 1; min-height: 44px; }
  .pager select { min-height: 44px; }

  .colmgr { grid-template-columns: 1fr; gap: 12px; }
  .colbox { max-height: 190px; }
  .chip { padding: 9px 13px; font-size: 13.5px; }
  .selchip { padding: 9px 10px; }
  .selchip .mv { width: 34px; height: 34px; font-size: 14px; }
  .selchip .grip { display: none; }

  .btn { min-height: 44px; }
  .btn-sm { min-height: 40px; padding: 8px 13px; }
  .fgroup select, .fgroup input { min-height: 46px; font-size: 15px; }

  .drawer { width: 100%; border-left: 0; border-radius: 16px 16px 0 0; top: 8vh; }
  .toasts { right: 12px; left: 12px; bottom: 12px; }
  .toast { max-width: none; }
}

/* =============================================================== print */
@media print {
  .topbar .tabs, #filterStep, .pager, .toasts,
  .sheet, .sheet-back, .drawer, .drawer-back { display: none !important; }
  body { background: #fff; }
  .card, .tile, .panel { box-shadow: none; border-color: #ccc; break-inside: avoid; }
  .grid { grid-template-columns: 1fr 1fr; }
  .tablewrap { max-height: none; overflow: visible; }
}

/* "Show all N" under the geographic drill — the top-12 cap used to hide the
   remainder with no sign it was doing so. */
.geo-more { margin-top: 10px; }

/* An auto-filled drill level: shown for orientation, but it was never a choice
   the reader made, so it must not look clickable. */
.crumb.auto {
  border-style: dashed;
  opacity: .72;
  cursor: default;
}

/* ---- jump-to-a-place search (geographic drill) ----
   Village names repeat across the country, so every result shows its full
   trail; the trail is what disambiguates and what gets applied on select. */
.geo-search { position: relative; margin-bottom: 12px; max-width: 460px; }
.geo-search input {
  font: inherit; font-size: 13px; padding: 8px 11px; min-height: 38px;
  width: 100%; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-2); border-radius: 6px;
}
.geo-search input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent);
}
.geo-results {
  position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--surface); border: 1px solid var(--line-2); border-radius: 8px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .16); overflow: hidden; max-height: 340px;
  overflow-y: auto;
}
.geo-hit {
  display: grid; grid-template-columns: 1fr auto; gap: 1px 10px;
  width: 100%; text-align: left; padding: 8px 11px; cursor: pointer;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  font: inherit; color: var(--ink);
}
.geo-hit:last-child { border-bottom: 0; }
.geo-hit.active, .geo-hit:hover { background: var(--accent-sf); }
/* Columns are pinned explicitly: .gh-n carries a definite grid-row, and grid
   places definite-row items before auto ones, which otherwise dropped the
   count into column 1 and pushed the name across to the right. */
.gh-top { grid-column: 1; grid-row: 1; display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.gh-name { font-size: 13.5px; font-weight: 600; }
.gh-lvl {
  font-size: 10px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); flex: none;
}
.gh-trail {
  grid-column: 1; grid-row: 2; font-size: 11.5px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gh-n {
  grid-column: 2; grid-row: 1 / span 2; align-self: center; text-align: right;
  font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
@media (max-width: 720px) {
  .geo-search { max-width: none; }
  .geo-search input { min-height: 44px; font-size: 15px; }
}

/* Legend keys mirror the marks: Pending is solid, Closed is a ring — the same
   secondary encoding the map uses, so the key teaches the shape. */
/* .ramp i sets a 22x9 swatch for the sequential ramp; these keys sit in the
   same container but describe round marks, so they must out-specify it. */
.ramp i.key-dot {
  width: 11px; height: 11px; border-radius: 50%; display: inline-block; flex: none;
}
.ramp i.key-dot.pending { background: var(--warn); }
.ramp i.key-dot.closed  { background: none; border: 2px solid var(--ok); }

/* ---- product movement: ours vs competitors ----
   Two panels inside one card, deliberately not two separate cards: they share a
   category and a fixed 0-10 axis, and the whole point is reading across them. */
.prod-cats { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.prod-grid { display: grid; gap: 22px; grid-template-columns: minmax(240px, 300px) 1fr; align-items: start; }
.prod-pair { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.prod-share .legend { max-width: none; margin-top: 10px; }
@media (max-width: 900px) { .prod-grid { grid-template-columns: 1fr; } }
.pair-h {
  font-size: 12px; font-weight: 650; margin: 0 0 8px; color: var(--ink);
  display: flex; align-items: baseline; gap: 8px;
}
.pair-h span { font-size: 11px; font-weight: 500; color: var(--ink-3); }
