/* Archive — the reader companion. The core surface of the site.

   The hard rule: a record is ABSENT until its first state's chapter is at or
   below the chapter being viewed. No teasers, no silhouettes, no locked
   cards, no counts that include the future. archive.js enforces the logic;
   this file only ever styles what already passed that test.

   Three animations exist here and nowhere else on the page: seamReveal (the
   identity-seam clip-path sweep), seamGlow (the one-time amendment ring) and
   the portrait crossfade transition on the detail dialog. Everything else on
   this page is instant. prefers-reduced-motion already kills all of it via
   site.css's global reset. */

/* — shared resets for JS-built interactive rows — */
.archive-btn-reset {
  background: transparent; border: none; color: inherit; font: inherit;
  text-align: left; cursor: pointer; padding: 0; display: block;
}

/* — not-started state — */
.archive-empty {
  flex: 1; display: grid; place-items: center; padding: 40px 20px;
}
.archive-empty__inner {
  max-width: 520px; text-align: center;
  display: flex; flex-direction: column; gap: 16px; align-items: center;
}
/* These three were <h6> for the LOOK, which put a level-6 heading above the
   page's only <h1> and skipped a level inside the evidence list. The rank now
   follows the document and the look lives in the class, so the two can never
   fight again. */
.archive-empty__kicker,
.archive-rail__label,
.archive-since__label {
  /* No font-family here on purpose: the THEME owns which face a label
     wears, and this file loads after it. Setting it here would silently
     outrank the theme's mono file-heading rule. */
  font-size: 13px;
  font-weight: var(--font-heading-weight);
  line-height: 1.12;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.archive-empty__kicker { color: var(--color-accent); margin: 0; }
.archive-empty__title {
  font-size: clamp(28px, 4vw, 40px); margin: 0; text-wrap: balance;
}
.archive-empty__body {
  font-size: 14.5px; line-height: 1.7; color: var(--color-neutral-400); margin: 0;
}
.archive-empty__cta { margin-top: 8px; }
.archive-empty__note {
  font-size: 13px; color: var(--color-neutral-500); margin: 6px 0 0;
}

/* — main grid — */
.archive-grid {
  flex: 1; display: grid; grid-template-columns: 264px minmax(0, 1fr);
  gap: 0; max-width: 1360px; margin: 0 auto; width: 100%;
}

/* — rail — */
.archive-rail {
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  padding: 28px clamp(16px, 2vw, 28px) 40px;
  display: flex; flex-direction: column; gap: 26px;
  border-right: 1px solid var(--color-divider);
}
.archive-rail__label { color: var(--color-neutral-500); margin-bottom: 10px; }
.archive-rail__segs { display: flex; gap: 3px; margin-bottom: 8px; }
.archive-rail__seg {
  flex: 1; height: 10px; border: none; cursor: pointer; border-radius: 2px; padding: 0;
}
.archive-rail__seg--read { background: var(--color-accent-800); }
.archive-rail__seg--ahead { background: var(--color-neutral-900); }
.archive-rail__seg--current {
  height: 14px; background: var(--color-accent);
  box-shadow: 0 0 10px color-mix(in srgb, var(--color-accent) 45%, transparent);
}
.archive-rail__furthest {
  font-size: 12.5px; color: var(--color-neutral-400); margin: 0 0 2px;
}
.archive-rail__viewing {
  font-size: 12px; color: var(--color-accent-300); margin: 6px 0 0;
}
.archive-rail__viewing a { font-size: 12px; }
.archive-rail__setbtn { margin-top: 8px; font-size: 13px; }

.archive-areanav { display: flex; flex-direction: column; gap: 2px; }
.archive-areanav__item {
  width: 100%;
  display: flex; justify-content: space-between; gap: 14px; align-items: baseline;
  font-size: 14px; border-left: 2px solid transparent;
  padding: 7px 12px; white-space: nowrap; color: var(--color-text);
}
.archive-areanav__item:hover { color: var(--color-accent); }
.archive-areanav__item--active { border-left-color: var(--color-accent); color: var(--color-accent); }
.archive-areanav__count { font-variant-numeric: tabular-nums; opacity: 0.55; font-size: 11.5px; }

.archive-rail__foot {
  margin-top: auto; display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
}
.archive-rail__export { font-size: 12.5px; }
.archive-rail__reset { font-size: 12.5px; color: var(--color-neutral-500); }

/* — main content — */
.archive-main {
  padding: 28px clamp(18px, 3vw, 44px) 80px;
  display: flex; flex-direction: column; gap: 28px;
}

.archive-header__label { margin: 0 0 4px; }
.archive-header__title { font-size: clamp(26px, 3.4vw, 34px); margin: 0 0 4px; }
.archive-header__title--wide { font-size: clamp(26px, 3.4vw, 38px); margin: 0 0 6px; }
.archive-header__desc { font-size: 13.5px; color: var(--color-neutral-500); margin: 0; }
.archive-header__desc--wide { font-size: 14px; color: var(--color-neutral-400); max-width: 46em; }
.archive-header__desc--maxw { max-width: 46em; }

/* — since your last visit — */
.archive-since {
  background: var(--color-surface); border-radius: var(--radius-md); padding: 18px 20px;
}
.archive-since__label { color: var(--color-accent); margin-bottom: 8px; }
.archive-since__list { display: flex; flex-direction: column; gap: 6px; }
.archive-since__row { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.archive-since__name { font-size: 14px; }
.archive-since__note { font-size: 12.5px; color: var(--color-neutral-500); }

/* — amendment log — */
.archive-log__label { color: var(--color-neutral-500); margin-bottom: 14px; }
.archive-log__list { display: flex; flex-direction: column; }
.archive-log__row {
  width: 100%;
  display: grid; grid-template-columns: 52px 1fr auto; gap: 14px; align-items: baseline;
  padding: 11px 4px;
}
.archive-log__row:hover { background-color: color-mix(in srgb, var(--color-text) 4%, transparent); }
.archive-log__ch { font-size: 12px; color: var(--color-neutral-500); font-variant-numeric: tabular-nums; }
.archive-log__title { font-size: 14.5px; }
.archive-log__mark {
  font-size: 11.5px; letter-spacing: 0.06em; font-variant-numeric: tabular-nums;
  color: var(--color-neutral-500);
}
.archive-log__mark--milestone { text-transform: uppercase; color: var(--color-accent); }
.archive-log__footnote { font-size: 12.5px; color: var(--color-neutral-500); margin: 14px 0 0; }

/* — people — */
.archive-people-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 18px;
}
/* EVERY button inside the archive inherits page type and colour.
   The people card is a <button> and did not carry `.archive-btn-reset`, so it
   took the UA's default `color: buttontext` and painted its name and body
   BLACK on the surface. Invisible, and invisible on the previous palette too:
   the text was in the DOM the whole time, which is why the spoiler sweep found
   it and no counter complained. Scoping the reset to the element rather than
   to a class is what stops the next card repeating it. */
.archive-grid button,
.archive-empty button {
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}

.archive-people-card {
  width: 100%;
  background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); overflow: hidden;
  display: flex; flex-direction: column;
  color: var(--color-text);
}
.archive-people-card:hover { border-color: var(--color-accent); }
.archive-people-card__portrait { display: block; }
/* One shape for every card.
   The sources are not one shape: most anchors are 3:4 but Benny's and
   Cherie's are 2:3, so `height: auto` produced a ragged grid where two cards
   ran visibly taller than their neighbours. The frame is fixed at 3:4 and the
   image fills it, anchored to the TOP so the crop can only ever fall at the
   chest and never across a face. */
