/* Page level styles for the two map pages, and for nothing else.
 *
 * WHY this is separate from theme.css: theme.css is the token vocabulary and is
 * shared with anything that renders a BCMS(R) surface. This file is only the
 * chrome AROUND the map: the shell, the frame, the hover card, the HTML legend,
 * the download bar and the interaction affordances. The plate itself cannot be
 * restyled from here on purpose. render.js writes literal hex into the SVG
 * because resvg does not resolve var(), so the browser, the PNG and the PPTX
 * all show the same colours, and a stylesheet that could override them would
 * quietly break that guarantee.
 *
 * Three rules to keep while editing:
 *   1. Light surfaces only. There is no dark variant. The theme query parameter
 *      is parsed and deliberately inert.
 *   2. Never set a CSS `transform` on .bcms-pin. Every pin is positioned by a
 *      transform ATTRIBUTE written by the renderer, and a CSS transform wins
 *      over a presentation attribute, so the rule would move every pin off its
 *      coordinate with nothing in the console to say so.
 *   3. Status is never colour alone. The legend entry carries the word, the
 *      count and the hint, the pin marker carries fill weight and ring, and the
 *      pressed state carries aria-pressed plus a dashed outline, not just a fade.
 */

@import "theme.css";

:root {
  color-scheme: light;
}

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

body {
  margin: 0;
  background: #FFFFFF;
}

/* Inside the agency's iframe the page ground must not paint a white box over
 * their section colour. The plate the renderer draws is opaque anyway, so the
 * only thing that goes transparent is the margin around it. */
html[data-embed="1"] body {
  background: transparent;
}

/* ------------------------------------------------------------------ shell -- */

.bcms-app {
  /* One breakpoint, and it is the CONTAINER width, not the viewport width.
   * This page is normally an iframe inside someone else's column, so the
   * viewport says nothing useful about how much room the map actually has.
   * interact.js reads the same 640 from a ResizeObserver on the frame to pick
   * render options. Change one, change the other. */
  container-type: inline-size;
  container-name: bcmsmap;

  box-sizing: border-box;
  max-width: 1280px;
  margin: 0 auto;
  padding: 24px;
  font-family: var(--font-text);
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
  background: #FFFFFF;
}

.bcms-app *,
.bcms-app *::before,
.bcms-app *::after {
  box-sizing: inherit;
}

html[data-embed="1"] .bcms-app {
  max-width: none;
  padding: 0;
  background: transparent;
}

/* ----------------------------------------------------------------- header -- */

.bcms-header {
  margin: 0 0 16px;
}

.bcms-wordmark {
  margin: 0 0 2px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text);
}

.bcms-wordmark .bcms-reg {
  /* The registered mark rides high and small so the wordmark stays a wordmark. */
  font-size: 0.62em;
  vertical-align: 0.5em;
  letter-spacing: 0;
}

.bcms-caption {
  margin: 0;
  max-width: 68ch;
  color: var(--text);
}

.bcms-counts {
  margin: 6px 0 0;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.bcms-counts:empty {
  display: none;
}

/* The agency's page carries its own heading, so a second one inside the frame
 * reads as a duplicated section rather than as a caption. */
html[data-embed="1"] .bcms-wordmark,
html[data-embed="1"] .bcms-counts,
html[data-embed="1"] .bcms-note,
html[data-embed="1"] .bcms-downloads {
  display: none;
}

html[data-embed="1"] .bcms-header {
  margin-bottom: 10px;
}

/* ------------------------------------------------------------------ stage -- */

.bcms-stage {
  display: grid;
  gap: 16px;
  align-items: start;
}

.bcms-app[data-legend="right"] .bcms-stage {
  grid-template-columns: minmax(0, 1fr) 288px;
}

.bcms-frame {
  position: relative;
  min-width: 0;
  border-radius: 14px;
}

.bcms-frame > svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The <noscript> export, and nothing else in the frame is an image. */
.bcms-frame img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
}

/* Loading and failure states. A blank frame inside someone else's page is the
 * failure nobody reports, so both states say something. */
.bcms-status {
  margin: 0;
  padding: 22px;
  border: 1px solid var(--map-land-stroke);
  border-radius: 14px;
  background: var(--cool-haze);
  color: var(--text-muted);
}

.bcms-status[hidden] {
  display: none !important;
}

.bcms-status code {
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.92em;
  overflow-wrap: anywhere;
}

.bcms-status a {
  color: var(--blue-500);
}

/* -------------------------------------------------------------------- pins -- */

