/* ============================================================================
   SLEUKRITH · application styles
   Builds on khmer-typography.css, which owns all type and colour tokens.
   Nothing here redefines a token — it only arranges.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* The browser's own rule for [hidden] is display:none, but any author rule
   setting display on the same element beats it. That is why the formatting
   toolbar sat permanently under the subtitle: .format-bar had display:flex.
   Stating it here, once, means `hidden` always means hidden. */
[hidden] { display: none !important; }
body { margin: 0; }
img { max-width: 100%; height: auto; }
a { color: inherit; }
button { font: inherit; color: inherit; }

.wrap        { max-width: 40em; margin-inline: auto; padding-inline: 1.5rem; }
.wrap-narrow { max-width: 26em; margin-inline: auto; padding-inline: 1.5rem; }
.wrap-wide   { max-width: 62em; margin-inline: auto; padding-inline: 1.5rem; }

/* ── header ─────────────────────────────────────────────────────────────── */

.site-head {
  border-bottom: 1px solid var(--rule);
  background: var(--leaf);
  position: sticky; top: 0; z-index: 40;
}
.head-in {
  max-width: 68em; margin-inline: auto; padding: 0.7rem 1.5rem;
  display: flex; align-items: center; gap: 1.1rem;
}
.brand { text-decoration: none; flex-shrink: 0; }
.head-nav { display: flex; gap: 1rem; /*font-family: var(--f-la-ui);*/ font-size: 0.88rem; }
.head-nav a { text-decoration: none; color: var(--ink-soft); }
.head-nav a:hover { color: var(--ink); }
.head-search { flex: 1; max-width: 16rem; margin-inline-start: auto; }
.head-search input {
  width: 100%; padding: 0.4rem 0.7rem; /*font-family: var(--f-la-ui);*/ font-size: 0.85rem;
  border: 1px solid var(--rule); border-radius: 2px; background: transparent; color: var(--ink);
}
.head-right { display: flex; align-items: center; gap: 0.55rem; }
.lang-toggle {
  /*font-family: var(--f-la-ui);*/ font-size: 0.78rem; letter-spacing: 0.04em;
  text-decoration: none; color: var(--ink-faint); padding: 0.3rem 0.5rem;
  border: 1px solid var(--rule); border-radius: 2px;
}
.lang-toggle:hover { color: var(--ink); border-color: var(--ink-faint); }

/* avatar + account menu */
.avatar { display: inline-block; border-radius: 50%; object-fit: cover; vertical-align: middle; }
.avatar-letter {
  /* The tint is a mid-tone chosen per user, so a fixed near-black letter fails
     in dark mode — it was 1.01:1 against the recessed panel colour. The letter
     colour is supplied inline alongside the tint instead, and these are only
     the fallbacks for when neither is set. */
  background: var(--tint, var(--rule)); color: var(--ink-letter, #17150F);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--f-km-ui);
}
.menu { position: relative; }
.menu summary { list-style: none; cursor: pointer; }
.menu summary::-webkit-details-marker { display: none; }
.menu-panel {
  position: absolute; right: 0; top: calc(100% + 0.5rem); min-width: 12rem;
  background: var(--leaf); border: 1px solid var(--rule); border-radius: 3px;
  display: flex; flex-direction: column; padding: 0.35rem 0;
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.08);
}
.menu-panel a {
  padding: 0.5rem 0.9rem; text-decoration: none;
  /*font-family: var(--f-la-ui);*/ font-size: 0.87rem;
}
.menu-panel a:hover { background: var(--leaf-sunk); }
.menu-panel hr { border: 0; border-top: 1px solid var(--rule); margin: 0.3rem 0; }

/* ── buttons ────────────────────────────────────────────────────────────── */

.btn {
  display: inline-block; /*font-family: var(--f-la-ui);*/ font-size: 0.85rem;
  padding: 0.44rem 0.95rem; border-radius: 2px; border: 1px solid transparent;
  text-decoration: none; cursor: pointer; background: none; white-space: nowrap;
}
.btn-solid  { background: var(--ink); color: var(--leaf); }
.btn-solid:hover { background: var(--rubric); }
.btn-quiet  { border-color: var(--rule); color: var(--ink-soft); }
.btn-quiet:hover { border-color: var(--ink-faint); color: var(--ink); }
.btn-danger { border-color: var(--rubric); color: var(--rubric); }
.btn-block  { display: block; width: 100%; text-align: center; }

.act {
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-faint);
  background: none; border: 0; cursor: pointer; padding: 0.3rem 0.5rem; text-decoration: none;
}
.act:hover { color: var(--ink); }
.act.on { color: var(--rubric); }

/* ── hero & home ────────────────────────────────────────────────────────── */

.hero { text-align: center; padding: 4rem 1.5rem 2.5rem; }
.hero-mark { display: block; margin: 0 0 0.9rem; }
.hero-line {
  font-family: var(--f-la-body); color: var(--ink-soft);
  max-width: 26em; margin: 0 auto 1.6rem;
}
.hero-line:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }

.topic-strip {
  display: flex; gap: 0.45rem; overflow-x: auto; padding-bottom: 0.9rem;
  scrollbar-width: none; margin-bottom: 1.4rem;
}
.topic-strip::-webkit-scrollbar { display: none; }
.topic-strip a {
  flex-shrink: 0; padding: 0.3rem 0.75rem; border: 1px solid var(--rule);
  border-radius: 999px; text-decoration: none; font-size: 0.85rem; color: var(--ink-soft);
  line-height: 1.9;
}
.topic-strip a:hover { border-color: var(--ink-faint); color: var(--ink); }

.feed-head { display: flex; gap: 1.2rem; border-bottom: 1px solid var(--rule); margin-bottom: 1.8rem; }
.tab {
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; text-decoration: none;
  padding: 0.5rem 0; color: var(--ink-faint); border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab.on { color: var(--ink); border-bottom-color: var(--rubric); }

/* ── article ────────────────────────────────────────────────────────────── */

.article { padding: 2.5rem 1.5rem 1rem; }
.article-head { margin-bottom: 2rem; }
.eyebrow {
  /*font-family: var(--f-la-ui);*/ font-size: 0.74rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--rubric); text-decoration: none;
}
.eyebrow:lang(km) { font-family: var(--f-km-ui); letter-spacing: 0; text-transform: none; font-size: 0.86rem; }
.article-title { font-size: 2rem; line-height: 1.25; margin: 0.6rem 0 0.5rem; font-weight: 700; }
.article-title:lang(km) { font-family: var(--f-km-body); line-height: 1.55; font-size: 1.8rem; }
.article-sub { color: var(--ink-soft); font-size: 1.1rem; margin: 0 0 1.2rem; }

.byline { display: flex; align-items: center; gap: 0.75rem; margin-top: 1.4rem; }
.byline-name { /*font-family: var(--f-la-ui);*/ font-weight: 600; text-decoration: none; font-size: 0.92rem; }
.byline .btn { margin-inline-start: auto; }

.article-cover { margin: 0 0 2rem; }
.article-cover img { width: 100%; border-radius: 2px; }

.article-tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 2.5rem 0 1.5rem; }
.tag {
  font-size: 0.82rem; padding: 0.25rem 0.7rem; border: 1px solid var(--rule);
  border-radius: 999px; text-decoration: none; color: var(--ink-soft); line-height: 1.9;
}
.article-actions {
  display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap;
  padding: 1rem 0; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
}

/* ── paywall ────────────────────────────────────────────────────────────── */

.paywall { max-width: var(--measure-km); margin: 0 auto; padding: 0 1.5rem 3rem; text-align: center; }
.paywall-kicker {
  /*font-family: var(--f-la-ui);*/ font-size: 0.72rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--brass); margin: 0 0 0.6rem;
}
.paywall-title { margin: 0 0 0.5rem; font-size: 1.3rem; }
.paywall-title:lang(km) { font-family: var(--f-km-body); line-height: 1.6; }
.paywall-price { /*font-family: var(--f-la-ui);*/ font-size: 1.5rem; margin: 0.4rem 0 1.2rem; }
.paywall-note { max-width: 24em; margin: 1rem auto 0; }

/* ── author box, profile ────────────────────────────────────────────────── */

.author-box { display: flex; gap: 1.1rem; align-items: flex-start; padding-block: 1.5rem 2.5rem; }
.author-bio { margin: 0.4rem 0; color: var(--ink-soft); }
.profile { display: flex; gap: 1.4rem; align-items: flex-start; padding-block: 3rem 1.5rem; }
.profile-main { flex: 1; min-width: 0; }
.profile-name { margin: 0 0 0.2rem; font-size: 1.7rem; }
.profile-bio { color: var(--ink-soft); margin: 0.7rem 0; }
.profile-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }

/* ── comments ───────────────────────────────────────────────────────────── */

.comments { padding-block: 2rem 4rem; }
.section-title { margin: 2rem 0 1rem; font-size: 0.78rem; }
.comment-form { display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 2rem; }
.comment-form textarea,
.form textarea, .form input, .form select, .field input, .field textarea, .field select {
  width: 100%; padding: 0.6rem 0.75rem; border: 1px solid var(--rule); border-radius: 2px;
  background: transparent; color: var(--ink); /*font-family: var(--f-la-ui);*/ font-size: 0.95rem;
}
.comment-form textarea:lang(km), .field textarea:lang(km), .field input:lang(km) {
  font-family: var(--f-km-body); line-height: var(--lh-khmer);
}
.comment-form .btn { align-self: flex-start; }
.comment { display: flex; gap: 0.8rem; padding: 1rem 0; border-top: 1px solid var(--rule); }
.comment-name { /*font-family: var(--f-la-ui);*/ font-weight: 600; text-decoration: none; font-size: 0.88rem; }
.comment p { margin: 0.35rem 0 0; }

/* ── forms ──────────────────────────────────────────────────────────────── */

.form { display: flex; flex-direction: column; gap: 1rem; }
.form-wide { max-width: 32em; }
.field { display: flex; flex-direction: column; gap: 0.3rem; }
.field > span { /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-soft); }
.field-inline { flex-direction: row; align-items: center; gap: 0.5rem; }
.field-inline input { width: auto; }
.inline-form { display: inline-flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; margin: 0.6rem 0; }
.inline-form input, .inline-form select { width: auto; padding: 0.35rem 0.5rem; }
.auth { padding-block: 4rem; }
.auth-alt { margin-top: 1.2rem; text-align: center; }
.page-title { font-size: 1.6rem; margin: 0 0 1rem; }
.search-big input { width: 100%; padding: 0.9rem 1rem; font-size: 1.1rem; margin-bottom: 1.5rem; }

/* ── feedback ───────────────────────────────────────────────────────────── */

.flash, .banner {
  /*font-family: var(--f-la-ui);*/ font-size: 0.87rem; padding: 0.7rem 1rem;
  border-inline-start: 3px solid var(--rule); background: var(--leaf-sunk);
  max-width: 62em; margin: 1rem auto; border-radius: 2px;
}
.flash-ok, .banner-ok { border-color: var(--brass); }
.flash-warn, .banner-warn { border-color: var(--rubric); }
.empty { color: var(--ink-faint); /*font-family: var(--f-la-ui);*/ padding: 3rem 0; text-align: center; }
.pager { display: flex; gap: 1.5rem; justify-content: center; padding: 2.5rem 0; font-size: 1.2rem; }
.pager a { text-decoration: none; color: var(--ink-faint); }
.pager a:hover { color: var(--rubric); }
.error-page { text-align: center; padding-block: 6rem; }

/* ── grids ──────────────────────────────────────────────────────────────── */

.topic-grid, .collection-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: 1rem;
}
.topic-card, .collection-card {
  border: 1px solid var(--rule); border-radius: 2px; padding: 1.1rem; text-decoration: none;
}
.topic-card:hover, .collection-card:hover { border-color: var(--ink-faint); }
.topic-card h2, .collection-card h3 { margin: 0 0 0.3rem; font-size: 1.05rem; }
.topic-head { padding-block: 2.5rem 0; }

/* ── tables ─────────────────────────────────────────────────────────────── */

.table { width: 100%; border-collapse: collapse; /*font-family: var(--f-la-ui);*/ font-size: 0.88rem; }
.table td { padding: 0.85rem 0.6rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
.table-tight td { padding: 0.5rem 0.6rem; }
.table .num { text-align: end; white-space: nowrap; }
.row-title { text-decoration: none; font-weight: 600; }
.pill {
  display: inline-block; font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 0.12rem 0.45rem; border: 1px solid var(--rule); border-radius: 2px; color: var(--ink-faint);
}
.pill-published, .pill-confirmed, .pill-paid, .pill-active { color: var(--brass); border-color: var(--brass); }
.pill-held, .pill-rejected, .pill-suspended { color: var(--rubric); border-color: var(--rubric); }

/* ── dashboard ──────────────────────────────────────────────────────────── */

.dash { padding-block: 2.5rem 4rem; }
.dash-tabs { display: flex; gap: 1.3rem; border-bottom: 1px solid var(--rule); margin-bottom: 2rem; }
.stat-row { display: flex; gap: 2rem; align-items: center; flex-wrap: wrap; margin-bottom: 2rem; }
.stat { display: flex; flex-direction: column; }
.stat b { /*font-family: var(--f-la-ui);*/ font-size: 1.5rem; font-weight: 600; }
.stat-row .btn { margin-inline-start: auto; }

/* ── order page ─────────────────────────────────────────────────────────── */

.order-page { padding-block: 3rem 5rem; }
.order-card {
  border: 1px solid var(--rule); border-radius: 2px; padding: 1.4rem;
  display: flex; flex-direction: column; gap: 1rem;
}
.order-item h2 { margin: 0.2rem 0 0; font-size: 1.15rem; }
.order-amount strong { /*font-family: var(--f-la-ui);*/ font-size: 1.6rem; display: block; }
.order-ref { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.ref-code {
  font-family: ui-monospace, Menlo, monospace; font-size: 1.05rem; letter-spacing: 0.06em;
  background: var(--leaf-sunk); padding: 0.25rem 0.6rem; border-radius: 2px;
}
.pay-steps { padding-inline-start: 1.2rem; line-height: 2; }
.pay-steps:lang(km) { line-height: var(--lh-khmer); }
.pay-methods { display: flex; gap: 2rem; align-items: flex-start; flex-wrap: wrap; margin: 1.5rem 0; }
.khqr img { width: 12rem; border: 1px solid var(--rule); border-radius: 2px; }
.pay-details dt { /*font-family: var(--f-la-ui);*/ font-size: 0.75rem; color: var(--ink-faint); margin-top: 0.7rem; }
.pay-details dd { margin: 0.15rem 0 0; font-family: ui-monospace, Menlo, monospace; }
.order-done { /*font-family: var(--f-la-ui);*/ color: var(--brass); margin: 1.5rem 0; }

/* ── admin ──────────────────────────────────────────────────────────────── */

.admin { display: grid; grid-template-columns: 14rem 1fr; min-height: 100vh; }
.admin-nav {
  border-inline-end: 1px solid var(--rule); padding: 1.2rem 1rem;
  display: flex; flex-direction: column; gap: 1.4rem;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.admin-brand { text-decoration: none; }
.admin-nav nav { display: flex; flex-direction: column; gap: 0.1rem; }
.admin-nav nav a {
  /*font-family: var(--f-la-ui);*/ font-size: 0.87rem; text-decoration: none;
  padding: 0.42rem 0.6rem; border-radius: 2px; color: var(--ink-soft);
  display: flex; align-items: center; gap: 0.5rem;
}
.admin-nav nav a:hover { background: var(--leaf-sunk); color: var(--ink); }
.admin-nav nav a.on { background: var(--leaf-sunk); color: var(--ink); font-weight: 600; }
.badge {
  margin-inline-start: auto; background: var(--rubric); color: var(--leaf);
  font-size: 0.68rem; padding: 0.05rem 0.35rem; border-radius: 999px;
}
.admin-foot { margin-block-start: auto; }
.admin-main { padding: 2rem 2.2rem 5rem; max-width: 66em; }
.admin-head h1 { margin: 0 0 0.3rem; font-size: 1.5rem; /*font-family: var(--f-la-ui);*/ }
.admin-head { margin-bottom: 2rem; }
.admin-sub { margin-top: 2.5rem; }

.kpi-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: 0.8rem; margin-bottom: 2rem;
}
.kpi {
  border: 1px solid var(--rule); border-radius: 2px; padding: 0.9rem 1rem;
  display: flex; flex-direction: column; gap: 0.15rem; text-decoration: none;
}
.kpi b { /*font-family: var(--f-la-ui);*/ font-size: 1.35rem; font-weight: 600; }
.kpi span { /*font-family: var(--f-la-ui);*/ font-size: 0.76rem; color: var(--ink-faint); }
.kpi-alert { border-color: var(--rubric); }
.kpi-alert b { color: var(--rubric); }

.mod-item {
  display: flex; gap: 1.5rem; padding: 1.2rem 0; border-bottom: 1px solid var(--rule);
  align-items: flex-start;
}
.mod-body { flex: 1; min-width: 0; }
.mod-body h3 { margin: 0 0 0.3rem; font-size: 1.1rem; }
.mod-excerpt { color: var(--ink-soft); margin: 0.6rem 0 0; font-size: 0.92rem; }
.mod-actions { display: flex; flex-direction: column; gap: 0.4rem; flex-shrink: 0; }
.mod-actions form { display: flex; flex-direction: column; gap: 0.4rem; }

/* settings screen */
.settings-tabs { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 2rem; }
.settings-tabs a {
  /*font-family: var(--f-la-ui);*/ font-size: 0.82rem; text-decoration: none;
  padding: 0.35rem 0.75rem; border: 1px solid var(--rule); border-radius: 999px;
  color: var(--ink-soft);
}
.settings-tabs a.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }

.settings-form { display: flex; flex-direction: column; gap: 1.3rem; max-width: 46em; }
.sfield { display: grid; grid-template-columns: 15rem 1fr; gap: 1.5rem; align-items: start; }
.sfield-label { display: flex; flex-direction: column; gap: 0.2rem; }
.sfield-label > span { /*font-family: var(--f-la-ui);*/ font-size: 0.9rem; }
.skey {
  font-family: ui-monospace, Menlo, monospace; font-size: 0.7rem;
  color: var(--ink-faint); background: var(--leaf-sunk); padding: 0.05rem 0.3rem;
  border-radius: 2px; align-self: flex-start;
}
.sfield-input { display: flex; flex-direction: column; gap: 0.3rem; }
.sfield-input input, .sfield-input select, .sfield-input textarea {
  width: 100%; padding: 0.5rem 0.65rem; border: 1px solid var(--rule);
  border-radius: 2px; background: transparent; color: var(--ink);
  /*font-family: var(--f-la-ui);*/ font-size: 0.9rem;
}
.sfield-input textarea:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.color-pair { display: flex; gap: 0.5rem; align-items: center; }
.color-pair input[type=color] { width: 2.6rem; height: 2.2rem; padding: 0.1rem; cursor: pointer; }
.s-preview { max-width: 10rem; margin-top: 0.4rem; border: 1px solid var(--rule); }
.switch { display: inline-flex; }
.switch input { width: auto; }
.settings-actions { display: flex; gap: 0.6rem; padding-top: 1rem; border-top: 1px solid var(--rule); }

/* ── footer ─────────────────────────────────────────────────────────────── */

.site-foot { padding-bottom: 3rem; }
.foot-in {
  max-width: 62em; margin-inline: auto; padding-inline: 1.5rem;
  display: flex; justify-content: space-between; gap: 2rem; flex-wrap: wrap;
}
.foot-links { display: flex; gap: 1rem; /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; }
.foot-links a { color: var(--ink-faint); text-decoration: none; }
.foot-links a:hover { color: var(--ink); }
.foot-legal { text-align: center; margin-top: 2rem; }

/* ── responsive ─────────────────────────────────────────────────────────── */

@media (max-width: 860px) {
  .admin { grid-template-columns: 1fr; }
  .admin-nav { position: static; height: auto; flex-direction: row; flex-wrap: wrap;
               border-inline-end: 0; border-bottom: 1px solid var(--rule); }
  .admin-nav nav { flex-direction: row; flex-wrap: wrap; }
  .admin-foot { margin: 0; }
  .admin-main { padding: 1.5rem 1.2rem 4rem; }
  .sfield { grid-template-columns: 1fr; gap: 0.4rem; }
}

@media (max-width: 640px) {
  .head-nav, .head-search { display: none; }
  .article-title { font-size: 1.6rem; }
  .article-title:lang(km) { font-size: 1.45rem; }
  .profile { flex-wrap: wrap; }
  .stat-row { gap: 1.2rem; }
  .mod-item { flex-direction: column; }
  .mod-actions, .mod-actions form { flex-direction: row; }
}

/* ============================================================================
   v1.1 · interface refresh, theme control, diagnostics
   ========================================================================== */

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--leaf); padding: 0.6rem 1rem;
}
.skip-link:focus { left: 0; }

