/* Tether change history — one column of commit rows connected by a timeline
   spine, since the content really is chronological and grouped. No motion:
   the spine is a static structural cue, not a state change, so there is
   still nothing here for prefers-reduced-motion to disable. */

.log__timeline {
  --tl-pad: var(--s-6);
  --tl-spine: 2px;
  --tl-spine-x: 5px;
  --tl-dot: 10px;
  position: relative;
  /* Room for the spine + dot at the left of every group, without touching
     each group's own internal padding (.entries stays exactly as wide). */
  padding-left: var(--tl-pad);
}

.log__timeline::before {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: var(--tl-spine-x);
  width: var(--tl-spine);
  border-radius: var(--r-pill);
  background: linear-gradient(
    to bottom,
    var(--pass-line) 0%,
    var(--hairline-strong) 92%,
    transparent 100%
  );
}

.log__timeline .group {
  position: relative;
}
/* A jump lands the heading below the sticky nav, not under it. */
.log__timeline .group h2 { scroll-margin-top: calc(var(--tap) + var(--s-6)); }
.log__timeline .group h2:focus-visible { outline-offset: 4px; }

/* Still h2::before -- tests/test_web_changelog_download.py reads the dot at
   getComputedStyle(h2, '::before') specifically, so the anchor stays there.
   The h2 is position:static, so the dot is placed against .group (position:
   relative), whose left edge sits exactly --tl-pad right of the timeline. The
   dot centre must land on the spine centre: spine-x + spine/2 - dot/2 - pad.
   The earlier offset also subtracted .group's padding on the false premise that
   the h2 was the positioned box, which parked every dot ~24px left of the spine
   (measured at 1440 and 390: dot centre x=302 vs spine centre x=326). */
.log__timeline .group h2::before {
  content: "";
  position: absolute;
  left: calc(var(--tl-spine-x) + var(--tl-spine) / 2 - var(--tl-dot) / 2 - var(--tl-pad));
  top: calc(0.55em + var(--group-pad));
  width: var(--tl-dot);
  height: var(--tl-dot);
  border-radius: 50%;
  background: var(--surface-1);
  border: 2px solid var(--pass-line);
  z-index: 1;
}

/* The open/absent group closes the spine with a neutral, not a "measured",
   marker: it lists what has NOT shipped, so a --pass dot would misstate it. */
.log__timeline .group--open h2::before {
  border-color: var(--hairline-strong);
  background: var(--surface-1);
}

.hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0 0 var(--s-4);
}

.log {
  max-width: 54rem;
  margin: 0 auto;
  padding: var(--s-7) var(--gutter) var(--s-8);
  min-width: 0;
}

.log__header { margin-bottom: var(--s-7); }

.log h1 {
  font-size: var(--t-display);
  line-height: 1.08;
  letter-spacing: -0.03em;
  text-wrap: balance;
  max-width: 22ch;
  margin-bottom: var(--s-3);
}

.log__sub {
  text-wrap: pretty;
  font-size: var(--t-15);
  color: var(--text-2);
  line-height: 1.55;
  margin-bottom: var(--s-4);
}

.log__facts {
  margin-bottom: var(--s-8);
  padding: var(--s-5);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  box-shadow: var(--depth-2);
}

.log__facts h2 {
  font-size: var(--t-18);
  margin-bottom: var(--s-4);
}

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--s-3) var(--s-5);
  margin: 0 0 var(--s-4);
}

.facts > div {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  min-width: 0;
}

.facts dt {
  font-size: var(--t-12);
  color: var(--text-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.facts dd {
  margin: 0;
  font-size: var(--t-18);
  color: var(--text-1);
}

.log__note {
  font-size: var(--t-13);
  color: var(--text-2);
  line-height: 1.55;
}

/* Real card boundary per group: the timeline spine marks a group's position in
   the sequence but drew no edge around the group ITSELF, so eight groups in a
   row read as one unbroken scroll broken only by heading text and whitespace.
   --e-1 (not --e-2/--e-3) keeps this below .log__facts and .shape, which are
   the page's one deliberately-heavier artifact; a --pass-line accent on the
   open/absent group would misstate it as "measured" the way its timeline dot
   already avoids, so that group keeps the neutral hairline instead. */
.group {
  --group-pad: var(--s-5);
  margin-bottom: var(--s-6);
  padding: var(--group-pad);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  box-shadow: var(--depth-1);
}
.group--open {
  border-color: var(--hairline-strong);
}

.group h2 {
  font-size: var(--t-24);
  line-height: 1.22;
  margin-bottom: var(--s-2);
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

/* Real inline SVG per group (CSP-legal markup, same technique as
   web/landing/styles.css .feature__icon), one distinct mark per theme rather
   than eight identical headings with only prose to tell them apart. */
.group__icon {
  flex: none;
  width: 22px;
  height: 22px;
  color: var(--pass);
}
.group--open .group__icon { color: var(--text-3); }

.group__lead {
  font-size: var(--t-13);
  color: var(--text-2);
  line-height: 1.6;
  margin-bottom: var(--s-4);
  max-width: var(--measure);
}

.entries {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--hairline);
  overflow: hidden;
}

.entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s-3);
  align-items: baseline;
  padding: var(--s-3) var(--s-4);
  background: var(--surface-1);
  min-width: 0;
}

