/* BrandLens — WeChat mobile snapshot (/m/)
   Deliberately standalone: no Google Fonts (slow inside WeChat), no shared
   desktop classes, nothing that can regress the desktop UI.

   Brand: deep purple #2E1452 · violet #764ba2 · turquoise #2BD6D9
   Page background is a light grey-blue (#f4f6fb), never pure white, so the
   white cards read as cards on an OLED phone in dark-adapted eyes.

   The report blocks below are the desktop Snapshot's visuals (templates/
   snapshot_report.html) redrawn for a 320-unit SVG column: same palette, same
   wording, same levels — a second design language would make "Strong" mean two
   different things.                                          */

:root {
  --purple: #2E1452;
  --purple-2: #3d1a6b;
  --violet: #764ba2;
  --turq: #2BD6D9;
  --turq-deep: #0e9ba0;
  --ink: #241a3a;
  --ink-2: #4b4360;
  --muted: #7b7490;
  --muted-2: #a6a6ba;
  --line: #e8e9f2;
  --soft: #eafafb;
  --bg: #f4f6fb;
  --card: #ffffff;
  --grad: linear-gradient(135deg, #2E1452 0%, #3d1a6b 58%, #764ba2 100%);
  --shadow: 0 1px 2px rgba(46,20,82,.05), 0 6px 18px rgba(46,20,82,.06);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
}

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

html { -webkit-text-size-adjust: 100%; }

body.m-body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.62 -apple-system, BlinkMacSystemFont, "PingFang SC",
        "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica,
        Arial, sans-serif;
  -webkit-tap-highlight-color: transparent;
  overflow-x: hidden;
  word-break: break-word;
}

