/* The briefing. Header strip, three sections, cards with collapsible depth.
 *
 * NO HEX CODES IN THIS FILE. Every colour is a token from tokens.css, which is the only file
 * allowed to name one — the same rule dash.css and admin.css follow.
 *
 * THE CONTAINMENT RULE, APPLIED TO A FOURTH PAGE. admin.css carries neither a brand hue nor a
 * band hue. This page carries BAND HUES ONLY, and brand is always a word — never a swatch, never
 * a fill. That is forced rather than chosen: the most valuable thing this page can say is
 * "Keune promoters keep naming scent", which is a brand hue and a band hue in one card, and
 * tokens.css records that there is no third green to separate them with.
 *
 * The three sections ARE band definitions, so the hue they wear is earned rather than decorative:
 *   Amplify = where promoters concentrate     --band-promoter
 *   Fix     = where detractors concentrate    --band-detractor
 *   Watch   = below MIN_N, nothing to act on  --band-passive
 * It is worn as a rule and an eyebrow, never as a fill behind text.
 *
 * WARNING, from tokens.css: light-mode --band-promoter is 2.33:1 against its surface, under the
 * 3:1 mark floor. That makes a direct text label an OBLIGATION, not a nicety. Every section
 * carries the literal word AMPLIFY / FIX / WATCH for exactly this reason. Reducing a section
 * heading to a coloured dot breaks an accessibility guarantee, not a preference.
 */

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--dash-bg);
  color: var(--dash-ink);
  font-family: var(--dash-font);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/* Figures that sit under one another must not dance as the filter changes. */
.stat-value, .card-fig, .bar-n, .card-n, .tick { font-variant-numeric: tabular-nums; }

button { font: inherit; color: inherit; }

/* One visible focus treatment for the whole page. Never remove it — a keyboard user who cannot
   see where they are has no way back. This page leans on <details>, so the focus ring on a
   <summary> is the only thing telling somebody which disclosure Enter will open. */
:focus-visible {
  outline: 2px solid var(--dash-accent);
  outline-offset: 2px;
  border-radius: 3px;
}

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

#insights {
  display: grid;
  grid-template-rows: auto 1fr;
  min-height: 100%;
}

.work {
  min-width: 0;
  padding: 20px 18px 64px;
  margin: 0 auto;
  width: 100%;
  /* A briefing is read, not scanned across a wall. Past roughly this width the headline
     sentences turn into single lines of forty words and the eye loses the start of the next. */
  max-width: 1320px;
}

/* ---------------------------------------------------------------- top bar
 *
 * Duplicated from dash.css rather than shared. There is no css/console.css, so admin.css already
 * holds a second copy of these rules and this is the third. Extracting the shared chrome is the
 * right fix and is deliberately not done here: it would edit two working pages for no gain in a
 * throwaway proposal artefact. Recorded so it stays a decision rather than an accident.
 */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--dash-line);
  background: var(--dash-panel);
  flex-wrap: wrap;
}

.bar-title { margin: 0; font-size: 14px; font-weight: 600; letter-spacing: .01em; }
.bar-sub { margin: 0; font-size: 12px; color: var(--dash-ink-3); }
.bar-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

.bar-nav { display: inline-flex; gap: 10px; }
.bar-nav a {
  font-size: 11.5px;
  color: var(--dash-ink-3);
  text-decoration: none;
  border-bottom: 1px solid var(--dash-line);
}
.bar-nav a:hover { color: var(--dash-accent); border-bottom-color: var(--dash-accent); }

.themetoggle, .langpick {
  display: inline-flex;
  border: 1px solid var(--dash-line);
  border-radius: 7px;
  overflow: hidden;
  background: var(--dash-bg);
}
.themetoggle button, .lang-btn {
  border: 0; background: transparent; cursor: pointer;
  padding: 6px 9px; display: grid; place-items: center;
  color: var(--dash-ink-3);
}
.lang-btn { font-size: 11px; font-weight: 600; letter-spacing: .04em; }
.themetoggle svg { width: 15px; height: 15px; display: block; }
.themetoggle button[aria-pressed="true"], .lang-btn[aria-pressed="true"] {
  background: var(--dash-accent); color: var(--dash-accent-ink);
}

/* ---------------------------------------------------------------- filters
 *
 * Two controls, in the bar rather than in a rail. There is NO BAND FILTER here, and its absence
 * is structural: measurement rule 8 says a band filter must never reach a computed figure, and on
 * this page every figure is inside a claim. The sections are the bands instead.
 */

.filters { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.filter { display: flex; align-items: center; gap: 7px; }
.filter-label {
  font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dash-ink-3);
}