/* ── reading progress ─────────────────────────────────────────────────────
   A hairline that fills as you read — the one piece of feedback a long Khmer
   article benefits from, since line counts are hard to eyeball. */
.read-progress {
  position: fixed; inset-block-start: 0; inset-inline: 0; height: 2px;
  background: var(--rubric); transform: scaleX(0); transform-origin: 0 50%;
  z-index: 60; will-change: transform; pointer-events: none;
}

/* ── theme toggle ─────────────────────────────────────────────────────────
   One button, three states. The icon shows what is currently active, not
   what tapping will do — matching how OS-level switches behave. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: none; cursor: pointer;
  color: var(--ink-faint); padding: 0;
}
.icon-btn:hover { color: var(--ink); border-color: var(--ink-faint); }
.icon-btn svg { display: none; }
.icon-btn[data-theme-state="light"] .ico-sun,
.icon-btn[data-theme-state="dark"]  .ico-moon,
.icon-btn[data-theme-state="auto"]  .ico-auto { display: block; }

/* ── header search with icon ──────────────────────────────────────────────── */
.head-search { position: relative; }
.head-search-icon {
  position: absolute; inset-inline-start: 0.6rem; top: 50%;
  transform: translateY(-50%); color: var(--ink-faint); pointer-events: none;
}
.head-search input { padding-inline-start: 2rem; border-radius: 999px; }

/* ── account menu ─────────────────────────────────────────────────────────── */
.menu-panel { border-radius: var(--radius); }
.menu-id { display: flex; flex-direction: column; gap: 0.1rem; padding-block: 0.6rem !important; }
.menu-id b { font-size: 0.9rem; }



/* ── editor additions ─────────────────────────────────────────────────────── */
.editor-note {
  max-width: var(--measure-km); margin: 1rem auto -1rem; padding: 0.6rem 1rem;
  border-inline-start: 3px solid var(--brass); background: var(--leaf-sunk);
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; border-radius: var(--radius);
}
.editor-error {
  max-width: var(--measure-km); margin: 1rem auto; padding: 0.75rem 1rem;
  border-inline-start: 3px solid var(--rubric); background: var(--leaf-sunk);
  color: var(--ink); /*font-family: var(--f-la-ui);*/ font-size: 0.88rem;
  border-radius: var(--radius);
}
#wordCount.short { color: var(--rubric); }


/* ── settings screen: preset preview swatches ─────────────────────────────── */
.preset-row { display: flex; gap: 0.5rem; margin-top: 0.4rem; }
.preset-swatch {
  display: flex; width: 3.4rem; height: 1.5rem;
  border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden;
}
.preset-swatch i { flex: 1; }

@media (max-width: 640px) {
  .head-write { display: none; }
  .feed-grid { grid-template-columns: 1fr; }
  .icon-btn { width: 1.9rem; height: 1.9rem; }
}

/* ── error page ───────────────────────────────────────────────────────────── */
.error-path { margin: 0.6rem 0 1.4rem; word-break: break-all; }
.error-path code {
  background: var(--leaf-sunk); padding: 0.2rem 0.5rem; border-radius: var(--radius);
  font-family: ui-monospace, Menlo, monospace; font-size: 0.85rem;
}
.error-suggest { list-style: none; padding: 0; margin: 0.4rem 0 1.6rem; }
.error-suggest li { padding: 0.35rem 0; }
.error-actions { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; }
.collection-head { padding-block: 3rem 1.5rem; }

/* ============================================================================
   v1.2 · home layout, cards, pages
   The home page follows note.com's structure — a picked lead, a topic strip,
   a cover-led grid, and a ranking rail — expressed in the manuscript palette
   rather than its own.
   ========================================================================== */

/* ── masthead ─────────────────────────────────────────────────────────────
   A short line of purpose plus the banner, side by side on a wide screen and
   stacked on a phone. The tagline stays first in the source either way, so it
   is what a screen reader meets and what loads before the artwork. */
.masthead { border-bottom: 1px solid var(--rule); background: var(--leaf-sunk); }
.masthead-in {
  max-width: 72em; margin-inline: auto; padding: 1.8rem 1.5rem;
  display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: 2rem; align-items: center;
}
.masthead-in:not(:has(.banner-carousel)) {
  grid-template-columns: 1fr; text-align: center; padding-block: 2.6rem 2.2rem;
}
.masthead-say { display: flex; flex-direction: column; gap: 1rem; align-items: flex-start; }
.masthead-in:not(:has(.banner-carousel)) .masthead-say { align-items: center; }
.masthead-line {
  font-family: var(--f-la-body); color: var(--ink-soft); margin: 0; font-size: 1.02rem;
}
.masthead-line:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }

/* ── banner carousel ──────────────────────────────────────────────────────
   16:6 on a desktop, where a wide strip reads as a banner. On a phone that
   same ratio collapses to an unreadable sliver, so it becomes 4:3 and the
   admin can supply a squarer crop to suit. */
.banner-carousel {
  position: relative; overflow: hidden; border-radius: var(--radius);
  aspect-ratio: 16 / 6; background: var(--rule);
}
.banner-track { display: flex; height: 100%; transition: transform 0.45s cubic-bezier(.3,.7,.2,1); }
.banner-slide {
  flex: 0 0 100%; position: relative; display: block; height: 100%;
  text-decoration: none; color: #fff;
}
.banner-slide picture, .banner-slide img {
  width: 100%; height: 100%; display: block; object-fit: cover;
}
.banner-text {
  position: absolute; inset-block-end: 0; inset-inline: 0;
  padding: 2.2rem 1.4rem 1rem;
  background: linear-gradient(to top, rgb(0 0 0 / 0.72), transparent);
  display: flex; flex-direction: column; gap: 0.15rem;
}
.banner-text strong { font-size: 1.05rem; font-weight: 600; line-height: 1.5; }
.banner-text span { font-size: 0.85rem; opacity: 0.9; line-height: 1.5; }

.banner-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 2rem; height: 2rem; border-radius: 50%; border: 0; cursor: pointer;
  background: rgb(0 0 0 / 0.4); color: #fff; font-size: 1.2rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; opacity: 0;
  transition: opacity 0.15s ease;
}
.banner-carousel:hover .banner-arrow, .banner-arrow:focus-visible { opacity: 1; }
.banner-prev { inset-inline-start: 0.5rem; }
.banner-next { inset-inline-end: 0.5rem; }

.banner-dots {
  position: absolute; inset-block-end: 0.6rem; inset-inline: 0;
  display: flex; gap: 0.35rem; justify-content: center;
}
.banner-dot {
  width: 0.45rem; height: 0.45rem; border-radius: 50%; border: 0; cursor: pointer;
  background: rgb(255 255 255 / 0.5); padding: 0;
}
.banner-dot.on { background: #fff; width: 1.1rem; border-radius: 999px; }

.banner-thumb { width: 8rem; height: 3rem; object-fit: cover; border-radius: var(--radius); display: block; }
.s-preview.wide { max-width: 18rem; }

.home { max-width: 72em; margin-inline: auto; padding: 0 1.5rem 4rem; }

/* ── topic strip ──────────────────────────────────────────────────────────── */
.topic-strip {
  display: flex; gap: 0.4rem; overflow-x: auto; scrollbar-width: none;
  padding: 1.1rem 0; margin-bottom: 0.4rem;
  border-bottom: 1px solid var(--rule);
  position: sticky; top: 3.1rem; background: var(--leaf); z-index: 20;
}
.topic-strip::-webkit-scrollbar { display: none; }
.topic-strip a {
  flex-shrink: 0; padding: 0.32rem 0.8rem; border: 1px solid var(--rule);
  border-radius: 999px; text-decoration: none; font-size: 0.85rem;
  color: var(--ink-soft); line-height: 1.9; white-space: nowrap;
}
.topic-strip a:hover { border-color: var(--ink-faint); color: var(--ink); }
.topic-strip a.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }

/* ── two columns ──────────────────────────────────────────────────────────── */
.home-cols { display: grid; grid-template-columns: minmax(0, 1fr) 17rem; gap: 3rem; padding-top: 1.6rem; }
.home-side { display: flex; flex-direction: column; gap: 2.2rem; align-self: start; position: sticky; top: 7rem; }

.rail-title {
  /*font-family: var(--f-la-ui);*/ font-size: 0.76rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-faint);
  margin: 0 0 0.9rem; font-weight: 600;
}
.rail-title:lang(km) { font-family: var(--f-km-ui); letter-spacing: 0; text-transform: none; font-size: 0.9rem; }

/* ── lead block ───────────────────────────────────────────────────────────── */
.lead { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 2rem; }
.lead-side { display: flex; flex-direction: column; gap: 0.2rem; }

/* ── cards ────────────────────────────────────────────────────────────────── */
.card { min-width: 0; }
.card-cover { display: block; position: relative; overflow: hidden; border-radius: var(--radius); }
/* The aspect-ratio lives on the <a>. Without height:100% the <img> keeps its
   own proportions and letterboxes inside that box — which is why the lead
   cover was only filling the top half of its frame. */
.card-cover img {
  width: 100%; height: 100%; display: block; object-fit: cover; object-position: center;
  transition: transform 0.35s cubic-bezier(.2,.6,.2,1);
}
.card-cover:hover img { transform: scale(1.03); }
.card-paid { position: absolute; inset-block-start: 0.6rem; inset-inline-end: 0.6rem;
             background: var(--leaf); }

.card-title { margin: 0 0 0.35rem; font-weight: 600; line-height: 1.35; font-size: 1.02rem; }
.card-title:lang(km) { font-family: var(--f-km-body); line-height: 1.6; }
.card-title a { text-decoration: none; }
.card-title a:hover { color: var(--rubric); }

.card-excerpt {
  margin: 0 0 0.7rem; color: var(--ink-soft); font-size: 0.9rem;
  font-family: var(--f-la-body);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card-excerpt:lang(km) { font-family: var(--f-km-body); line-height: 1.85; }

.card-foot { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; }
.card-author {
  display: inline-flex; align-items: center; gap: 0.4rem; text-decoration: none;
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-soft); min-width: 0;
}
.card-author span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 11rem; }
.card-author:hover { color: var(--ink); }
.card-stats { margin-inline-start: auto; display: flex; gap: 0.55rem; align-items: center; white-space: nowrap; }

/* grid: cover on top, the note.com shape */
.feed-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 2rem 1.5rem; }
.card-grid .card-cover { margin-bottom: 0.75rem; aspect-ratio: 16 / 10; }
.card-grid .card-excerpt { -webkit-line-clamp: 2; }

/* lead: one large card carrying the picked article */
.card-lead .card-cover { margin-bottom: 1rem; aspect-ratio: 16 / 9; }
.card-lead .card-title { font-size: 1.5rem; line-height: 1.3; }
.card-lead .card-title:lang(km) { font-size: 1.35rem; line-height: 1.55; }
.card-lead .card-excerpt { -webkit-line-clamp: 3; font-size: 0.95rem; }

/* row: compact, no cover, for the lead sidebar */
.card-row { padding: 0.85rem 0; border-bottom: 1px solid var(--rule); }
.card-row:last-child { border-bottom: 0; }
.card-row .card-title { font-size: 0.96rem; margin-bottom: 0.45rem; }

/* list: the default used by topic, author, search and library pages */
.feed { display: flex; flex-direction: column; }
.card-list {
  display: grid; grid-template-columns: minmax(0, 1fr) 10rem; gap: 1.5rem;
  padding: 1.6rem 0; border-bottom: 1px solid var(--rule); align-items: start;
}
.card-list .card-cover { grid-column: 2; grid-row: 1; aspect-ratio: 4 / 3; }
.card-list .card-body  { grid-column: 1; grid-row: 1; }
.card-list .card-title { font-size: 1.15rem; }
.card-list:not(:has(.card-cover)) { grid-template-columns: 1fr; }

/* ── ranking rail ─────────────────────────────────────────────────────────
   Numbered because the order is the information — this is a ranking, not a
   decorative list. */
.rank { list-style: none; margin: 0; padding: 0; counter-reset: r; }
.rank li { display: flex; gap: 0.7rem; padding: 0.55rem 0; border-bottom: 1px solid var(--rule); }
.rank li:last-child { border-bottom: 0; }
.rank-n {
  /*font-family: var(--f-la-ui);*/ font-size: 0.95rem; font-weight: 700;
  color: var(--brass); min-width: 1.1rem; line-height: 1.6;
}
.rank a {
  text-decoration: none; font-size: 0.88rem; line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rank a:lang(km) { line-height: 1.8; }
.rank a:hover { color: var(--rubric); }

.writer-list { list-style: none; margin: 0; padding: 0; }
.writer-list li { display: flex; gap: 0.65rem; padding: 0.6rem 0; align-items: center; }
.writer-name { /*font-family: var(--f-la-ui);*/ font-size: 0.87rem; font-weight: 600; text-decoration: none; }
.writer-name:hover { color: var(--rubric); }

.side-topics { list-style: none; margin: 0; padding: 0; }
.side-topics li { display: flex; justify-content: space-between; gap: 0.6rem; padding: 0.4rem 0; }
.side-topics a { text-decoration: none; font-size: 0.88rem; }
.side-topics a:hover { color: var(--rubric); }
.side-more { display: inline-block; margin-top: 0.7rem; text-decoration: none; }

/* ── admin pages ──────────────────────────────────────────────────────────── */
.page-form textarea { font-family: ui-monospace, Menlo, monospace; font-size: 0.85rem; line-height: 1.6; }
.page-form textarea[lang="km"] { font-family: var(--f-km-body); font-size: 1rem; line-height: var(--lh-khmer); }
.page-landing { width: 100%; }
.page-editlink { text-align: center; padding: 2rem 0 3rem; }

/* ── responsive ───────────────────────────────────────────────────────────── */
@media (max-width: 960px) {
  .home-cols { grid-template-columns: 1fr; gap: 2.5rem; }
  .home-side { position: static; }
  .lead { grid-template-columns: 1fr; gap: 1.2rem; }
}
@media (max-width: 640px) {
  .masthead-in { padding: 2rem 1.2rem 1.7rem; }
  .home { padding-inline: 1.2rem; }
  .topic-strip { top: 3rem; }
  .feed-grid { grid-template-columns: 1fr; gap: 1.8rem; }
  .card-list { grid-template-columns: minmax(0, 1fr) 6.5rem; gap: 1rem; }
  .card-lead .card-title { font-size: 1.25rem; }
}

/* ============================================================================
   COMPOSER
   Two screens. Writing gets the full width; publishing gets its own page.
   The old right-hand drawer is gone — it could never be wide enough on a
   laptop, and on a phone it covered the article you were trying to check.
   ========================================================================== */

body.bare { background: var(--leaf); }
.composer { min-height: 100vh; }

.cmp-bar {
  position: sticky; top: 0; z-index: 40; background: var(--leaf);
  border-bottom: 1px solid var(--rule);
  display: flex; align-items: center; gap: 1rem; padding: 0.7rem 1.4rem;
}
.cmp-close {
  background: none; border: 0; cursor: pointer; padding: 0;
  /*font-family: var(--f-la-ui);*/ font-size: 0.87rem; color: var(--ink-soft); text-decoration: none;
}
.cmp-close:hover { color: var(--ink); }
.cmp-status { display: flex; gap: 1rem; margin-inline: auto; }
.cmp-actions { display: flex; gap: 0.45rem; align-items: center; }

.tool {
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; background: none;
  border: 1px solid transparent; border-radius: var(--radius);
  padding: 0.36rem 0.65rem; cursor: pointer; color: var(--ink-faint);
}
.tool:hover, .tool.on { color: var(--ink); border-color: var(--rule); }
.tool.on { background: var(--leaf-sunk); }

/* ── dock and panels ──────────────────────────────────────────────────────
   A permanent icon dock, and one panel that slides out of it. The panel
   never takes a column out of the writing area — the page slides across —
   so the measure of the writing column is identical open or closed. */

.cmp-body { position: relative; min-height: calc(100vh - 3.3rem); }

.cmp-dock {
  position: fixed; inset-block-start: 3.3rem; inset-inline-start: 0; bottom: 0;
  width: 3rem; border-inline-end: 1px solid var(--rule); background: var(--leaf);
  display: flex; flex-direction: column; align-items: center; gap: 0.15rem;
  padding-top: 0.8rem; z-index: 35;
}
.dock-btn {
  width: 2.2rem; height: 2.2rem; border: 0; background: none; cursor: pointer;
  color: var(--ink-faint); border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
}
.dock-btn svg { width: 18px; height: 18px; }
.dock-btn:hover { color: var(--ink); background: var(--leaf-sunk); }
.dock-btn.on { color: var(--rubric); background: var(--leaf-sunk); }

.cmp-panel {
  position: fixed; inset-block-start: 3.3rem; inset-inline-start: 3rem; bottom: 0;
  width: 16rem; overflow-y: auto; z-index: 34;
  background: var(--leaf); border-inline-end: 1px solid var(--rule);
  padding: 1.4rem 1.1rem 3rem;
}
.panel-close {
  position: absolute; top: 0.6rem; inset-inline-end: 0.7rem;
  border: 0; background: none; cursor: pointer; color: var(--ink-faint);
  font-size: 1.1rem; line-height: 1;
}
.panel-close:hover { color: var(--ink); }

.guide-list { list-style: none; margin: 0 0 1.6rem; padding: 0; }
.guide-list li {
  display: flex; align-items: center; gap: 0.3rem; padding: 0.35rem 0;
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-soft);
}
.guide-list span { margin-inline-start: auto; }
kbd {
  font-family: ui-monospace, Menlo, monospace; font-size: 0.68rem;
  border: 1px solid var(--rule); border-radius: 3px; padding: 0.1rem 0.3rem;
  background: var(--leaf-sunk); color: var(--ink-soft);
}
.guide-note {
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; line-height: 1.6;
  color: var(--ink-soft); margin: 0 0 1rem;
}
.guide-note:lang(km) { font-family: var(--f-km-ui); line-height: var(--lh-khmer); }

/* contents panel */
.toc-list { list-style: none; margin: 0; padding: 0; counter-reset: toc; }
.toc-list li { padding: 0.3rem 0; }
.toc-list a {
  text-decoration: none; font-size: 0.84rem; line-height: 1.5; color: var(--ink-soft);
  display: block;
}
.toc-list a:lang(km), .toc-list a { line-height: 1.7; }
.toc-list a:hover { color: var(--rubric); }
.toc-h3 { padding-inline-start: 0.9rem; }
.toc-h3 a { font-size: 0.8rem; color: var(--ink-faint); }

