/* ═══════════════════════════════════════════════════════════════════
   OMC Learning — Design System
   Light theme · OMC Orange accent on navy type · 4pt spacing grid
   Shared by the public website, the auth pages and the app shell so
   OMC Learning reads as the same product family as OMC Connect.
   ═══════════════════════════════════════════════════════════════════ */

/* ── 1. TOKENS ───────────────────────────────────────────────────── */
:root {
  /* Brand — orange is an accent, never a full-bleed background */
  --brand:        #F26522;
  --brand-600:    #E2571A;
  --brand-700:    #C24810;
  --brand-100:    #FFE3D3;
  --brand-50:     #FFF4ED;

  /* Type */
  --navy:         #1B2A4A;
  --text:         #1B2A4A;
  --text-2:       #5A6B85;
  --muted:        #93A1B5;
  --on-brand:     #FFFFFF;
  /* Platform (Superadmin) header — a darker navy than --navy so the bar
     reads as a different context at a glance, not merely a darker shade
     of the same one. Orange stays the accent: the active pill is brand
     at low alpha over the dark ground, never a filled orange bar (§14). */
  --platform-bar:        #16213C;
  --platform-bar-line:   #26334F;
  --platform-bar-text:   #C4CDDF;
  --platform-bar-muted:  #8A97B2;
  --platform-bar-hover:  rgba(255,255,255,.08);
  --platform-bar-active: rgba(242,101,34,.26);

  /* Surfaces */
  --bg:           #FFFFFF;
  --bg-soft:      #F8FAFC;
  --bg-warm:      #FFF9F5;
  --surface:      #FFFFFF;
  --surface-2:    #F9FAFC;

  /* Borders */
  --border:       #E9EDF3;
  --border-2:     #DCE2EB;
  --ring:         rgba(242,101,34,.16);

  /* Semantic */
  --success:      #16A34A;  --success-bg: #ECFDF3;
  --warning:      #B45309;  --warning-bg: #FFF7ED;
  --danger:       #DC2626;  --danger-bg:  #FEF2F2;  --danger-bd:  #FCA5A5;
  --info:         #2563EB;  --info-bg:    #EFF6FF;

  /* Radii — one ladder, used everywhere */
  --r-sm:  8px;
  --r:     12px;
  --r-md:  14px;
  --r-lg:  20px;
  --r-xl:  24px;
  --r-pill: 999px;

  /* Shadows — light, never heavy */
  --sh-xs: 0 1px 2px rgba(16,24,40,.05);
  --sh-sm: 0 1px 3px rgba(16,24,40,.06), 0 1px 2px rgba(16,24,40,.04);
  --sh:    0 4px 12px rgba(16,24,40,.06);
  --sh-md: 0 8px 24px rgba(16,24,40,.07);
  --sh-lg: 0 20px 48px rgba(27,42,74,.10);

  /* Spacing (4pt) */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 20px;
  --s6: 24px; --s8: 32px; --s10: 40px; --s12: 48px; --s16: 64px; --s20: 80px;

  /* Type scale */
  --font: 'IBM Plex Sans Thai', 'Noto Sans Thai', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --tx-xs: .75rem; --tx-sm: .875rem; --tx-base: 1rem; --tx-md: 1.0625rem;
  --tx-lg: 1.25rem; --tx-xl: 1.5rem; --tx-2xl: 2rem; --tx-3xl: 2.5rem; --tx-4xl: 3.25rem;

  --container: 1200px;
  --header-h: 76px;
}

/* ── 2. BASE ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--tx-base);
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  /* Marketing pages use decorative blobs that must never create a
     horizontal scrollbar on small screens. */
  overflow-x: hidden;
}

h1, h2, h3, h4, h5 { margin: 0 0 var(--s3); color: var(--navy); font-weight: 700; line-height: 1.3; }
h1 { font-size: var(--tx-3xl); letter-spacing: -.02em; }
h2 { font-size: var(--tx-2xl); letter-spacing: -.01em; }
h3 { font-size: var(--tx-lg); }
p  { margin: 0 0 var(--s4); }

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-600); }

img, svg, video { max-width: 100%; height: auto; display: block; }

hr { border: 0; border-top: 1px solid var(--border); margin: var(--s6) 0; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }

.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--s6); }
.container-narrow { max-width: 880px; }

/* Utilities kept deliberately small — this is not a utility framework. */
.text-muted   { color: var(--text-2); }
.text-brand   { color: var(--brand); }
.text-center  { text-align: center; }
.text-right   { text-align: right; }
.mt-0 { margin-top: 0; } .mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: var(--s2); } .mb-4 { margin-bottom: var(--s4); }
.mb-6 { margin-bottom: var(--s6); } .mb-8 { margin-bottom: var(--s8); }
.hide { display: none !important; }
.nowrap { white-space: nowrap; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ── 3. BUTTONS ──────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  font-family: inherit; font-size: var(--tx-base); font-weight: 600; line-height: 1;
  padding: 13px 22px; border-radius: var(--r); border: 1px solid transparent;
  cursor: pointer; transition: background .16s, border-color .16s, color .16s, box-shadow .16s, transform .06s;
  white-space: nowrap; text-decoration: none;
}
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn.is-disabled { opacity: .55; pointer-events: none; }

