/* JSB Coins — shared stylesheet
 * Detail page styles extracted from the original akragas-punic-quarter-shekel.html
 * static prototype. Catalog grid styles added below (used by /JSB_Coins/index.php).
 *
 * THEMING (2026-07-25). Every colour in this file is a var(--token) defined in
 * the :root block below; the dark palette re-declares those tokens under
 * :root[data-theme="dark"]. Nothing else in the file knows about themes.
 *
 * The theme is chosen by a tiny inline script in page_header() (jsb_coins_render.py)
 * that runs BEFORE first paint and stamps a CONCRETE value — "light" or "dark" —
 * onto <html data-theme>, resolving the stored "auto" preference against the OS
 * setting at that moment. That is why there is no @media (prefers-color-scheme)
 * block here: by the time CSS applies, the choice is already a literal attribute.
 * Consequence: with JavaScript disabled the attribute is absent and the light
 * palette applies, which is the safe default.
 *
 * ADDING A COLOUR: add a token here and a dark counterpart below — never a raw
 * hex in a rule, or it will be wrong in one of the two themes. (The only raw
 * literals left are #000 borders inside @media print, which is always light.)
 */

:root {
  color-scheme: light;

  /* Surfaces */
  --bg: #fdfcf8;                /* page ground (parchment) */
  --surface: #fff;              /* cards, inputs */
  --surface-card: #fffdf7;
  --surface-input: #fffdf8;
  --panel-bg: #faf6ec;          /* SVG "Enlarge" panel */
  --surface-sunken: #f2ece0;    /* <pre>, code, image backing */
  --surface-tint: #f7f0e2;      /* summary block, filter bar */
  --surface-tint2: #f6f2e6;     /* want budget / want note */
  --surface-tint-hover: #f0e6d0;
  --chip-bg: #f0efe9;
  --open-bg: #fffbe8;           /* open-threads callout */
  --ok-bg: #e5f0d8;
  --warn-bg: #f1ebd5;
  --err-bg: #fbeaea;
  --info-bg: #e8eef5;

  /* Ink */
  --ink: #1e1a14;               /* body text */
  --ink-strong: #2e1f0a;        /* h1, card headers */
  --ink-accent: #5a3e1b;        /* h2/h3, labels, dt */
  --ink-quote: #4a3a26;
  --ink-caption: #6a5a42;
  --ink-credit: #7a6a52;
  --muted-strong: #555;
  --muted: #666;
  --muted2: #777;
  --muted3: #888;
  --muted4: #999;
  --muted-neutral: #5a5a5a;
  --muted-faint: #a09a88;
  --on-accent: #fff;            /* text ON a gold badge/button — stays white */
  --on-dark: #eee;              /* lightbox caption, always over a dark scrim */

  /* Brand */
  --link: #7a5c2e;
  --gold: #8b6914;              /* badges, accent rules, primary button */
  --link-hot: #7a2e12;          /* hover/focus on Enlarge + panel close */
  --rule-hot: #a8763e;

  /* Rules & borders */
  --rule: #c9b48a;
  --rule-soft: #e0d8c8;
  --rule-soft2: #ece4d0;
  --rule-soft3: #ddd6c4;
  --rule-card: #e0d6bd;
  --rule-chip: #d9d4c4;
  --rule-chip2: #d4d0c2;
  --rule-table: #ddd;
  --rule-open: #e0cd96;
  --rule-err: #e0b4b4;
  --rule-ok: #aac68f;

  /* Status inks (wanted list, catalogue refs, login errors) */
  --ok-ink: #3d6017;
  --warn-ink: #6b5519;
  --err-ink: #8a2b2b;
  --info-ink: #2f4a63;
  --info-border: #a9c0d6;
  --chip-ink: #6a675c;
  --avoid-ink: #7d3a2a;
  --appeal-bg: #f7e6ee;
  --appeal-ink: #8a3560;
  --appeal-rule: #d9aec5;
  --prio1: #9c3b1b;
  --prio2: #b06a1c;
  --prio45: #9a8d6f;

  /* Article feature banner — dark by design in BOTH themes, so these barely
     move; it is meant to contrast the parchment catalog and preview the
     article page's own dark look. */
  --banner-bg: #2e3a3f;
  --banner-border: #1f282c;
  --banner-rule: #3c4a50;
  --banner-title: #f2f3f0;
  --banner-lede: #aeb6b5;
  --banner-accent: #c58f4b;

  /* Semi-opaque chip floating ON TOP of a body-figure SVG, so it must follow
     the theme even though the SVG under it is filtered, not re-coloured. */
  --enlarge-bg: rgba(250,246,236,.92);

  /* Reader text-size controls (the "Aa" panel). --fs-scale multiplies the page
     base; --fs-small additionally lifts everything under 0.9em — captions,
     credits, chips — which is where the site got genuinely hard to read, since
     those multipliers stack on a fixed 16px base. Both default to 1, so an
     untouched browser renders exactly as before. */
  --fs-scale: 1;
  --fs-small: 1;

  /* Inline-SVG body figures (Cowork's timelines) hardcode near-black ink on a
     near-white ground, so CSS variables cannot reach them. In dark mode they
     are inverted instead — see the dark block. */
  --svg-figure-filter: none;
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #17140f;
  --surface: #201c15;
  --surface-card: #211d16;
  --surface-input: #1b1813;
  --panel-bg: #221e17;
  --surface-sunken: #262117;
  --surface-tint: #241f16;
  --surface-tint2: #241f16;
  --surface-tint-hover: #2c261a;
  --chip-bg: #262319;
  --open-bg: #2a2416;
  --ok-bg: #1e2a16;
  --warn-bg: #2a2416;
  --err-bg: #2e1a1a;
  --info-bg: #17212b;

  --ink: #e8e2d4;
  --ink-strong: #f2ead8;
  --ink-accent: #d8b877;        /* headings become warm gold, not dark brown */
  --ink-quote: #cfc6b2;
  --ink-caption: #b6ac95;
  --ink-credit: #b0a68f;
  --muted-strong: #a9a294;
  --muted: #a09a8c;
  --muted2: #9a9486;
  --muted3: #948e80;
  --muted4: #8a8478;
  --muted-neutral: #9a9a9a;
  --muted-faint: #7d786c;
  /* --gold lightens in dark mode, so white text on a gold badge would drop to
     ~2.6:1. Flip the badge text to dark ink instead (~8.9:1). --on-dark is
     unchanged: it only ever sits on the lightbox's dark scrim. */
  --on-accent: #1a1610;

  --link: #d2a869;
  --gold: #c79a3f;
  --link-hot: #e08a5a;
  --rule-hot: #b8894f;

  --rule: #4a3f2a;
  --rule-soft: #3a3225;
  --rule-soft2: #3a3225;
  --rule-soft3: #3a3225;
  --rule-card: #3d3527;
  --rule-chip: #3a3428;
  --rule-chip2: #3a3428;
  --rule-table: #3a3630;
  --rule-open: #5a4a22;
  --rule-err: #6b3a3a;
  --rule-ok: #46602c;

  --ok-ink: #a8cf7a;
  --warn-ink: #d9bc74;
  --err-ink: #e29a9a;
  --info-ink: #9dc0e0;
  --info-border: #35506b;
  --chip-ink: #b5b0a2;
  --avoid-ink: #e0a08e;
  /* Priority badges carry dark ink (see --on-accent), and the badge text is
     small bold caps — so these are lightened past the first guess to clear
     4.5:1 rather than settling for the large-text 3:1 allowance.
     P1 4.63 · P2 5.41 · P4/5 5.34. */
  --appeal-bg: #2b1b25;
  --appeal-ink: #e0a3c4;
  --appeal-rule: #5c3a4c;
  --prio1: #cf6040;
  --prio2: #c07f2a;
  --prio45: #968b70;

  --enlarge-bg: rgba(38,33,25,.92);

  /* 95% of the ink in Cowork's 65 inlined timelines is greyscale, so a straight
     invert reads correctly; hue-rotate(180deg) puts the ~4% of saturated accent
     colours (blue/amber/orange/green/pink) back near their original hues. */
  --svg-figure-filter: invert(1) hue-rotate(180deg);
}

/* ---------- Detail page ---------- */
body.coin-detail {
  font-family: Georgia, serif;
  font-size: calc(1rem * var(--fs-scale));
  max-width: 920px;
  margin: 0 auto;
  padding: 2em 1.5em;
  color: var(--ink);
  line-height: 1.7;
  background: var(--bg);
}

body.coin-detail h1 {
  font-size: 1.65em;
  border-bottom: 3px solid var(--link);
  padding-bottom: .4em;
  color: var(--ink-strong);
  margin-bottom: .25em;
}

body.coin-detail h2 {
  font-size: 1.1em;
  color: var(--ink-accent);
  border-bottom: 1px solid var(--rule);
  padding-bottom: .2em;
  margin-top: 2.2em;
  letter-spacing: .03em;
  text-transform: uppercase;
}

.breadcrumb {
  font-size: calc(.85em * var(--fs-small));
  margin-bottom: 1em;
}
.breadcrumb a { color: var(--link); text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }

.subtitle {
  color: var(--muted2);
  font-style: italic;
  font-size: .93em;
  margin-bottom: 1.8em;
}

.summary {
  background: var(--surface-tint);
  border-left: 4px solid var(--gold);
  padding: 1em 1.3em;
  border-radius: 0 8px 8px 0;
  margin: 1.3em 0;
}
.summary p { margin: .35em 0; font-size: .97em; }

/* Private money line (Cost / Est. value) — only rendered behind auth. A left
   accent + muted tone signals "owner-only" without shouting. */
.summary p.private-money {
  margin-top: .5em;
  padding-left: .6em;
  border-left: 3px solid var(--gold);
  color: var(--ink-accent);
}
.summary p.private-money .as-of { color: var(--muted3); font-style: italic; font-size: .9em; }
/* The authored point estimate inside the est.-value range. */
.summary p.private-money .est-median { color: var(--ink-caption); font-size: .92em; }

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.6em;
  margin: 1.4em 0;
}
.two-col figure { margin: 0; text-align: center; }
.two-col img {
  max-width: 100%;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0,0,0,.22);
}
.two-col figcaption {
  font-size: calc(.8em * var(--fs-small));
  color: var(--muted);
  margin-top: .4em;
  font-style: italic;
}
/* Rich captions (Related Coin Images): long match-evidence + mandatory image
   credit, shown in full. Left-aligned and upright so they stay readable, with
   the credit/link legible. */
.two-col figcaption.rich {
  font-style: normal;
  text-align: left;
  font-size: calc(.82em * var(--fs-small));
  line-height: 1.5;
}
.two-col figcaption.rich a {
  color: var(--link);
  text-decoration: underline;
  word-break: break-word;
}

.prov-list { margin: .4em 0; padding-left: 1.6em; }
.prov-list li { margin: .35em 0; }

table.tags { border-collapse: collapse; width: 100%; font-size: calc(.88em * var(--fs-small)); margin: .8em 0; }
table.tags td { padding: .55em .75em; vertical-align: top; border: 1px solid var(--rule-table); }
/* Zebra striping removed: the <pre> inside the transcript cell already
   provides the label-vs-transcript contrast, so the stripe just made the
   first row's label look special and shaded the rest. */