/* formats panel */
.format-list { display: flex; flex-direction: column; gap: 0.1rem; }
.format-list button {
  display: flex; align-items: center; gap: 0.6rem; text-align: start;
  background: none; border: 0; cursor: pointer; padding: 0.42rem 0.5rem;
  border-radius: var(--radius); /*font-family: var(--f-la-ui);*/
  font-size: 0.83rem; color: var(--ink); width: 100%;
}
.format-list button:hover { background: var(--leaf-sunk); }
.format-list span { color: var(--ink-soft); }

/* tips panel — admin-authored, so it needs real prose styling */
.tips-body { font-family: var(--f-la-body); font-size: 0.86rem; line-height: 1.6; color: var(--ink-soft); }
.tips-body:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.tips-body h3 { font-size: 0.82rem; color: var(--ink); margin: 0 0 0.5rem; }
.tips-body ul { padding-inline-start: 1.1rem; margin: 0 0 1.2rem; }
.tips-body li { margin-bottom: 0.45rem; }

/* ── the page ─────────────────────────────────────────────────────────────
   The left gutter is what the + sits in. It must be wider than the button's
   offset so the button can never overlap the text it belongs to. */
.cmp-page {
  max-width: calc(var(--measure-km) + 7rem);
  margin-inline: auto; width: 100%;
  padding: 2.4rem 1.5rem 9rem 4.5rem;
  transition: transform 0.18s ease;
}
.composer.panel-open .cmp-page { transform: translateX(8rem); }
.cmp-cover, .cmp-title, .cmp-subtitle, .cmp-write { max-width: var(--measure-km); }

/* ── cover ────────────────────────────────────────────────────────────────── */
.cmp-cover { position: relative; margin-bottom: 1.6rem; }
.cover-add {
  width: 3rem; height: 3rem; border-radius: 50%; border: 1px dashed var(--rule);
  background: var(--leaf-sunk); color: var(--ink-faint); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.cover-add:hover { color: var(--ink); border-color: var(--ink-faint); }
.cmp-cover.has-cover .cover-add { display: none; }
.cover-img { width: 100%; border-radius: var(--radius); display: block; }
.cover-remove {
  position: absolute; top: 0.6rem; inset-inline-end: 0.6rem;
  width: 1.9rem; height: 1.9rem; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--ink); color: var(--leaf); font-size: 1.1rem; line-height: 1;
}

/* ── title fields ─────────────────────────────────────────────────────────── */
.cmp-title, .cmp-subtitle {
  width: 100%; border: 0; background: none; resize: none; outline: none;
  color: var(--ink); font-family: var(--f-km-body); overflow: hidden; display: block;
  position: relative; z-index: 2;   /* nothing may float over the title */
}
.cmp-title { font-size: 1.9rem; font-weight: 700; line-height: 1.5; margin-bottom: 0.3rem; }
.cmp-subtitle { font-size: 1.05rem; color: var(--ink-soft); line-height: 1.8; margin-bottom: 1.6rem; }
.cmp-title::placeholder, .cmp-subtitle::placeholder { color: var(--ink-faint); }

/* ── insert rail ──────────────────────────────────────────────────────────
   Lives inside .cmp-write, the same box its position is measured against,
   and appears only when the caret is on an empty line. */
.cmp-write { position: relative; }
.cmp-insert { position: absolute; inset-inline-start: -3rem; top: 0; z-index: 3; }
.insert-btn {
  width: 2rem; height: 2rem; border-radius: 50%; border: 1px solid var(--rule);
  background: var(--leaf); color: var(--ink-faint); cursor: pointer;
  font-size: 1.15rem; line-height: 1; display: flex; align-items: center; justify-content: center;
  transition: transform 0.15s ease, color 0.15s ease;
}
.insert-btn:hover { color: var(--ink); border-color: var(--ink-faint); }
.insert-btn.open { transform: rotate(45deg); color: var(--ink); }
.insert-menu {
  position: absolute; inset-inline-start: 2.5rem; top: 0; min-width: 14rem;
  background: var(--leaf); border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 10px 34px rgb(0 0 0 / 0.12); padding: 0.3rem 0;
  display: flex; flex-direction: column; max-height: 70vh; overflow-y: auto; z-index: 40;
}
.insert-menu button {
  display: flex; gap: 0.6rem; align-items: center; text-align: start;
  background: none; border: 0; cursor: pointer; padding: 0.5rem 0.9rem;
  /*font-family: var(--f-la-ui);*/ font-size: 0.86rem; color: var(--ink);
}
.insert-menu button:hover { background: var(--leaf-sunk); }
.insert-menu button svg { width: 17px; height: 17px; flex-shrink: 0; color: var(--ink-faint); }
.insert-menu button:hover svg { color: var(--ink); }
.blk-h {
  width: 17px; font-size: 0.72rem; /*font-family: var(--f-la-ui);*/
  color: var(--ink-faint); text-align: center; flex-shrink: 0;
}
.insert-paid { color: var(--brass) !important; border-top: 1px solid var(--rule) !important; margin-top: 0.2rem; }
.insert-paid .blk-h { color: var(--brass); font-size: 0.95rem; }

/* ── blocks, in the composer and in the published article ─────────────────── */
.editor figure.audio, .article-body figure.audio { margin: 1.6rem 0; }
.editor audio, .article-body audio { width: 100%; }
.editor figure.comic, .article-body figure.comic {
  margin: 1.8rem 0; display: flex; flex-direction: column; gap: 0.4rem;
}
.editor figure.comic img, .article-body figure.comic img { margin: 0; width: 100%; border-radius: var(--radius); }
.editor p.attach, .article-body p.attach { margin: 1.2rem 0; }
.editor p.attach a, .article-body p.attach a {
  display: inline-flex; align-items: center; gap: 0.5rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0.55rem 0.9rem; text-decoration: none;
  /*font-family: var(--f-la-ui);*/ font-size: 0.87rem;
}
.editor p.attach a::before, .article-body p.attach a::before { content: '📎'; }
.editor p.attach a:hover, .article-body p.attach a:hover { border-color: var(--ink-faint); }

.editor nav.toc, .article-body nav.toc {
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 1rem 1.2rem; margin: 1.8rem 0; background: var(--leaf-sunk);
}
.editor nav.toc { color: var(--ink-faint); /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; }
.article-body nav.toc ol { list-style: none; margin: 0; padding: 0; counter-reset: t; }
.article-body nav.toc li { padding: 0.28rem 0; }
.article-body nav.toc li::before {
  counter-increment: t; content: counter(t) '. ';
  color: var(--ink-faint); /*font-family: var(--f-la-ui);*/ font-size: 0.8rem;
}
.article-body nav.toc .toc-h3 { padding-inline-start: 1.2rem; }
.article-body nav.toc a { text-decoration: none; }
.article-body nav.toc a:hover { color: var(--rubric); }
.article-body h2[id], .article-body h3[id] { scroll-margin-top: 5rem; }

/* ── format bar ───────────────────────────────────────────────────────────── */
.format-bar {
  /* Fixed, and given viewport coordinates straight from
     getBoundingClientRect. It used to be absolute inside .cmp-write, which is
     position:relative, while the script fed it document coordinates — so the
     bar landed a long way from the text it belonged to. */
  position: fixed; z-index: 50; display: flex; gap: 0.1rem;
  background: var(--ink); border-radius: 3px; padding: 0.2rem;
  box-shadow: 0 4px 16px rgb(0 0 0 / 0.2);
}
.format-bar button {
  background: none; border: 0; color: var(--leaf); cursor: pointer;
  padding: 0.35rem 0.6rem; font-size: 0.85rem; border-radius: 2px;
}
.format-bar button:hover { background: rgb(255 255 255 / 0.15); }

/* ── the writing surface ──────────────────────────────────────────────────── */
.editor[contenteditable] {
  font-family: var(--f-km-body), var(--f-la-body);
  font-size: calc(var(--size-body) * var(--km-scale));
  line-height: var(--lh-khmer);
  outline: none; caret-color: var(--rubric); min-height: 55vh;
}
.editor[contenteditable]:empty::before {
  content: attr(data-placeholder); color: var(--ink-faint); pointer-events: none;
}
.editor img { max-width: 100%; border-radius: var(--radius); margin: 1.5rem 0; }
.editor blockquote { border-inline-start: 2px solid var(--rubric); padding-inline-start: 1.2rem; color: var(--ink-soft); }
.editor pre { background: var(--leaf-sunk); padding: 0.9rem 1rem; border-radius: var(--radius); overflow-x: auto; }
.zwsp-dot { color: var(--rubric); opacity: 0.45; }

/* The paid-area marker is a real object in the text, not a hairline: the
   writer must be able to see exactly where the free part stops. */
.editor hr.paywall-cut, .article-body hr.paywall-cut {
  border: 0; border-top: 2px dashed var(--brass); margin: 2rem 0;
  position: relative; overflow: visible;
}
.editor hr.paywall-cut::after {
  content: '៛'; position: absolute; top: -0.85rem; inset-inline-start: 50%;
  transform: translateX(-50%); background: var(--leaf); color: var(--brass);
  padding: 0 0.5rem; font-size: 0.9rem;
}

/* ── publish step ─────────────────────────────────────────────────────────── */
.cmp-publish { min-height: 100vh; }
.publish-grid {
  max-width: 54em; margin-inline: auto; padding: 2.5rem 1.5rem 6rem;
  display: grid; grid-template-columns: 1fr 1fr; gap: 3rem;
}
.publish-col { display: flex; flex-direction: column; gap: 1.1rem; }
.publish-col .field input, .publish-col .field select, .publish-col .field textarea { width: 100%; }

.editor-error {
  max-width: var(--measure-km); margin: 1rem auto; padding: 0.75rem 1rem;
  border-inline-start: 3px solid var(--rubric); background: var(--leaf-sunk);
  color: var(--ink); /*font-family: var(--f-la-ui);*/ font-size: 0.88rem;
  border-radius: var(--radius);
}
#wordCount.short { color: var(--rubric); }
.editor-msg {
  position: fixed; inset-block-end: 1.5rem; inset-inline: 0; margin-inline: auto;
  width: fit-content; max-width: 90vw; background: var(--ink); color: var(--leaf);
  padding: 0.6rem 1.1rem; border-radius: 3px; /*font-family: var(--f-la-ui);*/
  font-size: 0.85rem; z-index: 60;
}

@media (max-width: 1180px) {
  /* Not enough room to slide the page across; the guide overlays instead. */
  .composer.panel-open .cmp-page { transform: none; }
  .cmp-panel { box-shadow: 8px 0 30px rgb(0 0 0 / 0.10); }
}

@media (max-width: 860px) {
  .publish-grid { grid-template-columns: 1fr; gap: 2rem; }
}

@media (max-width: 640px) {
  .cmp-dock {
    inset-block-start: auto; bottom: 0; inset-inline: 0; width: auto; height: 3rem;
    flex-direction: row; justify-content: center; gap: 1.2rem; padding: 0;
    border-inline-end: 0; border-top: 1px solid var(--rule);
  }
  .cmp-panel { inset-inline: 0; width: auto; inset-block-end: 3rem; }
  .cmp-page { padding: 1.6rem 1.1rem 9rem; max-width: 100%; }
  .cmp-title { font-size: 1.5rem; }
  /* No left gutter on a phone, so the + sits above the line it acts on. */
  .cmp-insert { inset-inline-start: 0; transform: translateY(-2.4rem); }
  .insert-menu { inset-inline-start: 0; top: 2.5rem; }
  .cmp-bar { padding: 0.6rem 0.9rem; gap: 0.6rem; }
  .cmp-status { font-size: 0.72rem; }
  .cmp-actions .tool { display: none; }
}

/* ============================================================================
   v1.4 · dialogs, author tab
   ========================================================================== */

/* ── dialogs ──────────────────────────────────────────────────────────────
   Replaces alert/confirm/prompt. On a phone a browser dialog reads as a
   warning from the browser; this reads as a question from the site. */
.sk-modal-back {
  position: fixed; inset: 0; z-index: 200;
  background: rgb(0 0 0 / 0.4); backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center; padding: 1.2rem;
  opacity: 0; transition: opacity 0.14s ease;
}
.sk-modal-back.open { opacity: 1; }
.sk-modal {
  background: var(--leaf); color: var(--ink);
  border: 1px solid var(--rule); border-radius: calc(var(--radius) + 4px);
  box-shadow: 0 18px 50px rgb(0 0 0 / 0.25);
  width: min(26rem, 100%); padding: 1.4rem;
  display: flex; flex-direction: column; gap: 0.85rem;
  transform: translateY(6px); transition: transform 0.16s ease;
}
.sk-modal-back.open .sk-modal { transform: none; }
.sk-modal-title {
  margin: 0; /*font-family: var(--f-la-ui);*/ font-size: 1rem; font-weight: 600;
}
.sk-modal-title:lang(km) { font-family: var(--f-km-body); line-height: 1.6; }
.sk-modal-msg {
  margin: 0; color: var(--ink-soft); /*font-family: var(--f-la-ui);*/
  font-size: 0.9rem; line-height: 1.55;
}
.sk-modal-input {
  width: 100%; padding: 0.6rem 0.75rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  /*font-family: var(--f-la-ui);*/ font-size: 0.95rem;
}
.sk-modal-input[lang="km"] { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.sk-modal-actions { display: flex; gap: 0.5rem; justify-content: flex-end; }
.sk-choices { display: flex; flex-direction: column; gap: 0.1rem; }
.sk-choices button {
  text-align: start; background: none; border: 0; cursor: pointer;
  padding: 0.55rem 0.6rem; border-radius: var(--radius);
  /*font-family: var(--f-la-ui);*/ font-size: 0.9rem; color: var(--ink);
}
.sk-choices button:hover { background: var(--leaf-sunk); }

/* ── authors tab ──────────────────────────────────────────────────────────
   Ranked by how much the writing is read, so the number carries meaning and
   is set in the accent rather than left as decoration. */
.author-grid { display: flex; flex-direction: column; }
.author-card {
  display: grid; grid-template-columns: 2rem auto minmax(0, 1fr) auto;
  gap: 0.9rem; align-items: center;
  padding: 1rem 0; border-bottom: 1px solid var(--rule);
}
.author-rank {
  /*font-family: var(--f-la-ui);*/ font-size: 1rem; font-weight: 700;
  color: var(--brass); text-align: center;
}
.author-main { min-width: 0; }
.author-main .author-bio {
  margin: 0.15rem 0; color: var(--ink-soft); font-size: 0.85rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 860px) {
  .masthead-in { grid-template-columns: 1fr; gap: 1.2rem; }
  .masthead-say { align-items: center; text-align: center; }
}
@media (max-width: 640px) {
  /* A 16:6 strip is unreadable on a phone; 4:3 gives the artwork room. */
  .banner-carousel { aspect-ratio: 4 / 3; }
  .banner-arrow { display: none; }
  .banner-text { padding: 1.6rem 1rem 1.4rem; }
  .author-card { grid-template-columns: 1.5rem auto minmax(0, 1fr); row-gap: 0.5rem; }
  .author-card .btn { grid-column: 2 / -1; justify-self: start; }
}

/* ============================================================================
   v1.5 · adverts, avatars, featured
   ========================================================================== */

/* ── advert slot ──────────────────────────────────────────────────────────
   Labelled, and visually quieter than the editorial around it. An advert that
   looks like an article is a trick played on the reader. */
.ad-slot { border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.7rem; }
.ad-label {
  margin: 0 0 0.5rem; /*font-family: var(--f-la-ui);*/ font-size: 0.66rem;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint);
}
.ad-body { min-height: 3rem; }
.ad-body img { width: 100%; height: auto; display: block; border-radius: var(--radius); }
.ad-body iframe, .ad-body ins { max-width: 100%; }

/* ── profile picture picker ──────────────────────────────────────────────── */
.avatar-picker { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1rem; }
.avatar-picker legend {
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-soft); padding-inline: 0.4rem;
}
.avatar-now { display: flex; gap: 1.1rem; align-items: center; }
.avatar-modes { display: flex; flex-direction: column; gap: 0.35rem; }
.avatar-modes label {
  display: flex; gap: 0.45rem; align-items: center;
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; cursor: pointer;
}
.avatar-modes input { width: auto; }
.avatar-pane { margin-top: 1rem; }
.avatar-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(3.2rem, 1fr));
  gap: 0.45rem; max-height: 15rem; overflow-y: auto; padding: 0.15rem;
}
.avatar-opt {
  border: 2px solid transparent; border-radius: 50%; background: none;
  cursor: pointer; padding: 0; line-height: 0;
}
.avatar-opt:hover { border-color: var(--rule); }
.avatar-opt.on { border-color: var(--rubric); }
.avatar-drawn { border-radius: 50%; display: block; }
/* Overridden inline per user; kept here so the shape holds without it. */
.avatar-letter { background: var(--tint, var(--rule)); }

/* ── featured picker ──────────────────────────────────────────────────────── */
.feat-list { display: flex; flex-direction: column; }
.feat-row {
  display: grid; grid-template-columns: 1.6rem 5rem minmax(0, 1fr) auto;
  gap: 0.8rem; align-items: center;
  padding: 0.7rem 0; border-bottom: 1px solid var(--rule);
}
.feat-pos {
  /*font-family: var(--f-la-ui);*/ font-weight: 700; color: var(--brass); text-align: center;
}
.feat-thumb { width: 5rem; height: 3rem; object-fit: cover; border-radius: var(--radius); display: block; }
.feat-nothumb {
  display: flex; align-items: center; justify-content: center;
  background: var(--leaf-sunk); color: var(--ink-faint);
}
.feat-main { min-width: 0; }
.feat-main a { text-decoration: none; font-weight: 600; font-size: 0.92rem; }
.feat-main a:hover { color: var(--rubric); }
.feat-actions { display: flex; gap: 0.2rem; align-items: center; }
.feat-auto { opacity: 0.85; }

@media (max-width: 640px) {
  .feat-row { grid-template-columns: 1.4rem 3.5rem minmax(0, 1fr); row-gap: 0.4rem; }
  .feat-actions { grid-column: 2 / -1; }
  .avatar-now { flex-direction: column; align-items: flex-start; }
}

/* ============================================================================
   v1.6 · request to sell, my orders
   ========================================================================== */

/* ── request to sell ──────────────────────────────────────────────────────
   Progress bars rather than a locked door. Being told only "no" gives a
   writer no idea whether they are nearly there or nowhere near. */
.sell-request { max-width: 34em; padding-block: 0.5rem 2rem; }
.sell-intro { margin-bottom: 1.6rem; }

.sell-bars { display: flex; flex-direction: column; gap: 1.2rem; margin-bottom: 1.8rem; }
.sell-bar-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  /*font-family: var(--f-la-ui);*/ font-size: 0.87rem; margin-bottom: 0.4rem;
}
.sell-bar-head span { color: var(--ink-soft); }
.sell-bar-head b { white-space: nowrap; }
.sell-track {
  height: 6px; background: var(--leaf-sunk); border-radius: 999px; overflow: hidden;
}
.sell-track i {
  display: block; height: 100%; background: var(--ink-faint);
  border-radius: 999px; transition: width 0.4s ease;
}
.sell-bar.done .sell-track i { background: var(--brass); }
.sell-bar.done .sell-bar-head b { color: var(--brass); }

