/* =====================================================================
   Dunia Anura — "Berkas Spesimen": the page below the field book.

   The detail pages open with the book (css/sketchbook.css). Everything
   under it is this: the desk the book was made on, and the file the book
   was made from. It is deliberately narrower than the book at every width,
   it has one left edge, and its only section header is the book's own leaf
   furniture translated into the page's sans — a number, a tracked word, a
   hairline. No display heading below the book competes with the name set
   on the paper.

   Three grounds, read top to bottom: BOOK (paper, 12% radius on nothing) →
   DESK (square-ish, 12px slips, hairlines, tabular figures) → SHOP (the
   design system's 32px cards and 999px pills, in "Serupa"). The corner
   radius is what marks each change; it is the one deliberate departure from
   ds/styles.css and it is stated here rather than scattered.

   This file loads AFTER css/sketchbook.css, so at equal specificity it
   wins — which is why nothing in here needs !important. If you find
   yourself reaching for one, an inline style attribute was left behind in
   site-src/pages/*-detail.html. Take it out instead.
   ===================================================================== */

body[data-page="species-detail"],
body[data-page="product-detail"] {
  /* one measure for everything below the book — 1240 at 1440, which is the
     measure the related grid already used, so the page finally has a single
     left edge instead of a 1060 counter under a 1240 body */
  --dsr-w:    min(1400px, calc(100vw - clamp(20px, 7vw, 100px) * 2));
  --dsr-gap:  clamp(16px, 1.7vw, 24px);      /* every grid gutter          */
  --dsr-band: clamp(56px, 5.2vw, 84px);      /* band to band               */
  --dsr-end:  clamp(84px, 9vh, 120px);       /* last band to the footer    */

  /* inks. The page's own tokens where they exist; the plate's values where
     the plate is what is being echoed. */
  --dsr-rule:  var(--color-neutral-400);     /* the plate's RULE, one step
                                                darker so it holds on cream */
  --dsr-hair:  var(--color-divider);
  --dsr-warn:  #a8761d;                      /* IUCN VU/EN                 */
  --dsr-alarm: #96442b;                      /* Stok habis, IUCN CR/EW/EX  */
  --dsr-chop:  #a34a30;                      /* the plate's RED, verbatim  */
  --dsr-trace: #a89b83;                      /* the plate's trace grey     */
  --dsr-card:  0 1px 2px rgba(58, 44, 26, .10), 0 6px 18px rgba(58, 44, 26, .07);
  --dsr-slip-r: 12px;
  --dsr-serif: 'Instrument Serif', "New York", Georgia, serif;
}

.dsr      { width: var(--dsr-w); margin-inline: auto; }
/* scroll-margin: the nav is fixed at y 14..78 at every width, so a band
   reached by its id (#sdPanelBand in a shared URL) would land with its head
   under the pill — the same 96px the transcript's record already uses */
.dsr-band { margin-top: var(--dsr-band); scroll-margin-top: 96px; }
.dsr-last { padding-bottom: var(--dsr-end); }
.dsr *    { box-sizing: border-box; }

/* Two bands exist in one state only. Gating the whole section — not just its
   body — is what lets DA.numberBands() count what is actually on the page, so
   a missing band leaves no hole in the numbering. */
.dsr-onlybook { display: none; }
html.has-book .dsr-onlybook { display: block; }
html.has-book .dsr-proseband { display: none; }
/* The product's Deskripsi block exists for the book's transcript only: without
   the book the same paragraph is already the lede under the photograph
   (#pdDesc) — measured at 390 it was printed twice, 900px apart. And 115 of
   184 products carry no tips, so without that block their Notes band would
   hold nothing at all; js/pages/product-detail.js marks those .no-tips. */
html:not(.has-book) .dsr-bookonly { display: none; }
html:not(.has-book) .dsr-proseband.no-tips { display: none; }

/* the breadcrumb keeps the measure too, so the page's left edge starts at
   the very top rather than at the counter */
.detail-top { padding: 150px 0 0; }
html.has-book .detail-top { padding-top: 96px; }
html.has-book .detail-top > div { margin-bottom: 12px; }

/* ---------------------------------------------------------- numerals */
.dsr-head .n, .dsr-plate .n, .dsr-row dd, .dsr-price, .dsr-time,
.dsr-pick .s, .dsr-avail b, .dsr-viewn {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* ================================================ the band head ======
   furniture() from js/sketchbook-plate.js at page scale: the leaf number,
   the tracked word, the rule under both, and the running head on the right.
   This is the only section header below the book. */
.dsr-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; column-gap: 20px;
  padding-bottom: 10px; margin-bottom: 26px;
  border-bottom: 1.5px solid var(--dsr-rule);
}
.dsr-head .l { display: flex; align-items: baseline; gap: 12px; min-width: 0; }
.dsr-head .n { font: 700 var(--fs-min)/1 var(--font-body); letter-spacing: .14em; color: var(--color-accent-700); }
.dsr-head .t { font: 700 var(--fs-read)/1 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--color-text); }
.dsr-head .r {
  font: 600 var(--fs-read)/1.2 var(--font-body); letter-spacing: .1em;
  text-transform: uppercase; color: var(--color-neutral-600);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dsr-head .r.run { font: italic 400 14px/1.2 var(--dsr-serif); letter-spacing: 0; text-transform: none; }

/* ================================================ the key/value row ==
   the plate's table(): key in the page's sans, value in the book's italic */
.dsr-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px;
  align-items: baseline; padding: 9px 0;
  border-bottom: 1px solid var(--dsr-hair); font-size: var(--fs-read); margin: 0;
}
.dsr-row dt { color: var(--color-neutral-600); }
.dsr-row dd { margin: 0; text-align: right; color: var(--color-neutral-800);
              font: italic 400 15.5px/1.35 var(--dsr-serif); }
/* — baris lembar perawatan, dengan ikonnya —
   Ikon datang dari Kolam BE: PNG transparan 1080x1080, garis tebal dengan
   isian kuning, keluarga yang sama dengan toko resmi. Ia duduk di atas cakram
   34 px, bukan langsung di atas kertas — kuning di atas krem nyaris hilang,
   dan cakram itu juga yang membuat delapan sampai dua belas baris terbaca
   sebagai satu keluarga, bukan sebagai gambar yang kebetulan berjejer.
   align-items center (bukan baseline seperti baris teks): yang disejajarkan
   di sini pusat cakram dengan pusat nilainya. */
.dsr-row--ico { align-items: center; padding: 7px 0; }
.dsr-row--ico dt { display: flex; align-items: center; gap: 11px; min-width: 0; color: var(--color-neutral-700); }
.dsr-ico {
  display: grid; place-items: center; width: 34px; height: 34px; flex: none;
  border-radius: 50%; background: var(--color-surface);
  box-shadow: inset 0 0 0 1px var(--dsr-hair);
}
.dsr-ico img { display: block; width: 26px; height: 26px; object-fit: contain; }
@media (max-width: 640px) {
  .dsr-row--ico { padding: 6px 0; }
  .dsr-ico { width: 30px; height: 30px; }
  .dsr-ico img { width: 22px; height: 22px; }
}
.dsr-row:last-child { border-bottom: 0; }
.dsr-dl { margin: 0; }

/* ============================================ 01 · KETERANGAN ========
   Band 01 does not take --dsr-band: the counter has to keep peeking under
   the book, which is what invites the scroll. */
.dsr-counterband { margin-top: clamp(26px, 4vh, 44px); }