.archive-people-card__portrait img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: center top;
}
.archive-people-card__body {
  display: flex; flex-direction: column; gap: 6px; padding: 14px 16px 16px;
}
.archive-people-card__kicker {
  font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--color-accent);
}
.archive-people-card__name { font-size: 18px; font-weight: 500; }
.archive-people-card__desc { font-size: 13px; line-height: 1.6; color: var(--color-neutral-400); }
.archive-people-card__tag { align-self: flex-start; margin-top: 4px; }

/* — connections — */
.archive-conn-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.archive-conn-card {
  background: var(--color-surface); border-radius: var(--radius-md); padding: 18px 20px;
  display: flex; flex-direction: column; gap: 12px;
}
.archive-conn-card__header { display: flex; align-items: center; gap: 10px; }
.archive-conn-card__avatar {
  display: block; width: 40px; height: 40px; border-radius: 50%; overflow: hidden;
  flex: none; background: var(--color-neutral-900);
}
.archive-conn-card__avatar img { width: 100%; height: 100%; object-fit: cover; }
.archive-conn-card__name { font-size: 15px; font-weight: 500; }
.archive-conn-card__line {
  height: 1px; flex: 1;
  background: linear-gradient(to right, var(--color-accent-800), var(--color-accent), var(--color-accent-800));
}
.archive-conn-card__states { display: flex; flex-direction: column; gap: 8px; }
/* Superseded states read dimmer than the latest, but still have to be
   readable: neutral-600 measured 3.3:1 here. The hierarchy survives because
   the latest state is full ivory. */
.archive-conn-card__state { display: flex; gap: 10px; align-items: baseline; color: var(--color-neutral-500); }
.archive-conn-card__state--latest { color: var(--color-text); }
.archive-conn-card__ch {
  font-size: 11px; color: var(--color-neutral-500); font-variant-numeric: tabular-nums;
  flex: none; width: 38px;
}
.archive-conn-card__text { font-size: 13.5px; line-height: 1.55; }