.sell-criteria {
  border-inline-start: 3px solid var(--rule); padding: 0.2rem 0 0.2rem 1rem;
  margin-bottom: 1.6rem; color: var(--ink-soft);
  font-family: var(--f-la-body); font-size: 0.9rem;
}
.sell-criteria:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }

.sell-form textarea:disabled, .sell-form button:disabled {
  opacity: 0.45; cursor: not-allowed;
}
.sell-form button:disabled:hover { background: var(--ink); }

/* ── advert under Worth reading ───────────────────────────────────────────
   Sits at the foot of the secondary column, so it reads as a slot in the
   layout rather than as a fourth article. */
.ad-lead { margin-top: 0.9rem; }
.ad-lead .ad-body { min-height: 0; }

/* Requests queue reuses the moderation item, but its actions stack. */
.mod-actions input[type="text"] {
  padding: 0.4rem 0.55rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  /*font-family: var(--f-la-ui);*/ font-size: 0.82rem; min-width: 13rem;
}

@media (max-width: 640px) {
  .sell-request { max-width: 100%; }
  .mod-actions input[type="text"] { min-width: 0; width: 100%; }
}

/* ============================================================================
   v1.7 · badges, image picker, library
   ========================================================================== */

/* ── badges ───────────────────────────────────────────────────────────────
   Quiet by design. These are a private checklist, not trophies, so an earned
   one is legible and an unearned one is simply dimmer — never crossed out. */
.badge-intro { max-width: 42em; margin-bottom: 2rem; }
.badge-progress { display: flex; align-items: center; gap: 1rem; margin-top: 1rem; max-width: 22rem; }
.badge-count { /*font-family: var(--f-la-ui);*/ white-space: nowrap; }
.badge-count b { font-size: 1.3rem; }
.badge-progress .sell-track { flex: 1; }

.badge-group { margin-bottom: 2.4rem; }
.badge-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 0.9rem; }

.badge {
  position: relative; display: flex; gap: 0.8rem; align-items: flex-start;
  padding: 0.9rem 1rem; border: 1px solid var(--rule); border-radius: var(--radius);
}
.badge-mark {
  width: 2.4rem; height: 2.4rem; flex-shrink: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.1rem; background: var(--leaf-sunk); color: var(--ink-faint);
}
.badge.got .badge-mark { background: var(--brass); color: var(--leaf); }
.badge-text h3 {
  margin: 0 0 0.15rem; /*font-family: var(--f-la-ui);*/ font-size: 0.9rem; font-weight: 600;
}
.badge-text h3:lang(km) { font-family: var(--f-km-ui); line-height: 1.6; }
.badge-text .meta { margin: 0; font-size: 0.78rem; line-height: 1.5; }
.badge.locked { opacity: 0.62; }
.badge.locked .badge-text h3 { font-weight: 500; }
.badge.fresh { border-color: var(--brass); }
.badge-new {
  position: absolute; top: -0.55rem; inset-inline-end: 0.7rem;
  background: var(--brass); color: var(--leaf); /*font-family: var(--f-la-ui);*/
  font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 0.1rem 0.4rem; border-radius: 999px;
}
.tab-dot {
  display: inline-block; min-width: 1.05rem; margin-inline-start: 0.3rem;
  background: var(--brass); color: var(--leaf); border-radius: 999px;
  font-size: 0.68rem; text-align: center; padding: 0 0.25rem;
}

/* ── image picker ─────────────────────────────────────────────────────────── */
.sk-picker { width: min(46rem, 100%); max-height: 86vh; display: flex; flex-direction: column; }
.pick-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.pick-x {
  border: 0; background: none; cursor: pointer; color: var(--ink-faint);
  font-size: 1.4rem; line-height: 1; padding: 0;
}
.pick-x:hover { color: var(--ink); }

.pick-tabs { display: flex; gap: 0.15rem; border-bottom: 1px solid var(--rule); flex-wrap: wrap; }
.pick-tabs button {
  border: 0; background: none; cursor: pointer; padding: 0.5rem 0.75rem;
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; color: var(--ink-soft);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.pick-tabs button:hover { color: var(--ink); }
.pick-tabs button.on { color: var(--ink); border-bottom-color: var(--ink); }

.pick-bar:not(:empty) { padding-top: 0.2rem; }
.pick-search {
  width: 100%; padding: 0.5rem 0.7rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  /*font-family: var(--f-la-ui);*/ font-size: 0.88rem;
}
.pick-body { overflow-y: auto; flex: 1; min-height: 12rem; }
.pick-note { color: var(--ink-soft); /*font-family: var(--f-la-ui);*/ font-size: 0.87rem; padding: 1.5rem 0; }

.pick-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.35rem; padding: 2.8rem 1rem; cursor: pointer; text-align: center;
  border: 1px dashed var(--rule); border-radius: var(--radius);
  /*font-family: var(--f-la-ui);*/ margin-top: 0.8rem;
}
.pick-drop:hover { border-color: var(--ink-faint); background: var(--leaf-sunk); }
.pick-drop b { font-size: 0.95rem; }
.pick-drop span { font-size: 0.8rem; color: var(--ink-soft); }

.pick-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
  gap: 0.6rem; padding: 0.8rem 0;
}
.pick-cell { position: relative; }
.pick-img {
  display: block; width: 100%; padding: 0; border: 2px solid transparent;
  border-radius: var(--radius); overflow: hidden; cursor: pointer; background: var(--leaf-sunk);
}
.pick-img img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.pick-img:hover { border-color: var(--rubric); }
.pick-meta {
  display: block; /*font-family: var(--f-la-ui);*/ font-size: 0.68rem;
  color: var(--ink-faint); padding-top: 0.2rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pick-del {
  position: absolute; top: 0.3rem; inset-inline-end: 0.3rem;
  width: 1.5rem; height: 1.5rem; border-radius: 50%; border: 0; cursor: pointer;
  background: rgb(0 0 0 / 0.55); color: #fff; font-size: 1rem; line-height: 1;
  opacity: 0; transition: opacity 0.12s ease;
}
.pick-cell:hover .pick-del, .pick-del:focus-visible { opacity: 1; }
.pick-done { align-self: flex-end; margin-top: 0.6rem; }

/* ── admin library ────────────────────────────────────────────────────────── */
.lib-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); gap: 1rem; }
.lib-cell { margin: 0; }
.lib-cell img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius); display: block; background: var(--leaf-sunk);
}
.lib-cell figcaption { padding: 0.3rem 0; font-size: 0.72rem; }
.lib-cell .inline-form { flex-wrap: wrap; gap: 0.3rem; }
.lib-cell input[type="text"] {
  width: 100%; padding: 0.3rem 0.45rem; font-size: 0.78rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: transparent; color: var(--ink);
}

@media (max-width: 640px) {
  .badge-grid { grid-template-columns: 1fr; }
  .pick-grid { grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr)); }
  .pick-del { opacity: 1; }
}

/* ============================================================================
   v1.8 · edit history
   ========================================================================== */

.hist-live { margin-bottom: 1.4rem; }
.hist-table td { vertical-align: top; }
.hist-up   { color: var(--brass); }
.hist-down { color: var(--rubric); }

/* A save that removed most of an article is the row a writer is looking for,
   so it is marked rather than left to be found by reading numbers. */
.hist-drop { background: color-mix(in srgb, var(--rubric) 7%, transparent); }
.hist-drop td:first-child { box-shadow: inset 3px 0 0 var(--rubric); }

/* ============================================================================
   v1.9 · dictionary
   ========================================================================== */

.dict { max-width: 52em; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.dict-head { margin-bottom: 2rem; }
.dict-intro { color: var(--ink-soft); max-width: 38em; }
.dict-intro:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }

.dict-search { display: flex; gap: 0.5rem; margin: 1.2rem 0 0.6rem; max-width: 32em; }
.dict-search input {
  flex: 1; padding: 0.6rem 0.85rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  font-family: var(--f-km-body); font-size: 1rem; line-height: var(--lh-khmer);
}
.dict-search input:focus { outline: 2px solid var(--rubric); outline-offset: 1px; }

/* The consonant strip. Khmer script is dense, so the letters need room to
   breathe or they read as one continuous mark. */
.dict-alphabet {
  display: flex; flex-wrap: wrap; gap: 0.3rem;
  padding: 1rem 0; border-block: 1px solid var(--rule); margin-bottom: 1.5rem;
}
.dict-alphabet a {
  min-width: 2.1rem; text-align: center; padding: 0.3rem 0.4rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  text-decoration: none; font-family: var(--f-km-body); font-size: 1.05rem;
  line-height: 1.7; color: var(--ink);
}
.dict-alphabet a:hover { border-color: var(--ink-faint); }
.dict-alphabet a.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }
.dict-alphabet a.none { opacity: 0.3; pointer-events: none; }
.dict-alphabet a:first-child { /*font-family: var(--f-la-ui);*/ font-size: 0.82rem; min-width: auto; }

.dict-count { margin-bottom: 1rem; }
.dict-empty { max-width: 40em; }

.dict-list { display: grid; gap: 1.4rem; }
.dict-item { padding-bottom: 1.2rem; border-bottom: 1px solid var(--rule); }
.dict-word { margin: 0 0 0.2rem; font-size: 1.15rem; font-weight: 600; }
.dict-word a { text-decoration: none; font-family: var(--f-km-body); line-height: 1.6; }
.dict-word a:hover { color: var(--rubric); }
.dict-pos {
  /*font-family: var(--f-la-ui);*/ font-size: 0.7rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-faint); margin-inline-start: 0.5rem;
}
.dict-say { font-family: ui-monospace, Menlo, monospace; font-size: 0.82rem; color: var(--ink-faint); }
.dict-def { margin: 0.3rem 0 0; color: var(--ink-soft); }
.dict-def:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.dict-used { margin: 0.3rem 0 0; font-size: 0.78rem; }

/* single entry */
.dict-single { max-width: 42em; margin-inline: auto; padding: 2rem 1.5rem 5rem; }
.dict-headword {
  font-family: var(--f-km-body); font-size: 2.1rem; font-weight: 700;
  line-height: 1.5; margin: 0.4rem 0 0.2rem;
}
.dict-meta { display: flex; gap: 0.8rem; align-items: baseline; margin: 0 0 1.8rem; }
.dict-block { margin-bottom: 1.8rem; }
.dict-body { color: var(--ink); }
.dict-body:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.dict-notes { color: var(--ink-soft); font-size: 0.9rem; }
.dict-example {
  border-inline-start: 2px solid var(--rubric); padding: 0.2rem 0 0.2rem 1rem;
  margin: 0 0 1rem; font-family: var(--f-km-body); line-height: var(--lh-khmer);
}
.dict-example cite { display: block; font-style: normal; font-size: 0.8rem; margin-top: 0.35rem; }
.dict-example cite a { color: var(--ink-faint); text-decoration: none; }
.dict-example cite a:hover { color: var(--rubric); }
.dict-related { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.dict-related a {
  border: 1px solid var(--rule); border-radius: 999px; padding: 0.2rem 0.7rem;
  text-decoration: none; font-family: var(--f-km-body); font-size: 0.95rem; line-height: 1.8;
}
.dict-related a:hover { border-color: var(--ink-faint); }
.dict-foot { padding-top: 1rem; border-top: 1px solid var(--rule); }
.dict-gap-word { font-family: var(--f-km-body); font-size: 1.05rem; line-height: 1.7; }

@media (max-width: 640px) {
  .dict, .dict-single { padding-inline: 1.1rem; }
  .dict-headword { font-size: 1.6rem; }
  .dict-alphabet a { min-width: 1.9rem; font-size: 1rem; }
}

/* ── dictionary visibility ────────────────────────────────────────────────
   The state is carried by a colour as well as by words, because "is this
   live?" is the question an admin asks fastest and reads slowest. */
.dict-visibility { border-inline-start: 3px solid var(--rule); padding-inline-start: 1rem; }
.dict-visibility.is-hidden { border-inline-start-color: var(--brass); }
.dict-visibility.is-live { border-inline-start-color: var(--rubric); }
.dict-vis-now { margin: 0 0 0.8rem; }
.dict-vis-form select { min-width: 18rem; }

/* ── dictionary: sound and sense ─────────────────────────────────────────── */
.dict-sound { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: baseline; margin: 0.15rem 0 0.4rem; }
.dict-roman {
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; color: var(--ink-soft);
  letter-spacing: 0.01em;
}
/* A transliteration nobody has checked is shown quieter and carries a mark,
   so it is never mistaken for the verified kind. */
.dict-roman.is-approx { color: var(--ink-faint); }
.dict-approx { font-size: 0.75em; opacity: 0.7; margin-inline-start: 0.15rem; cursor: help; }
.dict-approx-note { padding-top: 0.6rem; }
.dict-sense {
  font-family: var(--f-km-ui); font-size: 0.72rem; color: var(--ink-faint);
  border: 1px solid var(--rule); border-radius: 3px; padding: 0 0.3rem;
}
.dict-stats { border-inline-start: 3px solid var(--rule); padding-inline-start: 1rem; }

/* ============================================================================
   v2.2 · dictionary reference sections, suggestions, contributor credit
   ========================================================================== */

.dict-panel { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--rule); }
.dict-panel-title {
  /*font-family: var(--f-la-ui);*/ font-size: 1rem; font-weight: 600; margin: 0 0 0.6rem;
}
.dict-panel-title:lang(km) { font-family: var(--f-km-ui); line-height: 1.6; }
.dict-sub {
  /*font-family: var(--f-la-ui);*/ font-size: 0.78rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-faint); margin: 1.8rem 0 0.6rem; font-weight: 600;
}
.dict-sub:lang(km) { font-family: var(--f-km-ui); letter-spacing: 0; text-transform: none; font-size: 0.92rem; }
.dict-welcome { max-width: 40em; margin-bottom: 1.2rem; color: var(--ink-soft); }
.dict-welcome:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.dict-summary { margin-top: 0.5rem; }

/* ── the alphabet ─────────────────────────────────────────────────────────
   Khmer letters need room: at small sizes the subscripts and vowel marks
   collide with their neighbours and the table becomes a smudge. */
.letter-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(4.2rem, 1fr));
  gap: 0.4rem; margin-bottom: 0.6rem;
}
.letter {
  display: flex; flex-direction: column; align-items: center; gap: 0.1rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0.5rem 0.3rem; text-decoration: none; color: var(--ink);
}
a.letter:hover { border-color: var(--ink-faint); background: var(--leaf-sunk); }
.letter b { font-family: var(--f-km-body); font-size: 1.35rem; line-height: 1.8; font-weight: 400; }
.letter span { /*font-family: var(--f-la-ui);*/ font-size: 0.7rem; color: var(--ink-faint); }
/* The two consonant series carry a colour, because which series a letter
   belongs to is the thing a learner most needs and least sees. */
.letter.series-a { border-block-end: 2px solid var(--brass); }
.letter.series-o { border-block-end: 2px solid var(--rubric); }
.letter-key { display: flex; align-items: center; gap: 0.3rem; margin-bottom: 1rem; }
.swatch { display: inline-block; width: 0.8rem; height: 0.2rem; border-radius: 2px; }
.swatch.series-a { background: var(--brass); }
.swatch.series-o { background: var(--rubric); }

.mark-list { display: grid; gap: 0.25rem; }
.mark {
  display: grid; grid-template-columns: 3rem 9rem minmax(0, 1fr);
  gap: 0.6rem; align-items: baseline; padding: 0.3rem 0; border-bottom: 1px solid var(--rule);
}
.mark b { font-family: var(--f-km-body); font-size: 1.2rem; line-height: 1.8; }
.mark-name { font-family: ui-monospace, Menlo, monospace; font-size: 0.75rem; color: var(--ink-faint); }
.mark-what { /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; color: var(--ink-soft); }
.mark-what:lang(km) { font-family: var(--f-km-ui); line-height: var(--lh-khmer); }

/* ── abbreviations ────────────────────────────────────────────────────────── */
.abbr-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: 0.4rem; }
.abbr {
  display: grid; grid-template-columns: 3.4rem minmax(0, 1fr);
  gap: 0.2rem 0.5rem; padding: 0.4rem 0; border-bottom: 1px solid var(--rule);
}
.abbr b { font-family: var(--f-km-body); font-size: 0.95rem; line-height: 1.7; }
.abbr span { font-family: var(--f-km-body); font-size: 0.9rem; line-height: 1.7; }
.abbr i {
  grid-column: 2; font-style: normal; /*font-family: var(--f-la-ui);*/
  font-size: 0.75rem; color: var(--ink-faint);
}

/* ── contributors ─────────────────────────────────────────────────────────── */
.contrib-list { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: 0.3rem; }
.contrib { display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0; }
.contrib-name { /*font-family: var(--f-la-ui);*/ font-size: 0.88rem; text-decoration: none; }
.contrib-name:hover { color: var(--rubric); }
.contrib-guest {
  width: 32px; height: 32px; border-radius: 50%; background: var(--leaf-sunk);
  color: var(--ink-faint); display: inline-flex; align-items: center; justify-content: center;
}
.contrib .meta { margin-inline-start: auto; }

.source-list { margin: 0; }
.source-list dt { /*font-family: var(--f-la-ui);*/ font-weight: 600; font-size: 0.9rem; margin-top: 0.8rem; }
.source-list dt:lang(km) { font-family: var(--f-km-body); line-height: 1.7; }
.source-list dd { margin: 0.2rem 0 0; color: var(--ink-soft); font-size: 0.88rem; }
.source-list dd:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }

/* ── suggesting ───────────────────────────────────────────────────────────── */
.suggest-lead { max-width: 36em; margin-bottom: 1.4rem; }
.suggest-form .field { margin-bottom: 1.1rem; }
/* What the dictionary says now, under the box that would replace it — so a
   correction is written against the thing being corrected, not from memory. */
.suggest-now {
  display: block; margin-top: 0.3rem; padding: 0.35rem 0.55rem;
  background: var(--leaf-sunk); border-radius: var(--radius); line-height: 1.6;
}
.suggest-guest { border-block: 1px solid var(--rule); padding-block: 1rem; margin-bottom: 1rem; }
.req { color: var(--rubric); }
.dict-headword-inline { font-family: var(--f-km-body); font-size: 1.5rem; line-height: 1.6; margin: 0 0 1rem; }
.dict-suggest-link { padding-top: 1rem; }
.dict-credit { padding-top: 0.6rem; }

/* ── the review queue ─────────────────────────────────────────────────────── */
.sug { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1rem; margin-bottom: 1rem; }
.sug-head { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: baseline; margin-bottom: 0.7rem; }
.sug-head h3 { margin: 0; font-family: var(--f-km-body); font-size: 1.15rem; line-height: 1.6; }
.sug-diff { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.sug-diff th {
  text-align: start; width: 8rem; padding: 0.35rem 0.5rem 0.35rem 0; vertical-align: top;
  /*font-family: var(--f-la-ui);*/ font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--ink-faint); font-weight: 600;
}
.sug-diff td { padding: 0.35rem 0.5rem; vertical-align: top; border-bottom: 1px solid var(--rule); }
.sug-now { color: var(--ink-faint); width: 40%; }
.sug-new { background: color-mix(in srgb, var(--brass) 10%, transparent); }
.sug-note { margin: 0.7rem 0 0; font-family: var(--f-km-body); line-height: var(--lh-khmer); color: var(--ink-soft); }
.sug-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.8rem; align-items: center; }
.sug-actions input[type="text"] {
  flex: 1; min-width: 12rem; padding: 0.4rem 0.55rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  /*font-family: var(--f-la-ui);*/ font-size: 0.82rem;
}

