@layer components {
  /* Tabs Component
     ========================================================================== */

  .tabs {
    display: flex;
    justify-content: center;
    align-items: center;
    column-gap: var(--column-gap, var(--inline-space));
    border-block-end: var(--border);

    .tab {
      display: flex;
      border: var(--border);
      border-radius: var(--border-radius) var(--border-radius) 0 0;
      block-size: 3rem;
      justify-content: center;
      align-items: center;
      /* Room for the Shift-revealed digit keycap beside the label. */
      column-gap: 0.6ch;
      padding-inline: 1.5ch;
      margin-block-end: calc(var(--border-size) * -1);
      background-color: var(--color-gray-light);
      color: var(--color-ink-dark);

      &:hover {
        color: var(--color-ink-dark);
      }
    }

    .tab--active {
      border-block-end-color: var(--color-bg);
      background-color: var(--color-bg);
    }
  }

  /* Tab content that breaks out wider than the page's medium width (the embedded
     evaluation tab, so its ranking table isn't cramped). The header and tab strip
     stay at medium width on every tab, so switching tabs never reflows them; only
     this content widens. `margin-inline: calc(50% - half-target)` centers a child
     of `target` width on the parent's centre axis, going negative — and so
     breaking out symmetrically — once `target` exceeds the medium parent. `95vw`
     caps it to the viewport on small screens; the inner `.overflow-x` table
     wrapper still scrolls if even that is too narrow. */
  .tab-content--wide {
    /* Must min() against --main-available: with the dock or sidebar open the
       centre track shrinks, and a plain 95vw breakout would push content past
       the overflow-clipped root (see layout.css). */
    --tab-content-width: min(150ch, 95vw, var(--main-available, 100vw));

    inline-size: var(--tab-content-width);
    margin-inline: calc(50% - var(--tab-content-width) / 2);

    @media (max-width: 70ch) {
      --tab-content-width: 100%;

      margin-inline: 0;
    }
  }

  /* The shared tab strip partial wraps every `.tabs` in `.tabs-scroll` so a
     strip can overflow (e.g. the catalogue picker). Scroll behavior lives on this wrapper so
     `.tabs` itself keeps rendering normally — in particular, `.tab`'s
     `margin-block-end: -1.5px` (which lets the active tab's bg merge into the
     baseline border) is not clipped by the scroll container's overflow, because
     `padding-block-end` absorbs those 1.5px into the wrapper's own padding box.
     `margin-block-end` then compensates visually so subsequent content isn't
     pushed down. `safe center` keeps tabs centered while they fit and falls back
     to start-alignment when they overflow, so the first tab stays reachable. */
  .tabs-scroll {
    overflow-x: auto;
    overflow-y: clip;
    padding-block-end: var(--border-size);
    margin-block-end: calc(var(--border-size) * -1);
    scrollbar-width: thin;
    scrollbar-color: var(--color-gray) transparent;

    .tabs {
      justify-content: safe center;
      inline-size: max-content;
      min-inline-size: 100%;
    }

    .tab {
      flex-shrink: 0;
    }
  }

  /* Turbo Frame Loading Indicator
     ========================================================================== */
  turbo-frame#tab_content {
    position: relative;
    min-block-size: 50vh; /* Maintain minimum height to prevent footer jumping */
  }

  /* Show spinner when turbo frame is loading */
  turbo-frame#tab_content[aria-busy="true"]::after {
    --mask: no-repeat radial-gradient(#000 68%, #0000 71%);
    --dot-size: 1.75em;

    content: "";
    position: absolute;
    inset: 50% 50%;
    transform: translate(-50%, -50%);
    inline-size: var(--dot-size);
    aspect-ratio: 8/5;
    background: currentColor;
    -webkit-mask: var(--mask), var(--mask), var(--mask);
    -webkit-mask-size: 28% 45%;
    animation: submitting 1.3s infinite linear;
    z-index: 10;
  }

  /* Optional: Reduce opacity of content while loading */
  turbo-frame#tab_content[aria-busy="true"] > * {
    opacity: 0.3;
    transition: opacity 200ms;
  }
}
