/*
 * Report charts — chart-only visualisations.
 *
 * Every shortcode in this stylesheet renders ONLY its chart visualisation.
 * Surrounding prose (titles, intros, subtitles, footnotes, outros) is the
 * editor's responsibility and authored as native Gutenberg blocks around
 * the shortcode in the post body.
 *
 * Each chart's `variant` field controls its INNER styling so it visually
 * fits whatever surface the editor wraps it in. Recommended pairings:
 *   - default → cream / tan surface (Group block bg = #fffdf8 or #d6d2c9)
 *   - "brand" → orange surface (Group block bg = #f36600)
 *   - "navy"  → navy surface (Group block bg = #031f39)
 *
 * Files in this stylesheet:
 *   - .bitly-chart           Highcharts containers (rendered client-side)
 *   - .bitly-report-panel    Transparent wrapper for chart-only blocks
 *
 * Loaded conditionally on `report` post-type singles or any post containing
 * one of the report shortcodes.
 */

/* =====================================================================
 * Highcharts containers
 * ===================================================================== */

.bitly-chart {
  display: block;
  width: 100%;
  margin: 2.5rem 0;
  padding: 1.25rem;
  background: #fffdf8;
  border: 1px solid #eeeae3;
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(3, 31, 57, 0.04);
  box-sizing: border-box;
  overflow: hidden;
}

.bitly-chart .highcharts-credits {
  display: none !important;
}

/* =====================================================================
 * [bitly_report_chart] hydration wrapper
 *
 * Wraps an SSR-rendered chart fallback that the Highcharts hydrator
 * (assets/scripts/report-charts-hc.js) replaces on the client when the
 * chart scrolls into view. Visible state at each stage:
 *   1. Server-rendered HTML is inside this wrapper → user sees the same
 *      visual as [bitly_report_block].
 *   2. Hydrator fires → SSR markup is replaced with `.bitly-report-chart__mount`,
 *      Highcharts.chart() takes over.
 *   3. If Highcharts never loads (placeholder vendor file, JS off), step 2
 *      never runs and the SSR fallback stays visible — graceful degradation.
 *
 * The wrapper itself is layout-transparent (matches `.bitly-report-panel`)
 * because the surrounding Gutenberg Group/Cover block provides the surface.
 * ===================================================================== */

.bitly-report-chart {
  display: block;
  width: 100%;
  margin: 2rem 0;
  box-sizing: border-box;
}

.bitly-report-chart__mount {
  display: block;
  width: 100%;
}

.bitly-report-chart__mount .highcharts-credits {
  display: none !important;
}

.bitly-report-chart__error {
  padding: 1rem 1.25rem;
  background: #fff8f0;
  border: 1px dashed #f36600;
  border-radius: 8px;
  color: #6c6965;
  font-size: 0.9rem;
  line-height: 1.4;
}

.bitly-chart__error,
.bitly-report-panel__error {
  padding: 1rem 1.25rem;
  background: #fff8f0;
  border: 1px dashed #f36600;
  border-radius: 8px;
  color: #6c6965;
  font-size: 0.9rem;
  line-height: 1.4;
}

.bitly-chart__error strong,
.bitly-report-panel__error strong {
  display: inline-block;
  margin-bottom: 0.25rem;
  color: #031f39;
  font-weight: 500;
}

@media (max-width: 640px) {
  .bitly-chart {
    margin: 1.5rem 0;
    padding: 0.75rem;
    border-radius: 8px;
  }
}

/* =====================================================================
 * Report panels — design tokens + transparent wrapper
 *
 * .bitly-report-panel carries the design-system CSS variables so every
 * chart inherits the same palette/typography/spacing tokens. It does NOT
 * paint a background, padding, or border — the editor's surrounding
 * Group/Cover block provides those.
 *
 * Source: https://www.figma.com/design/eps3H9NoJIXKlTGJHOIOwI/Marketing-Reports
 * ===================================================================== */

.bitly-report-panel {
  /* ---------- raw design tokens (Marketing Reports / Graph-Styling frame) ---------- */
  /* Surfaces */
  --brp-cream: #fffdf8;
  --brp-base-02: #f7f4ee;
  --brp-base-03: #eeeae3;
  --brp-tan: #d6d2c9;
  --brp-navy: #031f39;
  --brp-orange: #f36600;
  --brp-on-navy: #fffdf8;
  --brp-text-muted: #777570;

  /* Accent palette — names mirror the Figma color/accents/* tokens */
  --brp-violet-light: #b7a7f4;
  --brp-violet-dark:  #a950a4;
  --brp-blue-light:   #4fcaff;
  --brp-blue-dark:    #219acd;
  --brp-teal-light:   #79dcdf;
  --brp-teal-dark:    #01b4ac;
  --brp-green-light:  #96de94;
  --brp-green-dark:   #257640;
  --brp-yellow-light: #ffbf3c;
  --brp-yellow-dark:  #e09600;
  --brp-orange-light: #ff950a;
  --brp-red-light:    #ef5b46;

  --brp-radius-m: 8px;
  --brp-axis-thickness: 4px;

  --brp-gap-bars: 16px;
  --brp-gap-bar-pct: 16px;
  --brp-bar-padding-x: 24px;
  --brp-bar-padding-y: 16px;
  --brp-pct-padding-x: 12px;
  --brp-pct-padding-y: 4px;

  --brp-font: "Bitly Displaay Standard", "Bitly Display", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --brp-fs-h4: 32px;
  --brp-fs-h5: var(--Font-size-H5, 24px);

  /* ---------- semantic theme tokens (overridden per variant) ---------- */
  --brp-bar-fill: var(--brp-tan);
  --brp-bar-border: var(--brp-navy);
  --brp-bar-label-color: var(--brp-navy);

  --brp-pct-bg: var(--brp-navy);
  --brp-pct-color: var(--brp-on-navy);
  --brp-pct-size: var(--brp-fs-h4);

  /* The wrapper itself paints nothing — surrounding Group/Cover blocks do.
   * Just give the chart breathing room and let inline content sit cleanly. */
  display: block;
  width: 100%;
  margin: 2rem 0;
  font-family: var(--brp-font);
  color: var(--brp-navy);
  box-sizing: border-box;
}

.bitly-report-panel * {
  box-sizing: border-box;
}

/* =====================================================================
 * bar-list — horizontal bar list with percentage badges
 * ===================================================================== */