/* ── honour on a profile ──────────────────────────────────────────────────── */
.honour {
  display: inline-flex; align-items: center; gap: 0.4rem; margin: 0.6rem 0 0;
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem;
}
.honour-mark { color: var(--brass); }
.honour a { text-decoration: none; }
.honour a:hover { color: var(--rubric); }

@media (max-width: 640px) {
  .letter-grid { grid-template-columns: repeat(auto-fill, minmax(3.6rem, 1fr)); }
  .mark { grid-template-columns: 2.4rem minmax(0, 1fr); }
  .mark-what { grid-column: 1 / -1; }
  .sug-diff, .sug-diff tbody, .sug-diff tr, .sug-diff td, .sug-diff th { display: block; width: auto; }
  .sug-now { padding-bottom: 0; }
}

/* ── live dictionary search ───────────────────────────────────────────────
   The panel hangs under the box, so the form needs to be the containing
   block or it would position against the page. */
.dict-search { position: relative; }

.live-results {
  position: absolute; inset-inline: 0; top: calc(100% + 0.35rem); z-index: 40;
  background: var(--leaf); border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 8px 28px rgb(0 0 0 / 0.12);
  max-height: min(60vh, 26rem); overflow-y: auto; overscroll-behavior: contain;
}
.live-row {
  display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: 0.15rem 0.5rem; align-items: baseline;
  padding: 0.5rem 0.75rem; text-decoration: none; color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
.live-row:last-of-type { border-bottom: 0; }
/* Hover and keyboard selection look identical on purpose: a person moving
   between mouse and arrow keys should not have to relearn where they are. */
.live-row:hover, .live-row.on { background: var(--leaf-sunk); }
.live-word { font-family: var(--f-km-body); font-size: 1.05rem; line-height: 1.7; }
.live-roman { /*font-family: var(--f-la-ui);*/ font-size: 0.75rem; color: var(--ink-soft); }
.live-roman.is-approx { color: var(--ink-faint); }
.live-pos {
  font-family: var(--f-km-ui); font-size: 0.68rem; color: var(--ink-faint);
  border: 1px solid var(--rule); border-radius: 3px; padding: 0 0.25rem;
}
.live-gloss {
  grid-column: 1 / -1; font-family: var(--f-km-body); font-size: 0.82rem;
  line-height: 1.6; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.live-all {
  display: block; padding: 0.5rem 0.75rem; text-align: center;
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; text-decoration: none;
  color: var(--ink-soft); background: var(--leaf-sunk);
  border-top: 1px solid var(--rule); position: sticky; bottom: 0;
}
.live-all:hover { color: var(--rubric); }
.live-empty {
  margin: 0; padding: 0.9rem 0.75rem; text-align: center;
  /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; color: var(--ink-faint);
}
@media (max-width: 640px) {
  .live-results { max-height: 50vh; }
  .live-gloss { display: none; }
}

/* ============================================================================
   v2.3 · magazines
   ========================================================================== */

.mag { max-width: 46rem; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.mag-head { margin-bottom: 1.6rem; }
.mag-cover {
  aspect-ratio: 16 / 6; border-radius: var(--radius); overflow: hidden;
  background: var(--leaf-sunk); margin-bottom: 1.2rem;
}
.mag-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mag-desc { color: var(--ink-soft); max-width: 34em; }
.mag-desc:lang(km) { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
/* The keeper is named on its own line: on a magazine holding other people's
   work, "who chose these" and "who wrote this" are different questions and a
   reader should not have to guess which name answers which. */
.mag-by { display: flex; align-items: center; gap: 0.5rem; margin: 0.9rem 0 0.4rem; font-size: 0.9rem; }
.mag-stats { margin: 0 0 1rem; }
.mag-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.mag-about {
  color: var(--ink-soft); max-width: 36em; margin-bottom: 1.5rem;
  font-family: var(--f-km-body); line-height: var(--lh-khmer);
}

.mag-list { display: grid; gap: 1.4rem; }
.mag-item {
  position: relative; display: grid; gap: 0 1rem;
  grid-template-columns: minmax(0, 1fr) 8rem; align-items: start;
  padding-bottom: 1.3rem; border-bottom: 1px solid var(--rule);
}
.mag-item-cover { grid-column: 2; grid-row: 1; border-radius: var(--radius); overflow: hidden; }
.mag-item-cover img { width: 100%; aspect-ratio: 4 / 3; height: 100%; object-fit: cover; display: block; }
.mag-item-body { grid-column: 1; grid-row: 1; min-width: 0; }
.mag-item-title { margin: 0 0 0.3rem; font-size: 1.05rem; font-weight: 600; }
.mag-item-title a { text-decoration: none; font-family: var(--f-km-body); line-height: 1.6; }
.mag-item-title a:hover { color: var(--rubric); }
.mag-item-excerpt {
  margin: 0 0 0.35rem; color: var(--ink-soft); font-size: 0.88rem;
  font-family: var(--f-km-body); line-height: var(--lh-khmer);
}
.mag-item-by { margin: 0; }
.mag-item-note {
  margin: 0.4rem 0 0; padding-inline-start: 0.7rem; border-inline-start: 2px solid var(--brass);
  font-size: 0.85rem; color: var(--ink-soft); font-family: var(--f-km-body); line-height: var(--lh-khmer);
}
.mag-remove {
  position: absolute; top: 0; inset-inline-end: 0; border: 0; background: none;
  color: var(--ink-faint); cursor: pointer; font-size: 1.1rem; line-height: 1;
  padding: 0.2rem 0.4rem; opacity: 0; transition: opacity 0.12s ease;
}
.mag-item:hover .mag-remove, .mag-remove:focus-visible { opacity: 1; }
.mag-remove:hover { color: var(--rubric); }

/* ── listings ─────────────────────────────────────────────────────────────── */
.mag-section { margin-bottom: 2.5rem; }
.mag-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1rem; }
.mag-card {
  display: flex; gap: 0.8rem; text-decoration: none; color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.7rem; align-items: flex-start;
}
.mag-card:hover { border-color: var(--ink-faint); background: var(--leaf-sunk); }
.mag-card-cover {
  flex-shrink: 0; width: 4rem; height: 4rem; border-radius: var(--radius);
  overflow: hidden; background: var(--leaf-sunk);
}
.mag-card-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mag-card-cover.is-blank {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--f-km-body); font-size: 1.6rem; color: var(--ink-faint);
}
.mag-card-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.mag-card-body b { font-family: var(--f-km-body); font-size: 0.95rem; line-height: 1.6; }
.mag-card-desc {
  font-family: var(--f-km-body); font-size: 0.8rem; color: var(--ink-soft); line-height: 1.6;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── on an article ────────────────────────────────────────────────────────── */
.post-mags { padding-block: 1.2rem; }
.mag-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0; }
.mag-chip {
  display: flex; flex-direction: column; gap: 0.05rem; text-decoration: none; color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.35rem 0.7rem;
}
.mag-chip:hover { border-color: var(--ink-faint); }
.mag-chip b { font-family: var(--f-km-body); font-size: 0.9rem; line-height: 1.5; font-weight: 600; }

/* ── the chooser ──────────────────────────────────────────────────────────── */
.sk-magpick { width: min(24rem, 100%); }
.magpick-list { max-height: 18rem; overflow-y: auto; margin-block: 0.6rem; }
.magpick-row {
  display: flex; align-items: center; gap: 0.6rem; width: 100%; text-align: start;
  padding: 0.5rem 0.6rem; border: 0; border-bottom: 1px solid var(--rule);
  background: none; cursor: pointer; color: var(--ink); font: inherit;
}
.magpick-row:hover { background: var(--leaf-sunk); }
.magpick-name { flex: 1; font-family: var(--f-km-body); font-size: 0.95rem; line-height: 1.6; }
.magpick-row .meta { font-size: 0.75rem; }
.magpick-tick { width: 1.2rem; text-align: center; color: var(--ink-faint); }
.magpick-row.on .magpick-tick { color: var(--brass); }
.magpick-row.on .magpick-name { font-weight: 600; }
.magpick-new { display: flex; gap: 0.4rem; padding-top: 0.6rem; border-top: 1px solid var(--rule); }
.magpick-new input {
  flex: 1; padding: 0.45rem 0.6rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: transparent; color: var(--ink); font-family: var(--f-km-body); font-size: 0.9rem;
}
.magpick-close { margin-top: 0.6rem; width: 100%; }
.mag-new { max-width: 30rem; margin-bottom: 1.5rem; }

@media (max-width: 640px) {
  .mag { padding-inline: 1.1rem; }
  .mag-item { grid-template-columns: minmax(0, 1fr) 5.5rem; }
  .mag-remove { opacity: 1; }
  .mag-grid { grid-template-columns: 1fr; }
}

/* ============================================================================
   v2.4 · badge editing, fault reports
   ========================================================================== */

.badge-edit { border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.8rem; margin-bottom: 0.7rem; }
.badge-edit.is-off { opacity: 0.55; }
.badge-edit-head { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; justify-content: space-between; }
.badge-edit-head .badge-mark { width: 1.8rem; height: 1.8rem; font-size: 0.9rem; }
.badge-edit-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.5rem; margin-top: 0.7rem;
}
.badge-edit-grid label { display: flex; flex-direction: column; gap: 0.15rem; }
.badge-edit-grid label span { font-size: 0.72rem; color: var(--ink-faint); /*font-family: var(--f-la-ui);*/ }
.badge-edit-grid input {
  padding: 0.35rem 0.5rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: transparent; color: var(--ink); font-size: 0.85rem;
}
.badge-edit-grid .narrow { max-width: 9rem; }
/* The save bar follows you down a long list, because a page of thirty badges
   is otherwise a scroll to the bottom after every single edit. */
.settings-sticky {
  position: sticky; bottom: 0; background: var(--leaf);
  border-top: 1px solid var(--rule); padding: 0.8rem 0; z-index: 5;
}

.bug-one { max-width: 44rem; }
.bug-copy {
  width: 100%; font-family: ui-monospace, Menlo, monospace; font-size: 0.78rem;
  line-height: 1.55; padding: 0.7rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf-sunk); color: var(--ink);
}
/* A fault seen many times is the one to look at first. */
.bug-hot td:first-child { box-shadow: inset 3px 0 0 var(--rubric); }

.sk-bugform { width: min(30rem, 100%); }
.bug-actions { display: flex; gap: 0.5rem; margin-top: 0.8rem; }