.dsr-ledger {
  display: grid; grid-template-columns: minmax(0, auto) minmax(24px, 1fr) auto;
  align-items: baseline; column-gap: 14px; margin-bottom: 26px;
}
.dsr-name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.dsr-ledger h1 {
  margin: 0; font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(28px, 2.4vw, 36px); line-height: 1.06;
  letter-spacing: -.015em; min-width: 0; text-wrap: balance;
}
.dsr-leader {
  height: 0; font-size: 28px; align-self: baseline;
  border-bottom: 1.5px dotted color-mix(in srgb, var(--color-text) 26%, transparent);
  transform: translateY(-.28em);
}
.dsr-price {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(22px, 1.9vw, 28px); line-height: 1.05;
  color: var(--color-accent); white-space: nowrap;
}

.dsr-counter { display: grid; grid-template-columns: minmax(0, 1fr) 400px; column-gap: 56px; align-items: start; }
.dsr-facts   { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.dsr-tags    { display: flex; gap: 8px; flex-wrap: wrap; }
/* .tag-neutral is #f2ece0 on #ece7dc here — all but invisible. Give it the
   card's ground and a hairline so it reads as a chip at all. */
.dsr-tags .tag-neutral { background: var(--color-surface); box-shadow: inset 0 0 0 1px var(--dsr-hair); }
.dsr-tags #sdOrigin { display: inline-flex; align-items: center; gap: 7px; max-width: min(100%, 360px); }
.dsr-tags #sdOrigin > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dsr-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; font-size: var(--fs-read); color: var(--color-neutral-600); }
.dsr-meta > span { display: inline-flex; align-items: center; gap: 7px; }
.da-stats { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.da-stat { display: inline-flex; align-items: center; gap: 5px; }
.da-stat__i { width: 15px; height: 15px; flex: none; }
.da-stat b { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--color-neutral-700); }
.dsr-lede { margin: 0; font-size: 15px; line-height: 1.75; color: var(--color-neutral-700); max-width: 62ch; }

/* ---- the slip: the one object on the page that carries the transaction */
.dsr-buy {
  position: relative; background: var(--color-surface);
  border-radius: var(--dsr-slip-r); padding: 20px 22px 26px;
  box-shadow: var(--dsr-card); display: flex; flex-direction: column; gap: 16px;
}
.dsr-buy hr { border: 0; border-top: 1px solid var(--dsr-hair); margin: 0; }
.dsr-cap { font: 700 var(--fs-read)/1 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--color-neutral-600); }
.dsr-avail { display: grid; grid-template-columns: auto auto; justify-content: space-between; align-items: baseline; gap: 12px; }
.dsr-avail b { font-size: 14px; font-weight: 700; color: var(--color-accent-700); }
.dsr-avail b.out { color: var(--dsr-alarm); }

.dsr-pickbox { display: flex; flex-direction: column; gap: 10px; }
.dsr-pick { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; align-items: stretch; }
.dsr-pick .pick-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  border: 1.5px solid var(--dsr-hair); border-radius: 10px; padding: 10px 12px;
  background: var(--color-bg); color: var(--color-text); cursor: pointer;
  font-family: var(--font-body); font-size: 14px; font-weight: 600; text-align: left;
  transition: border-color .18s ease, background-color .18s ease, color .18s ease;
}
.dsr-pick .pick-btn .s { font-size: var(--fs-read); font-weight: 500; opacity: .75; }
.dsr-pick .pick-btn:hover:not([disabled]) { border-color: var(--color-accent-400); }
.dsr-pick .pick-btn[aria-pressed="true"] { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-bg); }
.dsr-pick .pick-btn[disabled] { background: var(--color-neutral-200); border-color: var(--color-neutral-200); color: var(--color-neutral-500); cursor: not-allowed; text-decoration: line-through; }
/* 7-12 options: chips, label only, availability on one line beneath */
.dsr-pick.compact { display: flex; flex-wrap: wrap; gap: 8px; }
.dsr-pick.compact .pick-btn { border-radius: 999px; padding: 8px 14px; flex-direction: row; }
.dsr-pick.compact .pick-btn .s { display: none; }
.dsr-picknote { font-size: var(--fs-read); color: var(--color-neutral-600); }
.dsr-pickbox select.input { width: 100%; }

.dsr-act { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 12px; }
.dsr-act .dsr-step {
  grid-column: 1; display: flex; align-items: center; justify-content: space-between;
  border: 1.5px solid var(--dsr-hair); border-radius: 999px; overflow: hidden; background: var(--color-bg);
}
.dsr-act .dsr-step .qty-btn { border: none; background: transparent; width: 42px; height: 44px; font-size: 18px; cursor: pointer; color: var(--color-text); }
.dsr-act .dsr-step span { min-width: 32px; text-align: center; font-weight: 700; font-size: 15px; }
.dsr-act #addCart { grid-column: 2; width: 100%; justify-content: center; }
.dsr-act #buyNow { grid-column: 1 / -1; width: 100%; justify-content: center; }

/* "Maksimum N untuk stok saat ini." — muncul hanya saat batasnya tersentuh,
   jadi ia menjelaskan tombol + yang baru saja berhenti menanggapi. */
