:root {
  --blue: #032ea1;   /* Cambodian flag blue */
  --red: #e00025;    /* Cambodian flag red */
  --bg: #f4f6fb;
  --card: #ffffff;
  --ink: #1a2233;
  --muted: #64708a;
  --line: #dde3ef;
  --ok: #0a7d33;
  --warn: #b45309;
}
* { box-sizing: border-box; margin: 0; }
body {
  font-family: -apple-system, "Segoe UI", Roboto, "Noto Sans Khmer", sans-serif;
  background: var(--bg); color: var(--ink); min-height: 100vh;
}
header.site {
  background: var(--blue); color: #fff; padding: 14px 24px;
  display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap;
}
header.site h1 { font-size: 18px; font-weight: 600; }
header.site .sub { font-size: 12.5px; opacity: 0.85; }
/* align-items: center, not the header's baseline: a <button> and an <a> do not
   share a baseline, so the group buttons sat ~10px below Home and Admin. */
header.site nav { margin-left: auto; display: flex; gap: 14px; align-items: center; }
/* DIRECT children only. This rule predates the dropdowns, and as a descendant
   selector it also matched the links INSIDE a panel — setting them inline-flex,
   so three submenu links laid out side by side in a row instead of stacking.
   It outranked `.nav-menu a` on specificity, so the panel's own styling could
   not correct it. */