.bitly-bar-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--brp-gap-bars);

  /* The vertical "axis" line on the left of the bar group.
   * In the Figma this is a 4px navy bar that the bars butt up against. */
  border-left: var(--brp-axis-thickness) solid var(--brp-bar-border);
}

.bitly-bar-row {
  display: flex;
  align-items: center;
  gap: var(--brp-gap-bar-pct);
  /* Inline `width: <ratio>%` from the SSR is the source of truth for how long
   * each row is relative to the chart max. Do NOT use `min-width: min-content`
   * on the row — it lets the row expand past that percentage whenever the flex
   * min-content contribution (label + badge) exceeds the target width, which
   * can make a 4% row visually longer than a 16% row. `min-width: 0` on the row
   * keeps the used width at the authored %; the bar uses `min-width: auto`
   * so it can grow to fit the label’s intrinsic width inside the row. */
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
}

.bitly-bar-row__bar {
  flex: 1 1 0;
  min-width: auto;
  display: flex;
  align-items: center;
  background: var(--brp-bar-fill);
  border-top: var(--brp-axis-thickness) solid var(--brp-bar-border);
  border-right: var(--brp-axis-thickness) solid var(--brp-bar-border);
  border-bottom: var(--brp-axis-thickness) solid var(--brp-bar-border);
  border-radius: 0 var(--brp-radius-m) var(--brp-radius-m) 0;
  padding: var(--brp-bar-padding-y) var(--brp-bar-padding-x);
}

/* Zero-value rows render with no bar fill or border — just the label and the
 * percentage badge — matching the Figma "Never 0%" row treatment. The bar's
 * normal `--brp-bar-padding-x` is preserved on every side (including the left)
 * so the zero-row label stays vertically aligned with non-zero labels above
 * it instead of snapping flush to the axis line. */
.bitly-bar-row--zero .bitly-bar-row__bar {
  background: transparent;
  border-top-color: transparent;
  border-right-color: transparent;
  border-bottom-color: transparent;
}

.bitly-bar-row__label {
  flex: 1 1 0;
  min-width: auto;
  color: var(--brp-bar-label-color);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--brp-fs-h5);
  line-height: 1.2;
  /* Whole words only — row % width from PHP label floors gives the bar
   * enough room; avoid `break-word`, which can split “Never” as “Ne”/“ver”. */
  overflow-wrap: normal;
  word-break: normal;
  hyphens: manual;
}

.bitly-bar-row__pct {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--brp-pct-bg);
  color: var(--brp-pct-color);
  border-radius: var(--brp-radius-m);
  padding: var(--brp-pct-padding-y) var(--brp-pct-padding-x);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--brp-pct-size);
  line-height: 1.2;
  white-space: nowrap;
}

/* ---------- bar-list responsive ---------- */

@media (max-width: 1024px) {
  .bitly-report-panel {
    --brp-bar-padding-x: 20px;
  }
}

@media (max-width: 768px) {
  .bitly-report-panel {
    --brp-fs-h4: 24px;
    --brp-fs-h5: 18px;
    --brp-bar-padding-x: 16px;
    --brp-bar-padding-y: 12px;
    --brp-gap-bar-pct: 8px;
  }

  /* Mobile-only: bleed chart blocks toward `100vw` (minus gutters) so bar %
   * and other proportional graphics get more horizontal pixels than a
   * narrow prose column allows. Tablet/desktop keep normal `width: 100%`. */
  .bitly-report-chart,
  .bitly-report-panel {
    --brp-chart-stage-bleed: clamp(12px, 4vw, 24px);
    --brp-chart-stage-max: 1680px;
    position: relative;
    left: 50%;
    transform: translateX(-50%);
    width: min(
      var(--brp-chart-stage-max),
      calc(100vw - (2 * var(--brp-chart-stage-bleed)))
    );
    max-width: min(
      var(--brp-chart-stage-max),
      calc(100vw - (2 * var(--brp-chart-stage-bleed)))
    );
  }

  .bitly-report-chart .bitly-report-panel {
    left: auto;
    transform: none;
    width: 100%;
    max-width: none;
    margin-top: 0;
    margin-bottom: 0;
  }

  /* Bar row length comes from the inline `width: …%` on each `<li>` emitted
   * by PHP (`bitly_report_render_bar_rows`) — it already merges `min_bar_pct`,
   * value / chart max, and label-length floors. Do NOT override `width` here:
   * a `calc(var(--brp-bar-value-ratio)*100%)` rule collapses every row to the
   * same width when custom properties are stripped or zeroed (e.g. sanitised
   * markup), which reads as 4% / 7% / 16% bars all identical on mobile. */

  /* Row reveal uses `clip-path` on the bar; that clips overflowing label
   * paint past the bar box (e.g. long phrases or `overflow-wrap: normal` on
   * narrow bars). Skip the clip animation on phones so copy stays visible. */
  .bitly-anim-pending .bitly-bar-list .bitly-bar-row__bar,
  .bitly-report-panel.is-in-view .bitly-bar-list .bitly-bar-row__bar {
    clip-path: none !important;
    animation: none !important;
  }
}

@media (max-width: 480px) {
  .bitly-report-panel {
    --brp-fs-h4: 20px;
    --brp-fs-h5: 15px;
    --brp-bar-padding-x: 12px;
    --brp-pct-padding-x: 10px;
  }
}

/* ---------- bar-list surface variants ---------- */

/* Variant naming describes the BAR FILL colour so authors pick a variant by
 * what they want the bar to look like, not by what surface they're on. The
 * one exception is "navy", which also swaps the badge to cream so it stays
 * readable against a navy panel surface. */

/* "cream" — cream-fill bars + navy badges.
 * Pair with a tan / orange / navy Group block (NOT cream — no contrast). */
.bitly-report-panel--bar-list-cream {
  --brp-bar-fill: var(--brp-cream);
}

/* "orange" — orange-fill bars + navy badges.
 * Pair with a cream / tan / navy Group block. */
.bitly-report-panel--bar-list-orange {
  --brp-bar-fill: var(--brp-orange);
}

/* "navy" — orange-light fill bars + cream badges with navy text.
 * Pair with a navy Group block. */
.bitly-report-panel--bar-list-navy {
  --brp-bar-fill: var(--brp-orange-light);
  --brp-pct-bg: var(--brp-cream);
  --brp-pct-color: var(--brp-navy);
}