.bcms-map .bcms-pin {
  cursor: pointer;
}

.bcms-map .bcms-pin:focus {
  outline: none; /* the drawn ring is the focus indicator, see render.js */
}

.bcms-map .bcms-pin.is-active > path {
  stroke-width: 2.4;
}

/* The active pin ring, drawn by the renderer at opacity 0. */
.bcms-map .bcms-pin.is-active .bcms-pin-focus {
  opacity: 1;
}

/* A site whose deployment is under way. 1200ms, 60 to 100 per cent, fading out,
 * once per pin and never on anything else: a map where several things blink is
 * a map nobody reads. interact.js adds the circle and removes it again under
 * reduced motion, so the element is not merely paused, it is not there. */
@keyframes bcms-pulse {
  0% {
    transform: scale(0.6);
    opacity: 0.5;
  }
  60% {
    opacity: 0.18;
  }
  100% {
    transform: scale(1);
    opacity: 0;
  }
}

.bcms-map .bcms-pulse {
  transform-box: fill-box;
  transform-origin: center;
  animation: bcms-pulse 1200ms cubic-bezier(0.22, 1, 0.36, 1) infinite;
  pointer-events: none;
}

/* -------------------------------------------------------------------- card -- */

.bcms-card {
  position: absolute;
  z-index: 3;
  width: min(268px, 82%);
  padding: 12px 14px;
  border: 1px solid var(--map-land-stroke);
  border-radius: 10px;
  background: #FFFFFF;
  box-shadow: 0 6px 20px rgba(38, 37, 36, 0.16);
  transition: opacity var(--motion-fast) var(--easing-out);
}

.bcms-card[hidden] {
  display: none !important;
}

.bcms-card:focus {
  outline: 2px solid var(--blue-500);
  outline-offset: 2px;
}

.bcms-card-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

/* The dot repeats the pin fill so the eye can tie the card to the pin it came
 * from. It is never the only carrier of the status: the word is on the next line. */
.bcms-card-dot {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-top: 3px;
  border-radius: 50%;
  border: 1.5px solid var(--text);
}

.bcms-card-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
}

.bcms-card-rows {
  margin: 8px 0 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 2px 10px;
  font-size: 12.5px;
}

.bcms-card-rows dt {
  margin: 0;
  color: var(--text-muted);
}

.bcms-card-rows dd {
  margin: 0;
  color: var(--text);
  overflow-wrap: anywhere;
}

.bcms-card-hint {
  display: block;
  color: var(--text-muted);
}

.bcms-badge {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--map-land-stroke);
  background: var(--cool-haze);
  font-size: 11.5px;
  font-weight: 600;
}

/* The badge on a card whose status no source agrees on. Internal only.
 *
 * It takes the accent, which nothing else on a card does, because this is the
 * one badge that means "do not quote this pin yet". The border carries the
 * difference as well as the fill, so it survives a monochrome print and a
 * reader who cannot separate the two hues: the same rule the pins follow. */
.bcms-badge.is-unconfirmed {
  border-color: var(--orange-200);
  background: var(--orange-50);
  color: var(--orange-500);
}

.bcms-card-link {
  display: inline-block;
  margin-top: 10px;
  color: var(--blue-500);
  font-weight: 600;
  font-size: 12.5px;
}

/* The tap tooltip: the same element with everything but the identity removed.
 * On a phone there is no hover and no native title, so this is the only way a
 * pin can say its own name. */
.bcms-card.is-tip {
  width: auto;
  max-width: 72%;
  padding: 8px 10px;
}

.bcms-card.is-tip .bcms-card-rows {
  margin-top: 4px;
}

/* ------------------------------------------------------------------ legend -- */

.bcms-legend[hidden] {
  display: none !important;
}

.bcms-legend-list {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bcms-app[data-legend="right"] .bcms-legend-list {
  grid-template-columns: minmax(0, 1fr);
}

.bcms-legend-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  width: 100%;
  padding: 9px 10px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: var(--cool-haze);
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--motion-fast) var(--easing-out),
    opacity var(--motion-fast) var(--easing-out);
}

.bcms-legend-item:hover {
  background: var(--blue-50);
}

.bcms-legend-item:focus-visible {
  outline: 2px solid var(--blue-500);
  outline-offset: 2px;
}

/* Off state: faded AND dashed. The fade alone would be a colour cue, and the
 * count going to nothing is not a state a reader can see the cause of. */
.bcms-legend-item[aria-pressed="false"] {
  opacity: 0.55;
  background: transparent;
  border-style: dashed;
  border-color: var(--map-land-stroke);
}

