/* Competencia — the spy wall.
 *
 * ---------------------------------------------------------------- what this page IS
 *
 * A wall of CREATIVES, and a stage where two of them fight. Everything else is
 * chrome around those two jobs. The register is product (design serves the task),
 * so the boldness here is hierarchy and contrast, not theatrics: the creative is
 * large enough to judge, the chrome is a hairline, and the duel is the loudest
 * thing on the page.
 *
 * -------------------------------------------------------------- contrast, measured
 *
 * `--bb-ink-3` FAILS WCAG AA at body sizes in BOTH themes — 3.68:1 on light
 * surface, 3.83:1 on dark. It is used here only for decoration and never for a
 * number, a label or a sentence. Informational small text is `--bb-ink-2`
 * (7.29 light / 7.60 dark).
 *
 * Status colours are the same trap: `--bb-orange` on its own tint is 2.97:1,
 * `--bb-gold-ink` on gold-tint 3.19:1, `--bb-green` 4.44:1. So a status chip takes
 * `--bb-ink-2` for its TEXT (6.2–6.9 light, 5.5–6.1 dark) and carries the meaning
 * in a coloured dot and border instead. That also satisfies never-colour-alone,
 * which matters more here than anywhere: the flags ARE the product.
 *
 * Where a colour must read AS the colour — the duel's verdict — it is white on the
 * solid (5.03 green / 5.86 red / 13.91 navy).
 *
 * ------------------------------------------------------------------ the media well
 *
 * Near-black (#0A0D14) in both themes, deliberately. An ad creative is a picture;
 * a warm background around it makes the picture read muddy. videos.css made the
 * same call for its poster well. Aspect is 4/5 because that is the ratio Meta
 * actually serves, so a square well would letterbox almost every ad in it.
 */

/* =========================================================================
   0. Page-local tokens
   ========================================================================= */

.spy-page {
  /* A semantic z-scale. Never an arbitrary 999. */
  --spy-z-badge: 2;
  --spy-z-backdrop: 900;
  --spy-z-modal: 901;

  /* Exponential ease-out. No bounce, no elastic — this is a tool. */
  --spy-ease: cubic-bezier(.22, 1, .36, 1);
  --spy-fast: 140ms;
  --spy-base: 220ms;

  --spy-well: #0A0D14;
  --spy-tile: 300px;          /* wall tile floor — the creative has to be judgeable */
  padding-bottom: 72px;
}

/* =========================================================================
   1. Top bar — one line, not three blocks
   ========================================================================= */

/* This header used to carry a title, an explanatory paragraph, a four-chip strip
   AND a standing note about how Meta syncs: four things competing above the
   content, two of them prose. Prose in a UI reads as tacky and AI-made; the scope
   belongs in a chip and the reasoning in a tooltip. */
