/* Dino Proxy — professional design system.
   Be Vietnam Pro (rounded, full Vietnamese support) · high-contrast ink on
   light neutral · Dino Proxy green used purposefully · tight spacing. */
:root {
  /* DEFAULT THEME = Clean White (his pick, 2026-10-12). Every color on the
     site flows through these tokens; per-user themes override the tokens
     under [data-theme="..."] below — never hardcode a surface color. */
  color-scheme: light;
  --bg: #f4f6f8;
  --card: #ffffff;
  --ink: #171a1f;
  --muted: #5c6670;
  --line: #e2e6ea;
  --accent: #0f7a3d;
  --accent-dark: #0b5c2e;
  --accent-soft: #e8f5ec;
  --warn: #b45309;
  --danger: #b91c1c;
  --nav-ink: #3c4652;
  --surface2: #eceff1;
  --surface3: #dfe4e7;
  --band: #eceff1;
  --band-line: #d7dde1;
  --on-accent: #ffffff;
  --tabbar-bg: rgba(255,255,255,.96);
  --radius: 10px;
  /* order-status accent palette */
  --st-new: #2563eb;
  --st-shipping_us: #4f46e5;
  --st-arrived: #0d9488;
  --st-weighed: #d97706;
  --st-shipped_vn: #7c3aed;
  --st-arrived_vn: #0284c7;
  --st-delivered: #16a34a;
  --st-cancelled: #dc2626;
}
/* Ocean Slate — light theme (per-user choice) */
[data-theme="ocean"] {
  color-scheme: light;
  --bg: #edf2f5; --card: #ffffff; --ink: #132029; --muted: #5a6d78; --line: #d9e4e9;
  --accent: #1d6fa5; --accent-dark: #175a87; --accent-soft: #e2eef5;
  --nav-ink: #3a4f5c; --surface2: #e2eef5; --surface3: #d3e2ea;
  --band: #dcebf2; --band-line: #bfd9e4; --on-accent: #ffffff;
  --tabbar-bg: rgba(255,255,255,.96);
}
/* Coffee Cream — light theme (per-user choice) */
[data-theme="coffee"] {
  color-scheme: light;
  --bg: #f1e7d3; --card: #fffaf0; --ink: #2b1d11; --muted: #7d6c57; --line: #e3d5b8;
  --accent: #9c6b30; --accent-dark: #7c5222; --accent-soft: #f3e8d2;
  --nav-ink: #54432c; --surface2: #f3e8d2; --surface3: #ead9b8;
  --band: #e9dcbc; --band-line: #d8c69a; --on-accent: #ffffff;
  --tabbar-bg: rgba(255,250,240,.96);
}
/* Dino Dark — reached via the Auto light/dark toggle when the device is in
   dark mode (his spec, 2026-10-12). */
[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f1310; --card: #171c18; --ink: #e8ede9; --muted: #9ba79d; --line: #2b332c;
  --accent: #34c26e; --accent-dark: #57d68d; --accent-soft: #1e2a21;
  --warn: #f5b84c; --danger: #ff7b72;
  --nav-ink: #c3cec4; --surface2: #1e2a21; --surface3: #2b332c;
  --band: #222b23; --band-line: #33402f; --on-accent: #07130c;
  --tabbar-bg: rgba(23,28,24,.96);
  --st-new: #5b93ff; --st-shipping_us: #8f88ff; --st-arrived: #2dd4bf;
  --st-weighed: #f5b84c; --st-shipped_vn: #b7a6ff; --st-arrived_vn: #4fc3f7;
  --st-delivered: #4ade80; --st-cancelled: #ff8f8f;
}
/* Glass Light — frosted glass over a vibrant backdrop (per-user choice,
   2026-11-02). Cards/nav go translucent + blurred; the body background IS
   the colorful layer the glass blurs against. Card alpha 0.72 keeps dark
   ink readable over the blurred blobs. */
[data-theme="glass"] {
  color-scheme: light;
  --bg:
    radial-gradient(640px 420px at 12% -5%, rgba(52,194,110,.50), transparent 62%),
    radial-gradient(520px 400px at 92% 8%, rgba(29,111,165,.44), transparent 62%),
    radial-gradient(760px 520px at 50% 115%, rgba(124,58,237,.34), transparent 62%),
    #e9eff4;
  --card: rgba(255,255,255,.72);
  --ink: #171a1f; --muted: #55606b; --line: rgba(255,255,255,.7);
  --accent: #0f7a3d; --accent-dark: #0b5c2e; --accent-soft: rgba(15,122,61,.10);
  --nav-ink: #3c4652; --surface2: rgba(255,255,255,.55); --surface3: rgba(255,255,255,.4);
  --band: rgba(255,255,255,.5); --band-line: rgba(255,255,255,.6); --on-accent: #ffffff;
  --tabbar-bg: rgba(255,255,255,.65);
}
/* Glass Dark — the dark side of Glass (auto mode at night, or a fixed
   pick). Same recipe, smoked-glass surfaces over a deep vibrant backdrop. */
[data-theme="glass-dark"] {
  color-scheme: dark;
  --bg:
    radial-gradient(640px 420px at 12% -5%, rgba(52,194,110,.36), transparent 62%),
    radial-gradient(520px 400px at 92% 8%, rgba(29,111,165,.34), transparent 62%),
    radial-gradient(760px 520px at 50% 115%, rgba(124,58,237,.28), transparent 62%),
    #0b1114;
  --card: rgba(20,28,34,.62);
  --ink: #e9eef1; --muted: #9fb0ba; --line: rgba(255,255,255,.14);
  --accent: #34c26e; --accent-dark: #57d68d; --accent-soft: rgba(52,194,110,.14);
  --warn: #f5b84c; --danger: #ff7b72;
  --nav-ink: #c9d4da; --surface2: rgba(255,255,255,.08); --surface3: rgba(255,255,255,.12);
  --band: rgba(255,255,255,.06); --band-line: rgba(255,255,255,.12); --on-accent: #07130c;
  --tabbar-bg: rgba(16,24,30,.6);
  --st-new: #5b93ff; --st-shipping_us: #8f88ff; --st-arrived: #2dd4bf;
  --st-weighed: #f5b84c; --st-shipped_vn: #b7a6ff; --st-arrived_vn: #4fc3f7;
  --st-delivered: #4ade80; --st-cancelled: #ff8f8f;
}
/* Glass Dark: status tints + alert boxes get dark variants (same pairs as
   Dino Dark — the light-theme pastels are unreadable on smoked glass). */
