/* ---------- drilldown: back to where you came from ---------- */
/* Sits left of the search box, at the size of an icon rather than a control —
   it's a way out of the page, not one of the things the page is set to. It's
   only drawn when there is somewhere to go back to, so there is no disabled
   state to style. */
.backbtn {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--panel); color: var(--muted); cursor: pointer;
}
.backbtn svg { width: 15px; height: 15px; }
.backbtn:hover { color: var(--text); border-color: var(--accent); }

/* ---------- drilldown: search-and-select ---------- */
/* Hand-rolled rather than a <datalist>: 1,200 options make the native popup
   sluggish, it can't show the activity counts that make the right person
   obvious, and its styling is untouchable. */
.combo { position: relative; }
.combo input { min-width: 280px; }
.combo-pop {
  position: absolute; z-index: 20; top: calc(100% + 4px); left: 0;
  min-width: 320px; max-height: 320px; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.28);
  scrollbar-width: thin;
}
:root[data-theme="light"] .combo-pop { box-shadow: 0 8px 24px rgba(31,35,40,.12); }
.combo-pop[hidden] { display: none; }
.combo-opt {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 11px; cursor: pointer; white-space: nowrap;
}
.combo-opt .n { overflow: hidden; text-overflow: ellipsis; }
.combo-opt .c { margin-left: auto; color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.combo-opt:hover { background: var(--panel-2); }
/* Both can be true at once — the keyboard cursor sits on one row while the
   mouse rests on another — so the selected row needs something the hover
   doesn't have, or the popup shows two identical highlights and neither says
   which one Enter will pick. */
.combo-opt[aria-selected="true"] {
  background: var(--panel-2);
  box-shadow: inset 2px 0 0 var(--accent);
}
.combo-opt mark { background: none; color: var(--accent); font-weight: 600; }
.combo-none { padding: 12px; color: var(--muted); font-size: 12px; }

/* ---------- drilldown: subject header ---------- */
/* Avatar, then name over meta, then the GitHub link pushed to the far edge.
   The name and the dates were siblings of the button before, which put the
   two halves of one sentence on either side of an unrelated control. */
.subject { display: flex; align-items: center; gap: 13px; margin-bottom: 16px; }
.subject .idcard { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.subject h2 { margin: 0; font-size: 20px; font-weight: 600; line-height: 1.15; overflow-wrap: anywhere; }
.subject .dates { color: var(--muted); font-size: 12px; }
.subject .ghost { margin-left: auto; flex: none; align-self: center; }

/* The team strip travels with the GitHub link rather than trailing the name:
   the `auto` margin moves to whichever of the two comes first, so the pair
   sits together at the far edge whether or not there are any badges. */
.subject .teams {
  margin-left: auto; flex: none;
  display: flex; align-items: center; gap: 7px;
}
.subject .teams + .ghost { margin-left: 0; }

/* A span rather than the <img> itself, because the tooltip is a pseudo-element
   and images can't have those. */
.teambadge { position: relative; display: block; width: 30px; height: 30px; }
.teambadge img {
  display: block; width: 100%; height: 100%;
  filter: drop-shadow(0 1px 1px rgb(0 0 0 / .28));
}
.teambadge::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 7px); left: 50%;
  transform: translateX(-50%);
  padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
  font-size: 11px; line-height: 1.4; white-space: nowrap;
  box-shadow: 0 4px 12px rgb(0 0 0 / .3);
}
.teambadge::before {
  content: ""; position: absolute; bottom: calc(100% + 2px); left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--border);
}
.teambadge::after, .teambadge::before {
  opacity: 0; pointer-events: none; transition: opacity .12s;
  z-index: 5;
}
.teambadge:hover::after, .teambadge:hover::before { opacity: 1; }
@media (max-width: 640px) {
  .subject { flex-wrap: wrap; }
  .subject .teams { margin-left: 0; }
  .subject .teams + .ghost { margin-left: 0; }
}
/* ---------- drilldown: paired stat boxes ---------- */
/* Two related rankings read as a comparison when they're side by side and as
   a sequence when they're stacked. These are comparisons. */
.duo { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 900px) { .duo { grid-template-columns: 1fr; } }
/* Same two boxes, one above the other. A 4-column overview card is too
   narrow to put two ranked lists beside each other — the repo names ellipsis
   down to nothing — so it stacks there and pairs up in the expanded view,
   where there's a full 12 columns to spend. Explicit rows rather than `auto`:
   inside a `fill` body the pair has to split the height it's given, not ask
   for the height its content wants. */
.duo.stacked { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
.duo-box {
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel-2);
  display: flex; flex-direction: column; min-width: 0;
}
.duo-box > h3 {
  margin: 0; padding: 9px 12px;
  font-size: 12px; font-weight: 600;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: baseline; gap: 8px;
}
.duo-box > h3 .n { margin-left: auto; color: var(--muted); font-weight: 400; font-size: 11px; }
.duo-box > .scroll { padding: 11px 12px; flex: 1; min-height: 0; }