/* pil "Stok habis": merah bata yang sama dengan penanda di kartu katalog */
.dsr-tags .tag-out { color: #96442b; border: 1.5px solid #96442b; background: transparent; }
/* ══ ULASAN ══
   Ringkasan, penulisan, daftar. Kartunya kartu krem yang sama dengan katalog
   dan meja kasir; bintangnya komponen .stars di site.css. */

.rv { display: flex; flex-direction: column; gap: 18px; }

/* keadaan kosong: mengundang menulis, bukan memajang nilai nol */
.rv-empty { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; background: var(--dv-cream); border: 1.5px solid rgba(23, 63, 39, .12); box-shadow: 0 3px 0 rgba(23, 63, 39, .14); border-radius: 24px; padding: 24px 26px; }
.rv-empty__h { margin: 0 0 4px; font: 400 20px/1.15 var(--font-heading); color: var(--dv-ink); }
.rv-empty__p { margin: 0; max-width: 46ch; font-size: var(--fs-read); line-height: 1.55; color: #5c6356; }
.rv-empty .rv-open { margin-left: auto; cursor: pointer; }

/* ringkasan saat sudah ada ulasan: angka besar, bintang, jumlah */
.rv-sum { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; background: var(--dv-cream); border: 1.5px solid rgba(23, 63, 39, .12); box-shadow: 0 3px 0 rgba(23, 63, 39, .14); border-radius: 24px; padding: 22px 26px; }
.rv-sum__score { display: flex; align-items: baseline; gap: 7px; }
.rv-sum__score b { font: 400 clamp(34px, 4vw, 46px)/1 var(--font-heading); color: var(--dv-ink); }
.rv-sum__score span { font-size: var(--fs-read); color: #5c6356; }
.rv-sum__meta { display: flex; flex-direction: column; gap: 6px; }
.rv-sum__n { font-size: var(--fs-read); color: #5c6356; }
.rv-sum .rv-open { margin-left: auto; cursor: pointer; }
/* Sebaran bintang: lima baris, isian marigold yang sama dengan bintang yang
   dipakai pemilih nilai di bawahnya, di atas rel hijau tipis. Kolom tengah
   minmax(0,1fr) supaya relnya menyusut, bukan memaksa kartu ini melebar; di
   bawah 640 ia turun sendiri ke barisnya karena .rv-sum memang flex-wrap. */
.rv-sum__bars { display: grid; gap: 7px; flex: 1 1 200px; min-width: 180px; max-width: 320px; }
.rv-bar { display: grid; grid-template-columns: 10px minmax(0, 1fr) 26px; align-items: center; gap: 10px; }
.rv-bar__v { font-size: var(--fs-min); font-weight: 700; color: #5c6356; text-align: center; }
.rv-bar__t { height: 8px; border-radius: 999px; background: rgba(23, 63, 39, .11); overflow: hidden; }
.rv-bar__t i { display: block; height: 100%; border-radius: 999px; background: var(--dv-sun); }
.rv-bar__n { font-size: var(--fs-min); color: #5c6356; text-align: right; font-variant-numeric: tabular-nums; }

/* gerbang: ulasan ditulis atas nama akun */
/* gerbang ini sekarang benar-benar bisa muncul (lihat summary() di reviews.js),
   jadi ia harus terbaca sebagai kartu seperti ringkasan di atasnya, bukan
   sebagai blok abu yang mengambang */
.rv-gate { margin-top: 14px; background: var(--color-surface); border: 1.5px solid rgba(23, 63, 39, .12); border-radius: 20px; padding: 22px 24px; }
.rv-gate[hidden] { display: none; }
.rv-gate__h { margin: 0 0 6px; font: 400 19px/1.2 var(--font-heading); color: var(--dv-ink); }
.rv-gate p { margin: 0 0 16px; font-size: var(--fs-read); line-height: 1.55; color: #5c6356; }
.rv-gate__act { display: flex; gap: 10px; flex-wrap: wrap; }

/* penulisan */
.rv-form { background: var(--color-surface); border-radius: 20px; padding: 22px 24px 24px; }
.rv-form[hidden] { display: none; }
.rv-field { display: block; margin: 0 0 16px; }
.rv-cap { display: block; margin-bottom: 8px; font: 700 var(--fs-min)/1 var(--font-body); letter-spacing: .12em; text-transform: uppercase; color: #5c6356; }
.rv-cap i { font-style: normal; letter-spacing: .06em; opacity: .75; }
.rv-title, .rv-body { width: 100%; box-sizing: border-box; border: 1.5px solid rgba(23, 63, 39, .14); border-radius: 12px; background: var(--color-bg); padding: 12px 14px; font: 500 15px/1.5 var(--font-body); color: var(--color-text); outline: none; transition: border-color .2s ease; }
.rv-title:focus, .rv-body:focus { border-color: var(--color-accent); }
.rv-body { resize: vertical; min-height: 96px; }

/* pemilih bintang: 44px sasaran sentuh, bukan ikon 14px yang harus dibidik */
.rv-pick { display: flex; align-items: center; gap: 2px; }
.rv-pick__s { width: 44px; height: 44px; display: grid; place-items: center; border: 0; background: none; cursor: pointer; padding: 0; }
.rv-pick__s svg { width: 30px; height: 30px; fill: rgba(23, 63, 39, .18); transition: fill .15s ease, transform .15s cubic-bezier(.22, 1, .36, 1); }
.rv-pick__s.is-on svg { fill: var(--dv-sun); }
.rv-pick:hover .rv-pick__s svg { fill: rgba(23, 63, 39, .18); }
.rv-pick__s:hover svg, .rv-pick__s:hover ~ .rv-pick__s svg { fill: rgba(23, 63, 39, .18); }
/* sorot sampai bintang yang ditunjuk: saudara SEBELUMNYA tidak bisa dipilih
   di CSS, jadi barisnya dibalik arah dan dibalik lagi lewat transform */
.rv-pick { direction: rtl; justify-content: flex-end; }
.rv-pick__s:hover svg, .rv-pick__s:hover ~ .rv-pick__s svg { fill: #f0c24b; }
.rv-pick__t { direction: ltr; margin-inline-start: 10px; font-size: var(--fs-read); color: #5c6356; }

.rv-err { margin: 0 0 14px; font-size: var(--fs-read); font-weight: 600; color: #96442b; }
.rv-err[hidden] { display: none; }
.rv-act { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.rv-act .rv-send { cursor: pointer; }
.rv-cancel { border: 0; background: none; cursor: pointer; font: 700 var(--fs-read)/1 var(--font-body); color: #5c6356; padding: 8px; }
.rv-cancel:hover { color: var(--dv-ink); }

/* daftar */
.rv-list { display: flex; flex-direction: column; }
.rv-item { display: flex; gap: 14px; padding: 20px 0; border-top: 1px dashed rgba(23, 63, 39, .18); }
.rv-item__av { display: grid; place-items: center; width: 40px; height: 40px; flex: none; border-radius: 50%; background: var(--color-accent-2-100); color: var(--color-accent-2-700); font: 400 18px/1 var(--font-heading); overflow: hidden; }
img.rv-item__av { object-fit: cover; padding: 0; }
.rv-item__pics { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.rv-item__pic { width: 72px; height: 72px; object-fit: cover; border-radius: 10px; }
.rv-item__main { min-width: 0; }
.rv-item__top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rv-item__top b { font-size: 14.5px; color: var(--dv-ink); }
.rv-item__d { font-size: var(--fs-read); color: var(--color-neutral-500); }
.rv-item__h { margin: 8px 0 0; font: 400 17px/1.25 var(--font-heading); color: var(--dv-ink); }
.rv-item__b { margin: 6px 0 0; font-size: 15px; line-height: 1.7; color: var(--color-neutral-700); text-wrap: pretty; }
/* ulasan yang belum sampai ke server: ditandai, bukan disamarkan */
.rv-item.is-pending { background: var(--color-accent-2-100); border-radius: 16px; padding: 18px 16px; border-top: 0; margin-top: 12px; }
.rv-item__pend { margin: 8px 0 0; font-size: var(--fs-read); font-weight: 700; color: var(--color-accent-2-800); }

@media (max-width: 640px) {
  .rv-empty, .rv-sum { padding: 20px; border-radius: 20px; }
  .rv-empty .rv-open, .rv-sum .rv-open { margin-left: 0; width: 100%; justify-content: center; }
  .rv-form, .rv-gate { padding: 18px 16px 20px; }
}

.dsr-qnote { grid-column: 1 / -1; margin: 2px 0 0; font-size: var(--fs-read); color: var(--color-neutral-600); }
.dsr-qnote[hidden] { display: none; }

/* Stok habis: tombolnya mati dan mengatakan kenapa. Tanpa ini ia tetap hijau
   dan tetap mengundang, lalu diam-diam menambahkan barang yang tidak bisa
   dikirim ke keranjang. */
.dsr-act #addCart:disabled,
.dsr-act #buyNow:disabled { background: var(--color-neutral-200, #e8ece3); color: var(--color-neutral-600); box-shadow: none; cursor: not-allowed; }
.dsr-act #addCart:disabled .shine,
.dsr-act #buyNow:disabled .shine { display: none; }
.dsr-act .qty-btn:disabled { opacity: .35; cursor: not-allowed; }

.dsr-ship { display: flex; flex-direction: column; gap: 8px; font-size: var(--fs-read); color: var(--color-neutral-600); max-width: calc(100% - 68px); }
.dsr-ship span { display: flex; gap: 8px; align-items: flex-start; }
.dsr-ship svg { width: 15px; height: 15px; flex: none; margin-top: 2px; color: var(--color-accent-700); }

/* the breeder's stamp — exactly one on the page, and it lands on the slip,
   which is where the charm belongs */
.dsr-chop { position: absolute; right: 16px; bottom: 14px; width: 56px; height: 56px; transform: rotate(-5deg); opacity: .28; color: var(--dsr-chop); pointer-events: none; }

/* ============================================ 02 · GAMBAR ============ */
.dsr-plates { display: none; }
html.has-book .dsr-plates { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--dsr-gap); }
.dsr-plate { margin: 0; min-width: 0; }
.dsr-shot {
  display: block; width: 100%; aspect-ratio: 1; padding: 0; border: 0; cursor: zoom-in;
  overflow: hidden; border-radius: 4px; background: var(--color-surface);
  box-shadow: inset 0 0 0 1px var(--dsr-hair);
}
.dsr-shot img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .7s cubic-bezier(.22, 1, .36, 1); }
/* plate 01 is a specimen cut out on paper: it is shown whole, not cropped */
.dsr-shot.contain img { object-fit: contain; padding: 7%; }
.dsr-plate:hover .dsr-shot img { transform: scale(1.035); }
.dsr-plate figcaption {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px;
  align-items: baseline; margin-top: 10px; padding-top: 8px;
  border-top: 1px solid var(--dsr-hair);
  font: 600 var(--fs-read)/1.2 var(--font-body); letter-spacing: .14em; text-transform: uppercase;
}
.dsr-plate figcaption .n { color: var(--color-accent-700); }
.dsr-plate figcaption .c { color: var(--color-neutral-600); }
/* it used to be nowrap + ellipsis in a column that measured 123px at 1280 while
   "IN THE ENCLOSURE" needed 122px at the OLD 10.5px/.14em — i.e. it was already
   truncating. Letting it wrap frees the caption from the third column without
   moving .dsr-toleaf onto a second row, where it would reserve ~20px of blank
   space under every plate for a control that is invisible until hover. */
.dsr-toleaf { border: 0; background: none; padding: 0; cursor: pointer; font: inherit; color: var(--color-accent-700); opacity: 0; transition: opacity .2s ease; white-space: nowrap; }
.dsr-plate:hover .dsr-toleaf, .dsr-toleaf:focus-visible { opacity: 1; }
/* fewer than four photographs: the row terminates on purpose */
.dsr-platenote { font-size: 15px; line-height: 1.75; color: var(--color-neutral-700); max-width: 46ch; align-self: start; }
.dsr-platenote.tight { font-size: var(--fs-read); }

/* ============================================ 03 · REKAMAN =========== */
.dsr-rec { display: grid; grid-template-columns: 352px minmax(0, 1fr); column-gap: 44px; row-gap: 26px; align-items: start; }
.dsr-rec.voice-only { grid-template-columns: minmax(0, 1fr); }
.dsr-filmwrap { min-width: 0; }
.dsr-film {
  position: relative; width: 352px; max-width: 100%; aspect-ratio: 1;
  overflow: hidden; border-radius: 6px; background: #221e18;
  box-shadow: inset 0 0 0 1px rgba(58, 44, 26, .28), var(--dsr-card);
}
.dsr-film video { width: 100%; height: 100%; display: block; object-fit: contain; background: #221e18; }
.dsr-film > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.dsr-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(28, 24, 18, .42), rgba(28, 24, 18, .66)); }
.dsr-play {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px;
  border: 0; background: transparent; cursor: pointer;
  color: rgba(250, 246, 238, .92); font-family: var(--font-body); font-size: var(--fs-read); letter-spacing: .04em;
  transition: background-color .2s ease, color .2s ease;
}
.dsr-play .ring {
  width: 64px; height: 64px; border-radius: 50%; border: 1.5px solid currentColor;
  display: grid; place-items: center; transition: transform .2s ease;
}
.dsr-play .ring svg { width: 22px; height: 22px; fill: currentColor; margin-left: 3px; }
.dsr-play:hover { background: rgba(255, 250, 240, .10); color: #fffaf0; }
.dsr-play:hover .ring { transform: scale(1.05); }
.dsr-film .honest {
  position: absolute; left: 14px; bottom: 12px; pointer-events: none;
  font: 600 var(--fs-read)/1.2 var(--font-body); letter-spacing: .16em; text-transform: uppercase;
  color: rgba(246, 242, 233, .72);
}
/* no enclosure photograph to rest on: the panel says so in type instead */
.dsr-film.blank { background: var(--color-surface); box-shadow: inset 0 0 0 1px var(--dsr-hair), var(--dsr-card); }
.dsr-film.blank .dsr-play { color: var(--color-accent-700); }
.dsr-film.blank .honest { color: var(--color-neutral-500); }

.dsr-filmcap {
  display: grid; grid-template-columns: auto auto; justify-content: space-between;
  margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--dsr-hair);
  font: 600 var(--fs-read)/1.2 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--color-neutral-600);
}
.dsr-recnote { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.dsr-recnote p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--color-neutral-700); max-width: 46ch; }
/* a two-row table stretched across 840px puts a chasm between key and
   value; it keeps the note's measure instead */
.dsr-recnote .dsr-dl { max-width: 46ch; }

/* beside a 352px film the slip takes the rest of the measure — the trace
   stretches, so a wider one is simply a longer recording to look at.
   Alone on a full-width row it would be absurd, hence the cap. */
.dsr-call { background: var(--color-surface); border-radius: var(--dsr-slip-r); box-shadow: var(--dsr-card); padding: 18px 20px; }
.dsr-rec.voice-only .dsr-call { max-width: 560px; }
.dsr-call > .dsr-cap { display: block; padding-bottom: 10px; border-bottom: 1.5px solid var(--dsr-rule); }
.dsr-callrow { display: grid; grid-template-columns: 46px auto minmax(0, 1fr); gap: 16px; align-items: center; padding: 16px 0 12px; }
.dsr-call .vplay { width: 46px; height: 46px; flex: none; border: none; border-radius: 50%; background: var(--color-accent); color: var(--color-bg); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 15px; }
.dsr-time { font-size: var(--fs-read); font-weight: 600; color: var(--color-neutral-700); min-width: 84px; }
.dsr-call svg.trace { display: block; width: 100%; height: 34px; }
.dsr-callcap { font: italic 400 14px/1.3 var(--dsr-serif); color: var(--color-neutral-600); }
.dsr-callsub { margin-top: 6px; font: 600 var(--fs-read)/1.2 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--color-neutral-500); }

/* ============================================ 04 · BERKAS ============ */
.sbk.sbk-notes { background: transparent; padding: 0; font-family: var(--font-body); color: var(--color-text); }
.sbk .sbk-transcript { max-width: none; margin: 0; }
.sbk .sbk-transcript > summary {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px; align-items: center;
  padding: 16px 0; border: 0; border-bottom: 1px solid var(--dsr-hair);
  border-radius: 0; background: transparent; font-size: 14px; letter-spacing: .02em;
  transition: background-color .25s ease;
}
.sbk .sbk-transcript > summary:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
.sbk .sbk-transcript #sdRecord { max-width: none; padding: 26px 0 0; scroll-margin-top: 96px; }

/* The product's tips come as paragraphs separated by blank lines, and a line
   that opens with a check mark is the heading of the paragraph after it.
   Poured in as one text node they were a single block — 2,887px tall at 390
   on the longest record. js/pages/product-detail.js splits them here. */
.dsr-tips p { margin: 0 0 12px; }
.dsr-tips p:last-child { margin-bottom: 0; }
.dsr-tips .dsr-tip-h { margin-bottom: 4px; font-weight: 700; color: var(--color-text); }

/* On a phone the species record is a list of closed sections — the same +/−
   summary the transcript uses (css/sketchbook.css:353), on the desk's hairline.
   Open, the 3–7 sections were one 1,200–4,600px column at 390 with the care
   sheet below all of it. The markup is the gate: js/pages/species-detail.js
   only emits .dsr-fold at ≤640, so a tablet turned sideways keeps its styling. */
.dsr-fold { border-bottom: 1px solid var(--dsr-hair); }
.dsr-fold > summary {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px; align-items: center;
  min-height: 52px; padding: 12px 0; cursor: pointer; list-style: none;
}
.dsr-fold > summary::-webkit-details-marker { display: none; }
.dsr-fold > summary::before { content: "+"; width: 18px; text-align: center; font-size: 20px; line-height: 1; color: var(--color-neutral-500); }
.dsr-fold[open] > summary::before { content: "\2212"; }
.dsr-fold > summary h2 { margin: 0; font-size: 18px; line-height: 1.2; }
.dsr-fold > p { margin: 0 0 22px; font-size: 15px; line-height: 1.75; color: var(--color-neutral-700); white-space: pre-line; text-wrap: pretty; }
.dsr-fold > .rte-prose { margin: 0 0 22px; }

/* Deskripsi CMS (TipTap) — sama toko lama: heading, list, justify, 2 kolom, tabel. */
.rte-prose {
  font-size: 15px;
  line-height: 1.75;
  color: var(--color-neutral-700);
  max-width: none;
  text-wrap: pretty;
}
.rte-prose::after { content: ""; display: table; clear: both; }
.rte-prose p { margin: 0 0 1em; }
.rte-prose p:last-child { margin-bottom: 0; }
.rte-prose h1 { font-size: 1.65em; font-weight: 800; line-height: 1.2; margin: 1.1em 0 0.5em; color: var(--color-text); }
.rte-prose h2 { font-size: 1.35em; font-weight: 700; line-height: 1.3; margin: 1.2em 0 0.5em; color: var(--color-text); }
.rte-prose h3 { font-size: 1.15em; font-weight: 650; line-height: 1.35; margin: 1.1em 0 0.4em; color: var(--color-text); }
.rte-prose h4, .rte-prose h5, .rte-prose h6 { font-size: 1em; font-weight: 650; margin: 1em 0 0.4em; color: var(--color-text); }
.rte-prose h1:first-child, .rte-prose h2:first-child, .rte-prose h3:first-child { margin-top: 0; }
.rte-prose strong, .rte-prose b { font-weight: 700; color: var(--color-text); }
.rte-prose em, .rte-prose i { font-style: italic; }
.rte-prose a { color: var(--color-accent-700); text-decoration: underline; font-weight: 600; }
.rte-prose ul { list-style: disc; margin: 0.75em 0 1em; padding-left: 1.5em; }
.rte-prose ol { list-style: decimal; margin: 0.75em 0 1em; padding-left: 1.5em; }
.rte-prose li { margin: 0.35em 0; }
.rte-prose li > p { margin: 0.2em 0; }
.rte-prose blockquote {
  margin: 1.2em 0; padding: 0 0 0 1em; font-style: italic;
  border-left: 4px solid var(--color-divider); color: var(--color-neutral-600);
}
.rte-prose hr { border: 0; border-top: 1px solid var(--color-divider); margin: 2em 0; }
.rte-prose img { max-width: 100%; height: auto; border-radius: 8px; margin: 1em 0; }
.rte-prose img.align-left { float: left; margin: 0.4em 1.25em 0.8em 0; }
.rte-prose img.align-center { display: block; float: none; margin: 1em auto; }
.rte-prose img.align-right { float: right; margin: 0.4em 0 0.8em 1.25em; }
.rte-prose .rte-two-column, .rte-prose .rte-columns {
  display: grid; grid-template-columns: 1fr; gap: 1rem; margin: 1rem 0;
}
@media (min-width: 768px) {
  .rte-prose .rte-two-column { grid-template-columns: 1fr 1fr; gap: 1.5rem; }
  .rte-prose .rte-columns[data-columns="2"] { grid-template-columns: 1fr 1fr; gap: 1.5rem; }
  .rte-prose .rte-columns[data-columns="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; }
}
.rte-prose .rte-two-column-cell, .rte-prose .rte-column-cell { min-width: 0; }

/* --- Catatan produk: satu kolom, seperti berkas spesies -------------------
   Diukur terhadap 188 deskripsi yang benar-benar dikirim Kolam BE hari ini,
   bukan terhadap satu produk: 182 <h2>, 90 <h3>, 36 <h1>, 1551 <li>, 96
   paragraf kosong sisa TipTap, dan 16 produk yang membungkus isinya dalam
   blok kolom. Tiga hal membuat band ini terbaca berantakan, dan ketiganya
   keputusan tata letak:

   1. BLOK KOLOM ITU BUKAN DAFTAR DUA-UP, MELAINKAN WADAH BAGIAN. 13 dari 16
      produk punya sel yang masing-masing dibuka headingnya sendiri lalu
      berisi 6-29 paragraf. Dipasang sebagai grid dua kolom, satu bagian utuh
      terdampar di kanan dan mata harus naik lagi ke atas untuk membacanya.
      Ditumpuk vertikal ia justru kembali menjadi struktur yang memang ditulis
      penulisnya: judul, prosa, judul, prosa - irama yang sama dengan
      #sdSections di halaman spesies.
   2. HIERARKI RUNTUH. <h1>/<h2> dari CMS dirender 1,65em/1,35em dari 15px =
      24,8/20,3px, praktis seukuran judul band "Deskripsi" (clamp 20-26px)
      yang duduk tepat di atasnya, jadi sub-bagian berteriak sekeras bagian.
      Keduanya turun satu tingkat ke 18px, dan h1 disamakan dengan h2: sebuah
      <h1> di dalam deskripsi produk bukan h1 halaman - halaman ini sudah
      punya satu, yaitu nama produknya.
   3. IRAMA. Jarak di atas heading jauh lebih besar daripada di bawahnya,
      supaya satu kelompok terbaca sebagai satu kelompok. Angkanya mengikuti
      band spesies (44/14), sedikit dirapatkan karena di sini headingnya satu
      tingkat lebih kecil.

   Semua di-scope ke #pdProseBand: band prosa spesies memakai .rte-prose yang
   sama dan tidak ikut berubah. */
#pdProseBand .rte-prose .rte-columns,
#pdProseBand .rte-prose .rte-two-column { display: block; margin: 0; }
#pdProseBand .rte-prose .rte-column-cell + .rte-column-cell,
#pdProseBand .rte-prose .rte-two-column-cell + .rte-two-column-cell { margin-top: 40px; }
#pdProseBand .rte-prose h1,
#pdProseBand .rte-prose h2 { font-size: 18px; font-weight: 700; line-height: 1.32; margin: 40px 0 12px; color: var(--color-text); }
#pdProseBand .rte-prose h3,
#pdProseBand .rte-prose h4,
#pdProseBand .rte-prose h5,
#pdProseBand .rte-prose h6 { font-size: 15px; font-weight: 700; line-height: 1.42; margin: 28px 0 8px; color: var(--color-text); }
#pdProseBand .rte-prose :is(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }
/* judul kecil yang ditulis sebagai paragraf tebal - ditandai product-detail.js,
   karena "paragraf yang SELURUH isinya <strong>" tidak bisa dinyatakan sebagai
   selektor: :has(> strong) juga kena "<strong>Frog Soil</strong> adalah media..." */
#pdProseBand .rte-prose p.rte-subhead { margin: 26px 0 6px; font-weight: 700; color: var(--color-text); }
#pdProseBand .rte-prose p.rte-subhead:first-child { margin-top: 0; }
#pdProseBand .rte-prose p.rte-subhead + p,
#pdProseBand .rte-prose p.rte-subhead + ul,
#pdProseBand .rte-prose p.rte-subhead + ol { margin-top: 0; }
#pdProseBand .rte-prose ul,
#pdProseBand .rte-prose ol { margin: .5em 0 1em; padding-left: 1.35em; }
#pdProseBand .rte-prose li { margin: .25em 0; }
#pdProseBand .rte-prose li::marker { color: var(--color-accent-700); }
.rte-prose table, .rte-prose .rte-table {
  width: 100%; border-collapse: collapse; font-size: 0.92em; margin: 1.25em 0;
}
.rte-prose th, .rte-prose td {
  border: 1px solid var(--color-divider); padding: 0.5em 0.75em; vertical-align: top; text-align: left;
}
.rte-prose th { font-weight: 700; background: var(--color-surface); }
.rte-prose .rte-table-wrapper, .rte-prose .tableWrapper { max-width: 100%; overflow-x: auto; margin: 1.25em 0; }
.rte-prose code { font-size: 0.9em; background: var(--color-surface); padding: 0.15em 0.35em; border-radius: 4px; }
.rte-prose pre { overflow-x: auto; background: var(--color-surface); padding: 0.9em 1.1em; border-radius: 8px; }
.dsr-lede.rte-prose { font-size: 15px; }
.dsr-lede.rte-prose p { margin: 0 0 0.55em; }
.dsr-lede.rte-prose p:last-child { margin-bottom: 0; }

.rte-prose .rte-lh-1 { line-height: 1; }
.rte-prose .rte-lh-1_15 { line-height: 1.15; }
.rte-prose .rte-lh-1_5 { line-height: 1.5; }
.rte-prose .rte-lh-1_75 { line-height: 1.75; }
.rte-prose .rte-lh-2 { line-height: 2; }
.rte-prose .rte-sp-before-0_25em { margin-top: 0.25em; }
.rte-prose .rte-sp-before-0_5em { margin-top: 0.5em; }
.rte-prose .rte-sp-before-0_75em { margin-top: 0.75em; }
.rte-prose .rte-sp-before-1em { margin-top: 1em; }
.rte-prose .rte-sp-before-1_5em { margin-top: 1.5em; }
.rte-prose .rte-sp-before-2em { margin-top: 2em; }
.rte-prose .rte-sp-after-0_25em { margin-bottom: 0.25em; }
.rte-prose .rte-sp-after-0_5em { margin-bottom: 0.5em; }
.rte-prose .rte-sp-after-0_75em { margin-bottom: 0.75em; }
.rte-prose .rte-sp-after-1em { margin-bottom: 1em; }
.rte-prose .rte-sp-after-1_5em { margin-bottom: 1.5em; }
.rte-prose .rte-sp-after-2em { margin-bottom: 2em; }
.rte-prose .rte-indent-block-1 { margin-left: 2em; }
.rte-prose .rte-indent-block-2 { margin-left: 4em; }
.rte-prose .rte-indent-block-3 { margin-left: 6em; }
.rte-prose .rte-indent-block-4 { margin-left: 8em; }
.rte-prose .rte-indent-first-line-1 { text-indent: 2em; }
.rte-prose .rte-indent-first-line-2 { text-indent: 4em; }
.rte-prose .rte-indent-first-line-3 { text-indent: 6em; }
.rte-prose .rte-indent-first-line-4 { text-indent: 8em; }
.rte-prose .rte-indent-hanging-1 { padding-left: 2em; text-indent: -2em; }
.rte-prose .rte-indent-hanging-2 { padding-left: 4em; text-indent: -4em; }
.rte-prose .rte-indent-hanging-3 { padding-left: 6em; text-indent: -6em; }
.rte-prose .rte-indent-hanging-4 { padding-left: 8em; text-indent: -8em; }
.rte-prose p.rte-drop-cap::first-letter,
.rte-prose h1.rte-drop-cap::first-letter,
.rte-prose h2.rte-drop-cap::first-letter,
.rte-prose h3.rte-drop-cap::first-letter {
  float: left; font-size: 3.2em; line-height: 0.85; margin-right: 0.12em; margin-top: 0.05em; font-weight: 700;
}

/* ============================================ 05 · DATA ============== */
.dsr-panel {
  display: grid; gap: 0; background: var(--color-surface);
  border-radius: var(--dsr-slip-r); box-shadow: var(--dsr-card); padding: 32px 36px 28px;
}
.dsr-panel[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.dsr-panel[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.dsr-panel[data-cols="1"] { grid-template-columns: minmax(0, 1fr); }
.dsr-block { display: flex; flex-direction: column; padding-inline: 28px; min-width: 0; }
.dsr-block:first-child { padding-left: 0; }
.dsr-block:last-child  { padding-right: 0; }
.dsr-block + .dsr-block { border-left: 1px solid var(--dsr-hair); }
.dsr-block > h3 {
  font: 700 var(--fs-read)/1 var(--font-body); letter-spacing: .2em; text-transform: uppercase;
  color: var(--color-neutral-600); margin: 0 0 6px; padding-bottom: 10px;
  border-bottom: 1.5px solid var(--dsr-rule);
}
.dsr-block > h3 + * { margin-top: 6px; }
.dsr-block > h3.mid { margin-top: 24px; }
.dsr-iucn { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin: 12px 0 8px; }
.dsr-iucn .code { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 22px; color: var(--color-bg); background: var(--color-accent); border-radius: 6px; padding: 5px 12px; }
.dsr-iucn .code.warn  { background: var(--dsr-warn); }
.dsr-iucn .code.alarm { background: var(--dsr-alarm); }
.dsr-iucn .code.na    { background: var(--color-neutral-500); }
.dsr-iucn .lab { font-size: 14px; font-weight: 600; }
.dsr-iucn .dsr-iucn__logo { display: block; width: min(100%, 220px); height: auto; max-height: 128px; object-fit: contain; }
.dsr-iucn-link { color: inherit; text-decoration: none; display: block; }
.dsr-iucn-link:hover .lab { color: var(--color-accent-700); }
.dsr-origin-flags { display: inline-flex; align-items: center; gap: 5px; margin-left: 8px; vertical-align: -3px; }
.dsr-origin-flags--tag { margin-left: 0; }
.dsr-row dd > .dsr-origin-flags:first-child { margin-left: 0; margin-right: 8px; }
.dsr-country-flag { display: block; width: 22px; height: 16.5px; border-radius: 3px; object-fit: cover; box-shadow: var(--shadow-sm); flex: none; }
.dsr-map { position: relative; margin-top: 14px; border: 1px solid var(--dsr-hair); border-radius: 8px; overflow: hidden; background: var(--color-neutral-100); }
.dsr-map iframe { width: 100%; height: 200px; border: none; display: block; }
.dsr-map .loading { position: absolute; inset: 0; display: grid; place-items: center; font-size: var(--fs-read); color: var(--color-neutral-500); pointer-events: none; }
.dsr-maplink { display: block; text-align: right; margin-top: 10px; font-size: var(--fs-read); font-weight: 700; }
.dsr-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* ============================================ 06 · ULASAN ============ */
.dsr-revempty { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 18px; align-items: center; min-height: 76px; font-size: 14.5px; color: var(--color-neutral-600); }
.dsr-revfull { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--dsr-gap); align-items: start; }

/* ============================================ 07 · SERUPA =========== */
/* the desk ends and the shop begins — and the corner radius says so */
.dsr-relsub { margin: 0 0 22px; font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 20px; line-height: 1.2; color: var(--color-neutral-700); }
.dsr-rel { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--dsr-gap); }
/* the card's padding and title size used to be style attributes written by
   the two page scripts; they are here so the phone rule can change them */
.dsr-rel .card { padding: 12px 12px 18px; }
.dsr-rel .card-title { font-size: 16.5px; }
body[data-page="product-detail"] .dsr-rel .card-title { font-size: 16px; line-height: 1.25; }

/* ============================================ the viewer ============ */
#dsrView {
  position: fixed; inset: 0; z-index: 240; display: none;
  background: color-mix(in srgb, #ece7dc 92%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
#dsrView.open { display: grid; grid-template-rows: 1fr auto; place-items: center; padding: clamp(24px, 4vh, 56px); }
#dsrView img { max-width: min(1100px, 92vw); max-height: 78vh; object-fit: contain; border-radius: 6px; box-shadow: 0 24px 60px rgba(58, 44, 26, .28); background: var(--color-surface); }
#dsrView .bar {
  width: min(1100px, 92vw); display: grid; grid-template-columns: auto auto;
  justify-content: space-between; align-items: baseline; margin-top: 16px; padding-top: 10px;
  border-top: 1px solid var(--dsr-hair);
  font: 600 var(--fs-min)/1.2 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--color-neutral-600);
}
#dsrView .x, #dsrView .dsr-nav {
  position: absolute; border: 0; padding: 0; cursor: pointer; color: var(--color-text);
  background: var(--color-surface); box-shadow: var(--dsr-card);
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
}
#dsrView .x { top: clamp(16px, 3vh, 32px); right: clamp(16px, 3vw, 32px); font-size: 18px; }
#dsrView .x svg { width: 17px; height: 17px; display: block; }
#dsrView .dsr-nav svg { width: 21px; height: 21px; display: block; }
#dsrView .dsr-nav { top: 50%; transform: translateY(-50%); font-size: 20px; }
#dsrView .dsr-nav.prev { left: clamp(10px, 2vw, 28px); }
#dsrView .dsr-nav.next { right: clamp(10px, 2vw, 28px); }
#dsrView .x:hover, #dsrView .dsr-nav:hover { background: var(--color-bg); }

/* ================================ the no-book page ==================
   Below about 1015px the book is never drawn, so this is what a phone
   gets — and it is the same document, not a lesser one: the same bands,
   the same heads, the same measure. Four differences only. */
html:not(.has-book) .dsr-counter { grid-template-columns: minmax(300px, 480px) minmax(0, 1fr); column-gap: 56px; row-gap: 24px; }
/* the gallery spans both rows so that sticky has something to stick within */
html:not(.has-book) .dsr-counter > .detail-media { grid-column: 1; grid-row: 1 / span 2; position: sticky; top: 100px; align-self: start; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
html:not(.has-book) .dsr-facts { grid-column: 2; grid-row: 1; }
html:not(.has-book) .dsr-buy   { grid-column: 2; grid-row: 2; }
html:not(.has-book) .dsr-counter > .detail-media .shot { display: block; width: 100%; aspect-ratio: 1; background-size: cover; background-position: center; background-color: var(--color-surface); border-radius: var(--dsr-slip-r); box-shadow: var(--dsr-card); cursor: zoom-in; border: 0; padding: 0; }
/* selama .skel masih terpasang, kotak ini harus berwarna kerangka, bukan
   --color-surface: aturan di atas jauh lebih spesifik daripada .skel dan
   kilaunya jadi bermain di atas kotak yang nyaris putih */
html:not(.has-book) .dsr-counter > .detail-media .shot.skel { background-color: var(--color-neutral-200, #e7e4dc); box-shadow: none; }
html:not(.has-book) .dsr-counter > .detail-media .thumbs { display: flex; gap: 10px; flex-wrap: wrap; }
/* the thumb's size was inline in both page scripts; with the book up the
   whole .detail-media is hidden, so no has-book gate is needed here */
.detail-media .thumb-btn > span,
.detail-media .thumb-btn > img { width: 64px; height: 64px; object-fit: cover; border-radius: 7px; display: block; }
/* the same four photographs are the gallery two columns to the left; a
   register under it would be the same pictures twice */
html:not(.has-book) .dsr-plates { display: none; }
/* a slip floating beside a photograph on bare paper is one panel too many */
html:not(.has-book) .dsr-buy { background: transparent; box-shadow: none; border-radius: 0; padding: 0; }
html:not(.has-book) .dsr-chop { right: 0; bottom: -6px; }
html.has-book .detail-media { display: none; }
html.has-book .dsr-proseband { display: none; }

/* ============================================ breakpoints =========== */
@media (max-width: 1180px) {
  .dsr-counter { grid-template-columns: minmax(0, 1fr) 340px; column-gap: 40px; }
  .dsr-buy { padding: 18px 18px 24px; }
  .dsr-map iframe { height: 180px; }
}
@media (max-width: 1014px) {
  .dsr-counter { grid-template-columns: minmax(280px, 420px) minmax(0, 1fr); }
  .dsr-rec { grid-template-columns: minmax(0, 1fr); }
  .dsr-rel { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 939px) {
  /* site.css flattens .detail-grid here, but that is #sdBuy itself; the
     counter is a grid one level in, so it has to be told separately. Both
     selectors are repeated at the specificity of the no-book rules above so
     that source order decides, and no !important is needed. */
  .dsr-counter,
  html:not(.has-book) .dsr-counter { grid-template-columns: minmax(0, 1fr); row-gap: 26px; }
  html:not(.has-book) .dsr-counter > .detail-media { grid-column: 1; grid-row: 1; position: static; }
  html:not(.has-book) .dsr-facts { grid-column: 1; grid-row: 2; }
  html:not(.has-book) .dsr-buy   { grid-column: 1; grid-row: 3; }
  html:not(.has-book) .dsr-counter > .detail-media .shot { max-width: 520px; }
  .dsr-plates { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dsr-rec { grid-template-columns: minmax(0, 1fr); }
  .dsr-film { width: 100%; max-width: 420px; }
  .dsr-panel { grid-template-columns: minmax(0, 1fr) !important; padding: 24px 22px; }
  .dsr-block { padding-inline: 0; }
  .dsr-block + .dsr-block { border-left: 0; border-top: 1px solid var(--dsr-hair); padding-top: 22px; margin-top: 22px; }
  .dsr-rel { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
  .dsr-revfull { grid-template-columns: minmax(0, 1fr); }
  .detail-top { padding-top: 120px; }
}
@media (max-width: 640px) {
  .dsr-ledger { grid-template-columns: minmax(0, 1fr); }
  .dsr-leader { display: none; }
  .dsr-act { grid-template-columns: minmax(0, 1fr); }
  .dsr-act .dsr-step, .dsr-act #addCart, .dsr-act #buyNow, .dsr-act .dsr-qnote { grid-column: 1; }
  .dsr-act .dsr-step { width: 100%; }
  /* sasaran sentuh: tombol beli terukur 36px di 390 — di bawah ambang 44px,
     dan ini tombol yang paling menentukan di seluruh halaman */
  .dsr-act #addCart, .dsr-act #buyNow { min-height: 50px; }
  .dsr-panel { padding: 20px 18px; }
  .dsr-map iframe { height: 170px; }
  /* the 28px floor never stepped down: a 63-character product name was four
     28px lines at 360. 7vw is 25.2px there, 27.3px at 390. */
  .dsr-ledger h1 { font-size: clamp(23px, 7vw, 28px); }
  /* the last crumb repeats that same name in two lines right above the h1 */
  .detail-top #bcName { min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* the call: 46 + 84 + two gaps left the trace 133px for 52 bars at 390
     (108px at 360). It takes the whole slip on its own row instead. */
  .dsr-callrow { grid-template-columns: 46px minmax(0, 1fr); row-gap: 10px; }
  .dsr-callrow > span:last-child { grid-column: 1 / -1; }
  /* "MP3 · LOADS WHEN YOU PRESS PLAY" at .14em is 300px; at .04em it is 265px,
     one line inside the 270px slip at 360 */
  .dsr-callsub { letter-spacing: .04em; }
  /* Serupa: auto-fill minmax(230px) is one column at 335px, four cards of
     425px each — 1,750px of scroll for four links. Two across instead. */
  .dsr-rel { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .dsr-rel .card { padding: 8px 8px 14px; }
  .dsr-rel .card-title,
  body[data-page="product-detail"] .dsr-rel .card-title {
    font-size: var(--fs-read); line-height: 1.25;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
  }
  /* The viewer. The grid's one auto column was sized by the image (94vw) and
     the bar (92vw), both wider than the 322px content box the 4vh padding
     left, so both ran 10px past the right edge; and the arrows, dropped to
     the bottom, sat on the caption row. Pin the track to the padding box,
     keep the bar's text between the two 40px arrows, and centre all three on
     one 40px row. */
  #dsrView.open { padding: 72px 12px 20px; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  #dsrView img { max-width: 100%; max-height: 100%; width: auto; }
  /* the arrows end 50px from either edge and the bar starts at 12, so 44px
     clears them; at .14em the longest caption plus counter needed 264px of
     the 248px left at 360, at .08em they need 239 */
  #dsrView .bar {
    width: 100%; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px;
    margin-top: 12px; padding: 0 44px; min-height: 40px; align-items: center; letter-spacing: .08em;
  }
  #dsrView .cap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  #dsrView .dsr-nav { top: auto; bottom: 20px; transform: none; }
}
@media (max-width: 420px) {
  .dsr-head .r { display: none; }
  .dsr-plate figcaption { font-size: var(--fs-read); }
  /* four 74px thumbs at a 10px gap need 326px; the measure at 360 is 310 */
  .detail-media .thumb-btn > span,
  .detail-media .thumb-btn > img { width: 56px; height: 56px; }
  html:not(.has-book) .dsr-counter > .detail-media .thumbs { gap: 8px; }
}
.dsr-rel .card { position: relative; }
.dsr-rel .da-wish--plate { position: absolute; top: 10px; right: 10px; z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  .dsr-shot img, .dsr-toleaf, .dsr-play, .dsr-play .ring, .dsr-pick .pick-btn { transition: none; }
}

/* Species purchase gallery follows the product layout in both book modes. */
html body[data-page="species-detail"] .dsr-counter {
  grid-template-columns:minmax(0,480px) minmax(0,1fr); column-gap:56px; row-gap:24px;
}
html body[data-page="species-detail"] .dsr-counter > .detail-media {
  display:flex; flex-direction:column; gap:12px; grid-column:1; grid-row:1 / span 2;
  position:sticky; top:100px; align-self:start; min-width:0; width:100%;
}
html body[data-page="species-detail"] .dsr-facts { grid-column:2; grid-row:1; }
html body[data-page="species-detail"] .dsr-buy { grid-column:2; grid-row:2; background:transparent; padding:0; box-shadow:none; }
body[data-page="species-detail"] #sdMain {
  display:grid; place-items:center; width:100%; aspect-ratio:1; padding:12px;
  border:1px solid var(--dsr-hair); border-radius:var(--dsr-slip-r); background:var(--color-surface);
  overflow:hidden; cursor:zoom-in; position:relative;
}
#sdMainImage { width:100%; height:100%; position:absolute; inset:0; object-fit:contain; }
#sdMainImage[hidden], #sdMediaEmpty[hidden] { display:none; }
#sdMediaEmpty { padding:24px; color:var(--color-neutral-600); font:400 var(--fs-read) var(--font-body); }
#sdMain:disabled { cursor:default; }
.species-media-caption { display:flex; flex-direction:column; gap:4px; min-height:46px; font-size:var(--fs-read); }
.species-media-caption strong { line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.species-media-caption > span { color:var(--color-accent-700); font-variant-numeric:tabular-nums; }
.species-thumb-nav { display:grid; grid-template-columns:30px minmax(0,1fr) 30px; align-items:center; gap:6px; }
body[data-page="species-detail"] #sdThumbs {
  display:flex; flex-wrap:nowrap; gap:8px; overflow-x:auto; overflow-y:hidden; min-width:0;
  padding:4px 2px 8px; overscroll-behavior-x:contain; scrollbar-width:thin;
  scrollbar-color:var(--color-accent) transparent;
}
html body[data-page="species-detail"] .detail-media .species-thumb {
  display:flex; flex-direction:column; gap:5px; flex:0 0 96px; width:96px; transform:none;
  padding:4px; border:2px solid var(--dsr-hair); border-radius:9px; background:var(--color-bg);
  color:var(--color-text); cursor:pointer; text-align:center; font:500 var(--fs-min)/1.25 var(--font-body);
}
html body[data-page="species-detail"] .detail-media .species-thumb[aria-pressed="true"] {
  border-color:var(--color-accent); background:var(--color-accent-100);
}
html body[data-page="species-detail"] .detail-media .species-thumb-image {
  display:grid; place-items:center; width:84px; height:84px; flex:none; border-radius:5px; overflow:hidden;
  color:var(--color-neutral-600); background:var(--color-surface);
}
.species-thumb-image img { display:block; width:100%; height:100%; object-fit:contain; }
html body[data-page="species-detail"] .detail-media .species-thumb-label {
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; width:100%; height:33px;
  overflow:hidden; overflow-wrap:normal;
}
.species-thumb.is-sold-out .species-thumb-label { color:var(--color-neutral-600); }
.species-thumb-arrow { width:30px; height:44px; border:1px solid var(--dsr-hair); border-radius:8px; background:var(--color-surface); color:var(--color-text); font-size:26px; cursor:pointer; }
.species-thumb-arrow:disabled { opacity:.3; cursor:default; }
.species-purchase-gallery button:focus-visible { outline:2px solid var(--color-accent); outline-offset:2px; }
body[data-page="species-detail"] #phaseSelect { width:100%; max-width:100%; }
.dsr-act > button:disabled { opacity:.5; cursor:not-allowed; }
@media (max-width:939px) {
  html body[data-page="species-detail"] .dsr-counter { grid-template-columns:minmax(0,1fr); row-gap:22px; }
  html body[data-page="species-detail"] .dsr-counter > .detail-media { grid-column:1; grid-row:1; position:static; max-width:520px; }
  html body[data-page="species-detail"] .dsr-facts { grid-column:1; grid-row:2; }
  html body[data-page="species-detail"] .dsr-buy { grid-column:1; grid-row:3; }
}