.tag-lbl { font-weight: bold; color: var(--ink-accent); width: 25%; white-space: nowrap; }

pre {
  font-family: monospace;
  font-size: calc(.85em * var(--fs-small));
  background: var(--surface-sunken);
  padding: .5em .9em;
  border-radius: 4px;
  margin: .3em 0;
  white-space: pre-wrap;
}

.open {
  background: var(--open-bg);
  border: 1px solid var(--rule-open);
  border-radius: 8px;
  padding: 1em 1.3em;
}
.open ol { margin: .3em 0; padding-left: 1.4em; }
.open li { margin: .3em 0; font-size: .92em; }

.note {
  font-size: calc(.78em * var(--fs-small));
  color: var(--muted4);
  border-top: 1px solid var(--rule-soft);
  padding-top: .7em;
  margin-top: 2.5em;
}

/* Markdown body (historical context) — keep close to the rest of the page. */
body.coin-detail h3 {
  font-size: 1em;
  color: var(--ink-accent);
  margin-top: 1.6em;
  margin-bottom: .3em;
}
body.coin-detail h4 {
  font-size: .95em;
  color: var(--ink-accent);
  margin-top: 1.3em;
  margin-bottom: .2em;
}
body.coin-detail blockquote {
  border-left: 3px solid var(--rule);
  margin: .8em 0;
  padding: .2em 1em;
  color: var(--ink-quote);
  font-style: italic;
}
/* weight_note shown as a smaller qualifier after the structured weight value. */
body.coin-detail .phys-note {
  font-size: .9em;
  color: var(--ink-caption);
}
/* Shown above an auction photograph standing in for the owner's own photos, on
   a coin that has been won but not yet delivered. The label matters: without it
   a visitor would reasonably read the auction house's image as John's. All
   colour via tokens so it follows the light/dark toggle. */
body.coin-detail .photo-pending {
  margin: 0 0 .8em;
  padding: .45em .8em;
  border-left: 3px solid var(--rule);
  background: var(--panel-bg);
  color: var(--ink-caption);
  font-size: calc(.9em * var(--fs-small));
  font-style: italic;
}
/* "Earlier descriptions" section: verbatim auction/dealer cataloguing. */
body.coin-detail .earlier-desc { margin: 0 0 1.4em; }
body.coin-detail .earlier-desc:last-child { margin-bottom: 0; }
body.coin-detail h3.ed-label {
  margin: 0 0 .2em;
  font-size: 1em;
  font-weight: 600;
}
body.coin-detail .earlier-desc blockquote p { margin: .4em 0; }
body.coin-detail .earlier-desc blockquote p:first-child { margin-top: 0; }
body.coin-detail .earlier-desc blockquote p:last-child { margin-bottom: 0; }
body.coin-detail .ed-credit {
  margin: .3em 0 0;
  font-size: calc(.85em * var(--fs-small));
  color: var(--ink-credit);
}
body.coin-detail code {
  font-family: monospace;
  background: var(--surface-sunken);
  padding: .05em .35em;
  border-radius: 3px;
  font-size: .9em;
}
body.coin-detail ul, body.coin-detail ol { padding-left: 1.6em; }
body.coin-detail li { margin: .25em 0; }

@media (max-width: 620px) {
  .two-col { grid-template-columns: 1fr; }
}

/* ---------- Catalog index ---------- */
body.coin-catalog {
  font-family: Georgia, serif;
  font-size: calc(1rem * var(--fs-scale));
  max-width: 1200px;
  margin: 0 auto;
  padding: 2em 1.5em;
  color: var(--ink);
  background: var(--bg);
}

body.coin-catalog h1 {
  font-size: 1.65em;
  border-bottom: 3px solid var(--link);
  padding-bottom: .4em;
  color: var(--ink-strong);
  margin-bottom: .25em;
}

body.coin-catalog .subtitle {
  color: var(--muted2);
  font-style: italic;
  font-size: .93em;
  margin-bottom: 1.4em;
}

/* Link button to the Articles page. The banners themselves used to live on the
   catalog; this replaced them (2026-07-26) so the catalog opens on coins. Styled
   as a quiet dark chip that echoes the banner ground it leads to, rather than as
   a loud primary button competing with the coin grid. */
.articles-cta { margin: .2em 0 1.4em; }
.articles-link {
  display: inline-block;
  background: var(--banner-bg);
  border: 1px solid var(--banner-border);
  border-radius: 8px;
  padding: .55em 1.1em;
  color: var(--banner-accent);
  text-decoration: none;
  font-size: .92em;
  letter-spacing: .02em;
  transition: box-shadow .18s ease, transform .18s ease;
}
.articles-link:hover {
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
  transform: translateY(-1px);
  text-decoration: underline;
}
.articles-link:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* Informational / historical articles — a stack of compact dark "banner"
   teasers below the catalog masthead, each a miniature of the article's own
   hero: mono eyebrow + title + lede on the left, a small graphic on the right,
   the whole banner a link. The dark ground deliberately contrasts the parchment
   catalog and previews the destination page's look. */
.feature-strip { margin: .5em 0 1.6em; }

.feature-banner {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1.4em;
  align-items: center;
  background: var(--banner-bg);
  border: 1px solid var(--banner-border);
  border-radius: 8px;
  padding: 1.1em 1.35em;
  text-decoration: none;
  transition: box-shadow .18s ease, transform .18s ease;
}
.feature-banner + .feature-banner { margin-top: .8em; }
.feature-banner:hover {
  box-shadow: 0 6px 18px rgba(0,0,0,.28);
  transform: translateY(-1px);
}
.feature-banner .fb-eyebrow {
  font-family: "SF Mono", Menlo, Consolas, monospace;
  font-size: calc(.68em * var(--fs-small));
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--banner-accent);
  margin: 0 0 .45em;
}
.feature-banner .fb-title {
  font-size: 1.5em;
  font-weight: bold;
  color: var(--banner-title);
  letter-spacing: .02em;
  line-height: 1.1;
  margin: 0 0 .4em;
}
.feature-banner .fb-lede {
  margin: 0;
  font-size: .92em;
  font-style: normal;
  color: var(--banner-lede);
  max-width: 54ch;
}
.feature-banner .fb-cta {
  display: inline-block;
  margin-top: .7em;
  font-size: calc(.8em * var(--fs-small));
  letter-spacing: .04em;
  color: var(--banner-accent);
}
.feature-banner:hover .fb-cta { text-decoration: underline; }

/* The miniature strike graphic (right column). */
.feature-banner .fb-graphic {
  align-self: stretch;
  display: flex;
  align-items: center;
  padding-left: 1.2em;
  border-left: 1px solid var(--banner-rule);
}
.feature-banner .fb-svg {
  display: block;
  width: 118px;
  height: auto;
}
/* Image-graphic variant (a coin, a map…) — small, rounded, capped. */
.feature-banner .fb-img {
  display: block;
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 6px;
  box-shadow: 0 2px 6px rgba(0,0,0,.3);
}
/* Hover "strike": hammer and punch drop, as on the live article. */
.feature-banner .fb-hammer,
.feature-banner .fb-punch {
  transition: transform .5s cubic-bezier(.4, 0, 1, 1);
}
.feature-banner:hover .fb-hammer { transform: translateY(16px); }
.feature-banner:hover .fb-punch  { transform: translateY(11px); }

@media (prefers-reduced-motion: reduce) {
  .feature-banner:hover .fb-hammer,
  .feature-banner:hover .fb-punch { transform: none; }
}

/* Narrow screens: stack graphic under the text, like the article hero. */
@media (max-width: 620px) {
  .feature-banner {
    grid-template-columns: 1fr;
    gap: 1em;
  }
  .feature-banner .fb-graphic {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--banner-rule);
    padding-top: 1em;
    justify-content: center;
  }
  .feature-banner .fb-svg { width: 140px; }
}

/* "Show more" expander — CSS-only, driven by a visually hidden checkbox (small
   overflow) or radio group (two-step reveal) so overflow articles work without
   JS. Collapsed banners live in .fb-hidden / .fb-g1 / .fb-g2. */
.feature-strip .fb-more-toggle,
.feature-strip .fb-state {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0 0 0 0);
  overflow: hidden;
}
/* spacing above each collapsed group's banners (collapses through the wrapper
   div to the banner above, so no double gap) */
.feature-strip .fb-hidden .feature-banner,
.feature-strip .fb-g1 .feature-banner,
.feature-strip .fb-g2 .feature-banner { margin-top: .8em; }

.feature-strip .fb-hidden,
.feature-strip .fb-g1,
.feature-strip .fb-g2 { display: none; }
.feature-strip .fb-more-toggle:checked ~ .fb-hidden { display: block; }
.feature-strip #fb-step:checked ~ .fb-g1,
.feature-strip #fb-all:checked ~ .fb-g1,
.feature-strip #fb-all:checked ~ .fb-g2 { display: block; }

.feature-strip .fb-more-label {
  display: block;
  text-align: center;
  margin-top: .9em;
  padding: .55em;
  font-size: .9em;
  font-weight: bold;
  color: var(--link);
  background: var(--surface-tint);
  border: 1px dashed var(--rule);
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
  transition: background .15s ease, color .15s ease;
}
.feature-strip .fb-more-label:hover { background: var(--surface-tint-hover); color: var(--ink-accent); }
.feature-strip .fb-more-close { display: none; }
.feature-strip .fb-more-toggle:checked ~ .fb-more-label .fb-more-open { display: none; }
.feature-strip .fb-more-toggle:checked ~ .fb-more-label .fb-more-close { display: inline; }
.feature-strip .fb-more-toggle:focus-visible ~ .fb-more-label {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* Two-step control: a row of labels, only the ones valid for the current
   radio state are shown. */
.feature-strip .fb-controls {
  display: flex;
  flex-wrap: wrap;
  gap: .6em;
  margin-top: .9em;
}
.feature-strip .fb-controls .fb-more-label {
  display: none;
  flex: 1 1 12em;
  margin-top: 0;
}
.feature-strip #fb-collapsed:checked ~ .fb-controls .fb-ctl-step,
.feature-strip #fb-collapsed:checked ~ .fb-controls .fb-ctl-all,
.feature-strip #fb-step:checked ~ .fb-controls .fb-ctl-all,
.feature-strip #fb-step:checked ~ .fb-controls .fb-ctl-fewer,
.feature-strip #fb-all:checked ~ .fb-controls .fb-ctl-fewer { display: block; }
.feature-strip .fb-state:focus-visible ~ .fb-controls {
  outline: 2px solid var(--gold);
  outline-offset: 4px;
  border-radius: 8px;
}

#filter-bar {
  background: var(--surface-tint);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: .7em 1em;
  margin-bottom: 1.4em;
  display: flex;
  flex-wrap: wrap;
  gap: .8em 1.2em;
  align-items: center;
  font-size: .9em;
}
#filter-bar label   { font-weight: bold; color: var(--ink-accent); margin-right: .3em; }
/* Count beside the Recent Acquisitions controls. Says "showing 10 of 97" when
   the view is truncated and just "97 specimens" when it is not, so the page
   never quietly hides most of the collection. */