/* ------------------------------------------------------------------ header */
.m-hdr {
  position: sticky; top: 0; z-index: 30;
  background: var(--grad);
  padding-top: var(--safe-t);
  box-shadow: 0 2px 12px rgba(46,20,82,.18);
}
.m-hdr::after {
  content: ""; display: block; height: 3px;
  background: linear-gradient(90deg, var(--turq) 0%, rgba(43,214,217,0) 78%);
}
.m-hdr-in {
  display: flex; align-items: center; gap: 11px;
  padding: 12px 16px 11px;
  max-width: 640px; margin: 0 auto;
}
.m-logo { width: 36px; height: 36px; object-fit: contain; flex: none; border-radius: 9px; }
.m-hdr-t { min-width: 0; }
.m-hdr-t h1 { margin: 0; font-size: 17px; font-weight: 700; color: #fff; letter-spacing: .2px; }
.m-hdr-t p {
  margin: 2px 0 0; font-size: 12px; color: rgba(255,255,255,.72);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* -------------------------------------------------------------------- main */
.m-main {
  max-width: 640px; margin: 0 auto;
  padding: 14px 14px 0;
}
.m-card {
  background: var(--card);
  border-radius: 15px;
  box-shadow: var(--shadow);
  padding: 16px;
  margin: 0 0 12px;
}
.m-card-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.m-card-hd h2 { margin: 0; font-size: 16px; font-weight: 700; color: var(--purple); }
.m-card h2 { margin: 0 0 8px; font-size: 16px; font-weight: 700; color: var(--purple); }

/* ------------------------------------------------------------------- fields */
.m-field { margin-bottom: 15px; }
.m-field:last-child { margin-bottom: 0; }
.m-field > label {
  display: block; font-size: 14px; font-weight: 600; color: var(--ink);
  margin-bottom: 7px;
}
.m-field > label em { color: #e11d48; font-style: normal; margin-left: 2px; }
.m-opt {
  font-weight: 400; font-size: 12px; color: var(--muted);
  background: #f1f2f8; border-radius: 5px; padding: 1px 6px; margin-left: 4px;
}
.m-field input, .m-field textarea, .m-field select {
  width: 100%;
  font: inherit;
  font-size: 16px;               /* < 16px makes iOS zoom the whole page */
  color: var(--ink);
  background: #fbfbfe;
  border: 1.5px solid var(--line);
  border-radius: 11px;
  padding: 12px 13px;
  outline: none;
  transition: border-color .15s, background .15s;
  -webkit-appearance: none; appearance: none;
}
.m-field textarea { resize: none; line-height: 1.55; }
/* A select with appearance:none has no chevron of its own, so draw one — same
   muted grey as the rest. Declared after the shared rule so that rule's
   background shorthand cannot wipe it. */
.m-field select {
  padding-right: 38px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%237b7490' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
  cursor: pointer;
}
.m-field input::placeholder, .m-field textarea::placeholder { color: #a9a3bb; }
.m-field input:focus, .m-field textarea:focus, .m-field select:focus {
  /* background-color, not the shorthand: the shorthand would reset the select's
     chevron and it would vanish the moment the field took focus. */
  border-color: var(--turq); background-color: #fff;
  box-shadow: 0 0 0 3px rgba(43,214,217,.14);
}
.m-field.bad input { border-color: #f0736a; background: #fff6f5; }
.m-hint { margin: 7px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
/* The label row carries an optional action on the right (the AI fill button).
   Flex + wrap so a long label drops the button to its own line at 320px
   instead of squeezing the label into two words per line. */
.m-lab-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 6px 8px; flex-wrap: wrap; margin-bottom: 6px;
}
.m-lab-row > label { margin-bottom: 0; }
/* Small secondary action: reads as a utility, not as the page's primary button. */
.m-mini {
  display: inline-flex; align-items: center; gap: 4px; flex: none;
  padding: 3px 9px 3px 5px; border-radius: 999px; cursor: pointer;
  border: 1px solid #ded4f2; background: #f7f4ff; color: var(--purple-deep, #5b2d8e);
  font: inherit; font-size: 11.5px; font-weight: 600; line-height: 1.5;
  -webkit-tap-highlight-color: transparent;
}
.m-mini:active { background: #efe9ff; }
.m-mini[disabled] { opacity: .55; cursor: default; }
.m-mini-tag {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 1px 5px; border-radius: 5px; background: var(--purple); color: #fff;
  font-size: 9.5px; font-weight: 800; letter-spacing: .04em;
}
.m-hint-ct { margin-top: 11px; }
.m-hint b { color: var(--purple); }
.m-hint.ok { color: var(--turq-deep); }
.m-hint.warn { color: #b45309; }

/* ------------------------------------------------------------------- chips */
.m-chips { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.m-chip {
  display: flex; align-items: center; gap: 6px;
  min-height: 46px;
  padding: 9px 10px;
  border: 1.5px solid var(--line);
  border-radius: 11px;
  background: #fbfbfe;
  font-size: 14px;
  cursor: pointer;
  user-select: none;
  transition: border-color .15s, background .15s, transform .08s;
}
.m-chip input { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
.m-chip.on { border-color: var(--turq); background: #eefdfd; }
.m-chip:active { transform: scale(.985); }
.m-chip-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; opacity: .45; transition: opacity .15s; }
.m-chip.on .m-chip-dot { opacity: 1; }
.m-chip-n { font-weight: 600; color: var(--ink-2); flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.m-chip.on .m-chip-n { color: var(--purple); }
/* 10px: at 11px the tag left "Perplexity" ~6px short on a 375px phone and it
   rendered as "Perplex…". */
.m-chip-k { font-size: 10px; color: var(--muted); flex: none; }
.m-link {
  background: none; border: 0; padding: 4px 2px;
  font: inherit; font-size: 13px; color: var(--turq-deep);
  cursor: pointer;
}

/* -------------------------------------------------------------------- seg */
.m-seg { display: flex; gap: 8px; }
.m-seg-b {
  flex: 1; min-height: 46px;
  font: inherit; font-size: 15px; font-weight: 600;
  color: var(--ink-2); background: #fbfbfe;
  border: 1.5px solid var(--line); border-radius: 11px;
  cursor: pointer; transition: all .15s;
}
.m-seg-b.on { background: var(--purple); border-color: var(--purple); color: #fff; }

/* -------------------------------------------------------------------- misc */
.m-err {
  background: #fff1f0; border: 1px solid #ffd4d0; color: #b42318;
  border-radius: 12px; padding: 12px 14px; font-size: 14px; margin-bottom: 12px;
}
.m-fine { text-align: center; font-size: 12px; color: var(--muted); margin: 4px 0 0; }
/* Today's free run is gone. Informational, not an error: it has to read as
   "come back tomorrow or talk to us", never as "you broke it". */
/* ------------------------------------------------------- quota notice bar
   A flat tinted strip rather than a bordered card: the note is a state of this
   page, not another card competing with the form above it. Line icon, the
   sentence, then the standing fact at the far right (it wraps under the
   sentence below 520px, where there is no right edge to spare).
   🔴 The accent is darker than --orange on purpose. #f97316 is a FILL colour
   (2.9:1 on white); this is TEXT. #9a3412 on #fef4ef is 7.1:1. */
.m-notice {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: 4px 11px; background: #fef4ef; border-radius: 12px;
  padding: 13px 15px; margin: 0 0 12px;
}
/* Stroke inherits `currentColor`, so one `color` here paints the whole glyph
   and the icon follows the text if the tint ever changes. */
.m-notice-i {
  flex: 0 0 22px; width: 22px; height: 22px; margin-top: 1px; color: #c2410c;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.m-notice-tx { flex: 1 1 190px; min-width: 0; font-size: 13.5px;
  line-height: 1.55; color: var(--ink-2); }
.m-notice-en { display: block; color: #9a3412; font-weight: 600; }
/* Wrapped: full width, indented to the sentence's left edge so it reads as part
   of the same block rather than as a new one. */
.m-notice-reset { flex: 1 1 100%; margin-left: 33px; font-size: 12.5px;
  line-height: 1.4; color: var(--muted-2); }
@media (min-width: 520px) {
  .m-notice { align-items: baseline; }
  .m-notice-reset { flex: 0 0 auto; margin-left: auto; white-space: nowrap; }
}
.m-cta-space { height: 92px; }

/* --------------------------------------------------------------------- cta */
.m-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  padding: 9px 14px calc(9px + var(--safe-b));
  background: linear-gradient(180deg, rgba(244,246,251,0) 0%, rgba(244,246,251,.92) 26%, #f4f6fb 100%);
}
.m-btn {
  display: block; width: 100%; max-width: 612px; margin: 0 auto;
  padding: 12px 16px;
  border: 0; border-radius: 13px;
  background: var(--grad); color: #fff;
  font: inherit; text-align: center; text-decoration: none;
  cursor: pointer; box-shadow: 0 6px 16px rgba(46,20,82,.22);
  transition: transform .08s, box-shadow .15s;
}
.m-btn:active { transform: scale(.988); box-shadow: 0 3px 10px rgba(46,20,82,.2); }
.m-btn-t { display: block; font-size: 16.5px; font-weight: 700; letter-spacing: .3px; }
.m-btn-s { display: block; font-size: 11.5px; color: rgba(255,255,255,.75); margin-top: 2px; }
.m-btn[disabled] { opacity: .6; box-shadow: none; }
.m-btn-a { display: block; margin: 12px 0 0; }

/* -------------------------------------------------------------------- run */
.m-run { text-align: center; padding: 22px 16px 18px; }
.m-ring { position: relative; width: 156px; height: 156px; margin: 0 auto 6px; }
.m-ring svg { width: 100%; height: 100%; display: block; }
.m-ring-bg { fill: none; stroke: #eceaf5; stroke-width: 14; }
/* No transform: the path already starts at 12 o'clock. A rotate() here would
   reintroduce a transform-origin, which is what put the ring 12 units off
   centre when the viewBox changed. */
.m-ring-fg {
  fill: none; stroke: var(--turq); stroke-width: 14; stroke-linecap: round;
  transition: stroke-dashoffset .55s ease;
}
.m-ring-n {
  position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; gap: 1px;
}
/* The number and its "%" are two siblings on purpose: m.js writes the count
   with `pctN.textContent = n`, which replaces every child — a nested <i> would
   be wiped on the first tick. So the pair is aligned here instead. `top` nudges
   the "%" onto the digit's optical baseline without touching the flex geometry. */
.m-ring-n span { font-size: 40px; font-weight: 700; color: var(--purple); letter-spacing: -1.5px; line-height: 1; }
.m-ring-n i { font-style: normal; font-size: 16px; color: var(--muted); line-height: 1; position: relative; top: 8px; }
.m-stage { margin: 12px 0 0; font-size: 16px; font-weight: 600; color: var(--ink); }
.m-count { margin: 12px 0 0; font-size: 13px; color: var(--muted); }
.m-steps {
  list-style: none; display: flex; gap: 0; margin: 18px 0 0; padding: 0;
  font-size: 12px; color: var(--muted);
}
.m-steps li { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.m-steps li i {
  width: 9px; height: 9px; border-radius: 50%; background: #ddd8ec; display: block;
  transition: background .3s;
}
.m-steps li.on i { background: var(--turq); box-shadow: 0 0 0 4px rgba(43,214,217,.18); }
.m-steps li.on { color: var(--turq-deep); font-weight: 600; }
.m-steps li.done i { background: var(--violet); }
.m-steps li.done { color: var(--violet); }

.m-dead { text-align: center; }
.m-dead h2 { color: #b42318; }
.m-dead p { font-size: 14px; color: var(--ink-2); }

/* --------------------------------------------------------- tip carousel */
.m-tips { padding-top: 15px; }
.m-tips-hd {
  margin: 0 0 11px; display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 700; color: var(--muted);
  letter-spacing: .04em; text-transform: uppercase;
}
.m-tips-tag {
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em; color: #063f41;
  background: var(--turq); border-radius: 6px; padding: 2px 7px;
}
/* One grid cell for every tip, so the card is as tall as the longest one and
   nothing on the page jumps when it rotates. */
.m-tips-vp { display: grid; }
.m-tip { grid-area: 1 / 1; opacity: 0; transition: opacity .5s ease; }
.m-tip.on { opacity: 1; }
.m-tip b { display: block; font-size: 14px; font-weight: 700; color: var(--purple); margin-bottom: 5px; }
.m-tip p { margin: 0; font-size: 12.5px; line-height: 1.62; color: var(--ink-2); }
/* The Chinese one-line takeaway. Through the violet rather than the turquoise:
   at 12px the turquoise (--turq-deep) only reaches ~3.3:1 on white, which is
   under the 4.5:1 small-text floor, while the violet is ~6.4:1. It also has to
   read as a separate layer — a second colour that looked like the body would
   just look like a stray paragraph.
   Selector is `p.m-tip-cn`, not `.m-tip-cn`: `.m-tip p` above is (0,1,1) and
   would otherwise beat a bare class (0,1,0), silently repainting this line in
   the body colour. Measured: the colour is asserted, not eyeballed. */
.m-tip p.m-tip-cn {
  margin: 6px 0 0; font-size: 12px; line-height: 1.5;
  color: var(--violet);
}
.m-tips-dots { display: flex; align-items: center; justify-content: center; gap: 2px; margin-top: 12px; }
.m-dot {
  width: 26px; height: 26px; padding: 0; border: 0; background: none;
  position: relative; cursor: pointer;
}
.m-dot::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 7px; height: 7px; border-radius: 50%; background: #dcd8ea;
  transition: background .25s, width .25s, border-radius .25s;
}
.m-dot.on::before { background: var(--turq); width: 18px; border-radius: 4px; }

/* ------------------------------------------------------------------ report */
/* section heading + hint, same split as the desktop report's .sec-title/.sec-hint */
.m-sec-t { margin: 0; font-size: 14.5px; font-weight: 700; color: var(--purple); }
.m-sec-t::before {
  content: ""; display: inline-block; width: 3px; height: 14px; border-radius: 2px;
  background: var(--turq); margin-right: 8px; vertical-align: -2px;
}
.m-sec-h { margin: 6px 0 12px; font-size: 12.5px; color: var(--muted); line-height: 1.55; }
.m-sec-h b { color: var(--ink-2); font-weight: 700; }
/* The gauge's own box already carries ~5px of spare above the arc, so the
   generic 12px gap below the sentence stacked on top of it and opened a visible
   hole between the two. */
.m-sec-h-gauge { margin-bottom: 2px; }

.m-head { padding-top: 15px; }
.m-head h1 { margin: 0; font-size: 20px; font-weight: 700; color: var(--purple); letter-spacing: -.2px; }
.m-head-m { margin: 5px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5; }
/* The shortfall note: a fact about the sample, so it sits under the sample line
   in the same muted voice, on a soft amber so it is not missed. */
.m-head-note {
  margin: 8px 0 0; padding: 7px 10px; border-radius: 8px;
  background: #fef7e9; border: 1px solid #f2e2bf;
  font-size: 11.5px; line-height: 1.5; color: #8a4a0b;
}
.m-head-note .m-cn { color: #a16207; margin-top: 1px; }
.m-kpis { display: flex; gap: 8px; margin-top: 14px; }
.m-kpi {
  flex: 1; min-width: 0; background: #fbfbfe; border: 1px solid var(--line);
  border-radius: 11px; padding: 10px 9px;
}
.m-kpi b { display: block; font-size: 23px; font-weight: 700; color: var(--purple);
  letter-spacing: -.6px; line-height: 1.15; }
/* The reach letter in front of the score. Smaller and slightly transparent so
   "A-67.4" reads as one marker rather than two numbers, and in the deep brand
   purple rather than the card's own accent: the accent is the quality band, and
   a letter in the same hue would look like part of that band. Reach and quality
   are different axes. */
.m-kpi b .g {
  /* 🔴 `inline`, explicitly. `.m-kpi span` below sets `display:block` for the
     card's labels, and the grade IS a span — so it became a block of its own and
     the card rendered a lone "C-" with "35" underneath it. Scoping the label
     rule to direct children fixes it structurally; this line keeps it fixed if
     that rule ever widens again. */
  display: inline;
  font-size: .62em; font-weight: 800; letter-spacing: 0; opacity: .62;
  vertical-align: .09em; margin-right: 3px;
}
/* Direct children only: the labels are `.m-kpi > span`. Anything nested inside
   <b> is part of the number and must stay on its line. */
.m-kpi > span { display: block; font-size: 11px; font-weight: 700; color: var(--ink-2);
  margin-top: 2px; line-height: 1.3; }
.m-kpi i { display: block; font-style: normal; font-size: 10.5px; color: var(--muted);
  margin-top: 4px; line-height: 1.4; }
/* Three readings, three tints — so the row does not read as one three-column
   table. The value keeps a matching accent, which is what makes the colour
   meaningful rather than decorative. */
/* The three header cards. k-cites / k-queries are gone with the cards they
   tinted; the two new ones read on a strength gradient — top-3 is the softer
   violet, top-1 the brand turquoise, so the strongest signal carries the
   strongest colour. */
.m-kpi.k-top3 { background: #f4f0ff; border-color: #ded4f6; }
.m-kpi.k-top3 b { color: var(--violet); }
.m-kpi.k-top1 { background: #edfbfb; border-color: #cfeef0; }
.m-kpi.k-top1 b { color: var(--turq-deep); }
.m-kpi.k-score { background: #fef7e9; border-color: #f2e2bf; }
.m-kpi.k-score b { color: #b45309; }

/* ---- gauge. Geometry lives on the elements in the template; the CSS only
   colours them, so no rule here can silently repaint or resize an arc. */
.m-g { display: block; width: 100%; height: auto; margin: 0; }
.m-g path { fill: none; stroke-linecap: round; }
.m-g-trk { stroke: #f1f2f6; }
.m-g-trk-in { stroke: rgba(107,78,168,.10); }
.m-g-avg { stroke: #6B4EA8; }
.m-g-n, .m-g-w { font-weight: 700; letter-spacing: -.02em; }
/* The unit under the score. Both live in the empty column right of the arcs. */
.m-g-u { font-weight: 600; letter-spacing: .02em; }
.m-g-cap {
  margin: 10px 0 0; text-align: center; font-size: 12.5px; color: var(--ink-2);
  background: var(--soft); border-radius: 10px; padding: 10px 12px;
}
.m-g-foot {
  margin: 12px 0 0; display: grid; gap: 5px;
  font-size: 12px; color: var(--muted);
}
.m-g-frow { display: flex; align-items: center; gap: 8px; }
/* Which three competitors the benchmark is. Small and muted: it qualifies the
   row above it, it is not a third reading. */
.m-g-names {
  margin: 5px 0 0 18px; font-size: 10.5px; line-height: 1.4; color: var(--muted-2);
}
.m-g-names em { font-style: normal; color: var(--muted-2); opacity: .8; }
/* The label takes the slack so the two readings line up between the rows. */
.m-g-fn { flex: 1; min-width: 0; font-weight: 600; color: var(--ink-2); }
.m-g-fm { flex: none; white-space: nowrap; }
.m-g-foot b { color: var(--ink); }
.m-g-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: none; }
.m-g-sq { width: 10px; height: 12px; border-radius: 3px; background: #6B4EA8;
  display: inline-block; flex: none; }

/* ---- How the scale works */
/* Two rows beside the colour bar: the level and its rule on top, the brands in
   it underneath at full width. Side by side, the brand column was ~110px on a
   375px phone and a single Chinese product name wrapped to three lines. */
.m-scale-r {
  display: grid; grid-template-columns: 6px minmax(0, 1fr); column-gap: 10px;
  row-gap: 3px; align-items: start;
  padding: 8px 10px; border-radius: 10px; margin-bottom: 4px;
}
.m-scale-r.you { background: var(--soft); border: 1px solid #cdeef0; }
.m-scale-b { width: 6px; height: auto; align-self: stretch; border-radius: 3px;
  grid-row: 1 / span 2; }
.m-scale-m { display: flex; align-items: baseline; gap: 2px 6px; flex-wrap: wrap; }
.m-scale-m .m-cn { display: inline; margin-top: 0; font-size: 11px; order: 1; }
.m-scale-m b { font-size: 13px; font-weight: 700; order: 0; }
/* the rule goes last on the line, pushed right, so the level name and its
   Chinese stay together on the left */
.m-scale-m i { font-style: normal; font-size: 11px; color: var(--muted-2);
  order: 2; margin-left: auto; }
.m-scale-n {
  min-width: 0; font-size: 12px; color: var(--ink-2); line-height: 1.5;
}
.m-scale-n .b { display: block; }
.m-scale-n .m-cn { display: inline; margin-left: 4px; }
.m-scale-n b { color: var(--purple); }
.m-scale-n em { font-style: normal; font-size: 11px; color: var(--muted-2); }

/* ---- LLM distribution */
.m-bars { list-style: none; margin: 0; padding: 0; }
.m-bars li { display: flex; align-items: center; gap: 9px; padding: 6px 0; }
.m-bar-n {
  flex: none; width: 82px; font-size: 13px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-bar-w { flex: 1; height: 9px; background: #f0eef7; border-radius: 5px; overflow: hidden; }
.m-bar-v { display: block; height: 100%; border-radius: 5px; min-width: 3px; }
.m-bar-x { flex: none; width: 46px; text-align: right; font-size: 12.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }

/* ---- the board. One row per brand with the name as the axis: the left bar
   fills toward the name, the right bar away from it. Five fixed columns so the
   header row and every row line up — count, left track, name, right track,
   count. The tracks are the only flexible ones (minmax(0,1fr) so a full-width
   fill cannot push the grid wider than the card). */
.m-bd { list-style: none; margin: 0; padding: 0; }
/* The legend. The chart used to explain itself in one sentence ("Left is how
   often it was named... right is how many answers named it first") which a
   reader had to decode while looking at the bars. Two labelled lines say the
   same thing without the decoding. */
.m-bd-lg { list-style: none; margin: 11px 0 0; padding: 0; }
.m-bd-lg li {
  font-size: 11.5px; line-height: 1.5; color: var(--ink-2); padding: 2px 0;
}
.m-bd-lg b { color: var(--purple); font-weight: 700; }
.m-bd-hd, .m-bd-r {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) 96px minmax(0, 1fr) 24px;
  align-items: center; gap: 5px;
}
.m-bd-hd {
  margin: 11px 0 3px; font-size: 9.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
/* The mention label is the longest of the three and its own column is too
   narrow for it on a small phone — measured at 9.5px it needs 89-94px against
   columns of 74px (320w) and 87px (375w), so it broke onto two lines while the
   label on the other side stayed on one, leaving the header looking lopsided.
   The cell to its left is empty in the header (the rows use it for the mention
   count), so the label spans both: right-aligned, it takes the extra room on
   the left, keeps its right edge on the bar it describes, and now sits over the
   number AND the bar — which is what it names. The spacer span is hidden rather
   than deleted so the header keeps a cell per column and stays lined up with
   the rows below. */
.m-bd-hd span:nth-child(1) { display: none; }
.m-bd-hd span:nth-child(2) { grid-column: 1 / 3; text-align: right; }
.m-bd-hd span:nth-child(3) { text-align: center; }
.m-bd-hd span:nth-child(4) { text-align: left; }
.m-bd-r { padding: 5px 0; }
.m-bd-n {
  font-size: 12px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.m-bd-r > .m-bd-n:first-child { text-align: right; }
.m-bd-r > .m-bd-n:last-child { text-align: left; }
/* Two lines before it clips: product names like "修丽可 Phyto Corrective"
   were cut to "修丽可 Ph…" on one line, which is the one word the reader needs. */
.m-bd-b {
  font-size: 12px; font-weight: 600; color: var(--ink); text-align: center;
  line-height: 1.25; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.m-bd-w { height: 8px; background: #f0eef7; border-radius: 5px; overflow: hidden;
  display: flex; }
.m-bd-w i { display: block; height: 100%; border-radius: 5px;
  background: rgba(107,78,168,.42); }
/* The left bar grows leftward, so its fill is pinned to its right edge. */
.m-bd-wl { justify-content: flex-end; }
.m-bd-wr { justify-content: flex-start; }
.m-bd-r.you .m-bd-b, .m-bd-r.you .m-bd-n { color: var(--turq-deep); }
.m-bd-r.you .m-bd-w i { background: var(--turq); }

/* The questions the client's own brand came up in. A different unit from the
   bar above it (an answer can name a brand many times), so it gets its own
   heading rather than sitting under the row as if it belonged to that count. */
.m-bd-q { margin-top: 13px; border-top: 1px solid var(--line); padding-top: 10px; }
/* Two columns, so the number on each query line has a heading over it. */
.m-bd-qh { margin: 0 0 7px; font-size: 11.5px; font-weight: 600; color: var(--muted);
  display: flex; justify-content: space-between; gap: 8px; }
.m-bd-q ul { list-style: none; margin: 0; padding: 0; }
.m-bd-q li {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 0; font-size: 11.5px; line-height: 1.45; color: var(--ink-2);
}
/* A magnifier, drawn rather than typed: an emoji or a glyph would render
   differently on every device, and this site ships no icon font. Stroke-only
   so it inherits the muted tone and never competes with the query text. */
.m-bd-qi {
  flex: none; width: 12px; height: 12px;
  stroke: var(--muted-2); stroke-width: 1.6; fill: none;
  stroke-linecap: round;
  position: relative; top: 1px;
}
.m-bd-qt {
  flex: 1; min-width: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.m-bd-qs { flex: none; font-size: 11px; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.m-bd-qm { font-size: 11px; color: var(--muted); }

/* ---- bubble map */
.m-bub { display: block; width: 100%; height: auto; margin: 2px 0 0; }
.m-bub-gl { stroke: #eef0f6; stroke-width: 1; }
.m-bub-tk { font-size: 9.5px; fill: var(--muted); font-variant-numeric: tabular-nums; }
.m-bub-ax { font-size: 9.5px; font-weight: 600; fill: var(--ink-2); }
/* Fill and stroke come from the geometry (one pair per reach grade); CSS only
   sets the weight, so the colour a bubble gets is decided in one place. */
.m-bub-c { stroke-width: 1.2; }
/* The client keeps its grade colour and gets the brand turquoise as a heavy
   ring on top — "which one is me" and "what grade am I" both stay readable. */
.m-bub-c.you { stroke: var(--turq-deep) !important; stroke-width: 3; }
/* the halo (stroke under the fill) is what keeps a name readable on a bubble */
.m-bub-lb {
  font-weight: 700; fill: #33245a; paint-order: stroke;
  stroke: #fff; stroke-width: 3px; stroke-linejoin: round;
}
.m-bub-lb.you { fill: var(--turq-deep); }
.m-bub-ld { stroke: rgba(107,78,168,.45); stroke-width: 1; }
.m-bub-ld.you { stroke: rgba(14,155,160,.6); }
/* The key: one item per grade drawn, then "You". Wraps rather than shrinking,
   so at 320px it breaks to two tidy lines instead of 9px text. */
.m-bub-lg {
  list-style: none; margin: 8px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 12px;
  font-size: 11px; color: var(--muted);
}
.m-bub-lg li { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.m-bub-lg b { color: var(--ink-2); font-weight: 700; }
.m-bub-k { width: 10px; height: 10px; border-radius: 50%; display: inline-block;
  border: 1.2px solid transparent; flex: none; }
.m-bub-k.you { background: #fff; border: 2.5px solid var(--turq-deep); }

/* ---- Top cited sources */
.m-tw { margin-top: 2px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.m-tb { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 11.5px; }
.m-tb th {
  text-align: left; font-weight: 700; color: var(--muted); font-size: 9.5px;
  text-transform: uppercase; letter-spacing: .05em; padding: 6px;
  background: var(--soft); white-space: nowrap;
}
.m-tb th:first-child { border-radius: 7px 0 0 7px; }
.m-tb th:last-child { border-radius: 0 7px 7px 0; }
.m-tb td {
  padding: 8px 6px; border-bottom: 1px solid #f2f1f8; color: var(--ink-2);
  vertical-align: top; overflow-wrap: anywhere;
}
.m-tb tr:last-child td { border-bottom: 0; }
.m-tb td b { color: var(--purple); font-weight: 700; }
.m-td-m { color: var(--muted); }
.m-pill {
  display: inline-block; font-size: 9.5px; font-weight: 700; padding: 1px 6px;
  border-radius: 999px; background: var(--turq); color: #063f41; vertical-align: 1px;
}

.m-call { border-left: 4px solid var(--turq); }
.m-call p { margin: 0 0 4px; font-size: 13.5px; color: var(--ink-2); }

/* The two chevrons that point down at the fixed CTA. They fall, fade in at the
   bottom of the travel and fade out at the top, so the pair reads as a stream
   moving toward the button instead of a glyph blinking in place. The second
   chevron is delayed by a fifth of the cycle, which is what makes it look like
   motion rather than a shape. */
.m-call-jump { margin: 10px 0 0; display: flex; justify-content: center;
  color: var(--turq-deep); }
.m-call-jump svg { width: 26px; height: 32px; display: block; }
.m-call-jump path {
  fill: none; stroke: currentColor; stroke-width: 2.6;
  stroke-linecap: round; stroke-linejoin: round;
  animation: mjump 1.6s cubic-bezier(.45,.05,.55,.95) infinite;
}
.m-call-jump path + path { animation-delay: .2s; }
@keyframes mjump {
  0%   { opacity: .15; transform: translateY(-3px); }
  45%  { opacity: 1;   transform: translateY(2px); }
  70%  { opacity: 1;   transform: translateY(2px); }
  100% { opacity: .15; transform: translateY(-3px); }
}

/* ------------------------------------------------------------------- sheet */
.m-sheet { position: fixed; inset: 0; z-index: 60; display: flex; align-items: flex-end; }
.m-sheet[hidden] { display: none; }
.m-sheet-bd { position: absolute; inset: 0; background: rgba(24,12,46,.5); animation: mfade .22s ease; }
.m-sheet-pn {
  position: relative; width: 100%; max-width: 640px; margin: 0 auto;
  background: #fff;
  border-radius: 20px 20px 0 0;
  max-height: 92vh; display: flex; flex-direction: column;
  animation: mup .28s cubic-bezier(.22,.9,.3,1);
  box-shadow: 0 -8px 30px rgba(24,12,46,.22);
}
@keyframes mfade { from { opacity: 0 } to { opacity: 1 } }
@keyframes mup { from { transform: translateY(14%) } to { transform: translateY(0) } }
.m-sheet-x {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 34px; height: 34px; border-radius: 50%;
  border: 0; background: rgba(46,20,82,.06); color: var(--ink-2);
  font-size: 20px; line-height: 1; cursor: pointer;
}
.m-sheet-scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 16px 16px 4px; }
.m-sheet-hd .m-badge {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .6px;
  color: var(--turq-deep); background: #e9fbfb; border-radius: 6px; padding: 3px 8px;
}
.m-sheet-hd h2 { margin: 8px 0 5px; font-size: 17px; line-height: 1.35; color: var(--purple); }
.m-sheet-hd p { margin: 0; font-size: 12.5px; color: var(--ink-2); line-height: 1.55; }
.m-bullets { list-style: none; margin: 10px 0; padding: 0; }
.m-bullets li {
  position: relative; padding: 4px 0 4px 20px;
  font-size: 13px; color: var(--ink-2); line-height: 1.45;
}
.m-bullets li::before {
  content: ""; position: absolute; left: 2px; top: 10px;
  width: 8px; height: 8px; border-radius: 3px;
  background: linear-gradient(135deg, var(--turq), var(--violet));
}
.m-team { border-top: 1px solid var(--line); padding-top: 11px; }
.m-team h3 { margin: 0 0 3px; font-size: 14px; color: var(--purple); }
/* The one sentence addressed to the reader rather than about the agency. Set in
   body colour and a touch larger than the addresses, so it reads as the line
   that matters and not as a caption for the cards. */
.m-team-touch { margin: 0 0 9px; font-size: 12.5px; color: var(--ink-2); line-height: 1.45; }
/* Three codes across. At 375px each column is ~109px, which clears the 86px QR
   with room either side; the strip is what keeps all three above the fold. */
.m-people { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.m-person {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  background: #fafaff; border: 1px solid var(--line);
  border-radius: 11px; padding: 7px 5px;
}
.m-p-av { width: 19px; height: 19px; border-radius: 50%; overflow: hidden;
  background: #eee; display: inline-block; vertical-align: -4px; margin-right: 3px; }
.m-p-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.m-p-i { min-width: 0; width: 100%; text-align: center; }
.m-p-i b { display: block; font-size: 12.5px; color: var(--ink); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.m-p-i i { display: block; font-style: normal; font-size: 10.5px; color: var(--muted); }
.m-p-qr {
  flex: none; width: 86px; height: 86px; border-radius: 9px;
  border: 1px solid var(--line); background: #fff; object-fit: contain; cursor: zoom-in;
}
/* Three addresses on one line, the shared domain spelled once — the full form
   three times over was a third of the sheet's height on its own. */
.m-team-mails { margin: 9px 0 0; font-size: 11.5px; color: var(--muted); text-align: center; }
.m-team-mails a { color: var(--turq-deep); text-decoration: none; }
.m-team-mails a + a::before { content: " · "; color: var(--muted); }
.m-sheet-ft {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 18px calc(12px + var(--safe-b));
  border-top: 1px solid var(--line);
}
.m-sheet-note { font-size: 12px; color: var(--muted); }
/* Outlined rather than bare text. It sits opposite a solid "Add us on WeChat"
   primary, and as plain grey text it read as a label for the line next to it
   instead of a thing you can press. */
.m-later {
  flex: none; font: inherit; font-size: 13.5px; font-weight: 600;
  color: var(--ink-2); cursor: pointer;
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 9px 16px;
}
.m-later:active { background: #f4f2fb; }

/* ------------------------------------------------------- bilingual pairs */
/* English is the primary line and keeps its own type; the Chinese is a
   smaller, lighter companion so the pair reads as one label with a
   translation, not as two labels. Two shapes, because the same pair occurs
   twice: a full sentence or list item needs the Chinese on its own line,
   while a short label or heading wants it alongside. */
.m-cn {
  display: block; margin-top: 2px;
  font-size: .88em; font-weight: 400; color: var(--muted);
  line-height: 1.5; letter-spacing: .2px;
}
.m-cn-i {
  font-size: .82em; font-weight: 400; color: var(--muted);
  letter-spacing: .2px; white-space: nowrap;
}
/* Qualified on purpose: a bare `span` in a KPI card inherits `.m-kpi span`
   (11px, bold, ink-2), which would render the Chinese louder than the English
   it is meant to sit under. */
.m-kpi .m-cn { font-size: 10.5px; font-weight: 400; color: var(--muted);
  margin-top: 1px; }
/* The label inside the hand-off card is an `h2`, so the companion needs its
   own size or it would inherit the heading's. */
.m-call h2 .m-cn { margin-top: 5px; font-size: 12px; font-weight: 400;
  color: var(--muted); line-height: 1.5; }

/* -------------------------------------------------------------------- zoom */
.m-zoom {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(20,10,40,.92);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; padding: 24px;
}
.m-zoom[hidden] { display: none; }
.m-zoom img { width: min(78vw, 340px); height: auto; background: #fff; border-radius: 14px; padding: 10px; }
.m-zoom span { color: rgba(255,255,255,.7); font-size: 13px; }

/* ---------------------------------------------------------------- narrow */
@media (max-width: 359px) {
  .m-chip { font-size: 13px; padding: 9px; }
  .m-bar-n { width: 70px; font-size: 12.5px; }
  .m-bar-x { width: 42px; font-size: 12px; }
  /* The board's two tracks are the first thing to give way on a small phone —
     the name and count columns are already at their floor. */
  .m-bd-hd, .m-bd-r {
    grid-template-columns: 20px minmax(0, 1fr) 80px minmax(0, 1fr) 20px;
    gap: 4px;
  }
  .m-bd-n { font-size: 11.5px; }
  .m-bd-b { font-size: 11.5px; }
  .m-bd-hd { font-size: 9px; }
  .m-p-qr { width: 76px; height: 76px; }
  .m-main { padding-left: 11px; padding-right: 11px; }
  .m-kpi b { font-size: 20px; }
  .m-kpi i { display: none; }
  .m-scale-m b { font-size: 12.5px; }
  .m-scale-n { font-size: 11px; }
}

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