.bcms-legend-mark {
  flex: 0 0 auto;
  width: 22px;
  height: 26px;
}

.bcms-legend-mark svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.bcms-legend-text {
  min-width: 0;
}

.bcms-legend-label {
  font-weight: 600;
}

.bcms-legend-count {
  margin-left: 6px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.bcms-legend-hint {
  display: block;
  color: var(--text-muted);
  font-size: 11.5px;
}

.bcms-legend-glyphs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 18px;
  margin: 12px 0 0;
  font-size: 11.5px;
  color: var(--text);
}

.bcms-legend-glyph {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.bcms-legend-glyph svg {
  display: block;
  width: 15px;
  height: 15px;
}

.bcms-legend-term {
  color: var(--text-muted);
  font-weight: 600;
}

.bcms-legend-note {
  margin: 8px 0 0;
  font-size: 11.5px;
  color: var(--text-muted);
}

/* --------------------------------------------------------- provenance -- */

/* The sentence that says how far the statuses can be trusted.
 *
 * It sits directly under the map, above the consent note, and it is set a step
 * darker and heavier than .bcms-note on purpose. It is not a footnote: with a
 * seed built feed it is the sentence that stops a reader taking a disputed pin
 * for a settled one, and a reader who skips it has been misinformed by a map
 * that was trying to be honest. One step, not three: this is the tEC voice, so
 * it states the caveat plainly rather than shouting it.
 *
 * Unlike .bcms-note it is NOT hidden inside the agency's iframe. The chrome
 * that gets stripped there is the chrome the host page repeats; a provenance
 * claim is not repeated by anybody, so if it were stripped the embed would be
 * the one surface with no answer to "how do you know". */
.bcms-provenance {
  margin: 14px 0 0;
  max-width: 78ch;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
}

.bcms-provenance[hidden] {
  display: none;
}

/* The internal half: where the working list is. Set back to the muted weight,
 * because the claim is the sentence before it and this is the instruction. */
.bcms-provenance-action {
  font-weight: 400;
  color: var(--text-muted);
}

/* ------------------------------------------------------- notes, downloads -- */

.bcms-note {
  margin: 8px 0 0;
  max-width: 78ch;
  font-size: 12.5px;
  color: var(--text-muted);
}

.bcms-downloads {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--map-land-stroke);
}

.bcms-downloads-label {
  margin: 0 4px 0 0;
  font-size: 12.5px;
  color: var(--text-muted);
}

.bcms-download {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  padding: 8px 13px;
  border: 1px solid var(--map-land-stroke);
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  transition: border-color var(--motion-fast) var(--easing-out),
    background var(--motion-fast) var(--easing-out);
}

.bcms-download:hover {
  border-color: var(--blue-300);
  background: var(--blue-50);
}

.bcms-download:focus-visible {
  outline: 2px solid var(--blue-500);
  outline-offset: 2px;
}

.bcms-download small {
  font-weight: 400;
  color: var(--text-muted);
}

/* The one place the single accent is spent on this page: the file that goes
 * straight into a deck. */
.bcms-download.is-primary {
  border-color: var(--orange-200);
  background: var(--orange-200);
  color: #FFFFFF;
}

.bcms-download.is-primary small {
  color: rgba(255, 255, 255, 0.82);
}

.bcms-download.is-primary:hover {
  border-color: var(--orange-300);
  background: var(--orange-300);
}

/* -------------------------------------------------------- quality (internal) -- */

.bcms-quality {
  margin: 22px 0 0;
  padding: 18px 20px;
  border: 1px solid var(--map-land-stroke);
  border-radius: 14px;
  background: var(--cool-haze);
}

.bcms-quality[hidden] {
  display: none !important;
}

.bcms-quality h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
}

.bcms-quality-intro {
  margin: 6px 0 0;
  max-width: 78ch;
  font-size: 12.5px;
  color: var(--text-muted);
}

.bcms-quality-groups {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-top: 16px;
}

.bcms-quality-group h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
}

.bcms-quality-count {
  margin-left: 6px;
  font-variant-numeric: tabular-nums;
  color: var(--orange-300);
}

.bcms-quality-why {
  margin: 3px 0 6px;
  font-size: 11.5px;
  color: var(--text-muted);
}

.bcms-quality-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 12.5px;
}

/* These rows carry CRM text: a site name, a system string, a status source.
 * Nothing upstream caps their length, and at 400px one unbroken token would
 * push the panel wider than the page. Broken rather than trusted. */