.btn-primary { background: var(--brand); color: var(--on-brand); box-shadow: 0 1px 2px rgba(242,101,34,.24); }
.btn-primary:hover { background: var(--brand-600); color: #fff; }

.btn-outline { background: #fff; color: var(--navy); border-color: var(--border-2); }
.btn-outline:hover { border-color: var(--brand); color: var(--brand); }

.btn-brand-outline { background: #fff; color: var(--brand); border-color: var(--brand); }
.btn-brand-outline:hover { background: var(--brand-50); color: var(--brand-700); }

.btn-ghost { background: transparent; color: var(--text-2); }
.btn-ghost:hover { background: var(--surface-2); color: var(--navy); }

.btn-danger { background: var(--danger); color: #fff; }
/* Destructive, but not the loudest thing on the row — used in table actions,
   where a solid red button per row would read as a page full of alarms. */
.btn-danger-outline { background: #fff; color: var(--danger); border-color: var(--danger-bd); }
.btn-danger-outline:hover { background: var(--danger-bg); color: var(--danger); border-color: var(--danger); }
.btn-danger:hover { background: #B91C1C; color: #fff; }

.btn-lg  { padding: 16px 30px; font-size: var(--tx-md); border-radius: var(--r-md); }
.btn-sm  { padding: 8px 14px; font-size: var(--tx-sm); border-radius: var(--r-sm); }
.btn-block { width: 100%; }

/* ── 4. FORMS ────────────────────────────────────────────────────── */
.field { margin-bottom: var(--s5); }

.label {
  display: block; margin-bottom: var(--s2);
  font-size: var(--tx-sm); font-weight: 600; color: var(--navy);
}
.label .req { color: var(--danger); margin-left: 2px; }

.input, .select, .textarea {
  width: 100%; font-family: inherit; font-size: var(--tx-base); color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border-2);
  border-radius: var(--r); padding: 13px 16px;
  transition: border-color .16s, box-shadow .16s, background .16s;
}
.input::placeholder, .textarea::placeholder { color: var(--muted); }
.input:hover, .select:hover, .textarea:hover { border-color: #CBD5E1; }
.input:focus, .select:focus, .textarea:focus {
  outline: none; background: #fff; border-color: var(--brand); box-shadow: 0 0 0 4px var(--ring);
}
.textarea { min-height: 120px; resize: vertical; line-height: 1.6; }
.select { appearance: none; padding-right: 44px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2393A1B5' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 16px center;
}

/* Input with a leading icon — the login/register pattern from OMC Connect */
.input-icon { position: relative; }
.input-icon > svg, .input-icon > .icon {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; color: var(--muted); pointer-events: none;
}
.input-icon .input { padding-left: 46px; }
.input-icon .btn-eye {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  background: none; border: 0; padding: 8px; cursor: pointer; color: var(--muted);
  display: flex; align-items: center; border-radius: var(--r-sm);
}
.input-icon .btn-eye:hover { color: var(--navy); background: var(--border); }
.input-icon .input[type="password"], .input-icon .input.has-eye { padding-right: 48px; }

.input.is-invalid { border-color: var(--danger); background: #fff; }
.field-error { display: block; margin-top: 6px; font-size: var(--tx-sm); color: var(--danger); }
.field-hint  { display: block; margin-top: 6px; font-size: var(--tx-sm); color: var(--text-2); }

.checkbox { display: flex; align-items: flex-start; gap: var(--s2); cursor: pointer; font-size: var(--tx-sm); color: var(--text-2); }
.checkbox input[type="checkbox"] {
  width: 18px; height: 18px; margin: 2px 0 0; accent-color: var(--brand); cursor: pointer; flex: none;
}

.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }

.form-section-title {
  font-size: var(--tx-sm); font-weight: 700; color: var(--navy);
  margin: var(--s6) 0 var(--s4); padding-bottom: var(--s2); border-bottom: 1px solid var(--border);
}
.form-section-title:first-child { margin-top: 0; }

/* ── 5. CARDS ────────────────────────────────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-sm);
}
.card-pad { padding: var(--s6); }
.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s5) var(--s6); border-bottom: 1px solid var(--border);
}
.card-head h3 { margin: 0; font-size: var(--tx-md); display: flex; align-items: center; gap: var(--s3); }
/* Same chip as .kpi .ico one size down — a card's subject, not decoration. */
.card-head .ico {
  width: 34px; height: 34px; border-radius: var(--r-sm); flex: none;
  background: var(--brand-50); color: var(--brand); display: grid; place-items: center;
}
.card-head .head-tools { display: flex; align-items: center; gap: var(--s3); flex: 0 1 320px; }
.card-head .head-tools .input-icon { flex: 1 1 auto; }
.card-head .head-tools .input { padding: 9px 14px 9px 40px; font-size: var(--tx-sm); }
.card-head .head-tools .input-icon > svg { width: 17px; left: 13px; }
.card-body { padding: var(--s6); }
.card-foot { padding: var(--s4) var(--s6); border-top: 1px solid var(--border); background: var(--surface-2); border-radius: 0 0 var(--r-lg) var(--r-lg); }

/* ── 6. BADGES ───────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--r-pill);
  font-size: var(--tx-xs); font-weight: 600; line-height: 1.6; white-space: nowrap;
}
.badge-brand   { background: var(--brand-50);   color: var(--brand-700); }
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-warning { background: var(--warning-bg); color: var(--warning); }
.badge-danger  { background: var(--danger-bg);  color: var(--danger); }
.badge-info    { background: var(--info-bg);    color: var(--info); }
.badge-muted   { background: var(--surface-2);  color: var(--text-2); }
.badge-dot::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ── 7. ALERTS / TOAST ───────────────────────────────────────────── */
.alert {
  display: flex; gap: var(--s3); align-items: flex-start;
  padding: var(--s4); border-radius: var(--r); border: 1px solid transparent;
  font-size: var(--tx-sm); margin-bottom: var(--s4);
}
.alert-success { background: var(--success-bg); border-color: #BBF7D0; color: #15803D; }
.alert-warning { background: var(--warning-bg); border-color: #FED7AA; color: #B45309; }
.alert-danger  { background: var(--danger-bg);  border-color: #FECACA; color: #B91C1C; }
.alert-info    { background: var(--info-bg);    border-color: #BFDBFE; color: #1D4ED8; }

.toast-stack {
  position: fixed; top: 20px; right: 20px; z-index: 1200;
  display: flex; flex-direction: column; gap: var(--s2); max-width: min(380px, calc(100vw - 40px));
}
.toast {
  background: #fff; border: 1px solid var(--border); border-left: 4px solid var(--brand);
  border-radius: var(--r); box-shadow: var(--sh-md); padding: var(--s4);
  font-size: var(--tx-sm); animation: toastIn .22s ease;
}
.toast.is-success { border-left-color: var(--success); }
.toast.is-danger  { border-left-color: var(--danger); }
.toast.is-warning { border-left-color: var(--warning); }
@keyframes toastIn { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: none; } }

/* ── 8. PUBLIC HEADER ────────────────────────────────────────────── */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255,255,255,.92); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.site-header .container {
  display: flex; align-items: center; gap: var(--s6);
  height: var(--header-h);
}

/* The marketing header is a card rather than a full-width bar: its nav is two
   lines tall (icon over label), and a slab that deep across the whole viewport
   sits on the page instead of above it. Auth, error and blank layouts keep the
   plain bar — they carry a brand and a language switch, nothing to lift. */
.site-header-card {
  background: none; backdrop-filter: none; border-bottom: 0;
  padding: 12px 0;
}
.site-header-card .container {
  position: relative;
  max-width: calc(var(--container) + 96px);
  height: auto; min-height: var(--header-h);
  padding-block: 6px;
  background: rgba(255,255,255,.94); backdrop-filter: blur(12px);
  border: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: var(--sh-md);
}

.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.brand-mark {
  width: 40px; height: 40px; border-radius: 11px; flex: none;
  background: linear-gradient(135deg, #FF8A4C, var(--brand));
  display: grid; place-items: center; color: #fff;
  box-shadow: 0 2px 8px rgba(242,101,34,.28);
}
.brand-mark svg { width: 22px; height: 22px; }
/* The two lines must stack: they are spans, so without display:block the
   tagline sits beside the product name instead of under it. */
.brand-text { line-height: 1.1; min-width: 0; }
.brand-name { display: block; font-size: 1.3rem; font-weight: 700; color: var(--navy); letter-spacing: -.01em; white-space: nowrap; }
.brand-name em { font-style: normal; color: var(--brand); }
.brand-tagline { display: block; font-size: .68rem; color: var(--muted); letter-spacing: .04em; font-weight: 500; white-space: nowrap; }

/* The public navigation is icon over label. `> a` throughout, because the
   sign-in / sign-up links inside the mobile menu panel are plain text links
   and must not pick up the icon-column geometry. */
.site-nav { display: flex; align-items: stretch; gap: 2px; margin-inline: auto; }
.site-nav > a {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 8px 12px 10px; border-radius: var(--r-sm);
  font-size: .8125rem; font-weight: 500; color: var(--text-2); text-align: center;
}
.site-nav > a svg { width: 22px; height: 22px; }
.site-nav > a span { white-space: nowrap; }
.nav-only-mobile a { padding: 8px 14px; border-radius: var(--r-sm); font-weight: 500; color: var(--text-2); }
.site-nav a:hover { color: var(--navy); background: var(--surface-2); }
.site-nav a.is-active { color: var(--brand); font-weight: 600; }
/* The current page is marked with an underline rather than the filled pill
   hover uses, so hovering a different item never reads as "you are here". */
.site-nav > a.is-active { background: none; }
.site-nav > a.is-active::after {
  content: ''; position: absolute; left: 50%; bottom: 2px; transform: translateX(-50%);
  width: 26px; height: 2.5px; border-radius: 2px; background: var(--brand);
}
/* Sign-in / sign-up live in the header on desktop and inside the menu
   panel on a phone — see the header block in §16. */
.nav-only-mobile { display: none; }

.header-actions { display: flex; align-items: center; gap: var(--s3); flex: none; }
/* A rule between navigating the site and acting on it. */
.site-header-card .header-actions { padding-left: var(--s5); border-left: 1px solid var(--border); }
/* On the card the language control is already inside a bordered surface;
   a second border around it just draws a box inside a box. */
.site-header-card .lang-switch { border-color: transparent; background: transparent; }
.site-header-card .lang-switch:hover { border-color: var(--border-2); background: #fff; }

.lang-switch {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 14px; border: 1px solid var(--border-2); border-radius: var(--r);
  font-size: var(--tx-sm); color: var(--text-2); background: #fff; cursor: pointer;
}
.lang-switch:hover { border-color: var(--border-2); color: var(--navy); }
.lang-switch svg { width: 16px; height: 16px; }
.lang-switch .lang-name { margin: 0 2px; }
.dropdown-menu a.is-active { color: var(--navy); font-weight: 600; }

.nav-toggle {
  display: none; background: none; border: 1px solid var(--border-2);
  border-radius: var(--r-sm); padding: 9px; cursor: pointer; color: var(--navy);
}

/* ── 9. PUBLIC FOOTER ────────────────────────────────────────────── */
.site-footer { background: var(--navy); color: rgba(255,255,255,.68); padding: var(--s16) 0 var(--s8); margin-top: var(--s20); }
.site-footer h4 { color: #fff; font-size: var(--tx-sm); margin-bottom: var(--s4); letter-spacing: .02em; }
.site-footer a { color: rgba(255,255,255,.68); font-size: var(--tx-sm); }
.site-footer a:hover { color: #fff; }
.footer-grid { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: var(--s10); }
.footer-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.footer-brand .brand-name { color: #fff; }
.footer-brand p { font-size: var(--tx-sm); margin-top: var(--s4); max-width: 34ch; }
.footer-bottom {
  margin-top: var(--s12); padding-top: var(--s6); border-top: 1px solid rgba(255,255,255,.12);
  display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: space-between; font-size: var(--tx-sm);
}

/* ── 10. MARKETING SECTIONS ──────────────────────────────────────── */
.section { padding: var(--s20) 0; }
.section-soft { background: var(--bg-soft); }
.section-warm { background: linear-gradient(180deg, var(--bg-warm), #fff); }

.eyebrow {
  display: block; text-align: center; font-size: var(--tx-sm); font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--brand); margin-bottom: var(--s3);
}
.section-title { text-align: center; font-size: var(--tx-2xl); margin-bottom: var(--s3); }
.section-sub { text-align: center; color: var(--text-2); max-width: 60ch; margin: 0 auto var(--s12); }

/* Hero */
.hero { position: relative; padding: var(--s16) 0 var(--s20); overflow: hidden; }
.hero::before {
  content: ''; position: absolute; inset: 0 auto auto 0;
  width: 620px; height: 620px; transform: translate(-42%, -34%);
  background: radial-gradient(circle, rgba(242,101,34,.10), transparent 66%);
  border-radius: 50%; pointer-events: none;
}
.hero::after {
  content: ''; position: absolute; top: -120px; right: -180px;
  width: 720px; height: 720px;
  background: radial-gradient(circle, rgba(242,101,34,.09), transparent 62%);
  border-radius: 50%; pointer-events: none;
}
.hero .container { position: relative; z-index: 1; }
.hero-grid { display: grid; grid-template-columns: minmax(0,.9fr) minmax(0,1.1fr); gap: var(--s12); align-items: center; }

.pill {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: 7px 16px; border-radius: var(--r-pill);
  background: var(--brand-50); color: var(--brand-700);
  font-size: var(--tx-sm); font-weight: 600; margin-bottom: var(--s6);
}
.hero h1 { font-size: var(--tx-4xl); line-height: 1.18; margin-bottom: var(--s5); }
.hero h1 em { font-style: normal; color: var(--brand); }
.hero-lead { font-size: var(--tx-md); color: var(--text-2); max-width: 52ch; margin-bottom: var(--s8); }

.hero-features { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--s5); margin-bottom: var(--s8); }
.hero-feature { display: flex; gap: 10px; align-items: flex-start; }
.hero-feature .ico {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  background: var(--brand-50); color: var(--brand);
  display: grid; place-items: center; border: 1px solid var(--brand-100);
}
.hero-feature .ico svg { width: 18px; height: 18px; }
.hero-feature strong { display: block; font-size: var(--tx-sm); color: var(--navy); line-height: 1.35; }
.hero-feature span { font-size: var(--tx-xs); color: var(--text-2); }

.hero-cta { display: flex; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s8); }

.trust-row { display: flex; flex-wrap: wrap; gap: var(--s8); }
.trust-item { display: flex; gap: 10px; align-items: center; }
.trust-item .ico { width: 30px; height: 30px; border-radius: 9px; background: var(--brand-50); color: var(--brand); display: grid; place-items: center; flex: none; }
.trust-item .ico svg { width: 16px; height: 16px; }
.trust-item strong { display: block; font-size: var(--tx-sm); color: var(--navy); line-height: 1.3; }
.trust-item span { font-size: var(--tx-xs); color: var(--text-2); }

/* Product UI preview — CSS composition, never fabricated business numbers */
.app-preview {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: var(--sh-lg); overflow: hidden;
}
.app-preview-bar {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--border); background: #fff;
}
.app-preview-search {
  flex: 1; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 7px 12px; font-size: var(--tx-xs); color: var(--muted);
}
.app-preview-body { display: grid; grid-template-columns: 168px 1fr; min-height: 380px; }
.app-preview-side { background: var(--surface-2); border-right: 1px solid var(--border); padding: var(--s3); }
.app-preview-side .item {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border-radius: var(--r-sm); font-size: var(--tx-xs); color: var(--text-2); margin-bottom: 2px;
}
.app-preview-side .item.is-active { background: var(--navy); color: #fff; font-weight: 600; }
.app-preview-side .item .dot { width: 14px; height: 14px; border-radius: 4px; background: currentColor; opacity: .35; flex: none; }
.app-preview-main { padding: var(--s4); background: var(--bg-soft); }

.preview-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s3); margin-bottom: var(--s3); }
.preview-kpi { background: #fff; border: 1px solid var(--border); border-radius: var(--r); padding: var(--s3); }
.preview-kpi .lbl { font-size: 9px; color: var(--text-2); margin-bottom: 4px; }
.preview-kpi .bar { height: 10px; border-radius: 3px; background: var(--surface-2); margin-bottom: 6px; }
.preview-kpi .bar.w-lg { width: 62%; background: var(--navy); opacity: .82; }
.preview-kpi .bar.w-md { width: 48%; background: var(--navy); opacity: .82; }
.preview-kpi .bar.w-sm { width: 36%; background: var(--navy); opacity: .82; }
.preview-kpi .delta { height: 6px; width: 40%; border-radius: 3px; background: var(--brand-100); }

.preview-panels { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--s3); }
.preview-panel { background: #fff; border: 1px solid var(--border); border-radius: var(--r); padding: var(--s3); }
.preview-panel .ttl { height: 8px; width: 42%; border-radius: 3px; background: var(--border-2); margin-bottom: var(--s3); }
.preview-chart { height: 104px; display: block; width: 100%; }
.preview-donut { display: grid; place-items: center; height: 104px; }
.preview-legend { display: flex; flex-direction: column; gap: 6px; margin-top: var(--s2); }
.preview-legend i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 6px; }
.preview-legend span { font-size: 9px; color: var(--text-2); }

/* Feature grid */
.feature-grid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--s5); }
.feature-card {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--s6); transition: border-color .18s, box-shadow .18s, transform .18s;
}
.feature-card:hover { border-color: var(--brand-100); box-shadow: var(--sh-md); transform: translateY(-2px); }
.feature-card .ico {
  width: 48px; height: 48px; border-radius: var(--r); margin-bottom: var(--s4);
  background: var(--brand-50); color: var(--brand); display: grid; place-items: center;
  border: 1px solid var(--brand-100);
}
.feature-card .ico svg { width: 24px; height: 24px; }
.feature-card h3 { font-size: var(--tx-md); margin-bottom: var(--s2); }
.feature-card p { font-size: var(--tx-sm); color: var(--text-2); margin: 0; }

/* Use cases */
.usecase-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--s4); }
.usecase-card {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s5); display: flex; flex-direction: column; gap: var(--s2);
}
.usecase-card .ico { width: 38px; height: 38px; border-radius: 10px; background: var(--brand-50); color: var(--brand); display: grid; place-items: center; }
.usecase-card .ico svg { width: 19px; height: 19px; }
.usecase-card h4 { margin: 0; font-size: var(--tx-base); color: var(--navy); }
.usecase-card p { margin: 0; font-size: var(--tx-sm); color: var(--text-2); }

/* Split feature section (certificate / API) */
.split { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--s16); align-items: center; }
.split-list { list-style: none; margin: var(--s6) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--s4); }
.split-list li { display: flex; gap: var(--s3); align-items: flex-start; }
.split-list .tick {
  width: 24px; height: 24px; border-radius: 50%; flex: none; margin-top: 2px;
  background: var(--brand-50); color: var(--brand); display: grid; place-items: center;
}
.split-list .tick svg { width: 13px; height: 13px; }
.split-list strong { display: block; color: var(--navy); font-size: var(--tx-base); }
.split-list span { font-size: var(--tx-sm); color: var(--text-2); }

/* Certificate preview — sample only, never a real person's data */
.cert-preview {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-lg); padding: var(--s8); text-align: center; position: relative;
  border-top: 6px solid var(--brand);
}
.cert-preview .cert-kicker { font-size: var(--tx-xs); letter-spacing: .18em; text-transform: uppercase; color: var(--brand); font-weight: 700; }
.cert-preview h3 { font-size: var(--tx-xl); margin: var(--s2) 0 var(--s5); }
.cert-preview .cert-name { font-size: var(--tx-lg); font-weight: 700; color: var(--navy); border-bottom: 2px dashed var(--border-2); display: inline-block; padding: 0 var(--s6) 6px; margin-bottom: var(--s3); }
.cert-preview .cert-course { color: var(--text-2); font-size: var(--tx-sm); margin-bottom: var(--s6); }
.cert-foot { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s6); margin-top: var(--s6); }
.cert-qr { width: 74px; height: 74px; border: 1px solid var(--border); border-radius: var(--r-sm); display: grid; place-items: center; background: var(--surface-2); }
.cert-meta { text-align: left; font-size: var(--tx-xs); color: var(--text-2); }
.cert-sign { text-align: right; font-size: var(--tx-xs); color: var(--text-2); }
.cert-sign .line { width: 130px; border-top: 1px solid var(--border-2); margin-bottom: 6px; }