#filter-bar .filter-count {
  color: var(--ink-caption);
  font-size: calc(.9em * var(--fs-small));
  font-style: italic;
  margin-left: .4em;
}
#filter-bar select,
#filter-bar input[type="text"] {
  padding: .25em .4em;
  font-size: .9em;
  font-family: inherit;
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: 4px;
}
#filter-bar input[type="text"] { min-width: 16em; }

.catalog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}

.coin-card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 14px 16px 16px;
  box-shadow: 0 2px 6px rgba(0,0,0,.08);
  display: flex;
  flex-direction: column;
}

.coin-header {
  font-size: 1.05em;
  font-weight: bold;
  color: var(--ink-strong);
  margin-bottom: .25em;
}
.coin-header a { color: inherit; text-decoration: none; }
.coin-header a:hover { text-decoration: underline; }

.coin-meta {
  color: var(--ink-accent);
  font-size: calc(.85em * var(--fs-small));
  margin-bottom: .6em;
}

.coin-text-block {
  font-size: .9em;
  margin: .3em 0;
}
.coin-text-block .label,
.coin-ref     .label { font-weight: bold; color: var(--ink-accent); }
.coin-ref { font-size: calc(.85em * var(--fs-small)); margin: .3em 0 .4em; }

.coin-images {
  margin-top: .6em;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .8em;
}
.coin-image-block { text-align: center; }
.coin-image-block img {
  max-width: 100%;
  height: auto;
  max-height: 200px;
  border-radius: 6px;
  background: var(--surface-sunken);
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
  transition: transform .15s ease, box-shadow .15s ease;
}
.coin-image-block img:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(0,0,0,.28);
}
.coin-caption { font-size: calc(.8em * var(--fs-small)); color: var(--muted); margin-top: .3em; font-style: italic; }
.coin-caption .view-label { font-weight: bold; }

/* Card images — used by the catalog index hero and the obverse/reverse pair
   on type-page specimen lists + recent acquisitions. Without these caps the
   renderer's bare <a><img></a> would display at natural JPEG width (~1200px). */
.coin-card .hero {
  display: block;
  text-align: center;
  margin: .6em 0 .4em;
}
.coin-card .hero img {
  max-width: 100%;
  max-height: 220px;
  width: auto;
  height: auto;
  border-radius: 6px;
  background: var(--surface-sunken);
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
  transition: transform .15s ease, box-shadow .15s ease;
}
.coin-card .hero img:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(0,0,0,.28);
}
.coin-card .coin-images a {
  display: block;
  text-align: center;
}
.coin-card .coin-images a img {
  max-width: 100%;
  max-height: 180px;
  width: auto;
  height: auto;
  border-radius: 6px;
  background: var(--surface-sunken);
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
  transition: transform .15s ease, box-shadow .15s ease;
}
.coin-card .coin-images a img:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(0,0,0,.28);
}

/* Type page has more headroom per card than the catalog grid — let the
   obverse/reverse pair render larger. */
body.coin-type .coin-card .coin-images a img {
  max-height: 500px;
}

/* A coin catalogued from the auction house's photograph, not yet delivered:
   ONE image standing in for the pair. The grid is 1fr 1fr for a real
   obverse+reverse, so a lone image lands in the left column at half width —
   and these are ~2.08:1 crops showing BOTH sides, so half width made them
   half the size they should be. One column, full width, for the single-image
   case only; a real pair is untouched. */
.coin-images.auction-photo {
  grid-template-columns: 1fr;
}
.coin-card .coin-images.auction-photo a img,
.specimen-card .coin-images.auction-photo a img {
  width: 100%;
  max-width: 100%;
  height: auto;
}
/* The pair-sized max-heights would crop a full-width 2:1 image; let its own
   aspect ratio decide the height instead. */
body.coin-catalog .coin-card .coin-images.auction-photo a img,
body.coin-type .coin-card .coin-images.auction-photo a img,
body.coin-catalog .specimen-card .coin-images.auction-photo a img {
  max-height: none;
}

/* ---------- Reports page (private) ---------- */
/* All colour via existing tokens, so light/dark and the text-size control work
   with no new plumbing. */
body.coin-reports .report-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1em;
  margin: 1.2em 0 2em;
}
body.coin-reports .report-card {
  border: 1px solid var(--rule-card);
  border-radius: 8px;
  padding: .9em 1em;
  background: var(--panel-bg);
}
body.coin-reports .rc-label {
  font-size: calc(.85em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-caption);
}
body.coin-reports .rc-value {
  font-size: 1.5em;
  font-weight: bold;
  color: var(--ink-accent);
  margin: .15em 0 .2em;
}
/* The coverage line is the point of these cards, not decoration: a total with
   no "51 of 97" beside it reads as a total for the whole collection. */
body.coin-reports .rc-note {
  font-size: calc(.85em * var(--fs-small));
  color: var(--ink-caption);
}
body.coin-reports .report-note {
  font-size: calc(.9em * var(--fs-small));
  color: var(--ink-caption);
  font-style: italic;
  margin: -.4em 0 .8em;
}
body.coin-reports .report-table {
  border-collapse: collapse;
  width: 100%;
  margin-bottom: 2em;
}
body.coin-reports .report-table th,
body.coin-reports .report-table td {
  border-bottom: 1px solid var(--rule-table);
  padding: .4em .7em;
  text-align: left;
}
body.coin-reports .report-table th {
  background: var(--surface-tint);
  color: var(--ink-accent);
  font-size: calc(.9em * var(--fs-small));
}
/* Numeric columns right-align; the first column is always the label. */
body.coin-reports .report-table td:not(:first-child),
body.coin-reports .report-table th:not(:first-child) { text-align: right; }
body.coin-reports .report-table tbody tr:hover { background: var(--surface-sunken); }

/* Collapsed derivation help. <details> is native — no JS, nothing runs unless
   it is opened, and it costs nothing when closed. */
body.coin-reports .report-help {
  border: 1px solid var(--rule-soft);
  border-radius: 8px;
  padding: .5em .9em;
  margin: 0 0 2em;
  background: var(--surface-tint);
}
body.coin-reports .report-help > summary {
  cursor: pointer;
  font-weight: bold;
  color: var(--ink-accent);
  font-size: calc(.95em * var(--fs-small));
}
body.coin-reports .report-help[open] > summary { margin-bottom: .6em; }
body.coin-reports .report-help h3 {
  font-size: calc(1em * var(--fs-small));
  color: var(--ink-accent);
  margin: 1em 0 .4em;
}
body.coin-reports .report-help code {
  background: var(--surface-sunken);
  padding: .05em .35em;
  border-radius: 3px;
  font-size: .92em;
}
/* Derivation is on the card's title attribute, so the cursor should say so. */
body.coin-reports .report-card[title] { cursor: help; }

/* ---------- Type page ---------- */
body.coin-type {
  font-family: Georgia, serif;
  font-size: calc(1rem * var(--fs-scale));
  max-width: 920px;
  margin: 0 auto;
  padding: 2em 1.5em;
  color: var(--ink);
  line-height: 1.7;
  background: var(--bg);
}
body.coin-type h1 {
  font-size: 1.65em;
  border-bottom: 3px solid var(--link);
  padding-bottom: .4em;
  color: var(--ink-strong);
  margin-bottom: .25em;
}
body.coin-type h2 {
  font-size: 1.1em;
  color: var(--ink-accent);
  border-bottom: 1px solid var(--rule);
  padding-bottom: .2em;
  margin-top: 2.2em;
  letter-spacing: .03em;
  text-transform: uppercase;
}
body.coin-type h3 {
  font-size: 1em;
  color: var(--ink-accent);
  margin-top: 1.6em;
  margin-bottom: .3em;
}

dl.type-facts {
  margin: .8em 0 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1em;
  row-gap: .25em;
  font-size: .92em;
}
dl.type-facts dt { font-weight: bold; color: var(--ink-accent); }
dl.type-facts dd { margin: 0; }

.type-map {
  margin: 1.6em 0;
  text-align: center;
}
/* Each map (main + inset) is its own <figure>. */
.type-map figure { margin: 0 0 1.2em; }
.type-map .type-map-inset { margin-top: 1em; }
.type-map img {
  max-width: 100%;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0,0,0,.22);
}
/* Inset is a tighter zoom — cap displayed width so it doesn't dominate. */
.type-map .type-map-inset img {
  max-width: 540px;
  width: 100%;
}
.type-map .map-caption {
  margin: .7em auto 0;
  max-width: 600px;
  font-size: .9em;
  color: var(--muted-strong);
  font-style: italic;
  text-align: left;
}
.type-map .map-caption p { margin: .3em 0; }

/* Attribution / credit line. Smaller, lighter; sits below both the main
   map and the inset (the inset is cropped from the same source). */
.type-map .map-source {
  margin: .9em auto 0;
  max-width: 640px;
  font-size: calc(.78em * var(--fs-small));
  color: var(--muted3);
  text-align: left;
  line-height: 1.45;
}
.type-map .map-source p { margin: .15em 0; }
.type-map .map-source a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  word-break: break-word;
}

ul.references-docs { list-style: disc; padding-left: 1.4em; }
ul.references-docs li { margin: .6em 0; font-size: .93em; }
ul.references-docs .ref-citation {
  color: var(--muted-strong);
  font-size: calc(.88em * var(--fs-small));
  font-style: italic;
}