/* On a navy panel surface the default navy axis line vanishes against the
 * background. Repaint just the left axis stroke in cream (#fffdf8) so it
 * reads against navy — matches the Figma "navy" bar-list spec. The bars'
 * own top/right/bottom borders stay navy on purpose: they sit on top of
 * the orange-light fill where navy still has contrast, and we don't want
 * to outline every bar in cream. */
.bitly-report-panel--bar-list-navy .bitly-bar-list {
  border-left-color: var(--brp-cream);
}

/* Back-compat alias — "brand" was the original name for what is now "cream".
 * Existing JSON or post bodies referencing variant: "brand" still work. */
.bitly-report-panel--bar-list-brand {
  --brp-bar-fill: var(--brp-cream);
}

/* =====================================================================
 * stacked-bar-list — multi-segment horizontal stacked bars
 * ===================================================================== */

.bitly-stacked-legend {
  list-style: none;
  margin: 0 0 16px 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: center;
}

.bitly-stacked-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-right: 8px;
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.6;
}

@media (min-width: 769px) {
  .bitly-report-panel .bitly-stacked-legend__item {
    font-size: var(--Font-size-H5, 24px);
  }
}

.bitly-stacked-legend__chip {
  flex: 0 0 auto;
  display: inline-block;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 3px solid var(--brp-navy);
  background-color: #d9d9d9;
}

.bitly-stacked-legend__label {
  min-width: auto;
}

.bitly-stacked-bar-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.bitly-stacked-bar-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
}

.bitly-stacked-bar-row__title {
  margin: 0;
  padding: 12px 0 2px 0;
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--brp-fs-h5);
  line-height: 1.4;
  min-width: auto;
}

.bitly-stacked-bar-row__bars {
  display: flex;
  align-items: stretch;
  width: 100%;
  min-width: 0;
}

.bitly-stacked-bar-row__seg {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 16px 8px;
  background-color: #d9d9d9;
  border-top: var(--brp-axis-thickness) solid var(--brp-navy);
  border-right: var(--brp-axis-thickness) solid var(--brp-navy);
  border-bottom: var(--brp-axis-thickness) solid var(--brp-navy);
  border-left: 0;
  overflow: hidden;
  box-sizing: border-box;
}

.bitly-stacked-bar-row__seg--first {
  border-left: var(--brp-axis-thickness) solid var(--brp-navy);
}

.bitly-stacked-bar-row__seg-pct {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  background: var(--brp-navy);
  color: var(--brp-on-navy);
  border-radius: var(--brp-radius-m);
  padding: var(--brp-pct-padding-y) var(--brp-pct-padding-x);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--brp-fs-h4);
  line-height: 1.2;
  white-space: nowrap;
}

/* ---------- stacked-bar-list surface variants ---------- */

/* On a navy surface the legend chip's navy 3px border vanishes against the
 * panel; swap to a cream stroke + cream text so the legend stays visible. */
.bitly-report-panel--stacked-bar-list-navy .bitly-stacked-legend__item,
.bitly-report-panel--stacked-bar-list-navy .bitly-stacked-bar-row__title {
  color: var(--brp-cream);
}

.bitly-report-panel--stacked-bar-list-navy .bitly-stacked-legend__chip {
  border-color: var(--brp-cream);
}

/* No CSS changes needed for `--stacked-bar-list-base` — the default theme
 * already reads correctly on a tan surface. The class still exists as a
 * stable hook in case future design tweaks need it. */

/* ---------- stacked-bar-list responsive ---------- */

@media (max-width: 768px) {
  .bitly-stacked-bar-row__seg {
    padding: 12px 6px;
  }

  .bitly-stacked-bar-row__seg-pct {
    padding: 3px 8px;
  }

  .bitly-stacked-legend__chip {
    width: 18px;
    height: 18px;
    border-width: 2px;
  }

  /* On a phone, three side-by-side segments (e.g. 63% / 19% / 16%) crush the
   * smaller two into illegibility — only the dominant segment fits its
   * badge, the others either clip or overflow into their neighbours.
   *
   * Stack the segments vertically instead, so each one becomes its own
   * short bar with width proportional to its share of the row's total.
   * `align-items: flex-start` keeps segments at their inline `width: <X>%`
   * (set by the SSR renderer as `value / row_total * 100`) rather than
   * stretching them to full width. The result reads as a horizontal bar
   * race, scaled down into a single category. */
  .bitly-stacked-bar-row__bars {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }

  /* Each segment is now a free-standing pill, so it needs all four borders
   * (the desktop layout omits `border-left` on every non-first segment so
   * adjacent segments share an axis stroke — that visual cheat doesn't
   * apply when segments are stacked vertically with gap). */
  .bitly-stacked-bar-row__seg,
  .bitly-stacked-bar-row__seg--first {
    border-left: var(--brp-axis-thickness) solid var(--brp-navy);
    border-radius: var(--brp-radius-m);
    /* Floor the segment width so even the smallest value (e.g. 14% of the
     * row total) keeps enough room for its percentage badge to fit inside
     * cleanly. The inline `width: <X>%` from the renderer still drives
     * relative proportion above this floor. */
    min-width: 96px;
  }
}

/* =====================================================================
 * pie-legend — SVG pie chart with floating badges + side legend
 * ===================================================================== */

.bitly-pie-legend {
  /* Chart-specific tokens — defined here so the chart works in any
   * surrounding context. */
  --brp-pie-gap: 90px;
  --brp-pie-max: 640px;
  --brp-legend-fs: var(--Font-size-H5, 24px);
  --brp-legend-chip: 48px;

  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--brp-pie-gap);
}

.bitly-pie-legend__chart {
  flex: 0 1 var(--brp-pie-max);
  width: 100%;
  max-width: var(--brp-pie-max);
  min-width: 0;
}

.bitly-pie-legend__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.bitly-pie-legend__list {
  list-style: none;
  /* Foundation's `ul { margin-left: 1.25rem; }` and any theme rule that
   * sets `list-style-type: disc` higher up the cascade would otherwise
   * push our chips right and render bullets. The `::marker` reset is
   * the most reliable cross-browser way to kill any inherited marker
   * content the `list-style: none` shorthand might miss. */
  margin: 0;
  padding: 0;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.bitly-pie-legend__list > li::marker,
.bitly-pie-legend__item::marker {
  content: "";
  color: transparent;
}

.bitly-pie-legend__item {
  display: flex;
  align-items: center;
  gap: 18px;
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--brp-legend-fs);
  line-height: 1.3;
}

