/* THE COUNCIL OF SIX — storefront
   ==================================================================
   Authored, not templated. build_site.py writes the HTML around this
   file and never rewrites it. Same for assets/js/store.js.

   TWO GROUNDS, AND THE SWITCH MEANS SOMETHING.

   Almost every shop in this category is dark: purple, starfields,
   glowing quartz. This series sells honesty about evidence, so the
   shop is BONE — plain, bright, set like a reference work — and the
   night ground is reserved for the one place the Council actually
   speaks. Light where we sell, dark where the voices talk. If a
   section is on night and nobody is speaking, it is on the wrong
   ground.

   TWENTY-THREE LIGHTS, NOT ONE.
   The sister imprints have a single accent sampled off their jackets.
   This one has twenty-three, because each volume's jacket carries its
   own, and that spectrum in attestation order IS the series. So the
   accent is not a token here — it is a per-page custom property,
   --accent-bone / --accent-night, injected by build_site.py.

   Every one of those forty-six values is SOLVED to 4.5:1 against its
   ground by site_content.solve_contrast(), holding the hue. None of
   them was picked by eye, because twenty-three could not be, and the
   raw jacket colours all fail on bone. site_audit.py re-checks them.
   ================================================================== */

:root {
  /* --- bone: the ground we sell on. Warm, because the stock is. --- */
  --bone:        #F2EFE9;
  --bone-raise:  #FBF9F5;
  --bone-sink:   #E7E3DA;
  --bone-line:   #D6D1C6;   /* decorative rules */
  --bone-edge:   #8A8377;   /* borders of things you click or type in, 3.2:1 */

  --ink:         #16151A;   /* body on bone, 15.9:1 */
  --ink-mid:     #45424B;   /* secondary on bone, 8.7:1 */
  --ink-dim:     #63606A;   /* muted label on bone, 5.6:1 */

  /* --- night: the ground the Council speaks on. The jacket. --- */
  --night:       #101116;
  --night-raise: #1A1B22;
  --night-sink:  #08080C;
  --night-line:  #2B2C36;

  --chalk:       #EDEAE3;   /* body on night, 16.0:1 */
  --chalk-mid:   #B0ACA3;   /* secondary on night, 8.9:1 */
  --chalk-dim:   #8A867E;   /* muted label on night, 5.5:1 */

  /* Series default accent, used where no single volume owns the page.
     Amber, the commonest hue across the twenty-three jackets. */
  --accent-bone:  #88672F;
  --accent-night: #C09448;

  /* Instrument Serif has one weight and a real italic. That restraint
     is the point: a display face with nine weights invites nine
     decisions, and this page needs about two. Newsreader carries the
     long passages — six voices in a row is a lot of reading, and it
     has an optical-size axis that is allowed to do its job. */
  --display: "Instrument Serif", "Iowan Old Style", Palatino, Georgia, serif;
  --body:    "Newsreader", Georgia, "Times New Roman", serif;
  --data:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --wrap: 1180px;
  --measure: 34rem;
  --pad: clamp(1.15rem, 4vw, 3rem);
  --band: clamp(3.5rem, 7.5vw, 6.5rem);

  --lift: 0 22px 44px -28px rgb(22 21 26 / 0.45), 0 2px 5px -3px rgb(22 21 26 / 0.28);
}

/* ------------------------------------------------------------ reset */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--body);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.075rem);
  line-height: 1.62;
  font-optical-sizing: auto;
}

/* Attributes reserve the space and stop layout shift; height:auto is what
   lets aspect-ratio still apply. Both are needed. */
img { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

h1, h2, h3, h4 { margin: 0; font-weight: 400; line-height: 1.12; }
p, ul, ol, dl, table, figure { margin: 0; }
ul, ol { padding-left: 1.15rem; }

button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent-bone);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 60;
  background: var(--ink); color: var(--bone);
  padding: 0.75rem 1.1rem; text-decoration: none;
}
.skip:focus { left: 0; }

.wrap { width: min(100% - (var(--pad) * 2), var(--wrap)); margin-inline: auto; }
.measure { max-width: var(--measure); }