.bcms-quality-list li {
  padding: 4px 0;
  border-top: 1px solid var(--map-land-stroke);
  overflow-wrap: anywhere;
}

.bcms-quality-list a {
  color: var(--blue-500);
  font-weight: 600;
}

.bcms-quality-detail {
  display: block;
  color: var(--text-muted);
  font-size: 11.5px;
}

.bcms-quality-clean {
  margin: 12px 0 0;
  font-size: 12.5px;
  color: var(--text-muted);
}

/* -------------------------------------------------------------- utilities -- */

/* Content for a screen reader, and for nothing else. Not display:none: that
 * would take it out of the accessibility tree, which is the whole point of it. */
.bcms-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.bcms-app a:focus-visible,
.bcms-app button:focus-visible {
  outline: 2px solid var(--blue-500);
  outline-offset: 2px;
}

/* -------------------------------------------------- names off the plate -- */

/* The plate is drawn once at 1600 units and scaled to the frame, so every name
 * on it scales with the map. renderMap sets names at 11 units, which is 11 px
 * only if the frame is 1600 px wide, and the shell caps at 1280. The real
 * sizes, frame width being the container less 48 px of shell padding:
 *
 *     container   frame   name
 *     1280        1232    8.5 px
 *     1060        1012    7.0 px
 *      900         852    5.9 px
 *      760         712    4.9 px
 *
 * interact.js already stops asking for names below 640, where they would be
 * about 4 px. That is the right behaviour and the wrong number: type this size
 * does not read as small, it reads as a blurred map, and the grey pipeline
 * names go first because they are the lightest ink on the plate. Rasterised at
 * each width and read, the last width where a muted name still resolves is
 * about 7 px, so the names come off at a container of 1060 rather than at 640.
 *
 * Here and not in the renderer, because this is a question about how much room
 * the frame has on the day, and the renderer answers it once at build time for
 * the SVG, the PNG and the PPTX alike. Those three are read at their own size
 * and keep every name. Nothing is lost on the page either: the pin still
 * carries its name in its <title>, the card opens on hover, tap and focus, and
 * the hidden list under the map reads every site in order.
 *
 * A legend column takes 288 px plus its 16 px gap off the frame before any of
 * this. The shell caps at 1280, so ?legend=right leaves the frame 928 px at
 * the very widest, which is already under the line: that layout never shows
 * names, and it says so without a breakpoint rather than with one nobody can
 * check. Below 640 the column collapses and the rule above takes over. */
@container bcmsmap (max-width: 1060px) {
  .bcms-frame > svg .bcms-labels {
    display: none;
  }
}

.bcms-app[data-legend="right"] .bcms-frame > svg .bcms-labels {
  display: none;
}

/* ------------------------------------------------------- narrow container -- */

@container bcmsmap (max-width: 640px) {
  /* Everything stacks. A legend column beside a 360px map leaves neither of
   * them readable. */
  .bcms-app[data-legend="right"] .bcms-stage {
    grid-template-columns: minmax(0, 1fr);
  }

  .bcms-legend-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .bcms-legend-item {
    padding: 8px;
    gap: 7px;
  }

  .bcms-legend-hint {
    display: none; /* the word and the count survive, the gloss does not fit */
  }

  .bcms-quality-groups {
    grid-template-columns: minmax(0, 1fr);
  }

  .bcms-downloads {
    gap: 8px;
  }

  .bcms-download {
    flex: 1 1 auto;
    justify-content: center;
  }

  .bcms-card {
    width: min(240px, 86%);
  }
}

@container bcmsmap (max-width: 420px) {
  .bcms-legend-list {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Viewport fallback for the page shell. Container queries drive the map chrome,
 * but the outer padding has no container above it to ask. */
@media (max-width: 640px) {
  .bcms-app {
    padding: 16px;
  }
}

/* ------------------------------------------------------------ reduced motion -- */

@media (prefers-reduced-motion: reduce) {
  /* The shell is in the list as well as its descendants. `.bcms-app *` misses
   * the container itself, and a transition added to it later would be the one
   * thing on the page that still moved, with nothing to say why. */
  .bcms-app,
  .bcms-app *,
  .bcms-app *::before,
  .bcms-app *::after {
    transition: none !important;
    animation: none !important;
  }

  /* Not just paused: gone. A frozen ring at 60 per cent scale reads as a
   * rendering fault rather than as a deliberate still state. */
  .bcms-map .bcms-pulse {
    display: none !important;
  }
}