.entry__line {
  margin: 0;
  font-size: var(--t-15);
  color: var(--text-1);
  line-height: 1.5;
  max-width: var(--measure);
  overflow-wrap: anywhere;
}

/* The commit code is a small, quiet permalink: evidence for whoever wants to check, not a
   call to action. Underline on hover/focus only, so it never competes with the line. */
.entry__sha {
  font-size: var(--t-12);
  color: var(--text-3);
  text-decoration: none;
  border-bottom: 1px dotted var(--hairline-strong);
  padding: 2px 0;
}
.entry__sha:hover { color: var(--text-1); border-bottom-style: solid; }
.entry:target { background: var(--tint-info); }
/* The permalink is a 266x23 strip at 390px. Give it the full tap height wherever the
   pointer is coarse or the viewport is narrow; the dotted underline stays on the text. */
@media (pointer: coarse), (max-width: 34rem) {
  .entry__sha { display: inline-flex; align-items: center; min-height: var(--tap); padding: 0; border-bottom: 0; }
  .entry__sha:hover { text-decoration: underline; }
}

.group h2 time { font: inherit; }

.group--open .open-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-2);
}

.group--open .open-list li {
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--fail);
  border-radius: var(--r-sm);
  background: var(--fail-dim);
  font-size: var(--t-13);
  color: var(--text-2);
  line-height: 1.5;
}

/* shared.css sets a 2px ring; this page needs the 3px AA target. */
.log a:focus-visible,
.site-nav a:focus-visible,
.pagefoot a:focus-visible,
.skip-link:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 3px;
}
/* Same specificity + later source order was clobbering shared.css's
   .btn--primary:focus-visible outline-color fix (--info on an --info fill
   measures ~1:1). Restore it here. */
.site-nav a.btn--primary:focus-visible {
  outline-color: var(--focus-ring);
}

@media (max-width: 34rem) {
  /* A phone gives the entries the width the spine gutter and card padding used to
     eat (content column measured 262px of 390). Spine and dot follow the variables. */
  .log__timeline { --tl-pad: var(--s-5); --tl-spine-x: 3px; }
  .group { --group-pad: var(--s-4); }
  .entry { grid-template-columns: 1fr; gap: var(--s-1); }
}


/* Depth pass: the facts card carries the shared lit edge. */
.log__facts { box-shadow: var(--depth-2); }


/* Filter + jump rail (web/changelog/changelog.js). Built by script, so none of this
   renders without JavaScript. `display:grid` on .entry/.group would beat the UA
   [hidden] rule, so hidden is restated here. */
.entry[hidden],
.group[hidden] { display: none; }

.log__filter {
  max-width: var(--page);
  margin: 0 auto var(--s-5);
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  box-shadow: var(--depth-1);
}
.log__filter-label {
  display: block;
  font-size: var(--t-13);
  font-weight: 560;
  color: var(--text-2);
  margin-bottom: var(--s-2);
}
.log__filter-input {
  width: 100%;
  min-height: var(--tap);
  padding: 10px var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  color: var(--text-1);
  font: inherit;
  font-size: var(--t-13);
}
.log__filter-input::placeholder { color: var(--text-3); }
.log__filter-input:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  border-color: var(--info);
}
.log__filter-help,
.log__filter-count {
  margin: var(--s-2) 0 0;
  font-size: var(--t-12);
  line-height: 1.5;
  color: var(--text-3);
}
.log__filter-count:empty { display: none; }

.log__empty { margin: 0 auto var(--s-5); max-width: var(--page); }
.log__clear { margin-left: var(--s-2); min-height: var(--tap); }

}


/* Jump rail (web/changelog/changelog.js): the page is ~5000px of 33 entries in 7
   groups; the rail names each group with its live count so a visitor can go to one
   without scrolling the spine. Built by script, so nothing renders without JS. */
.log__jump {
  max-width: var(--page);
  margin: 0 auto var(--s-5);
}
.log__jump-title {
  margin: 0 0 var(--s-2);
  font-size: var(--t-12);
  font-weight: 560;
  color: var(--text-2);
}
.log__jump-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}
.log__jump[hidden],
.log__jump-list li[hidden] { display: none; }
.log__jump-link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding: 0 var(--s-3);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-pill);
  background: var(--surface-1);
  color: var(--text-2);
  font-size: var(--t-12);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.log__jump-link:hover { color: var(--text-1); border-color: var(--info-line); background: var(--surface-2); }
.log__jump-count {
  font-family: var(--mono);
  font-size: var(--t-12);
  color: var(--text-3);
}
@media (prefers-reduced-motion: reduce) {
  .log__jump-link { transition-duration: 0s; }
}

/* Category chips (web/changelog/changelog.js): toggle buttons, one pressed at a time. */
.log__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0 0 var(--s-3);
}
.log__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding: 0 var(--s-3);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-pill);
  background: var(--surface-1);
  color: var(--text-2);
  font: inherit;
  font-size: var(--t-12);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.log__chip:hover { color: var(--text-1); border-color: var(--info-line); background: var(--surface-2); }
.log__chip[aria-pressed="true"] {
  color: var(--text-1);
  border-color: var(--info);
  background: var(--tint-info);
}
.log__chip:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}
.log__chip-count { font-family: var(--mono); color: var(--text-3); }
.log__chip[aria-pressed="true"] .log__chip-count { color: var(--text-2); }
@media (prefers-reduced-motion: reduce) {
  .log__chip { transition-duration: 0s; }
}