/* Code sample (API section) */
.code-card {
  background: var(--navy); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--sh-lg);
}
.code-head { display: flex; align-items: center; gap: 6px; padding: var(--s3) var(--s4); border-bottom: 1px solid rgba(255,255,255,.10); }
.code-head .dot { width: 10px; height: 10px; border-radius: 50%; background: rgba(255,255,255,.22); }
.code-head .name { margin-left: var(--s3); font-size: var(--tx-xs); color: rgba(255,255,255,.55); font-family: ui-monospace, monospace; }
.code-card pre {
  margin: 0; padding: var(--s5); overflow-x: auto;
  font-family: ui-monospace, 'IBM Plex Mono', monospace; font-size: .8125rem; line-height: 1.75;
  color: #D7E0EE;
}
.code-card .k { color: #FFB07C; }
.code-card .s { color: #93E4B0; }
.code-card .c { color: #7A8CA8; }

/* Pricing */
.pricing-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--s5); align-items: stretch; }
.plan {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--s6); display: flex; flex-direction: column;
}
.plan.is-featured { border-color: var(--brand); box-shadow: 0 12px 32px rgba(242,101,34,.14); position: relative; }
.plan.is-featured::after {
  content: 'แนะนำ'; position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
  background: var(--brand); color: #fff; font-size: var(--tx-xs); font-weight: 700;
  padding: 4px 14px; border-radius: var(--r-pill);
}
.plan h3 { font-size: var(--tx-md); margin-bottom: var(--s1); }
.plan .plan-tagline { font-size: var(--tx-sm); color: var(--text-2); min-height: 42px; margin-bottom: var(--s4); }
.plan-price { display: flex; align-items: baseline; gap: 6px; margin-bottom: var(--s2); }
.plan-price .amount { font-size: var(--tx-2xl); font-weight: 700; color: var(--navy); letter-spacing: -.02em; }
.plan-price .unit { font-size: var(--tx-sm); color: var(--text-2); }
.plan-learners { font-size: var(--tx-sm); color: var(--brand-700); background: var(--brand-50); border-radius: var(--r-sm); padding: 6px 10px; display: inline-block; margin-bottom: var(--s5); font-weight: 600; }
.plan-features { list-style: none; margin: 0 0 var(--s6); padding: 0; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.plan-features li { display: flex; gap: 10px; font-size: var(--tx-sm); color: var(--text-2); }
.plan-features svg { width: 16px; height: 16px; color: var(--brand); flex: none; margin-top: 4px; }

/* CTA band */
.cta-band {
  background: linear-gradient(135deg, var(--navy), #24395F);
  border-radius: var(--r-xl); padding: var(--s16) var(--s10); text-align: center; color: #fff;
  position: relative; overflow: hidden;
}
.cta-band::after {
  content: ''; position: absolute; right: -80px; bottom: -140px; width: 420px; height: 420px;
  background: radial-gradient(circle, rgba(242,101,34,.30), transparent 66%); border-radius: 50%;
}
.cta-band h2 { color: #fff; position: relative; }
.cta-band p { color: rgba(255,255,255,.76); max-width: 56ch; margin-inline: auto; position: relative; }
.cta-band .hero-cta { justify-content: center; position: relative; margin-bottom: 0; }

/* ── 11. AUTH PAGES ──────────────────────────────────────────────── */
.auth-page { min-height: 100vh; display: flex; flex-direction: column; background: #fff; }
.auth-main { flex: 1; position: relative; overflow: hidden; }
.auth-main::before {
  content: ''; position: absolute; left: -260px; top: -160px; width: 720px; height: 720px;
  background: radial-gradient(circle, rgba(242,101,34,.09), transparent 64%); border-radius: 50%; pointer-events: none;
}
.auth-main::after {
  content: ''; position: absolute; left: -40px; bottom: -60px; width: 320px; height: 320px;
  background-image: radial-gradient(circle, rgba(242,101,34,.16) 1.6px, transparent 1.6px);
  background-size: 16px 16px; opacity: .5; pointer-events: none;
}
.auth-grid {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: var(--s16); align-items: center; padding: var(--s16) 0;
}
.auth-intro h1 { font-size: var(--tx-3xl); line-height: 1.24; margin-bottom: var(--s4); }
.auth-intro h1 em { font-style: normal; color: var(--brand); }
.auth-intro > p { color: var(--text-2); font-size: var(--tx-md); max-width: 44ch; margin-bottom: var(--s8); }

.auth-features { list-style: none; margin: 0 0 var(--s8); padding: 0; display: flex; flex-direction: column; gap: var(--s5); }
.auth-features li { display: flex; gap: var(--s4); align-items: flex-start; }
.auth-features .ico {
  width: 44px; height: 44px; border-radius: var(--r); flex: none;
  background: #fff; border: 1px solid var(--brand-100); color: var(--brand);
  display: grid; place-items: center; box-shadow: var(--sh-xs);
}
.auth-features .ico svg { width: 21px; height: 21px; }
.auth-features strong { display: block; color: var(--navy); font-size: var(--tx-base); line-height: 1.4; }
.auth-features span { font-size: var(--tx-sm); color: var(--text-2); }

.trust-box {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--s6); box-shadow: var(--sh-sm); display: flex; gap: var(--s5); align-items: flex-start;
}
.trust-shield {
  width: 68px; height: 68px; border-radius: var(--r-md); flex: none;
  background: linear-gradient(135deg, var(--brand-50), var(--brand-100));
  color: var(--brand); display: grid; place-items: center;
}
.trust-shield svg { width: 34px; height: 34px; }
.trust-box h4 { margin: 0 0 6px; font-size: var(--tx-md); }
.trust-box > div > p { font-size: var(--tx-sm); color: var(--text-2); margin: 0 0 var(--s4); }
.trust-badges { display: flex; flex-wrap: wrap; gap: var(--s5); }
.trust-badges .trust-item span { display: block; }

.auth-card {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: var(--sh-lg); padding: var(--s10);
}
.auth-card h2 { font-size: var(--tx-xl); margin-bottom: 6px; }
.auth-card > p.auth-card-sub { color: var(--text-2); font-size: var(--tx-sm); margin-bottom: var(--s6); }

.auth-label-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s2); }
.auth-label-row .label { margin-bottom: 0; }
.auth-label-row a { font-size: var(--tx-sm); font-weight: 600; }

.auth-divider { display: flex; align-items: center; gap: var(--s4); margin: var(--s6) 0; color: var(--muted); font-size: var(--tx-sm); }
.auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }

.auth-foot { text-align: center; font-size: var(--tx-sm); color: var(--text-2); margin-top: var(--s6); }
.auth-foot a { font-weight: 600; }

.auth-icon-badge {
  width: 92px; height: 92px; border-radius: 50%; margin: 0 auto var(--s5);
  background: var(--brand-50); color: var(--brand); display: grid; place-items: center;
}
.auth-icon-badge svg { width: 44px; height: 44px; }

.auth-footer {
  border-top: 1px solid var(--border); padding: var(--s5) 0;
  display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: space-between;
  font-size: var(--tx-sm); color: var(--text-2);
}
.auth-footer nav { display: flex; flex-wrap: wrap; gap: var(--s4); }
.auth-footer a { color: var(--text-2); }
.auth-footer a:hover { color: var(--brand); }

/* ── 12. APP SHELL ───────────────────────────────────────────────── */
.app-header { background: #fff; border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 90; }
.app-header .container { display: flex; align-items: center; gap: var(--s5); height: 68px; }

.app-nav { display: flex; align-items: center; gap: 2px; margin-inline: auto; }
.app-nav > * { position: relative; }
.app-nav a, .app-nav .navbtn {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 13px; border-radius: var(--r-sm); background: none; border: 0; cursor: pointer;
  font-family: inherit; font-size: .9375rem; font-weight: 500; color: var(--text-2); white-space: nowrap;
}
.app-nav a:hover, .app-nav .navbtn:hover { background: var(--surface-2); color: var(--navy); }
.app-nav a.is-active, .app-nav .navbtn.is-active { background: var(--brand-50); color: var(--brand-700); font-weight: 600; }
.app-nav svg { width: 17px; height: 17px; }
/* Platform staff wear a dark header. Which identity you are signed in with
   is the one thing you must not have to work out from the menu labels (§3),
   and the banner on the page only says so once you are already reading it.
   A surface swap only: same height, same spacing, same type scale, same
   dropdown panels — nothing moves when the colour changes.

   **Every selector below stops at the bar itself.** The dropdown panels are
   still white, so `.app-nav a` — which matches the links inside them too —
   would paint pale grey text onto a white panel, and its hover rule would
   paint white text onto it, which is a menu item that disappears when you
   reach for it. The bar's own items are `.app-nav > a` and the dropdown
   toggles; what hangs below the bar keeps the light theme it is drawn on. */
.app-header.is-platform { background: var(--platform-bar); border-bottom-color: var(--platform-bar-line); }
.app-header.is-platform .brand-name { color: #fff; }
.app-header.is-platform .app-nav > a,
.app-header.is-platform .app-nav > .dropdown > .navbtn,
.app-header.is-platform .bell,
.app-header.is-platform .nav-toggle,
.app-header.is-platform .lang-switch { color: var(--platform-bar-text); }
.app-header.is-platform .lang-switch { border-color: var(--platform-bar-line); background: transparent; }
.app-header.is-platform .app-nav > a:hover,
.app-header.is-platform .app-nav > .dropdown > .navbtn:hover,
.app-header.is-platform .bell:hover,
.app-header.is-platform .nav-toggle:hover,
.app-header.is-platform .lang-switch:hover,
.app-header.is-platform .user-menu:hover { background: var(--platform-bar-hover); color: #fff; }
.app-header.is-platform .app-nav > a.is-active,
.app-header.is-platform .app-nav > .dropdown > .navbtn.is-active { background: var(--platform-bar-active); color: #fff; }
.app-header.is-platform .user-menu .who strong { color: #fff; }
.app-header.is-platform .user-menu .who span { color: var(--platform-bar-muted); }

/* A submenu row is scannable by shape before it is read: the tile carries
   the same icon language as the top row, in the accent rather than as a
   filled orange block. Applies to both navigations — the platform menu and
   the organization menus are the same kind of list. */
.dropdown-menu .mi {
  flex: none; display: grid; place-items: center; width: 28px; height: 28px;
  border-radius: var(--r-sm); background: var(--brand-50); color: var(--brand);
}
.dropdown-menu .mi svg { width: 16px; height: 16px; }
.dropdown-menu a:hover .mi { background: var(--brand-100); color: var(--brand-700); }

.dropdown { position: relative; }
.dropdown-menu {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 220px; z-index: 120;
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--sh-md); padding: 6px; display: none;
}
.dropdown-menu.is-open { display: block; }
.dropdown-menu.to-right { left: auto; right: 0; }
.dropdown-menu a,
.dropdown-menu button {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--r-sm);
  font-size: var(--tx-sm); color: var(--text-2); font-weight: 500;
}
/* An item that changes state is a POST, so it is a button in a form —
   it still has to read as one of the items above it. */
.dropdown-menu button {
  width: 100%; background: none; border: 0; cursor: pointer;
  font-family: inherit; text-align: left;
}
.dropdown-menu a:hover,
.dropdown-menu button:hover { background: var(--surface-2); color: var(--navy); }
.dropdown-menu .sep { height: 1px; background: var(--border); margin: 6px 0; }

.avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  background: var(--brand-50); color: var(--brand-700);
  display: grid; place-items: center; font-size: var(--tx-sm); font-weight: 700;
  border: 1px solid var(--brand-100);
}
.user-menu { display: flex; align-items: center; gap: 10px; background: none; border: 0; cursor: pointer; padding: 4px; border-radius: var(--r); font-family: inherit; }
.avatar-sm { width: 28px; height: 28px; font-size: var(--tx-xs); }
.user-menu:hover { background: var(--surface-2); }
.user-menu .who { text-align: left; line-height: 1.25; }
.user-menu .who strong { display: block; font-size: var(--tx-sm); color: var(--navy); }
.user-menu .who span { font-size: var(--tx-xs); color: var(--text-2); }

/* The bottom padding keeps the Assistant FAB off the page's own controls.
   The button is position:fixed in the bottom-right corner, so whatever
   happens to be rendered there is under it — and a browser audit found it
   covering primary submit buttons ("เพิ่มผู้ใช้", "มอบหมายหลักสูตร"), the
   per-page <select> under long tables, and a learner's "เรียนต่อ" card. On a
   short form the page is already at its end, so there is nowhere to scroll
   to get out from under it. Reserving the button's own footprint at the end
   of the scroll area means the last control can always be scrolled clear.
   --fab-clear is the FAB (60px) plus its offset and a little breathing room;
   the phone value below tracks the smaller 54px button. */
:root { --fab-clear: 108px; }
.app-main { padding: var(--s8) 0 calc(var(--s16) + var(--fab-clear)); background: var(--bg-soft); min-height: calc(100vh - 68px); }

/* The backoffice is a working surface, not a reading column. Tables,
   filter rows and KPI strips have more to show than the 1200px measure
   the marketing pages are set in — at 1920px that measure left a third
   of the screen empty while a six-card KPI row wrapped to two lines.
   Only the application shell widens; the public site keeps its measure,
   where line length is the thing being protected. */
.app-header .container,
.app-main .container { max-width: none; padding-inline: var(--s8); }

.page-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s5); margin-bottom: var(--s6); flex-wrap: wrap; }
.page-header h1 { font-size: var(--tx-xl); margin-bottom: 4px; }
.page-header p { margin: 0; color: var(--text-2); font-size: var(--tx-sm); }
.page-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }

.breadcrumb { display: flex; align-items: center; gap: 8px; font-size: var(--tx-sm); color: var(--muted); margin-bottom: var(--s3); flex-wrap: wrap; }
.breadcrumb a { color: var(--text-2); }
.breadcrumb a:hover { color: var(--brand); }

/* Two-column page layout (main + side).
   Ratios come in as --ca/--cb so a page can weight the columns without
   inlining a grid that would never collapse — the breakpoint below is what
   makes these usable on a phone. */
.cols {
  display: grid;
  grid-template-columns: minmax(0, var(--ca, 2fr)) minmax(0, var(--cb, 1fr));
  gap: var(--s5);
  align-items: start;
}
/* Grid items default to min-width:auto, so a wide child — a table carrying
   min-width:640px, a long unbroken string — pushes the whole column past the
   viewport instead of scrolling inside its own container. minmax(0, …) and
   min-width:0 are what let the column actually shrink. */
.cols > * { min-width: 0; }
@media (max-width: 1100px) {
  .cols { grid-template-columns: minmax(0, 1fr); }
}

/* KPI tiles */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--s4); margin-bottom: var(--s6); }
.kpi {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s5); display: flex; gap: var(--s4); align-items: flex-start;
}
.kpi .ico { width: 42px; height: 42px; border-radius: var(--r); background: var(--brand-50); color: var(--brand); display: grid; place-items: center; flex: none; }
.kpi .ico svg { width: 21px; height: 21px; }
.kpi .lbl { font-size: var(--tx-sm); color: var(--text-2); margin-bottom: 2px; }
.kpi .val { font-size: var(--tx-xl); font-weight: 700; color: var(--navy); line-height: 1.2; letter-spacing: -.01em; }
.kpi .sub { font-size: var(--tx-xs); color: var(--muted); }

/* Tabs */
.tabs { display: flex; gap: var(--s1); border-bottom: 1px solid var(--border); margin-bottom: var(--s6); overflow-x: auto; }
.tabs a {
  padding: 11px 16px; font-size: var(--tx-sm); font-weight: 600; color: var(--text-2);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
}
.tabs a:hover { color: var(--navy); }
.tabs a.is-active { color: var(--brand); border-bottom-color: var(--brand); }

/* Hint lines: a rule the form is about to check, said before it is broken. */
.hint-line { display: flex; align-items: flex-start; gap: 8px; font-size: var(--tx-sm); color: var(--text-2); }
.hint-line + .hint-line { margin-top: var(--s2); }
.hint-line > svg { flex: none; margin-top: 1px; }
.hint-line.is-ok > svg { color: var(--success); }
.hint-line.is-info > svg { color: var(--info); }
.hint-line.is-warn > svg { color: var(--warning); }
.hint-line.is-danger > svg { color: var(--danger); }