ul.catalogue-refs {
  list-style: none;
  padding: 0;
  margin: .6em 0 0;
}
ul.catalogue-refs li {
  padding: .25em 0;
  font-size: .94em;
}
.ref-role {
  display: inline-block;
  font-size: calc(.72em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .04em;
  border-radius: 4px;
  padding: .1em .5em;
  margin-left: .3em;
  vertical-align: 1px;
}
.ref-role-current     { background: var(--ok-bg); color: var(--ok-ink); border: 1px solid var(--rule-ok); }
.ref-role-superseded  { background: var(--warn-bg); color: var(--warn-ink); border: 1px solid var(--rule); font-style: italic; }
.ref-note {
  font-size: calc(.85em * var(--fs-small));
  color: var(--muted2);
  font-style: italic;
  margin-left: .35em;
}

.spec-count {
  display: inline-block;
  background: var(--gold);
  color: var(--on-accent);
  font-size: calc(.7em * var(--fs-small));
  padding: .15em .55em;
  border-radius: 12px;
  vertical-align: middle;
  margin-left: .35em;
  letter-spacing: .05em;
}
.suffix { color: var(--link); font-style: italic; font-size: calc(.85em * var(--fs-small)); }

.footer-link {
  margin-top: 2.5em;
  padding-top: .8em;
  border-top: 1px solid var(--rule-soft);
  font-size: .9em;
  color: var(--ink-accent);
}

/* ---------- Recent acquisitions ---------- */
.specimen-card .recent-date {
  display: inline-block;
  font-size: calc(.78em * var(--fs-small));
  font-weight: bold;
  color: var(--ink-accent);
  background: var(--surface-tint);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .1em .55em;
  margin-bottom: .4em;
  letter-spacing: .03em;
}
.recent-actions {
  margin-top: .6em;
  font-size: calc(.85em * var(--fs-small));
  text-align: right;
}
.recent-actions a { color: var(--link); }

/* ---------- Regions view ---------- */
section.region-block {
  margin-top: 2em;
}
.region-totals {
  font-size: calc(.7em * var(--fs-small));
  font-weight: normal;
  color: var(--muted2);
  letter-spacing: 0;
  text-transform: none;
  font-style: italic;
}
ul.region-list {
  list-style: none;
  padding: 0;
  margin: .6em 0 0;
}
ul.region-list > li {
  padding: .55em 0;
  border-bottom: 1px solid var(--rule-soft2);
}
ul.region-list .region-meta {
  font-size: calc(.85em * var(--fs-small));
  color: var(--ink-accent);
  margin-top: .15em;
}

/* ---------- Mobile (phones, narrow tablets) ----------
 * Aggressive: this is the "at a dealer, holding my phone" use case —
 * quick browse, not deep read. Compact thumbs, terser layout, no two-
 * column anything. Use !important on the image caps because the
 * desktop rules and the mobile rules tie on specificity and we want
 * the mobile cap to win unambiguously regardless of CSS source order.
 */
@media (max-width: 720px) {
  body.coin-detail,
  body.coin-type,
  body.coin-catalog {
    padding: .8em .6em;
  }

  /* Headings tighter. */
  body.coin-detail h1,
  body.coin-type h1,
  body.coin-catalog h1 {
    font-size: 1.3em;
  }

  /* Specimen page (coin.php) — .two-col collapses to 1 column at 620px.
     Cap heights so each photo stays a tidy phone-frame and the page
     doesn't scroll forever. */
  body.coin-detail .two-col img {
    max-height: 320px !important;
    width: auto;
  }

  /* Catalog index — small thumbs, two-side-by-side. */
  body.coin-catalog .coin-card .coin-images a img {
    max-height: 90px !important;
  }

  /* Type page "My specimens" cards — bigger than catalog, smaller than
     desktop. Override the 500px desktop rule unambiguously. */
  body.coin-type .coin-card .coin-images a img {
    max-height: 180px !important;
  }

  /* Recent acquisitions feed — same compact style as the catalog. */
  body.coin-catalog .specimen-card .coin-images a img {
    max-height: 120px !important;
  }

  /* Single auction photo standing in for the pair spans the full card, so the
     pair-sized caps above would crop it. Those carry !important, so this must
     too — specificity alone would lose to them. */
  body.coin-catalog .coin-card .coin-images.auction-photo a img,
  body.coin-type .coin-card .coin-images.auction-photo a img,
  body.coin-catalog .specimen-card .coin-images.auction-photo a img {
    max-height: none !important;
  }

  /* Type-level map — must not dominate. */
  .type-map img {
    max-height: 220px !important;
  }

  /* Filter bar: stack the search box on its own row. */
  #filter-bar input[type="text"] {
    min-width: 0;
    flex: 1 1 100%;
  }

  /* Tag transcriptions: break the table into stacked label + body
     rows instead of trying to keep two columns. */
  table.tags,
  table.tags tbody,
  table.tags tr {
    display: block;
    width: 100%;
  }
  table.tags td {
    display: block;
    width: auto;
    border: none;
    padding: .25em 0;
    background: transparent !important;
  }
  table.tags td.tag-lbl {
    padding-top: .9em;
    padding-bottom: .1em;
    border-top: 1px solid var(--rule);
    width: auto;
    white-space: normal;
  }
  table.tags tr:first-child td.tag-lbl {
    border-top: none;
    padding-top: 0;
  }
  table.tags pre {
    font-size: calc(.82em * var(--fs-small));
    padding: .4em .6em;
  }

  /* Catalogue references / region list / DL facts — keep compact. */
  dl.type-facts {
    grid-template-columns: max-content 1fr;
    column-gap: .6em;
    font-size: calc(.88em * var(--fs-small));
  }
  ul.catalogue-refs li { font-size: .9em; }
  ul.references-docs li { font-size: calc(.88em * var(--fs-small)); }
}

/* ---------- Top bar: theme toggle + Log in/out ---------- */
/* One flex row in the page corner. page_header() emits the toggle before the
   auth bar so the auth state stays rightmost where it has always been. */
.top-bar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: .9em;
  margin: 0 0 .3em;
  /* Anchors the absolutely-positioned text-size panel. Without this the panel
     resolves against the page box and lands off the right edge. */
  position: relative;
}
.top-bar .auth-bar { margin: 0; }

.theme-toggle {
  font-family: inherit;
  font-size: calc(.8em * var(--fs-small));
  color: var(--link);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .15em .6em;
  cursor: pointer;
  line-height: 1.6;
  white-space: nowrap;
}
.theme-toggle:hover { background: var(--surface-tint); }
.theme-toggle:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* Label is swapped by lightbox.js; the glyph keeps the button a stable width. */
.theme-toggle .tt-glyph { margin-right: .35em; }


/* ---------- Reader text-size panel ("Aa") ---------- */
.fs-btn {
  font-family: Georgia, serif;
  font-size: .85em;
  font-weight: bold;
  color: var(--link);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .1em .5em;
  cursor: pointer;
  line-height: 1.6;
}
.fs-btn:hover { background: var(--surface-tint); }
.fs-btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.fs-panel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 900;
  margin-top: .35em;
  min-width: 17em;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 6px;
  box-shadow: 0 6px 20px rgba(0,0,0,.28);
  padding: .7em .8em .6em;
  text-align: left;
}
.fs-panel[hidden] { display: none; }
.fs-row {
  display: flex;
  align-items: center;
  gap: .5em;
  padding: .3em 0;
}
.fs-label { flex: 1 1 auto; font-size: .88em; color: var(--ink); }
.fs-now {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8em;
  color: var(--muted3);
  min-width: 4.4em;
  text-align: right;
}
.fs-controls { display: flex; gap: .25em; }
.fs-step {
  font-family: inherit;
  font-size: .95em;
  line-height: 1;
  width: 1.9em;
  height: 1.9em;
  color: var(--link);
  background: var(--surface-tint);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
}
.fs-step:hover { background: var(--surface-tint-hover); }
.fs-step:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
.fs-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6em;
  margin-top: .5em;
  padding-top: .5em;
  border-top: 1px solid var(--rule-soft);
}
.fs-reset {
  font-family: inherit;
  font-size: .8em;
  color: var(--link);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .2em .6em;
  cursor: pointer;
}
.fs-reset:hover { background: var(--surface-tint); }
.fs-note { font-size: .74em; color: var(--muted3); font-style: italic; }

/* ---------- Auth: corner Log in/out link + login page ---------- */
.auth-bar {
  text-align: right;
  font-size: calc(.8em * var(--fs-small));
  margin: 0 0 .3em;
}
.auth-bar .auth-state { color: var(--muted4); font-style: italic; margin-right: .7em; }
.auth-link {
  color: var(--link);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.auth-link:hover { border-bottom-color: var(--link); }

body.coin-login {
  font-family: Georgia, serif;
  background: var(--bg);
  color: var(--ink);
  min-height: 100vh;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2em 1.2em;
}
.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 10px;
  box-shadow: 0 4px 14px rgba(0,0,0,.1);
  padding: 1.8em 1.7em 1.6em;
}
.login-card h1 {
  font-size: 1.2em;
  color: var(--ink-strong);
  border-bottom: 3px solid var(--link);
  padding-bottom: .35em;
  margin: 0 0 .6em;
}
.login-lede { font-size: .9em; color: var(--ink-accent); margin: 0 0 1.2em; line-height: 1.5; }
.login-card label {
  display: block;
  font-weight: bold;
  color: var(--ink-accent);
  font-size: calc(.85em * var(--fs-small));
  margin-bottom: .3em;
}
.login-card input[type="password"] {
  width: 100%;
  padding: .55em .6em;
  font-size: 1em;
  font-family: inherit;
  border: 1px solid var(--rule);
  border-radius: 5px;
  background: var(--surface-input);
  margin-bottom: 1em;
}
.login-card button {
  width: 100%;
  padding: .6em;
  font-size: .95em;
  font-family: inherit;
  font-weight: bold;
  color: var(--on-accent);
  background: var(--gold);
  border: 0;
  border-radius: 5px;
  cursor: pointer;
}
.login-card button:hover { background: var(--link); }
.login-error {
  background: var(--err-bg);
  border: 1px solid var(--rule-err);
  color: var(--err-ink);
  font-size: calc(.85em * var(--fs-small));
  padding: .5em .7em;
  border-radius: 5px;
  margin: 0 0 1em;
}
.login-back { margin: 1.1em 0 0; font-size: calc(.82em * var(--fs-small)); text-align: center; }
.login-back a { color: var(--link); text-decoration: none; }
.login-back a:hover { text-decoration: underline; }

/* ---------- Body graphics (historical-context figures) ----------
   Cowork drops a graphic in coins/<slug>/graphics/ and references it in the
   type body; render_type_body() wraps it in <figure class="body-figure">.
   Kept small (click to zoom via the lightbox); caption sits below. */
.body-figure {
  margin: 1.4em auto;
  max-width: 500px;
  text-align: center;
}
.body-figure img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  box-shadow: 0 1px 4px rgba(0,0,0,.25);
}
.body-figure figcaption {
  margin-top: .5em;
  font-size: calc(.82em * var(--fs-small));
  font-style: italic;
  color: var(--ink-caption);
  text-align: left;
  line-height: 1.4;
}
.body-figure figcaption a { color: var(--link); }

/* Zoom-in cursor cue on any lightbox-enabled image link (tagged by lightbox.js). */
a.lb-zoom { cursor: zoom-in; }

/* Inline-SVG body figure (figure.svg-figure): the .svg is inlined (not an <img>)
   so its embedded <a href> coin links work. Sized like a raster figure; the
   viewBox handles scaling. An "Enlarge" button (added by lightbox.js) opens a
   larger cloned copy — click-to-zoom is NOT used here so link clicks navigate. */
.body-figure.svg-figure { position: relative; }
.body-figure.svg-figure svg {
  width: 100%;
  height: auto;
  display: block;
  /* none in light; invert+hue-rotate in dark (see :root[data-theme="dark"]). */
  filter: var(--svg-figure-filter);
}
.body-figure.svg-figure .enlarge {
  position: absolute;
  top: .3em;
  right: .3em;
  font-size: calc(.72em * var(--fs-small));
  font-family: Georgia, serif;
  color: var(--ink-accent);
  background: var(--enlarge-bg);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: .2em .5em;
  cursor: pointer;
}
.body-figure.svg-figure .enlarge:hover,
.body-figure.svg-figure .enlarge:focus-visible {
  color: var(--link-hot);
  border-color: var(--rule-hot);
  outline: none;
}

/* Enlarge panel overlay for inline-SVG figures (a light, scrollable panel —
   SVG diagrams can be wide — distinct from the dark image lightbox above). */