.seg { display: flex; gap: 4px; }
.seg-btn {
  padding: 5px 9px; cursor: pointer;
  border: 1px solid var(--dash-line); border-radius: 6px;
  background: var(--dash-bg); color: var(--dash-ink-2);
  font-size: 11.5px; white-space: nowrap;
}
.seg-btn:hover { border-color: var(--dash-ink-3); }
.seg-btn[aria-pressed="true"] {
  background: var(--dash-accent); border-color: var(--dash-accent);
  color: var(--dash-accent-ink); font-weight: 600;
}

/* ---------------------------------------------------------------- the header strip */

.strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px;
  background: var(--dash-line);
  border: 1px solid var(--dash-line);
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 14px;
}

.stat { background: var(--dash-panel); padding: 13px 15px; min-width: 0; }
.stat-label {
  margin: 0 0 5px;
  font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dash-ink-3);
}
.stat-value {
  margin: 0;
  font-size: 27px; font-weight: 300; line-height: 1.1;
  letter-spacing: -.02em;
}
.stat-value--sm { font-size: 17px; font-weight: 500; letter-spacing: 0; }
.stat-note { margin: 5px 0 0; font-size: 11px; color: var(--dash-ink-3); line-height: 1.35; }

/* The incentive caveat is not a footnote here. Rule 6: every surface showing an NPS says it is
   incentivised, and this is the surface most likely to be photographed and pasted into a slide. */
.stat-note--warn { color: var(--dash-warn); }

/* ---------------------------------------------------------------- the scaffolding notice
 *
 * Unbranded and set apart, in the same family as the questionnaire's demo bar and the funnel
 * panel's "invented" footer. A reader must not be able to mistake hand-written prose for
 * generated analysis, and the page is far more persuasive when it says so itself.
 */

.notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 14px;
  border: 1px dashed var(--dash-warn);
  border-radius: 8px;
  color: var(--dash-ink-2);
  font-size: 12px; line-height: 1.5;
  margin-bottom: 26px;
}
.notice svg { width: 15px; height: 15px; flex: 0 0 auto; margin-top: 1px; color: var(--dash-warn); }

/* ---------------------------------------------------------------- sections */

.sec { margin-bottom: 30px; }
.sec:last-child { margin-bottom: 0; }

.sec-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 0 0 9px 11px;
  border-left: 3px solid var(--sec-hue);
  margin-bottom: 13px;
}
.sec-glyph { color: var(--sec-hue); display: block; width: 13px; height: 13px; align-self: center; }
.sec-title {
  margin: 0;
  font-size: 12px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: var(--sec-hue);
}
.sec-sub { margin: 0; font-size: 12px; color: var(--dash-ink-3); }
.sec-count { margin-left: auto; font-size: 11px; color: var(--dash-ink-3); }

.sec--amplify { --sec-hue: var(--band-promoter); }
.sec--fix     { --sec-hue: var(--band-detractor); }
.sec--watch   { --sec-hue: var(--band-passive); }

/* ---------------------------------------------------------------- the card grid */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: 13px;
  /* Stretch, not start. A card carrying five bars is much taller than one carrying a sentence,
     and letting each end where its content ends gives the row a ragged lower edge that reads as
     broken layout rather than as varying content. The footers line up instead. */
  align-items: stretch;
}

.card {
  display: flex;
  flex-direction: column;
  background: var(--dash-panel);
  border: 1px solid var(--dash-line);
  border-radius: 10px;
  padding: 15px 16px 12px;
  min-width: 0;
  box-shadow: var(--dash-shadow);
}

/* The provenance line is pushed to the bottom of whatever height the row settled on, so the
   "computed from N responses" line reads as a rule across the row rather than as nine lines at
   nine different heights. */
.card-foot { margin-top: auto; }

/* A Watch card is marked for the same reason a sub-MIN_N month is drawn hatched: the reader must
   be able to tell at a glance that the figure on it is not load-bearing, before reading a word of
   the caveat.
   The hatch is a strip along the top edge, NOT a wash behind the card. Running it behind the text
   was the first attempt and it made the one card whose whole message is "read this carefully" the
   hardest card on the page to read. A dashed border carries the same signal and costs no
   legibility. */
.card--watch { border-style: dashed; position: relative; overflow: hidden; }
.card--watch::before {
  content: "";
  position: absolute; inset: 0 0 auto; height: 3px;
  background: repeating-linear-gradient(
    45deg, var(--dash-hatch) 0 3px, transparent 3px 6px);
}