/* — places — */
.archive-places-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 18px;
}
.archive-place-card {
  background: var(--color-surface); border-radius: var(--radius-md); overflow: hidden;
  display: flex; flex-direction: column;
}
.archive-place-card__art { display: block; }
/* 3:2, matching the plates as generated, with `contain` so nothing is cut.
   These were 21/9 + cover, which cropped a band out of every plate no matter
   what shape the source was: the art was being cut by CSS whether or not it
   had been cut on disk. The plates are composed as whole images and are shown
   whole. */
.archive-place-card__art img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.archive-place-card__body {
  padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 8px;
}
.archive-place-card__name { font-size: 18px; font-weight: 500; }
.archive-place-card__desc { font-size: 13.5px; line-height: 1.6; color: var(--color-neutral-400); }
.archive-place-card__tag { align-self: flex-start; }

/* — evidence — */
.archive-evidence-list { display: flex; flex-direction: column; gap: 16px; max-width: 760px; }
.archive-evidence-card {
  background: var(--color-surface); border-radius: var(--radius-md); padding: 18px 22px;
}
.archive-evidence-card__name { font-size: 17px; margin: 0 0 12px; }
.archive-evidence-card__states { display: flex; flex-direction: column; gap: 10px; }
.archive-evidence-card__row {
  display: grid; grid-template-columns: 118px 1fr; gap: 12px; align-items: baseline;
}
.archive-evidence-card__row--older { opacity: 0.55; }
.archive-evidence-card__tag {
  font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--color-neutral-500);
}
.archive-evidence-card__tag--accent { color: var(--color-accent); }
.archive-evidence-card__text { font-size: 13.5px; line-height: 1.6; }

/* — gallery — */
.archive-gallery-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 18px;
}
.archive-gallery-item img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: var(--radius-md);
}
.archive-gallery-item figcaption {
  display: flex; justify-content: space-between; gap: 8px; margin-top: 6px;
}

/* — empty area — */
.archive-empty-area { font-size: 14px; color: var(--color-neutral-500); max-width: 40em; }

/* — dialogs: picker — */
.archive-picker-list { display: flex; flex-direction: column; }
.archive-picker-row {
  width: 100%;
  display: grid; grid-template-columns: 36px 1fr auto; gap: 12px; align-items: baseline;
  padding: 10px 6px;
  background: linear-gradient(to right,
    transparent, var(--color-divider) 24px,
    var(--color-divider) calc(100% - 24px), transparent) no-repeat bottom / 100% 1px;
}
.archive-picker-row:hover { background-color: color-mix(in srgb, var(--color-accent) 8%, transparent); }
.archive-picker-row__num { font-size: 12px; color: var(--color-neutral-500); font-variant-numeric: tabular-nums; }
.archive-picker-row__title { font-size: 14px; }
.archive-picker-row__mark {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-neutral-600);
}
.archive-picker-row__mark--ahead { color: var(--color-accent); }

/* — dialogs: gate — */
.archive-gate { border: 1px solid var(--color-accent-800); }

/* — dialogs: detail — */
/* THE PORTRAIT IS NOT CROPPED AT ALL ANY MORE.
   It was a landscape band across the top, which meant a 3:4 portrait always
   lost something; the first version lost the crown of the head. A band tall
   enough to never cut a face is a band that pushes the record off the screen,
   so the shape was the problem rather than the anchor point. The portrait now
   stands in its own column at full height beside the record, which is what a
   file with a photograph clipped to it looks like anyway. */
.archive-detail { width: min(900px, 100%); padding: 0; gap: 0; }

/* `overflow: hidden` is scoped to the SPLIT variant only. It is there to clip
   the portrait to the dialog's corner radius, and in that variant the record
   column does the scrolling instead. A record with no portrait never becomes a grid, so it keeps `.dialog`'s own scrolling and
   must not be clipped, or a long amendment history would have no way out. */
.archive-detail--split { overflow: hidden; }

.archive-detail--split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  align-items: start;
  max-height: min(86vh, 760px);
}
/* Body first in the visual order, image second, without touching DOM order:
   a screen reader still meets the portrait and its alt text before the name. */
.archive-detail--split > .archive-detail__body { grid-column: 1; grid-row: 1; }
.archive-detail--split > .archive-detail__banner { grid-column: 2; grid-row: 1; }

/* The RECORD scrolls, not the whole dialog, so the face stays put while its
   amendment history moves. On one column that inverts: see the media query. */
.archive-detail--split > .archive-detail__body {
  overflow-y: auto;
  max-height: min(86vh, 760px);
}

