/* ════════════════════════════════════════════════════════════════════════════
   km-ui.css — KeyMart shared design SYSTEM (single physical source of truth).
   ADR docs/adr/0001-shared-frontend-design-system-no-build.md (option C).

   Served by nginx `location /shared/` (one host copy at /opt/shared-frontend/),
   referenced — NOT copied — by every live page:
     /        index.html   (the console: live market + contracts)
     /wallet  wallet.html
     /logs    logs.html
     /admin   admin.html   (backoffice)
   via <link rel="stylesheet" href="/shared/km-ui.css?v=KM_VER">.

   v2 (2026-08-26): the console's design language is now THE design language.
     · Layer 1 — tokens. The v2 names (--bg/--fg/--clay/…) are canonical; the
       v1 names (--paper/--ink/--navy/--brass/--serif/…) are kept as ALIASES
       onto the same values so admin.html and any v1-era CSS restyle without
       a rewrite. --serif deliberately resolves to the UI sans: there is no
       serif anywhere in the product any more.
     · Layer 2 — base reset + primitives that never diverge.
     · Layer 3 — km- namespaced SHARED-COMPONENT classes whose MARKUP is
       rendered by exactly one function in km-kit.js (kmHeader / kmGate /
       kmToast / kmCheckReset). The console renders its own topbar markup with
       the SAME km- classes so the four pages share one header, pixel for pixel.

   tests/test_frontend_drift.py asserts no page re-inlines a :root token block,
   so this file stays the one source.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── Typefaces: SELF-HOSTED (2026-09-02). The page used to <link> them from
   fonts.googleapis.com, which is a black hole from mainland China — and a
   render-blocking stylesheet in <head> also blocks every <script> after it,
   so the whole console sat blank for ~28s per full reload (login/logout)
   until the connection timed out. Variable woff2, latin + latin-ext, served
   from /shared/fonts/ — no third-party request on the critical path. ── */