/* `.wrap` centres itself with auto margins, so putting `.measure` on the SAME
   element shrinks the box to 34rem and then centres THAT — the column drifts
   into the middle of the page and no longer lines up with the breadcrumb above
   it. When both are on one element, the wrap keeps its width and the children
   take the measure instead. */
.wrap.measure { max-width: var(--wrap); }
.wrap.measure > * { max-width: var(--measure); }

/* ------------------------------------------------- ground switching */

.on-night {
  background: var(--night);
  color: var(--chalk);
}
.on-night h1, .on-night h2, .on-night h3 { color: var(--chalk); }
.on-night .dim { color: var(--chalk-dim); }
.on-night .mid { color: var(--chalk-mid); }
.on-night .rule { border-color: var(--night-line); }

.dim { color: var(--ink-dim); }
.mid { color: var(--ink-mid); }

/* --------------------------------------------------------- typography */

.display {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: -0.005em;
  line-height: 1.04;
}
.display--xl  { font-size: clamp(2.6rem, 1.5rem + 4.6vw, 5.1rem); }
.display--lg  { font-size: clamp(2rem, 1.35rem + 2.6vw, 3.3rem); }
.display--md  { font-size: clamp(1.5rem, 1.2rem + 1.3vw, 2.15rem); }
.display--sm  { font-size: clamp(1.22rem, 1.1rem + 0.6vw, 1.5rem); }

.eyebrow {
  font-family: var(--data);
  font-size: 0.71rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.on-night .eyebrow { color: var(--chalk-dim); }

.lede { font-size: clamp(1.1rem, 1.02rem + 0.4vw, 1.3rem); line-height: 1.55; }

.data { font-family: var(--data); font-variant-numeric: tabular-nums; }
.small { font-size: 0.86rem; }

.stack > * + * { margin-top: 1rem; }
.stack-lg > * + * { margin-top: 1.75rem; }

.rule { border: 0; border-top: 1px solid var(--bone-line); margin: 0; }

/* ------------------------------------------------------------ masthead */

.head {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bone) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--bone-line);
}
.head__in {
  display: flex; align-items: center; gap: 1.25rem;
  min-height: 3.9rem; flex-wrap: wrap;
}
.wordmark {
  display: flex; align-items: center; gap: 0.6rem;
  text-decoration: none; margin-right: auto;
}
.wordmark__mark { width: 1.5rem; height: 1.5rem; flex: none; }
.wordmark__name {
  font-family: var(--display);
  font-size: 1.24rem;
  letter-spacing: 0.005em;
}
.nav {
  display: flex; align-items: center; gap: clamp(0.7rem, 1.6vw, 1.5rem);
  font-size: 0.87rem;
}
.nav a { text-decoration: none; padding: 0.35rem 0; border-bottom: 1px solid transparent; }
.nav a:hover { border-bottom-color: var(--accent-bone); }
.nav__cart {
  font-family: var(--data); font-size: 0.78rem;
  border: 1px solid var(--bone-edge) !important;
  border-radius: 999px; padding: 0.3rem 0.75rem !important;
}
.nav__count[data-empty="1"] { opacity: 0.5; }

@media (max-width: 640px) {
  .nav { width: 100%; order: 3; overflow-x: auto; padding-bottom: 0.5rem; }
}

/* --------------------------------------------------------------- marks */

/* The series mark: six nodes on a ring with every chord between them.
   Fifteen chords for six voices — the number of distinct disagreements
   available in the room, which is the whole proposition. Drawn as SVG
   so it stays crisp and inherits currentColor. */
.mark { display: block; }
.mark circle[data-node] { fill: currentColor; }
.mark line, .mark circle[data-ring] { stroke: currentColor; fill: none; }

/* ------------------------------------------------------------ sections */

.band { padding-block: var(--band); }
.band--tight { padding-block: calc(var(--band) * 0.55); }