/* One-click ranges. They write into the date inputs rather than holding
   state of their own, so the lit chip is always the dates actually in use. */
.chip-group { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chip-group a {
  padding: 8px 14px; border-radius: var(--r-sm); border: 1px solid var(--border-2);
  font-size: var(--tx-sm); font-weight: 600; color: var(--text-2); background: #fff;
}
.chip-group a:hover { border-color: var(--brand); color: var(--brand); }
.chip-group a.is-active { background: var(--brand); border-color: var(--brand); color: #fff; }

/* Filter panel: a form too wide for .toolbar's single row. */
.filter-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s4); padding: var(--s5) var(--s6);
}
.filter-grid .field { margin: 0; }
.filter-grid .field-wide { grid-column: 1 / -1; }
.filter-actions {
  display: flex; align-items: flex-end; justify-content: flex-end; gap: var(--s3);
}

/* ── 13. TABLES & LIST TOOLBAR ───────────────────────────────────── */
.toolbar {
  display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center;
  padding: var(--s4) var(--s5); border-bottom: 1px solid var(--border);
}
.toolbar .search { flex: 1 1 260px; min-width: 200px; }
.toolbar .input, .toolbar .select { padding: 9px 14px; font-size: var(--tx-sm); }
.toolbar .input-icon .input { padding-left: 40px; }
.toolbar .input-icon > svg { width: 17px; left: 13px; }

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.table th, .table td { padding: 13px 16px; text-align: left; vertical-align: middle; }
.table thead th {
  font-size: var(--tx-sm); font-weight: 600; color: var(--text-2);
  background: var(--surface-2); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table thead th a { color: inherit; display: inline-flex; align-items: center; gap: 4px; }
.table thead th a:hover { color: var(--navy); }
.table tbody tr { border-bottom: 1px solid var(--border); }
.table tbody tr:last-child { border-bottom: 0; }
.table tbody tr:hover { background: var(--bg-soft); }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
.table .actions { text-align: right; white-space: nowrap; }

.cell-main { display: flex; align-items: center; gap: 10px; }
.cell-main strong { display: block; color: var(--navy); font-weight: 600; }
.cell-main span { display: block; font-size: var(--tx-xs); color: var(--text-2); }

.progress { height: 6px; background: var(--border); border-radius: var(--r-pill); overflow: hidden; min-width: 90px; }
.progress > i { display: block; height: 100%; background: var(--brand); border-radius: inherit; }
.progress.is-done > i { background: var(--success); }

.pagination {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s3); padding: var(--s4) var(--s5); border-top: 1px solid var(--border);
  font-size: var(--tx-sm); color: var(--text-2);
}
.pagination .pages { display: flex; gap: 4px; }
.pagination .pages a, .pagination .pages span {
  min-width: 34px; height: 34px; padding: 0 10px; border-radius: var(--r-sm);
  display: grid; place-items: center; font-weight: 600; color: var(--text-2); border: 1px solid transparent;
}
.pagination .pages a:hover { background: var(--surface-2); color: var(--navy); }
.pagination .pages .is-active { background: var(--brand); color: #fff; }
.pagination .pages .is-gap { color: var(--muted); font-weight: 400; }
.pagination .per-page { display: flex; align-items: center; gap: var(--s2); }
.pagination .per-page .select { padding: 6px 32px 6px 10px; font-size: var(--tx-sm); width: auto; }

/* ── 14. EMPTY / LOADING / ERROR ─────────────────────────────────── */
.state { text-align: center; padding: var(--s16) var(--s6); }
.state .ico {
  width: 64px; height: 64px; border-radius: var(--r-lg); margin: 0 auto var(--s5);
  background: var(--surface-2); color: var(--muted); display: grid; place-items: center;
}
.state .ico svg { width: 30px; height: 30px; }
.state h3 { font-size: var(--tx-md); margin-bottom: var(--s2); }
.state p { color: var(--text-2); font-size: var(--tx-sm); max-width: 46ch; margin: 0 auto var(--s5); }
.state.is-error .ico { background: var(--danger-bg); color: var(--danger); }

.spinner {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2.5px solid var(--border-2); border-top-color: var(--brand);
  animation: spin .7s linear infinite; display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--border) 37%, var(--surface-2) 63%);
  background-size: 400% 100%; animation: shimmer 1.3s ease infinite; border-radius: var(--r-sm);
}
@keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ── 15. MODAL & DRAWER ──────────────────────────────────────────── */
/* Hidden until .is-open — a single static modal in the page is toggled by
   the delegated listener in omc.js, rather than one hidden copy per row. */
.modal-backdrop {
  display: none; position: fixed; inset: 0; background: rgba(27,42,74,.42); z-index: 1000;
  align-items: center; justify-content: center; padding: var(--s6);
}
.modal-backdrop.is-open { display: flex; }
.modal {
  background: #fff; border-radius: var(--r-lg); box-shadow: var(--sh-lg);
  width: 100%; max-width: 560px; max-height: calc(100vh - 96px); display: flex; flex-direction: column;
}
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); padding: var(--s5) var(--s6); border-bottom: 1px solid var(--border); }
.modal-head h3 { margin: 0; font-size: var(--tx-md); }
.modal-body { padding: var(--s6); overflow-y: auto; }
.modal-body pre {
  margin: 0; white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, monospace; font-size: var(--tx-sm); color: var(--text);
}
.modal-foot { padding: var(--s4) var(--s6); border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: var(--s2); }
.modal-close { background: none; border: 0; cursor: pointer; color: var(--muted); padding: 6px; border-radius: var(--r-sm); display: flex; }
.modal-close:hover { background: var(--surface-2); color: var(--navy); }

.drawer-backdrop { position: fixed; inset: 0; background: rgba(27,42,74,.42); z-index: 1000; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(460px, 100vw); z-index: 1001;
  background: #fff; box-shadow: var(--sh-lg); display: flex; flex-direction: column;
  animation: drawerIn .2s ease;
}
@keyframes drawerIn { from { transform: translateX(24px); opacity: .6; } to { transform: none; opacity: 1; } }

/* ── 15b. PERMISSION REFERENCE SHEET ─────────────────────────────
   The read-only "what can each role do" panel on the user form.

   Opened by CSS :target — the trigger is a link to this element's id and
   the close controls are links that clear the fragment — so it works with
   no JavaScript at all (§1). It is `position: fixed` and hidden until
   targeted, which is the part that matters on that screen: the form must
   not move, reflow or grow when somebody opens the reference. It slides
   over the page and slides off it again. */
.perm-sheet { display: none; }
.perm-sheet:target { display: block; }

.perm-sheet-backdrop {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(27,42,74,.42);
}

.perm-sheet-panel {
  position: fixed; z-index: 1001;
  top: 0; right: 0; bottom: 0;
  width: min(1080px, 100vw);
  background: #fff; box-shadow: var(--sh-lg);
  display: flex; flex-direction: column;
  animation: permSheetIn .18s ease;
}
@keyframes permSheetIn { from { transform: translateX(28px); opacity: .5; } to { transform: none; opacity: 1; } }

.perm-sheet-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s5) var(--s6); border-bottom: 1px solid var(--border); flex: none;
}
.perm-sheet-head h3 { margin: 0; font-size: var(--tx-md); }
.perm-sheet-body { padding: var(--s6); overflow-y: auto; flex: 1 1 auto; }
.perm-sheet-foot {
  padding: var(--s4) var(--s6); border-top: 1px solid var(--border); flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap;
}

/* The matrix itself. Row headers stay readable while the columns scroll. */
.perm-table th[scope="row"] { font-weight: 600; color: var(--navy); white-space: nowrap; }
.perm-table td { vertical-align: middle; }
.perm-table td .badge { margin: 1px 2px 1px 0; }
.perm-none { color: var(--muted); }

.perm-legend {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  font-size: var(--tx-sm); color: var(--text-2);
}

/* The sentence under the role dropdown, and the way to the table. */
.role-summary { margin: var(--s3) 0 2px; }
.role-summary-text {
  margin: 0; padding: var(--s3) var(--s4);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
  font-size: var(--tx-sm); color: var(--text-2); line-height: 1.6;
}
.role-perm-link {
  display: inline-flex; align-items: center; gap: 6px; margin-top: var(--s3);
  font-size: var(--tx-sm); color: var(--brand-700); font-weight: 500;
}
.role-perm-link:hover { color: var(--brand); text-decoration: underline; }
/* ── 16. RESPONSIVE ──────────────────────────────────────────────── */
/* Seven items, a brand and two buttons stop fitting long before the phone menu
   takes over at 860px — and English is the tight case, because its labels are
   wider than the Thai they translate ("ศูนย์ความรู้" → "Knowledge centre").
   The row gives here rather than pushing the page into a sideways scroll. */
@media (min-width: 1061px) and (max-width: 1320px) {
  .site-header .container { gap: var(--s3); }
  .site-header-card .container { padding-inline: var(--s4); }
  .site-nav { gap: 0; }
  .site-nav > a { padding: 8px 7px 10px; font-size: .75rem; }
  .site-nav > a svg { width: 20px; height: 20px; }
  .site-header-card .header-actions { padding-left: var(--s3); gap: var(--s2); }
  .site-header-card .btn { padding: 11px 16px; font-size: var(--tx-sm); }
}