/* ── magazine cover, and picking magazines while publishing ───────────────── */
.mag-cover-pick { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.mag-cover-pick img {
  width: 12rem; aspect-ratio: 16 / 6; object-fit: cover;
  border-radius: var(--radius); background: var(--leaf-sunk);
}
.pub-mags { display: grid; gap: 0.2rem; max-height: 11rem; overflow-y: auto; }

/* ============================================================================
   v2.5 · drawn covers
   ----------------------------------------------------------------------------
   Four patterns, no image files. Each is built from repeating gradients, which
   means they cost nothing to serve, stay sharp at any size, and follow the
   palette rather than being baked at one colour.
   ========================================================================== */

.gcover {
  position: relative; display: flex; align-items: flex-end;
  width: 100%; overflow: hidden; border-radius: var(--radius);
  background-color: var(--gc-base);
  /* Every pattern is drawn in this one colour at low opacity, so a single
     palette entry controls both the wash and the marks on it. */
  --gc-base: #E8DFC8;
  --gc-mark: #00000018;
  --gc-deep: #00000010;
  --gc-ink:  #2A241A;
}

/* ── shapes ───────────────────────────────────────────────────────────────── */
.gcover-card  { aspect-ratio: 16 / 10; }
.gcover-lead  { aspect-ratio: 16 / 9; }
.gcover-wide  { aspect-ratio: 16 / 6; }
.gcover-thumb { aspect-ratio: 4 / 3; }

/* ── palm leaf ────────────────────────────────────────────────────────────
   A palm-leaf manuscript is read as fine horizontal fibres running the length
   of the leaf, with the two ruled lines the scribe wrote between. */


/* ── krama ────────────────────────────────────────────────────────────────
   The check is two sets of bands crossing. Where they overlap the colour
   doubles, which is exactly how the woven cloth behaves — so the pattern
   needs no third layer to look right. */
.gc-krama {
  background-image:
    repeating-linear-gradient(
      to right,
      var(--gc-mark) 0, var(--gc-mark) 16px,
      transparent 16px, transparent 32px),
    repeating-linear-gradient(
      to bottom,
      var(--gc-mark) 0, var(--gc-mark) 16px,
      transparent 16px, transparent 32px),
    repeating-linear-gradient(
      to right,
      var(--gc-deep) 0, var(--gc-deep) 2px,
      transparent 2px, transparent 8px);
}

/* ── ruled paper ──────────────────────────────────────────────────────────── */
.gc-stripe {
  background-image:
    repeating-linear-gradient(
      to bottom,
      transparent 0, transparent 21px,
      var(--gc-mark) 21px, var(--gc-mark) 22px);
}

/* ── plain ────────────────────────────────────────────────────────────────
   Not flat: a very soft wash, so it reads as paper rather than as a colour
   swatch that failed to load. */
.gc-plain {
  background-image:
    radial-gradient(120% 90% at 20% 0%, #ffffff20, transparent 60%),
    linear-gradient(to bottom, transparent 60%, #0000000f);
}

/* ── palette ──────────────────────────────────────────────────────────────
   All light: the title sits on top in near-black and has to stay readable,
   which is the only real constraint on the colours. */
.gc-tint-sand    { --gc-base: #E8DFC8; }
.gc-tint-palm    { --gc-base: #D8DFC6; }
.gc-tint-indigo  { --gc-base: #CBD3E0; }
.gc-tint-rubric  { --gc-base: #E5CBC5; }
.gc-tint-saffron { --gc-base: #EDD9B0; }
.gc-tint-slate   { --gc-base: #D5D6D2; }
.gc-tint-rose    { --gc-base: #E8D2D6; }

/* ── the words ────────────────────────────────────────────────────────────
   Real text, not part of the pattern. The browser shapes the Khmer properly,
   a screen reader can read it, and it reflows at every size instead of being
   frozen into a bitmap.

   Centred rather than sitting on the base line: a cover is a title card, and
   a headline pinned to the bottom edge reads as a caption on a photograph
   that failed to load. */
.gcover { align-items: center; justify-content: center; }

.gcover-text {
  position: relative; z-index: 1; width: 100%;
  padding: 1rem 1.2rem; margin: 0; text-align: center;
  font-family: var(--f-km-body); line-height: 1.75;
  color: var(--gc-ink); font-weight: 600;
  /* A soft wash behind the words so a busy pattern underneath — the krama
     check especially — cannot eat the descenders. */
  background: linear-gradient(to bottom, transparent, #ffffffb0 18%, #ffffffb0 82%, transparent);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.gcover-card  .gcover-text { font-size: 0.95rem; }
.gcover-lead  .gcover-text { font-size: 1.3rem; -webkit-line-clamp: 3; }
.gcover-wide  .gcover-text { font-size: 1.2rem; -webkit-line-clamp: 2; }

/* ── a single letter, for covers too small for a headline ─────────────────
   One large Khmer character is legible at a size where a shrunken sentence
   is not, so a square cover shows the opening cluster of the title. */
.gcover.is-initial { align-items: center; justify-content: center; }
.gcover-initial {
  position: relative; z-index: 1;
  font-family: var(--f-km-body); font-weight: 400; line-height: 1.4;
  color: var(--gc-ink); opacity: 0.75;
  font-size: clamp(1.6rem, 42%, 3.4rem);
}
.gcover-thumb  .gcover-initial { font-size: clamp(1.4rem, 38%, 2.6rem); }
.gcover-square { aspect-ratio: 1 / 1; }

/* Dark mode keeps the covers light. They are paper; paper does not invert. */
@media (prefers-color-scheme: dark) {
  .gcover-text { color: #241F17; }
}

/* ── choosing one, in the composer ────────────────────────────────────────── */
.cover-choice { display: grid; gap: 0.9rem; margin-top: 0.8rem; }
.cover-styles, .cover-tints { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.cover-style-btn {
  border: 2px solid var(--rule); border-radius: var(--radius); padding: 0;
  background: none; cursor: pointer; width: 6.5rem; overflow: hidden;
}
.cover-style-btn.on { border-color: var(--ink); }
.cover-style-btn .gcover { border-radius: 0; }
.cover-style-btn b {
  display: block; padding: 0.25rem; font-family: var(--f-km-ui);
  font-size: 0.72rem; font-weight: 500; color: var(--ink-soft);
}
.cover-tint-btn {
  width: 2rem; height: 2rem; border-radius: 50%; cursor: pointer;
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px #00000018;
}
.cover-tint-btn.on { border-color: var(--ink); }
.cover-preview { max-width: 22rem; }

/* A drawn cover fills its slot exactly as a photograph would, so nothing
   downstream needs to know which kind it is. */
.card-cover.is-drawn .gcover,
.article-cover.is-drawn .gcover,
.mag-cover.is-drawn .gcover { height: 100%; border-radius: inherit; }
.article-cover.is-drawn, .mag-cover.is-drawn { overflow: hidden; border-radius: var(--radius); }
.mag-card-cover .gcover { height: 100%; aspect-ratio: auto; }
.cover-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.8rem; }
.cover-gallery-item { display: block; text-decoration: none; }

/* ── four more patterns, drawn from Khmer ornament ────────────────────────
   All still pure gradients: no image files, and every one takes its colour
   from the same palette entry as the rest. */

/* ── Angkor ───────────────────────────────────────────────────────────────
   A temple tower read as a stepped silhouette narrowing as it rises. Two
   opposed diagonals make the taper; the horizontal banding makes the tiers. */


/* ── kbach ────────────────────────────────────────────────────────────────
   Khmer ornament is built on a repeating floral unit set in a lattice. Two
   offset grids of soft rosettes give the repeat; the fine diagonals give the
   lattice holding them. */


/* ── lotus ────────────────────────────────────────────────────────────────
   Petals as overlapping circles, offset row by row so the arcs interlock the
   way real petals do rather than sitting in a plain grid. */


/* ── lozenge lattice ──────────────────────────────────────────────────────
   The diamond banding along a carved border: the krama idea turned forty-five
   degrees, which is a different thing to the eye even though the maths is the
   same. */


.mail-state { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.mail-state li { font-size: 0.9rem; }
.mail-detail { font-family: ui-monospace, Menlo, monospace; font-size: 0.72rem; }

/* ── the drawn patterns ───────────────────────────────────────────────────
   Six of the nine are SVG rather than gradients, because gradients cannot
   make a curve that turns back on itself and Khmer ornament is almost nothing
   but curves that turn back on themselves.

   The artwork uses currentColor throughout, and the colour is set here from
   the tint — so one palette choice still drives the whole cover, and the
   shapes need no colours baked into them. */
.gcover-art {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* Solid colour, with the fading done by opacity on the whole drawing.
     A semi-transparent fill would compound wherever two shapes overlap — a
     tower crossing the gallery roof came out visibly darker than either — and
     an outline built from several paths would show its own seams. */
  color: var(--gc-ink);
  opacity: var(--gc-art-o, 0.13);
  pointer-events: none;
}

/* The temple silhouettes sit heavier than the repeating ornament: one shape
   at the foot of the cover can carry more weight than a pattern filling the
   whole of it, which at the same strength would shout. */
.gc-angkor      { --gc-art-o: 0.20; }
.gc-preahvihear { --gc-art-o: 0.20; }
.gc-kbach       { --gc-art-o: 0.15; }
.gc-dakchan     { --gc-art-o: 0.13; }
.gc-lotus       { --gc-art-o: 0.13; }
.gc-sleukrith   { --gc-art-o: 0.22; }

/* The palm leaf is the site's own name, so it gets a warmer ground than the
   flat tint — dried leaf rather than paper. */
.gc-sleukrith {
  background-image: linear-gradient(to bottom, #ffffff1a, transparent 45%, #00000014);
}

/* Ornament reads better a little denser on a large cover and a little lighter
   on a small one, where the repeat is tighter and can turn to noise. */
/* Ornament reads better a little denser on a large cover and lighter on a
   small one, where the repeat tightens and can turn to noise. */
.gcover-thumb .gcover-art, .gcover-square .gcover-art { opacity: calc(var(--gc-art-o, 0.13) * 0.8); }

@media (prefers-reduced-motion: no-preference) {
  /* Nothing animates; the query is here only to make that explicit for
     anyone reading the file later and wondering. */
}

/* ── patterns you upload ──────────────────────────────────────────────────
   An uploaded pattern carries its own background inline, since its key can
   contain a colon and cannot become a class name. */
.gc-custom { background-image: none; }
.gcover-custom-svg { position: absolute; inset: 0; color: var(--gc-ink); }
.gcover-custom-svg svg { width: 100%; height: 100%; display: block; }

.pattern-item { display: flex; flex-direction: column; gap: 0.2rem; }
.pattern-item.is-off { opacity: 0.5; }
.pattern-item b { font-size: 0.88rem; }
.pattern-acts { display: flex; gap: 0.5rem; align-items: center; }
.pattern-form { max-width: 34rem; margin-top: 1.4rem; }
.pattern-pick { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.pattern-pick img {
  width: 5rem; height: 5rem; object-fit: contain; background: var(--leaf-sunk);
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.2rem;
}
.field.narrow { max-width: 16rem; }

/* ── the writer's page ────────────────────────────────────────────────────── */
/* Spaced and underlined so they read as tabs. Sitting flush against each
   other with only a margin below, they looked like a run of links. */
.profile-tabs {
  display: flex;
  gap: 1.3rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 1.4rem;
}
.pinned { margin-bottom: 0.5rem; }
.pin-mark { color: var(--brass); font-size: 0.7em; margin-inline-end: 0.2rem; }

/* The sub-tabs are quieter than the tabs above them: they change how one
   list is ordered, not which list you are looking at. */
.subtabs { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 1.2rem; }
.subtab {
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; text-decoration: none;
  color: var(--ink-soft); padding: 0.25rem 0.7rem;
  border: 1px solid var(--rule); border-radius: 999px;
}
.subtab:lang(km) { font-family: var(--f-km-ui); }
.subtab:hover { border-color: var(--ink-faint); color: var(--ink); }
.subtab.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }

/* Controls only the writer sees, kept faint so their own page still reads as
   a page rather than as an editing screen. */
.own-post-acts { margin: -0.6rem 0 1rem; opacity: 0.55; }
.own-post-acts:hover, .own-post-acts:focus-within { opacity: 1; }

/* ── the dictionary inside the composer ───────────────────────────────────── */
.dictpanel-search { display: flex; gap: 0.3rem; margin-bottom: 0.7rem; }
.dictpanel-search input {
  flex: 1; min-width: 0; padding: 0.4rem 0.6rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  font-family: var(--f-km-body); font-size: 0.9rem; line-height: var(--lh-khmer);
}
.dictpanel-results { display: grid; gap: 0.6rem; max-height: 22rem; overflow-y: auto; }
.dictpanel-row { border-bottom: 1px solid var(--rule); padding-bottom: 0.5rem; }
.dictpanel-row h3 {
  margin: 0; font-family: var(--f-km-body); font-size: 1rem; line-height: 1.6; font-weight: 600;
  display: inline; margin-inline-end: 0.4rem;
}
.dictpanel-roman { /*font-family: var(--f-la-ui);*/ font-size: 0.72rem; color: var(--ink-soft); }
.dictpanel-roman.is-approx { color: var(--ink-faint); }
.dictpanel-pos {
  font-family: var(--f-km-ui); font-size: 0.65rem; color: var(--ink-faint);
  border: 1px solid var(--rule); border-radius: 3px; padding: 0 0.25rem; margin-inline-start: 0.3rem;
}
.dictpanel-row p {
  margin: 0.25rem 0 0; font-family: var(--f-km-body); font-size: 0.82rem;
  line-height: var(--lh-khmer); color: var(--ink-soft);
}

/* ============================================================================
   v3.0 · កាសែត — audio posts
   ========================================================================== */

.audio-page { max-width: 44rem; margin-inline: auto; }
.audio-form { padding: 1.5rem 1.5rem 4rem; display: grid; gap: 1.1rem; }
.audio-form .field { margin: 0; }

/* The recording sits first and largest, because without it there is no post. */
.audio-drop { border: 1px dashed var(--rule); border-radius: var(--radius); padding: 1rem; }
.audio-choose {
  display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
  width: 100%; padding: 2rem 1rem; border: 0; background: none; cursor: pointer;
  color: var(--ink); /*font-family: var(--f-la-ui);*/
}
.audio-choose:hover { background: var(--leaf-sunk); border-radius: var(--radius); }
.audio-choose svg { width: 2rem; height: 2rem; color: var(--ink-faint); }
.audio-have audio, .audio-player audio { width: 100%; }
.audio-progress { text-align: center; }

.audio-player { margin: 0 0 1.5rem; }
.audio-player figcaption { padding-top: 0.4rem; }

/* A recording is chosen by its title and its length, and a wall of covers
   hides both — so this is a list, not a grid. */
.audio-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.2rem; }
.audio-row {
  display: flex; gap: 0.8rem; align-items: center;
  padding: 0.7rem 0.4rem; border-bottom: 1px solid var(--rule);
}
.audio-row-play {
  flex-shrink: 0; width: 2.4rem; height: 2.4rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--leaf-sunk); color: var(--ink); text-decoration: none; font-size: 0.8rem;
}
.audio-row-play:hover { background: var(--ink); color: var(--leaf); }
.audio-row-body { min-width: 0; }
.audio-row-title {
  font-family: var(--f-km-body); font-size: 1rem; line-height: 1.6;
  text-decoration: none; font-weight: 600;
}
.audio-row-title:hover { color: var(--rubric); }
.audio-row p { margin: 0.1rem 0 0; }

.stat-row-audio { border-top: 1px solid var(--rule); margin-top: -0.4rem; padding-top: 0.7rem; }
.kind-mark { color: var(--ink-faint); }

/* ── filtering the dashboard list ─────────────────────────────────────────── */
.post-filter {
  display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: center;
  margin-bottom: 1rem; padding-bottom: 0.8rem; border-bottom: 1px solid var(--rule);
}
.filter-group { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.chip {
  /*font-family: var(--f-la-ui);*/ font-size: 0.78rem; text-decoration: none;
  color: var(--ink-soft); padding: 0.2rem 0.65rem;
  border: 1px solid var(--rule); border-radius: 999px;
}
.chip:lang(km) { font-family: var(--f-km-ui); }
.chip:hover { border-color: var(--ink-faint); color: var(--ink); }
.chip.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }
.post-filter select, .post-filter input[type="search"] {
  padding: 0.3rem 0.5rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: transparent; color: var(--ink); font-size: 0.82rem;
}
.topic-pick { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.2rem; }

/* ── the publish menu ─────────────────────────────────────────────────────
   This had no styling at all, which is why it came out as a white box with
   unreadable text in dark mode: an unstyled div inherits nothing, so none of
   the theme reached it. It now uses the same surface variables as every other
   popover on the site, which means it follows all three presets and both
   themes without needing its own dark rules. */
.publish-pick { position: relative; margin-inline-start: auto; }
.publish-menu {
  position: absolute; inset-inline-end: 0; top: calc(100% + 0.4rem); z-index: 60;
  min-width: 11rem; padding: 0.3rem;
  background: var(--leaf); color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 12px 30px rgb(0 0 0 / 0.28);
}
.publish-menu a {
  display: block; padding: 0.55rem 0.7rem; border-radius: var(--radius);
  text-decoration: none; color: var(--ink); font-size: 0.9rem;
  /*font-family: var(--f-la-ui);*/
}
.publish-menu a:lang(km) { font-family: var(--f-km-ui); }
.publish-menu a:hover, .publish-menu a:focus-visible { background: var(--leaf-sunk); }

.filter-make { margin-inline-start: auto; }

/* A native <select> draws its own dropdown using the operating system's
   colours. color-scheme is what tells it which set to use — without it the
   options list stays white on a dark page and the text is unreadable. */
select, input, textarea, button { color-scheme: inherit; }
.post-filter select, .post-filter input[type="search"] { background: var(--leaf); }
select option { background: var(--leaf); color: var(--ink); }

/* Three choices do not fit side by side at a readable size, and stacking them
   also puts the safest one under the thumb on a phone. */
.sk-modal-stack { flex-direction: column; align-items: stretch; gap: 0.4rem; }
.sk-modal-stack .btn { width: 100%; }

/* ── podcasts and playlists ───────────────────────────────────────────────── */
.episode-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.1rem; }
.episode {
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.55rem 0.3rem; border-bottom: 1px solid var(--rule);
}
.episode-n {
  flex-shrink: 0; width: 1.8rem; text-align: center;
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-faint);
}
.episode-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.episode-body a { font-family: var(--f-km-body); font-size: 0.95rem; line-height: 1.6; text-decoration: none; }
.episode-body a:hover { color: var(--rubric); }
.episode .act[disabled] { opacity: 0.3; cursor: default; }
.mag-item.is-episode { grid-template-columns: 2rem minmax(0, 1fr) 8rem; }
.mag-item.is-episode .episode-n { grid-row: 1; grid-column: 1; padding-top: 0.2rem; }
.mag-item.is-episode .mag-item-body { grid-column: 2; }
.mag-item.is-episode .mag-item-cover { grid-column: 3; }

/* ============================================================================
   v3.2 · បណ្ណាល័យ — the Library
   ========================================================================== */

.lib { max-width: 46rem; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.lib-desc { color: var(--ink-soft); max-width: 34em; font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.lib-about { color: var(--ink-soft); max-width: 36em; margin-block: 1.2rem;
             font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.lib-until { margin-block: 0.6rem; }

/* ── the shelf ────────────────────────────────────────────────────────────
   A locked row is still a row. The titles are the reason to subscribe, so
   they are shown; only the opening is withheld. */
.lib-shelf { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.15rem; }
.lib-item {
  display: flex; align-items: baseline; gap: 0.8rem;
  padding: 0.7rem 0.3rem; border-bottom: 1px solid var(--rule);
}
.lib-kind {
  flex-shrink: 0; width: 5.5rem; text-align: end; font-size: 0.72rem;
  /*font-family: var(--f-la-ui);*/ text-transform: lowercase;
}
.lib-kind:lang(km) { font-family: var(--f-km-ui); }
.lib-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.lib-body a, .lib-locked {
  font-family: var(--f-km-body); font-size: 1rem; line-height: 1.6; font-weight: 600;
}
.lib-body a { text-decoration: none; }
.lib-body a:hover { color: var(--rubric); }
.lib-locked { color: var(--ink-soft); }
.lib-lock { flex-shrink: 0; opacity: 0.4; font-size: 0.8rem; }
.lib-heading { padding-top: 1.4rem; }
.lib-heading h2 { margin: 0; font-family: var(--f-km-display); font-size: 1.1rem; }

/* ── subscribing ──────────────────────────────────────────────────────────── */
.lib-buy {
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 1.2rem; margin-block: 1.4rem; background: var(--leaf-sunk);
}
.lib-plans { display: grid; gap: 0.6rem; }
.lib-plan {
  display: flex; align-items: center; gap: 0.7rem; cursor: pointer;
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0.7rem 0.9rem; background: var(--leaf);
}
.lib-plan:has(input:checked) { border-color: var(--ink); }
.lib-plan-body { display: flex; align-items: baseline; gap: 0.5rem; }
.lib-plan-body b { font-size: 1.1rem; }
/* Struck through, and only ever rendered when it is genuinely higher — the
   save refuses a "was" price that is not a reduction. */
.lib-was { text-decoration: line-through; color: var(--ink-faint); font-size: 0.85rem; }

/* ── building one ─────────────────────────────────────────────────────────── */
.shelf-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.1rem; }
.shelf-row {
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.5rem 0.3rem; border-bottom: 1px solid var(--rule);
}
.shelf-kind { flex-shrink: 0; width: 5.5rem; text-align: end; font-size: 0.7rem; }
.shelf-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.05rem; }
.shelf-heading { flex: 1; font-family: var(--f-km-display); }
.shelf-row.shelf-heading { background: var(--leaf-sunk); }
.shelf-adders { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 1rem; }
.shelf-adder {
  display: flex; flex-direction: column; gap: 0.4rem; align-items: flex-start;
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.8rem;
}
.shelf-adder h3 { margin: 0; }
.shelf-adder select, .shelf-adder input[type="text"], .shelf-adder input[type="url"] {
  width: 100%; padding: 0.35rem 0.5rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink); font-size: 0.85rem;
}
.price-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 0.7rem; }

@media (max-width: 640px) {
  .lib { padding-inline: 1.1rem; }
  .lib-item, .shelf-row { flex-wrap: wrap; }
  .lib-kind, .shelf-kind { width: auto; text-align: start; }
}
.pattern-help { margin-block: 0.5rem; }
.pattern-help summary { cursor: pointer; }
.pattern-help ul { margin: 0.5rem 0 0; padding-inline-start: 1.1rem; display: grid; gap: 0.3rem; }

/* ── the words screen ─────────────────────────────────────────────────────── */
.word-filter { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; }
.word-filter input[type="search"], .word-filter select {
  padding: 0.35rem 0.6rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf); color: var(--ink); font-size: 0.85rem;
}
.word-filter input[type="search"] { min-width: 16rem; font-family: var(--f-km-body); }
.word-table th { /*font-family: var(--f-la-ui);*/ font-size: 0.75rem; color: var(--ink-faint); text-align: start; }
.word-table td { vertical-align: top; padding-block: 0.45rem; }
.word-table input {
  width: 100%; padding: 0.35rem 0.5rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: transparent; color: var(--ink);
  font-family: var(--f-km-body); font-size: 0.9rem; line-height: 1.6;
}
.word-table small { display: block; margin-top: 0.15rem; }
.word-key { width: 13rem; }
/* A reworded line is marked, so a long list shows at a glance what has been
   touched without reading every row. */
.word-changed td:first-child { box-shadow: inset 3px 0 0 var(--brass); }

/* ── topics, two levels ───────────────────────────────────────────────────── */
.topic-subs { display: flex; flex-wrap: wrap; gap: 0.5rem 0.9rem; margin-top: 0.6rem; }
.topic-subs > .meta { flex-basis: 100%; }
.topic-pick select { width: 100%; padding: 0.4rem 0.55rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink); font-family: var(--f-km-ui); }

/* the admin tree */
.topic-block { border: 1px solid var(--rule); border-radius: var(--radius);
  margin-bottom: 0.9rem; padding: 0.5rem 0.7rem; }
.topic-block.is-off { opacity: 0.55; }
.topic-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; padding: 0.35rem 0; }
.topic-row + .topic-row { border-top: 1px solid var(--rule); }
.topic-main { font-weight: 600; }
/* Indented, so the shape of the tree is visible without reading the names. */
.topic-sub { padding-inline-start: 1.6rem; }
.topic-sub.is-off { opacity: 0.5; }
.topic-count { flex-shrink: 0; min-width: 2.6rem; text-align: end;
  /*font-family: var(--f-la-ui);*/ font-size: 0.78rem; color: var(--ink-faint); }
.topic-name { flex: 1 1 9rem; min-width: 7rem; padding: 0.3rem 0.45rem;
  border: 1px solid transparent; border-radius: var(--radius);
  background: transparent; color: var(--ink); font-family: var(--f-km-body); font-size: 0.92rem; }
.topic-name:hover, .topic-name:focus { border-color: var(--rule); background: var(--leaf); }
.topic-en { /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; }
.topic-move { flex: 0 1 10rem; padding: 0.25rem 0.4rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink); font-size: 0.8rem; }
.topic-acts { display: flex; gap: 0.15rem; margin-inline-start: auto; }
.topic-acts .act[disabled] { opacity: 0.3; cursor: default; }
.topic-none { padding-inline-start: 1.6rem; }
.topic-new-row { display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: flex-end; }
.topic-new-row .field { flex: 1 1 12rem; margin: 0; }
.tag-cloud { display: flex; flex-wrap: wrap; gap: 0.35rem; }
@media (max-width: 640px) { .topic-acts { margin-inline-start: 0; } }

/* sub-topics shown as chips, on the index and on a topic page */
.topic-kin { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-block: 0.8rem; }
.topic-chip {
  display: inline-flex; align-items: baseline; gap: 0.3rem;
  padding: 0.25rem 0.6rem; border: 1px solid var(--rule); border-radius: 999px;
  font-family: var(--f-km-ui); font-size: 0.82rem; text-decoration: none; color: var(--ink-soft);
}
.topic-chip:hover { border-color: var(--ink); color: var(--ink); }
.topic-chip.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }
.topic-chip.on .meta { color: var(--leaf); opacity: 0.7; }
.topic-card-subs { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.5rem; }
.topic-card > a { text-decoration: none; display: block; }

/* ============================================================================
   v3.7 · the arranged home page
   ========================================================================== */

.home-blocks { max-width: var(--w-wide, 74rem); margin-inline: auto; padding-inline: 1.5rem; }
.home-block { margin-block: 2.6rem; }
.block-head { display: flex; align-items: baseline; gap: 0.8rem; flex-wrap: wrap; margin-bottom: 1rem; }
.block-title { margin: 0; font-family: var(--f-km-display); font-size: 1.25rem; line-height: 1.5; }
.block-title:lang(en) { font-family: var(--f-la-display); }
/* Pushed to the end so the heading and its link sit at opposite edges, which
   is what makes a row of blocks scan as a list of sections. */
.block-more { margin-inline-start: auto; /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; text-decoration: none; }
.block-more:hover { color: var(--rubric); }

.block-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1.6rem 1.4rem; }
.block-list { display: grid; gap: 0.2rem; }

/* ── a row that scrolls sideways ──────────────────────────────────────────
   Twelve columns: eleven things and somewhere to go. Snap points stop it
   resting halfway through a card, which on a phone looks like a rendering
   fault rather than a scroll position. */
.block-rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(13.5rem, 1fr);
  gap: 1.2rem; overflow-x: auto; scroll-snap-type: x proximity;
  padding-bottom: 0.2rem;
}
.block-rail > * { scroll-snap-align: start; }

.rail-wrap { position: relative; }
.rail-nav {
  position: absolute; top: 40%; z-index: 3;
  width: 2.4rem; height: 2.4rem; border-radius: 999px;
  display: grid; place-items: center;
  border: 1px solid var(--rule); background: var(--leaf); color: var(--ink);
  font-size: 1.4rem; line-height: 1; cursor: pointer;
  box-shadow: 0 3px 14px rgb(0 0 0 / 0.16);
}
.rail-nav:hover { background: var(--leaf-sunk); border-color: var(--ink); }
.rail-nav[hidden] { display: none; }
.rail-prev { inset-inline-start: -1.1rem; }
.rail-next { inset-inline-end: -1.1rem; }

@media (max-width: 720px) {
  /* Inside the edge on a phone, where there is no room beside the rail. */
  .rail-prev { inset-inline-start: 0.2rem; }
  .rail-next { inset-inline-end: 0.2rem; }
}
/* A device without a mouse has touch scrolling already, and the arrows sit on
   top of the cards, so they are left to the pointers that need them. */
@media (hover: none) { .rail-nav { display: none !important; } }

.block-seemore {
  display: flex; align-items: center; justify-content: center;
  min-height: 8rem; border: 1px dashed var(--rule); border-radius: var(--radius);
  text-decoration: none; color: var(--ink-soft); /*font-family: var(--f-la-ui);*/ font-size: 0.9rem;
}
.block-seemore:hover { border-color: var(--ink); color: var(--ink); }

.block-wide { max-width: none; }
.recent-read { margin-block: 2.2rem; }

/* ── the item kinds a block can hold ──────────────────────────────────────── */
.block-item { display: flex; flex-direction: column; gap: 0.25rem; text-decoration: none; }
.writer-card {
  align-items: center; text-align: center; padding: 1rem 0.7rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
}
.writer-card b { font-family: var(--f-km-ui); font-size: 0.95rem; }
.writer-bio { line-height: 1.5; }
.topic-tile {
  padding: 0.9rem 1rem; border: 1px solid var(--rule); border-radius: var(--radius);
  font-family: var(--f-km-ui);
}
.topic-tile:hover { border-color: var(--ink); }
.custom-card {
  padding: 1rem; border: 1px solid var(--rule); border-radius: var(--radius);
  font-family: var(--f-km-body);
}
.custom-card:hover { border-color: var(--ink); }

/* ── arranging them, in the admin ─────────────────────────────────────────── */
.block-list-admin { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.2rem; }
.block-admin {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.6rem 0.4rem; border-bottom: 1px solid var(--rule);
}
.block-admin.is-off { opacity: 0.5; }
.block-n {
  flex-shrink: 0; width: 1.9rem; text-align: center;
  /*font-family: var(--f-la-ui);*/ font-size: 0.8rem; color: var(--ink-faint);
}
.block-admin-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.block-admin .inline-form { margin-inline-start: auto; display: flex; gap: 0.15rem; }
.block-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 0.8rem; }
/* The three inputs for one custom card, in the admin.
   Named `ccard-row`, not `card-row`: that name was already the article card in
   its row variant, and this rule was overriding it — turning every Worth
   Reading side article into a three-column grid with two empty columns, which
   is what left a wide band of white space beside them. */
.ccard-row { display: grid; grid-template-columns: 1fr 1.4fr 1.4fr; gap: 0.4rem; margin-bottom: 0.4rem; }
.ccard-row input {
  padding: 0.35rem 0.5rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf); color: var(--ink); font-size: 0.85rem; font-family: var(--f-km-body);
}

@media (max-width: 640px) {
  .home-blocks { padding-inline: 1.1rem; }
  .block-rail { grid-auto-columns: minmax(11rem, 1fr); }
  .ccard-row { grid-template-columns: 1fr; }
  .block-admin { flex-wrap: wrap; }
  .block-admin .inline-form { margin-inline-start: 0; }
}

/* ── wide adverts ─────────────────────────────────────────────────────────── */
.wide-ad { margin-block: 1.6rem; text-align: center; }
/* Always visible, never styled to disappear: a reader is entitled to know
   which parts of a page were paid for. */
.wide-ad-label {
  margin: 0 0 0.4rem; /*font-family: var(--f-la-ui);*/ font-size: 0.68rem;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-faint);
}
.wide-ad-img { display: block; }
.wide-ad-img img {
  display: block; width: 100%; height: auto; max-height: 18rem;
  object-fit: cover; border-radius: var(--radius); border: 1px solid var(--rule);
}
.wide-ad-slot { min-height: 6rem; }
.wide-ad-code { overflow: hidden; }
.wide-ad-text {
  display: flex; flex-direction: column; gap: 0.35rem; align-items: center;
  padding: 1.6rem 1.2rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf-sunk); text-decoration: none; color: var(--ink);
}
.wide-ad-text:hover { border-color: var(--ink); }
.wide-ad-heading { font-family: var(--f-km-display); font-size: 1.15rem; line-height: 1.5; }
.wide-ad-body { font-family: var(--f-km-body); font-size: 0.92rem; color: var(--ink-soft); max-width: 40em; }
.wide-ad-cta { /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; color: var(--rubric); }
.ad-preview { max-width: 100%; max-height: 10rem; border: 1px solid var(--rule); border-radius: var(--radius); }
.table tr.is-off { opacity: 0.55; }