.lb-panel-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3vmin;
  background: rgba(18,22,26,.84);
}
.lb-panel-overlay[hidden] { display: none; }
.lb-panel {
  position: relative;
  background: var(--panel-bg);
  border-radius: 3px;
  width: min(1200px, 96vw);
  max-height: 94vh;
  overflow: auto;
  padding: clamp(1.5rem, 3vw, 2.6rem);
  box-shadow: 0 24px 70px rgba(0,0,0,.55);
}
.lb-panel-close {
  position: absolute;
  top: .6rem;
  right: .6rem;
  font-size: calc(.78em * var(--fs-small));
  font-family: Georgia, serif;
  color: var(--ink-accent);
  background: var(--surface-sunken);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: .3em .6em;
  cursor: pointer;
}
.lb-panel-close:hover,
.lb-panel-close:focus-visible { color: var(--link-hot); border-color: var(--rule-hot); outline: none; }
.lb-panel-body figure { margin: 0; max-width: none; }
.lb-panel-body svg { width: 100%; height: auto; filter: var(--svg-figure-filter); }
.lb-panel-body figcaption { margin-top: 1em; font-size: calc(.85em * var(--fs-small)); font-style: italic; color: var(--ink-caption); }

/* ---------- Image lightbox overlay (lightbox.js) ---------- */
.lb-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3vmin;
  background: rgba(0,0,0,.86);
}
.lb-overlay[hidden] { display: none; }
body.lb-open { overflow: hidden; }
.lb-figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 96vw;
  max-height: 96vh;
}
.lb-img {
  max-width: 96vw;
  max-height: 88vh;
  object-fit: contain;
  border-radius: 3px;
  box-shadow: 0 4px 24px rgba(0,0,0,.5);
  cursor: default;
}
.lb-cap {
  margin-top: .7em;
  max-width: 70ch;
  color: var(--on-dark);
  font-size: calc(.85em * var(--fs-small));
  font-style: italic;
  text-align: center;
  line-height: 1.4;
}
.lb-close {
  position: fixed;
  top: 2vmin;
  right: 2vmin;
  width: 2em;
  height: 2em;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255,255,255,.15);
  /* Sits on the dark lightbox scrim in BOTH themes, so it wants --on-dark,
     not --on-accent (which flips to dark ink on the lighter dark-mode gold). */
  color: var(--on-dark);
  font-size: 1.6em;
  line-height: 1;
  cursor: pointer;
}
.lb-close:hover { background: rgba(255,255,255,.3); }

/* ---------- Wanted list (private view) ---------- */
/* The whole wanted.php page is auth-gated; these styles never render for an
   anonymous visitor. Palette follows the catalog's warm browns, with the
   priority badge carrying the only strong colour so a P1 reads at a glance. */
.want-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 1.2em;
  margin-top: 1.2em;
}
.want-card {
  background: var(--surface-card);
  border: 1px solid var(--rule-card);
  border-radius: 6px;
  padding: 1em 1.1em;
  box-shadow: 0 1px 3px rgba(0,0,0,.06);
}
.want-card.want-status-acquired { opacity: .75; border-color: var(--rule-ok); }
.want-card.want-status-passed   { opacity: .6;  font-style: italic; }

.want-header {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .45em;
  margin-bottom: .5em;
}
.want-header h3 {
  margin: 0;
  flex: 1 1 auto;
  font-size: 1.08em;
}
/* Opens this want on its own page. Deliberately quiet — it sits on every card,
   so it must not compete with the priority badge or a LIVE chip. */
.want-open {
  flex: 0 0 auto;
  text-decoration: none;
  color: var(--muted3);
  border: 1px solid var(--rule-card);
  border-radius: 4px;
  padding: 0 .4em;
  font-size: 1em;
  line-height: 1.5;
}
.want-open:hover { color: var(--link); border-color: var(--gold); }
.want-open:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* The single-want page: same markup as a card, given room. */
.want-card-detail {
  max-width: 860px;
  margin: 1.2em auto 0;
  padding: 1.4em 1.6em;
}
.want-card-detail .want-example img { max-height: 460px; }
.want-card-detail .cmp-grid { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.want-card-detail .cmp-photo img { max-height: 190px; }
.want-card-detail .want-body > summary { font-size: 1em; }
.want-card-detail .want-items { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.4em; }
@media (max-width: 720px) {
  .want-card-detail { padding: 1em 1.1em; }
  .want-card-detail .want-items { grid-template-columns: 1fr; }
}
.want-priority {
  display: inline-block;
  background: var(--gold);
  color: var(--on-accent);
  font-size: calc(.72em * var(--fs-small));
  font-weight: bold;
  padding: .15em .5em;
  border-radius: 12px;
}
.want-priority-1 { background: var(--prio1); }
.want-priority-2 { background: var(--prio2); }
.want-priority-4,
.want-priority-5 { background: var(--prio45); }
.want-kind,
.want-status-chip {
  display: inline-block;
  font-size: calc(.72em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .04em;
  border-radius: 4px;
  padding: .1em .5em;
}
.want-kind-type_gap { background: var(--info-bg); color: var(--info-ink); border: 1px solid var(--info-border); }
.want-kind-upgrade  { background: var(--warn-bg); color: var(--warn-ink); border: 1px solid var(--rule); }
/* STUDY — a coin wanted for what it documents, where the very condition that
   disqualifies it everywhere else is the reason to buy. Green, so it reads as
   its own category rather than a variant of gap or upgrade. */
.want-kind-study    { background: var(--ok-bg); color: var(--ok-ink); border: 1px solid var(--rule-ok); }
/* APPEAL — wanted simply because John would like to own it: taste, not a gap
   in the story. Its own colour so it doesn't read as any of the other three. */
.want-kind-appeal   { background: var(--appeal-bg); color: var(--appeal-ink); border: 1px solid var(--appeal-rule); }
/* SALE — the card IS one auction, not a coin. Uses the live/urgent accent,
   because that is what it behaves like: it matters intensely for a few days
   and becomes a price record afterwards. */
.want-kind-bidsheet { background: var(--open-bg); color: var(--prio1); border: 1px solid var(--rule-open); font-weight: bold; }
/* SWEEP — a dated report, sibling to a sale card: a working document rather
   than a want. Neutral, so it doesn't compete with the urgent Sale badge. */
.want-kind-sweep    { background: var(--chip-bg); color: var(--chip-ink); border: 1px solid var(--rule-chip); font-weight: bold; }
/* ACQUIRED — bought, but not yet weighed, measured and photographed. Green:
   this is the only card whose contents are always a completed purchase. */
.want-kind-acquired { background: var(--ok-bg); color: var(--ok-ink); border: 1px solid var(--rule-ok); font-weight: bold; }
.want-status-chip   { background: var(--chip-bg); color: var(--chip-ink); border: 1px solid var(--rule-chip2); }

.want-links {
  font-size: calc(.88em * var(--fs-small));
  margin-bottom: .5em;
}
.want-links a { color: var(--link); }

/* "An upgrade on <specimen>" — given its own block rather than a chip in the
   links row, because the trailing clause (it ADDS a specimen, it does not
   replace one) is the point and needs room to be read. */
.want-upgrade-of {
  font-size: calc(.88em * var(--fs-small));
  margin: -.2em 0 .6em;
  padding: .35em .6em;
  border-left: 3px solid var(--rule-ok);
  background: var(--ok-bg);
  border-radius: 0 4px 4px 0;
}
.want-upgrade-of a { color: var(--link); }
.want-upgrade-note { color: var(--muted-strong); font-style: italic; }

.want-facts {
  margin: .4em 0 .6em;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .12em .7em;
  font-size: .9em;
}
.want-facts dt { color: var(--muted3); }
.want-facts dd { margin: 0; }

/* Money — only ever emitted behind is_authenticated(). */
.want-budget {
  background: var(--surface-tint2);
  border-left: 3px solid var(--gold);
  padding: .4em .7em;
  margin: .5em 0;
  font-size: .92em;
}
.want-budget-label {
  text-transform: uppercase;
  font-size: calc(.78em * var(--fs-small));
  letter-spacing: .05em;
  color: var(--gold);
  margin-right: .4em;
}
.want-price-note { color: var(--muted2); font-style: italic; font-size: .92em; }

/* Card "what to look for" photo. Full card width with a capped height so a tall
   image can't dominate the card; the <figure> wraps image + caption + source so
   the "Show images" switch hides them as one unit. */
.want-example {
  margin: .2em 0 .7em;
  text-align: center;
}
.want-example[hidden] { display: none; }
.want-example img {
  max-width: 100%;
  max-height: 260px;
  width: auto;
  height: auto;
  border-radius: 5px;
  background: var(--surface-sunken);
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
}
.want-example-cap {
  margin-top: .45em;
  font-size: calc(.84em * var(--fs-small));
  font-style: italic;
  color: var(--ink-caption);
  text-align: left;
  line-height: 1.45;
}
.want-example-src {
  margin-top: .3em;
  font-size: calc(.74em * var(--fs-small));
  color: var(--muted3);
  text-align: left;
  line-height: 1.4;
}
.want-example-missing {
  font-size: calc(.8em * var(--fs-small));
  color: var(--muted3);
  font-style: italic;
  padding: .5em;
  border: 1px dashed var(--rule);
  border-radius: 4px;
}
.want-example-missing code { font-style: normal; }

/* All / Gaps / Upgrades — a filter; and Show images — a display switch. Kept
   visually distinct so the switch never reads as a fourth facet. */
.want-kind-filter { gap: .35em; display: flex; }
.wf-btn {
  font-family: inherit;
  font-size: .9em;
  color: var(--link);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .25em .8em;
  cursor: pointer;
}
.wf-btn:hover { background: var(--surface-tint-hover); }
.wf-btn[aria-pressed="true"] {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--on-accent);
  font-weight: bold;
}
/* "Live now" filters on a different axis from the kind buttons — deadline, not
   category — so it carries the same warm accent the LIVE chip does, to read as
   the urgent one in the row. */
.wf-btn-live { color: var(--prio1); border-color: var(--prio1); }
.wf-btn-live[aria-pressed="true"] {
  background: var(--prio1);
  border-color: var(--prio1);
  color: var(--on-accent);
}
.wf-btn:focus-visible,
.wf-toggle:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.wf-toggle {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  font-family: inherit;
  font-size: .9em;
  color: var(--ink-accent);
  background: transparent;
  border: 0;
  padding: .25em .2em;
  cursor: pointer;
}
.wf-toggle-box {
  width: 1.9em;
  height: 1.05em;
  border-radius: 1em;
  background: var(--rule-chip);
  border: 1px solid var(--rule);
  position: relative;
  transition: background .15s ease;
}
.wf-toggle-box::after {
  content: "";
  position: absolute;
  top: 50%;
  left: .12em;
  transform: translateY(-50%);
  width: .78em;
  height: .78em;
  border-radius: 50%;
  background: var(--surface);
  transition: left .15s ease;
}
.wf-toggle[aria-pressed="true"] .wf-toggle-box { background: var(--gold); }
.wf-toggle[aria-pressed="true"] .wf-toggle-box::after { left: calc(100% - .9em); }

/* Live-sale links — the ONE thing on a card with a deadline, so it sits at the
   top and is the only element styled for attention. An entry past its
   last_useful_date is not deleted; it goes muted and points at the sold archive
   instead (the renderer decides, comparing against today at render time). */
.wl-live-row { display: flex; flex-direction: column; gap: .3em; margin: 0 0 .55em; }
.wl-live {
  display: block;
  text-decoration: none;
  border-radius: 4px;
  padding: .4em .6em;
  font-size: calc(.85em * var(--fs-small));
  line-height: 1.35;
}
.wl-live-open {
  background: var(--open-bg);
  border: 1px solid var(--rule-open);
  color: var(--ink);
}
.wl-live-open:hover { border-color: var(--gold); }
.wl-live-flag {
  display: inline-block;
  background: var(--prio1);
  color: var(--on-accent);
  font-size: calc(.72em * var(--fs-small));
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: .06em;
  border-radius: 3px;
  padding: .1em .45em;
  margin-right: .45em;
  vertical-align: 1px;
}
.wl-live-label { font-weight: bold; }
.wl-live-when {
  display: block;
  font-size: calc(.88em * var(--fs-small));
  color: var(--muted-strong);
  margin-top: .15em;
}
.wl-live-open .wl-live-when { color: var(--ink-accent); font-weight: bold; }
/* Ended: same shape, no flag, deliberately quiet — it is history now. */
.wl-live-ended {
  background: transparent;
  border: 1px dashed var(--rule);
  color: var(--muted-strong);
}
.wl-live-ended .wl-live-label { font-weight: normal; font-style: italic; }
.wl-live-ended:hover { border-style: solid; border-color: var(--link); }


/* Lot photo inside the live box — lets a lot be triaged from the card without
   opening the sale. Obeys the Show images toggle like every other want photo. */
.wl-live-photo { display: block; margin-top: .45em; }
.wl-live-photo[hidden] { display: none; }
.wl-live-photo img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 200px;
  object-fit: contain;
  border-radius: 3px;
  background: var(--surface-sunken);
}
.wl-live-nophoto {
  display: block;
  margin-top: .4em;
  font-size: calc(.8em * var(--fs-small));
  font-style: italic;
  color: var(--muted3);
}

