@layer components {
  /* A zero-based column chart in plain CSS. The chart sets --chart-max (the
     value the tallest column would reach) and each bar sets --value; bar
     heights scale linearly against a fixed plot height so the geometry never
     lies about the numbers. */
  .bar-chart {
    --plot-height: 12rem;

    list-style: none;
    padding: 0;
    margin-top: var(--space-4);
    /* Labels hang below the plot, absolutely positioned — in-flow labels of
       unequal height would lift their bars off the shared baseline. This
       reserves the room they hang into (up to three label lines), plus clear
       air before the prose that follows. */
    margin-bottom: calc(var(--space-8) + var(--space-4));
    display: flex;
    align-items: flex-end;
    gap: var(--space-2);
  }

  .bar-chart-title {
    margin-top: var(--space-4);
    font-weight: 600;
  }

  .bar-chart-title + .bar-chart {
    margin-top: var(--space-2);
  }

  .bar-chart__item {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    text-align: center;
    font-size: var(--text-sm);
  }

  .bar-chart__bar {
    width: 100%;
    height: calc(var(--value) / var(--chart-max) * var(--plot-height));
    background: var(--color-accent);
    border-radius: var(--radius) var(--radius) 0 0;
  }

  /* A bar whose reading is not final is hatched in the same accent as a
     measured one, so the two sit on one scale and the reader can still see
     which reading was actually taken. Do not swap the hatch for a second hue:
     the bars are one series, and a second hue would read as a second one.
     The two modifiers differ in what is unfinished, and not in how they draw:
     --projected estimates a reading nobody has taken, and --unsettled is a
     real reading over a window still open. */
  .bar-chart__bar--projected,
  .bar-chart__bar--unsettled {
    background: repeating-linear-gradient(
      45deg,
      color-mix(in srgb, var(--color-accent) 55%, transparent) 0 3px,
      transparent 3px 7px
    );
  }

  .bar-chart__value {
    color: var(--color-ink-muted);
  }

  .bar-chart__label {
    position: absolute;
    top: calc(100% + var(--space-1));
    left: 0;
    right: 0;
    color: var(--color-ink-muted);
    line-height: var(--leading-tight);
    /* Column-width labels wrap; long set names carry soft hyphens at their
       safe break points rather than relying on `hyphens: auto`, which needs
       a hyphenation dictionary not every browser build ships. */
  }

  /* Below this width the staircase's columns are too narrow for their set
     names — labels collide — so the chart flips to horizontal bars: label,
     bar, value as one row each. The dense variant keeps its vertical form;
     hairline bars with sparse year labels still fit. (A raw length because
     media queries cannot read custom properties.) */
  @media (max-width: 40rem) {
    .bar-chart:not(.bar-chart--dense) {
      display: grid;
      gap: var(--space-2);
      margin-bottom: var(--space-4);
    }

    .bar-chart:not(.bar-chart--dense) .bar-chart__item {
      display: grid;
      grid-template-columns: minmax(7rem, auto) 1fr auto;
      align-items: center;
      gap: var(--space-2);
      text-align: left;
    }

    .bar-chart:not(.bar-chart--dense) .bar-chart__label {
      position: static;
      grid-column: 1;
      grid-row: 1;
    }

    /* The bar's percentage width resolves against its own grid track, so
       every bar shares one scale and the geometry stays honest. */
    .bar-chart:not(.bar-chart--dense) .bar-chart__bar {
      grid-column: 2;
      grid-row: 1;
      width: calc(var(--value) / var(--chart-max) * 100%);
      height: var(--space-3);
      border-radius: 0 var(--radius) var(--radius) 0;
    }

    .bar-chart:not(.bar-chart--dense) .bar-chart__value {
      grid-column: 3;
      grid-row: 1;
    }
  }

  /* Dense variant for long series (one bar per year): hairline gaps, labels
     only where the view emits them. Bars this thin drop the rounded ends —
     at 2px of gap they read as noise. */
  .bar-chart--dense {
    gap: calc(var(--space-1) / 2);
    /* Dense labels are a single line, so less room needs reserving. */
    margin-bottom: var(--space-7);
  }

  .bar-chart--dense .bar-chart__bar {
    border-radius: 0;
  }

  /* A year must never wrap; it may overhang its hairline column because
     labeled years have unlabeled neighbors. */
  .bar-chart--dense .bar-chart__label {
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    white-space: nowrap;
  }

  /* A wider seam ahead of a bar that opens a new regime. */
  .bar-chart__item--regime {
    margin-left: var(--space-3);
  }

  /* Each era's overall rate as a reference line over its bars, drawn
     per-item at the height --era-avg so the line follows the regime and
     breaks naturally at the seams. */
  .bar-chart--dense .bar-chart__item::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(var(--era-avg) / var(--chart-max) * var(--plot-height));
    border-top: 2px solid var(--color-ink);
  }

  /* An unsettled bar carries no reference line, because it is outside the era
     rate the line draws. Give it one and the chart says those years are in
     the average, which is the claim the hatch exists to deny. */
  .bar-chart--dense .bar-chart__item--unsettled::after {
    content: none;
  }

  /* The second axis row naming the regimes, sitting above the plot: spans
     sized by how many years each era covers, so the brackets line up over
     their bars, opening downward toward them. */
  .bar-chart-eras {
    display: flex;
    gap: var(--space-3);
    font-size: var(--text-sm);
    color: var(--color-ink-muted);
    text-align: center;
  }

  .bar-chart-eras span {
    flex: var(--years);
    border-bottom: 1px solid var(--color-border);
    padding-bottom: var(--space-1);
  }
}