/* Lists are uncapped now, so long ones scroll inside their box instead of
   making the page metres tall. */
.scroll { overflow-y: auto; scrollbar-width: thin; }
.scroll.tall { max-height: 620px; }
.scroll.short { max-height: 260px; }

/* A list card should take its height *from* the chart beside it, never give
   height to the row. Flexbox can't do that: a flex child still reports its
   content size to the grid, so a 400-row list made its own row 6,000px tall
   and dragged the chart with it.

   Taking the content out of flow with `position:absolute` is what actually
   works — an absolutely-positioned child contributes nothing to layout, so
   the row is sized purely by its other card and the list scrolls inside
   whatever that turns out to be. `min-height` is the floor for when there is
   no other card, which is every card once the grid collapses to one column
   below 1080px. */
.card .body.fill { position: relative; min-height: 260px; padding: 0; }
.card .body.fill > * { position: absolute; inset: 14px; }
.card .body.fill > .scroll { overflow-y: auto; max-height: none; }
.card .body.fill > .duo { overflow: hidden; }
.card .body.fill .duo-box { min-height: 0; }
.card .body.fill .duo-box > .scroll { flex: 1; min-height: 0; max-height: none; }

/* ---------- drilldown: head to head ---------- */
/* The lineup reads as a legend and a set of controls at once: each chip's dot is
   the colour that subject keeps in every chart on the card, and the × is how you
   drop it. The first chip is the page's own subject and has no ×. */
.vs-chips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.vs-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 8px 5px 9px; font-size: 12px;
  border: 1px solid var(--border); border-radius: 999px; background: var(--panel-2);
}
.vs-chip i { width: 9px; height: 9px; border-radius: 50%; flex: none; }
/* The dot and the face are both leading markers; without this they sit a full
   gap apart and the chip reads as three things instead of one name. */
.vs-chip:has(.pfp) { gap: 6px; padding-left: 7px; }
.vs-chip[data-pinned] { border-color: var(--accent); }
.vs-you { color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: .04em; }
.vs-x {
  border: 0; background: none; color: var(--muted); cursor: pointer;
  font-size: 14px; line-height: 1; padding: 0 1px;
}
.vs-x:hover { color: var(--bad); }
.vs-add input { min-width: 200px; }

/* Room for the picker's popup.
   ---------------------------------------------------------------------------
   This one is drawn inside the card rather than in the layer at the end of
   <body> the Dream Panel's popups use, because it belongs to an input that has
   to keep the caret — and a card is `overflow: hidden` so its table can have
   rounded corners. So the list was being sliced off at the card's bottom edge,
   which on a card holding nothing but a chip row meant most of it.

   The card makes room instead, while the popup is open and not otherwise. The
   list is absolutely positioned, so this reserves empty space below the chips
   rather than moving anything: the table and charts under it stay where they
   were, and the card simply gets taller for as long as you're picking.

   Two heights, because the list itself has two lengths — see VS_LIMIT. On the
   card it offers three rows and needs very little; on its own tab it offers
   forty and scrolls at 320. */
.card .body:has(> .vs-chips .combo-pop:not([hidden])) { min-height: 400px; }
.grid .card .body:has(> .vs-chips .combo-pop:not([hidden])) { min-height: 210px; }

/* A comparison table is read across, not down, so the row label has to stay put
   while the eye moves along it — hence the sticky first column rather than the
   usual free-scrolling table. */
table.vs td:first-child, table.vs th:first-child { position: sticky; left: 0; background: var(--panel); }
table.vs .vs-group td {
  padding-top: 16px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted); background: var(--panel);
}
table.vs .vs-head { display: inline-flex; align-items: center; gap: 6px; }
table.vs .vs-head i { width: 8px; height: 8px; border-radius: 50%; }
/* Leading, not winning — see the note under the table. Weight and a tint rather
   than a colour, because half these rows are volumes where "more" is neither
   good nor bad. */
table.vs td.lead { font-weight: 600; color: var(--text); background: var(--panel-2); }

/* ---------- drilldown: per-bucket axis ---------- */
/* Rendered as HTML under the chart rather than as SVG <text>. The charts use
   preserveAspectRatio="none", which scales x and y differently — anything
   drawn inside gets squashed horizontally as the card narrows, which is
   survivable for six labels and unreadable for twenty-four. */
/* Two horizontal lines rather than one rotated one. At 24 buckets a single
   line of "Aug '26" doesn't fit the slot, and rotating it makes the axis
   hard to read; stacking the month over the year keeps every label upright
   and halves the width it needs. There is still one grid column per bucket —
   xAxis() blanks the ones it thins out, so the labels stay under their bars. */
.xaxis { display: grid; margin-top: 6px; align-items: start; }
.xaxis span {
  font-size: 10px; line-height: 1.25; color: var(--muted);
  justify-self: center; text-align: center; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.xaxis .yr { display: block; opacity: .6; }