/* Judging notes — the standing lesson about the type. */
.want-notes { margin-top: .7em; }
.want-notes > summary { cursor: pointer; font-size: .9em; color: var(--link); }
.want-notes p { font-size: calc(.88em * var(--fs-small)); line-height: 1.55; margin: .5em 0; }

/* The evaluation log: every lot looked at, and why it was passed. */
.want-evals { margin-top: .5em; }
.want-evals > summary { cursor: pointer; font-size: .9em; color: var(--link); }
ul.wev-list { list-style: none; margin: .4em 0 0; padding: 0; }
.wev {
  border-left: 2px solid var(--rule-card);
  padding: .35em 0 .35em .7em;
  margin-bottom: .5em;
}
.wev-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .4em; }
.wev-date { font-size: calc(.78em * var(--fs-small)); color: var(--muted3); font-family: ui-monospace, Menlo, monospace; }
.wev-verdict {
  font-size: calc(.7em * var(--fs-small));
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: .06em;
  border-radius: 3px;
  padding: .1em .45em;
}
.wev-pass  { background: var(--warn-bg); color: var(--warn-ink); border: 1px solid var(--rule); }
.wev-acted { background: var(--ok-bg);   color: var(--ok-ink);   border: 1px solid var(--rule-ok); }
.wev-lot { font-size: calc(.84em * var(--fs-small)); font-weight: bold; flex: 1 1 12em; }
a.wev-lot { color: var(--link); text-decoration: none; }
a.wev-lot:hover { text-decoration: underline; }
a.wev-lot:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* Photo of the evaluated lot. Sized modestly — it is evidence for the
   verdict above it, not the card's headline image. */
.wev-photo { display: block; margin-top: .45em; }
.wev-photo img { max-width: 100%; max-height: 150px; width: auto;
  border-radius: 3px; background: var(--surface-sunken); }
/* The stored lot photos run to 2000px for most houses, so the thumbnail
   is a click-to-zoom target; lightbox.js adds .lb-zoom (cursor: zoom-in). */
.wev-photo a { display: block; }
.wev-why { font-size: calc(.82em * var(--fs-small)); color: var(--muted-strong); line-height: 1.5; margin-top: .25em; }


/* "updated <date>" — a want added or reviewed within FRESH_DAYS. Quiet: it
   marks recency, it is not a call to action. */
.want-fresh {
  display: inline-block;
  font-size: calc(.7em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ok-ink);
  background: var(--ok-bg);
  border: 1px solid var(--rule-ok);
  border-radius: 3px;
  padding: .1em .45em;
}

/* Missing ceiling on an APPEAL want — the category where discipline fails, so
   this one is deliberately loud, unlike every other note on the card. */
.want-nobudget {
  background: var(--err-bg);
  border: 1px solid var(--rule-err);
  border-left: 3px solid var(--prio1);
  color: var(--err-ink);
  border-radius: 0 4px 4px 0;
  padding: .45em .7em;
  margin: .5em 0;
  font-size: calc(.85em * var(--fs-small));
  line-height: 1.45;
}
.want-nobudget code { background: none; font-size: .95em; }

/* Saved-search links — durable queries (a lot link dies the day after the
   sale), shown as small outlined buttons above the watch-venue chips. */
.wl-search-links {
  display: flex;
  flex-wrap: wrap;
  gap: .35em;
  margin: 0 0 .45em;
}
.wl-search-link {
  display: inline-block;
  font-size: calc(.8em * var(--fs-small));
  line-height: 1.35;
  color: var(--link);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .22em .6em;
  text-decoration: none;
}
.wl-search-link:hover { background: var(--surface-tint-hover); text-decoration: underline; }
.wl-search-link:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* Price comparables — sold lots as a cheapest-first ladder. AUTH-GATED: the
   photos are (c) CNG, kept for private research only, hence the credit line
   and the independent is_authenticated() check in render_comparables(). */
.want-comparables { margin-top: .7em; }
.want-comparables h4 {
  margin: .6em 0 .3em;
  font-size: calc(.82em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--gold);
}
.cmp-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .5em;
}
.cmp-tile {
  display: block;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--rule-card);
  border-radius: 5px;
  padding: .4em .5em;
  background: var(--surface-card);
}
.cmp-tile:hover { border-color: var(--gold); }
.cmp-tile:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.cmp-photo { display: block; margin-bottom: .3em; }
.cmp-photo[hidden] { display: none; }
.cmp-photo img {
  width: 100%;
  height: auto;
  max-height: 110px;
  object-fit: contain;
  border-radius: 3px;
  background: var(--surface-sunken);
}
.cmp-hammer {
  display: block;
  font-weight: bold;
  font-size: .95em;
  color: var(--ink-strong);
}
.cmp-note {
  display: block;
  font-size: calc(.76em * var(--fs-small));
  color: var(--muted-strong);
  line-height: 1.35;
}
/* With photos off the tiles are pure text, so let them run in a tighter row. */
.cmp-tile-noimg .cmp-note { font-size: calc(.74em * var(--fs-small)); }
.cmp-price-note {
  margin: .5em 0 .2em;
  font-size: calc(.82em * var(--fs-small));
  color: var(--ink-caption);
  line-height: 1.45;
}
.cmp-credit {
  margin: .2em 0 0;
  font-size: calc(.72em * var(--fs-small));
  font-style: italic;
  color: var(--muted3);
  line-height: 1.4;
}

.want-items { margin-top: .6em; }
.want-item-block h4 {
  margin: .6em 0 .25em;
  font-size: calc(.82em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--gold);
}
ul.want-list { margin: 0; padding-left: 1.2em; font-size: .9em; }
ul.want-list li { padding: .1em 0; }
ul.want-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .35em; }
.want-chip {
  background: var(--chip-bg);
  border: 1px solid var(--rule-chip);
  border-radius: 3px;
  padding: .12em .5em;
  font-size: calc(.84em * var(--fs-small));
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.want-item-avoid ul.want-list li { color: var(--avoid-ink); }

.want-body { margin-top: .7em; }
.want-body > summary {
  cursor: pointer;
  font-size: .9em;
  color: var(--link);
}
.want-body .body-figure { max-width: 100%; }

.want-resolution {
  margin-top: .6em;
  font-size: calc(.88em * var(--fs-small));
  color: var(--muted-neutral);
  border-top: 1px dotted var(--rule-soft3);
  padding-top: .4em;
}
.want-added { margin-top: .4em; font-size: calc(.8em * var(--fs-small)); color: var(--muted-faint); }

.want-history { margin-top: 2em; }
.want-history > summary {
  cursor: pointer;
  font-size: 1.05em;
  color: var(--link);
  padding: .4em 0;
}

/* The private cross-link shown on a type page when an open want targets it. */
.want-note {
  background: var(--surface-tint2);
  border-left: 3px solid var(--gold);
  padding: .5em .8em;
  margin: 1em 0;
  font-size: .92em;
}
.want-note-label {
  display: block;
  text-transform: uppercase;
  font-size: calc(.75em * var(--fs-small));
  letter-spacing: .05em;
  color: var(--gold);
  margin-bottom: .2em;
}
.want-note ul { margin: 0; padding-left: 1.2em; }
.nav-private { font-style: italic; }

/* ---------- Wanted page body ----------
   This was missing entirely until 2026-07-27: body.coin-wanted matched no rule,
   so the page rendered in Times with no padding and no background, and only
   looked right because the cards style themselves. No max-width on purpose —
   the grid is meant to fill a wide screen. */
body.coin-wanted {
  font-family: Georgia, serif;
  font-size: calc(1rem * var(--fs-scale));
  margin: 0;
  padding: 1.4em 1.5em 2em;
  color: var(--ink);
  background: var(--bg);
  line-height: 1.6;
}

/* ---------- John Docs index ----------
   One card per markdown file in JohnDocs/. The folder is listed at request
   time, so a new file appears here with no code change. */
.doc-list { display: grid; gap: .8em; margin-top: 1.2em; }
.doc-card {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--surface-card);
  border: 1px solid var(--rule-card);
  border-left: 3px solid var(--gold);
  border-radius: 6px;
  padding: .9em 1.1em;
  transition: border-color .15s ease, transform .15s ease;
}
.doc-card:hover { border-color: var(--gold); transform: translateY(-1px); }
.doc-card:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.doc-title {
  display: block;
  font-size: 1.05em;
  font-weight: bold;
  color: var(--ink-strong);
}
.doc-lede {
  display: block;
  margin-top: .25em;
  font-size: calc(.88em * var(--fs-small));
  color: var(--muted-strong);
  line-height: 1.5;
}
.doc-meta {
  display: block;
  margin-top: .4em;
  font-size: calc(.76em * var(--fs-small));
  color: var(--muted3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ---------- Generic markdown page (John Docs) ----------
   A whole .md file rendered straight to HTML, so it needs styling for elements
   the coin pages never produce: real tables, fenced code blocks, hr rules. The
   existing table rules are scoped to .tags (tag transcriptions), so they don't
   reach here. */
body.coin-tasks {
  font-family: Georgia, serif;
  font-size: calc(1rem * var(--fs-scale));
  max-width: 900px;
  margin: 0 auto;
  padding: 2em 1.5em;
  color: var(--ink);
  line-height: 1.7;
  background: var(--bg);
}
body.coin-tasks h1 {
  font-size: 1.65em;
  border-bottom: 3px solid var(--link);
  padding-bottom: .4em;
  color: var(--ink-strong);
  margin-bottom: .25em;
}
.md-page h2 {
  font-size: 1.12em;
  color: var(--ink-accent);
  border-bottom: 1px solid var(--rule);
  padding-bottom: .2em;
  margin-top: 2em;
  letter-spacing: .03em;
  text-transform: uppercase;
}
.md-page h3 { font-size: 1em; color: var(--ink-accent); margin: 1.5em 0 .3em; }
.md-page h4 { font-size: .95em; color: var(--ink-accent); margin: 1.2em 0 .2em; }
.md-page p { margin: .7em 0; }
.md-page ul, .md-page ol { padding-left: 1.5em; }
.md-page li { margin: .3em 0; }
.md-page hr { border: 0; border-top: 1px solid var(--rule-soft); margin: 2em 0; }
.md-page a { color: var(--link); }
.md-page blockquote {
  border-left: 3px solid var(--rule);
  margin: .8em 0;
  padding: .2em 1em;
  color: var(--ink-quote);
}
.md-page code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-sunken);
  padding: .08em .35em;
  border-radius: 3px;
  font-size: calc(.88em * var(--fs-small));
  word-break: break-word;
}
.md-page pre {
  background: var(--surface-sunken);
  border: 1px solid var(--rule-soft);
  border-radius: 5px;
  padding: .8em 1em;
  overflow-x: auto;
  font-size: calc(.86em * var(--fs-small));
  line-height: 1.5;
}
.md-page pre code { background: none; padding: 0; font-size: 1em; }
/* Tables carry most of the content here, so they get real treatment. Wrapped in
   an overflow rule rather than shrinking text, so a long path stays readable. */