.section-head { display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
.section-head .eyebrow { margin-left: auto; }

/* Argument left, evidence right. A reading measure with two feet of dead
   space beside it reads as an unfinished layout, and this page has a table
   worth putting there. `minmax(0, …)` on both tracks because the right one
   holds a table: a bare `1fr` floors at its content's min-content width and
   shoves the whole page sideways on a phone. */
.split {
  display: grid; gap: clamp(1.8rem, 4vw, 3.5rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 900px) {
  .split { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
}
.split > .stack-lg, .split > div > p { max-width: 38rem; }

/* ---------------------------------------------------------------- hero */

.hero { padding-block: clamp(3rem, 7vw, 6rem) 0; }
.hero__claim { max-width: 22ch; }
.hero__sub { max-width: 46ch; margin-top: 1.4rem; }

.hero__figure { margin-top: clamp(2rem, 4vw, 3.5rem); }
.hero__figure img {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: 2px;
}

/* --------------------------------------------- THE SIGNATURE: a reading
   One entry, read six times, laid out the way a critical edition lays out
   its apparatus: the speaker in the margin, the reading in the measure.
   You can find the Skeptic without reading a word of the other five, which
   is exactly how people use this book. */

.reading { --gap: clamp(1rem, 2.4vw, 2.25rem); }

.reading__head {
  display: flex; align-items: baseline; gap: 0.9rem;
  flex-wrap: wrap; padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--night-line);
}
.reading__title { font-family: var(--display); font-size: clamp(1.6rem, 1.2rem + 1.7vw, 2.6rem); }
.reading__from { font-family: var(--data); font-size: 0.74rem; letter-spacing: 0.13em;
                 text-transform: uppercase; color: var(--chalk-dim); margin-left: auto; }

.voices { margin-top: 1.6rem; }

.voice {
  display: grid;
  grid-template-columns: 10.5rem minmax(0, 1fr);
  gap: var(--gap);
  padding-block: 1.15rem;
  border-top: 1px solid var(--night-line);
}
.voice:first-child { border-top: 0; }

.voice__name {
  font-family: var(--data);
  font-size: 0.73rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-night);
  padding-top: 0.3rem;
  align-self: start;
}
.voice__text { color: var(--chalk); max-width: 46rem; }

@media (max-width: 720px) {
  .voice { grid-template-columns: minmax(0, 1fr); gap: 0.45rem; }
}

.reading__actions {
  display: flex; gap: 0.8rem; flex-wrap: wrap; align-items: center;
  margin-top: 1.9rem; padding-top: 1.4rem; border-top: 1px solid var(--night-line);
}

/* ------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  font-family: var(--data); font-size: 0.8rem; letter-spacing: 0.07em;
  text-transform: uppercase; text-decoration: none;
  padding: 0.72rem 1.3rem; border-radius: 2px; cursor: pointer;
  border: 1px solid var(--ink); background: var(--ink); color: var(--bone);
  transition: transform 0.12s ease, background-color 0.15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: none; }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--bone-sink); }
.on-night .btn { background: var(--chalk); border-color: var(--chalk); color: var(--night); }
.on-night .btn--ghost { background: transparent; color: var(--chalk); border-color: var(--night-line); }
.on-night .btn--ghost:hover { background: var(--night-raise); }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; transform: none; }

/* --------------------------------------------------------------- shelf */

.shelf {
  display: grid; gap: clamp(1.4rem, 2.6vw, 2.4rem);
  grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
}

.vol {
  display: flex; flex-direction: column; gap: 0.75rem;
  text-decoration: none;
}
.vol__jacket {
  position: relative; display: block;
  aspect-ratio: 1600 / 2560; overflow: hidden;
  background: var(--night); border-radius: 2px;
  box-shadow: var(--lift);
  transition: transform 0.18s ease;
}
.vol:hover .vol__jacket { transform: translateY(-3px); }
.vol__jacket img { width: 100%; height: 100%; object-fit: cover; }
.vol__num {
  font-family: var(--data); font-size: 0.7rem; letter-spacing: 0.13em;
  color: var(--accent-bone);
}
.vol__title { font-family: var(--display); font-size: 1.28rem; line-height: 1.1; }
.vol__sub { font-size: 0.85rem; color: var(--ink-dim); line-height: 1.4; }
.vol__foot {
  display: flex; gap: 0.7rem; align-items: baseline; margin-top: auto;
  padding-top: 0.5rem; font-family: var(--data); font-size: 0.76rem;
}
.vol__price { color: var(--ink); }
.vol__pages { color: var(--ink-dim); }

/* -------------------------------------------------------- evidence chip */

/* The shop sorts itself by how well evidenced each system is. No other
   shop in this category will tell you that, and it is the honest filter
   the series is built on — so it gets a real component, not a footnote. */
.chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-family: var(--data); font-size: 0.68rem; letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.24rem 0.6rem; border-radius: 999px;
  border: 1px solid var(--bone-edge); color: var(--ink-mid);
  background: var(--bone-raise);
  /* A pill that wraps to two lines stops reading as a pill and starts reading
     as a speech bubble. It stays on one line and the table scrolls instead. */
  white-space: nowrap;
}
.chip__dot { width: 0.45rem; height: 0.45rem; border-radius: 50%; background: currentColor; flex: none; }
.chip[data-evidence="evidence-informed"] { color: #3D6B45; border-color: #3D6B45; }
.chip[data-evidence="mixed"]             { color: #5B6480; border-color: #5B6480; }
.chip[data-evidence="contested"]         { color: #7A5E2C; border-color: #7A5E2C; }
.chip[data-evidence="traditional"]       { color: #63606A; border-color: #8A8377; }
.chip[data-evidence="unevidenced"]       { color: #8A4A2A; border-color: #8A4A2A; }
.chip[data-evidence="disconfirmed"]      { color: #9A3324; border-color: #9A3324; }
.on-night .chip { background: transparent; }

/* ------------------------------------------------------------- filters */

.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.filters button {
  font-family: var(--data); font-size: 0.72rem; letter-spacing: 0.08em;
  text-transform: uppercase; background: transparent; cursor: pointer;
  border: 1px solid var(--bone-edge); border-radius: 999px;
  padding: 0.33rem 0.8rem;
}
.filters button[aria-pressed="true"] { background: var(--ink); color: var(--bone); border-color: var(--ink); }

/* --------------------------------------------------------------- table */

/* A `1fr` track floors at its content's min-content width, so one wide
   table shoves the whole page sideways on a phone. Every scroll container
   here is explicit rather than relying on the grid. */
.scroller { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table.tbl { border-collapse: collapse; width: 100%; font-size: 0.92rem; }
table.tbl th, table.tbl td {
  text-align: left; padding: 0.62rem 1rem 0.62rem 0;
  border-bottom: 1px solid var(--bone-line); vertical-align: top;
}
table.tbl th {
  font-family: var(--data); font-size: 0.7rem; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--ink-dim); font-weight: 400;
  border-bottom-color: var(--bone-edge);
}
table.tbl td.num { font-family: var(--data); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The ledger's first two columns carry a volume number and a title that should
   not be broken across four lines when the table is squeezed. The container
   scrolls; the cells do not concertina. */
table.tbl td:first-child { white-space: nowrap; }
table.tbl th:nth-child(2), table.tbl td:nth-child(2) { min-width: 12rem; }
.on-night table.tbl th, .on-night table.tbl td { border-bottom-color: var(--night-line); }
.on-night table.tbl th { color: var(--chalk-dim); }

/* -------------------------------------------------------- volume page */

.vol-hero { display: grid; gap: clamp(1.8rem, 4vw, 3.5rem); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 860px) {
  .vol-hero { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); align-items: start; }
}
.vol-hero__jacket { box-shadow: var(--lift); border-radius: 2px; overflow: hidden; }

.facts { display: grid; gap: 0.1rem 1.4rem; grid-template-columns: max-content minmax(0, 1fr); font-size: 0.9rem; }
.facts dt { font-family: var(--data); font-size: 0.7rem; letter-spacing: 0.1em;
            text-transform: uppercase; color: var(--ink-dim); padding-top: 0.42rem; }
.facts dd { margin: 0; padding-top: 0.3rem; }

.contents { columns: 2; column-gap: 2.5rem; font-size: 0.92rem; }
@media (max-width: 700px) { .contents { columns: 1; } }
.contents ol { padding-left: 1.3rem; }
.contents li { break-inside: avoid; margin-bottom: 0.28rem; }
.contents h3 { break-after: avoid; margin: 1.1rem 0 0.5rem; }

.limits {
  border-left: 2px solid var(--accent-bone);
  padding: 0.15rem 0 0.15rem 1.15rem;
}

/* ----------------------------------------------------------- buy panel */

.buy {
  border: 1px solid var(--bone-edge); border-radius: 2px;
  padding: clamp(1.1rem, 2.4vw, 1.6rem);
  background: var(--bone-raise);
  display: grid; gap: 0.9rem;
}
.buy__price { font-family: var(--display); font-size: 2.1rem; line-height: 1; }
.buy__row { display: flex; gap: 0.7rem; align-items: center; flex-wrap: wrap; }
.qty { display: inline-flex; align-items: center; border: 1px solid var(--bone-edge); border-radius: 2px; }
.qty button { background: none; border: 0; cursor: pointer; padding: 0.5rem 0.75rem; font-family: var(--data); }
.qty output { font-family: var(--data); min-width: 2.2rem; text-align: center; }

/* ---------------------------------------------------------------- faq */

.faq details {
  border-top: 1px solid var(--bone-line);
  padding: 0.95rem 0;
}
.faq details:last-of-type { border-bottom: 1px solid var(--bone-line); }
.faq summary {
  cursor: pointer; font-family: var(--display); font-size: 1.16rem;
  list-style: none; display: flex; gap: 1rem; align-items: baseline;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; margin-left: auto; font-family: var(--data); color: var(--ink-dim); }
.faq details[open] summary::after { content: "\2212"; }
.faq p { margin-top: 0.7rem; max-width: var(--measure); }

/* -------------------------------------------------------------- figure */

figure.plate { margin: 0; }
figure.plate img { width: 100%; object-fit: cover; border-radius: 2px; }
figure.plate figcaption {
  margin-top: 0.6rem; font-size: 0.8rem; color: var(--ink-dim);
  font-family: var(--data); letter-spacing: 0.02em;
}
.on-night figure.plate figcaption { color: var(--chalk-dim); }

.plate--wide img { aspect-ratio: 21 / 9; }
.plate--land img { aspect-ratio: 3 / 2; }
.plate--port img { aspect-ratio: 4 / 5; }

/* ------------------------------------------------------- the six voices
   Six long entries stacked identically read as a list of six of the same
   thing, which is the opposite of the claim the page makes. The plate
   swaps sides on every second voice so the eye has to re-find the column.
   Below 900px the whole card collapses to one column, because an
   alternating grid there only produces an inconsistent reading order. */

.voice-card {
  display: grid; gap: clamp(1.5rem, 3.5vw, 3rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  padding-block: clamp(2rem, 4vw, 3.2rem);
  border-top: 1px solid var(--bone-line);
}
.voice-card:first-child { border-top: 0; padding-top: 0; }
.voice-card__body { max-width: 42rem; }

@media (min-width: 900px) {
  .voice-card { grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); }
  .voice-card--flip { grid-template-columns: minmax(0, 1fr) minmax(0, 19rem); }
  .voice-card--flip .voice-card__body { order: -1; }
  /* No plate on disk: one column, or the prose sits in the picture's slot. */
  .voice-card--solo { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------- research
   Provenance and evidence. A transmission is a sequence, so it is an <ol>
   with a hanging date column and a rule down the left — scannable by date
   without reading a word of it. */

.chain { list-style: none; padding: 0; margin: 0; }
.chain__step {
  display: grid; gap: 0.35rem 1.6rem;
  grid-template-columns: minmax(0, 1fr);
  padding: 1.15rem 0 1.15rem 1.15rem;
  border-left: 2px solid var(--bone-line);
}
.chain__when {
  font-size: 0.72rem; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--ink-dim); padding-top: 0.25rem; margin: 0;
}
.chain__who { font-weight: 500; margin: 0 0 0.3rem; }
.chain__step p { max-width: 44rem; }
.chain--index .chain__step { padding-block: 1.6rem; }
.chain--index .chain__step:hover { border-left-color: var(--accent-bone); }
.chain--index .chain__who .chip { margin-left: 0.5rem; vertical-align: 0.1em; }

@media (min-width: 760px) {
  .chain__step { grid-template-columns: 8.5rem minmax(0, 1fr); }
  /* The timeline rows carry a thumbnail between the date and the text. The
     thumb column disappears below 760px rather than shrinking, because a
     100px picture of a dark room is a smudge. */
  .chain__step--art { grid-template-columns: 7rem 13rem minmax(0, 1fr); }
}
.chain__thumb { display: none; }
@media (min-width: 760px) {
  .chain__thumb { display: block; align-self: start; margin-top: 0.15rem; }
  .chain__thumb img {
    width: 100%; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 2px;
    filter: saturate(0.9);
    transition: filter 0.25s ease, transform 0.25s ease;
  }
  .chain__thumb:hover img { filter: none; transform: scale(1.015); }
}
.on-night .chain__step { border-left-color: var(--night-line); }
.on-night .chain__when { color: var(--chalk-dim); }

.artifact { font-size: 1.08rem; line-height: 1.35; margin: 0 0 0.25rem; }

/* A correction is a claim the reader arrives already believing, then the
   record. The claim is italic and dimmed so it can never be misread as the
   page's own assertion — the most important distinction on these pages. */

.corrections { display: grid; gap: 1.6rem; margin-top: 1.4rem; }
.corrections--index { grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr)); }
.correction {
  border-left: 2px solid var(--accent-bone);
  padding: 0.1rem 0 0.1rem 1.15rem;
  max-width: 44rem;
}
.correction__claim { font-style: italic; color: var(--ink-dim); margin-bottom: 0.55rem; }
.on-night .correction { border-left-color: var(--accent-night); }
.on-night .correction__claim { color: var(--chalk-dim); }

.studies {
  display: grid; gap: 1.4rem; margin-top: 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr));
}
.study { border: 1px solid var(--bone-line); border-radius: 2px; padding: 1.15rem 1.25rem; }
.study p { margin-bottom: 0.55rem; }
.study p:last-child { margin-bottom: 0; }
.study__cite { font-size: 1.02rem; }
.study__label {
  font-family: var(--data); font-size: 0.65rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-dim); margin-right: 0.5rem;
}
.on-night .study { border-color: var(--night-line); }
.on-night .study__label { color: var(--chalk-dim); }

/* --------------------------------------------------------------- cart */

.line {
  display: grid; gap: 1rem; align-items: center;
  grid-template-columns: 4.5rem minmax(0, 1fr) max-content;
  padding: 1rem 0; border-top: 1px solid var(--bone-line);
}
.line img { border-radius: 2px; box-shadow: var(--lift); }
.totals { display: grid; gap: 0.35rem; margin-left: auto; max-width: 22rem; }
.totals div { display: flex; justify-content: space-between; gap: 2rem; font-family: var(--data); font-size: 0.9rem; }
.totals div.grand { border-top: 1px solid var(--bone-edge); padding-top: 0.5rem; font-size: 1.05rem; }

.notice {
  border: 1px dashed var(--bone-edge); border-radius: 2px;
  padding: 1rem 1.2rem; background: var(--bone-sink);
}
.on-night .notice { background: var(--night-raise); border-color: var(--night-line); }

/* -------------------------------------------------------------- footer */

.foot { border-top: 1px solid var(--bone-line); padding-block: 3rem 4rem; font-size: 0.9rem; }
.foot__cols { display: grid; gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); }
.foot h2 { font-family: var(--data); font-size: 0.7rem; letter-spacing: 0.12em;
           text-transform: uppercase; color: var(--ink-dim); margin-bottom: 0.7rem; }
.foot ul { list-style: none; padding: 0; }
.foot li { margin-bottom: 0.35rem; }

/* -------------------------------------------------------------- motion
   Entrances are CSS with `backwards` fill, never a class a script adds:
   a reveal gated on JavaScript is a permanently blank page when the
   script fails. */

@keyframes rise {
  from { opacity: 0; transform: translateY(0.7rem); }
  to   { opacity: 1; transform: none; }
}
.rise { animation: rise 0.6s cubic-bezier(0.22, 0.61, 0.36, 1) backwards; animation-delay: var(--delay, 0ms); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

@media print {
  .head, .nav, .foot, .btn { display: none; }
  body { background: #fff; color: #000; }
}