.bitly-pie-legend__chip {
  flex: 0 0 auto;
  display: inline-block;
  width: var(--brp-legend-chip);
  height: var(--brp-legend-chip);
  border: 4px solid var(--brp-navy);
  border-radius: 12px;
  background-color: #d9d9d9;
  box-sizing: border-box;
}

.bitly-pie-legend__label {
  flex: 1 1 0;
  min-width: auto;
}

/* ---------- pie-legend responsive ---------- */

@media (max-width: 1024px) {
  .bitly-pie-legend {
    --brp-pie-gap: 56px;
    /* Cap below the desktop 640px so the wider pie still fits comfortably
     * next to the legend list on laptop-sized viewports before the layout
     * stacks vertically at 768px. */
    --brp-pie-max: 480px;
    --brp-legend-fs: 20px;
    --brp-legend-chip: 40px;
  }
}

@media (max-width: 768px) {
  .bitly-pie-legend {
    --brp-legend-fs: 16px;
    --brp-legend-chip: 32px;
    flex-direction: column;
    gap: 32px;
  }

  .bitly-pie-legend__chart {
    max-width: 360px;
  }

  .bitly-pie-legend__item {
    gap: 12px;
  }

  .bitly-pie-legend__chip {
    border-width: 3px;
    border-radius: 8px;
  }
}

@media (max-width: 480px) {
  .bitly-pie-legend {
    --brp-legend-fs: 14px;
  }

  .bitly-pie-legend__chart {
    max-width: 280px;
  }
}

/* =====================================================================
 * bar-tiles — wrapping treemap-style horizontal bar chart
 * ===================================================================== */

.bitly-bar-tiles {
  --brp-tile-radius: 8px;
  --brp-tile-row-gap: 8px;
  /* pad-top is sized so a 2-line label still fits inside the locked tile
   * height: tile-h (150) − label box (~62, two lines + 2×2 border) − gap (8)
   * − badge (~38, 28 font × 1.2 + 4 top pad) ≈ 42px headroom. */
  --brp-tile-pad-top: 40px;
  --brp-tile-pad-x: 16px;
  --brp-tile-gap: 8px;
  --brp-tile-label-pad-x: 12px;
  --brp-tile-pct-pad-x: 20px;
  --brp-tile-pct-pad-y: 4px;
  --brp-tile-label-fs: var(--Font-size-H5, 24px);
  --brp-tile-pct-fs: 28px;
  /* Locked tile height — Figma row 1 is 150 px, and the user's intent is
   * that every tile in every row matches that height regardless of label
   * line count. The tile is a column flex container, so leftover vertical
   * space is absorbed between label (top) and badge (`margin-top: auto`,
   * bottom). Width still flexes per JSON `width_pct`. */
  --brp-tile-h: 150px;

  display: flex;
  flex-wrap: wrap;
  row-gap: var(--brp-tile-row-gap);
  column-gap: 0;
  /* Every tile in a row stretches to the row's tallest tile so the boxes
   * stay uniform — matches the Figma. Label text wraps to more lines
   * inside narrower tiles; the badge uses `margin-top: auto` (below) to
   * stay flush with the tile's bottom edge regardless of label height. */
  align-items: stretch;
  width: 100%;
  border-radius: var(--brp-tile-radius);
  overflow: hidden;
  box-sizing: border-box;
}

.bitly-bar-tile {
  display: flex;
  flex-direction: column;
  gap: var(--brp-tile-gap);
  align-items: flex-start;
  /* Label sticks to top (default flex-start). Badge gets `margin-top: auto`
   * below so it always sits flush against the tile's bottom edge — works
   * even when a tile gets stretched by an outer flex parent or when its
   * label wraps to fewer lines than its row neighbours. */
  flex-grow: 0;
  flex-shrink: 1;
  /* Use `min-height` (not a hard `height`) so labels that wrap to 3 lines on
   * tight viewports — most visibly the row-2 tiles in `opportunities.json`
   * around 768–1130px where `width_pct: 18%` tiles have ~150px text area —
   * grow the tile vertically instead of overflowing the badge below the
   * bottom edge. Within a single row `align-items: stretch` (set on the
   * `.bitly-bar-tiles` flex parent above) still pulls every tile up to the
   * tallest one's height, so rows stay visually uniform from left to right.
   * Different rows can now have different heights when their label-line
   * counts differ — this is the lesser of two evils versus invisible badges. */
  min-height: var(--brp-tile-h);
  padding: var(--brp-tile-pad-top) var(--brp-tile-pad-x) 0 var(--brp-tile-pad-x);
  background-color: #d9d9d9;
  min-width: 0;
  box-sizing: border-box;
}

.bitly-bar-tile__label {
  /* `flex` + `width: 100%` + `min-width: 0` on the pill keeps it within the
   * tile’s content box; inner `span` uses `min-width: auto` so label text
   * keeps intrinsic word width (see tile label span rules). */
  display: flex;
  align-items: center;
  align-self: stretch;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  padding: 0 var(--brp-tile-label-pad-x);
  background: var(--brp-cream);
  border: 2px solid var(--brp-navy);
  border-radius: var(--brp-tile-radius);
  box-sizing: border-box;
}

.bitly-bar-tile__label span {
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 400;
  font-size: var(--brp-tile-label-fs);
  line-height: 1.6;
  min-width: auto;
  max-width: 100%;
  flex: 0 1 auto;
  /* Wrap only at spaces; tile / mobile width floors (PHP + CSS) supply room. */
  overflow-wrap: normal;
  word-break: normal;
  hyphens: manual;
}

.bitly-bar-tile__pct {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  /* The default `auto` consumes any leftover vertical space inside the tile
   * and pushes the badge to the very bottom edge, so the badge "blends"
   * with the tile's border-bottom regardless of label wrap or row-stretch
   * behaviour. JSON items can set `pct_margin_top: "12px"` (or any length /
   * `auto`) to override per-tile — useful for narrow tiles whose 2-line
   * labels would otherwise jam the badge against the bottom corner. The
   * value is surfaced as a CSS variable on the parent `.bitly-bar-tile`
   * by the SSR renderer, so the fallback here applies whenever the JSON
   * doesn't set one. */
  margin-top: var(--brp-tile-pct-mt, auto);
  padding: var(--brp-tile-pct-pad-y) var(--brp-tile-pct-pad-x) 0 var(--brp-tile-pct-pad-x);
  background: var(--brp-navy);
  border-radius: var(--brp-tile-radius) var(--brp-tile-radius) 0 0;
  box-sizing: border-box;
}