.md-page table {
  border-collapse: collapse;
  width: 100%;
  margin: 1em 0;
  font-size: .9em;
  display: block;
  overflow-x: auto;
}
.md-page thead th {
  background: var(--surface-tint);
  color: var(--ink-accent);
  text-align: left;
  font-size: calc(.82em * var(--fs-small));
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: .5em .7em;
  border-bottom: 2px solid var(--rule);
}
.md-page td {
  padding: .5em .7em;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: top;
}
.md-page tbody tr:last-child td { border-bottom: 0; }

/* ---------- Print pass (all pages) ---------- */
@media print {
  /* Always print the LIGHT palette, whatever the screen theme is: printing a
     dark page wastes ink and reads badly. Re-declaring the tokens here beats
     :root[data-theme="dark"] because @media print applies later in the cascade
     at equal specificity. The SVG filter is reset too, or inverted timelines
     would print as white-on-white. */
  :root, :root[data-theme="dark"] {
    color-scheme: light;
    --bg: #fdfcf8;            --surface: #fff;
    --surface-card: #fffdf7;  --surface-input: #fffdf8;
    --panel-bg: #faf6ec;      --surface-sunken: #f2ece0;
    --surface-tint: #f7f0e2;  --surface-tint2: #f6f2e6;
    --surface-tint-hover: #f0e6d0;
    --chip-bg: #f0efe9;       --open-bg: #fffbe8;
    --ok-bg: #e5f0d8;         --warn-bg: #f1ebd5;
    --err-bg: #fbeaea;        --info-bg: #e8eef5;
    --ink: #1e1a14;           --ink-strong: #2e1f0a;
    --ink-accent: #5a3e1b;    --ink-quote: #4a3a26;
    --ink-caption: #6a5a42;   --ink-credit: #7a6a52;
    --muted-strong: #555;     --muted: #666;
    --muted2: #777;           --muted3: #888;
    --muted4: #999;           --muted-neutral: #5a5a5a;
    --muted-faint: #a09a88;
    --link: #7a5c2e;          --gold: #8b6914;
    --link-hot: #7a2e12;      --rule-hot: #a8763e;
    --rule: #c9b48a;          --rule-soft: #e0d8c8;
    --rule-soft2: #ece4d0;    --rule-soft3: #ddd6c4;
    --rule-card: #e0d6bd;     --rule-chip: #d9d4c4;
    --rule-chip2: #d4d0c2;    --rule-table: #ddd;
    --rule-open: #e0cd96;     --rule-err: #e0b4b4;
    --rule-ok: #aac68f;
    --ok-ink: #3d6017;        --warn-ink: #6b5519;
    --err-ink: #8a2b2b;       --info-ink: #2f4a63;
    --info-border: #a9c0d6;   --chip-ink: #6a675c;
    --avoid-ink: #7d3a2a;
    --prio1: #9c3b1b;         --prio2: #b06a1c;   --prio45: #9a8d6f;
    --svg-figure-filter: none;
    --enlarge-bg: rgba(250,246,236,.92);
  }
  .top-bar, .theme-toggle, .fs-btn, .fs-panel { display: none; }
  .lb-overlay { display: none !important; }
  body { background: var(--surface); max-width: none; padding: 0; }
  body.coin-catalog { background: var(--surface); }
  #filter-bar { display: none; }
  .breadcrumb, .footer-link, .recent-actions, .auth-bar { display: none; }
  .coin-card { box-shadow: none; border: 1px solid #000; page-break-inside: avoid; }
  .two-col img { max-height: none; }
  a { color: inherit; text-decoration: none; }
  /* Catalog grid: 2 columns for letter-size print */
  .catalog-grid { grid-template-columns: 1fr 1fr; gap: 10mm; }
  /* Wanted list is meant to be printed and carried into a saleroom: keep a want
     on one page and drop the disclosure triangles. The <details> elements are
     forced open by the page's own beforeprint handler — CSS alone can't do it
     reliably across browsers. */
  .want-grid { grid-template-columns: 1fr 1fr; gap: 8mm; }
  .want-card { box-shadow: none; border: 1px solid #000; page-break-inside: avoid; opacity: 1; }
  .want-body > summary, .want-history > summary { display: none; }
  /* Keep the example photo on the saleroom copy — that is the whole point of
     it — but cap it harder than on screen so a card still fits a column. Force
     it visible even if "Show images" is currently off on screen. */
  .want-example, .want-example[hidden] { display: block !important; }
  .want-example img { max-height: 45mm; }
  .want-kind-filter, .wf-toggle { display: none; }
  h1, h2, h3 { page-break-after: avoid; }
  pre { white-space: pre-wrap; word-break: break-word; }
}

/* ===================================================================
   WATCHES
   -------------------------------------------------------------------
   Everything above this line is inherited from JSB Coins: the token
   system, the light/dark contract, the lightbox, the text-size panel.
   Only the token NAMES are load-bearing — nothing below declares a
   colour literal, so dark mode works here for free, exactly as it does
   on Coins (BUILD-PLAN section 6).
   =================================================================== */

/* ---------- Landing page: one photograph and a login ---------- */
/* The only page an anonymous visitor sees. The photograph is a fixed,
   cover-fitted background rather than an <img> so it fills any viewport
   without dictating the card's position; if the hero file is missing —
   which is the normal state of a fresh checkout, since photographs are
   gitignored — .watch-hero is simply not emitted and the page falls back
   to the page ground. */
body.watch-login {
  font-family: Georgia, serif;
  background: var(--bg);
  color: var(--ink);
  min-height: 100vh;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2em 1.2em;
  position: relative;
}
.watch-hero {
  position: fixed;
  inset: 0;
  background-size: cover;
  background-position: center;
  z-index: 0;
}
/* Keeps the card legible over an arbitrary photograph — a bright dial can
   otherwise sit right behind the password field. */
.watch-hero-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .45);
  z-index: 1;
}
body.watch-login .login-card {
  position: relative;
  z-index: 2;
  backdrop-filter: blur(2px);
}

/* ---------- All Watches: the card grid ---------- */
.watch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
  margin: 1.4em 0 0;
  padding: 0;
  list-style: none;
}
.watch-card {
  background: var(--surface-card);
  border: 1px solid var(--rule);
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0,0,0,.08);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* WHOLE WATCH, NOT A CROP OF ONE. John, 2026-08-05: the thumbnails were cutting
   off part of each watch's bezel.

   The cause was `object-fit: cover` in a 4:3 landscape slot while the
   photographs are portrait — median ratio 0.66. Cover fills the box and crops
   the overflow, so the card was showing as little as 43% of the photo's height,
   taken from the middle. On a watch photographed head-on, the middle is the dial
   and the parts lost off the top and bottom are the bezel and the lugs.

   `contain` shows the entire photograph whatever its shape, so nothing can be
   cropped again. The box is 3/4 because that is the shape that wastes least
   around these particular photos — measured across all 18 leads, it leaves 15%
   empty on average and 27% at worst, against 30%/42% for a square and 48%/57%
   for the 4:3 it replaces.

   Padding keeps a watch off the card edge; the surrounding surface reads as a
   deliberate mount rather than a gap. */
.watch-card .watch-lead {
  display: block;
  background: var(--surface-sunken);
  aspect-ratio: 3 / 4;
  overflow: hidden;
}
.watch-card .watch-lead img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 8px;
  box-sizing: border-box;
  display: block;
  transition: transform .18s ease;
}
.watch-card .watch-lead:hover img { transform: scale(1.03); }
/* A watch with no photograph still gets a card — the collection is the
   point, not the photography. */
.watch-card .watch-lead.is-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted4);
  font-size: calc(.8em * var(--fs-small));
  font-style: italic;
}
.watch-card-body { padding: 12px 14px 14px; display: flex; flex-direction: column; flex: 1; }
.watch-brand {
  font-size: calc(.78em * var(--fs-small));
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-strong);
  margin-bottom: .2em;
}
.watch-title { font-size: 1.02em; font-weight: bold; color: var(--ink-strong); margin: 0 0 .3em; }
.watch-title a { color: inherit; text-decoration: none; }
.watch-title a:hover { text-decoration: underline; }
.watch-ref { font-size: calc(.82em * var(--fs-small)); color: var(--muted); margin-bottom: .5em; }
/* Key facts. Specs are sparse — case_size_mm is present on only 8 of the 18
   initial watches — so this is a flow of chips, not a fixed set of slots: a
   card with one fact looks deliberate rather than broken. */
.watch-facts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; padding-top: .5em; }
.watch-chip {
  background: var(--chip-bg);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 1px 9px;
  font-size: calc(.76em * var(--fs-small));
  color: var(--ink-accent);
  white-space: nowrap;
}
/* A departed watch keeps its card and says so — lifecycle over deletion. */
.watch-badge-departed {
  background: var(--warn-bg);
  border-color: var(--rule-hot);
  color: var(--ink-quote);
  font-style: italic;
}
.watch-count { color: var(--muted); font-size: calc(.85em * var(--fs-small)); }

/* ---------- One watch ---------- */
.watch-head { margin-bottom: 1.2em; }
.watch-head h1 { margin-bottom: .15em; }
.watch-subtitle { color: var(--ink-accent); font-size: 1em; margin: 0 0 .4em; }
.watch-gallery { display: flex; flex-wrap: wrap; gap: 14px; margin: 1em 0 1.6em; }
.watch-gallery figure { margin: 0; max-width: 320px; }
.watch-gallery img {
  max-width: 100%;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--surface-sunken);
  display: block;
}
.watch-gallery figcaption {
  font-size: calc(.8em * var(--fs-small));
  color: var(--ink-caption);
  margin-top: .35em;
  line-height: 1.4;
}
/* Specs. Two columns on a wide screen, one on a phone. Absent specs are not
   rendered at all rather than shown empty, because most watches are missing
   most of them. */