@media (max-width: 1100px) {
  /* The application header gives before the phone menu takes over at 860px,
     for the same reason the public one does: English labels are wider than
     the Thai they translate. */
  .app-header .container { gap: var(--s3); }
  .app-nav a, .app-nav .navbtn { padding: 9px 9px; font-size: .875rem; }
  .hero-grid { grid-template-columns: 1fr; gap: var(--s10); }
  .hero-features { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .feature-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .usecase-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .pricing-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .split { grid-template-columns: 1fr; gap: var(--s10); }
  .auth-grid { grid-template-columns: 1fr; gap: var(--s10); padding: var(--s10) 0; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: var(--s8); }
}

/* Below this the application header cannot hold the navigation, the account
   name and the organization name at once — in English it runs off the right
   edge. The name is what goes: the avatar still identifies the account, and
   the navigation is what the page is there for. */
@media (max-width: 1000px) {
  .user-menu .who { display: none; }
}

/* The public navigation folds into the menu button at 1060px, not at the 860px
   the application header uses: seven items with icons, a brand and two CTAs
   simply stop fitting first, and in English they stop fitting sooner still. */
@media (max-width: 1060px) {
  .site-header .nav-toggle { display: flex; order: 3; flex: none; }
  /* The panel hangs off the header card, so it is anchored to the card
     (position: relative) rather than to a fixed header height. */
  .site-nav {
    position: absolute; top: calc(100% + 8px); left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
    box-shadow: var(--sh-md);
    padding: var(--s3); display: none;
  }
  .site-nav.is-open { display: flex; }
  /* Icon beside the label, not above it: a stacked column wastes the height of
     a menu panel and reads as a grid of tiles. */
  .site-nav > a {
    flex-direction: row; justify-content: flex-start; gap: var(--s3);
    padding: 12px 14px; font-size: var(--tx-base); text-align: left;
  }
  .site-nav > a svg { width: 22px; height: 22px; }
  .site-nav > a.is-active { background: var(--brand-50); }
  .site-nav > a.is-active::after { display: none; }
  .nav-only-mobile a { padding: 12px 14px; }
  .nav-only-mobile {
    display: flex; flex-direction: column;
    border-top: 1px solid var(--border); margin-top: var(--s2); padding-top: var(--s2);
  }
  /* With the navigation folded away the rule before the actions has nothing
     left to separate. */
  .site-header-card .header-actions { margin-left: auto; padding-left: 0; border-left: 0; }
}

@media (max-width: 860px) {
  :root { --tx-3xl: 2rem; --tx-4xl: 2.35rem; --tx-2xl: 1.6rem; }

  /* ── Phone headers ──────────────────────────────────────────────
     Both headers are a single flex row. On a phone the brand, the CTAs
     and the user block together are wider than the viewport, which pushed
     the menu button off-screen entirely — leaving no way to open the
     navigation at all. Everything optional is dropped here so the toggle
     is always reachable, and the row is allowed to shrink. */
  .app-header .nav-toggle { display: flex; order: 3; flex: none; }
  .site-header .container,
  .app-header .container { gap: var(--s2); min-width: 0; }
  .brand { min-width: 0; overflow: hidden; }
  /* The card tightens on a phone: a 24px radius and a 76px row read as a
     panel rather than a header once the viewport is 390px wide. */
  .site-header-card { padding: 8px 0; }
  .site-header-card .container { min-height: 64px; padding-inline: var(--s4); border-radius: var(--r-lg); }
  .brand-tagline { display: none; }
  .header-actions { min-width: 0; flex: none; }
  .header-actions .btn-outline,
  .header-actions .btn-primary,
  .header-actions > .text-muted,
  .header-actions > a:not(.btn) { display: none; }

  /* Keep the avatar as the account affordance, drop the name and org
     text that made the app header overflow. */
  .user-menu .who,
  .user-menu > svg { display: none; }
  .user-menu { padding: 0; }

  /* The language control stays reachable everywhere; only its label goes. */
  .lang-switch { padding: 9px 10px; }
  .lang-switch .lang-name,
  .lang-switch svg:last-child { display: none; }

  /* Login/register: the form comes first on mobile so marketing copy
     never pushes it below the fold (§14). */
  .auth-grid { display: flex; flex-direction: column; }
  .auth-form-col { order: 1; }
  .auth-intro { order: 2; }
  .auth-card { padding: var(--s6); }

  .section { padding: var(--s12) 0; }
  .cta-band { padding: var(--s12) var(--s6); }
  .app-preview-body { grid-template-columns: 1fr; }
  .app-preview-side { display: none; }
  .preview-kpis { grid-template-columns: repeat(2, 1fr); }
  .preview-panels { grid-template-columns: 1fr; }

  .app-header .container { height: 60px; }
  .app-nav {
    position: fixed; inset: 60px 0 auto 0; background: #fff; flex-direction: column;
    align-items: stretch; padding: var(--s3); border-bottom: 1px solid var(--border);
    box-shadow: var(--sh-md); display: none; max-height: calc(100vh - 60px); overflow-y: auto; z-index: 95;
  }
  .app-nav.is-open { display: flex; }
  /* The stacked panel is the header, so it keeps the header's ground. */
  .app-header.is-platform .app-nav { background: var(--platform-bar); border-bottom-color: var(--platform-bar-line); }
  .dropdown-menu { position: static; box-shadow: none; border: 0; padding-left: var(--s5); }

  /* The reference sheet takes the whole screen on a phone; the matrix
     scrolls inside .table-wrap, never the page (§14). */
  .perm-sheet-panel { width: 100vw; }
  .perm-sheet-body, .perm-sheet-head, .perm-sheet-foot { padding-inline: var(--s4); }
  .perm-table { min-width: 900px; }

  /* Tables scroll inside their own container rather than the page. */
  .table { min-width: 640px; }
  .toolbar { padding: var(--s3) var(--s4); }
  .pagination { justify-content: center; }
}

@media (max-width: 560px) {
  .container,
  .app-header .container,
  .app-main .container { padding-inline: var(--s4); }
  .hero-features { grid-template-columns: 1fr; }
  .feature-grid, .usecase-grid, .pricing-grid { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr; gap: var(--s6); }
  .form-row { grid-template-columns: 1fr; }
  .trust-box { flex-direction: column; }
  .btn-lg { width: 100%; }
  .hero-cta .btn { width: 100%; }
  .page-header { flex-direction: column; }
  .cert-foot { flex-direction: column; align-items: flex-start; gap: var(--s4); }
}

/* ── 17. PRINT (certificate) ─────────────────────────────────────── */
@media print {
  .site-header, .app-header, .site-footer, .auth-footer, .page-actions, .no-print { display: none !important; }
  body { background: #fff; }
  .app-main { padding: 0; background: #fff; }
  .card { box-shadow: none; border: 0; }
}

/* ── 18. NOTIFICATION BELL ───────────────────────────────────────── */
.bell {
  position: relative; display: grid; place-items: center; flex: none;
  width: 40px; height: 40px; border-radius: var(--r); color: var(--text-2);
}
.bell:hover { background: var(--surface-2); color: var(--navy); }
.bell-dot {
  position: absolute; top: 4px; right: 4px; min-width: 17px; height: 17px;
  padding: 0 4px; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; border: 2px solid #fff;
  font-size: 10px; font-weight: 700; line-height: 13px; text-align: center;
}

/* ── 19. PAGE HERO BANNER (wallet, settings, …) ───────────────────── */
.page-hero {
  position: relative; overflow: hidden; display: flex; align-items: center;
  justify-content: space-between; gap: var(--s6);
  background: linear-gradient(135deg, var(--brand-50), #fff 65%);
  border: 1px solid var(--brand-100); border-radius: var(--r-xl);
  /* --s7 does not exist: the ladder is 4/8/12/16/20/24/32/40/48/64/80.
     An undeclared var() makes the whole declaration invalid at
     computed-value time, so this hero banner was rendering with no
     padding at all rather than with a value somebody could see was
     wrong. --s6 keeps the vertical smaller than the horizontal, which
     is what the two different rungs were reaching for. */
  padding: var(--s6) var(--s8); margin-bottom: var(--s6);
}
.page-hero h1 { font-size: var(--tx-2xl); margin-bottom: 4px; }
.page-hero p { margin: 0; color: var(--text-2); }
.page-hero-art { position: relative; width: 128px; height: 96px; flex: none; }
.page-hero-art .coin {
  position: absolute; display: grid; place-items: center; border-radius: 50%;
  background: linear-gradient(135deg, #FFB27A, var(--brand)); color: #fff;
  box-shadow: 0 6px 16px rgba(242,101,34,.28);
}
.page-hero-art .coin svg { width: 55%; height: 55%; }
.page-hero-art .coin.c1 { top: 0;    left: 6px;  width: 42px; height: 42px; }
.page-hero-art .coin.c2 { top: 4px;  right: 0;   width: 32px; height: 32px; }
.page-hero-art .coin.c3 { bottom: 6px; left: 44px; width: 26px; height: 26px; }
.page-hero-art .bag {
  position: absolute; bottom: 0; left: 26px; width: 76px; height: 58px;
  background: #fff; border: 1px solid var(--brand-100); color: var(--brand);
  border-radius: 14px 14px 10px 10px; box-shadow: var(--sh-md);
  display: grid; place-items: center;
}
.page-hero-art .bag svg { width: 32px; height: 32px; }

/* A looser cluster of floating icon badges for pages with no single "thing"
   to illustrate (settings, audit) — scattered dots rather than one scene. */
.page-hero-cluster { position: relative; width: 220px; height: 110px; flex: none; }
.page-hero-cluster .dot {
  position: absolute; display: grid; place-items: center; border-radius: 50%;
  background: #fff; border: 1px solid var(--brand-100); color: var(--brand);
  box-shadow: var(--sh-sm);
}
.page-hero-cluster .dot svg { width: 50%; height: 50%; }
.page-hero-cluster .dot.solid {
  background: linear-gradient(135deg, #FFB27A, var(--brand)); color: #fff; border: 0;
  box-shadow: 0 6px 16px rgba(242,101,34,.28);
}
.page-hero-cluster .d1 { top: 4px;   left: 6px;   width: 34px; height: 34px; }
.page-hero-cluster .d2 { top: 44px;  left: 60px;  width: 46px; height: 46px; }
.page-hero-cluster .d3 { top: 8px;   left: 116px; width: 30px; height: 30px; }
.page-hero-cluster .d4 { top: 50px;  left: 158px; width: 40px; height: 40px; }
.page-hero-cluster .d5 { top: 0;     left: 196px; width: 26px; height: 26px; }

.balance-card {
  background: linear-gradient(135deg, #FF8A4C, var(--brand)); color: #fff;
  border-radius: var(--r-lg); padding: var(--s6);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  box-shadow: 0 10px 24px rgba(242,101,34,.28);
}
.balance-card .lbl { font-size: var(--tx-sm); opacity: .92; margin-bottom: 4px; }
.balance-card .amt { font-size: var(--tx-2xl); font-weight: 700; line-height: 1.2; }
.balance-card .ico {
  width: 52px; height: 52px; border-radius: var(--r); flex: none;
  background: rgba(255,255,255,.2); display: grid; place-items: center;
}

.icon-badge {
  width: 40px; height: 40px; border-radius: var(--r); flex: none;
  background: var(--brand-50); color: var(--brand); display: grid; place-items: center;
  font-weight: 700; font-size: var(--tx-md);
}

/* A file input styled as a drop target. The <input> stays in the document
   and does the work — a <label> wrapping it opens the file picker on click
   with no JS at all, so drag-and-drop is a visual nicety, never a
   requirement (omc.js is progressive enhancement only). */
.upload-drop {
  position: relative; display: flex; align-items: center; gap: var(--s4);
  border: 1.5px dashed var(--border-2); border-radius: var(--r);
  background: var(--surface-2); padding: var(--s5); cursor: pointer;
  transition: border-color .16s, background .16s;
}
.upload-drop:hover, .upload-drop.is-dragover { border-color: var(--brand); background: var(--brand-50); }
.upload-drop input[type="file"] {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap;
}

/* ── 20. KNOWLEDGE CENTER ─────────────────────────────────────────── */
.kc-search { display: flex; gap: var(--s2); max-width: 34rem; margin: var(--s8) auto 0; }
.kc-search .input-icon { flex: 1 1 auto; }

.kc-breadcrumb {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: var(--tx-sm); color: var(--text-2); margin-bottom: var(--s5);
}
.kc-breadcrumb a { color: var(--text-2); }
.kc-breadcrumb a:hover { color: var(--brand); }
.kc-breadcrumb svg { width: 14px; height: 14px; color: var(--muted); }
.kc-breadcrumb > span { color: var(--navy); font-weight: 600; }

.kc-toolbar { border: 1px solid var(--border); border-radius: var(--r-lg); margin-bottom: var(--s6); }

/* A card link is a whole feature-card acting as an <a> — block display and
   inherited colour so it reads like the same card everywhere else, not a
   giant blue link. */
.kc-card-link { display: block; color: inherit; }
.kc-meta-line { display: inline-flex; align-items: center; gap: 4px; font-size: var(--tx-xs); margin-top: var(--s2); }

/* One row style shared by the recent-articles list on the home page and the
   article list on the category/search pages (§10 — one component, not three
   near-identical ones). */
.kc-list-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) var(--s6); border-bottom: 1px solid var(--border); color: inherit;
}
.kc-list-row:last-child { border-bottom: 0; }
.kc-list-row:hover { background: var(--bg-soft); }
.kc-list-row strong { display: block; color: var(--navy); }
.kc-list-row > span:first-child > span.text-muted { display: block; font-size: var(--tx-xs); margin-top: 2px; }
.kc-list-row .badge { margin-top: var(--s2); }

/* The body was capped at 760px, which left a third of a wide screen empty
   beside it and squeezed anything with columns — the permission matrix is
   nineteen rows by seven roles and had nowhere to go. It now takes the
   width the container allows; the container's own max-width is what keeps
   a line of prose from running the full width of a large monitor. */
.kc-article-layout { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: var(--s8); align-items: start; }
/* min-width:0 lets the body shrink inside its grid column; overflow-wrap stops
   an unbreakable token an author pasted in — an API key, a hash, a long URL —
   from widening the page on a phone. */
.kc-article-body { min-width: 0; overflow-wrap: anywhere; }
.kc-article-meta {
  display: flex; flex-wrap: wrap; gap: var(--s5); color: var(--text-2); font-size: var(--tx-sm);
  padding-bottom: var(--s5); margin-bottom: var(--s5); border-bottom: 1px solid var(--border);
}
.kc-article-meta span { display: inline-flex; align-items: center; gap: 6px; }

/* Article body typography — the renderer emits plain h2/h3/p/ul/ol/table/
   pre/code/blockquote-shaped .callout, all already-escaped HTML (see
   helpers/MarkdownRenderer.php); this is presentation only. */
.kc-article-content h2 { margin-top: var(--s8); }
.kc-article-content h3 { margin-top: var(--s6); font-size: var(--tx-base); }
.kc-article-content ul, .kc-article-content ol { margin: 0 0 var(--s4); padding-left: 1.4em; }
.kc-article-content li { margin-bottom: var(--s2); }
.kc-article-content img { border-radius: var(--r); margin: var(--s4) 0; }
.kc-article-content code {
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 6px; font-size: .875em;
}
.kc-article-content pre {
  background: var(--navy); color: #E7ECF5; border-radius: var(--r); padding: var(--s5);
  overflow-x: auto; margin: 0 0 var(--s4);
}
.kc-article-content pre code { background: none; border: 0; padding: 0; color: inherit; }
.kc-article-content table { width: 100%; border-collapse: collapse; margin: 0 0 var(--s4); font-size: var(--tx-sm); }
.kc-article-content th, .kc-article-content td { padding: 10px 14px; border: 1px solid var(--border); text-align: left; }
.kc-article-content thead th { background: var(--surface-2); }
.kc-article-content .callout {
  display: flex; gap: var(--s3); border-radius: var(--r); padding: var(--s4);
  margin: 0 0 var(--s4); font-size: var(--tx-sm);
}
.kc-article-content .callout-note { background: var(--info-bg); border: 1px solid #BFDBFE; color: #1D4ED8; }
.kc-article-content .callout::before {
  content: ''; flex: none; width: 18px; height: 18px; margin-top: 2px; border-radius: 50%;
  background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 16v-4M12 8h.01'/%3E%3C/svg%3E") center / 70% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 16v-4M12 8h.01'/%3E%3C/svg%3E") center / 70% no-repeat;
}

/* Sticky on desktop; the responsive rule below removes it on narrower
   viewports rather than shrinking it into something unreadable. */
.kc-toc { position: sticky; top: calc(var(--header-h) + var(--s6)); align-self: start; }
.kc-toc-title {
  font-size: var(--tx-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin-bottom: var(--s3);
}
.kc-toc-list { display: flex; flex-direction: column; gap: 8px; border-left: 2px solid var(--border); padding-left: var(--s3); }
.kc-toc-list a { color: var(--text-2); font-size: var(--tx-sm); line-height: 1.4; }
.kc-toc-list a:hover { color: var(--brand); }
.kc-toc-list a.kc-toc-sub { padding-left: var(--s3); font-size: var(--tx-xs); color: var(--muted); }

/* The TOC sidebar needs real width to be worth showing; below that it just
   steals room from the reading column, so it goes rather than shrinks (the
   client-built script still ran — this only hides it).

   This lives here, after .kc-article-layout's base rule, and not up in the
   shared 1100px block with the other responsive overrides. A media query adds
   no specificity, so the same single-class selector declared later in the file
   wins regardless of viewport: written earlier, this override never applied at
   any width. Hiding .kc-toc was not enough on its own either — display:none
   removes the grid *item*, while the 240px *track* stays and goes on reserving
   its width, which left the reading column about 78px wide on a phone and
   wrapped every line to roughly one character. */
@media (max-width: 1100px) {
  .kc-article-layout { grid-template-columns: minmax(0, 1fr); }
  .kc-toc { display: none; }
}

.kc-related { margin-top: var(--s10); }
.kc-feedback { margin-top: var(--s8); max-width: 760px; }
.kc-feedback-buttons { display: flex; gap: var(--s2); flex-wrap: wrap; }
.kc-feedback-buttons .btn.is-active { background: var(--brand-50); border-color: var(--brand); color: var(--brand-700); }
.kc-feedback-note { font-size: var(--tx-xs); margin: var(--s3) 0 0; }
.upload-drop .ico {
  width: 44px; height: 44px; border-radius: var(--r); flex: none;
  background: #fff; border: 1px solid var(--border); color: var(--brand); display: grid; place-items: center;
}
.upload-drop .txt strong { display: block; color: var(--navy); font-size: var(--tx-sm); }
.upload-drop .txt span { display: block; font-size: var(--tx-xs); color: var(--text-2); margin-top: 2px; }
.upload-drop .file-name { color: var(--brand-700) !important; font-weight: 600; }

@media (max-width: 860px) {
  .page-hero { flex-direction: column; text-align: center; padding: var(--s6); }
  .page-hero-art, .page-hero-cluster { display: none; }
  .balance-card { flex-direction: column; text-align: center; }
}

/* ── Assistant Widget ─────────────────────────────────────────────
   FAB + drawer, app layout only (views/partials/assistant_widget.php).
   z-index sits between .drawer (1001) and .toast-stack (1200) so a toast
   fired from a shortcut still shows above the drawer. */
.assistant-fab {
  position: fixed;
  right: calc(var(--s6) + env(safe-area-inset-right, 0px));
  bottom: calc(var(--s6) + env(safe-area-inset-bottom, 0px));
  width: 60px; height: 60px;
  border-radius: var(--r-pill);
  background: var(--brand); color: var(--on-brand);
  border: none; box-shadow: var(--sh-md);
  display: flex; align-items: center; justify-content: center;
  z-index: 1150;
  cursor: pointer;
}
@media (max-width: 640px) {
  .assistant-fab { width: 54px; height: 54px; }
  /* Tracks the smaller button, so .app-main reserves exactly what it needs. */
  :root { --fab-clear: 100px; }
}
.assistant-backdrop {
  position: fixed; inset: 0; z-index: 1150;
  background: rgba(27,42,74,.42); /* same navy/alpha as .modal-backdrop / .drawer-backdrop */
  opacity: 0; transition: opacity .2s ease;
}
.assistant-backdrop.is-open { opacity: 1; }
.assistant-drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: 400px; max-width: 100vw;
  background: var(--surface); box-shadow: var(--sh-lg);
  z-index: 1151;
  transform: translateX(100%);
  transition: transform .25s ease;
  display: flex; flex-direction: column;
  overflow-y: auto;
}
.assistant-drawer.is-open { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) {
  .assistant-backdrop, .assistant-drawer { transition: none; }
}
.assistant-drawer-header {
  display: flex; align-items: flex-start; gap: var(--s3);
  padding: var(--s5) var(--s6); border-bottom: 1px solid var(--border);
}
.assistant-drawer-header h2 { margin: 0; font-size: var(--tx-md); color: var(--navy); }
.assistant-drawer-subtitle { margin: 2px 0 0; font-size: var(--tx-sm); color: var(--text-2); }
.assistant-drawer-icon { color: var(--brand); flex: none; }
/* 44x44 is the minimum comfortable tap target; padding alone left this at
   36x36 on a phone, which a real-browser measurement caught. */
.assistant-drawer-close {
  margin-left: auto; background: none; border: 0; cursor: pointer;
  color: var(--muted); padding: 6px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
}
.assistant-drawer-close:hover { background: var(--surface-2); color: var(--navy); }
.assistant-shortcut-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3);
  padding: var(--s4);
}
.assistant-shortcut-card {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s3); border: 1px solid var(--border); border-radius: var(--r);
  color: var(--text); text-decoration: none;
  background: var(--surface-2);
}
.assistant-shortcut-card:hover { border-color: var(--brand); background: var(--brand-50); }
.assistant-recent { padding: 0 var(--s6) var(--s4); }
.assistant-recent h3 { margin: 0 0 var(--s2); font-size: var(--tx-sm); color: var(--navy); }
.assistant-empty { margin: 0; font-size: var(--tx-sm); color: var(--muted); }
.assistant-recent-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s2); }
.assistant-recent-list li {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s3); border: 1px solid var(--border); border-radius: var(--r-sm);
  font-size: var(--tx-sm);
}
.assistant-recent-ref { font-weight: 600; color: var(--navy); }
.assistant-recent-status { font-size: var(--tx-xs); color: var(--text-2); }
.assistant-drawer-footer {
  margin-top: auto; padding: var(--s4) var(--s6);
  border-top: 1px solid var(--border); background: var(--surface-2);
}
.assistant-drawer-footer p { margin: 0; font-size: var(--tx-xs); color: var(--text-2); }
body.assistant-scroll-lock { overflow: hidden; }