.bitly-bar-tile__pct span {
  color: var(--brp-on-navy);
  font-family: var(--brp-font);
  font-weight: 700;
  font-size: var(--brp-tile-pct-fs);
  line-height: 1.2;
  white-space: nowrap;
}

/* ---------- bar-tiles responsive ---------- */

@media (max-width: 1024px) {
  .bitly-bar-tiles {
    /* Same fit-2-line-labels math as the default rule, scaled to the
     * smaller tile height: 132 − 62 − 8 − 33 ≈ 29px headroom for pad-top. */
    --brp-tile-pad-top: 28px;
    --brp-tile-pct-fs: 24px;
    --brp-tile-h: 132px;
  }
}

@media (max-width: 768px) {
  .bitly-bar-tiles {
    --brp-tile-pad-top: 28px;
    --brp-tile-pad-x: 12px;
    --brp-tile-pct-fs: 22px;
    --brp-tile-label-fs: 15px;
    --brp-tile-label-pad-x: 10px;
    --brp-tile-pct-pad-x: 14px;
    --brp-tile-row-gap: 4px;
    --brp-tile-h: 108px;

    /* Treemap proportions don't read well on a phone, so each tile gets
     * its own row. Switch the parent to a column flex with `align-items:
     * flex-start` so children are NOT stretched to full width — they're
     * free to take the proportional width set on each tile below. */
    flex-direction: column;
    align-items: flex-start;
  }

  /* Each tile's width on mobile is proportional to its `value` (chart max
   * normalised to `--brp-tile-value-ratio` on each tile). A flat `max(36%, …)`
   * made 9%, 8%, and 1% identical whenever `ratio×100%` was below 36% (e.g.
   * 9/25 = 36% hits the floor, 8/25 and 1/25 both floor to 36%). Use a linear
   * blend instead: `floor% + ratio × (100% − floor%)` so every ratio gets a
   * distinct width while the smallest row still gets ~18% for wrapped labels. */
  .bitly-bar-tile {
    flex-basis: auto !important;
    width: min(
      100%,
      calc(18% + var(--brp-tile-value-ratio, 0) * 82%)
    );
  }
}

@media (max-width: 480px) {
  .bitly-bar-tiles {
    --brp-tile-pad-top: 24px;
    --brp-tile-pct-fs: 20px;
    --brp-tile-label-fs: 14px;
    --brp-tile-h: 96px;
  }
}

/* Targeted wide-viewport fix for `opportunities.json` row 2.
 *
 * That chart's 5th tile — "Better cross-team alignment" (9%) — has a JSON
 * `pct_margin_top: "3px"` because at narrower widths its label wraps to two
 * lines and the badge would otherwise jam against the bottom corner. Above
 * ~1640px the same label fits on a single line, so the 3px override stops
 * being protective and starts leaving a visible gap above the badge.
 *
 * Force just that one tile back to its default `auto` margin-top on wide
 * screens. Scoped to `#report-block-opportunities` (the SSR id derived from
 * the JSON filename) AND `:nth-child(5)` so other bar-tiles charts and the
 * other tiles in this chart (16%, 8%, 1%, which still need their inline
 * overrides because their labels still wrap) are untouched.
 *
 * `!important` is required: the per-tile override is emitted as an inline
 * `style="--brp-tile-pct-mt: ..."` by the SSR renderer (specificity 1000),
 * which a class-level rule otherwise can't beat. */
@media (min-width: 1640px) {
  #report-block-opportunities .bitly-bar-tile:nth-child(5) {
    --brp-tile-pct-mt: auto !important;
  }
}

/* =====================================================================
 * column-chart — vertical bar chart with proportional heights
 * ===================================================================== */

.bitly-column-chart {
  --col-max-h: 248px;
  --col-gap: 32px;
  --col-pad-x: 16px;
  --col-bar-bg: var(--brp-blue-light);
  --col-bar-border-w: 4px;
  --col-bar-radius: var(--brp-radius-m);
  --col-bar-shadow: 0 4px 16px 0 rgba(146, 144, 138, 0.25);
  --col-pct-fs: var(--brp-fs-h4);
  --col-pct-pad-x: 12px;
  --col-pct-pad-y: 4px;
  --col-pct-gap: 16px;
  --col-axis-thickness: var(--brp-axis-thickness);
  --col-label-gap: 16px;
  --col-label-fs: var(--Font-size-H5, 24px);

  width: 100%;
  box-sizing: border-box;
}

/* Plot area: bars row + axis line. Cols inside are bottom-aligned so every
 * bar's bottom edge sits on the same Y position regardless of value. The
 * axis is rendered via the container's bottom border so it spans every
 * column AND the gaps as a single unbroken line. */
.bitly-column-chart__plot {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: var(--col-gap);
  padding: 0 var(--col-pad-x);
  border-bottom: var(--col-axis-thickness) solid var(--brp-navy);
  width: 100%;
  box-sizing: border-box;
}

.bitly-column-chart__col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--col-pct-gap);
}

.bitly-column-chart__pct {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--brp-navy);
  border: 3px solid var(--brp-navy);
  border-radius: var(--brp-radius-m);
  padding: var(--col-pct-pad-y) var(--col-pct-pad-x);
  box-sizing: border-box;
}

.bitly-column-chart__pct span {
  color: var(--brp-on-navy);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--col-pct-fs);
  line-height: 1.2;
  white-space: nowrap;
}

.bitly-column-chart__bar {
  width: 100%;
  height: calc(var(--bar-h-pct, 0) * var(--col-max-h) / 100);
  background: var(--col-bar-bg);
  border: var(--col-bar-border-w) solid var(--brp-navy);
  border-bottom: 0;
  border-radius: var(--col-bar-radius) var(--col-bar-radius) 0 0;
  box-shadow: var(--col-bar-shadow);
  box-sizing: border-box;
}

.bitly-column-chart__labels-row {
  display: flex;
  gap: var(--col-gap);
  padding: var(--col-label-gap) var(--col-pad-x) 0 var(--col-pad-x);
  width: 100%;
  box-sizing: border-box;
}