/* ============================================================================
   Scrollbars inside the page
   ----------------------------------------------------------------------------
   Every box that scrolls within the layout hides its bar. On a rail the arrows
   are the control, and two controls for one thing is one too many; on a panel
   the content visibly cuts off, which says the same thing more quietly.

   All three properties are needed, and each covers a different engine:
     scrollbar-width      Firefox
     -ms-overflow-style   older Edge
     ::-webkit-scrollbar  Chrome, Safari, current Edge

   `display: none` rather than `height: 0`, because a zero-height webkit bar can
   still reserve its track. That was the first attempt and is why one remained.

   The window's own scrollbar is deliberately untouched. It is how somebody
   knows where they are in a long article, and hiding it would take away the
   only thing telling them how much is left.
   ========================================================================== */
.topic-strip,
.admin-nav,
.cmp-panel,
.insert-menu,
.editor pre,
.avatar-grid,
.pick-body,
.live-results,
.magpick-list,
.pub-mags,
.dictpanel-results,
.block-rail,
.block-list,
.table-wrap,
.rail-wrap {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.topic-strip::-webkit-scrollbar,
.admin-nav::-webkit-scrollbar,
.cmp-panel::-webkit-scrollbar,
.insert-menu::-webkit-scrollbar,
.editor pre::-webkit-scrollbar,
.avatar-grid::-webkit-scrollbar,
.pick-body::-webkit-scrollbar,
.live-results::-webkit-scrollbar,
.magpick-list::-webkit-scrollbar,
.pub-mags::-webkit-scrollbar,
.dictpanel-results::-webkit-scrollbar,
.block-rail::-webkit-scrollbar,
.block-list::-webkit-scrollbar,
.table-wrap::-webkit-scrollbar,
.rail-wrap::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

/* ============================================================================
   v3.9 · a library as somewhere to work
   ========================================================================== */
.libx { max-width: 60rem; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.libx-title { margin: 0.2rem 0 0.4rem; font-family: var(--f-km-display); font-size: 1.7rem; line-height: 1.45; }
.libx-desc { color: var(--ink-soft); max-width: 40em; font-family: var(--f-km-body); line-height: var(--lh-khmer); }

/* Search above the sections, not inside one: somebody arrives at a research
   library already knowing what they want. */
.libx-search { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-block: 1.1rem; }
.libx-search input[type="search"] {
  flex: 1 1 20rem; padding: 0.6rem 0.8rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink);
  font-family: var(--f-km-body); font-size: 0.95rem;
}
.libx-search input[type="search"]:focus { border-color: var(--ink); outline: none; }

.libx-tabs { display: flex; flex-wrap: wrap; gap: 1.3rem; border-bottom: 1px solid var(--rule); margin-bottom: 1.4rem; }
.libx-tab {
  padding: 0.6rem 0; margin-bottom: -1px; border-bottom: 2px solid transparent;
  text-decoration: none; color: var(--ink-soft);
  font-family: var(--f-km-ui); font-size: 0.95rem;
}
.libx-tab:hover { color: var(--ink); }
.libx-tab.on { color: var(--ink); border-bottom-color: var(--ink); }
.libx-count {
  display: inline-block; min-width: 1.3rem; padding: 0 0.3rem; border-radius: 999px;
  background: var(--leaf-sunk); font-size: 0.72rem; text-align: center;
}

.libx-filter { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 1.2rem; }
.libx-chip {
  display: inline-flex; align-items: baseline; gap: 0.35rem;
  padding: 0.3rem 0.7rem; border: 1px solid var(--rule); border-radius: 999px;
  text-decoration: none; color: var(--ink-soft); font-family: var(--f-km-ui); font-size: 0.85rem;
}
.libx-chip:hover { border-color: var(--ink); color: var(--ink); }
.libx-chip.on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }
.libx-chip.on .meta { color: var(--leaf); opacity: 0.75; }

/* ── the shelf ────────────────────────────────────────────────────────────
   A locked row is still a row: the titles are the reason to subscribe, so
   they are shown and only the opening is withheld. */
.libx-shelf { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.15rem; }
.libx-item {
  display: flex; align-items: baseline; gap: 0.9rem;
  padding: 0.85rem 0.3rem; border-bottom: 1px solid var(--rule);
}
.libx-kind {
  flex-shrink: 0; width: 5.5rem; text-align: end;
  font-size: 0.72rem; text-transform: lowercase; /*font-family: var(--f-la-ui);*/
}
.libx-kind:lang(km) { font-family: var(--f-km-ui); }
.libx-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.libx-name { font-family: var(--f-km-body); font-size: 1rem; font-weight: 600; line-height: 1.6; text-decoration: none; }
.libx-name:hover { color: var(--rubric); }
.libx-name.is-locked { color: var(--ink-soft); }
.libx-facts { font-size: 0.78rem; }
.libx-acts { flex-shrink: 0; display: flex; gap: 0.3rem; align-items: center; }
.libx-lock { opacity: 0.4; font-size: 0.8rem; }
.libx-heading { padding-top: 1.5rem; }
.libx-heading h2 { margin: 0; font-family: var(--f-km-display); font-size: 1.1rem; }

/* ── notebooks ────────────────────────────────────────────────────────────── */
.libx-note-form { display: grid; gap: 0.6rem; margin-block: 1.2rem; }
.libx-note-title, .libx-note-body {
  width: 100%; padding: 0.7rem 0.85rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink);
  font-family: var(--f-km-body); line-height: var(--lh-khmer);
}
.libx-note-title { font-size: 1.05rem; font-weight: 600; }
.libx-note-body { font-size: 0.95rem; resize: vertical; }
.libx-note-acts { display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: center; }
.libx-notes-head { display: flex; align-items: center; gap: 0.8rem; margin-top: 1.8rem; }
.libx-notes-head .btn { margin-inline-start: auto; }
.libx-notes { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.15rem; }
.libx-note {
  display: flex; gap: 0.9rem; align-items: flex-start;
  padding: 0.8rem 0.3rem; border-bottom: 1px solid var(--rule);
}
.libx-note.is-pinned { background: var(--leaf-sunk); }
.libx-note-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.libx-note-peek {
  margin: 0; color: var(--ink-soft); font-family: var(--f-km-body);
  font-size: 0.88rem; line-height: 1.65;
}
.libx-note-side { flex-shrink: 0; display: flex; gap: 0.25rem; align-items: center; }

/* ── price ────────────────────────────────────────────────────────────────── */
.libx-plans { display: grid; gap: 0.7rem; max-width: 30rem; }
.libx-plan {
  display: flex; align-items: center; gap: 0.7rem; cursor: pointer;
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0.8rem 1rem; background: var(--leaf);
}
.libx-plan:has(input:checked) { border-color: var(--ink); }
.libx-plan-body { display: flex; align-items: baseline; gap: 0.5rem; }
.libx-plan-body b { font-size: 1.15rem; }
.libx-was { text-decoration: line-through; color: var(--ink-faint); font-size: 0.85rem; }
.libx-about { margin-top: 1.6rem; color: var(--ink-soft); font-family: var(--f-km-body); line-height: var(--lh-khmer); max-width: 38em; }

@media (max-width: 640px) {
  .libx { padding-inline: 1.1rem; }
  .libx-item, .libx-note { flex-wrap: wrap; }
  .libx-kind { width: auto; text-align: start; }
  .libx-tabs { gap: 0.9rem; }
}

/* ── library pricing tiers ────────────────────────────────────────────────
   Side by side, because a reader who cannot see what free gets them has no
   way to judge what paying adds. */
.libx-tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
              gap: 1rem; margin-block: 1.2rem; }
.libx-tier { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1.2rem; }
.libx-tier.is-paid { border-color: var(--ink); }
.libx-tier-name { margin: 0; font-family: var(--f-km-ui); font-size: 1rem; color: var(--ink-soft); }
.libx-tier-price { margin: 0.3rem 0 0.9rem; font-size: 1.5rem; font-weight: 700; }
.libx-tier-price .meta { font-size: 0.85rem; font-weight: 400; }
.libx-perks { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.45rem; }
.libx-perks li { position: relative; padding-inline-start: 1.2rem;
                 font-family: var(--f-km-body); font-size: 0.9rem; line-height: 1.6; }
.libx-perks li::before { content: '✓'; position: absolute; inset-inline-start: 0; color: var(--rubric); }

.libx-support { margin-top: 2rem; padding-top: 1.4rem; border-top: 1px solid var(--rule); }
.libx-donate { display: grid; gap: 0.6rem; max-width: 26rem; margin-top: 0.8rem; }

.libx-pay { margin-top: 2rem; padding-top: 1.4rem; border-top: 1px solid var(--rule); }
/* A small green flag on a row a free reader may open, so the shelf shows at a
   glance where the free tier ends. */
.pill-free { background: var(--rubric); color: var(--leaf); }
.act.act-on { background: var(--ink); color: var(--leaf); border-color: var(--ink); }

/* ── reading a Drive document on the site ────────────────────────────────── */
.libread { max-width: 62rem; margin-inline: auto; padding: 1.6rem 1.5rem 3rem; }
.libread-title { margin: 0.2rem 0 0.5rem; font-family: var(--f-km-display); font-size: 1.4rem; line-height: 1.5; }
/* A tall frame by default because most documents are portrait; a folder list
   needs far less, so it gets its own height rather than a screen of blank. */
.libread-frame { position: relative; width: 100%; height: 80vh; min-height: 30rem;
                 border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden;
                 background: var(--leaf-sunk); }
.libread-frame.is-folder { height: 32rem; min-height: 0; }
.libread-frame iframe { width: 100%; height: 100%; border: 0; display: block; }
.libread-fall { margin-top: 0.7rem; }

/* ── payment details behind a button ─────────────────────────────────────── */
.pay-reveal summary { display: inline-block; cursor: pointer; list-style: none; }
.pay-reveal summary::-webkit-details-marker { display: none; }
.pay-reveal[open] summary { margin-bottom: 0.9rem; }

@media (max-width: 640px) {
  .libread { padding-inline: 1.1rem; }
  .libread-frame { height: 70vh; }
}

/* ============================================================================
   v4.2 · ស្ទូឌីយោ
   ========================================================================== */