header.site nav > a {
  color: #fff; text-decoration: none; font-size: 13.5px; opacity: .9;
  padding: 4px 2px; line-height: 1.4; border-bottom: 2px solid transparent;
  display: inline-flex; align-items: center;
}
header.site nav > a.active, header.site nav > a:hover { border-bottom-color: var(--red); opacity: 1; }
main { max-width: 1100px; margin: 24px auto; padding: 0 20px; display: grid; gap: 18px; }
.card { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 18px 20px; }
.card h2 { font-size: 15px; margin-bottom: 12px; color: var(--blue); }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 800px) { .grid2 { grid-template-columns: 1fr; } }
label { display: block; font-size: 12px; color: var(--muted); margin: 10px 0 4px; }
input, select {
  width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: 6px;
  font-size: 13.5px; font-family: inherit; background: #fff; color: var(--ink);
  -webkit-text-fill-color: var(--ink); /* guard against invisible text on some engines */
}
input:focus, select:focus { outline: 2px solid #b9c6f2; border-color: var(--blue); }
button {
  margin-top: 12px; padding: 8px 16px; border: 0; border-radius: 6px; cursor: pointer;
  background: var(--blue); color: #fff; font-size: 13.5px; font-weight: 600;
}
button:hover { filter: brightness(1.15); }
button.danger { background: var(--red); }
button.ghost { background: #e8ecf7; color: var(--blue); }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 7px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
th { color: var(--muted); font-weight: 600; font-size: 12px; }
td.mono, .mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; word-break: break-all; }
.badge { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 700; }
.badge.ok { background: #e2f5e9; color: var(--ok); }
.badge.bad { background: #fde8e8; color: var(--red); }
.badge.warn { background: #fef3e2; color: var(--warn); }
.badge.info { background: #e8ecf7; color: var(--blue); }
.banner { padding: 10px 14px; border-radius: 8px; font-size: 13px; display: none; white-space: pre-wrap; }
.banner.err { background: #fdecec; border: 1px solid #f5c2c2; color: #8f1d1d; display: block; }
.banner.ok { background: #e6f6ec; border: 1px solid #bfe5cd; color: #14532d; display: block; }
.stat { text-align: center; }
.stat .v { font-size: 22px; font-weight: 700; color: var(--blue); }
.stat .k { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.statrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
.tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--line); margin-bottom: 14px; flex-wrap: wrap; }
.tabs button { margin: 0; border-radius: 6px 6px 0 0; background: #e8ecf7; color: var(--ink); font-weight: 600; }
.tabs button.active { background: var(--blue); color: #fff; }
.tabpane { display: none; }
.tabpane.active { display: block; }
.kv { font-size: 13px; line-height: 1.9; }
.kv b { color: var(--muted); font-weight: 600; margin-right: 6px; }
#login-overlay {
  position: fixed; inset: 0; background: rgba(3, 20, 60, .92); display: flex;
  align-items: center; justify-content: center; z-index: 50;
}
#login-overlay .box { background: #fff; border-radius: 12px; padding: 30px 34px; width: 360px; }
#login-overlay h2 { color: var(--blue); font-size: 16px; }
#login-overlay p { font-size: 12.5px; color: var(--muted); margin-top: 6px; }
.small { font-size: 12px; color: var(--muted); }
.footer { text-align: center; color: var(--muted); font-size: 11.5px; padding: 20px 0 30px; }

/* ---------------------------------------------------------------- mobile fit
 * Measured on a 390px viewport: every page scrolled sideways. Two causes, both
 * easy to miss on a desktop browser.
 *
 * 1. The header nav was a non-wrapping flex row. It was already wider than a
 *    phone before the Connect wallet button was added, which then pushed it
 *    further out.
 *
 * 2. A grid or flex CHILD defaults to `min-width: auto`, meaning it refuses to
 *    shrink below the widest unbreakable thing inside it. One long command in a
 *    <pre>, or one 42-character address, and the whole card — and with it the
 *    page — grows past the screen. `overflow-x: auto` on the <pre> does nothing
 *    until the ancestor is allowed to be narrower than its content.
 */
header.site nav { flex-wrap: wrap; row-gap: 6px; }

main { min-width: 0; }
main > *,
.grid2 > *,
.statrow > * { min-width: 0; }

pre { max-width: 100%; overflow-x: auto; }
pre code { white-space: pre; }

/* Long hashes and addresses should wrap rather than widen their container. */
.mono, td.mono, .addr, .mono2 { overflow-wrap: anywhere; }

/* Wide tables scroll inside their own card instead of the page. */
.card table { max-width: 100%; }

/* The menu button only exists on narrow screens. */
.nav-toggle {
  display: none; margin: 0; padding: 4px 10px; border-radius: 7px; cursor: pointer;
  border: 1px solid rgba(255,255,255,.45); background: rgba(255,255,255,.12);
  color: #fff; font-size: 17px; line-height: 1.2; font-family: inherit;
}
.nav-toggle:hover { background: rgba(255,255,255,.22); }

.footer {
  text-align: center; color: var(--muted); font-size: 11.5px;
  padding: 20px 18px 30px; max-width: 720px; margin: 0 auto; line-height: 1.6;
}

/* ------------------------------------------------------------------ phones
 * Eight navigation links do not fit on a phone. Wrapping them produced two
 * cramped rows of ~22px tap targets that pushed the page content down; the
 * links collapse behind a menu button instead, and get a thumb-sized height
 * when stacked.
 *
 * `order` places things explicitly rather than relying on source order, because
 * the menu button is inserted by a script and lands in the DOM wherever that
 * script happens to run.
 */
@media (max-width: 760px) {
  header.site {
    padding: 11px 14px; align-items: center; gap: 8px 10px; position: relative;
  }
  /* Title and menu share one row. Connect wallet is not here at all — it sits
     at the top of the page body (see connect.js), because three controls never
     fitted across ~390px. */
  header.site h1 { font-size: 15.5px; order: 1; flex: 1 1 auto; min-width: 0; }
  header.site .sub { order: 3; flex: 1 0 100%; font-size: 11.5px; margin-top: -2px; }
  .nav-toggle { display: inline-block; order: 2; flex: 0 0 auto; }

  header.site nav {
    order: 5; flex: 1 0 100%; margin-left: 0; display: none;
    flex-direction: column; gap: 0; row-gap: 0;
    border-top: 1px solid rgba(255,255,255,.22); margin-top: 4px; padding-top: 2px;
  }
  header.site nav.open { display: flex; }

  main { padding: 0 14px; gap: 14px; margin: 16px auto; }
  .card { padding: 15px 16px; }
  .card h2 { font-size: 14.5px; }
  .grid2 { grid-template-columns: 1fr; gap: 14px; }
  .statrow { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
  .stat .v { font-size: 19px; }

  /* Inputs below 16px make iOS Safari zoom the page on focus. */
  input, select { font-size: 16px; }
  button { padding: 10px 16px; }

  table { font-size: 12.5px; }
  th, td { padding: 6px 6px; }
  .footer { padding: 18px 16px 26px; }
}

/* ---------------------------------------------------------------------------
 * Grouped navigation (rendered by shell.js).
 *
 * Twelve flat links told a visitor nothing about what the site does and did not
 * fit a phone. Seven groups do both jobs: fewer top-level targets, and each one
 * names an intention rather than a page.
 * ------------------------------------------------------------------------ */
/* flex, not block: an inline-flex button inside a block div sits on a line box
   whose strut (inherited 16px) adds descender space underneath, making the group
   37px tall against the links' 29px. The boxes then centre correctly while the
   TEXT sits visibly higher in the links than in the buttons. Making the group a
   flex container removes the line box entirely. */
/* The nav row is laid out by explicit height rather than by alignment.
 *
 * Three attempts at doing it with alignment failed: align-items:center on the
 * header, then on the nav, then align-self on the group. Measured, the group
 * stayed 41px tall against the links' 29px, with its button pinned to the
 * bottom — so the text sat visibly lower in the dropdown groups than in Home
 * and Admin, which is the ragged row people notice.
 *
 * A fixed 30px on every direct child, links and groups alike, makes the row
 * deterministic and puts every underline on the same line. */
header.site nav > a,
header.site nav > .nav-group,
header.site nav > .nav-group > .nav-group-btn {
  height: 30px; box-sizing: border-box; align-self: center;
}
/* Identical box model for links and group buttons. With padding doing the
   vertical centring the two disagreed by 6px — a <button>'s content box does not
   centre text the way an <a>'s does — so the height above does the work and
   both simply centre their content with no vertical padding at all. */
header.site nav > a,
header.site nav > .nav-group > .nav-group-btn {
  display: flex; align-items: center; justify-content: center;
  padding: 0 2px; line-height: 1;
  border-bottom: 2px solid transparent;
}
.nav-group { position: relative; display: flex; align-items: center; }
.nav-group-btn {
  color: #fff; font-size: 13.5px; opacity: .9; cursor: pointer;
  display: flex; align-items: center; gap: 4px; user-select: none;
  border-bottom: 2px solid transparent;
}
.nav-group-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 3px; }
.nav-group-btn:hover, .nav-group-btn.active { opacity: 1; border-bottom-color: var(--red); }
.nav-group-btn .caret { font-size: 9px; opacity: .75; transition: transform .15s; }
.nav-group.open .nav-group-btn .caret { transform: rotate(180deg); }

.nav-menu {
  display: none; position: absolute; right: 0; top: calc(100% + 8px); z-index: 60;
  min-width: 236px; background: #fff; border: 1px solid var(--line);
  border-radius: 10px; padding: 6px; box-shadow: 0 10px 28px rgba(15, 23, 42, .18);
}
.nav-group.open .nav-menu { display: block; }
.nav-menu a {
  display: block; padding: 8px 10px; border-radius: 7px; text-decoration: none;
  color: var(--ink); border-bottom: 0;
}
.nav-menu a:hover { background: #f1f4fa; border-bottom: 0; }
.nav-menu a.active { background: #e8ecf7; }
.nav-menu a .l { display: block; font-size: 13.5px; font-weight: 600; }
.nav-menu a .h { display: block; font-size: 11.5px; color: var(--muted); margin-top: 1px; line-height: 1.4; }

@media (max-width: 760px) {
  /* The desktop row is laid out by a fixed 30px height on every nav child. That
   * must NOT survive here: with the group pinned to 30px the open panel had
   * nowhere to go and rendered ON TOP of the items below it, which is what the
   * menu actually looked like on a phone. Stacked navigation needs the group to
   * grow when it opens.
   */
  header.site nav > a,
  header.site nav > .nav-group,
  header.site nav > .nav-group > .nav-group-btn {
    height: auto;
    align-self: stretch;
  }

  header.site nav { gap: 0; }

  /* Column, so the panel sits BELOW its button and pushes the rest down. */
  .nav-group { width: 100%; flex-direction: column; align-items: stretch; }

  /* Label left, caret right, and a 46px row — a thumb needs about 44px, and the
   * desktop's 30px is not close.
   *
   * These repeat the desktop selectors in full ON PURPOSE. The desktop rule is
   * `header.site nav > .nav-group > .nav-group-btn`, which outranks a bare
   * `.nav-group-btn` no matter that it comes later in the file — so the short
   * version silently lost and the labels stayed centred. */
  header.site nav > a,
  header.site nav > .nav-group > .nav-group-btn {
    justify-content: space-between;
    padding: 13px 2px;
    font-size: 15.5px;
    min-height: 46px;
    border-bottom: 1px solid rgba(255,255,255,.14);
  }
  header.site nav > a.active,
  header.site nav > .nav-group > .nav-group-btn.active { border-bottom-color: var(--red); }

  .nav-menu {
    display: none; position: static; min-width: 0; border: 0; box-shadow: none;
    border-radius: 0; padding: 0 0 6px 12px; background: rgba(0,0,0,.14);
  }
  .nav-group.open .nav-menu { display: block; }
  .nav-menu a {
    color: #fff; padding: 11px 10px; min-height: 44px;
    display: flex; flex-direction: column; justify-content: center;
  }
  .nav-menu a:hover, .nav-menu a.active { background: rgba(255,255,255,.16); }
  .nav-menu a .h { color: rgba(255,255,255,.72); }
}

/* ---------------------------------------------------------------------------
 * Long hex strings on narrow screens.
 *
 * A 42-character address has no break opportunity, so on a phone it pushes its
 * container wider than the viewport. Everything else here already fits: measured
 * at 500px, 760px and 1400px, documentElement.scrollWidth never exceeds
 * innerWidth and the menu button stays inside the viewport.
 * ------------------------------------------------------------------------ */
@media (max-width: 760px) {
  .mono, pre, code { overflow-wrap: anywhere; word-break: break-word; }
}