.card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 11px; }
.card-glyph { color: var(--dash-ink-3); display: block; width: 15px; height: 15px; flex: 0 0 auto; }
.card-eyebrow {
  margin: 0; min-width: 0;
  font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--dash-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.card-n {
  margin-left: auto; flex: 0 0 auto;
  padding: 1px 7px; border-radius: 999px;
  border: 1px solid var(--dash-line);
  font-size: 10px; font-weight: 600;
  color: var(--dash-ink-3);
  font-family: var(--dash-mono);
}
.card--watch .card-n { border-style: dashed; }

/* WHAT — the half that is always visible. One sentence, at a size that is read rather than
   scanned, because the whole page is an argument that a number needs a sentence around it. */
.card-what {
  margin: 0 0 12px;
  font-size: 15.5px; line-height: 1.42; font-weight: 500;
  letter-spacing: -.005em;
  color: var(--dash-ink);
}

/* Theme and channel names are stored lower-case because they are interpolated MID-sentence in the
   evidence prose ("...were about delivery"). The same string also opens the headline, where a
   lower-case first letter reads as a typo. Capitalising here rather than in the strings file
   keeps one name per concept instead of a sentence-case duplicate of every theme — and it is the
   presentation layer's problem, which is where it now lives. */
.card-what::first-letter { text-transform: capitalize; }

.card-mark { margin: 0 0 12px; }

/* CHART CHROME. charts.js emits class names and geometry and nothing else: every colour, and
   crucially every font-size, comes from the page's stylesheet. dash.css carries this block for
   the console; without it here the SVG labels fall back to the UA default of 16px and print
   straight through the bars they are meant to be labelling. Only the rules the two charts this
   page draws actually need — a copy of dash.css's chart section would bring six charts' worth. */
.chart { display: block; max-width: 100%; overflow: visible; }

/* Named .gridline, NOT .grid: a bare .grid rule would also match <line class="grid"> inside
   every SVG. Inherited verbatim from dash.css, where it was learned the hard way. */
.chart .gridline { stroke: var(--dash-grid); stroke-width: 1; }
.chart .gridline--zero { stroke: var(--dash-ink-3); stroke-width: 1; opacity: .55; }

.chart .tick { fill: var(--dash-ink-3); font-size: 9.5px; }
.chart .tick--row { text-anchor: start; fill: var(--dash-ink-2); font-size: 11px; }
.chart .tick--val { fill: var(--dash-ink-2); font-size: 10.5px; font-weight: 600; }

.chart .hit { fill: transparent; }
.chart .hit:hover { fill: var(--dash-ink); fill-opacity: .045; }

.chart-tip {
  position: fixed; top: 0; left: 0; z-index: 60;
  max-width: 260px; padding: 7px 10px;
  border: 1px solid var(--dash-line); border-radius: 7px;
  background: var(--dash-panel); color: var(--dash-ink);
  box-shadow: var(--dash-shadow);
  font-size: 11.5px; line-height: 1.45;
  pointer-events: none; opacity: 0;
  transition: opacity 100ms ease;
}
.chart-tip.is-on { opacity: 1; }
.chart-tip b { display: block; font-size: 11px; margin-bottom: 1px; }
.chart-tip span { color: var(--dash-ink-2); }

/* Proportion bars. Not a chart — the same two-layer construction dash.css uses for themes, kept
   here rather than in charts.js because charts.js knows nothing about surveys and this is card
   chrome rather than a plotted mark. */
.bars { display: grid; gap: 6px; }
.bar-row { display: grid; grid-template-columns: minmax(64px, 88px) 1fr auto; gap: 9px; align-items: center; }
.bar-label {
  font-size: 11.5px; color: var(--dash-ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* display:block on BOTH, and it is not decoration.
   These are spans. .bar-track survives without it because a grid item is blockified by the grid,
   but .bar-fill sits INSIDE the track, which is not a grid container — so it stayed inline, where
   width and height are simply ignored. Every proportion bar on the page rendered as an empty
   track with a correctly-computed width painting nothing at all, in both themes, with no error
   anywhere. Blockify the element you set a width on; do not rely on a parent to do it for you. */
.bar-track { display: block; height: 9px; border-radius: 4px; background: var(--dash-panel-2); overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 4px; background: var(--bar-hue); }
.bar-n { font-size: 11px; color: var(--dash-ink-3); min-width: 30px; text-align: right; }

.bars--promoter  { --bar-hue: var(--band-promoter); }
.bars--detractor { --bar-hue: var(--band-detractor); }
.bars--passive   { --bar-hue: var(--band-passive); }

/* No opacity ramp on the trailing bars. It was there to mark the leading bar as the one the
   headline is about, but the bars are already sorted longest-first, so it distinguished nothing
   the length had not already said — and against light-mode --band-promoter, which tokens.css
   records at 2.33:1, a 45% wash put the remaining bars somewhere below visible. Rank is carried
   by order and length; the direct labels carry identity. That is the whole job. */

/* ---------------------------------------------------------------- the disclosures
 *
 * Native <details>. Keyboard and screen-reader correct with no custom JS, and it works under
 * file:// — the same reasoning that puts real radio inputs in the questionnaire rather than
 * div-based ones.
 */

.disc { border-top: 1px solid var(--dash-line); }

.disc-sum {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 0;
  cursor: pointer;
  font-size: 12px; font-weight: 600;
  color: var(--dash-ink-2);
  list-style: none;
}
.disc-sum::-webkit-details-marker { display: none; }
.disc-sum:hover { color: var(--dash-ink); }

.disc-caret {
  width: 9px; height: 9px; flex: 0 0 auto;
  color: var(--dash-ink-3);
  transition: transform var(--t-fast) var(--ease);
}
.disc[open] .disc-caret { transform: rotate(90deg); }

.disc-body { padding: 0 0 12px; font-size: 12.5px; line-height: 1.55; color: var(--dash-ink-2); }
.disc-body > p { margin: 0 0 10px; }
.disc-body > p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- evidence and the play */

.quotes { display: grid; gap: 7px; margin: 0 0 11px; padding: 0; list-style: none; }
.quote {
  border-left: 2px solid var(--dash-line);
  padding: 2px 0 2px 10px;
  font-size: 12.5px; line-height: 1.45;
  color: var(--dash-ink);
}
.quote-meta {
  display: block; margin-top: 3px;
  font-size: 10.5px; color: var(--dash-ink-3);
  font-family: var(--dash-mono);
}

.play-label {
  margin: 0 0 5px;
  font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--dash-ink-3);
}

/* The copy line is the customer's own sentence, offered as ad copy. Set apart from the analysis
   because it is the one thing on the card that should be lifted verbatim rather than paraphrased. */
.copy {
  margin: 0 0 11px; padding: 10px 12px;
  border: 1px solid var(--dash-line); border-radius: 7px;
  background: var(--dash-panel-2);
  font-size: 13.5px; line-height: 1.45;
  color: var(--dash-ink);
}

/* The audience block. It states a SHARE and then immediately states that the share cannot become
   a list, because this survey stores no customer identifier. The two halves must stay together —
   a percentage with an implied audience and no caveat is the same class of error as an unlabelled
   invented figure, and it is the error this page is most likely to make. */
.aud {
  margin: 0 0 10px; padding: 9px 11px;
  border: 1px dashed var(--dash-warn); border-radius: 7px;
  font-size: 11.5px; line-height: 1.5;
}
.aud b { display: block; color: var(--dash-ink); font-weight: 600; margin-bottom: 3px; }
.aud span { color: var(--dash-ink-2); }

/* ---------------------------------------------------------------- caveats and the footer */

.thin {
  margin: 0 0 11px; padding: 9px 11px;
  border-left: 2px solid var(--band-passive);
  background: var(--dash-panel-2);
  border-radius: 0 7px 7px 0;
  font-size: 11.5px; line-height: 1.5; color: var(--dash-ink-2);
}

.notes { margin: 0; padding: 0; list-style: none; display: grid; gap: 5px; }
.notes li {
  font-size: 11px; line-height: 1.45; color: var(--dash-ink-3);
  padding-left: 11px; position: relative;
}
.notes li::before { content: "·"; position: absolute; left: 3px; }

.card-foot {
  margin: 10px 0 0; padding-top: 9px;
  /* margin-top:auto above wins for the vertical push; this keeps the horizontal reset. */
  border-top: 1px solid var(--dash-line);
  font-size: 10.5px; color: var(--dash-ink-3);
}

/* ---------------------------------------------------------------- empty */

.empty {
  border: 1px dashed var(--dash-line); border-radius: 10px;
  padding: 44px 24px; text-align: center;
}
.empty h2 { margin: 0 0 7px; font-size: 15px; font-weight: 600; }
.empty p { margin: 0 auto; max-width: 42ch; font-size: 12.5px; color: var(--dash-ink-3); }

/* ---------------------------------------------------------------- narrow screens */

@media (max-width: 720px) {
  .work { padding: 16px 13px 48px; }
  .bar { gap: 10px; }
  .cards { grid-template-columns: 1fr; }
  .stat-value { font-size: 23px; }
  .card-what { font-size: 14.5px; }
}

/* At 375px the label column starves the bar it is labelling. Stacking the label over the track
   keeps both readable rather than truncating the one that carries the meaning. */
@media (max-width: 400px) {
  .bar-row { grid-template-columns: 1fr auto; }
  .bar-label { grid-column: 1 / -1; }
  .sec-count { margin-left: 0; width: 100%; }
}

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