.spec-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: .3em 1.1em;
  margin: 0 0 1.6em;
  font-size: calc(.94em * var(--fs-small));
}
.spec-list dt { color: var(--ink-accent); font-weight: bold; }
.spec-list dd { margin: 0; color: var(--ink); }
@media (min-width: 800px) {
  .spec-list { grid-template-columns: max-content 1fr max-content 1fr; }
}
/* The gated block: money and acquisition. Rendered only for an authenticated
   reader — today that is everyone who can see any page at all, but the block
   is marked so that opening the site later is a template change and nothing
   more (John's decision 2: prices stay gated forever). */
.watch-private {
  background: var(--surface-tint2);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--gold);
  border-radius: 6px;
  padding: .9em 1.1em;
  margin: 0 0 1.6em;
}
.watch-private h2 { margin-top: 0; }
.watch-private .private-note { font-size: calc(.82em * var(--fs-small)); color: var(--muted); font-style: italic; }
.accessory-table { width: 100%; border-collapse: collapse; font-size: calc(.88em * var(--fs-small)); }
.accessory-table th, .accessory-table td {
  text-align: left;
  padding: .35em .6em .35em 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.accessory-table th { color: var(--ink-accent); }
.accessory-table td.num { text-align: right; white-space: nowrap; }
/* An unknown price is shown as unknown, never as zero and never guessed. */
.accessory-table td.unknown { color: var(--muted4); font-style: italic; }
.open-threads {
  background: var(--open-bg);
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: .8em 1.1em .8em 2em;
  margin: 0 0 1.6em;
  font-size: calc(.9em * var(--fs-small));
}
.watch-body { line-height: 1.65; }
.watch-nav { margin: 2em 0 0; font-size: calc(.85em * var(--fs-small)); }
.watch-nav a { color: var(--link); }

@media print {
  .watch-grid { grid-template-columns: 1fr 1fr; gap: 8mm; }
  .watch-card { box-shadow: none; border: 1px solid #000; page-break-inside: avoid; }
  .watch-nav, .auth-bar { display: none; }
}

/* The "All watches" link repeated at the TOP of a watch page. The bottom copy
   keeps .watch-nav's generous top margin, which would push this one away from
   the title it sits above. */
.watch-nav-top { margin: 0 0 1em; }

/* The front page is now a title page anyone can walk past, not a gate, so it
   needs a primary way IN rather than a password field. */
.splash-card { text-align: center; }
.splash-card .login-lede { text-align: left; }
.splash-enter {
  display: block;
  width: 100%;
  box-sizing: border-box;
  background: var(--gold);
  color: var(--on-accent);
  border-radius: 6px;
  padding: .7em 1em;
  font-size: 1em;
  text-decoration: none;
  margin: .2em 0 0;
}
.splash-enter:hover { background: var(--link); }

/* Grouping control on the cards page. Plain links — the active grouping lives
   in the URL, so a view can be bookmarked or opened in a second tab to compare
   against another. */
.watch-groupbar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 1.2em;
}
.group-opt {
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 2px 12px;
  font-size: calc(.82em * var(--fs-small));
  text-decoration: none;
  color: var(--link);
  background: var(--surface);
}
.group-opt:hover { background: var(--surface-tint-hover); }
.group-opt.is-on {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--on-accent);
}
/* Each group is a <details>, so collapsing is native: keyboard-operable,
   announced properly, and working with JavaScript unavailable. */
.watch-group { margin: 1.6em 0 0; }
.watch-group:first-of-type { margin-top: 0; }
.watch-group-head {
  cursor: pointer;
  list-style: none;                 /* hide the default triangle... */
  border-bottom: 1px solid var(--rule);
  padding-bottom: .25em;
  display: flex;
  align-items: baseline;
  gap: .45em;
}
.watch-group-head::-webkit-details-marker { display: none; }  /* ...and in Safari */
/* The heading is INSIDE the summary so the outline survives; it must not
   introduce its own block box or the chevron loses its baseline. */
.watch-group-head h2 {
  display: inline;
  font-size: 1.05em;
  color: var(--ink-accent);
  margin: 0;
  border: 0;
  padding: 0;
}
.watch-group-head .chev {
  color: var(--muted3);
  font-size: 1.1em;
  line-height: 1;
  transition: transform .15s ease;
  display: inline-block;
}
.watch-group[open] > .watch-group-head .chev { transform: rotate(90deg); }
.watch-group-head:hover h2 { color: var(--link-hot); }
.watch-group-count {
  color: var(--muted3);
  font-weight: normal;
  font-size: calc(.82em * var(--fs-small));
}
/* The grid carries its own top margin; inside a group the summary supplies the
   separation, so it does not need a second one. */
.watch-group > .watch-grid { margin-top: .9em; }

/* Filter chips: narrow the page to one brand or movement. Same shape as the
   grouping pills a row above, one step quieter, so the two rows read as
   related controls rather than competing ones. */
.watch-filterbar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: -.6em 0 1.3em;
}
.filter-opt {
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 1px 10px;
  font-size: calc(.78em * var(--fs-small));
  text-decoration: none;
  color: var(--ink-accent);
  background: var(--chip-bg);
}
.filter-opt:hover { background: var(--surface-tint-hover); }
.filter-opt.is-on {
  background: var(--ink-accent);
  border-color: var(--ink-accent);
  color: var(--on-accent);
}
.filter-n { opacity: .65; }

@media print {
  .watch-groupbar, .watch-filterbar, .watch-group-head .chev { display: none; }
  /* A collapsed group must still print — paper has no disclosure triangle. */
  .watch-group > .watch-grid { display: grid !important; }
}

/* A card appearing in a bin it is TAGGED into, rather than one that is its
   primary category. Quieter than a fact chip — it describes the card's place on
   the page, not the watch. */
.watch-chip-also {
  background: transparent;
  border-style: dashed;
  color: var(--muted2);
  font-style: italic;
}

/* Provenance link on a sourced specification. Deliberately quiet — it should be
   findable when you wonder where a figure came from, and invisible when you do
   not. The note rides in the title attribute. */
.spec-src {
  font-size: calc(.72em * var(--fs-small));
  color: var(--muted3);
  text-decoration: none;
  border-bottom: 1px dotted var(--muted4);
  margin-left: .35em;
  white-space: nowrap;
}
.spec-src:hover { color: var(--link); border-bottom-color: var(--link); }

/* ===================================================================
   ARTICLES  (2026-08-05)
   -------------------------------------------------------------------
   The public half of the site. Articles are self-contained static HTML
   authored by Cowork, but they link to THIS stylesheet, so they inherit
   the light/dark toggle, the text-size control and the typography
   without each carrying its own design system.

   That is the opposite of JSB Coins, where every article embeds its own
   tokens and fonts. Coins' articles are one-off illustrated essays and
   the design is part of the argument; these are reference pieces about
   how watches work, and consistency serves them better than variety —
   it also means Cowork writes prose, not CSS.
   =================================================================== */

/* ---------- The bar on the landing page ---------- */
.splash-section-label {
  font-size: calc(.72em * var(--fs-small));
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted3);
  margin: 0 0 .5em;
  text-align: left;
}
.splash-articles {
  list-style: none;
  margin: 0 0 1.1em;
  padding: 0;
  text-align: left;
}
.splash-articles li {
  padding: .45em 0;
  border-top: 1px solid var(--rule);
}
.splash-articles li:first-child { border-top: 0; }
.splash-articles a {
  color: var(--link);
  text-decoration: none;
  font-weight: bold;
  display: block;
}
.splash-articles a:hover { text-decoration: underline; }
.splash-kicker {
  display: block;
  font-size: calc(.76em * var(--fs-small));
  color: var(--muted2);
  margin-top: .1em;
}
.splash-more {
  text-align: left;
  margin: 0 0 1.2em;
  font-size: calc(.82em * var(--fs-small));
}
.splash-more a { color: var(--link); text-decoration: none; }
.splash-more a:hover { text-decoration: underline; }

/* ---------- The Articles page ---------- */
.article-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px;
  margin: 1.4em 0 0;
  padding: 0;
  list-style: none;
}
.article-card {
  background: var(--surface-card);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--gold);
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0,0,0,.08);
}
.article-card > a {
  display: block;
  padding: 14px 16px 16px;
  text-decoration: none;
  color: inherit;
}
.article-card:hover { border-left-color: var(--link-hot); }
.article-card-kicker {
  font-size: calc(.74em * var(--fs-small));
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-strong);
  margin: 0 0 .3em;
}
.article-card-title {
  font-size: 1.05em;
  color: var(--ink-strong);
  margin: 0 0 .4em;
}
.article-card > a:hover .article-card-title { text-decoration: underline; }
.article-card-blurb {
  margin: 0;
  color: var(--ink);
  font-size: calc(.9em * var(--fs-small));
  line-height: 1.55;
}
/* Code wrote two placeholder articles so this feature could be built against
   something real. Labelled on the page, not just in the file: an unlabelled
   placeholder is what quietly becomes permanent. */
.article-card-flag {
  font-size: calc(.62em * var(--fs-small));
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted3);
  border: 1px dashed var(--rule);
  border-radius: 999px;
  padding: 0 7px;
  margin-left: .6em;
  vertical-align: middle;
  font-weight: normal;
}

/* ---------- An article page ---------- */
/* Set on <body> by each article. Narrow measure, because these are read rather
   than scanned: roughly 70 characters, which is where prose stops being work. */
body.article-page {
  max-width: 42rem;
  margin: 0 auto;
  padding: 1.5em 1.2em 3em;
  line-height: 1.7;
}
.article-back {
  font-size: calc(.85em * var(--fs-small));
  margin: 0 0 1.6em;
}
.article-back a { color: var(--link); text-decoration: none; }
.article-back a:hover { text-decoration: underline; }
.article-back-foot { margin: 2.4em 0 0; border-top: 1px solid var(--rule); padding-top: 1em; }
.article-kicker {
  font-size: calc(.76em * var(--fs-small));
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted-strong);
  margin: 0 0 .3em;
}
.article-body h1 {
  font-size: 1.7em;
  color: var(--ink-strong);
  margin: 0 0 .5em;
  border-bottom: 3px solid var(--link);
  padding-bottom: .25em;
}
.article-body h2 {
  font-size: 1.15em;
  color: var(--ink-accent);
  margin: 1.8em 0 .5em;
}
.article-lede {
  font-size: 1.08em;
  color: var(--ink-quote);
  font-style: italic;
  margin: 0 0 1.6em;
}
.article-body p { margin: 0 0 1.1em; }
.article-body img {
  max-width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: 6px;
}
.article-body figure { margin: 1.6em 0; }
.article-body figcaption {
  font-size: calc(.82em * var(--fs-small));
  color: var(--ink-caption);
  margin-top: .4em;
}
.article-body blockquote {
  border-left: 3px solid var(--rule);
  margin: 1.4em 0;
  padding: .2em 0 .2em 1.1em;
  color: var(--ink-quote);
}

/* Separator between the two nav links at the top of a collection page. */
.nav-sep { color: var(--muted4); margin: 0 .5em; }

@media print {
  .article-back { display: none; }
  body.article-page { max-width: none; }
}