.studio { max-width: 60rem; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.studio-title { margin: 0 0 0.4rem; font-family: var(--f-km-display); font-size: 1.8rem; }
.studio-note { color: var(--ink-soft); max-width: 36em; font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.studio-shelf { margin-block: 2.4rem; }
.shelf-head { display: flex; align-items: baseline; gap: 0.8rem; flex-wrap: wrap; margin-bottom: 0.9rem; }
.shelf-name { margin: 0; font-family: var(--f-km-display); font-size: 1.15rem; }
.shelf-more { margin-inline-start: auto; /*font-family: var(--f-la-ui);*/ font-size: 0.85rem; text-decoration: none; }
.studio-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: 0.9rem; }
.play-card {
  display: flex; flex-direction: column; gap: 0.3rem; padding: 1.1rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  text-decoration: none; color: var(--ink); background: var(--leaf);
}
.play-card:hover { border-color: var(--ink); }
.play-card b { font-family: var(--f-km-ui); font-size: 1rem; }
.play-mark {
  width: 2.2rem; height: 2.2rem; display: grid; place-items: center; margin-bottom: 0.3rem;
  border-radius: var(--radius); background: var(--leaf-sunk);
  font-family: var(--f-km-display); font-size: 1.1rem; color: var(--rubric);
}

/* ── playing ─────────────────────────────────────────────────────────────── */
.play { max-width: 42rem; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.play-title { margin: 0.2rem 0 0.3rem; font-family: var(--f-km-display); font-size: 1.5rem; }
.word-clue { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1.1rem; margin-block: 1.2rem; }
.word-clue-text { font-family: var(--f-km-body); font-size: 1.05rem; line-height: var(--lh-khmer); margin: 0.2rem 0 0.6rem; }
.word-rows { display: grid; gap: 0.4rem; margin-block: 1rem; }
.word-row, .word-blanks { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.word-cell {
  min-width: 2.9rem; padding: 0.55rem 0.4rem; text-align: center;
  border: 1px solid var(--rule); border-radius: var(--radius);
  font-family: var(--f-km-body); font-size: 1.15rem; line-height: 1.4;
}
/* Colour is never the only signal: exact is filled, elsewhere is outlined,
   and a wrong letter is faded — three different shapes, so this still reads
   for somebody who cannot tell the two colours apart. */
.word-cell.is-exact { background: var(--rubric); color: var(--leaf); border-color: var(--rubric); font-weight: 700; }
.word-cell.is-elsewhere { border-color: var(--rubric); border-width: 2px; color: var(--rubric); }
.word-cell.is-no { opacity: 0.45; }
.word-cell.is-blank { border-style: dashed; color: var(--ink-faint); }
.word-form { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.word-input {
  flex: 1 1 14rem; padding: 0.65rem 0.8rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink);
  font-family: var(--f-km-body); font-size: 1.05rem;
}
.choice-form { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.choice-btn { font-family: var(--f-km-body); font-size: 1.05rem; padding: 0.6rem 1.1rem; }

.quiz-form { display: grid; gap: 1.4rem; margin-block: 1.2rem; }
.quiz-q { border: 0; padding: 0; margin: 0; }
.quiz-q legend { font-family: var(--f-km-body); font-size: 1rem; line-height: var(--lh-khmer); margin-bottom: 0.5rem; }
.quiz-opt {
  display: flex; gap: 0.6rem; align-items: flex-start; padding: 0.55rem 0.7rem;
  border: 1px solid var(--rule); border-radius: var(--radius); cursor: pointer; margin-bottom: 0.35rem;
  font-family: var(--f-km-body); line-height: 1.6;
}
.quiz-opt:has(input:checked) { border-color: var(--ink); background: var(--leaf-sunk); }
.mark-list { list-style: none; margin: 1rem 0; padding: 0; display: grid; gap: 0.5rem; }
.mark { display: flex; flex-direction: column; gap: 0.15rem; padding: 0.7rem 0.9rem;
        border: 1px solid var(--rule); border-radius: var(--radius); border-inline-start-width: 3px; }
.mark.is-ok { border-inline-start-color: var(--rubric); }
.mark.is-no { border-inline-start-color: var(--ink-faint); opacity: 0.85; }

.zodiac-out { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 1rem; margin-block: 1.2rem; }
.zodiac-card { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1.2rem; text-align: center; }
.zodiac-card h2 { margin: 0.2rem 0; font-family: var(--f-km-display); font-size: 1.6rem; }

.type-out { border: 1px solid var(--ink); border-radius: var(--radius); padding: 1.4rem; margin-block: 1.2rem; }
.type-code { margin: 0; /*font-family: var(--f-la-ui);*/ font-size: 2rem; letter-spacing: 0.16em; font-weight: 700; }
.type-out h2 { margin: 0.2rem 0 0.6rem; font-family: var(--f-km-display); font-size: 1.3rem; }
.type-desc { font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.type-bars { display: grid; gap: 0.5rem; margin-top: 1rem; }
.type-bar { display: flex; align-items: center; gap: 0.6rem; }
.type-bar .bar { flex: 1; height: 0.5rem; background: var(--leaf-sunk); border-radius: 999px; overflow: hidden; }
.type-bar .bar-fill { display: block; height: 100%; background: var(--rubric); }

@media (max-width: 640px) {
  .studio, .play { padding-inline: 1.1rem; }
  .word-cell { min-width: 2.4rem; font-size: 1rem; }
}

/* ── making a quiz ────────────────────────────────────────────────────────── */
.quiz-maker { display: grid; gap: 0.9rem; }
.qmake {
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0.9rem 1rem; display: grid; gap: 0.4rem; margin: 0;
}
.qmake legend { /*font-family: var(--f-la-ui);*/ font-size: 0.78rem; color: var(--ink-faint); padding-inline: 0.3rem; }
.qmake input {
  width: 100%; padding: 0.5rem 0.65rem; border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--leaf); color: var(--ink);
  font-family: var(--f-km-body); font-size: 0.95rem;
}
.qmake-prompt { font-weight: 600; }
.qmake-note { font-size: 0.85rem !important; }
/* The radio sits beside its answer rather than above it, so which one is
   marked right is obvious at a glance down the column. */
.qmake-opt { display: flex; align-items: center; gap: 0.6rem; }
.qmake-opt input[type="radio"] { flex-shrink: 0; }
.quiz-about {
  padding: 0.7rem 0.9rem; border-inline-start: 3px solid var(--rubric);
  background: var(--leaf-sunk); border-radius: var(--radius);
  font-family: var(--f-km-body); font-size: 0.92rem;
}
.play-after { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1rem; }

/* ── a full zodiac reading ────────────────────────────────────────────────── */
.zx { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1.4rem; margin-block: 1.1rem; }
.zx-name { margin: 0.15rem 0; font-family: var(--f-km-display); font-size: 1.8rem; line-height: 1.4; }
.zx-lead { font-family: var(--f-km-body); font-size: 1.02rem; line-height: var(--lh-khmer); margin: 0.7rem 0 1rem; }
/* Two columns on a wide screen, one on a phone. The label column is fixed so
   the values line up down the page and can be scanned rather than read. */
.zx-rows { display: grid; grid-template-columns: 10rem 1fr; gap: 0.5rem 1rem; margin: 0; }
.zx-rows dt { font-family: var(--f-km-ui); font-size: 0.82rem; color: var(--ink-faint); }
.zx-rows dd { margin: 0; font-family: var(--f-km-body); font-size: 0.94rem; line-height: 1.7; }

/* ── a full type reading ──────────────────────────────────────────────────── */
.type-tag { font-family: var(--f-km-body); font-size: 1.05rem; color: var(--rubric); margin: 0 0 0.5rem; }
.type-sections { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 1rem; margin-block: 1.4rem; }
.type-sec { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1rem 1.1rem; }
.type-sec-name { margin: 0 0 0.5rem; font-family: var(--f-km-ui); font-size: 0.88rem; color: var(--ink-faint); }
.type-sec p { margin: 0; font-family: var(--f-km-body); font-size: 0.94rem; line-height: var(--lh-khmer); }
.type-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.type-list li { position: relative; padding-inline-start: 0.9rem;
                font-family: var(--f-km-body); font-size: 0.94rem; line-height: 1.65; }
.type-list li::before { content: '·'; position: absolute; inset-inline-start: 0; color: var(--rubric); font-weight: 700; }

@media (max-width: 640px) {
  .zx-rows { grid-template-columns: 1fr; gap: 0.15rem 0; }
  .zx-rows dd { margin-bottom: 0.6rem; }
}

/* ── taking a note from a selection ───────────────────────────────────────── */
.notepop {
  position: absolute; z-index: 60; width: min(20rem, calc(100vw - 1rem));
  padding: 0.6rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf); box-shadow: 0 6px 26px rgb(0 0 0 / 0.2);
}
.notepop button { font-family: var(--f-km-ui); font-size: 0.85rem; cursor: pointer;
  padding: 0.4rem 0.8rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf-sunk); color: var(--ink); }
.notepop-go { width: 100%; }
.notepop-quote {
  margin: 0 0 0.5rem; padding-inline-start: 0.6rem; border-inline-start: 2px solid var(--rubric);
  font-family: var(--f-km-body); font-size: 0.85rem; line-height: 1.6; color: var(--ink-soft);
}
.notepop-body, .notepop-tags {
  width: 100%; margin-bottom: 0.4rem; padding: 0.45rem 0.55rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf); color: var(--ink); font-family: var(--f-km-body); font-size: 0.88rem;
}
.notepop-acts { display: flex; gap: 0.4rem; }
.notepop-msg { margin: 0.4rem 0 0; }

/* ── the notebook ─────────────────────────────────────────────────────────── */
.mystudio { max-width: 56rem; margin-inline: auto; padding: 2rem 1.5rem 4rem; }
.note-form { display: grid; gap: 0.6rem; margin-block: 1.2rem; }
.note-form-row { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: flex-end; }
/* A quotation is shown but never editable: changing somebody else's words
   inside quotation marks would make the note a forgery of itself. */
.note-quote, .note-quote-peek {
  margin: 0.3rem 0; padding: 0.5rem 0.8rem;
  border-inline-start: 3px solid var(--rubric); background: var(--leaf-sunk);
  border-radius: var(--radius);
  font-family: var(--f-km-body); font-size: 0.9rem; line-height: 1.7; color: var(--ink-soft);
}

/* ── sharing ──────────────────────────────────────────────────────────────── */
.share { margin-top: 1.6rem; padding-top: 1.2rem; border-top: 1px solid var(--rule); }
.share-text {
  padding: 0.7rem 0.9rem; border: 1px dashed var(--rule); border-radius: var(--radius);
  font-family: var(--f-km-body); font-size: 0.95rem; line-height: 1.7;
}
.share-acts { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.bank-wrong {
  width: 100%; margin-bottom: 0.35rem; padding: 0.45rem 0.6rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf); color: var(--ink); font-family: var(--f-km-body); font-size: 0.9rem;
}
@media (max-width: 640px) { .mystudio { padding-inline: 1.1rem; } }

/* ── the admin overview figures ───────────────────────────────────────────── */
.stat-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
              gap: 0.7rem; margin-block: 1.2rem; }
.stat-card { border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.9rem 1rem;
             display: flex; flex-direction: column; gap: 0.1rem; }
.stat-n { /*font-family: var(--f-la-ui);*/ font-size: 1.7rem; line-height: 1.2; }
.stat-sub { font-size: 0.72rem; }
/* Bars rather than a chart library. A quiet day is still a visible column —
   a gap would read as missing data rather than as a quiet day. */
.spark { display: flex; align-items: flex-end; gap: 2px; height: 5rem;
         padding: 0.4rem; border: 1px solid var(--rule); border-radius: var(--radius); }
.spark-bar { flex: 1; min-width: 2px; background: var(--rubric); opacity: 0.75; border-radius: 1px; }
.spark-bar:hover { opacity: 1; }
.stat-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
             gap: 1.2rem; margin-block: 1.4rem; }
.table-tight td { padding-block: 0.3rem; }

/* ── តេស្ដចិត្តសាស្រ្ដ ─────────────────────────────────────────────────────── */
.reveal-title { margin: 0 0 0.3rem; font-family: var(--f-km-display); font-size: 1.2rem; }
.reveal-form { display: grid; gap: 0.5rem; margin-block: 1.2rem; }
/* Full-width buttons, because each option is a sentence rather than a word
   and a row of pills would wrap into nonsense. */
.reveal-opt {
  display: block; width: 100%; text-align: start; cursor: pointer;
  padding: 0.85rem 1rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--leaf); color: var(--ink);
  font-family: var(--f-km-body); font-size: 0.98rem; line-height: 1.7;
}
.reveal-opt:hover { border-color: var(--ink); background: var(--leaf-sunk); }
.reveal-out { border: 1px solid var(--ink); border-radius: var(--radius); padding: 1.3rem; margin-block: 1.2rem; }
.reveal-pick { margin: 0.2rem 0 0.8rem; font-family: var(--f-km-display); font-size: 1.15rem; line-height: 1.6; }
.reveal-read { margin: 0; font-family: var(--f-km-body); font-size: 1rem; line-height: var(--lh-khmer); }
.reveal-spread { margin-block: 1.2rem; display: grid; gap: 0.4rem; }

/* ── one question at a time ───────────────────────────────────────────────── */
.askbar { display: flex; align-items: center; gap: 0.7rem; margin-block: 1rem; flex-wrap: wrap; }
/* Progress, because a round with no visible end is one people leave halfway. */
.askbar-track { flex: 1; min-width: 6rem; height: 0.35rem; background: var(--leaf-sunk);
                border-radius: 999px; overflow: hidden; }
.askbar-fill { display: block; height: 100%; background: var(--rubric); }
.pill.lv-1 { background: var(--leaf-sunk); }
.pill.lv-2 { background: var(--rule); }
/* The hardest level is the only one that gets a strong colour — if all three
   were coloured, none of them would mean anything. */
.pill.lv-3 { background: var(--rubric); color: var(--leaf); }
.score { text-align: center; border: 1px solid var(--ink); border-radius: var(--radius);
         padding: 1.4rem; margin-block: 1.2rem; }
.score-n { margin: 0; /*font-family: var(--f-la-ui);*/ font-size: 2.4rem; font-weight: 700; line-height: 1.1; }
.start-form { margin-block: 1.2rem; }
.start-form .choice-form { margin-bottom: 1rem; }
.bulk { margin-block: 1.4rem; }
.bulk summary { display: inline-block; cursor: pointer; list-style: none; }
.bulk summary::-webkit-details-marker { display: none; }
.bulk[open] summary { margin-bottom: 0.8rem; }
.bulk textarea { font-family: var(--f-mono, monospace); font-size: 0.85rem; }

/* ============================================================================
   Telegram mode
   ----------------------------------------------------------------------------
   Only inside the app. Every rule is scoped to .in-telegram, so nothing here
   can touch the website — which is the whole point of doing this as a mode
   rather than a second front end.
   ========================================================================== */

/* Telegram supplies the reader's own theme; telegram.js copies it into these
   variables. The fallbacks are the site's own colours, so a client that sends
   no theme still gets something coherent rather than white on white. */
.in-telegram {
  --leaf: var(--tg-bg, #fff);
  --leaf-sunk: var(--tg-section, #f4f4f5);
  --ink: var(--tg-text, #111);
  --ink-soft: var(--tg-hint, #666);
  --ink-faint: var(--tg-hint, #888);
  --rubric: var(--tg-button, #8a1c1c);
}

/* Telegram draws its own header and back button. Ours would be a second set
   of the same controls, which on a phone reads as a bug. */
.in-telegram .site-header,
.in-telegram .site-footer,
.in-telegram .theme-toggle { display: none; }

/* The app has no address bar, so the page starts at the very top. */
.in-telegram main { padding-top: 0.5rem; }
.in-telegram .studio, .in-telegram .play, .in-telegram .mystudio { padding-top: 0.8rem; }

/* Buttons take Telegram's own button colour, so the primary action looks like
   a primary action in whichever theme the reader has chosen. */
.in-telegram .btn-solid {
  background: var(--tg-button, var(--rubric));
  color: var(--tg-button-text, #fff);
  border-color: transparent;
}

/* Comfortably tappable. A 40px target is fine with a mouse and a nuisance with
   a thumb on a phone held one-handed on a moto. */
.in-telegram .reveal-opt,
.in-telegram .choice-btn,
.in-telegram .btn { min-height: 2.9rem; }

/* ── the Mini App's own front door ────────────────────────────────────────── */
.tgapp { max-width: 34rem; margin-inline: auto; padding: 1rem 1rem 3rem; }
.tgapp-hi { margin: 0 0 1.2rem; font-family: var(--f-km-body); line-height: var(--lh-khmer); }
.tgapp-grid { display: grid; gap: 0.7rem; }
.tgapp-card {
  display: flex; align-items: center; gap: 0.9rem; padding: 1rem 1.1rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  text-decoration: none; color: var(--ink); background: var(--leaf-sunk);
}
.tgapp-card b { font-family: var(--f-km-ui); font-size: 1.02rem; display: block; }
.tgapp-mark {
  width: 2.6rem; height: 2.6rem; flex-shrink: 0; display: grid; place-items: center;
  border-radius: var(--radius); background: var(--leaf);
  font-family: var(--f-km-display); font-size: 1.15rem; color: var(--rubric);
}
/* The two sections that are deliberately NOT in the app get a quieter card
   that says plainly it opens the website. */
.tgapp-card.is-out { background: transparent; }
.tgapp-card.is-out .tgapp-mark { background: var(--leaf-sunk); }

/* ── diagnostics ──────────────────────────────────────────────────────────── */
.diag-mark { width: 2rem; text-align: center; font-weight: 700; vertical-align: top; padding-top: 0.7rem; }
.diag-ok   .diag-mark { color: var(--rubric); }
.diag-warn .diag-mark { color: var(--ink-faint); }
.diag-fail .diag-mark { color: #c0392b; }
/* The failing rows carry a bar so the eye finds them without reading. */
.diag-fail td:first-child { box-shadow: inset 3px 0 0 #c0392b; }
.diag-fix { margin-top: 0.3rem; padding: 0.4rem 0.6rem; background: var(--leaf-sunk);
            border-radius: var(--radius); }
.diag-url { padding: 0.6rem 0.8rem; background: var(--leaf-sunk); border-radius: var(--radius);
            font-size: 0.78rem; overflow-x: auto; white-space: pre-wrap; word-break: break-all; }

/* ── diagnostics · Admin → Telegram ───────────────────────────────────────
   Cards, never a table. The version this replaces put URLs in table cells,
   and one unbreakable 150-character address forced the table wider than the
   screen, collapsing every other column to a few pixels. A table must agree
   on column widths; a list need not, so nothing a check prints can distort
   anything else.
   ------------------------------------------------------------------------ */
.diag-list { display: grid; gap: 0.5rem; margin-block: 1.2rem; }
.diag {
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0.8rem 1rem; border-inline-start-width: 3px;
  /* The rule that matters: no child may push this wider than the page. */
  min-width: 0; overflow-wrap: anywhere;
}
.diag-ok   { border-inline-start-color: var(--rubric); }
.diag-warn { border-inline-start-color: var(--ink-faint); }
.diag-fail { border-inline-start-color: #c0392b; }
.diag-head { margin: 0 0 0.25rem; display: flex; align-items: baseline; gap: 0.6rem; }
.diag-mark { flex-shrink: 0; width: 1.1rem; text-align: center; font-weight: 700; }
.diag-ok   .diag-mark { color: var(--rubric); }
.diag-warn .diag-mark { color: var(--ink-faint); }
.diag-fail .diag-mark { color: #c0392b; }
.diag-detail, .diag-fix {
  margin: 0; font-size: 0.86rem; line-height: 1.65; color: var(--ink-soft);
  overflow-wrap: anywhere;
}
.diag-fix { margin-top: 0.45rem; padding: 0.5rem 0.7rem;
            background: var(--leaf-sunk); border-radius: var(--radius); }
.diag code { font-size: 0.82rem; background: var(--leaf-sunk);
             padding: 0.05rem 0.3rem; border-radius: 3px; overflow-wrap: anywhere; }

/* Label column fixed, value column free to hold a URL of any length. */
.diag-facts { display: grid; grid-template-columns: 14rem minmax(0, 1fr);
              gap: 0.4rem 1rem; margin: 0; }
.diag-facts dt { font-size: 0.85rem; color: var(--ink-faint); }
.diag-facts dd { margin: 0; font-size: 0.88rem; overflow-wrap: anywhere; }
.diag-facts .is-bad, .is-bad { color: #c0392b; }
.diag-url { padding: 0.6rem 0.8rem; margin: 0.4rem 0 1rem;
            background: var(--leaf-sunk); border-radius: var(--radius);
            font-size: 0.76rem; line-height: 1.6;
            white-space: pre-wrap; overflow-wrap: anywhere; }

/* Small gaps found by the coverage scan rather than by eye. */
.mono { font-family: var(--f-mono, ui-monospace, monospace); }
.form-narrow { max-width: 26rem; }
.studio-head, .play-head, .mystudio-head { margin-bottom: 1rem; }

@media (max-width: 640px) {
  .diag-facts { grid-template-columns: 1fr; gap: 0.1rem; }
  .diag-facts dd { margin-bottom: 0.5rem; }
}

/* ── មគ្គុទ្ទេសក៍ · the guide ──────────────────────────────────────────────
   Set like the manuscript the site is named after: a rubric red for the
   section numbers, the way a scribe marked divisions in red before the black
   text was written. The numbers are Khmer numerals because the sequence is
   the content's own, not a decoration borrowed from a template.
   ------------------------------------------------------------------------ */
.guide { max-width: var(--measure-km, 34em); margin-inline: auto; padding: 2rem 1.4rem 5rem; }
.guide-head { margin-bottom: 1rem; }
.guide-title { font-family: var(--f-km-disp); font-size: 1.9rem; line-height: 1.6; margin: 0.2rem 0 0.8rem; }
.guide-lede { font-family: var(--f-km-body); font-size: 1.05rem; line-height: var(--lh-khmer); color: var(--ink-soft); }

/* The contents list doubles as the map of the whole page, so it is a grid
   rather than a paragraph of links. */
.guide-toc { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
             gap: 0.3rem 1rem; margin: 1.8rem 0 0; padding-top: 1.2rem;
             border-top: 1px solid var(--rule); }
.guide-toc a { text-decoration: none; color: var(--ink); font-family: var(--f-km-ui);
               font-size: 0.95rem; padding: 0.25rem 0; }
.guide-toc a:hover { color: var(--rubric); }

.guide-num { color: var(--rubric); font-family: var(--f-la-ui); font-size: 0.8em;
             letter-spacing: 0.06em; margin-inline-end: 0.5em; }

.guide-sec { margin-top: 3rem; scroll-margin-top: 1.5rem; }
.guide-sec h2 { font-family: var(--f-km-disp); font-size: 1.3rem; line-height: 1.7;
                padding-bottom: 0.5rem; border-bottom: 2px solid var(--rubric); }
.guide-sec h3 { font-family: var(--f-km-ui); font-size: 1.02rem; margin-top: 1.8rem; color: var(--ink); }
.guide-sec p, .guide-sec li, .guide-sec dd {
  font-family: var(--f-km-body); line-height: var(--lh-khmer); }

.guide-steps { counter-reset: gstep; list-style: none; padding: 0; margin: 1rem 0; }
.guide-steps li { counter-increment: gstep; position: relative;
                  padding-inline-start: 2.2rem; margin-bottom: 0.6rem; }
.guide-steps li::before {
  content: counter(gstep, khmer); position: absolute; inset-inline-start: 0; top: 0.35em;
  width: 1.5rem; text-align: center; color: var(--rubric);
  font-family: var(--f-km-ui); font-size: 0.82rem;
}

.guide-defs { margin: 1rem 0; }
.guide-defs dt { font-family: var(--f-km-ui); color: var(--rubric); margin-top: 0.9rem; }
.guide-defs dd { margin: 0.1rem 0 0; }

/* Marginalia, set apart the way a note in a margin is. */
.guide-note { margin: 1.4rem 0; padding: 0.9rem 1.1rem;
              border-inline-start: 3px solid var(--brass); background: var(--leaf-sunk);
              font-family: var(--f-km-body); font-size: 0.95rem; line-height: var(--lh-khmer); }

.guide-fig { margin: 1.6rem 0; }
.guide-fig svg { width: 100%; height: auto; display: block; }
.guide-fig figcaption { margin-top: 0.5rem; font-family: var(--f-km-ui);
                        font-size: 0.85rem; color: var(--ink-faint); text-align: center; }

.guide-foot { margin-top: 3.5rem; padding-top: 1.2rem; border-top: 1px solid var(--rule);
              font-family: var(--f-km-body); font-size: 0.95rem; color: var(--ink-soft); }

@media (max-width: 640px) { .guide { padding-inline: 1.1rem; } }