.bitly-column-chart__label {
  flex: 1 1 0;
  min-width: auto;
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: var(--col-label-fs);
  line-height: 1.6;
  text-align: center;
  overflow-wrap: normal;
  word-break: normal;
  hyphens: manual;
}

/* ---------- column-chart responsive ---------- */

@media (max-width: 1024px) {
  .bitly-column-chart {
    --col-max-h: 200px;
    --col-gap: 20px;
    --col-pct-fs: 20px;
    --col-label-fs: 15px;
  }
}

@media (max-width: 768px) {
  .bitly-column-chart {
    --col-max-h: 160px;
    --col-gap: 12px;
    --col-pad-x: 8px;
    --col-pct-fs: 16px;
    --col-pct-pad-x: 8px;
    --col-pct-pad-y: 2px;
    --col-pct-gap: 8px;
    --col-label-gap: 12px;
    --col-label-fs: 13px;
    --col-bar-border-w: 3px;
  }

  .bitly-column-chart__pct {
    border-width: 2px;
  }
}

@media (max-width: 480px) {
  .bitly-column-chart {
    --col-max-h: 130px;
    --col-gap: 8px;
    --col-pct-fs: 14px;
    --col-pct-pad-x: 6px;
    --col-label-fs: 11px;
  }
}

/* Tablet/desktop viewports: restore H5 label size after max-width rules above. */
@media (min-width: 769px) {
  .bitly-pie-legend {
    --brp-legend-fs: var(--Font-size-H5, 24px);
  }

  .bitly-pie-legend__svg text {
    font-size: var(--Font-size-H5, 24px);
  }

  .bitly-column-chart {
    --col-label-fs: var(--Font-size-H5, 24px);
  }
}

/* =====================================================================
 * banner-cta — orange CTA banner with heading, body, button, image
 * ===================================================================== */

.bitly-banner-cta {
  display: flex;
  align-items: stretch;
  width: 100%;
  background: var(--brp-orange);
  border-radius: 24px;
  overflow: hidden;
}

.bitly-banner-cta__content {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 48px 64px;
}

.bitly-banner-cta--text-only .bitly-banner-cta__content {
  flex: 1 1 100%;
  align-items: flex-start;
  text-align: left;
}

.bitly-banner-cta__heading {
  margin: 0 0 16px 0;
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 700;
  font-size: 28px;
  line-height: 1.2;
}

.bitly-banner-cta__body {
  margin: 0 0 32px 0;
  color: var(--brp-navy);
  font-family: var(--brp-font);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.6;
}

.bitly-banner-cta__body p {
  margin: 0 0 0.75em 0;
}

.bitly-banner-cta__body p:last-child {
  margin-bottom: 0;
}

.bitly-banner-cta__body a {
  color: var(--brp-navy);
  text-decoration: underline;
}

.bitly-banner-cta__body a:hover,
.bitly-banner-cta__body a:focus-visible {
  text-decoration: none;
}

.bitly-banner-cta__button {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  padding: 8px 20px;
  background: var(--brp-cream);
  color: var(--brp-navy);
  border-radius: var(--brp-radius-m);
  font-family: var(--brp-font);
  font-weight: 500;
  font-size: 18px;
  line-height: 24px;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.15s ease, transform 0.15s ease;
}

.bitly-banner-cta__button:hover,
.bitly-banner-cta__button:focus-visible {
  background: #ffffff;
  text-decoration: none;
  transform: translateX(2px);
}

.bitly-banner-cta__button-arrow {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  display: block;
}