/* Knowledge Center screenshots and their lightbox. Images are capped to the
   reading column and never widen it, which is what keeps a wide screenshot
   from doing what a wide table would. */
.kc-article-content img {
  max-width: 100%; height: auto; display: block;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  margin: var(--s4) 0; background: var(--surface-2);
}
.kc-article-content img.kc-zoomable { cursor: zoom-in; }
.kc-article-content img.kc-zoomable:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.kc-lightbox {
  position: fixed; inset: 0; z-index: 1160;
  background: rgba(27, 42, 74, .82);
  display: flex; align-items: center; justify-content: center;
  padding: var(--s6);
}
.kc-lightbox[hidden] { display: none; }
.kc-lightbox-img { max-width: 100%; max-height: 100%; border-radius: var(--r-sm); background: var(--surface); }
.kc-lightbox-close {
  position: absolute; top: var(--s4); right: var(--s4);
  min-width: 44px; min-height: 44px;
  display: flex; align-items: center; justify-content: center;
  font-size: 28px; line-height: 1;
  background: var(--surface); color: var(--navy);
  border: 0; border-radius: var(--r-pill); cursor: pointer;
}

/* ── 20. INTEGRATION MONITOR ─────────────────────────────────────── */

/* Monospace for the things that are literally strings a machine sent:
   endpoints, ids, header names. Never for prose. */
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.text-danger { color: var(--danger); font-weight: 600; }