[data-theme="glass-dark"] .badge.new, [data-theme="glass-dark"] .chip.new { background: #1c2a4a; color: #7db1ff; }
[data-theme="glass-dark"] .badge.pending, [data-theme="glass-dark"] .badge.weighed, [data-theme="glass-dark"] .badge.sent, [data-theme="glass-dark"] .badge.unpaid,
[data-theme="glass-dark"] .chip.weighed { background: #3a2f10; color: #f5c451; }
[data-theme="glass-dark"] .badge.shipping_us, [data-theme="glass-dark"] .chip.shipping_us { background: #262450; color: #a8b0ff; }
[data-theme="glass-dark"] .badge.arrived, [data-theme="glass-dark"] .chip.arrived { background: #0e2a26; color: #4fd1bd; }
[data-theme="glass-dark"] .badge.shipped_vn, [data-theme="glass-dark"] .chip.shipped_vn { background: #2a2145; color: #b7a6ff; }
[data-theme="glass-dark"] .badge.arrived_vn, [data-theme="glass-dark"] .chip.arrived_vn { background: #0f2c3d; color: #5ec2f2; }
[data-theme="glass-dark"] .badge.delivered, [data-theme="glass-dark"] .badge.accepted, [data-theme="glass-dark"] .badge.paid,
[data-theme="glass-dark"] .chip.delivered { background: #14301d; color: #5ed38a; }
[data-theme="glass-dark"] .badge.cancelled, [data-theme="glass-dark"] .badge.void, [data-theme="glass-dark"] .badge.declined,
[data-theme="glass-dark"] .chip.cancelled { background: #3a1d1d; color: #ff9c9c; }
[data-theme="glass-dark"] .badge.draft { background: #26262a; color: #b8b4ae; }
[data-theme="glass-dark"] .badge.discord { background: #262a4d; color: #a5b0ff; }
[data-theme="glass-dark"] .badge.mod { background: #3d2410; color: #fdba74; }
[data-theme="glass-dark"] .alert.error { background: #3a1d1d; border-color: #6e2f2f; color: #ff9c9c; }
[data-theme="glass-dark"] .alert.ok { background: #14301d; border-color: #245534; color: #5ed38a; }
[data-theme="glass-dark"] .alert.info { background: #16294d; border-color: #2c4a7c; color: #8ab6ff; }
[data-theme="glass-dark"] .alert.warn { background: #33290e; border-color: #6b5518; color: #ffd97a; }
[data-theme="glass-dark"] .btn.danger { background: #b91c1c; color: #fff; }
/* Glass blur — the frosted layer itself. Main surfaces only: inputs and
   long-form text stay on the (already translucent) card, never on a
   second blur layer. -webkit- prefix is for Safari. */
[data-theme="glass"] .card, [data-theme="glass"] .dash-card, [data-theme="glass"] .deal-card, [data-theme="glass"] .step, [data-theme="glass"] .balance-banner, [data-theme="glass"] .event-row, [data-theme="glass"] .nav, [data-theme="glass"] .statusbar, [data-theme="glass"] body.logged-in .sheet,
[data-theme="glass-dark"] .card, [data-theme="glass-dark"] .dash-card, [data-theme="glass-dark"] .deal-card, [data-theme="glass-dark"] .step, [data-theme="glass-dark"] .balance-banner, [data-theme="glass-dark"] .event-row, [data-theme="glass-dark"] .nav, [data-theme="glass-dark"] .statusbar, [data-theme="glass-dark"] body.logged-in .sheet {
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  backdrop-filter: blur(16px) saturate(1.5);
}
[data-theme="glass"] .card { box-shadow: 0 10px 30px rgba(15,30,50,.12); }
[data-theme="glass-dark"] .card { box-shadow: 0 10px 30px rgba(0,0,0,.35); }
/* Glass-only definition fixes: --line is luminous-white on purpose (the
   glass edge), so nav, secondary buttons and field borders — which need a
   real edge against the card — get their own darker/lighter border here.
   Other themes are untouched. */
[data-theme="glass"] .nav { border-bottom-color: rgba(23,26,31,.14); }
[data-theme="glass-dark"] .nav { border-bottom-color: rgba(255,255,255,.18); }
[data-theme="glass"] .btn.secondary { border: 1px solid rgba(23,26,31,.20); }
[data-theme="glass-dark"] .btn.secondary { border: 1px solid rgba(255,255,255,.22); }
[data-theme="glass"] input[type=text], [data-theme="glass"] input[type=email], [data-theme="glass"] input[type=password], [data-theme="glass"] input[type=number], [data-theme="glass"] input[type=url], [data-theme="glass"] input[type=date], [data-theme="glass"] input[type=datetime-local], [data-theme="glass"] input[type=time], [data-theme="glass"] select, [data-theme="glass"] textarea { border-color: rgba(23,26,31,.20); }
[data-theme="glass-dark"] input[type=text], [data-theme="glass-dark"] input[type=email], [data-theme="glass-dark"] input[type=password], [data-theme="glass-dark"] input[type=number], [data-theme="glass-dark"] input[type=url], [data-theme="glass-dark"] input[type=date], [data-theme="glass-dark"] input[type=datetime-local], [data-theme="glass-dark"] input[type=time], [data-theme="glass-dark"] select, [data-theme="glass-dark"] textarea { border-color: rgba(255,255,255,.22); }
/* No backdrop-filter support at all → solid surfaces, same tokens otherwise. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  [data-theme="glass"] { --card: #ffffff; --surface2: #f2f5f7; --surface3: #e6ebef; --band: #eef2f5; --tabbar-bg: rgba(255,255,255,.96); }
  [data-theme="glass-dark"] { --card: #171e24; --surface2: #1c262d; --surface3: #243038; --band: #1a242b; --tabbar-bg: rgba(23,30,36,.96); }
}
/* Dino Dark: status tints + alert boxes get dark variants (the pastel pairs
   above are light-theme only). */
[data-theme="dark"] .badge.new, [data-theme="dark"] .chip.new { background: #1c2a4a; color: #7db1ff; }
[data-theme="dark"] .badge.pending, [data-theme="dark"] .badge.weighed, [data-theme="dark"] .badge.sent, [data-theme="dark"] .badge.unpaid,
[data-theme="dark"] .chip.weighed { background: #3a2f10; color: #f5c451; }
[data-theme="dark"] .badge.shipping_us, [data-theme="dark"] .chip.shipping_us { background: #262450; color: #a8b0ff; }
[data-theme="dark"] .badge.arrived, [data-theme="dark"] .chip.arrived { background: #0e2a26; color: #4fd1bd; }
[data-theme="dark"] .badge.shipped_vn, [data-theme="dark"] .chip.shipped_vn { background: #2a2145; color: #b7a6ff; }
[data-theme="dark"] .badge.arrived_vn, [data-theme="dark"] .chip.arrived_vn { background: #0f2c3d; color: #5ec2f2; }
[data-theme="dark"] .badge.delivered, [data-theme="dark"] .badge.accepted, [data-theme="dark"] .badge.paid,
[data-theme="dark"] .chip.delivered { background: #14301d; color: #5ed38a; }
[data-theme="dark"] .badge.cancelled, [data-theme="dark"] .badge.void, [data-theme="dark"] .badge.declined,
[data-theme="dark"] .chip.cancelled { background: #3a1d1d; color: #ff9c9c; }
[data-theme="dark"] .badge.draft { background: #26262a; color: #b8b4ae; }
[data-theme="dark"] .badge.discord { background: #262a4d; color: #a5b0ff; }
[data-theme="dark"] .badge.mod { background: #3d2410; color: #fdba74; }
[data-theme="dark"] .alert.error { background: #3a1d1d; border-color: #6e2f2f; color: #ff9c9c; }
[data-theme="dark"] .alert.ok { background: #14301d; border-color: #245534; color: #5ed38a; }
[data-theme="dark"] .alert.info { background: #16294d; border-color: #2c4a7c; color: #8ab6ff; }
[data-theme="dark"] .alert.warn { background: #33290e; border-color: #6b5518; color: #ffd97a; }
[data-theme="dark"] .btn.danger { background: #b91c1c; color: #fff; }
* { box-sizing: border-box; }
/* Lock text sizing: without this, iOS Safari inflates text inside wide
   (scrollable) tables — the homepage pricing table renders oversized. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* No sideways page scroll: clip (not hidden) keeps inner scrollers and
   absolutely-positioned menus working while stray wide content can no
   longer push the page sideways on mobile. */
html, body { overflow-x: clip; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-size: 16px;
  font-family: "Be Vietnam Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  line-height: 1.5;
}
::selection { background: #c9ecd4; }
a { color: var(--accent); }
.mono { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
code, pre, kbd, samp { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
.container { max-width: 1440px; margin: 0 auto; padding: 0 24px; }
.container.narrow { max-width: 820px; }
/* Auth pages (login / signup): on medium and large screens the whole
   column — heading, alerts and the form card — centers as one 480px
   column instead of hugging the left edge of the narrow container.
   Mobile keeps the natural full-width flow (owner, 2026-10-19). */
@media (min-width: 641px) {
  .auth-col { max-width: 480px; margin-inline: auto; }
}

/* nav — light, professional */
.nav { background: var(--card); border-bottom: 1px solid var(--line); color: var(--ink); }
.nav-inner { display: flex; align-items: center; gap: 12px; padding: 10px 24px; max-width: 1440px; margin: 0 auto; flex-wrap: wrap; }
.brand { color: var(--ink); text-decoration: none; font-weight: 800; font-size: 18px; letter-spacing: .2px; display: inline-flex; align-items: center; gap: 8px; }
.brand-logo { width: 34px; height: 34px; border-radius: 8px; }
.brand small { font-weight: 500; color: var(--muted); font-size: 12px; margin-left: 6px; }
.nav-links { display: flex; gap: 2px; margin-left: auto; align-items: center; flex-wrap: wrap; }
.nav-links a, .nav-links button.linklike {
  color: var(--nav-ink); text-decoration: none; padding: 6px 10px; border-radius: 8px;
  background: none; border: none; font-size: 15px; font-weight: 500; cursor: pointer;
  line-height: 1.5;
}
.nav-links a:hover, .nav-links button.linklike:hover { background: var(--surface2); color: var(--ink); }
.nav-user { color: var(--muted); font-size: 14px; margin-right: 4px; }
.nav-links a.active { background: var(--accent-soft); color: var(--accent-dark); font-weight: 700; }

/* desktop dropdown menus */
.nav-drop { position: relative; }
.nav-drop-btn {
  color: var(--nav-ink); background: none; border: none; font-size: 15px; font-weight: 500;
  padding: 6px 10px; border-radius: 8px; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  /* match the plain nav links' line-height — without it buttons fall back to
     the UA's line-height:normal, making their box ~3px shorter and their text
     sit ~2px lower than the links in the centered flex row (2026-10-12) */
  line-height: 1.5;
}
.nav-drop-btn:hover { background: var(--surface2); color: var(--ink); }
.nav-drop-btn.active { background: var(--accent-soft); color: var(--accent-dark); font-weight: 700; }
.nav-drop-btn .caret { font-size: 19px; line-height: 1; font-weight: 700; margin-left: 2px; }
.nav-drop-menu {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; z-index: 80;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12); padding: 6px; min-width: 210px;
}
.nav-drop:hover .nav-drop-menu, .nav-drop:focus-within .nav-drop-menu { display: block; }
/* invisible bridge over the gap between button and menu, so the menu
   doesn't snap shut while the mouse travels down to it */
.nav-drop-menu::before {
  content: ""; position: absolute; top: -10px; left: 0; right: 0; height: 10px;
}
.nav-drop-menu a, .nav-drop-menu .linklike {
  display: flex; align-items: center; gap: 8px; width: 100%; box-sizing: border-box;
  padding: 8px 12px; border-radius: 8px; color: var(--nav-ink); text-decoration: none;
  font-size: 15px; font-weight: 500; background: none; border: none; cursor: pointer;
  font-family: inherit; text-align: left; white-space: nowrap;
}
.nav-drop-menu a:hover, .nav-drop-menu .linklike:hover { background: var(--surface2); color: var(--ink); }
.nav-drop-menu a.active { background: var(--accent-soft); color: var(--accent-dark); font-weight: 700; }
.nav-drop-menu form { margin: 0; }
/* hairline between dropdown items (his ask, 2026-10-15) */
.nav-drop-menu > * + * { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 4px; }
.nav-account { margin-left: auto; }
.nav-account .nav-drop-menu { left: auto; right: 0; }

/* hamburger — small viewports only */
.nav-toggle {
  display: none;
  margin-left: auto;
  background: none; border: none; color: var(--ink);
  font-size: 24px; line-height: 1;
  padding: 6px 10px; border-radius: 8px; cursor: pointer;
}
.nav-toggle:hover { background: var(--surface2); }
.nav-group { display: contents; }
.nav-group-label { display: none; }

/* Inline SVG icons (components/Icon.astro) — baseline alignment in inline contexts. */
svg.ic { vertical-align: -0.16em; flex: none; }
@media (max-width: 760px) {
  .nav-inner { flex-wrap: nowrap; position: relative; }
  .nav-toggle { display: inline-block; }
  .nav-links {
    display: none;
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch;
    background: var(--card); color: var(--ink);
    margin: 0; padding: 8px 12px 12px;
    border-top: 1px solid var(--line);
    box-shadow: 0 12px 24px rgba(0,0,0,.12);
    z-index: 50;
  }
  .nav.open .nav-links { display: flex; }
  .nav-group { display: flex; flex-direction: column; }
  .nav-group + .nav-group { border-top: 1px solid var(--line); margin-top: 8px; padding-top: 8px; }
  .nav-group-label {
    display: block;
    font-size: 12px; text-transform: uppercase; letter-spacing: .08em;
    color: var(--muted); padding: 8px 10px 2px;
  }
  .nav-links a { padding: 10px 12px; font-size: 16px; }
  .nav-account { flex-direction: row; align-items: center; justify-content: space-between; }
  .nav-user { margin: 0; padding: 8px 10px; font-size: 14px; }
}

/* layout */
main.container { padding-top: 16px; padding-bottom: 48px; }
.footer { text-align: center; color: var(--muted); font-size: 14px; padding: 20px 0 32px; }

h1 { font-size: 23px; margin: 0 0 10px; font-weight: 800; letter-spacing: -.01em; }
h2 { font-size: 19px; margin: 20px 0 8px; font-weight: 700; }
h3 { font-size: 16px; margin: 16px 0 6px; font-weight: 700; }

.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px; margin-bottom: 12px; box-shadow: 0 1px 2px rgba(16,24,16,.05);
}
.muted { color: var(--muted); }
.small { font-size: 14px; }
.link-chip { flex: 1; min-width: 220px; padding: 8px 10px; background: var(--bg); border: 1px solid var(--line); border-radius: 8px; overflow-x: auto; white-space: nowrap; }

/* forms */
label { display: block; font-weight: 600; margin: 10px 0 4px; font-size: 15px; }
input[type=text], input[type=email], input[type=password], input[type=number], input[type=url], select, textarea {
  width: 100%; min-width: 0; max-width: 100%; padding: 9px 12px; border: 1px solid var(--line); border-radius: 8px;
  font-size: 16px; font-family: inherit; background: var(--card); color: var(--ink);
  /* Pinned so a field's total height equals .btn's (44px desktop):
     24 content + 18 padding + 2 border. The ≤640px block re-pins it
     against the smaller mobile button. Font stays 16px (anti-zoom). */
  line-height: 24px;
}
/* Single-line fields: native control appearance OFF — iOS Safari sizes
   appearance:auto fields itself and ignores line-height/height, which is
   why fields rendered taller than buttons there. With appearance off,
   the border-box height pins exactly to .btn's (44px desktop, 38px in
   the ≤640px block). Selects get a drawn chevron to replace the native
   one. Textareas and file inputs keep native rendering (multi-line /
   picker controls are never button-paired). */
input[type=text], input[type=email], input[type=password], input[type=number], input[type=url], select {
  -webkit-appearance: none; appearance: none; height: 44px;
}
select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center; padding-right: 34px;
}
/* Flex rows that pair fields with buttons: flex-end alignment compares
   MARGIN boxes, so a label's bottom margin (or a button's top margin)
   makes the button sit below its field. Zero both inside these rows. */
.inline-form label, .filters label { margin-bottom: 0; }
.inline-form .btn, .filters .btn { margin-top: 0; }
/* Date/time pickers: WebKit won't shrink their internal segments below an
   intrinsic width, so full-width stretches overflow on phones. Natural width
   with the same field styling instead. */
input[type=date], input[type=datetime-local], input[type=time] {
  width: auto; min-width: 0; max-width: 100%; padding: 9px 12px; border: 1px solid var(--line); border-radius: 8px;
  font-size: 16px; font-family: inherit; background: var(--card); color: var(--ink);
}
/* File pickers: style the native control to match the design system */
input[type=file] {
  width: 100%; max-width: 100%; padding: 7px 10px; border: 1px solid var(--line); border-radius: 8px;
  font-size: 15px; font-family: inherit; background: var(--card); color: var(--ink);
}
input[type=file]::file-selector-button {
  background: var(--surface2); color: var(--ink); border: none; border-radius: 6px;
  padding: 7px 14px; margin-right: 12px; font-size: 14px; font-weight: 600; font-family: inherit; cursor: pointer;
  /* Line-height pinned (owner, 2026-10-19): unpinned, the button height fell
     out of font metrics (26px) while the mobile field's inner space is 28px,
     and WebKit parks the button at the top of that space — the button sat 1px
     high (4px gap above, 6px below). At 20px the button is exactly 34px on
     desktop and exactly 28px on mobile, filling the space symmetrically. */
  line-height: 20px;
}
input[type=file]::file-selector-button:hover { background: var(--surface3); }
/* Filter-bar buttons: full height to match the inputs they sit beside */
.filters .btn { padding: 10px 18px; font-size: 16px; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
textarea { min-height: 84px; resize: vertical; }
input[type=checkbox], input[type=radio] { width: 20px; height: 20px; accent-color: var(--accent); cursor: pointer; vertical-align: -4px; flex-shrink: 0; }
.hint { color: var(--muted); font-size: 14px; margin-top: 4px; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.row > div { min-width: 0; }
@media (max-width: 640px) { .row { grid-template-columns: 1fr; } }

.btn {
  display: inline-block; background: var(--accent); color: var(--on-accent); border: none;
  padding: 10px 18px; border-radius: 8px; font-size: 16px; font-weight: 600; font-family: inherit;
  cursor: pointer; text-decoration: none; margin-top: 12px;
}
.btn:hover { background: var(--accent-dark); color: var(--on-accent); }
.btn.secondary { background: var(--surface2); color: var(--ink); }
.btn.secondary:hover { background: var(--surface3); }
.btn.danger { background: var(--danger); }
.btn.small-btn { padding: 6px 12px; font-size: 14px; margin-top: 0; }
.btn:disabled { opacity: .55; cursor: default; }

.alert { padding: 10px 14px; border-radius: 8px; margin-bottom: 12px; font-size: 15px; }
.alert.error { background: #fdecec; border: 1px solid #f3c1c1; color: #7f1d1d; }
.alert.ok { background: #e9f7ef; border: 1px solid #bfe6cd; color: #0b5c2e; }
.alert.info { background: #eef4ff; border: 1px solid #c9dafc; color: #1e3a8a; }
.alert.warn { background: #fdf3e0; border: 1px solid #f0dcae; color: #71460a; }

/* status badges */
.badge {
  display: inline-block; padding: 2px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 700; white-space: nowrap;
}
.badge.new { background: #dbeafe; color: #1d4ed8; }
.badge.pending { background: #fef3c7; color: #92400e; }
.badge.shipping_us { background: #e0e7ff; color: #4338ca; }
.badge.arrived { background: #ccfbf1; color: #0f766e; }
.badge.weighed { background: #fef3c7; color: #92400e; }
.badge.shipped_vn { background: #ede9fe; color: #6d28d9; }
.badge.arrived_vn { background: #e0f2fe; color: #0369a1; }
.badge.delivered { background: #dcfce7; color: #15803d; }
.badge.cancelled { background: #fee2e2; color: #b91c1c; }
.badge.draft { background: #e7e5e4; color: #57534e; }
.badge.discord { background: #e1e4fd; color: #3d46b8; }
.badge.mod { background: #ffedd5; color: #c2410c; }
.badge.sent { background: #fef3c7; color: #92400e; }
.badge.accepted { background: #dcfce7; color: #15803d; }
.badge.declined { background: #fdecec; color: #7f1d1d; }
.badge.void { background: #fee2e2; color: #b91c1c; }

/* tables */
table { width: 100%; border-collapse: collapse; font-size: 15px; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
th { color: var(--muted); font-weight: 600; font-size: 13px; text-transform: uppercase; letter-spacing: .4px; }
/* The last body row never carries a bottom border — inside a card it
   would double up with the card's own bottom edge (owner rule,
   2026-10-22). One selector per border source below, each specific
   enough to beat its base rule (.otable td, .docs-section td). */
tbody tr:last-child > td,
.otable tbody tr:last-child > td,
.docs-section tbody tr:last-child > td { border-bottom: none; }

/* kanban */
.kanban { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 10px; align-items: flex-start; }
/* Column well: the surface2 tint alone sits too close to --bg in the light
   themes (worst in Coffee, where it is nearly the same cream), so empty
   columns dissolved into the page. The 1px var(--line) border + hairline
   shadow — the same treatment .card uses — bounds every column in every
   theme regardless of how subtle the tint is (owner's phone, 2026-10-19). */
.kcol { min-width: 250px; max-width: 290px; flex: 1; background: var(--surface2); border: 1px solid var(--line); border-radius: var(--radius); padding: 8px; box-shadow: 0 1px 2px rgba(16,24,16,.05); }
.kcol h3 { margin: 2px 4px 8px; font-size: 15px; display: flex; justify-content: space-between; align-items: center; }
.kcol h3 .count { background: var(--card); border: 1px solid var(--line); border-radius: 999px; padding: 0 8px; font-size: 12px; }
.kcard {
  background: var(--card); border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 10px; margin-bottom: 8px; font-size: 14px;
}
.kcard a.code { font-weight: 700; text-decoration: none; font-family: "JetBrains Mono", ui-monospace, Menlo, monospace; font-size: 14px; }
.kcard .item { font-weight: 600; margin: 3px 0; }
.kcard .meta { color: var(--muted); font-size: 13px; }
/* Tracking numbers are long unbroken strings that WebKit refuses to
   wrap — the line truncates with an ellipsis instead of overflowing the
   card (his call, 2026-10-19). The full number is on the order page. */
.kcard .trk { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Customer list (his asks, 2026-10-19): a wider name column, and cells
   vertically centered so the order count lines up with the name block
   instead of hugging the top. The Discord handle is a quiet meta line
   under the name (option A) — pills are for status (Mod), not info. */
.cust-list th:first-child, .cust-list td:first-child { min-width: 210px; }
.cust-list th, .cust-list td { vertical-align: middle; }
.cust-list .dc-meta { display: inline-block; margin-top: 3px; font-size: 12px; font-weight: 600; color: var(--muted); white-space: nowrap; }
.kcard .total { font-weight: 700; color: var(--accent-dark); margin-top: 4px; }

/* status accent: colored top strip + full border in the status color */
.st-new { border: 1px solid var(--st-new); border-top: 5px solid var(--st-new); }
.st-shipping_us { border: 1px solid var(--st-shipping_us); border-top: 5px solid var(--st-shipping_us); }
.st-arrived { border: 1px solid var(--st-arrived); border-top: 5px solid var(--st-arrived); }
.st-weighed { border: 1px solid var(--st-weighed); border-top: 5px solid var(--st-weighed); }
.st-shipped_vn { border: 1px solid var(--st-shipped_vn); border-top: 5px solid var(--st-shipped_vn); }
.st-arrived_vn { border: 1px solid var(--st-arrived_vn); border-top: 5px solid var(--st-arrived_vn); }
.st-delivered { border: 1px solid var(--st-delivered); border-top: 5px solid var(--st-delivered); }
.st-cancelled { border: 1px solid var(--st-cancelled); border-top: 5px solid var(--st-cancelled); }

/* admin dashboard */
.dash-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin-bottom: 20px; }
.dash-card { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; text-decoration: none; color: inherit; display: block; }
.dash-card:hover { border-color: var(--accent); }
.dc-num { font-size: 22px; font-weight: 700; color: var(--accent-dark); }
.dc-unit { font-size: 14px; font-weight: 600; color: inherit; }
.dc-label { font-weight: 600; margin-top: 2px; }
.dc-sub { color: var(--muted); font-size: 13px; }

/* segmented control (homepage calculator) — two clear equal buttons */
.seg { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px; }
.seg button { border: 1.5px solid var(--line); background: var(--card); border-radius: 10px; padding: 10px 8px; font: inherit; font-weight: 600; cursor: pointer; color: var(--ink); }
.seg button.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.est-total { font-size: 19px; font-weight: 700; margin-top: 4px; }

/* hidden attribute must win over display utilities like .row */
[hidden] { display: none !important; }

/* readonly inputs driven by a dropdown (bank name / BIN) */
input.ro { background: var(--surface2); color: var(--muted); }

/* timeline */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { padding: 6px 0 6px 28px; position: relative; color: var(--muted); }
.timeline li::before {
  content: ""; position: absolute; left: 8px; top: 12px; width: 10px; height: 10px;
  border-radius: 50%; background: #d1d5db;
}
.timeline li.done { color: var(--ink); }
.timeline li.done::before { background: var(--accent); }
.timeline li.current { color: var(--ink); font-weight: 700; }
.timeline li.current::before { background: var(--accent); box-shadow: 0 0 0 4px rgba(15,122,61,.18); }

/* Admin order page: horizontal clickable status timeline. Done steps are
   filled, the current step is ringed, later steps are submit buttons —
   clicking one saves that status in place (data-ajax). */
.stl{display:flex;overflow-x:auto;padding:2px 0 4px;position:relative}
.stl-step{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:6px;position:relative;text-align:center;padding:0 2px}
button.stl-step{background:none;border:none;font:inherit;color:inherit;cursor:pointer;width:100%}
.stl-form{flex:1 1 0;min-width:0;display:flex;position:relative}
.stl-step::before{content:"";position:absolute;top:13px;left:-50%;width:100%;height:2px;background:var(--line)}
.stl-step:first-child::before,.stl-form:first-child .stl-step::before{display:none}
.stl-step.done::before,.stl-step.current::before{background:var(--accent)}
.stl-dot{width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;background:var(--card);border:2px solid var(--line);color:var(--muted);position:relative;z-index:1;flex-shrink:0}
.stl-step.done .stl-dot{background:var(--accent);border-color:var(--accent);color:#fff}
.stl-step.current .stl-dot{border-color:var(--accent)}
.stl-inner{width:10px;height:10px;border-radius:50%;background:var(--accent)}
.stl-label{font-size:12px;line-height:15px;color:var(--muted)}
.stl-step.done .stl-label{color:var(--ink)}
.stl-step.current .stl-label{color:var(--ink);font-weight:700}
button.stl-step.todo:hover .stl-dot{border-color:var(--accent);color:var(--accent)}
.stl-form .ajax-spin{position:absolute;top:-2px;right:calc(50% - 24px);margin:0;width:12px;height:12px}
@media (max-width:640px){.stl-step,.stl-form{flex:0 0 76px}}

pre.quote {
  background: #111111; color: #f5f5f4; padding: 12px; border-radius: 8px;
  white-space: pre-wrap; font-size: 14px;
}
.kv { display: grid; grid-template-columns: 170px 1fr; gap: 4px 12px; font-size: 15px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; overflow-wrap: break-word; min-width: 0; }

/* mobile: prevent horizontal overflow */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll table { min-width: 560px; }
/* Edge fade for sideways-scrollable tables (owner, 2026-10-20, "option
   4"): the Layout script sets data-shade from the scroll position
   (right | both | left | none) and the content dissolves at the edge
   that has more to show. "none" — or no attribute when JS is off —
   means no fade, so tables that fit render untouched. */
.table-scroll[data-shade="right"] { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); }
.table-scroll[data-shade="left"] { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); }
.table-scroll[data-shade="both"] { -webkit-mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent); }
/* NOTE: no mask-clip here — iOS Safari mis-paints masked card-scrollers
   when the mask is clipped to the content box (the card's background and
   border get clipped too and the table renders shifted/narrow, seen
   2026-10-20). Framed tables instead put .table-scroll INSIDE the card,
   so the masked element never carries the border. */
/* Customer pages: wider floor + no-wrap columns so phones scroll the card
   instead of crushing columns (order codes/dates/badges stay on one line;
   the item-name cell keeps its stored line breaks and a floor width). */
.cust-orders table, .my-orders table, .batch-orders table { min-width: 700px; }
.cust-orders th, .cust-orders td, .my-orders th, .my-orders td, .batch-orders th, .batch-orders td { white-space: nowrap; }
.cust-orders td.items, .my-orders td.items, .batch-orders td.items { min-width: 230px; white-space: normal; }
/* Item-list lines (lib/format itemsHtml): one block per item, bold count. */
.itm { display: block; }
.itm + .itm { margin-top: 6px; }
/* Admin tables: item column caps — desktop max 800px, phones max 360px (media block at EOF).
   The cap sits on the inner .itm blocks too — a td max-width alone is only
   a suggestion in auto table layout and wide few-column tables ignore it. */
td.items { max-width: 800px; }
td.items .itm, .otable .item-cell .itm { max-width: 800px; }
.cust-list table { min-width: 800px; }
.cust-list th:nth-child(1), .cust-list td:nth-child(1) { width: 168px; }
.cust-list th:nth-child(2), .cust-list td:nth-child(2) { width: 54px; text-align: center; }
.cust-list td:nth-child(4) { white-space: nowrap; }
.cust-list th:nth-child(5), .cust-list td:nth-child(5) { min-width: 124px; }
td, dd { overflow-wrap: break-word; }
@media (max-width: 640px) {
  .kv { grid-template-columns: 1fr; gap: 2px; }
  .kv dt { font-size: 13px; text-transform: uppercase; letter-spacing: .4px; margin-top: 6px; }
}
.filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 12px; }
.filters .f { min-width: 150px; }
.filters label { margin-top: 0; }
img.qr { max-width: 220px; border: 1px solid var(--line); border-radius: 8px; }
.hero { text-align: center; padding: 32px 16px 24px; }
.hero h1 { font-size: 32px; }
.hero p.lead { font-size: 18px; color: var(--muted); max-width: 640px; margin: 0 auto 16px; }
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; margin-top: 20px; }
.step { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; }
.step .n { font-weight: 800; color: var(--accent); font-size: 20px; }

/* streamlined order form */
.form-h { font-size: 16px; margin: 18px 0 6px; }
.form-h:first-child { margin-top: 0; }
#items { display: flex; flex-direction: column; gap: 6px; margin-bottom: 6px; }
.item-row { display: grid; grid-template-columns: 1fr 54px 74px 30px; gap: 6px; align-items: center; }
.item-row input { margin: 0; min-width: 0; }
.item-qty { text-align: center; padding-left: 4px; padding-right: 4px; }
.item-remove {
  border: 1px solid var(--line); background: var(--card); color: var(--muted);
  border-radius: 8px; height: 42px; font-size: 19px; line-height: 1; cursor: pointer; padding: 0;
}
.item-remove:hover { color: var(--danger); border-color: var(--danger); }
#add-item { margin-top: 2px; }
/* segmented product-type picker */
.seg { display: flex; gap: 8px; }
.seg-opt { flex: 1; margin: 0; }
.seg-opt input { position: absolute; opacity: 0; pointer-events: none; }
.seg-opt span {
  display: block; text-align: center; padding: 9px 6px; font-size: 15px; font-weight: 600;
  border: 1px solid var(--line); border-radius: 8px; background: var(--card); cursor: pointer;
}
.seg-opt input:checked + span { background: var(--accent); border-color: var(--accent); color: #fff; }
.seg-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 400px) {
  .item-row { grid-template-columns: 1fr 48px 64px 28px; gap: 5px; }
}

/* Hide camera-only UI on desktop (mouse + hover); the manual input stays. */
@media (hover: hover) and (pointer: fine) {
  .camera-only { display: none; }
}

/* Inline input + button rows: vertically centered, no button top margin. */
.row-center { align-items: center; }
.row-center .btn { margin-top: 0; }

/* Order detail: US-tracking mini form — carrier, tracking code and save button
   on one tidy line that wraps on narrow screens. */
.tracking-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 8px; }
.tracking-form select { flex: 0 1 160px; min-width: 0; }
.tracking-form input[type="text"] { flex: 1 1 190px; min-width: 0; }
.tracking-form .btn { margin-top: 0; flex-shrink: 0; }

/* Sent-email log on the admin order page: stacked rows instead of a cramped table. */
.email-log { list-style: none; margin: 0; padding: 0; }
.email-log li { padding: 10px 0; border-bottom: 1px solid var(--line); }
.email-log li:first-child { padding-top: 0; }
.email-log li:last-child { border-bottom: 0; padding-bottom: 0; }
.email-log-meta { display: flex; justify-content: space-between; align-items: baseline; gap: 2px 12px; flex-wrap: wrap; margin-top: 2px; }

/* Bouncing "working" dots for the receipt OCR status line. */
.ocr-dots { display: inline-flex; gap: 6px; margin-left: 10px; vertical-align: middle; }
.ocr-dots span {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent);
  animation: ocr-bounce 1.1s infinite;
}
.ocr-dots span:nth-child(2) { animation-delay: 0.15s; }
.ocr-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes ocr-bounce {
  0%, 60%, 100% { transform: translateY(0); }
  30% { transform: translateY(-7px); }
}

/* admin view tabs + order table */
.tabs { display: flex; gap: 8px; margin: 4px 0 12px; }
.tabs a { padding: 8px 18px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); text-decoration: none; color: var(--ink); font-weight: 600; }
.tabs a.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.table-wrap { overflow-x: auto; }
.otable { width: 100%; border-collapse: collapse; font-size: 14px; }
.otable th, .otable td { padding: 9px 10px; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; }
.otable thead th { background: var(--bg); }
.otable th a { text-decoration: none; color: inherit; }
.otable tbody tr:hover { background: var(--accent-soft); }
.otable .code { font-weight: 700; text-decoration: none; }
.otable .item-cell { white-space: normal; min-width: 160px; max-width: 800px; }
.trow td:first-child { border-left: 5px solid transparent; }
.trow.st-new td:first-child { border-left-color: var(--st-new); }
.trow.st-shipping_us td:first-child { border-left-color: var(--st-shipping_us); }
.trow.st-arrived td:first-child { border-left-color: var(--st-arrived); }
.trow.st-weighed td:first-child { border-left-color: var(--st-weighed); }
.trow.st-shipped_vn td:first-child { border-left-color: var(--st-shipped_vn); }
.trow.st-arrived_vn td:first-child { border-left-color: var(--st-arrived_vn); }
.trow.st-delivered td:first-child { border-left-color: var(--st-delivered); }
.trow.st-cancelled td:first-child { border-left-color: var(--st-cancelled); }
.pager { display: flex; gap: 12px; align-items: center; justify-content: center; margin: 14px 0; }
/* order table rows: simple borders only — none of the status-color borders
   (row box, top strip, left accent bar) show in the table view */
.otable tr.st-new, .otable tr.st-shipping_us, .otable tr.st-arrived,
.otable tr.st-weighed, .otable tr.st-shipped_vn, .otable tr.st-arrived_vn,
.otable tr.st-delivered, .otable tr.st-cancelled { border: none; }
.otable tr.trow td:first-child { border-left: none; }

/* role dashboards (homepage) */
.balance-banner { display: block; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 18px; text-decoration: none; color: inherit; margin: 12px 0 4px; }
.balance-banner:hover { border-color: var(--accent); }
.balance-banner .bb-label { color: var(--muted); font-size: 14px; }
.balance-banner .bb-num { font-size: 30px; font-weight: 800; }
.balance-banner.owes .bb-num { color: var(--warn); }
.balance-banner.clear .bb-num { color: var(--accent-dark); }
.balance-banner .bb-sub { color: var(--muted); font-size: 14px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 8px; }
/* Dashboard status chips — single-layer tinted pills (owner's pick from
   mockups, 2026-10-12): the status tint IS the pill (colors mirror .badge
   exactly), the count sits in a frosted bubble. No white shell, no border. */
.chip { display: inline-flex; align-items: center; gap: 7px; border-radius: 999px; padding: 7px 8px 7px 12px; text-decoration: none; font-size: 14px; font-weight: 600; }
.chip:hover { filter: brightness(.97); }
.chip.new { background: #dbeafe; color: #1d4ed8; }
.chip.shipping_us { background: #e0e7ff; color: #4338ca; }
.chip.arrived { background: #ccfbf1; color: #0f766e; }
.chip.weighed { background: #fef3c7; color: #92400e; }
.chip.shipped_vn { background: #ede9fe; color: #6d28d9; }
.chip.arrived_vn { background: #e0f2fe; color: #0369a1; }
.chip.delivered { background: #dcfce7; color: #15803d; }
.chip.cancelled { background: #fee2e2; color: #b91c1c; }
.chip-n { background: rgba(255,255,255,.6); border-radius: 999px; padding: 1px 8px; font-size: 14px; font-weight: 800; }
.action-list { padding: 0; }
.action-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.action-row:last-child { border-bottom: none; }
.badge.paid { background: #dcfce7; color: #166534; }
.badge.unpaid { background: #fef3c7; color: #92400e; }

/* admin status bar (Layout, admin only, owner 2026-10-22): one glance
   line on every page — the live exchange rate (always, pinned left) plus
   every non-zero dashboard number, each a link. Replaces the old /admin
   dash-strip. Desktop: sticky directly under the top nav. Mobile: fixed
   directly above the bottom tab bar (see the ≤760px block). */
.statusbar { position: sticky; top: 0; z-index: 55; background: var(--card); border-bottom: 1px solid var(--line); font-size: 13px; }
.sb-inner { display: flex; align-items: center; gap: 16px; max-width: 1440px; margin: 0 auto; padding: 5px 24px; }
.sb-rate { display: inline-flex; align-items: center; gap: 5px; flex: none; color: inherit; text-decoration: none; white-space: nowrap; }
.sb-rate strong, .sb-item strong { font-weight: 700; }
.sb-rate:hover strong, .sb-item:hover strong { color: var(--accent-dark); }
.sb-items { display: flex; align-items: center; gap: 16px; overflow-x: auto; flex: 1; scrollbar-width: none; }
.sb-items::-webkit-scrollbar { display: none; }
.sb-item { display: inline-flex; align-items: center; gap: 5px; color: inherit; text-decoration: none; white-space: nowrap; }
.sb-item span { color: var(--muted); }
/* edge fade on the swipeable items — same mask language as .table-scroll */
.sb-items[data-shade="right"] { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); }
.sb-items[data-shade="left"] { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); }
.sb-items[data-shade="both"] { -webkit-mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent); }

/* view tabs + save-default */
.viewbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 2px 0 10px; }
.viewbar .tabs { margin: 0; }
.inline-form { display: inline; margin: 0; }

/* compact filters */
.filters.compact { gap: 6px; margin-bottom: 10px; align-items: center; }
.filters.compact .f { min-width: 0; }
.filters.compact .f label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.filters.compact select, .filters.compact input[type="text"] { font-size: 13px; padding: 6px 8px; border-radius: 8px; }
.filters.compact select { padding-right: 30px; }
.filters.compact input[type="text"] { min-width: 140px; }
.filters.compact .btn { padding: 6px 12px; font-size: 13px; }

/* ---- Mobile compact pass (matches the slim admin-home aesthetic) ---- */
@media (max-width: 640px) {
  /* Base text size on mobile — without this, plain paragraphs/lists inherit
     the full 16px while every component around them is scaled down. */
  body { font-size: 14px; }

  main.container { padding-top: 10px; padding-bottom: 32px; }

  h1 { font-size: 18px; margin-bottom: 8px; }
  h2 { font-size: 16px; margin: 14px 0 6px; }
  h3 { font-size: 14px; margin: 12px 0 4px; }
  .form-h { font-size: 14px; margin: 12px 0 4px; }

  .card { padding: 10px 12px; margin-bottom: 8px; }
  .small { font-size: 13px; }
  .hint { font-size: 12px; }
  .footer { font-size: 12px; padding: 14px 0 24px; }

  /* tables */
  table { font-size: 13px; }
  .est-total { font-size: 17px; }
  th, td { padding: 6px; }
  th { font-size: 12px; }
  .otable { font-size: 12px; }
  .otable th, .otable td { padding: 6px 8px; }

  /* badges */
  .badge { font-size: 12px; }

  /* forms */
  label { font-size: 13px; margin: 8px 0 3px; }
  /* 16px on purpose: iOS Safari auto-zooms the page when a focused field's
     font is smaller than 16px. This stops the focus zoom while leaving
     pinch-zoom fully available. */
  input[type=text], input[type=email], input[type=password], input[type=number], input[type=url],
  input[type=date], input[type=datetime-local], input[type=time],
  select, textarea { font-size: 16px; padding: 8px 10px; }
  /* The shorthand above resets padding-right to 10px — restore the select's
     chevron clearance or the label runs under the drawn chevron (mobile-only
     overlap, burned 2026-10-18 on the order page batch dropdown). */
  select { padding-right: 34px; }
  /* ONE mobile control height — 38px (his standard, 2026-10-18): every
     field, select, date/time picker, file picker and button renders
     exactly 38px tall, so controls paired in a row align by construction.
     Fields: 20 content + 16 padding + 2 border = 38. Textarea excluded —
     it is multi-line and keeps the roomier leading. */
  input[type=text], input[type=email], input[type=password], input[type=number], input[type=url],
  select { line-height: 20px; height: 38px; }
  /* Date/time pickers: desktop WebKit honours the height pin under native
     appearance, but iOS Safari does NOT — its native control renders at
     its own intrinsic height regardless of CSS height (owner's phone,
     2026-10-19: the date picker stood way taller than 38px). Taking over
     the appearance hands the height back to CSS; the value still renders
     as text and tapping still opens the native wheel. The internal value
     box also carries UA margins — zero them and pin its line to the same
     20px as every other field, so the value sits exactly like typed text. */
  input[type=date], input[type=datetime-local], input[type=time] {
    -webkit-appearance: none; appearance: none; height: 38px; min-height: 38px;
    /* width:auto was safe under native appearance (the OS control brings
       its own intrinsic width) but NOT under appearance:none — on iOS an
       EMPTY date field's segment box has no intrinsic width, so the field
       collapsed to a ~50px nub (owner's phone, 2026-10-19, deal + batch
       forms). Full width like every other mobile field instead. */
    width: 100%;
  }
  input[type=date]::-webkit-date-and-time-value,
  input[type=datetime-local]::-webkit-date-and-time-value,
  input[type=time]::-webkit-date-and-time-value { margin: 0; line-height: 20px; text-align: left; }
  input[type=date]::-webkit-datetime-edit,
  input[type=datetime-local]::-webkit-datetime-edit,
  input[type=time]::-webkit-datetime-edit { padding: 0; }
  input[type=file] { font-size: 14px; height: 38px; padding: 4px 10px; }
  input[type=file]::file-selector-button { padding: 4px 12px; }
  input[type=checkbox], input[type=radio] { width: 24px; height: 24px; }
  textarea { min-height: 72px; }
  /* Buttons: line-height pinned at 20px — an unpinned line-height is what
     let <button> (34px), <a class=btn> (37px) and icon buttons (35.8px)
     drift apart. 20 content + 18 padding = 38 for every variant. */
  /* inline-flex (not inline-block): an inline SVG icon's baseline shift
     (vertical-align:-0.16em) pokes ~0.9px out of the 20px line box and
     stretched icon buttons to 38.9px. As flex items, icon and label lay
     out by their boxes, so every button is exactly 38px; gap replaces
     the literal space that used to separate icon and label. */
  .btn { font-size: 14px; line-height: 20px; padding: 9px 14px; margin-top: 8px; display: inline-flex; align-items: center; justify-content: center; gap: 4px; }
  .btn.small-btn { font-size: 13px; padding: 9px 10px; }
  /* Buttons inside table cells stay SMALL — 28px (his call): a 38px
     button in every row would stretch the dense admin tables. */
  td .btn, td .btn.small-btn { font-size: 13px; line-height: 18px; padding: 5px 10px; margin-top: 0; }
  .filters .btn:not(.small-btn) { padding: 9px 14px; font-size: 14px; }
  .filters.compact .btn { padding: 9px 12px; }
  .alert { font-size: 14px; padding: 8px 12px; margin-bottom: 8px; }
  .seg-opt span { font-size: 14px; padding: 8px 6px; }

  /* homepage hero */
  .hero { padding: 20px 12px 16px; }
  .hero h1 { font-size: 24px; }
  .hero p.lead { font-size: 15px; }
  .step { padding: 10px; }

  /* dashboards */
  .balance-banner { padding: 10px 14px; }
  .balance-banner .bb-num { font-size: 24px; }
  .dc-num { font-size: 18px; }
  .tabs a { padding: 6px 14px; font-size: 14px; }
  .chip { font-size: 13px; padding: 6px 7px 6px 11px; }
  .chip-n { font-size: 13px; }
  .action-row { padding: 10px 12px; }

  /* kanban */
  .kcol { min-width: 220px; padding: 6px; }
  .kcard { font-size: 13px; }
  .kcol h3 { font-size: 14px; }

  /* detail lists */
  .kv { font-size: 14px; }
  img.qr { max-width: 180px; }

  /* nav */
  .brand { font-size: 16px; }
}

/* bottom tab bar + "more" sheet — mobile only, logged-in users */
.tabbar, .sheet, .sheet-backdrop { display: none; }
@media (max-width: 760px) {
  body.logged-in { padding-bottom: 84px; }
  /* admin status bar: fixed directly above the tab bar. The tab bar is
     62px tall plus the safe-area inset (already inside its own bottom
     padding) — keep the offset below in sync with it. Page content
     reserves the extra room; the deal scroll-up button hops the stack. */
  body.has-sb { padding-bottom: 116px; }
  body.has-sb .statusbar {
    position: fixed; left: 0; right: 0; z-index: 59;
    top: auto; /* the desktop sticky rule's top:0 must not survive —
                  with both set, a fixed box stretches full-height */
    bottom: calc(62px + env(safe-area-inset-bottom));
    background: var(--tabbar-bg); backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-top: 1px solid var(--line); border-bottom: none;
  }
  .statusbar .sb-inner { padding: 5px 12px; gap: 12px; }
  .statusbar .sb-items { gap: 12px; }
  body.has-sb #deal-top-btn { bottom: 106px; }
  body.logged-in #nav-toggle { display: none; }
  body.logged-in .tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    background: var(--tabbar-bg); backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-top: 1px solid var(--line);
    padding: 6px 4px calc(8px + env(safe-area-inset-bottom));
  }
  .tab {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
    font-size: 10px; color: var(--muted); text-decoration: none; padding: 2px 0;
    background: none; border: none; cursor: pointer; font-family: inherit;
  }
  /* The pill box exists on EVERY tab (transparent when inactive) so the
     active tab's pill never changes the bar's height — only its fill,
     color and icon weight change. (Owner pick, 2026-10-22.)
     CHILD combinator on purpose: the <svg> inside the pill span ALSO
     carries class "ic" (Icon.astro), so a descendant selector would
     restyle the svg itself — pill padding crushes its content box to
     0 wide (icons vanish) and the active fill paints a second, inner
     pill on the svg. Burned 2026-10-22: shipped, harness checks
     measured only the span and passed; the owner's phone caught it. */
  .tab > .ic {
    display: flex; align-items: center; justify-content: center;
    padding: 3px 16px; border-radius: 999px; line-height: 1;
  }
  .tab.active { color: var(--accent-dark); font-weight: 700; }
  .tab.active > .ic { background: color-mix(in srgb, var(--accent) 18%, transparent); }
  .tab.active > .ic svg { stroke-width: 2.4; }
  body.logged-in .sheet-backdrop {
    display: block; position: fixed; inset: 0; z-index: 70;
    background: rgba(0,0,0,.35); opacity: 0; pointer-events: none;
    transition: opacity .2s;
  }
  body.logged-in .sheet-backdrop.open { opacity: 1; pointer-events: auto; }
  body.logged-in .sheet {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 71;
    background: var(--card); border-radius: 18px 18px 0 0;
    padding: 10px 16px calc(16px + env(safe-area-inset-bottom));
    transform: translateY(105%); transition: transform .25s ease;
    max-height: 70vh; max-height: 70dvh; overflow-y: auto;
  }
  body.logged-in .sheet.open { transform: translateY(0); }
  .sheet .grab { width: 40px; height: 4px; border-radius: 2px; background: var(--line); margin: 2px auto 10px; }
  .sheet h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 12px 0 6px; }
  .sheet h4:first-of-type { margin-top: 0; }
  .sheet-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .sheet-item {
    display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit;
    background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
    padding: 10px 12px; font-size: 14px; font-weight: 600;
  }
  /* Current page's tile: accent frame + tint, same language as the deal
     cards — border stays 1px so the grid never shifts. */
  .sheet-item.active {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 12%, var(--bg));
    color: var(--accent-dark); font-weight: 700;
  }
  .sheet-item.active svg { stroke-width: 2.4; }
  .sheet-logout, .sheet-close {
    display: block; width: 100%; margin-top: 10px; border-radius: 10px; padding: 10px;
    font-size: 14px; font-weight: 600; cursor: pointer; font-family: inherit;
  }
  .sheet-logout { background: none; border: 1px solid var(--line); color: var(--danger); }
  .sheet-close { background: var(--surface2); border: 1px solid var(--line); color: var(--ink); }
}

/* documentation pages (/admin/tai-lieu, /huong-dan): bilingual blocks,
   one language shown at a time via data-active-lang on the .docs wrapper */
.docs [data-lang] { display: none; }
.docs[data-active-lang="vi"] [data-lang="vi"] { display: block; }
.docs[data-active-lang="en"] [data-lang="en"] { display: block; }
.docs-bar { display: flex; justify-content: flex-end; margin-bottom: 10px; }
.lang-toggle { display: inline-flex; gap: 6px; }
.docs[data-active-lang="vi"] [data-set-lang="vi"],
.docs[data-active-lang="en"] [data-set-lang="en"] {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.docs-toc { margin: 6px 0 6px 18px; }
.docs-section h2 { margin-top: 0; }
.docs-section h3 { margin: 16px 0 6px; }
.docs-section table { width: 100%; border-collapse: collapse; margin: 8px 0; }
.docs-section th, .docs-section td {
  border-bottom: 1px solid var(--line); padding: 6px 8px;
  text-align: left; vertical-align: top;
}

/* Ward type-to-filter picker (AddressFields component) */
.ward-picker{position:relative}
.ward-list{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:40;background:var(--card);border:1px solid var(--line);border-radius:10px;box-shadow:0 12px 32px rgba(0,0,0,.16);max-height:264px;overflow:auto;padding:4px}
.ward-item{display:flex;justify-content:space-between;align-items:baseline;gap:8px;width:100%;text-align:left;background:none;border:0;padding:9px 10px;border-radius:7px;font:inherit;cursor:pointer;color:var(--ink)}
.ward-item:hover,.ward-item.active{background:var(--accent-soft)}
.ward-prov{color:var(--muted);font-size:13px;white-space:nowrap}
.ward-empty{padding:9px 10px;color:var(--muted)}
.ward-hint{color:var(--warn);font-size:14px;margin:6px 0 0}

/* Promotion ribbon (Layout) — visible on all pages while a campaign is live */
.promo-ribbon{display:block;text-align:center;background:linear-gradient(90deg,var(--accent-dark),var(--accent));color:var(--on-accent);text-decoration:none;font-size:13.5px;font-weight:600;padding:8px 12px;line-height:1.45}
.promo-ribbon:hover{filter:brightness(1.07);color:var(--on-accent)}

/* Promo code delete confirm (details-based, no native dialog) */
.row-actions{display:flex;gap:6px;align-items:flex-start;white-space:nowrap}
/* US receiving-address card (components/UsAddressCard.astro). The card root
   is a <details>: .usaddr-static renders it permanently open with a plain
   heading row (dashboard, FAQ); .usaddr-fold (create-order page) starts
   collapsed so the order form comes first — the summary IS the heading
   (h3 sizes: 16px / 14px mobile) plus a ▾ caret that flips when open. */
.usaddr-summary{list-style:none;font-size:16px;font-weight:700;line-height:1.35}
.usaddr-summary::-webkit-details-marker{display:none}
.usaddr-static>.usaddr-summary{pointer-events:none;cursor:default}
.usaddr-fold>.usaddr-summary{cursor:pointer}
.usaddr[open ]>.usaddr-summary{margin-bottom:8px}
.usaddr-caret{display:inline-block;margin-left:6px;color:var(--accent);font-size:14px;transition:transform .15s ease}
.usaddr[open ] .usaddr-caret{transform:rotate(180deg)}
.usaddr-fields{border-top:1px solid var(--line)}
.usaddr-row{display:grid;grid-template-columns:132px 1fr auto;gap:10px;align-items:center;padding:8px 0;border-bottom:1px solid var(--line)}
.usaddr-meta{display:flex;flex-direction:column}
.usaddr-label{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.06em}
.usaddr-sub{font-size:12px;color:var(--muted)}
.usaddr-value{font-size:15px;font-weight:600;overflow-wrap:break-word;min-width:0}
@media (max-width:640px){
  .usaddr-summary{font-size:14px}
  .usaddr-row{grid-template-columns:104px 1fr auto;gap:8px}
  .usaddr-value{font-size:14px}
}

/* Deals page (/deal) + sale events */
.event-list{display:flex;flex-direction:column;gap:10px;margin-bottom:8px}
.event-row{display:flex;gap:14px;align-items:flex-start;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:12px 14px}
.event-when{display:flex;flex-direction:column;gap:6px;align-items:flex-start;min-width:170px}
.event-dates{font-weight:700;font-size:15px}
.event-main{font-size:15px}
.deal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(225px,1fr));gap:14px}
.deal-card{background:var(--card);border:1px solid var(--accent);border-radius:12px;display:flex;flex-direction:column;position:relative;box-shadow:0 0 0 1px var(--accent),0 6px 18px color-mix(in srgb,var(--accent) 16%,transparent)}
.deal-img{width:100%;height:210px;object-fit:contain;background:#fff;display:block;padding:20px 10px}
.deal-body{padding:12px 14px 14px;display:flex;flex-direction:column;gap:8px;flex:1}
.deal-card .deal-body > .deal-cta.cta-main{margin-top:auto}
.deal-top{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.deal-top .info-pop{display:inline-flex;align-items:center;margin-left:0}
.store-chip{display:inline-flex;align-items:center;height:22px;padding:0 10px;line-height:1;background:#eef2ff;color:#3730a3;border-radius:999px;font-size:12px;font-weight:700}
.deal-off{position:absolute;top:8px;right:8px;z-index:2;display:inline-flex;align-items:center;height:22px;padding:0 8px;line-height:1;background:#dc2626;color:#fff;border-radius:999px;font-size:12px;font-weight:700;box-shadow:0 1px 4px rgb(0 0 0/.18)}
.deal-ends{display:inline-flex;align-items:center;gap:5px;height:22px;line-height:1;font-size:12px;color:var(--muted)}
.deal-cats{display:flex;flex-wrap:wrap;gap:8px;margin:18px 0 2px;scroll-margin-top:76px}
.deal-cats a,.deal-cats .deal-cat-pill{display:inline-flex;align-items:center;height:32px;padding:0 14px;border:1px solid var(--line);border-radius:999px;background:var(--card);color:var(--ink);font-family:inherit;font-size:14px;font-weight:600;text-decoration:none;cursor:pointer}
.deal-cats .deal-cat-pill.active{background:var(--accent);border-color:var(--accent);color:#fff}
.deal-cat[hidden]{display:none}
.deal-top-btn{position:fixed;right:16px;bottom:20px;z-index:65;width:44px;height:44px;border-radius:999px;border:1px solid var(--line);background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;box-shadow:0 6px 18px rgb(0 0 0/.22);cursor:pointer;opacity:0;transform:translateY(8px);pointer-events:none;transition:opacity .25s ease,transform .25s ease}
.deal-top-btn.show{opacity:1;transform:none;pointer-events:auto}
.deal-card .info-panel{left:8px;right:8px;width:auto;transform:none}
.deal-icons{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.deal-icons .info-pop{margin-left:0}
.deal-desc{display:block;width:100%}
.deal-card .deal-desc{margin-left:0}
.details-btn{width:100%;box-sizing:border-box;list-style:none}
.details-btn::-webkit-details-marker{display:none}
.deal-icons .deal-ends{margin-left:auto}
.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:999px;background:var(--surface2);color:var(--muted);cursor:pointer;list-style:none}
.icon-btn::-webkit-details-marker{display:none}
.deal-cat-head{scroll-margin-top:76px;margin-top:26px}
.deal-cat-head.flash{animation:cat-flash 1.2s ease;border-radius:8px}
@keyframes cat-flash{0%{background:color-mix(in srgb,var(--accent) 16%,transparent)}100%{background:transparent}}
.deal-title{margin:0;font-size:16px;line-height:1.35}
.deal-title a{color:var(--ink);text-decoration:none}
.deal-title a:hover{text-decoration:underline}
.deal-was{font-size:14px;color:var(--muted);text-decoration:line-through}
.deal-vnd{font-size:14px;color:var(--muted)}
.dp-main{display:inline-flex;align-items:baseline;gap:6px}
.deal-pricebar{display:flex;align-items:baseline;gap:4px 6px;flex-wrap:wrap;background:color-mix(in srgb,var(--accent) 12%,var(--card));border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:6px 14px;line-height:1.25}
.deal-pricebar strong{font-size:18px;color:var(--accent)}
.deal-pricebar .deal-was{font-size:13px}
.deal-pricebar .deal-vnd{font-size:13px}
.deal-pricebar .deal-vnd{margin-left:auto}
.deal-note{margin:0;font-size:14px}
.deal-blurb{margin:0;font-size:14px;color:var(--muted);flex:1}
.deal-cta{display:flex;gap:8px;flex-wrap:wrap;margin-top:4px}
.book-banner{display:flex;gap:14px;align-items:center;text-decoration:none;color:inherit;margin-bottom:18px}
.book-banner img{width:64px;height:85px;object-fit:cover;border-radius:6px;border:1px solid var(--line);flex:none}
.book-banner-main{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
.book-banner-main .muted{font-size:13px}
.book-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.book-fig{margin:0}
.book-page{display:block;width:100%;padding:0;background:var(--card);border:1px solid var(--line);border-radius:8px;overflow:hidden;cursor:pointer}
.book-page img{display:block;width:100%;height:auto}
.book-fig figcaption{font-size:12px;color:var(--muted);text-align:center;margin-top:4px}
.book-row{display:flex;gap:12px;align-items:center;padding:10px 0;border-top:1px solid var(--line);text-decoration:none;color:inherit}
.book-row img{width:45px;height:60px;object-fit:cover;border-radius:4px;border:1px solid var(--line);flex:none}
.book-row-main{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
.book-viewer{position:fixed;inset:0;z-index:200;background:rgba(10,10,10,.94);display:flex;align-items:center;justify-content:center}
.book-viewer[hidden]{display:none}
.book-viewer img{max-width:100%;max-height:100%;object-fit:contain}
.book-viewer-bar{position:absolute;top:0;left:0;right:0;display:flex;justify-content:space-between;align-items:center;padding:12px 16px;color:#fff;font-size:14px;z-index:2}
.book-viewer-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:999px;border:1px solid rgba(255,255,255,.4);background:rgba(255,255,255,.12);color:#fff;cursor:pointer}
.book-viewer-nav{position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:42px;height:42px;border-radius:999px;border:1px solid rgba(255,255,255,.4);background:rgba(255,255,255,.12);color:#fff;cursor:pointer;z-index:2}
.book-viewer-nav.prev{left:10px}
.book-viewer-nav.next{right:10px}
.deal-blocked-tag{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;line-height:1;list-style:none;cursor:pointer;background:color-mix(in srgb,var(--warn) 14%,var(--card));color:var(--warn);border-radius:999px;font-size:12px;font-weight:700}
.deal-blocked-tag::-webkit-details-marker{display:none}
@media (max-width:640px){
  .event-row{flex-direction:column;gap:6px}
  .event-when{min-width:0;flex-direction:row;align-items:center}
  .event-dates{font-size:14px}
  .event-main{font-size:14px}
  .deal-grid{grid-template-columns:1fr}
  .deal-title{font-size:14px}
  .deal-blurb,.deal-note{font-size:13px}
}

/* settings accordion (/admin/cai-dat) — compact 14px bold titles on the
   theme's band color (var(--band) + var(--band-line)): the band must stay
   visibly DARKER than the page background in every theme — the first
   version reused the page bg and collapsed sections blended into the
   page (owner-flagged). Rate any new theme's band by contrast numbers. */
.acc{border:1px solid var(--band-line);border-radius:12px;background:var(--card);margin-bottom:10px;overflow:hidden}
.acc-pw{margin-top:24px}
.acc-head{width:100%;display:flex;align-items:center;gap:8px;background:var(--band);border:none;border-bottom:1px solid transparent;padding:8px 12px;font-size:14px;font-weight:700;color:var(--ink);cursor:pointer;font-family:inherit;text-align:left}
.acc.open .acc-head{border-bottom-color:var(--band-line)}
.acc-chev{margin-left:auto;color:var(--accent);font-size:15px;font-weight:700;transition:transform .15s}
.acc.open .acc-chev{transform:rotate(90deg)}
.acc-body{display:none;padding:12px 12px 2px}
.acc.open .acc-body{display:block}
.acc-body .card{border:none;border-radius:0;background:transparent;padding:0;margin:0 0 12px;box-shadow:none}
.acc-body .card + .card{border-top:1px solid var(--line);padding-top:12px}

/* info popover — a (i) at the end of a heading; the explanation hides in a
   <details> panel (no JS). Usage: put class="pop-host" on the heading that
   carries the (i). The panel hangs directly under the heading (attached to
   the (i)) and centers on the heading — which spans the card, so the panel
   lands in the page's left–right middle without clipping either edge.
   (History: icon-anchored absolute clipped off-screen; viewport-fixed
   floated detached mid-page — owner rejected both.) The (i) is 17px,
   nudged UP 2px: downward nudges (+1px, +3px) both read worse on-device —
   the button sits low by default, so the correction is negative.
   Calibrated on-device 2026-10-12. Outside-tap close lives in Layout's
   single script (search "Info popovers"). All behavior lives here. */
.pop-host{position:relative}
.info-pop{display:inline-block;vertical-align:middle;margin-left:4px}
.info-btn{display:inline-flex;align-items:center;justify-content:center;width:17px;height:17px;border-radius:50%;border:1.5px solid var(--accent);color:var(--accent);font-size:11px;font-weight:700;font-style:italic;font-family:Georgia,serif;line-height:1;cursor:pointer;list-style:none;background:var(--card);transform:translateY(-2px)}
.info-btn::-webkit-details-marker{display:none}
.info-panel{display:block;position:absolute;top:calc(100% + 6px);left:50%;transform:translateX(-50%);width:320px;max-width:calc(100vw - 32px);background:var(--card);border:1px solid var(--line);border-radius:10px;box-shadow:0 12px 32px rgba(0,0,0,.16);padding:12px 14px;font-size:14px;font-weight:400;color:var(--muted);line-height:1.5;text-align:left;z-index:60}
@media (max-width:640px){
  .info-panel{font-size:13px}
}

/* Theme picker (Tài khoản card + Cài đặt accordion section) */
.theme-row{display:flex;align-items:center;gap:10px;padding:6px 0}
.theme-row .grow{flex:1}
.theme-switch{position:relative;display:inline-block;width:46px;height:26px;flex-shrink:0}
.theme-switch input{position:absolute;opacity:0;width:0;height:0}
.theme-track{position:absolute;inset:0;border-radius:999px;background:var(--surface3);transition:background .15s;cursor:pointer}
.theme-track::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:var(--card);box-shadow:0 1px 3px rgba(0,0,0,.3);transition:left .15s}
.theme-switch input:checked + .theme-track{background:var(--accent)}
.theme-switch input:checked + .theme-track::after{left:23px}
.theme-swatches{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.theme-opt{display:inline-flex;align-items:center;gap:8px;border:1.5px solid var(--line);border-radius:10px;padding:8px 12px;cursor:pointer;font-size:14px;font-weight:600;background:var(--card);color:var(--ink)}
.theme-opt input{position:absolute;opacity:0;width:0;height:0}
.theme-opt.sel{border-color:var(--accent);background:var(--accent-soft)}
.theme-dot{width:16px;height:16px;border-radius:50%;border:1px solid rgba(0,0,0,.25);display:inline-block;flex-shrink:0;background-clip:padding-box}
.theme-status{font-size:13px;color:var(--muted);margin-top:8px}

/* Dino Dark leftovers: text selection + deal store chip */
[data-theme="dark"] ::selection{background:#1e4d2e}
[data-theme="dark"] .store-chip{background:#262450;color:#a8b0ff}

/* Loading overlay — owner's pick 2026-10-15 (mockup #10, blur + spinner):
   the current page blurs behind a translucent veil with a spinning ring
   while the next page loads. Deal-card image slots (.deal-media) keep the
   shimmer sweep below. All colors flow from the theme variables. */
@keyframes sk-sweep{to{transform:translateX(100%)}}
.page-loading{position:fixed;inset:0;z-index:200;display:none;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:color-mix(in srgb,var(--bg) 45%,transparent);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
.page-loading.on{display:flex}
.pl-ring{width:54px;height:54px;border-radius:50%;border:5px solid color-mix(in srgb,var(--accent) 18%,var(--surface2));border-top-color:var(--accent);animation:pl-spin .9s linear infinite}
@keyframes pl-spin{to{transform:rotate(360deg)}}
.pl-text{font-size:14px;color:var(--muted)}
@media (max-width:640px){.pl-text{font-size:13px}}
.deal-media{display:block;height:210px;background:var(--surface2);position:relative;overflow:hidden;border-radius:11px 11px 0 0}
.deal-media::after{content:'';position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,color-mix(in srgb,var(--ink) 7%,transparent) 50%,transparent 70%);transform:translateX(-100%);animation:sk-sweep 1.4s infinite}
.deal-media.done::after{display:none}
.deal-media img{opacity:0;transition:opacity .35s ease}
.deal-media img.ready{opacity:1}
@media (prefers-reduced-motion:reduce){
  .deal-media::after,.pl-ring{animation:none}
}

/* Stat cards — shared by /admin/thong-ke and /admin/truy-cap (moved out of
   thong-ke's page-scoped <style> 2026-10-15: scoped styles never reached the
   analytics page, whose cards rendered as bare text). */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-bottom:16px}
.stat{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:14px}
.stat-v{font-size:20px;font-weight:800}
.stat-l{font-size:13px;color:var(--muted);margin-top:4px}

/* Traffic chart (/admin/truy-cap) — pure CSS bars, themed via --accent.
   The wrap adds a y-axis column + gridlines behind the bars; both are
   positioned with the same axisY() math in the page (baseline = 16px up,
   bars track = 104px), so ticks, gridlines and bar tops always agree. */
.chart-wrap{display:flex;gap:6px;margin-top:8px}
.chart-y{position:relative;width:32px;flex:none}
.chart-yt{position:absolute;right:0;transform:translateY(50%);font-size:12px;line-height:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.chart-plot{position:relative;flex:1;min-width:0}
.chart-grid{position:absolute;left:0;right:0;border-top:1px solid color-mix(in srgb,var(--line) 55%,transparent)}
.chart{display:flex;align-items:flex-end;gap:2px;height:148px;position:relative;z-index:1}
.chart::after{content:'';position:absolute;left:0;right:0;bottom:16px;border-bottom:1px solid var(--line)}
.chart-col{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;min-width:0;position:relative}
/* The two values of a day ride as one stacked block above the TALLER bar —
   per-bar labels collided whenever the pair was close in height. */
.chart-valpair{position:absolute;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center}
.chart-val{font-size:12px;line-height:12px;font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}
.chart-val.views{color:var(--accent-dark)}
.chart-val.visitors{color:var(--muted)}
.chart-bars{display:flex;align-items:flex-end;gap:1px;height:104px}
.chart-bar{display:block;width:7px;border-radius:3px 3px 0 0}
.chart-bar.views{background:var(--accent)}
.chart-bar.visitors{background:color-mix(in srgb,var(--accent) 35%,transparent)}
.chart-x{font-size:12px;color:var(--muted);height:16px;line-height:16px;white-space:nowrap}
/* Edge labels are wider than their ~10px phone columns: centered, the first
   label pokes half its width past the chart's left edge and clips at the
   card border (and the last label does the same on the right in the 7-day
   range, where every column is labeled). Anchor the edge labels to the
   chart's own edges instead; bars stay centered, untouched. */
.chart-col:first-child .chart-x{align-self:flex-start}
.chart-col:last-child .chart-x{align-self:flex-end}
/* Ledger history: receipt icon on payments that came from a submitted
   receipt (migration 016) — reopens the image in the photo viewer. */
.receipt-view{display:inline-flex;vertical-align:-3px;margin-left:6px;color:var(--accent-dark)}
/* Balances table: the whole row loads the customer's detail card in place
   (AJAX swap in cong-no's page script; the Chi tiết link remains as the
   no-JS path). The selected tint uses the theme's accent-soft. */
#balances-card tbody tr[data-user]{cursor:pointer}
#balances-card tbody tr[data-user]:hover{background:color-mix(in srgb,var(--accent) 6%,transparent)}
#balances-card tbody tr[data-user].bal-selected{background:var(--accent-soft)}
#ledger-card{scroll-margin-top:100px}
#ledger-card.is-loading{opacity:.55;transition:opacity .15s}
.chart-key{display:inline-block;width:10px;height:10px;border-radius:2px;vertical-align:-1px}
.chart-key.views{background:var(--accent)}
.chart-key.visitors{background:color-mix(in srgb,var(--accent) 35%,transparent)}
@media (max-width:640px){
  .chart-bar{width:3px}
}

/* Item columns (his standard, 2026-10-15): desktop max 800px (base rules),
   phones max 360px so rows stay compact and the table scrolls sideways. */
@media (max-width: 640px) {
  .otable .item-cell { width: auto; min-width: 160px; max-width: 360px; }
  td.items { width: auto; max-width: 360px; }
  .cust-orders td.items, .my-orders td.items, .batch-orders td.items { width: auto; min-width: 230px; max-width: 360px; }
  td.items .itm, .otable .item-cell .itm { max-width: 360px; }
}

/* Toasts — inline feedback for AJAX actions (Layout owns the stack +
   window.dinoToast; forms marked data-ajax are intercepted there).
   Bottom offset clears the mobile tab bar; desktop sits at 24px. */
.toast-stack{position:fixed;left:50%;transform:translateX(-50%);bottom:84px;z-index:1200;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none;width:min(92vw,480px)}
@media (min-width:641px){.toast-stack{bottom:24px}}
.toast{pointer-events:auto;background:var(--ink);color:var(--bg);padding:10px 16px;border-radius:10px;font-size:14px;line-height:19px;box-shadow:0 6px 24px rgba(0,0,0,.28);max-width:100%;text-align:center;animation:toast-in .18s ease-out}
.toast.success{background:var(--accent-dark);color:#fff}
.toast.error{background:#b3261e;color:#fff}
.toast.leaving{opacity:0;transition:opacity .25s}
@keyframes toast-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@media (max-width:640px){.toast{font-size:13px}}
.is-busy{opacity:.55;pointer-events:none}
/* Spinner shown next to the submit button while a data-ajax save is in
   flight (inserted/removed by the Layout interceptor). */
.ajax-spin{display:inline-block;width:16px;height:16px;margin-left:8px;vertical-align:-3px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--accent);animation:dino-spin .7s linear infinite}
@keyframes dino-spin{to{transform:rotate(360deg)}}
/* Photo viewer caption — the viewer shell itself reuses .book-viewer. */
.photo-caption{position:absolute;left:0;right:0;bottom:0;padding:26px 16px calc(12px + env(safe-area-inset-bottom));color:#fff;font-size:14px;text-align:center;background:linear-gradient(transparent,rgba(0,0,0,.55));z-index:1;pointer-events:none}
@media (max-width:640px){.photo-caption{font-size:13px}}

@media (max-width: 640px) {
  /* 38px standard, late-file overrides: the .acc-head and .item-remove
     base rules live BELOW the main ≤640px block, so these must come last
     in the file to win at equal specificity. */
  .acc-head { padding-top: 9px; padding-bottom: 9px; }
  .item-remove { height: 38px; }
}

/* Deal grid density (owner, 2026-10-19): phones show TWO compact columns
   so 4–6 deals fit on one screen; the block sits at EOF so it beats the
   base .deal-media/.deal-img heights defined mid-file. Desktop keeps the
   auto-fill grid (250px min → more columns as the viewport widens). */
@media (max-width:640px){
  .deal-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .deal-media{height:150px}
  .deal-img{height:150px;padding:16px 6px}
  .deal-body{padding:9px 10px;gap:5px}
  .deal-pricebar{padding:5px 6px;gap:4px}
  .deal-pricebar .dp-main{gap:4px}
  .deal-pricebar{letter-spacing:-.2px}
  .deal-pricebar strong{font-size:13px}
  .deal-pricebar .deal-was{font-size:12px}
  .deal-pricebar .deal-vnd{font-size:12px}
  .deal-title{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .deal-cta{flex-wrap:nowrap}
  .deal-cta .btn{flex:1;justify-content:center;height:28px;min-height:28px;line-height:18px;padding:5px 10px;font-size:13px}
  .deal-icons .deal-ends{margin-left:0}
  .deal-top-btn{bottom:70px}
  .deal-grid > .deal-card:nth-child(odd) .info-panel{left:-11px;right:auto;width:calc(100vw - 48px)}
  .deal-grid > .deal-card:nth-child(even) .info-panel{left:auto;right:-11px;width:calc(100vw - 48px)}
}