.archive-detail__banner { position: relative; align-self: stretch; }
.archive-detail__portrait { display: block; }
.archive-detail__portrait img { width: 100%; height: auto; }
.archive-detail__portrait-alt {
  display: block; position: absolute; inset: 0; transition: opacity 0.8s ease;
}
.archive-detail__portrait-alt img { width: 100%; height: auto; }
.archive-detail__body { padding: 6px 28px 28px; display: flex; flex-direction: column; gap: 14px; }
.archive-detail__kicker {
  font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--color-accent);
  margin: 0 0 6px;
}
.archive-detail__heading { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.archive-detail__name { font-size: 26px; margin: 0; }
.archive-detail__reg2 { font-size: 22px; color: var(--color-accent); letter-spacing: 0.14em; }
.archive-detail__altbtn { font-size: 12.5px; margin-top: 6px; }
.archive-detail__history { display: flex; flex-direction: column; gap: 12px; }
.archive-detail__row {
  display: grid; grid-template-columns: 118px 1fr; gap: 12px; align-items: baseline;
}
.archive-detail__row--older { opacity: 0.55; }
.archive-detail__tag {
  font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--color-neutral-500);
}
.archive-detail__tag--accent { color: var(--color-accent); }
.archive-detail__text { font-size: 14px; line-height: 1.65; }
.archive-detail__footnote { font-size: 12px; color: var(--color-neutral-600); margin: 4px 0 0; }

/* — motion: the three animations this page is allowed — */
@keyframes seamReveal {
  from { clip-path: inset(0 100% 0 0); opacity: 0.2; }
  to { clip-path: inset(0 0 0 0); opacity: 1; }
}
@keyframes seamGlow {
  from {
    box-shadow: 0 0 0 1px var(--color-accent),
      0 0 32px color-mix(in srgb, var(--color-accent) 30%, transparent);
  }
  to { box-shadow: 0 0 0 1px transparent; }
}
.seam-glow { animation: seamGlow 2.4s ease-out both; }
.seam-reveal { animation: seamReveal 0.9s ease-out both; }

/* — responsive — */
@media (max-width: 900px) {
  .archive-grid { grid-template-columns: 1fr; }
  .archive-rail {
    position: static; height: auto; border-right: none; padding-bottom: 0;
  }
  .archive-areanav { flex-direction: row; overflow-x: auto; padding-bottom: 6px; }
  .archive-conn-grid { grid-template-columns: 1fr; }
}

/* The picker's honesty line. Quiet: it explains a limit rather than selling
   anything, so it sits below the list at the weight of a footnote. */
.archive-picker-note {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--color-neutral-400);
  margin: 12px 0 0;
}

/* One column under 760px: the portrait on top, the record beneath it, and the
   whole dialog scrolls as a single run rather than scrolling a panel inside a
   panel. Nested scroll regions on a phone are how a reader ends up dragging
   the wrong thing. */
@media (max-width: 760px) {
  .archive-detail--split {
    display: flex;
    flex-direction: column;
    max-height: min(88vh, 760px);
    overflow-y: auto;
  }
  .archive-detail--split > .archive-detail__banner { order: 1; }
  .archive-detail--split > .archive-detail__body {
    order: 2;
    overflow-y: visible;
    max-height: none;
  }
  /* Cap the portrait so the record is not pushed a full screen down. */
  .archive-detail__portrait img,
  .archive-detail__portrait-alt img {
    max-height: 44vh;
    width: 100%;
    object-fit: cover;
    object-position: center top;
  }
}

/* ── No likeness on record ───────────────────────────────────────────────────
   The plate a record wears when the book has never given the person a face.
   It is a designed absence rather than a placeholder: an unfilled outline in
   the accent, at low strength, with the reason stated under it. The card
   keeps its shape in the grid and nothing reads as broken.

   The mount rule and the label do the work; the figure is deliberately faint,
   because the point is that there is nobody to show. */
.archive-noface {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  aspect-ratio: 3 / 4;
  width: 100%;
  padding: 18px;
  background:
    linear-gradient(color-mix(in srgb, var(--color-accent) 4%, transparent),
                    color-mix(in srgb, var(--color-accent) 4%, transparent)),
    var(--color-surface-raised, var(--color-surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-accent) 22%, transparent);
}
.archive-noface__mark {
  width: 44%;
  max-width: 90px;
  height: auto;
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  opacity: 0.42;
}
.archive-noface__label {
  font-family: var(--font-mono, inherit);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  line-height: 1.5;
  color: var(--color-neutral-500);
}

/* In the detail dialog the plate sits in the portrait column, which is 3:2
   rather than 3:4 and stretches to the record's height. */
.archive-detail__banner .archive-noface {
  aspect-ratio: auto;
  height: 100%;
  min-height: 260px;
}