/* KPI tiles gain a tone. The icon carries it; the number stays navy, so a
   row of tiles still reads as one set rather than as five warnings. */
.kpi.is-success .ico { background: var(--success-bg); color: var(--success); }
.kpi.is-warning .ico { background: var(--warning-bg); color: var(--warning); }
.kpi.is-danger  .ico { background: var(--danger-bg);  color: var(--danger); }

/* The row a drawer is showing, so the list keeps its place behind it. */
.table tbody tr.is-open { background: var(--brand-50); }

/* Payloads and headers. Dark on purpose: it is the one place in the product
   showing raw machine output, and it should not read as prose. */
.code-title { font-size: var(--tx-xs); font-weight: 600; color: var(--text-2); margin: var(--s4) 0 var(--s2); }
.code-block {
  background: #0F172A; color: #E2E8F0; border-radius: var(--r-sm);
  padding: var(--s4); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--tx-xs); line-height: 1.7; overflow-x: auto; white-space: pre;
  margin: 0 0 var(--s3);
}

.detail-title { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s5); }
.detail-title code { font-size: var(--tx-sm); color: var(--navy); font-weight: 600; word-break: break-all; }

.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--s4); margin: 0 0 var(--s4); }
.detail-grid dt { font-size: var(--tx-xs); color: var(--text-2); margin-bottom: 3px; }
.detail-grid dd { margin: 0; font-size: var(--tx-sm); color: var(--navy); }

.drawer-section {
  font-size: var(--tx-sm); color: var(--navy); margin: var(--s6) 0 var(--s3);
  padding-bottom: var(--s2); border-bottom: 1px solid var(--border);
}

/* ── The drawer ──────────────────────────────────────────────────────
   Driven by the URL, not by script: it is already in the document when the
   page arrives. omc.js only adds the slide. A panel that appeared solely
   because JavaScript ran would be missing exactly when somebody is here to
   find out why something is broken (§1). */
.drawer-scrim { position: fixed; inset: 0; background: rgba(15,23,42,.38); z-index: 60; }
.drawer-scrim a { display: block; width: 100%; height: 100%; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(460px, 100vw);
  background: #fff; border-left: 1px solid var(--border); box-shadow: var(--sh-lg);
  z-index: 61; display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .22s ease;
}
.drawer.is-open { transform: translateX(0); }
.drawer.is-wide { width: min(540px, 100vw); }
.drawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s5) var(--s6); border-bottom: 1px solid var(--border); flex: none;
}
.drawer-head h3 { margin: 0; font-size: var(--tx-md); }
.drawer-close { color: var(--text-2); display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--r-sm); }
.drawer-close:hover { background: var(--surface-2); color: var(--navy); }
.drawer-body { padding: var(--s6); overflow-y: auto; flex: 1; }
.drawer-foot { padding: var(--s4) var(--s6); border-top: 1px solid var(--border); background: var(--surface-2); flex: none; }

@media (prefers-reduced-motion: reduce) { .drawer { transition: none; } }

/* Trend bars: real per-day counts, no charting library (§1). */
.legend { display: flex; gap: var(--s5); font-size: var(--tx-xs); color: var(--text-2); margin-bottom: var(--s4); }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; }
.sw-api  { background: var(--brand); }
.sw-hook { background: var(--info); }
.minibars { display: flex; align-items: flex-end; gap: var(--s2); height: 170px; }
.minibar { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: var(--s2); height: 100%; }
.minibar .stack { flex: 1; width: 100%; display: flex; align-items: flex-end; justify-content: center; gap: 3px; }
.minibar .stack i { width: 42%; min-height: 2px; border-radius: 3px 3px 0 0; }
.minibar > span { font-size: var(--tx-xs); color: var(--muted); }

@media (max-width: 720px) {
  .drawer, .drawer.is-wide { width: 100vw; }
  .minibars { height: 130px; }
}

/* Feature checkboxes read as a grid rather than a 15-item scroller: a plan's
   feature set is something you compare at a glance, not scroll through. */
.feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s3); }
.feature-grid .checkbox { align-items: flex-start; padding: var(--s3); border: 1px solid var(--border); border-radius: var(--r-sm); }
.feature-grid .checkbox:hover { border-color: var(--brand); }
.feature-grid .checkbox strong { display: block; color: var(--navy); font-weight: 600; }
.feature-grid .checkbox .mono { display: block; margin-top: 2px; }

/* ── 21. GUIDED TOUR ──────────────────────────────────────────────
   views/partials/onboarding_tour.php. An overlay over the real product:
   nothing here draws a mock-up of a screen, and the element in the hole is
   the live one, in its normal colours, at its normal size.

   The shade is four panels rather than one box with a hole in it. A
   `box-shadow: 0 0 0 9999px` spread is the usual trick and it tints the
   highlighted element too — which defeats the point, because the reader is
   being shown what that element looks like when they go and use it.

   z-index above the lightbox (1160) and the assistant FAB (1150), below the
   toast stack (1200): a toast still has to be readable over the tour. */
.tour[hidden] { display: none; }
/* Clicks land on the shade, not on the product underneath: a tour that let
   somebody navigate away mid-step would leave the spotlight pointing at an
   element that is no longer on the page. */
.tour-shade {
  position: fixed;
  background: rgba(27, 42, 74, .55);
  z-index: 1170;
}
/* The ring covers the hole exactly, so it is also what stops a click on the
   highlighted element itself. It has no background, so the element still
   looks precisely as it will when the reader goes and uses it — which is
   the whole reason the spotlight is a hole rather than a picture. */
.tour-ring {
  position: fixed;
  border-radius: var(--r-sm);
  box-shadow: 0 0 0 2px var(--brand), 0 0 0 6px rgba(242, 101, 34, .28);
  z-index: 1171;
  transition: top .18s ease, left .18s ease, width .18s ease, height .18s ease;
}
.tour-tip {
  position: fixed;
  width: min(360px, calc(100vw - 2 * var(--s4)));
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--sh-lg);
  padding: var(--s5);
  z-index: 1172;
}
.tour-tip h3 { font-size: var(--tx-md); margin-bottom: var(--s2); }
.tour-tip p  { color: var(--text-2); font-size: var(--tx-sm); margin: 0 0 var(--s5); }
.tour-tip-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); margin-bottom: var(--s2);
}
.tour-step {
  font-size: var(--tx-xs); font-weight: 600; letter-spacing: .04em;
  color: var(--brand-700); background: var(--brand-50);
  padding: 3px 10px; border-radius: var(--r-pill);
}
.tour-tip-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); flex-wrap: wrap;
}
.tour-tip-nav { display: flex; gap: var(--s2); }
.tour-tip-nav .btn { display: inline-flex; align-items: center; gap: 6px; }

/* The finish panel is centred rather than anchored to an element: there is
   no longer anything being pointed at. */
.tour-done {
  position: fixed;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(420px, calc(100vw - 2 * var(--s4)));
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--sh-lg);
  padding: var(--s8) var(--s6);
  text-align: center;
  z-index: 1172;
}
.tour-done[hidden] { display: none; }
.tour-done p { color: var(--text-2); font-size: var(--tx-sm); margin: 0 0 var(--s6); }
.tour-done-mark {
  display: grid; place-items: center;
  width: 60px; height: 60px; margin: 0 auto var(--s4);
  border-radius: var(--r-pill);
  background: var(--brand-50); color: var(--brand);
}
.tour-done-actions { display: flex; gap: var(--s3); justify-content: center; flex-wrap: wrap; }

/* On a phone the tip is a sheet at the bottom rather than a card floating
   beside a 40px-wide menu button: there is no room beside anything, and a
   card that dodges the spotlight ends up covering it. */
@media (max-width: 640px) {
  .tour-tip {
    left: var(--s3) !important;
    right: var(--s3);
    bottom: calc(var(--s3) + env(safe-area-inset-bottom, 0px)) !important;
    top: auto !important;
    width: auto;
  }
  .tour-tip-foot { flex-direction: column-reverse; align-items: stretch; }
  .tour-tip-nav { justify-content: space-between; }
  .tour-tip-nav .btn { flex: 1; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) { .tour-ring { transition: none; } }

/* The replay entry point lives in the assistant drawer rather than in a
   second floating button beside the first (§14 — one of a thing). */
.assistant-tour { padding: 0 var(--s6) var(--s5); }
.assistant-tour .btn { width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