.bitly-banner-cta__image {
  flex: 0 0 auto;
  align-self: stretch;
  width: 50%;
  max-width: 750px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.bitly-banner-cta__image img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* ---------- banner-cta responsive ---------- */

@media (max-width: 1024px) {
  .bitly-banner-cta__content {
    padding: 36px 40px;
  }
}

@media (max-width: 768px) {
  .bitly-banner-cta {
    flex-direction: column;
    border-radius: 16px;
  }

  .bitly-banner-cta__content {
    padding: 28px 24px;
    align-items: flex-start;
  }

  .bitly-banner-cta__heading {
    font-size: 22px;
  }

  .bitly-banner-cta__body {
    margin-bottom: 24px;
  }

  .bitly-banner-cta__image {
    order: 1;
    width: 100%;
    max-width: 100%;
    max-height: 240px;
  }
}

@media (max-width: 480px) {
  .bitly-banner-cta__content {
    padding: 24px 20px;
  }

  .bitly-banner-cta__heading {
    font-size: 20px;
    margin-bottom: 12px;
  }

  .bitly-banner-cta__body {
    font-size: 14px;
  }

  .bitly-banner-cta__button {
    font-size: 16px;
    gap: 12px;
    padding: 6px 16px;
  }

  .bitly-banner-cta__image {
    max-height: 180px;
  }
}


/* =====================================================================
 * Scroll-triggered entry animations
 *
 * Pairs with assets/scripts/report-charts-anim.js. The JS:
 *   1. Adds `.bitly-anim-pending` to every off-screen panel on page-load.
 *      This is the trigger that flips elements into their "pre-reveal"
 *      state (clipped / faded out). Panels already on-screen at load
 *      never get this class — they stay in the final visible state with
 *      no animation, since the user is already looking at them.
 *   2. Adds `.is-in-view` to a panel when it scrolls into the viewport
 *      (rootMargin -10% from bottom, threshold 5%), at which point the
 *      `.bitly-anim-pending` class is also removed and the keyframe
 *      animation runs from pre-reveal to the final state.
 *
 * Progressive-enhancement guarantee: when the JS file fails to load (JS
 * disabled, network blocked, syntax error), `.bitly-anim-pending` is
 * never added, panels stay in their final visible state, and the page
 * reads correctly. No invisible-chart bug.
 *
 * Skipped on:
 *   - Panels nested inside `.bitly-report-chart` wrappers (the JS detects
 *     these and never adds the pending class — Highcharts will hydrate
 *     and run its own animation; we don't want a CSS animation flash to
 *     fire just before Highcharts replaces the DOM).
 *   - `prefers-reduced-motion: reduce` — every animated element reverts
 *     to its final state with no motion. (Override at the bottom.)
 *
 * Animation styleguide:
 *   - 700 ms ease-out for "growth" reveals (clip-path).
 *   - 300 ms ease-out for "appear" reveals (opacity + small scale).
 *   - Stagger: 80–120 ms per item depending on element count.
 *   - Easing: cubic-bezier(0.22, 1, 0.36, 1) — Bitly-feeling deceleration.
 *
 * The `--brp-anim-i` custom property lets each item declare its position
 * in the stagger sequence. Items without an explicit value use 0
 * (animate immediately). The `nth-child` selectors below cover the
 * common cases up to N=12; longer lists fall through to delay 0.
 * ===================================================================== */

/* ---------- shared keyframes ---------- */

@keyframes bitly-clip-grow-from-left {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

@keyframes bitly-clip-grow-from-bottom {
  from { clip-path: inset(100% 0 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

@keyframes bitly-fade-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes bitly-fade-pop {
  from { opacity: 0; transform: scale(0.92); }
  to   { opacity: 1; transform: scale(1); }
}

/* ---------- bar-list ---------- */

.bitly-anim-pending .bitly-bar-list .bitly-bar-row__bar {
  clip-path: inset(0 100% 0 0);
}

.bitly-anim-pending .bitly-bar-list .bitly-bar-row__pct {
  opacity: 0;
  transform: scale(0.92);
}

.bitly-report-panel.is-in-view .bitly-bar-list .bitly-bar-row__bar {
  /* `both` (= `backwards` + `forwards`) keeps the `from` keyframe applied
   * during the `animation-delay` window. Without it, the moment JS swaps
   * `.bitly-anim-pending` for `.is-in-view` the element falls back to its
   * natural CSS state (visible) until the delay expires, then snaps to
   * `from` and animates in — perceived as "shows then vanishes then fades
   * in". `both` makes the pre-reveal state hold continuously until the
   * animation actually fires. Same reasoning for every other staggered
   * `.is-in-view` rule below. */
  animation: bitly-clip-grow-from-left 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--brp-anim-i, 0ms);
}

.bitly-report-panel.is-in-view .bitly-bar-list .bitly-bar-row__pct {
  animation: bitly-fade-pop 300ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--brp-anim-i, 0ms) + 600ms);
}

/* Per-row stagger — 80 ms apart so a 10-row chart finishes in ~1.5 s. */
.bitly-bar-list .bitly-bar-row:nth-child(1)  { --brp-anim-i:    0ms; }
.bitly-bar-list .bitly-bar-row:nth-child(2)  { --brp-anim-i:   80ms; }
.bitly-bar-list .bitly-bar-row:nth-child(3)  { --brp-anim-i:  160ms; }
.bitly-bar-list .bitly-bar-row:nth-child(4)  { --brp-anim-i:  240ms; }
.bitly-bar-list .bitly-bar-row:nth-child(5)  { --brp-anim-i:  320ms; }
.bitly-bar-list .bitly-bar-row:nth-child(6)  { --brp-anim-i:  400ms; }
.bitly-bar-list .bitly-bar-row:nth-child(7)  { --brp-anim-i:  480ms; }
.bitly-bar-list .bitly-bar-row:nth-child(8)  { --brp-anim-i:  560ms; }
.bitly-bar-list .bitly-bar-row:nth-child(9)  { --brp-anim-i:  640ms; }
.bitly-bar-list .bitly-bar-row:nth-child(10) { --brp-anim-i:  720ms; }
.bitly-bar-list .bitly-bar-row:nth-child(11) { --brp-anim-i:  800ms; }
.bitly-bar-list .bitly-bar-row:nth-child(12) { --brp-anim-i:  880ms; }

/* ---------- stacked-bar-list ---------- */

.bitly-anim-pending .bitly-stacked-bar-row__seg {
  clip-path: inset(0 100% 0 0);
}

.bitly-anim-pending .bitly-stacked-bar-row__seg-pct {
  opacity: 0;
}

.bitly-report-panel.is-in-view .bitly-stacked-bar-row__seg {
  animation: bitly-clip-grow-from-left 600ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--brp-anim-i, 0ms);
}

.bitly-report-panel.is-in-view .bitly-stacked-bar-row__seg-pct {
  animation: bitly-fade-pop 250ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--brp-anim-i, 0ms) + 500ms);
}

/* Within a row, segments animate left → right with 200 ms gaps. The
 * `--first` modifier means the leftmost segment kicks off the row; the
 * sibling combinator is unreliable here because segments may share the
 * same DOM depth, so we use nth-child instead. */
.bitly-stacked-bar-row__bars .bitly-stacked-bar-row__seg:nth-child(1) { --brp-anim-i:   0ms; }
.bitly-stacked-bar-row__bars .bitly-stacked-bar-row__seg:nth-child(2) { --brp-anim-i: 200ms; }
.bitly-stacked-bar-row__bars .bitly-stacked-bar-row__seg:nth-child(3) { --brp-anim-i: 400ms; }
.bitly-stacked-bar-row__bars .bitly-stacked-bar-row__seg:nth-child(4) { --brp-anim-i: 600ms; }
.bitly-stacked-bar-row__bars .bitly-stacked-bar-row__seg:nth-child(5) { --brp-anim-i: 800ms; }

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

.bitly-anim-pending .bitly-pie-legend__slices > * {
  opacity: 0;
  transform-origin: 50% 50%;
  transform: scale(0.94);
}

.bitly-anim-pending .bitly-pie-legend__badges > * {
  opacity: 0;
}

.bitly-anim-pending .bitly-pie-legend__item {
  opacity: 0;
  transform: translateX(-8px);
}

.bitly-report-panel.is-in-view .bitly-pie-legend__slices > * {
  animation: bitly-fade-pop 500ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--brp-anim-i, 0ms);
}

.bitly-report-panel.is-in-view .bitly-pie-legend__badges > * {
  /* IMPORTANT: opacity-only animation (no `transform` in the keyframe).
   *
   * Each badge `<g>` is positioned with the SVG presentation attribute
   * `transform="translate(X, Y)"`. CSS `transform` (including from a
   * keyframe) OVERRIDES that SVG attribute rather than composing with
   * it — a well-known browser quirk. Using `bitly-fade-pop` (which
   * animates `transform: scale(0.92) → scale(1)`) would zero out every
   * badge's translate, collapsing all five into the SVG origin (0, 0)
   * — the "only the 2% badge shows up in the top-left corner" bug we
   * hit when a panel sits inside an inactive Foundation `.tabs-panel`
   * (which is `display: none` at page load, so the animation JS treats
   * the panel as off-screen and queues the keyframe to fire on tab
   * activation; on a panel that's on-screen at load the animation
   * never runs and the bug is invisible).
   *
   * `bitly-fade-opacity` only animates opacity, leaving the SVG
   * translate untouched. */
  animation: bitly-fade-opacity 300ms cubic-bezier(0.22, 1, 0.36, 1) both;
  /* Badges fade in once all slices have settled (~slice count * 100 ms + 500). */
  animation-delay: calc(var(--brp-anim-pie-badges, 800ms));
}