.spy-topbar {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 4px 0 14px;
}
.spy-id { display: flex; align-items: baseline; gap: 14px; min-width: 0; }
.spy-id h2 {
  margin: 0; font-size: 21px; font-weight: 680; letter-spacing: -.022em;
  color: var(--bb-ink, #16181D); white-space: nowrap;
}
/* THE number. One big figure earns its size; a row of six does not. */
.spy-total { display: flex; align-items: baseline; gap: 7px; }
.spy-total b {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-size: 27px; font-weight: 620; line-height: 1; letter-spacing: -.03em;
  color: var(--bb-ink, #16181D);
}
.spy-total i {
  font-style: normal; font-size: 11px; font-weight: 500;
  color: var(--bb-ink-2, #5A564F);
}
.spy-topbar-sp { flex: 1 1 24px; }
.spy-acts { display: flex; gap: 7px; flex-wrap: wrap; }

/* --- source chips --------------------------------------------------------- */

/* Two sources, two clocks, kept legible apart: Google refreshes from the button
   here, Meta only from the laptop. A single combined "actualizado hace 2h" would
   be true of one half and a lie about the other. */
.spy-srcs { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.spy-src {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 10px 5px 8px; border-radius: var(--bb-r-chip, 6px);
  font-size: 11.5px; line-height: 1.3; font-variant-numeric: tabular-nums;
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  color: var(--bb-ink-2, #5A564F); cursor: help;
}
/* The state lives in a DOT, not the text colour — the text must stay at
   --bb-ink-2 to clear 4.5:1, and colour alone is never the signal. */
.spy-src::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--bb-ink-3, #8A8578);
}
.spy-src b { font-weight: 620; color: var(--bb-ink, #16181D); }
.spy-src.is-ok::before    { background: var(--bb-green, #2E7D52); }
.spy-src.is-stale::before { background: var(--bb-orange, #C77D1B); }
.spy-src.is-bad::before,
.spy-src.is-never::before { background: var(--bb-red, #B23B3B); }
.spy-src.is-stale { border-color: color-mix(in srgb, var(--bb-orange, #C77D1B) 40%, var(--bb-line, #E4E2DD)); }
.spy-src.is-bad,
.spy-src.is-never { border-color: color-mix(in srgb, var(--bb-red, #B23B3B) 40%, var(--bb-line, #E4E2DD)); }

.spy-note {
  margin: 0 0 12px; padding: 8px 12px; border-radius: var(--bb-r-chip, 6px);
  font-size: 12px; line-height: 1.45;
  background: var(--bb-inset, #F7F6F3); color: var(--bb-ink-2, #3F444C);
  border: 1px solid var(--bb-line, #E4E2DD);
}
.spy-note code, .spy-hint code, .spy-empty code, .spy-first code {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: .92em;
  padding: 1px 5px; border-radius: 4px;
  background: var(--bb-hover, #EFEDE8); color: var(--bb-ink, #16181D);
}
.spy-note-bad {
  background: var(--bb-red-tint, #FBEFEC); color: var(--bb-ink-2, #5A564F);
  border-color: color-mix(in srgb, var(--bb-red, #B23B3B) 40%, transparent);
}

/* =========================================================================
   2. Controls
   ========================================================================= */

.spy-btn {
  appearance: none; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 560;
  padding: 8px 14px; border-radius: var(--bb-r-control, 8px);
  border: 1px solid var(--bb-line-strong, #D6D3CC);
  background: var(--bb-surface, #fff); color: var(--bb-ink, #16181D);
  box-shadow: var(--bb-sh-btn, 0 1px 2px rgba(20,18,14,.05));
  transition: transform var(--spy-fast) var(--spy-ease),
              background var(--spy-fast) var(--spy-ease),
              box-shadow var(--spy-fast) var(--spy-ease);
  line-height: 1.2; white-space: nowrap;
}
.spy-btn:hover:not(:disabled) { background: var(--bb-hover, #F3F1EC); transform: translateY(-1px); }
.spy-btn:active:not(:disabled) { transform: translateY(0); }
.spy-btn:disabled { opacity: .5; cursor: default; }
.spy-btn-primary { background: var(--bb-accent, #0D2A5E); border-color: transparent; color: #fff; }
.spy-btn-primary:hover:not(:disabled) { background: color-mix(in srgb, var(--bb-accent, #0D2A5E) 88%, #fff); }

.spy-mini {
  appearance: none; cursor: pointer; font: inherit; font-size: 11px; font-weight: 550;
  padding: 4px 9px; border-radius: 6px; text-decoration: none;
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  color: var(--bb-ink-2, #5A564F); line-height: 1.4; white-space: nowrap;
  transition: background var(--spy-fast) var(--spy-ease), color var(--spy-fast) var(--spy-ease);
}
.spy-mini:hover { background: var(--bb-hover, #F3F1EC); color: var(--bb-ink, #16181D); }

.spy-btn:focus-visible, .spy-mini:focus-visible, .spy-tab:focus-visible,
.spy-card:focus-visible, .spy-ad:focus-visible, .spy-chip:focus-visible,
.spy-input:focus-visible, .spy-select:focus-visible, .spy-card-x:focus-visible {
  outline: none; box-shadow: var(--bb-sh-focus, 0 0 0 3px rgba(13,42,94,.28));
}

.spy-input, .spy-select {
  appearance: none; font: inherit; font-size: 12.5px;
  padding: 7px 11px; border-radius: var(--bb-r-control, 8px);
  border: 1px solid var(--bb-line-strong, #D6D3CC);
  background: var(--bb-field, #fff); color: var(--bb-ink, #16181D);
  min-width: 0;
}
/* Placeholders held to the body ratio, not the muted-grey default. */
.spy-input::placeholder { color: var(--bb-ink-2, #5A564F); opacity: .8; }
.spy-input { width: 218px; }
/* A filter toggle, not a checkbox. As a checkbox the input measured 24x24 (under
   the 44px tap-target floor) and the label "Solo vivos" wrapped to THREE lines in
   91px at 768px, which the responsive audit flagged as serious. */
.spy-toggle {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px; font-weight: 560;
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; flex: none;
  min-height: 34px; padding: 0 13px; border-radius: var(--bb-r-control, 8px);
  border: 1px solid var(--bb-line-strong, #D6D3CC);
  background: var(--bb-surface, #fff); color: var(--bb-ink-2, #5A564F);
  transition: background var(--spy-fast) var(--spy-ease), color var(--spy-fast) var(--spy-ease);
}
.spy-toggle::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--bb-line-strong, #D6D3CC);
}
.spy-toggle:hover { background: var(--bb-hover, #F3F1EC); color: var(--bb-ink, #16181D); }
.spy-toggle.is-on {
  background: var(--bb-accent-tint, #EAEFF8); color: var(--bb-ink, #16181D);
  border-color: color-mix(in srgb, var(--bb-accent, #0D2A5E) 40%, transparent);
}
.spy-toggle.is-on::before { background: var(--bb-green, #2E7D52); }
.spy-toggle:focus-visible { outline: none; box-shadow: var(--bb-sh-focus, 0 0 0 3px rgba(13,42,94,.28)); }

/* =========================================================================
   3. The rail — ours is the anchor
   ========================================================================= */

.spy-rail {
  display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 12px;
  margin-bottom: 16px; scrollbar-width: thin;
  scroll-snap-type: x proximity; overscroll-behavior-x: contain;
}
.spy-card {
  position: relative; flex: 0 0 auto; width: 158px; min-height: 96px; text-align: left;
  appearance: none; cursor: pointer; font: inherit; scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 3px;
  padding: 11px 12px 10px; border-radius: var(--bb-r-card, 10px);
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  box-shadow: var(--bb-sh-hairline, 0 1px 2px rgba(20,18,14,.04));
  transition: transform var(--spy-fast) var(--spy-ease),
              box-shadow var(--spy-fast) var(--spy-ease),
              border-color var(--spy-fast) var(--spy-ease);
  overflow: hidden;
}
.spy-card:hover { transform: translateY(-2px); box-shadow: var(--bb-sh-raised, 0 6px 18px rgba(20,18,14,.09)); }
.spy-card.is-on { border-color: var(--c, var(--bb-accent, #0D2A5E)); box-shadow: inset 0 0 0 1px var(--c, var(--bb-accent, #0D2A5E)); }
/* A 3px TOP rule, never a side stripe — side stripes are banned and always read
   as an accident. A top rule reads as a tab. */
.spy-card-bar { position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--c, var(--bb-accent, #0D2A5E)); }
.spy-card-all .spy-card-bar { background: var(--bb-ink-3, #8A8578); }

/* Ours: gold ground and wider. It is the reference every other card is read
   against, so it should not be findable only by squinting for a star. */
.spy-card.is-self {
  width: 200px;
  background: var(--bb-gold-tint, #FBF4E2);
  border-color: color-mix(in srgb, var(--bb-gold, #C9A43F) 46%, var(--bb-line, #E4E2DD));
}
.spy-card.is-self .spy-card-bar { background: var(--bb-gold, #C9A43F); }

.spy-card-name {
  font-size: 12px; font-weight: 620; line-height: 1.28; color: var(--bb-ink, #16181D);
  margin-top: 3px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-width: 0; max-width: 100%; overflow-wrap: anywhere;
}
.spy-card.is-self .spy-card-name { -webkit-line-clamp: 1; }

.spy-card-nums { display: flex; gap: 14px; margin-top: auto; padding-top: 7px; }
.spy-card-nums em {
  font-style: normal; font-size: 19px; font-weight: 620; line-height: 1; letter-spacing: -.02em;
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  color: var(--bb-ink, #16181D); display: flex; flex-direction: column; gap: 4px;
}
.spy-card.is-self .spy-card-nums em { font-size: 24px; }
.spy-card-nums em.is-zero { color: var(--bb-ink-2, #5A564F); opacity: .5; }
.spy-card-nums i {
  font-style: normal; font-size: 10px; font-weight: 570; letter-spacing: .05em;
  text-transform: uppercase; color: var(--bb-ink-2, #5A564F); font-family: inherit;
}
.spy-card-sig {
  font-size: 10px; color: var(--bb-ink-2, #5A564F); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spy-card-sig.is-none::before,
.spy-card-sig.is-warn::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  margin-right: 5px; vertical-align: 1px;
}
.spy-card-sig.is-none::before { background: var(--bb-orange, #C77D1B); }
.spy-card-sig.is-warn { color: var(--bb-ink, #16181D); font-weight: 570; }
.spy-card-sig.is-warn::before { background: var(--bb-red, #B23B3B); }

.spy-card-x {
  position: absolute; top: 6px; right: 6px; width: 20px; height: 20px; border-radius: 5px;
  display: grid; place-items: center; font-size: 15px; line-height: 1;
  color: var(--bb-ink-2, #5A564F); opacity: 0;
  transition: opacity var(--spy-fast) var(--spy-ease);
}
.spy-card:hover .spy-card-x, .spy-card:focus-within .spy-card-x { opacity: 1; }
.spy-card-x:hover { background: var(--bb-red-tint, #FBEFEC); color: var(--bb-red, #B23B3B); }
.spy-card-add { align-items: center; justify-content: center; border-style: dashed; background: transparent; }
.spy-card-add .spy-card-name { text-align: center; color: var(--bb-ink-2, #5A564F); }
.spy-card-plus { font-size: 21px; font-weight: 300; color: var(--bb-ink-2, #5A564F); line-height: 1; }

/* =========================================================================
   4. View switch + filters
   ========================================================================= */

.spy-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin-bottom: 18px;
  padding-bottom: 12px; border-bottom: 1px solid var(--bb-line, #E4E2DD);
}
.spy-tabs { display: flex; gap: 2px; padding: 3px; border-radius: 10px; background: var(--bb-canvas, #EFEDE6); }
.spy-tab {
  appearance: none; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 570;
  padding: 6px 15px; border-radius: 7px; border: 1px solid transparent;
  background: transparent; color: var(--bb-ink-2, #5A564F);
  transition: background var(--spy-fast) var(--spy-ease), color var(--spy-fast) var(--spy-ease);
}
.spy-tab:hover { color: var(--bb-ink, #16181D); }
.spy-tab.is-on {
  background: var(--bb-surface, #fff); color: var(--bb-ink, #16181D);
  box-shadow: var(--bb-sh-btn, 0 1px 2px rgba(20,18,14,.06));
}
.spy-filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* =========================================================================
   5. The wall — the creative IS the card
   ========================================================================= */

.spy-group { margin-bottom: 32px; }
/* A section rule, not a floating cluster. It used to be swatch + star glyph + bold
   name + count with nothing holding them together, and the star and the gold swatch
   were TWO markers for the same fact ("this is ours") — which is exactly why it read
   cluttered. One marker now: an explicit "Ours" chip. */
.spy-group-h {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px; padding-bottom: 9px;
  border-bottom: 1px solid var(--bb-line, #E4E2DD);
}
.spy-group-h h3 {
  margin: 0; font-size: 14.5px; font-weight: 660; color: var(--bb-ink, #16181D);
  display: flex; align-items: center; gap: 9px; letter-spacing: -.014em;
}
/* The competitor's colour, as a swatch that matches its rail card's top rule. */
.spy-group-h h3::before {
  content: ''; width: 4px; height: 15px; border-radius: 2px; flex: none;
  background: var(--c, var(--bb-accent, #0D2A5E));
}
.spy-gcount {
  font-size: 11.5px; color: var(--bb-ink-2, #5A564F);
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
}
.spy-group-sp { flex: 1 1 12px; }
.spy-group.is-self .spy-group-h h3::before { background: var(--bb-gold, #C9A43F); }
.spy-group.is-self .spy-group-h { border-bottom-color: color-mix(in srgb, var(--bb-gold, #C9A43F) 40%, var(--bb-line, #E4E2DD)); }

/* The Page avatar. The monogram is the BASE layer and the <img> lies on top of it,
   so an expired fbcdn URL removes itself (onerror) and reveals initials rather than
   a broken-image glyph. Never the other way round. */
.spy-av {
  position: relative; display: inline-grid; place-items: center; flex: none;
  border-radius: 50%; overflow: hidden; background: var(--c, var(--bb-accent, #0D2A5E));
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.12);
}
.spy-av > i {
  font-style: normal; font-weight: 700; color: #fff; letter-spacing: .01em;
  line-height: 1; user-select: none;
}
.spy-av > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.spy-av-xs { width: 16px; height: 16px; } .spy-av-xs > i { font-size: 7.5px; }
.spy-av-sm { width: 22px; height: 22px; } .spy-av-sm > i { font-size: 9px; }
.spy-av-md { width: 26px; height: 26px; } .spy-av-md > i { font-size: 10.5px; }
.spy-av-lg { width: 34px; height: 34px; } .spy-av-lg > i { font-size: 13px; }

/* min-width:0 on BOTH the row and the name. A flex item defaults to min-width:auto,
   so the avatar (flex:none) plus an unbreakable name pushed 19px past the card's
   content box at every width — the same trap the name itself hit earlier. */
.spy-card-top {
  display: flex; align-items: flex-start; gap: 8px;
  min-width: 0; max-width: 100%; margin-top: 3px;
}
.spy-card-top .spy-card-name { margin-top: 0; min-width: 0; flex: 1 1 auto; }
.spy-card-aud {
  font-size: 10px; color: var(--bb-ink-2, #5A564F);
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.spy-chip { display: inline-flex; align-items: center; gap: 7px; }
.spy-group-h h3 { gap: 9px; }
.spy-side-h b { display: inline-flex; align-items: center; gap: 8px; }
.spy-pb-who h3 { display: flex; align-items: center; gap: 10px; }
.spy-ad-who .spy-av { margin-right: 1px; }

/* One "this is us" marker, used in both the rail and the group header. */
.spy-ours {
  font-size: 9.5px; font-weight: 680; letter-spacing: .07em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 4px; white-space: nowrap;
  background: var(--bb-gold, #C9A43F); color: #16130A;
}
.spy-card .spy-ours { align-self: flex-start; margin-top: 1px; }
.spy-more { margin-top: 10px; }

.spy-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(var(--spy-tile), 1fr));
}

.spy-ad {
  display: flex; flex-direction: column; position: relative;
  border-radius: var(--bb-r-card, 10px); overflow: hidden;
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  box-shadow: var(--bb-sh-hairline, 0 1px 2px rgba(20,18,14,.04));
  transition: transform var(--spy-base) var(--spy-ease), box-shadow var(--spy-base) var(--spy-ease);
}
.spy-ad:hover { transform: translateY(-3px); box-shadow: var(--bb-sh-raised, 0 10px 26px rgba(20,18,14,.11)); }
.spy-ad.is-pickable { cursor: pointer; }
.spy-ad.is-picked { border-color: var(--bb-accent, #0D2A5E); box-shadow: inset 0 0 0 2px var(--bb-accent, #0D2A5E); }

/* The well. 4/5 is Meta's real serving ratio; a square would letterbox nearly
   every ad it holds. */
.spy-ad-media {
  position: relative; aspect-ratio: 4 / 5; background: var(--spy-well); overflow: hidden;
  display: grid; place-items: center;
}
.spy-ad-media img {
  position: absolute; inset: 0; place-self: stretch;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 420ms var(--spy-ease);
}
.spy-ad:hover .spy-ad-media img { transform: scale(1.03); }
/* A landscape creative is contained, not cropped — see the note in spy.js. The
   letterbox is the honest rendering: it is the ad's real shape. */
.spy-ad-media.is-contain img { object-fit: contain; inset: 10px; width: auto; height: auto; place-self: stretch; }
.spy-ad:hover .spy-ad-media.is-contain img { transform: scale(1.015); }
.spy-ad-media.is-broken img { display: none; }
.spy-ad-media.is-broken::after { content: 'imagen expirada'; font-size: 11px; color: rgba(255,255,255,.5); }
.spy-ad-nomedia {
  font-size: 11px; color: rgba(255,255,255,.44); letter-spacing: .06em; text-transform: uppercase;
}

/* Badges sit ON the creative so the card body is all copy. */
.spy-ad-badges {
  position: absolute; inset: 8px 8px auto 8px; z-index: var(--spy-z-badge);
  display: flex; align-items: flex-start; justify-content: space-between; gap: 6px;
  pointer-events: none;
}
.spy-ad-plat, .spy-ad-var, .spy-ad-age {
  padding: 3px 7px; border-radius: 5px; font-size: 10px; font-weight: 620;
  letter-spacing: .02em; line-height: 1.3; white-space: nowrap;
  background: rgba(8,10,16,.76); color: #fff;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.spy-ad-rt { display: flex; gap: 5px; }
/* Variant count is the loudest signal the archive gives, so it is the loudest
   badge. Dark ink on gold: 7.83:1. */
.spy-ad-var {
  background: var(--bb-gold, #C9A43F); color: #16130A;
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
}
/* The liveness badge. It answers "is this RUNNING", which is a different question
   from "how old is it" — see liveness() in spy.js. A dead creative says when it
   stopped; it must not look like a live one wearing a big number. */
.spy-ad-age {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  background: rgba(8,10,16,.64); font-weight: 560;
  display: inline-flex; align-items: center; gap: 5px;
}
.spy-ad-age::before { content: ''; width: 5px; height: 5px; border-radius: 50%; flex: none; background: currentColor; }
.spy-ad-age.is-live    { background: rgba(8,10,16,.7); color: #7BE0A8; }
.spy-ad-age.is-dead    { background: rgba(8,10,16,.7); color: #F3A6A6; font-weight: 500; }
.spy-ad-age.is-unknown { background: rgba(8,10,16,.7); color: rgba(255,255,255,.66); font-weight: 500; }
/* A creative that is not running should not compete with one that is. */
.spy-ad:has(.spy-ad-age.is-dead) .spy-ad-media img,
.spy-ad:has(.spy-ad-age.is-unknown) .spy-ad-media img { opacity: .58; }
.spy-ad:has(.spy-ad-age.is-dead):hover .spy-ad-media img,
.spy-ad:has(.spy-ad-age.is-unknown):hover .spy-ad-media img { opacity: 1; }

.spy-ad-body { padding: 11px 12px 12px; display: flex; flex-direction: column; gap: 7px; flex: 1; }
/* No copy in the archive for this format? Give the room back to the picture
   instead of printing a tall empty box under it. */
.spy-ad.is-nocopy .spy-ad-body { padding: 9px 11px 10px; gap: 6px; }
.spy-ad.is-nocopy .spy-ad-media { aspect-ratio: 1 / 1; }
.spy-ad-who {
  display: flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 600;
  color: var(--bb-ink-2, #5A564F); text-transform: uppercase; letter-spacing: .06em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spy-ad-dot { width: 7px; height: 7px; border-radius: 2px; background: var(--c, #666); flex: none; }
.spy-ad-body h4 {
  margin: 0; font-size: 13.5px; font-weight: 640; line-height: 1.32; color: var(--bb-ink, #16181D);
  letter-spacing: -.011em; text-wrap: pretty;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.spy-ad-body p {
  margin: 0; font-size: 12px; line-height: 1.5; color: var(--bb-ink-2, #5A564F); text-wrap: pretty;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.spy-ad-body p.is-unreadable { font-style: italic; opacity: .85; }

.spy-ad-meta { display: flex; flex-wrap: wrap; gap: 5px; margin-top: auto; padding-top: 3px; }
/* Every tag takes --bb-ink-2 for text and carries meaning in a dot + border, so it
   clears 4.5:1 in both themes and never depends on colour alone. */
.spy-ad-tag {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10.5px; padding: 3px 7px; border-radius: 5px; line-height: 1.4;
  background: var(--bb-inset, #F7F6F3); color: var(--bb-ink-2, #5A564F);
  border: 1px solid var(--bb-line, #E4E2DD);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spy-ad-tag::before {
  content: ''; width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: currentColor; opacity: .42;
}
.spy-ad-tag.is-plain::before, .spy-ad-tag.is-trunc::before { display: none; }
.spy-ad-tag.is-cta  { background: var(--bb-accent-tint, #EAEFF8); border-color: color-mix(in srgb, var(--bb-accent, #0D2A5E) 26%, transparent); }
.spy-ad-tag.is-cta::before  { background: var(--bb-accent, #0D2A5E); opacity: 1; }
.spy-ad-tag.is-form { background: var(--bb-violet-tint, #F0EBF9); border-color: color-mix(in srgb, var(--bb-violet, #6B4FA8) 28%, transparent); }
.spy-ad-tag.is-form::before  { background: var(--bb-violet, #6B4FA8); opacity: 1; }
.spy-ad-tag.is-land { max-width: 172px; }
.spy-ad-tag.is-land::before  { background: var(--bb-cyan, #16788F); opacity: 1; }
.spy-ad-tag.is-dyn  { background: var(--bb-gold-tint, #FBF4E2); border-color: color-mix(in srgb, var(--bb-gold, #C9A43F) 34%, transparent); }
.spy-ad-tag.is-dyn::before   { background: var(--bb-gold-ink, #A8842C); opacity: 1; }
.spy-ad-tag.is-trunc { font-style: italic; }

/* Actions appear on hover but stay keyboard-reachable. An invisible button that
   still takes the click is the ghost-button bug, so this removes it from the hit
   area until it is actually shown. */
/* The actions live ON the creative, bottom-left, revealed on hover. In the card
   BODY they reserved their height even at opacity 0, which left a tall empty box
   under every creative the archive gives no copy for. */
.spy-ad-links {
  position: absolute; inset: auto 8px 8px 8px; z-index: var(--spy-z-badge);
  display: flex; gap: 6px; flex-wrap: wrap;
  opacity: 0; pointer-events: none; transform: translateY(4px);
  transition: opacity var(--spy-fast) var(--spy-ease), transform var(--spy-fast) var(--spy-ease);
}
.spy-ad-links .spy-mini {
  background: rgba(255,255,255,.94); border-color: transparent; color: #16181D;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); font-weight: 570;
}
.spy-ad-links .spy-mini:hover { background: #fff; }
.spy-ad:hover .spy-ad-links,
.spy-ad:focus-within .spy-ad-links { opacity: 1; pointer-events: auto; transform: none; }
@media (hover: none) { .spy-ad-links { opacity: 1; pointer-events: auto; transform: none; } }

/* =========================================================================
   6. Duelo — the stage. The page's focal point.
   ========================================================================= */

.spy-duel { display: flex; flex-direction: column; gap: 18px; }

.spy-stage {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: stretch;
  border-radius: 14px; overflow: hidden;
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  box-shadow: var(--bb-sh-card, 0 2px 12px rgba(20,18,14,.07));
}
.spy-side { display: flex; flex-direction: column; min-width: 0; }
.spy-side-h {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 11px 15px; border-bottom: 1px solid var(--bb-line, #E4E2DD); min-height: 44px;
}
.spy-side-h b {
  font-size: 10.5px; font-weight: 660; text-transform: uppercase; letter-spacing: .08em;
  color: var(--bb-ink-2, #5A564F);
}
/* An auto-matched side says so, and says what it matched ON. A pair presented as
   "the equivalent" with no stated basis is one he cannot check. */
.spy-auto {
  font-size: 9.5px; font-weight: 620; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 4px; margin-right: auto; cursor: help;
  background: var(--bb-cyan-tint, #E5F1F4); color: var(--bb-ink-2, #5A564F);
  border: 1px solid color-mix(in srgb, var(--bb-cyan, #16788F) 34%, transparent);
}
.spy-matching { font-size: 10.5px; color: var(--bb-ink-2, #5A564F); margin-left: auto; }
.spy-nomatch {
  font-size: 12.5px; line-height: 1.5; color: var(--bb-ink, #16181D);
  padding: 10px 12px; border-radius: 8px; margin-bottom: 2px;
  background: var(--bb-orange-tint, #FBF2E3);
  border: 1px solid color-mix(in srgb, var(--bb-orange, #C77D1B) 34%, transparent);
}
.spy-side.is-ours .spy-side-h { background: var(--bb-gold-tint, #FBF4E2); }
.spy-side.is-ours .spy-side-h b { color: var(--bb-ink, #16181D); }

/* The creative at judging size. This is the whole reason the view exists.
   object-fit: contain, not cover — a duel must not crop the thing being judged. */
.spy-side-media {
  position: relative; aspect-ratio: 4 / 5; background: var(--spy-well);
  display: grid; place-items: center; overflow: hidden;
}
.spy-side-media img { position: absolute; inset: 12px; place-self: stretch; object-fit: contain; display: block; }
.spy-side-copy { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 9px; flex: 1; }
.spy-side-copy h4 {
  margin: 0; font-size: 15px; font-weight: 650; line-height: 1.3;
  letter-spacing: -.014em; color: var(--bb-ink, #16181D); text-wrap: pretty;
}
.spy-side-copy p {
  margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--bb-ink-2, #5A564F);
  max-width: 62ch; text-wrap: pretty;
}
.spy-side-tags { display: flex; gap: 5px; flex-wrap: wrap; margin-top: auto; }

/* The gutter: a vertical rule with VS on it — an axis, not a label. */
.spy-vs {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  padding: 0 16px; background: var(--bb-canvas, #EFEDE6);
  border-inline: 1px solid var(--bb-line, #E4E2DD);
}
.spy-vs span {
  font-size: 11px; font-weight: 700; letter-spacing: .14em; color: var(--bb-ink-2, #5A564F);
  writing-mode: vertical-rl; text-orientation: mixed;
}

.spy-slot-empty { display: flex; flex-direction: column; gap: 11px; padding: 16px; min-height: 330px; }
.spy-slot-empty > p { margin: 0; font-size: 12.5px; color: var(--bb-ink-2, #5A564F); }
.spy-slot-none { color: var(--bb-ink, #16181D) !important; line-height: 1.55; }
/* `align-content: start` and `grid-auto-rows` are LOAD-BEARING, not tidiness.
   A grid whose height is clamped by max-height has a definite size, so its auto
   rows stretch — or here, SHRINK — to fill it, and `align-content` defaults to
   stretch. Measured with 40 tiles in this 460px box: ten rows at 39px each, so the
   1:1 media well came out 131x37 and every thumbnail was a sliver. It read as
   broken images rather than as a layout that ran out of room. It was invisible at
   the old hard cap of 18 tiles (four rows, ~90px, nearly square) and appeared the
   moment the picker could show the whole pool. With the rows pinned to their own
   height the box scrolls, which is what the max-height was for. */
.spy-slot-pool {
  display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  grid-auto-rows: max-content; align-content: start;
  max-height: 520px; overflow-y: auto; padding-right: 4px;
}

/* The picker says how many it is SHOWING of how many there are. It used to slice
   18 off the front of the pool and say nothing, which is indistinguishable from a
   collector that only found 18 ads. */
.spy-pick-lead {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  flex-wrap: wrap; margin: 0 !important;
}
.spy-pick-count {
  font-style: normal; font-size: 11px; font-weight: 600; letter-spacing: .01em;
  color: var(--bb-ink-2, #5A564F); font-variant-numeric: tabular-nums;
}
.spy-pick-count i { font-style: normal; font-weight: 500; opacity: .72; }
.spy-pick-more { display: flex; gap: 6px; flex-wrap: wrap; }
.spy-pick-warn {
  margin: 0 !important; font-size: 11.5px; line-height: 1.5;
  color: var(--bb-ink, #16181D); padding: 8px 10px; border-radius: 7px;
  background: var(--bb-orange-tint, #FBF2E3);
  border: 1px solid color-mix(in srgb, var(--bb-orange, #C77D1B) 30%, transparent);
}
/* In the picker the tiles are thumbnails, not cards — no copy, no actions. */
.spy-slot-pool .spy-ad-body { display: none; }
.spy-slot-pool .spy-ad-media { aspect-ratio: 1 / 1; }
.spy-slot-pool .spy-ad-badges { inset: 5px 5px auto 5px; }
.spy-slot-pool .spy-ad-plat { display: none; }

.spy-duel-go { display: flex; gap: 8px; justify-content: center; align-items: center; }

/* =========================================================================
   7. The verdict — a scoreboard
   ========================================================================= */

.spy-verdict {
  border-radius: 14px; overflow: hidden;
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  box-shadow: var(--bb-sh-card, 0 2px 12px rgba(20,18,14,.07));
}
.spy-board { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 18px; padding: 20px 20px 4px; }
.spy-score { display: flex; flex-direction: column; gap: 4px; }
.spy-score.is-them { text-align: right; align-items: flex-end; }
.spy-score-n {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-size: 46px; font-weight: 640; line-height: .95; letter-spacing: -.04em;
  color: var(--bb-ink-2, #5A564F);
}
.spy-score.is-win .spy-score-n { color: var(--bb-ink, #16181D); }
.spy-score i {
  font-style: normal; font-size: 10px; font-weight: 620; text-transform: uppercase;
  letter-spacing: .08em; color: var(--bb-ink-2, #5A564F);
}
.spy-callout {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 15px; border-radius: 999px;
  font-size: 12.5px; font-weight: 620; white-space: nowrap;
}
.spy-verdict.is-win  .spy-callout { background: var(--bb-green, #2E7D52); color: #fff; }
.spy-verdict.is-lose .spy-callout { background: var(--bb-red, #B23B3B); color: #fff; }
.spy-verdict.is-tie  .spy-callout { background: var(--bb-canvas, #EFEDE6); color: var(--bb-ink, #16181D); }

/* One split bar carries the whole result: two numbers, one bar, no doubt. */
.spy-split { display: flex; height: 8px; margin: 14px 20px 0; border-radius: 999px; overflow: hidden; background: var(--bb-canvas, #EFEDE6); }
.spy-split-us, .spy-split-them { transition: flex-basis 640ms var(--spy-ease); }
.spy-split-us   { background: var(--bb-gold, #C9A43F); }
.spy-split-them { background: var(--bb-accent, #0D2A5E); }
.spy-split-key {
  display: flex; justify-content: space-between; padding: 7px 20px 0;
  font-size: 10px; font-weight: 570; letter-spacing: .05em; text-transform: uppercase;
  color: var(--bb-ink-2, #5A564F);
}

.spy-verdict-say {
  margin: 16px 20px 18px; font-size: 14px; line-height: 1.6;
  color: var(--bb-ink, #16181D); max-width: 72ch; text-wrap: pretty;
}
.spy-conf {
  font-size: 10px; padding: 3px 8px; border-radius: 5px; font-weight: 620;
  background: var(--bb-inset, #F7F6F3); color: var(--bb-ink-2, #5A564F);
  border: 1px solid var(--bb-line, #E4E2DD); text-transform: uppercase; letter-spacing: .05em;
}
.spy-conf.is-baja { border-color: color-mix(in srgb, var(--bb-orange, #C77D1B) 48%, transparent); }

/* Dimensions as leaning bars: direction is spatial, so it reads before the word. */
.spy-dims { list-style: none; margin: 0; padding: 0 20px 18px; display: grid; gap: 9px; }
.spy-dim { display: grid; grid-template-columns: 124px 120px 1fr; gap: 12px; align-items: center; font-size: 12.5px; }
.spy-dim > b { font-weight: 620; color: var(--bb-ink, #16181D); }
.spy-lean { display: flex; align-items: center; height: 6px; border-radius: 999px; background: var(--bb-canvas, #EFEDE6); overflow: hidden; }
.spy-lean-l, .spy-lean-r { height: 100%; }
.spy-lean-l { background: var(--bb-gold, #C9A43F); }
.spy-lean-r { background: var(--bb-accent, #0D2A5E); }
.spy-dim em { font-style: normal; color: var(--bb-ink-2, #5A564F); line-height: 1.5; text-wrap: pretty; }

.spy-vlists { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; padding: 0 20px 18px; }
.spy-vlist { padding: 14px 16px; border-radius: 10px; border: 1px solid var(--bb-line, #E4E2DD); }
.spy-vlist h5 {
  margin: 0 0 9px; font-size: 11px; font-weight: 660; letter-spacing: .05em;
  text-transform: uppercase; color: var(--bb-ink-2, #5A564F);
}
.spy-vlist ul { margin: 0; padding-left: 17px; display: grid; gap: 7px; }
.spy-vlist li { font-size: 12.5px; line-height: 1.55; color: var(--bb-ink, #16181D); text-wrap: pretty; }
.spy-vlist.is-steal { background: var(--bb-gold-tint, #FBF4E2); border-color: color-mix(in srgb, var(--bb-gold, #C9A43F) 30%, transparent); }
.spy-vlist.is-fix   { background: var(--bb-accent-tint, #EAEFF8); border-color: color-mix(in srgb, var(--bb-accent, #0D2A5E) 22%, transparent); }

.spy-verdict-foot {
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
  padding: 10px 20px; border-top: 1px solid var(--bb-line, #E4E2DD);
  background: var(--bb-inset, #F7F6F3);
  font-size: 11px; color: var(--bb-ink-2, #5A564F);
}
/* "It never saw the images" must out-read the rest of the footer: a judgement
   about a creative nobody looked at is a different KIND of claim. */
.spy-warn { display: inline-flex; align-items: center; gap: 6px; font-weight: 620; color: var(--bb-ink, #16181D); }
.spy-warn::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--bb-orange, #C77D1B);
}

/* =========================================================================
   8. Playbook + panorama
   ========================================================================= */

.spy-pb-pick { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 18px; }
/* The AI is a BUTTON here, not something that fires when you click a chip. So the
   header carries the competitor, the count, and the commissioning action together. */
.spy-pb-head {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 16px; padding-bottom: 12px;
  border-bottom: 1px solid var(--bb-line, #E4E2DD);
}
.spy-pb-who { display: flex; align-items: baseline; gap: 12px; flex: 1; min-width: 0; }
.spy-pb-who h3 { margin: 0; font-size: 17px; font-weight: 660; letter-spacing: -.018em; color: var(--bb-ink, #16181D); }
.spy-chip {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px; font-weight: 560;
  padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--bb-line-strong, #D6D3CC); background: var(--bb-surface, #fff);
  color: var(--bb-ink-2, #5A564F);
  transition: background var(--spy-fast) var(--spy-ease), color var(--spy-fast) var(--spy-ease);
}
.spy-chip:hover { background: var(--bb-hover, #F3F1EC); color: var(--bb-ink, #16181D); }
.spy-chip.is-on { background: var(--c, var(--bb-accent, #0D2A5E)); border-color: transparent; color: #fff; }

.spy-pb { margin-bottom: 26px; }
.spy-pb-lead {
  margin: 0 0 18px; font-size: 16px; line-height: 1.58; color: var(--bb-ink, #16181D);
  max-width: 70ch; font-weight: 480; letter-spacing: -.006em; text-wrap: pretty;
}
.spy-pb-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); }
.spy-pb-block {
  padding: 14px 16px; border-radius: var(--bb-r-card, 10px);
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
}
.spy-pb-block h5 {
  margin: 0 0 9px; font-size: 11px; font-weight: 660; letter-spacing: .05em;
  text-transform: uppercase; color: var(--bb-ink-2, #5A564F);
  display: flex; align-items: center; gap: 8px;
}
.spy-pb-block h5::before { content: ''; width: 7px; height: 7px; border-radius: 2px; background: var(--bb-ink-3, #8A8578); flex: none; }
.spy-pb-block ul { margin: 0; padding-left: 17px; display: grid; gap: 7px; }
.spy-pb-block li { font-size: 12.5px; line-height: 1.55; color: var(--bb-ink, #16181D); text-wrap: pretty; }
.spy-pb-block.is-threat { background: var(--bb-red-tint, #FBEFEC); border-color: color-mix(in srgb, var(--bb-red, #B23B3B) 26%, transparent); }
.spy-pb-block.is-threat h5::before { background: var(--bb-red, #B23B3B); }
.spy-pb-block.is-opp { background: var(--bb-green-tint, #EAF3EE); border-color: color-mix(in srgb, var(--bb-green, #2E7D52) 26%, transparent); }
.spy-pb-block.is-opp h5::before { background: var(--bb-green, #2E7D52); }
.spy-pb-block.is-weak h5::before { background: var(--bb-orange, #C77D1B); }
.spy-pb-block.is-strong h5::before { background: var(--bb-accent, #0D2A5E); }
.spy-pb-block.is-msg h5::before { background: var(--bb-violet, #6B4FA8); }
.spy-pb-block.is-offer h5::before { background: var(--bb-cyan, #16788F); }
.spy-pb-foot { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 14px; font-size: 12px; color: var(--bb-ink-2, #5A564F); }

.spy-land {
  margin-bottom: 18px; padding: 18px 20px; border-radius: 14px;
  border: 1px solid var(--bb-line, #E4E2DD); background: var(--bb-surface, #fff);
  box-shadow: var(--bb-sh-card, 0 2px 12px rgba(20,18,14,.07));
}
.spy-land-h { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.spy-land-h h3 { margin: 0; flex: 1; font-size: 14.5px; font-weight: 650; color: var(--bb-ink, #16181D); }
.spy-land-lead { margin: 0 0 14px; font-size: 14.5px; line-height: 1.6; color: var(--bb-ink, #16181D); max-width: 74ch; text-wrap: pretty; }
.spy-land-cols { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(228px, 1fr)); }
.spy-land-col { padding: 13px 15px; border-radius: 10px; background: var(--bb-inset, #F7F6F3); border: 1px solid var(--bb-line, #E4E2DD); }
.spy-land-col h5 {
  margin: 0 0 9px; font-size: 10.5px; font-weight: 660; letter-spacing: .05em;
  text-transform: uppercase; color: var(--bb-ink-2, #5A564F);
  display: flex; align-items: center; gap: 8px;
}
.spy-land-col h5::before { content: ''; width: 7px; height: 7px; border-radius: 2px; background: var(--bb-ink-3, #8A8578); flex: none; }
.spy-land-col ul { margin: 0; padding-left: 16px; display: grid; gap: 6px; }
.spy-land-col li { font-size: 12.5px; line-height: 1.55; color: var(--bb-ink, #16181D); text-wrap: pretty; }
.spy-land-col.is-win  { background: var(--bb-green-tint, #EAF3EE); border-color: color-mix(in srgb, var(--bb-green, #2E7D52) 24%, transparent); }
.spy-land-col.is-win h5::before  { background: var(--bb-green, #2E7D52); }
.spy-land-col.is-lose { background: var(--bb-red-tint, #FBEFEC); border-color: color-mix(in srgb, var(--bb-red, #B23B3B) 24%, transparent); }
.spy-land-col.is-lose h5::before { background: var(--bb-red, #B23B3B); }
.spy-land-col.is-gap  { background: var(--bb-gold-tint, #FBF4E2); }
.spy-land-col.is-gap h5::before  { background: var(--bb-gold-ink, #A8842C); }
.spy-land-col.is-do   { background: var(--bb-accent-tint, #EAEFF8); }
.spy-land-col.is-do h5::before   { background: var(--bb-accent, #0D2A5E); }

/* =========================================================================
   9. Picker
   ========================================================================= */

.spy-modal {
  position: fixed; inset: 0; z-index: var(--spy-z-backdrop);
  display: grid; place-items: center; padding: 20px;
  background: rgba(10,13,20,.52);
  animation: spy-fade 180ms var(--spy-ease);
}
.spy-modal-box {
  position: relative; z-index: var(--spy-z-modal);
  width: min(680px, 100%); max-height: 88vh; overflow-y: auto;
  background: var(--bb-surface, #fff); border-radius: 14px;
  border: 1px solid var(--bb-line, #E4E2DD);
  box-shadow: var(--bb-sh-overlay, 0 24px 60px rgba(10,12,18,.3));
  padding: 20px 22px 22px; display: flex; flex-direction: column; gap: 15px;
  animation: spy-rise 220ms var(--spy-ease);
}
@keyframes spy-fade { from { opacity: 0; } }
@keyframes spy-rise { from { opacity: 0; transform: translateY(10px) scale(.985); } }
.spy-modal-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.spy-modal-h h3 { margin: 0; font-size: 16.5px; font-weight: 660; color: var(--bb-ink, #16181D); letter-spacing: -.015em; }
.spy-lab { display: flex; flex-direction: column; gap: 6px; font-size: 12px; font-weight: 570; color: var(--bb-ink-2, #3F444C); }
.spy-lab .spy-input { width: 100%; }
.spy-self {
  align-items: flex-start; gap: 8px; padding: 11px 13px; border-radius: 9px;
  background: var(--bb-gold-tint, #FBF4E2); flex-wrap: wrap;
  border: 1px solid color-mix(in srgb, var(--bb-gold, #C9A43F) 32%, transparent);
}
.spy-self em {
  flex-basis: 100%; font-style: normal; font-size: 11.5px; line-height: 1.5;
  color: var(--bb-ink-2, #5A564F); padding-left: 22px;
}
.spy-modal-sec { display: flex; flex-direction: column; gap: 9px; padding-top: 14px; border-top: 1px solid var(--bb-line, #E4E2DD); }
.spy-modal-sec h4 {
  margin: 0; font-size: 12px; font-weight: 660; letter-spacing: .04em;
  text-transform: uppercase; color: var(--bb-ink-2, #5A564F);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.spy-tagrec, .spy-tagalt { font-size: 9.5px; font-weight: 620; letter-spacing: .03em; text-transform: none; padding: 2px 7px; border-radius: 4px; }
.spy-tagrec { background: var(--bb-green-tint, #EAF3EE); color: var(--bb-ink-2, #5A564F); border: 1px solid color-mix(in srgb, var(--bb-green, #2E7D52) 34%, transparent); }
.spy-tagalt { background: var(--bb-inset, #F7F6F3); color: var(--bb-ink-2, #5A564F); font-weight: 500; }
.spy-searchrow { display: flex; gap: 8px; }
.spy-searchrow .spy-input { flex: 1; width: auto; }
.spy-hint { margin: 0; font-size: 11.5px; line-height: 1.55; color: var(--bb-ink-2, #5A564F); }
.spy-res { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; max-height: 244px; overflow-y: auto; }
.spy-res li { display: flex; gap: 6px; align-items: stretch; }
.spy-res li > button:first-child {
  flex: 1; text-align: left; appearance: none; cursor: pointer; font: inherit;
  padding: 9px 11px; border-radius: 8px; border: 1px solid var(--bb-line, #E4E2DD);
  background: var(--bb-surface, #fff);
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
  transition: background var(--spy-fast) var(--spy-ease);
}
.spy-res li > button:first-child:hover { background: var(--bb-hover, #F3F1EC); }
.spy-res li.is-on > button:first-child {
  border-color: var(--bb-accent, #0D2A5E); background: var(--bb-accent-tint, #EAEFF8);
  box-shadow: inset 0 0 0 1px var(--bb-accent, #0D2A5E);
}
.spy-res b { font-size: 12.5px; font-weight: 620; color: var(--bb-ink, #16181D); }
.spy-res span { font-size: 11px; color: var(--bb-ink-2, #5A564F); white-space: nowrap; font-variant-numeric: tabular-nums; }
.spy-prevgrid { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.spy-prevgrid img { width: 66px; height: 66px; object-fit: cover; border-radius: 6px; background: var(--spy-well); }
.spy-prev-html {
  width: 66px; height: 66px; border-radius: 6px; background: var(--bb-inset, #F7F6F3);
  display: grid; place-items: center; font-size: 9px; color: var(--bb-ink-2, #5A564F);
  border: 1px solid var(--bb-line, #E4E2DD);
}
.spy-modal-f { display: flex; justify-content: flex-end; }

/* =========================================================================
   10. Empty + loading
   ========================================================================= */

.spy-empty {
  padding: 40px 26px; text-align: center; border-radius: 14px;
  border: 1px dashed var(--bb-line-strong, #D6D3CC); background: var(--bb-inset, #F7F6F3);
}
.spy-empty h3 { margin: 0 0 8px; font-size: 16px; font-weight: 650; color: var(--bb-ink, #16181D); letter-spacing: -.014em; }
.spy-empty p { margin: 0 auto 14px; max-width: 58ch; font-size: 13.5px; line-height: 1.6; color: var(--bb-ink-2, #5A564F); text-wrap: pretty; }
.spy-first ol { text-align: left; max-width: 60ch; margin: 0 auto 16px; padding-left: 22px; display: grid; gap: 10px; }
.spy-first li { font-size: 13.5px; line-height: 1.6; color: var(--bb-ink, #16181D); }

.spy-skel { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(var(--spy-tile), 1fr)); }
.spy-skel-card {
  height: 430px; border-radius: var(--bb-r-card, 10px);
  border: 1px solid var(--bb-line, #E4E2DD);
  background: linear-gradient(100deg, var(--bb-inset, #F7F6F3) 30%, var(--bb-hover, #EFEDE8) 50%, var(--bb-inset, #F7F6F3) 70%);
  background-size: 220% 100%; animation: spy-shimmer 1.35s linear infinite;
}
@keyframes spy-shimmer { to { background-position: -220% 0; } }

/* =========================================================================
   11. Reduced motion — collapse to a static state, never a blank one
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  .spy-skel-card { animation: none; background: var(--bb-inset, #F7F6F3); }
  .spy-modal, .spy-modal-box { animation: none; }
  .spy-ad, .spy-card, .spy-btn, .spy-mini, .spy-tab, .spy-chip,
  .spy-ad-media img, .spy-split-us, .spy-split-them, .spy-ad-links,
  .spy-res li > button:first-child { transition: none; }
  .spy-ad:hover, .spy-card:hover, .spy-btn:hover:not(:disabled) { transform: none; }
  .spy-ad:hover .spy-ad-media img { transform: none; }
}

/* =========================================================================
   11b. Dark theme — ink on the SOLID fills
   =========================================================================

   beautiful.css flips the status ramp for dark: --bb-red becomes #EF6B6B,
   --bb-green #3FBE7A, --bb-accent #6FA8F5. Those are LIGHT colours, so the white
   text that was correct in the light theme fails hard on them — measured
   white-on-dark-red 3.01:1, on green 2.37:1, on accent 2.44:1.

   Dark page-ink on the same fills is 6.23 / 7.90 / 7.66. So every solid-filled
   element takes its ink from the theme, not from a hardcoded #fff.

   Keyed on the attribute exactly the way beautiful.css keys its own palette: the
   attribute is written by beautiful.js before first paint, and its absence means
   light. Matching that convention keeps one source of truth for "which theme". */

html[data-bb-theme="dark"] .spy-verdict.is-win .spy-callout,
html[data-bb-theme="dark"] .spy-verdict.is-lose .spy-callout,
html[data-bb-theme="dark"] .spy-btn-primary,
html[data-bb-theme="dark"] .spy-chip.is-on {
  color: #0B1220;
}
html[data-bb-theme="dark"] .spy-btn-primary:hover:not(:disabled) {
  background: color-mix(in srgb, var(--bb-accent) 88%, #fff);
}
/* The conf pill sits inside the callout, so it inherits the same problem. */
html[data-bb-theme="dark"] .spy-callout .spy-conf {
  background: transparent; color: #0B1220; border-color: rgba(11, 18, 32, .42);
}
.spy-callout .spy-conf { background: transparent; color: #fff; border-color: rgba(255,255,255,.55); }
.spy-verdict.is-tie .spy-callout .spy-conf { background: var(--bb-surface); color: var(--bb-ink-2); border-color: var(--bb-line); }

/* =========================================================================
   12. Narrow
   ========================================================================= */

@media (max-width: 1100px) {
  .spy-dim { grid-template-columns: 106px 96px 1fr; gap: 10px; }
}
@media (max-width: 900px) {
  .spy-page { --spy-tile: 240px; }
  .spy-stage { grid-template-columns: 1fr; }
  /* The axis turns horizontal when the sides stack, or VS reads as a typo. */
  .spy-vs { flex-direction: row; padding: 10px 0; border-inline: 0; border-block: 1px solid var(--bb-line, #E4E2DD); }
  .spy-vs span { writing-mode: horizontal-tb; }
  .spy-vlists { grid-template-columns: 1fr; }
  .spy-board { grid-template-columns: 1fr 1fr; row-gap: 14px; }
  .spy-callout { grid-column: 1 / -1; order: -1; justify-self: center; }
  .spy-dim { grid-template-columns: 1fr; gap: 4px; }
  .spy-lean { max-width: 180px; }
  .spy-input, .spy-filters { width: 100%; }
  .spy-topbar { gap: 12px; }
  .spy-score-n { font-size: 38px; }
}
@media (max-width: 560px) {
  .spy-page { --spy-tile: 100%; }
  .spy-toggle { min-height: 44px; }
  .spy-btn { min-height: 42px; }
  .spy-card { width: 140px; }
  .spy-card.is-self { width: 162px; }
}

/* =========================================================================
   13. Benchmark — measured volume above, ONE fenced model below
   =========================================================================

   The two halves must never read as one table. The measured half is stated as
   fact; the modelled half multiplies THEIR volume by OUR rate and is therefore a
   different kind of claim. So it sits on its own ground, its numbers all carry a
   `≈`, and it is always a range. A point estimate of a competitor's leads is
   exactly the number that gets quoted in a meeting as measured truth. */

.spy-bm { display: flex; flex-direction: column; gap: 4px; }
.spy-bm-warn {
  background: var(--bb-inset, #F7F6F3); border-color: var(--bb-line-strong, #D6D3CC);
  color: var(--bb-ink, #16181D); line-height: 1.55; margin-bottom: 18px;
}
.spy-bm-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 8px 0 12px; padding-bottom: 10px;
  border-bottom: 1px solid var(--bb-line, #E4E2DD);
}
.spy-bm-head h3 { margin: 0; font-size: 15px; font-weight: 660; letter-spacing: -.016em; color: var(--bb-ink, #16181D); }
/* The model's own heading rule is dashed — the same device the Weekly Review uses
   to say "suggested, not chosen". */
.spy-bm-head.is-model { margin-top: 30px; border-bottom-style: dashed; }

.spy-bm-list { display: flex; flex-direction: column; gap: 2px; }
.spy-bm-list.is-model {
  padding: 14px; border-radius: 12px; gap: 4px;
  background: var(--bb-canvas, #EFEDE6);
  border: 1px dashed var(--bb-line-strong, #D6D3CC);
}
.spy-bm-row {
  display: grid; align-items: center; gap: 12px;
  grid-template-columns: 210px minmax(90px, 1fr) 52px auto 74px;
  padding: 9px 10px; border-radius: 8px;
}
.spy-bm-row:hover { background: var(--bb-hover, #F3F1EC); }
.spy-bm-row.is-self { background: var(--bb-gold-tint, #FBF4E2); }
.spy-bm-list.is-model .spy-bm-row { grid-template-columns: 210px 1fr 1fr 96px; background: var(--bb-surface, #fff); }
.spy-bm-list.is-model .spy-bm-row:hover { background: var(--bb-surface, #fff); }
.spy-bm-who { display: flex; align-items: center; gap: 9px; min-width: 0; }
.spy-bm-who b {
  font-size: 12.5px; font-weight: 620; color: var(--bb-ink, #16181D);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spy-bm-bar { height: 10px; border-radius: 999px; background: var(--bb-canvas, #EFEDE6); overflow: hidden; }
.spy-bm-bar > span { display: block; height: 100%; background: var(--bb-accent, #0D2A5E); border-radius: 999px; }
.spy-bm-row.is-self .spy-bm-bar > span { background: var(--bb-gold, #C9A43F); }
.spy-bm-share {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 620; text-align: right; color: var(--bb-ink, #16181D);
}
.spy-bm-nums { display: flex; gap: 10px; flex-wrap: wrap; }
.spy-bm-nums > span {
  font-size: 10.5px; color: var(--bb-ink-2, #5A564F); cursor: help; white-space: nowrap;
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
}
/* Destination split: an on-platform form and a landing page are different bets, and
   the mix is one of the few strategy reads the archive genuinely supports. */
.spy-bm-dest { display: flex; height: 8px; border-radius: 999px; overflow: hidden; background: var(--bb-canvas, #EFEDE6); }
.spy-bm-form { background: var(--bb-violet, #6B4FA8); }
.spy-bm-land { background: var(--bb-cyan, #16788F); }
.spy-bm-key { display: flex; gap: 16px; margin-top: 10px; font-size: 10.5px; color: var(--bb-ink-2, #5A564F); }
.spy-bm-key i { display: inline-block; width: 18px; height: 8px; border-radius: 999px; margin-right: 6px; vertical-align: 0; }
.spy-k-form { background: var(--bb-violet, #6B4FA8); }
.spy-k-land { background: var(--bb-cyan, #16788F); }

.spy-bm-basis {
  font-size: 12.5px; line-height: 1.6; color: var(--bb-ink, #16181D);
  padding: 12px 14px; border-radius: 9px; margin-bottom: 12px;
  background: var(--bb-surface, #fff); border: 1px solid var(--bb-line, #E4E2DD);
}
.spy-bm-nobasis {
  font-size: 13px; line-height: 1.6; color: var(--bb-ink, #16181D);
  padding: 14px 16px; border-radius: 9px;
  background: var(--bb-orange-tint, #FBF2E3);
  border: 1px solid color-mix(in srgb, var(--bb-orange, #C77D1B) 34%, transparent);
}
.spy-bm-nobasis-act { display: flex; gap: 8px; align-items: center; margin-top: 12px; }
.spy-bm-band { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.spy-bm-band label { font-size: 12px; font-weight: 570; color: var(--bb-ink-2, #5A564F); }
/* Every modelled figure wears the ≈ its markup gives it, in mono so a range reads
   as one quantity rather than two numbers. */
.spy-bm-est, .spy-bm-vs {
  display: flex; flex-direction: column; gap: 2px;
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 600; color: var(--bb-ink, #16181D);
}
.spy-bm-vs { text-align: right; }
.spy-bm-est > i, .spy-bm-vs > i {
  font-style: normal; font-family: inherit; font-size: 9.5px; font-weight: 500;
  letter-spacing: .04em; text-transform: uppercase; color: var(--bb-ink-2, #5A564F);
}

@media (max-width: 1100px) {
  .spy-bm-row { grid-template-columns: 170px 1fr 48px; row-gap: 6px; }
  .spy-bm-nums, .spy-bm-dest { grid-column: 1 / -1; }
  .spy-bm-list.is-model .spy-bm-row { grid-template-columns: 1fr 1fr; }
  .spy-bm-list.is-model .spy-bm-who { grid-column: 1 / -1; }
}

/* ---- tag chips on the card ---- */
.spy-ad-tag.is-theme { background: var(--bb-accent-tint, #EAEFF8); border-color: color-mix(in srgb, var(--bb-accent, #0D2A5E) 24%, transparent); font-weight: 570; }
.spy-ad-tag.is-theme::before { background: var(--bb-accent, #0D2A5E); opacity: 1; }
.spy-ad-tag.is-offer { background: var(--bb-green-tint, #EAF3EE); border-color: color-mix(in srgb, var(--bb-green, #2E7D52) 28%, transparent); }
.spy-ad-tag.is-offer::before { background: var(--bb-green, #2E7D52); opacity: 1; }

/* =========================================================================
   14. The angle mix — the comparison prose could not give
   =========================================================================

   A small matrix, one row per advertiser, one column per angle, the cell height
   carrying the share. Deliberately NOT a stacked bar: the question is "how does
   THEIR share on this angle compare to OURS", which is a vertical read down a
   column, and a stack makes that comparison impossible. */

.spy-bm-head.is-angle { margin-top: 30px; }
.spy-mix {
  display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--bb-line, #E4E2DD); border-radius: 12px;
  padding: 10px 12px 12px; background: var(--bb-surface, #fff); overflow-x: auto;
}
.spy-mix-head, .spy-mix-row {
  display: grid; align-items: end; gap: 8px;
  grid-template-columns: 210px repeat(var(--cols, 7), minmax(46px, 1fr)) 34px;
}
.spy-mix-head { padding-bottom: 8px; border-bottom: 1px solid var(--bb-line, #E4E2DD); align-items: end; }
.spy-mix-col {
  font-size: 9.5px; font-weight: 620; letter-spacing: .03em; text-transform: uppercase;
  color: var(--bb-ink-2, #5A564F); text-align: center; line-height: 1.25;
}
.spy-mix-row { padding: 7px 0; border-radius: 8px; align-items: center; }
.spy-mix-row:hover { background: var(--bb-hover, #F3F1EC); }
.spy-mix-row.is-self { background: var(--bb-gold-tint, #FBF4E2); }
.spy-mix-cell {
  position: relative; height: 40px; border-radius: 6px; cursor: help;
  background: var(--bb-canvas, #EFEDE6); display: flex; align-items: flex-end; justify-content: center;
  overflow: hidden;
}
.spy-mix-fill { position: absolute; inset: auto 0 0 0; background: var(--bb-accent, #0D2A5E); opacity: .85; }
.spy-mix-row.is-self .spy-mix-fill { background: var(--bb-gold, #C9A43F); }
.spy-mix-cell > em {
  position: relative; font-style: normal; font-size: 10.5px; font-weight: 640; line-height: 1;
  padding-bottom: 4px; color: var(--bb-ink, #16181D);
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  text-shadow: 0 0 3px var(--bb-surface, #fff), 0 0 3px var(--bb-surface, #fff);
}
.spy-mix-n {
  font-size: 10.5px; text-align: right; color: var(--bb-ink-2, #5A564F);
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
}
.spy-mix-thin { margin-top: 10px; }

@media (max-width: 1100px) {
  .spy-mix-head, .spy-mix-row { grid-template-columns: 150px repeat(var(--cols, 7), minmax(38px, 1fr)) 30px; gap: 5px; }
  .spy-mix-cell { height: 34px; }
}

/* Division chip. Ours only — a competitor has no divisions, and the filter's own
   tooltip says so rather than leaving the empty competitor side looking broken. */
.spy-ad-tag.is-div {
  background: var(--bb-gold-tint, #FBF4E2); font-weight: 600;
  border-color: color-mix(in srgb, var(--bb-gold, #C9A43F) 40%, transparent);
}
.spy-ad-tag.is-div::before { background: var(--bb-gold-ink, #A8842C); opacity: 1; }

/* =========================================================================
   15. Global scan — one of ours against every university's equivalent
   ========================================================================= */

.spy-mode { display: flex; gap: 2px; padding: 3px; border-radius: 10px; background: var(--bb-canvas, #EFEDE6); align-self: flex-start; }

.spy-glob { display: grid; grid-template-columns: minmax(280px, 340px) 1fr; gap: 20px; align-items: start; }
/* Ours sticks: the point is comparing everything against it, and it must stay on
   screen while the row of equivalents is scanned. */
.spy-glob-mine {
  position: sticky; top: 12px;
  border: 1px solid color-mix(in srgb, var(--bb-gold, #C9A43F) 46%, var(--bb-line, #E4E2DD));
  background: var(--bb-gold-tint, #FBF4E2);
  border-radius: 12px; padding: 10px; display: flex; flex-direction: column; gap: 9px;
}
.spy-glob-h {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 620; color: var(--bb-ink-2, #5A564F);
}
.spy-glob-h b { font-size: 12px; color: var(--bb-ink, #16181D); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spy-glob-h.is-ours b { color: var(--bb-ink, #16181D); }
.spy-glob-h .spy-mini { margin-left: auto; }
.spy-glob-score {
  margin-left: auto; cursor: help;
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-size: 10.5px; font-weight: 620; padding: 2px 7px; border-radius: 5px;
  background: var(--bb-cyan-tint, #E5F1F4); color: var(--bb-ink-2, #5A564F);
  border: 1px solid color-mix(in srgb, var(--bb-cyan, #16788F) 30%, transparent);
}
.spy-glob-grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.spy-glob-col { display: flex; flex-direction: column; gap: 8px; }
.spy-glob-judge { align-self: flex-start; }
.spy-glob-none { margin-top: 12px; }
.spy-glob-pick { display: flex; flex-direction: column; gap: 10px; }
.spy-glob-pick h3 { margin: 0; font-size: 15px; font-weight: 650; color: var(--bb-ink, #16181D); }

@media (max-width: 1000px) {
  .spy-glob { grid-template-columns: 1fr; }
  .spy-glob-mine { position: static; }
}