@font-face{font-family:'Inter';font-style:normal;font-weight:400 700;font-display:swap;src:url(/shared/fonts/inter-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 700;font-display:swap;src:url(/shared/fonts/inter-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 700;font-display:swap;src:url(/shared/fonts/jetbrains-mono-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 700;font-display:swap;src:url(/shared/fonts/jetbrains-mono-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}


:root{
  /* v2 — canonical */
  --bg:#F6F5F1; --surface:#FFFFFF; --panel:#FAF9F6;
  --fg:#201F1B; --fg2:#57544D; --fg3:#8B8780; --faint:#BDB9B1;
  --edge:#E6E3DC; --edge2:#F0EEE8;
  --clay:#BF5B38; --clay-d:#A84A28; --clay-soft:#F7ECE6; --clay-edge:#E0C0AF;
  --grn:#0E7A43; --grn-soft:#E8F2EC; --grn-edge:#BFD9CA;
  --err:#B3362B; --err-soft:#F9ECEA;
  --ui:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:'JetBrains Mono',ui-monospace,Menlo,monospace;
  /* v1 aliases — same values, old names (admin.html + legacy CSS) */
  --paper:var(--bg); --surface-2:var(--panel);
  --ink:var(--fg); --ink-2:var(--fg2); --ink-3:var(--fg3); --ink-faint:var(--faint);
  --line:var(--edge); --line-2:var(--edge2);
  --navy:var(--fg); --navy-d:#000000; --navy-soft:var(--edge2);
  --brass:var(--clay-d); --brass-soft:var(--clay-soft);
  --green:var(--grn); --red:var(--err);
  --sans:var(--ui); --serif:var(--ui);
  --shadow:0 1px 2px rgba(32,31,27,.04);
  --shadow-rail:0 1px 3px rgba(32,31,27,.05),0 8px 24px rgba(32,31,27,.04);
}
*{box-sizing:border-box;margin:0;padding:0}
a{color:var(--clay-d);text-decoration:none;cursor:pointer}
a:hover{text-decoration:underline;text-underline-offset:2px}
.tnum,.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
::selection{background:var(--clay-soft)}
:focus-visible{outline:2px solid var(--clay);outline-offset:1px;border-radius:3px}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ════ Layer 3 — km- shared components ════ */

/* kmHeader() → #km-header  (the console renders the same classes itself) */
.km-topbar{height:48px;display:flex;align-items:center;gap:14px;padding:0 20px;border-bottom:1px solid var(--edge);background:var(--surface);position:sticky;top:0;z-index:40;font-family:var(--ui)}
.km-brand{font-family:var(--mono);font-size:15.5px;font-weight:600;letter-spacing:-.02em;display:flex;align-items:center;gap:8px;color:var(--fg);text-decoration:none}
.km-brand:hover{text-decoration:none}
.km-brand .km-dot{width:9px;height:9px;background:var(--clay);display:inline-block;border-radius:2px}
.km-nav{display:flex;align-self:stretch;margin-left:16px}
.km-navlink{align-self:stretch;display:flex;align-items:center;font-family:var(--ui);font-size:14px;font-weight:600;color:var(--fg3);padding:0 3px;margin:0 11px;border:0;background:none;border-bottom:2px solid transparent;border-top:2px solid transparent;text-decoration:none;cursor:pointer}
.km-navlink:hover{color:var(--fg);text-decoration:none}
.km-navlink.on{color:var(--fg);border-bottom-color:var(--clay)}
.km-sp{flex:1}
/* D20: the address is a BUTTON (it opens the account panel), styled as the
   plain text chip it has always looked like. */
.km-acct{font-family:var(--mono);font-size:13px;color:var(--fg3);margin-right:14px;background:none;border:0;padding:0;cursor:pointer;line-height:1.4}
.km-acct:hover{color:var(--fg)}
/* D16: below 900 the bar has no room for an address, but the account entry
   itself must not vanish — the mail half is swapped for the short one. */
.km-acct-short{display:none}
.km-bal{font-family:var(--mono);font-size:13px;color:var(--fg2);text-decoration:none}
.km-bal:hover{text-decoration:none}
.km-bal b{color:var(--fg);font-weight:600}
.km-tbtn{font-family:var(--ui);font-size:13.5px;font-weight:600;color:var(--fg2);background:none;border:1px solid var(--edge);border-radius:6px;padding:5px 13px;cursor:pointer;text-decoration:none;line-height:1.4}
.km-tbtn:hover{border-color:var(--fg3);color:var(--fg);text-decoration:none}
.km-tbtn.pri{background:var(--fg);border-color:var(--fg);color:var(--surface)}
.km-tbtn.pri:hover{opacity:.88;color:var(--surface)}

/* kmGate() → #km-gate · kmCheckReset() → #km-reset */
.km-modal-bg{position:fixed;inset:0;background:rgba(32,31,27,.42);backdrop-filter:blur(2px);display:none;align-items:center;justify-content:center;z-index:100}
.km-modal-bg.show{display:flex}
.km-modal{width:380px;max-width:calc(100vw - 32px);background:var(--surface);border:1px solid var(--edge);border-radius:10px;box-shadow:0 24px 60px -20px rgba(32,31,27,.35);position:relative;max-height:90vh;overflow:auto;font-family:var(--ui);font-size:14px;color:var(--fg);line-height:1.5}
.km-modal-x{position:absolute;top:12px;right:16px;font-size:22px;color:var(--faint);line-height:1;cursor:pointer}
.km-modal-x:hover{color:var(--fg)}
.km-modal-h{padding:22px 24px 16px;border-bottom:1px solid var(--edge)}
.km-modal-h h2{font-family:var(--ui);font-size:17px;font-weight:600;letter-spacing:-.01em}
.km-sub{font-size:13.5px;color:var(--fg3);margin-top:3px}
.km-modal-b{padding:20px 24px 22px}
.km-modal-b input{width:100%;font-family:var(--ui);font-size:14.5px;height:40px;padding:0 12px;border:1px solid var(--edge);border-radius:6px;background:var(--surface);color:var(--fg);outline:0;margin-bottom:10px}
.km-modal-b input:focus{border-color:var(--clay);box-shadow:0 0 0 3px var(--clay-soft)}
.km-err{color:var(--err);font-size:12.5px;min-height:17px;margin-bottom:6px}
.km-msg{display:none;color:var(--grn);font-size:12.5px;margin:4px 0;line-height:1.5}
.km-toggle{font-size:13.5px;color:var(--fg2);text-align:center;margin-top:14px}
.km-btn{display:block;width:100%;font-family:var(--ui);font-size:14.5px;font-weight:600;height:40px;background:var(--fg);color:var(--surface);border:0;border-radius:6px;cursor:pointer}
.km-btn:hover{opacity:.88}
.km-btn:disabled{opacity:.5;cursor:default}

/* kmToast() → #km-toast */
.km-toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(80px);background:var(--fg);color:var(--surface);padding:10px 18px;border-radius:6px;font-size:13.5px;font-family:var(--ui);opacity:0;transition:.22s;z-index:300;box-shadow:0 12px 32px -8px rgba(32,31,27,.35);pointer-events:none}
.km-toast.show{transform:translateX(-50%) translateY(0);opacity:1}
.km-toast.err{background:var(--err)}

/* kmFooter() → <footer class="km-foot">  (E12 · the public footer)
   One row of quiet links under every public page. `flex-wrap` is what keeps a
   390px phone from being pushed sideways by five destinations plus an address:
   the row becomes two rows instead of a document that scrolls horizontally. */
.km-foot{display:flex;flex-wrap:wrap;align-items:center;gap:6px 20px;margin-top:56px;
  padding:18px 0 34px;border-top:1px solid var(--edge);font-family:var(--ui);
  font-size:12.5px;color:var(--fg3)}
.km-foot a{color:var(--fg3);font-weight:500}
.km-foot a:hover{color:var(--fg)}

/* the gate's consent row (E12): checkbox + one sentence, aligned at the top so
   a wrapped sentence does not drag the box down with it. */
.km-consent{display:flex;align-items:flex-start;gap:8px;margin:2px 0 10px;
  font-size:12.5px;line-height:1.45;color:var(--fg2);cursor:pointer}
.km-consent input{width:15px;height:15px;margin:1px 0 0;flex:0 0 auto;accent-color:var(--clay)}

/* D16 (2026-09-11): below 900 the bar is allowed to wrap. It used to be a
   nowrap row that simply ran off the side of a 700px window once the account
   entry and the Key button were added to it; flex-wrap turns the surplus into a
   second row instead of into a document that scrolls sideways. One row still
   measures 48px, which is what the rails are offset by. */
@media(max-width:900px){
  .km-topbar{height:auto;min-height:48px;flex-wrap:wrap;padding:5px 14px;gap:10px;row-gap:6px}
  .km-navlink{margin:0 7px}
  .km-acct-mail{display:none}
  .km-acct-short{display:inline}
}

/* Phone (≤640px). The single non-wrapping row needs 571px, so at 390 the
   balance (448–504) and Sign out / Sign in (514–571) sat OUTSIDE the viewport
   — and body{overflow-x:hidden} clipped them rather than letting the page
   scroll to them, i.e. untappable on every console route. The smallest honest
   fix: let the bar wrap and send the nav strip to its own full-width second
   row, so row one is brand + balance + the session button, all inside 390.
   The nav row scrolls inside itself if a future link makes it too long, so
   the topbar can never push the document sideways again. Nothing at or above
   641px is touched: the desktop bar is the same 48px single row it was. */
@media(max-width:640px){
  .km-topbar{height:auto;flex-wrap:wrap;gap:8px;padding:7px 12px}
  .km-nav{order:5;width:100%;margin-left:0;align-self:auto;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}
  .km-nav::-webkit-scrollbar{display:none}
  .km-navlink{align-self:auto;flex:0 0 auto;padding:5px 3px;margin:0 10px 0 0}
  .km-navlink:first-child{margin-left:0}
  .km-acct{margin-right:0}
}