@keyframes bitly-fade-opacity {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.bitly-report-panel.is-in-view .bitly-pie-legend__item {
  animation: bitly-fade-rise 400ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--brp-anim-i, 0ms) + 400ms);
}

/* Slice stagger (clockwise reveal). */
.bitly-pie-legend__slices > *:nth-child(1)  { --brp-anim-i:   0ms; }
.bitly-pie-legend__slices > *:nth-child(2)  { --brp-anim-i: 100ms; }
.bitly-pie-legend__slices > *:nth-child(3)  { --brp-anim-i: 200ms; }
.bitly-pie-legend__slices > *:nth-child(4)  { --brp-anim-i: 300ms; }
.bitly-pie-legend__slices > *:nth-child(5)  { --brp-anim-i: 400ms; }
.bitly-pie-legend__slices > *:nth-child(6)  { --brp-anim-i: 500ms; }
.bitly-pie-legend__slices > *:nth-child(7)  { --brp-anim-i: 600ms; }
.bitly-pie-legend__slices > *:nth-child(8)  { --brp-anim-i: 700ms; }

/* Legend list item stagger. */
.bitly-pie-legend__item:nth-child(1)  { --brp-anim-i:   0ms; }
.bitly-pie-legend__item:nth-child(2)  { --brp-anim-i:  80ms; }
.bitly-pie-legend__item:nth-child(3)  { --brp-anim-i: 160ms; }
.bitly-pie-legend__item:nth-child(4)  { --brp-anim-i: 240ms; }
.bitly-pie-legend__item:nth-child(5)  { --brp-anim-i: 320ms; }
.bitly-pie-legend__item:nth-child(6)  { --brp-anim-i: 400ms; }
.bitly-pie-legend__item:nth-child(7)  { --brp-anim-i: 480ms; }
.bitly-pie-legend__item:nth-child(8)  { --brp-anim-i: 560ms; }

/* ---------- bar-tiles ---------- */

.bitly-anim-pending .bitly-bar-tile {
  clip-path: inset(100% 0 0 0);
}

.bitly-report-panel.is-in-view .bitly-bar-tile {
  animation: bitly-clip-grow-from-bottom 600ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--brp-anim-i, 0ms);
}

/* Tile stagger across the panel — gives a "wave" of fills sweeping left
 * to right, then row 2 picks up where row 1 stopped. */
.bitly-bar-tile:nth-child(1)  { --brp-anim-i:   0ms; }
.bitly-bar-tile:nth-child(2)  { --brp-anim-i:  90ms; }
.bitly-bar-tile:nth-child(3)  { --brp-anim-i: 180ms; }
.bitly-bar-tile:nth-child(4)  { --brp-anim-i: 270ms; }
.bitly-bar-tile:nth-child(5)  { --brp-anim-i: 360ms; }
.bitly-bar-tile:nth-child(6)  { --brp-anim-i: 450ms; }
.bitly-bar-tile:nth-child(7)  { --brp-anim-i: 540ms; }
.bitly-bar-tile:nth-child(8)  { --brp-anim-i: 630ms; }

/* ---------- column-chart ---------- */

.bitly-anim-pending .bitly-column-chart__bar {
  clip-path: inset(100% 0 0 0);
}

.bitly-anim-pending .bitly-column-chart__pct {
  opacity: 0;
  transform: translateY(6px);
}

.bitly-report-panel.is-in-view .bitly-column-chart__bar {
  animation: bitly-clip-grow-from-bottom 800ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--brp-anim-i, 0ms);
}

.bitly-report-panel.is-in-view .bitly-column-chart__pct {
  animation: bitly-fade-rise 350ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--brp-anim-i, 0ms) + 700ms);
}

/* Column stagger — each column starts 120 ms after the previous. */
.bitly-column-chart__col:nth-child(1) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(1) .bitly-column-chart__pct  { --brp-anim-i:   0ms; }
.bitly-column-chart__col:nth-child(2) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(2) .bitly-column-chart__pct  { --brp-anim-i: 120ms; }
.bitly-column-chart__col:nth-child(3) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(3) .bitly-column-chart__pct  { --brp-anim-i: 240ms; }
.bitly-column-chart__col:nth-child(4) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(4) .bitly-column-chart__pct  { --brp-anim-i: 360ms; }
.bitly-column-chart__col:nth-child(5) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(5) .bitly-column-chart__pct  { --brp-anim-i: 480ms; }
.bitly-column-chart__col:nth-child(6) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(6) .bitly-column-chart__pct  { --brp-anim-i: 600ms; }
.bitly-column-chart__col:nth-child(7) .bitly-column-chart__bar,
.bitly-column-chart__col:nth-child(7) .bitly-column-chart__pct  { --brp-anim-i: 720ms; }

/* ---------- banner-cta ---------- */

.bitly-anim-pending .bitly-banner-cta {
  opacity: 0;
  transform: translateY(12px);
}

.bitly-report-panel.is-in-view .bitly-banner-cta {
  animation: bitly-fade-rise 500ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* ---------- reduced motion override ----------
 * Anyone with the OS-level reduced-motion preference (Mac System Settings >
 * Accessibility > Display > Reduce motion, Windows equivalent, etc.) sees
 * the chart in its final state with no animation. We also short-circuit
 * the JS so `.is-in-view` is added immediately on page-load instead of on
 * scroll; the animation properties below ensure the final-state styles
 * apply regardless. */

@media (prefers-reduced-motion: reduce) {
  .bitly-bar-list .bitly-bar-row__bar,
  .bitly-stacked-bar-row__seg,
  .bitly-bar-tile,
  .bitly-column-chart__bar {
    clip-path: none !important;
    animation: none !important;
  }

  .bitly-bar-list .bitly-bar-row__pct,
  .bitly-stacked-bar-row__seg-pct,
  .bitly-pie-legend__slices > *,
  .bitly-pie-legend__badges > *,
  .bitly-pie-legend__item,
  .bitly-column-chart__pct,
  .bitly-banner-cta {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
}
