/* ttdHUB — design system (implements DESIGN.md tokens).
   Rules: token-only colors, pill buttons, hairline structure, min text 12px,
   restrained elevation, Outfit typography, :focus-visible everywhere, 8-pt spacing grid. */

@font-face{font-family:"Outfit";font-style:normal;font-display:swap;font-weight:100 900;
  src:url(/vendor/fonts/outfit-latin-wght-normal.woff2) format("woff2-variations");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Outfit";font-style:normal;font-display:swap;font-weight:100 900;
  src:url(/vendor/fonts/outfit-latin-ext-wght-normal.woff2) format("woff2-variations");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

:root{
  /* brand. --primary (#059669) is for fills, accents, focus rings and charts only:
     white on it is 3.77:1. Text-bearing surfaces use the AA-safe "strong" shades. */
  --primary:#059669; --primary-active:#047857; --primary-disabled:#a7f3d0;
  --primary-strong:#047857;          /* button background — white text 5.48:1 */
  --primary-strong-hover:#065f46;    /* 7.6:1 */
  --primary-text:#047857;            /* emerald text on white (5.48:1) / tint (5.2:1) */
  --link:#047857; --link-hover:#065f46;
  --primary-tint:#ecfdf5; --primary-border:#d1fae5; --primary-glow:rgba(5,150,105,.15);
  /* deep brand surfaces (auth / marketing panels) */
  --deep:#064e3b; --deep-2:#065f46; --on-deep:#ffffff; --on-deep-muted:#a7f3d0; --deep-line:rgba(255,255,255,.14);
  /* neutrals. --muted (#5f6f86, darker than DESIGN.md #64748b) keeps 12–13px secondary text ≥4.5:1 on every
     tinted surface: white 5.12 · surface-soft 4.89 · surface-strong 4.67 · error-50 4.71 · primary-border 4.51.
     --muted-soft (2.56:1) is for disabled text and decorative separators only — never for meaningful graphics. */
  --ink:#0f172a; --body:#334155; --muted:#5f6f86; --muted-soft:#94a3b8;
  --hairline:#e2e8f0; --hairline-soft:#f1f5f9; --border-strong:#cbd5e1;
  /* Form-control boundary (WCAG 1.4.11 ≥3:1): white 3.46 · surface-soft 3.31 · surface-strong 3.16. */
  --border-input:#7c8ba1;
  --canvas:#ffffff; --surface-soft:#f8fafc; --surface-card:#ffffff; --surface-strong:#f1f5f9;
  --on-primary:#ffffff; --scrim:#000000; --overlay:rgba(15,23,42,.5);
  /* semantic (50/100/500/700 only) */
  --success-50:#ecfdf3; --success-100:#d1fadf; --success-500:#12b76a; --success-700:#027a48;
  --error-50:#fef3f2; --error-100:#fee4e2; --error-500:#f04438; --error-700:#b42318;
  --warning-50:#fffaeb; --warning-100:#fef0c7; --warning-500:#f79009; --warning-700:#b54708;
  --error-text:#dc2626; --error-text-hover:#b91c1c;
  /* signer palette (data-viz exception: identifies signers on the document) */
  --signer-1:#059669; --signer-2:#2563eb; --signer-3:#b54708; --signer-4:#7c3aed; --signer-5:#b42318;
  /* radius */
  --r-xs:6px; --r-sm:10px; --r-md:14px; --r-lg:16px; --r-xl:20px; --r-2xl:24px; --r-full:9999px;
  /* spacing (8-pt grid with 2/4/12 half steps) */
  --s-xxs:2px; --s-xs:4px; --s-sm:8px; --s-md:12px; --s-base:16px; --s-lg:24px; --s-xl:32px; --s-xxl:48px; --s-section:64px;
  /* layout. --sticky-offset: height of an extra sticky bar under the header (e.g. the signer banner);
     pages that have one raise it so focused elements scroll clear of both (WCAG 2.4.11). */
  --container:1280px; --content-narrow:880px; --gutter:16px; --header-h:64px; --sticky-offset:0px;
  /* elevation: one resting tier + one floating tier for popovers, drawers and dialogs */
  --shadow-xs:0 1px 2px rgba(15,23,42,.05);
  --shadow-sm:0 1px 3px rgba(15,23,42,.08),0 1px 2px rgba(15,23,42,.04);
  --shadow-pop:0 12px 32px rgba(15,23,42,.12),0 2px 6px rgba(15,23,42,.06);
  --font:"Outfit",Circular,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"Cascadia Mono",Menlo,Consolas,monospace;
}
@media (min-width:640px){:root{--gutter:24px}}

/* ---------- Base ---------- */
*,*::before,*::after{box-sizing:border-box}
/* Keyboard focus and in-page anchors never land under the sticky 64px header (+ any page sticky bar). */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%;scroll-padding-top:calc(var(--header-h) + var(--sticky-offset) + var(--s-base))}
body{font-family:var(--font);font-size:15px;line-height:1.5;margin:0;background:var(--surface-soft);color:var(--body);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
body.scroll-locked{overflow:hidden}
h1,h2,h3,h4{color:var(--ink);margin:0;letter-spacing:-.01em}
h1{font-size:28px;font-weight:700;line-height:1.25;letter-spacing:-.02em}
h2{font-size:20px;font-weight:700;line-height:1.3}
h3{font-size:16px;font-weight:600;line-height:1.35}
h4{font-size:15px;font-weight:600;line-height:1.35}
p{margin:0 0 var(--s-md)}
a{color:var(--link);text-decoration:none;font-weight:500}
a:hover{color:var(--link-hover);text-decoration:underline;text-underline-offset:2px}
img,svg{max-width:100%}
code,.mono{font-family:var(--mono);font-size:13px;word-break:break-all}
.num,td.num,th.num,.tabular{font-variant-numeric:tabular-nums}
th.num,td.num{text-align:right}
:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:var(--r-xs)}
.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}
.skip-link{position:absolute;left:var(--s-base);top:-64px;background:var(--ink);color:var(--on-primary);padding:var(--s-sm) var(--s-base);border-radius:var(--r-full);z-index:100;font-weight:600}
.skip-link:focus{top:var(--s-sm);color:var(--on-primary);text-decoration:none}

/* Type scale (DESIGN.md): app H1 28/700 · public H1 30–36/700 · hero ≤44/800 · section H2 24/700 · card H2 18/600 · H3 16/600 */
.display{font-size:32px;font-weight:800;line-height:1.12;letter-spacing:-.03em;color:var(--ink)}
.title-public{font-size:30px;font-weight:700;line-height:1.2;letter-spacing:-.025em;color:var(--ink)}
.section-title{font-size:24px;font-weight:700;line-height:1.25;letter-spacing:-.02em;color:var(--ink)}
.eyebrow{display:inline-block;font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--primary-text)}
.lead{font-size:17px;line-height:1.6;color:var(--body)}
@media (min-width:640px){.display{font-size:40px}.title-public{font-size:36px}}
@media (min-width:1024px){.display{font-size:44px}}

/* ---------- Icons (UI.icon / UI.iconHtml; Lucide-derived, stroke = currentColor) ---------- */
.icon{display:inline-block;flex:none;vertical-align:middle}
.logo-mark{display:block;flex:none;border-radius:var(--r-sm)}

/* ---------- App shell: header ---------- */
.topbar{position:sticky;top:0;z-index:40;height:var(--header-h);background:var(--canvas);border-bottom:1px solid var(--hairline)}
.topbar-inner{max-width:var(--container);height:100%;margin:0 auto;padding:0 var(--gutter);display:flex;align-items:center;gap:var(--s-md)}
.brand{display:inline-flex;align-items:center;gap:var(--s-sm);font-weight:700;font-size:19px;color:var(--ink);letter-spacing:-.02em;flex:none;border-radius:var(--r-sm)}
.brand:hover{text-decoration:none;color:var(--ink)}
.brand .logo-mark{width:32px;height:32px}
.brand-mark{width:32px;height:32px;border-radius:var(--r-sm);background:var(--primary-strong);color:var(--on-primary);display:inline-grid;place-items:center;font-size:15px;font-weight:700}
.brand-tag{display:inline-flex;align-items:center;gap:var(--s-xs);font-size:12px;font-weight:600;color:var(--primary-text);background:var(--primary-tint);border:1px solid var(--primary-border);border-radius:var(--r-full);padding:var(--s-xs) var(--s-sm);letter-spacing:.02em;white-space:nowrap;max-width:200px;overflow:hidden;text-overflow:ellipsis}
.secure-badge{display:inline-flex;align-items:center;gap:var(--s-xs);font-size:12px;font-weight:600;color:var(--success-700);background:var(--success-50);border-radius:var(--r-full);padding:var(--s-xs) var(--s-sm);white-space:nowrap}
.secure-badge svg{width:14px;height:14px}
.nav{display:flex;align-items:center;gap:var(--s-xs);margin-left:var(--s-lg);min-width:0}
.nav a{display:inline-flex;align-items:center;gap:var(--s-sm);font-size:14px;font-weight:600;line-height:1.25;color:var(--body);padding:var(--s-sm) var(--s-md);border-radius:var(--r-full);white-space:nowrap}
.nav a svg{width:18px;height:18px;color:var(--muted)}
.nav a:hover{background:var(--surface-strong);color:var(--ink);text-decoration:none}
.nav a[aria-current="page"]{background:var(--primary-tint);color:var(--primary-text)}
.nav a[aria-current="page"] svg{color:var(--primary-text)}
.spacer{flex:1}
.topbar-actions{display:flex;align-items:center;gap:var(--s-sm);flex:none}
/* Icon-only header buttons (bell, hamburger). Always carry an aria-label. */
.icon-btn,.bell-btn{position:relative;display:inline-grid;place-items:center;width:40px;height:40px;padding:0;border:1px solid transparent;border-radius:var(--r-full);background:transparent;color:var(--body);cursor:pointer;flex:none;transition:background-color .15s,color .15s}
.icon-btn:hover,.bell-btn:hover{background:var(--surface-strong);color:var(--ink)}
.icon-btn[aria-expanded="true"],.bell-btn[aria-expanded="true"]{background:var(--surface-strong);color:var(--ink)}
.icon-btn svg,.bell-btn svg{width:20px;height:20px}
.topbar .nav-toggle{display:none}
/* User menu trigger: avatar + name + chevron */
.user-btn{display:inline-flex;align-items:center;gap:var(--s-sm);min-height:40px;max-width:240px;padding:var(--s-xs) var(--s-sm) var(--s-xs) var(--s-xs);border:1px solid var(--hairline);border-radius:var(--r-full);background:var(--canvas);color:var(--ink);font:600 14px/1.2 var(--font);cursor:pointer;transition:background-color .15s,border-color .15s}
.user-btn:hover,.user-btn[aria-expanded="true"]{background:var(--surface-soft);border-color:var(--border-strong)}
.user-btn .user-name{min-width:0;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.user-btn svg{width:16px;height:16px;color:var(--muted);flex:none}
.avatar{display:inline-grid;place-items:center;flex:none;width:32px;height:32px;border-radius:50%;background:var(--primary-tint);color:var(--primary-text);border:1px solid var(--primary-border);font-size:12px;font-weight:700;letter-spacing:.02em;text-transform:uppercase}
.avatar.lg{width:40px;height:40px;font-size:14px}
.user-chip{font-size:13px;color:var(--muted);max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:859.98px){
  .nav,.user-btn{display:none}
  .topbar .nav-toggle{display:inline-grid;margin-left:calc(-1 * var(--s-sm))}
  .topbar-inner{gap:var(--s-sm)}
}
@media (max-width:479.98px){
  .brand-tag{max-width:120px}
  /* Token pages (mountHeader({nav:false})): logo + secure badge only on phones. */
  .topbar.is-token .brand-tag{display:none}
}

/* ---------- Mobile navigation drawer ---------- */
.drawer-bg{position:fixed;inset:0;z-index:65;background:var(--overlay);display:flex;animation:fade-in .15s ease-out}
.drawer{position:relative;display:flex;flex-direction:column;width:min(320px,calc(100vw - 48px));height:100%;background:var(--canvas);box-shadow:var(--shadow-pop);overflow:hidden;animation:drawer-in .2s ease-out}
.drawer-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s-sm);height:var(--header-h);padding:0 var(--s-base);border-bottom:1px solid var(--hairline);flex:none}
.drawer-body{flex:1;overflow-y:auto;padding:var(--s-sm) var(--s-sm) var(--s-base);overscroll-behavior:contain}
.drawer-user{display:flex;align-items:center;gap:var(--s-md);margin:var(--s-sm) var(--s-sm) var(--s-base);padding:var(--s-md);border:1px solid var(--hairline);border-radius:var(--r-lg);background:var(--surface-soft)}
.drawer-user-text{min-width:0}
.drawer-user-text b{display:block;color:var(--ink);font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.drawer-user-text span{display:block;color:var(--muted);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.drawer-group{margin-bottom:var(--s-sm)}
.drawer-group-title{margin:var(--s-md) var(--s-md) var(--s-xs);font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.drawer-list{list-style:none;margin:0;padding:0}
.drawer-link{display:flex;align-items:center;gap:var(--s-md);min-height:44px;padding:var(--s-sm) var(--s-md);border-radius:var(--r-md);color:var(--body);font-size:15px;font-weight:600}
.drawer-link svg{width:20px;height:20px;color:var(--muted)}
.drawer-link:hover{background:var(--surface-strong);color:var(--ink);text-decoration:none}
.drawer-link[aria-current="page"]{background:var(--primary-tint);color:var(--primary-text)}
.drawer-link[aria-current="page"] svg{color:var(--primary-text)}
.drawer-foot{flex:none;padding:var(--s-base);border-top:1px solid var(--hairline);display:flex;flex-direction:column;gap:var(--s-sm)}
@keyframes drawer-in{from{transform:translateX(-24px);opacity:0}to{transform:none;opacity:1}}
@keyframes fade-in{from{opacity:0}to{opacity:1}}

/* ---------- Dropdown menu (UI.menu: row actions, user menu) ---------- */
.menu{position:fixed;z-index:70;min-width:220px;max-width:min(320px,calc(100vw - 16px));padding:var(--s-xs);background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--r-lg);box-shadow:var(--shadow-pop);animation:fade-in .12s ease-out}
.menu-head{padding:var(--s-sm) var(--s-md) var(--s-md);margin:0 0 var(--s-xs);border-bottom:1px solid var(--hairline);min-width:0}
.menu-head b{display:block;color:var(--ink);font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.menu-head span{display:block;color:var(--muted);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.menu-head .pill{margin-top:var(--s-sm)}
.menu-item{display:flex;align-items:center;gap:var(--s-md);width:100%;min-height:40px;padding:var(--s-sm) var(--s-md);border:0;border-radius:var(--r-sm);background:none;color:var(--body);font:500 14px/1.3 var(--font);text-align:left;cursor:pointer;text-decoration:none;white-space:nowrap}
.menu-item svg{width:18px;height:18px;color:var(--muted);flex:none}
.menu-item:hover,.menu-item:focus{background:var(--surface-strong);color:var(--ink);text-decoration:none;outline:none}
.menu-item:focus-visible{outline:2px solid var(--primary);outline-offset:-2px}
.menu-item[aria-current="page"]{color:var(--primary-text);background:var(--primary-tint)}
.menu-item[aria-current="page"] svg{color:var(--primary-text)}
.menu-item.danger{color:var(--error-700)}
.menu-item.danger svg{color:var(--error-700)}
.menu-item.danger:hover,.menu-item.danger:focus{background:var(--error-50);color:var(--error-700)}
.menu-item[aria-disabled="true"]{color:var(--muted-soft);cursor:not-allowed;background:none}
.menu-item[aria-disabled="true"] svg{color:var(--muted-soft)}
.menu-sep{height:1px;margin:var(--s-xs) 0;background:var(--hairline);border:0}
.menu-label{padding:var(--s-sm) var(--s-md) var(--s-xs);font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}

/* ---------- Layout ---------- */
/* One container everywhere so page edges line up with the header. `.narrow` keeps the
   same outer box and caps the *content* width (left-aligned, not centred). */
.container{max-width:var(--container);margin:0 auto;padding:var(--s-lg) var(--gutter) var(--s-xxl)}
.container.narrow > :not(.modal-bg):not(.drawer-bg){max-width:var(--content-narrow)}
.content-narrow{max-width:var(--content-narrow)}
.prose-width{max-width:72ch}
.container.auth{max-width:calc(448px + 2 * var(--gutter));padding-top:var(--s-xxl)}
@media (min-width:1024px){.container{padding-top:var(--s-xl)}}
.page-header{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s-base);flex-wrap:wrap;margin-bottom:var(--s-lg)}
.page-header > div:first-child{min-width:0}
.page-header p{color:var(--muted);margin:var(--s-xs) 0 0;max-width:72ch}
.page-header .btn-row{flex:none}
@media (min-width:1024px){.page-header{margin-bottom:var(--s-xl)}}

/* Breadcrumb (UI.breadcrumb) */
.breadcrumb{margin:0 0 var(--s-sm)}
.breadcrumb ol{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-xs);list-style:none;margin:0;padding:0;font-size:13px;line-height:1.4}
.breadcrumb li{display:inline-flex;align-items:center;gap:var(--s-xs);min-width:0}
.breadcrumb a{color:var(--muted);font-weight:500}
.breadcrumb a:hover{color:var(--ink)}
.breadcrumb svg{width:14px;height:14px;color:var(--muted-soft)}
.breadcrumb [aria-current="page"]{color:var(--ink);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:40ch}

/* ---------- Surfaces ---------- */
.card{background:var(--surface-card);border:1px solid var(--hairline);border-radius:var(--r-xl);padding:var(--s-base);margin-bottom:var(--s-base);box-shadow:var(--shadow-xs)}
@media (min-width:640px){.card{padding:var(--s-lg);margin-bottom:var(--s-lg)}}
.card-header{display:flex;align-items:center;justify-content:space-between;gap:var(--s-md);flex-wrap:wrap;margin-bottom:var(--s-base)}
.card-header > div:first-child{min-width:0}
.card-header h2{font-size:18px;font-weight:600;line-height:1.35;margin:0}
.card-header h3{margin:0}
.card-desc{color:var(--muted);font-size:13px;margin:var(--s-xs) 0 0}
/* Card title with a leading icon chip (UI.cardTitle): <div class="card-title"><span class="card-icon">svg</span><div><h2/><p class="card-desc"/></div></div> */
.card-title{display:flex;align-items:center;gap:var(--s-md);min-width:0}
.card-header > .card-title{flex:1 1 280px}
.card-title > div{min-width:0}
.card-title h2,.card-title h3{margin:0;overflow-wrap:anywhere}
.card-icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:var(--r-md);background:var(--primary-tint);border:1px solid var(--primary-border);color:var(--primary-text)}
.card-icon svg{width:20px;height:20px}
.card-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--s-sm);flex-wrap:wrap;margin-top:var(--s-lg);padding-top:var(--s-base);border-top:1px solid var(--hairline)}
.divider{border:0;border-top:1px solid var(--hairline);margin:var(--s-lg) 0}
/* Sign in with Google (/masuk, /invite.html): brand button + "atau" separator */
.sso{margin-bottom:var(--s-base)}
.sso-btn{gap:var(--s-sm)}
.sso-btn img{display:block;flex:none}
.sso-or{display:flex;align-items:center;gap:var(--s-sm);margin:var(--s-base) 0 0;font-size:13px;color:var(--muted)}
.sso-or::before,.sso-or::after{content:"";flex:1;border-top:1px solid var(--hairline)}

/* ---------- Buttons (pill) ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s-sm);min-height:46px;padding:var(--s-md) var(--s-lg);border-radius:var(--r-full);
  border:1px solid transparent;background:var(--primary-strong);color:var(--on-primary);font:600 15px/1.25 var(--font);letter-spacing:.01em;cursor:pointer;
  text-decoration:none;white-space:nowrap;transition:background-color .15s,border-color .15s,color .15s,box-shadow .15s}
.btn svg{width:18px;height:18px;flex:none}
.btn:hover{background:var(--primary-strong-hover);color:var(--on-primary);text-decoration:none}
.btn:active{box-shadow:inset 0 1px 2px rgba(15,23,42,.12)}
.btn:disabled,.btn[aria-disabled="true"]{background:var(--primary-disabled);color:var(--primary-strong-hover);border-color:transparent;cursor:not-allowed;box-shadow:none}
.btn.sec{background:var(--canvas);color:var(--ink);border-color:var(--border-strong)}
.btn.sec svg{color:var(--body)}
.btn.sec:hover{background:var(--surface-strong);color:var(--ink)}
.btn.sec:disabled,.btn.sec[aria-disabled="true"]{background:var(--surface-soft);color:var(--muted-soft);border-color:var(--hairline)}
.btn.sec:disabled svg{color:var(--muted-soft)}
.btn.ghost{background:transparent;color:var(--body);border-color:transparent}
.btn.ghost:hover{background:var(--surface-strong);color:var(--ink)}
.btn.ghost:disabled{background:transparent;color:var(--muted-soft)}
.btn.green{background:var(--primary-strong)}
.btn.danger{background:var(--error-700);color:var(--on-primary)}
.btn.danger:hover{background:var(--error-text-hover)}
.btn.danger:disabled{background:var(--error-50);color:var(--muted)}
.btn.danger-outline{background:var(--canvas);color:var(--error-700);border-color:var(--error-100)}
.btn.danger-outline:hover{background:var(--error-50);border-color:var(--error-100);color:var(--error-700)}
.btn.danger-outline:disabled{background:var(--canvas);color:var(--muted-soft);border-color:var(--hairline)}
.btn.sm{min-height:36px;padding:var(--s-sm) var(--s-base);font-size:13px;letter-spacing:0}
.btn.sm svg{width:16px;height:16px}
.btn.lg{min-height:52px;padding:var(--s-md) var(--s-xl);font-size:16px}
/* Square icon-only button — aria-label is required. */
.btn.icon{min-height:36px;width:36px;height:36px;padding:0;gap:0}
.btn.icon.sm{min-height:32px;width:32px;height:32px}
.btn.icon.lg{min-height:44px;width:44px;height:44px}
.btn.icon svg{width:18px;height:18px}
.btn.icon.sm svg{width:16px;height:16px}
/* Text-only button that reads like a link. */
.btn.link{min-height:auto;padding:0;border:0;background:none;color:var(--link);font-weight:600;letter-spacing:0;border-radius:var(--r-xs)}
.btn.link:hover{background:none;color:var(--link-hover);text-decoration:underline;text-underline-offset:2px}
.btn.link:disabled{background:none;color:var(--muted-soft)}
.btn.block{display:flex;width:100%}
.btn-row{display:flex;gap:var(--s-sm);flex-wrap:wrap;align-items:center}
.btn-row.end{justify-content:flex-end}

/* ---------- Forms ---------- */
.field-group{margin-bottom:var(--s-base)}
label,.label{display:block;font-size:13px;font-weight:500;color:var(--ink);margin:0 0 var(--s-sm)}
.label-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-sm)}
.label-row label{margin-bottom:var(--s-sm)}
.hint{font-size:12px;color:var(--muted);margin-top:var(--s-sm)}
.optional{font-weight:400;color:var(--muted)}
/* Text controls. The element part sits in :where() (specificity 0) so state rules below and any
   component/page rule (.search-field input, .input-group > input, #id …) override it without :not() chains. */
:where(input:not([type=checkbox]):not([type=radio]):not([type=color]),select,textarea){
  font:400 15px/1.5 var(--font);color:var(--ink);background:var(--surface-soft);border:1px solid var(--border-input);border-radius:var(--r-md);
  min-height:46px;padding:var(--s-sm) var(--s-md);width:100%;transition:border-color .15s,box-shadow .15s,background-color .15s}
textarea{min-height:96px;resize:vertical}
input[type=file]{padding:var(--s-sm) var(--s-md);font-size:13px}
:where(input:not([type=checkbox]):not([type=radio]):not([type=color]),select,textarea):hover{border-color:var(--muted)}
:where(input:not([type=checkbox]):not([type=radio]):not([type=color]),select,textarea):focus{outline:none;border-color:var(--primary);background:var(--canvas);box-shadow:0 0 0 4px var(--primary-glow)}
:where(input,select,textarea)[aria-invalid="true"]{border-color:var(--error-500)}
:where(input,select,textarea)[aria-invalid="true"]:focus{box-shadow:0 0 0 4px var(--error-50)}
:where(input:not([type=checkbox]):not([type=radio]):not([type=color]),select,textarea):disabled{color:var(--muted);background:var(--surface-strong);border-color:var(--hairline);cursor:not-allowed}
:where(input,textarea)[readonly]{background:var(--surface-strong)}
input::placeholder,textarea::placeholder{color:var(--muted);opacity:1}
input[type=checkbox],input[type=radio]{accent-color:var(--primary-strong);width:18px;height:18px;margin:0;flex:none}
.check{display:flex;align-items:flex-start;gap:var(--s-sm);font-size:14px;color:var(--body);font-weight:400;margin:var(--s-sm) 0;cursor:pointer}
.check input{margin-top:var(--s-xxs)}
.input-sm{min-height:36px!important;padding:var(--s-xs) var(--s-md)!important;font-size:13px!important;border-radius:var(--r-sm)!important}
/* Input with a trailing icon button (e.g. show/hide password). */
.input-group{position:relative;display:flex;align-items:center}
.input-group > input{padding-right:calc(36px + var(--s-xs) + var(--s-md))}
.input-group > .input-addon{position:absolute;right:var(--s-xs);top:50%;transform:translateY(-50%)}
.form-grid{display:grid;gap:0 var(--s-base);grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.form-grid .span-all{grid-column:1/-1}
.toolbar{display:flex;gap:var(--s-sm);flex-wrap:wrap;align-items:center;margin-bottom:var(--s-base)}
.toolbar > input,.toolbar > select{width:auto;flex:1 1 180px;max-width:280px}
.search-field{position:relative;flex:1 1 220px;max-width:320px}
.search-field svg{position:absolute;left:var(--s-md);top:50%;transform:translateY(-50%);width:18px;height:18px;color:var(--muted);pointer-events:none}
.search-field input{padding-left:calc(var(--s-md) + 18px + var(--s-md))}

/* Segmented control — the one implementation for tabs (role=tablist + aria-selected) and filters (aria-pressed).
   .seg: 40px / 14px, full width, equal buttons. .seg.sm: 36px / 13px, inline, scrolls when it overflows;
   add .fill to stretch a .seg.sm to the row width. Selected = white pill with a 1px --border-input edge
   (≥3:1 against the track, WCAG 1.4.11) + ink text — the state never relies on the fill alone. */
.seg{display:flex;gap:var(--s-xs);padding:var(--s-xs);background:var(--surface-strong);border-radius:var(--r-full);margin-bottom:var(--s-lg)}
.seg button{display:inline-flex;align-items:center;justify-content:center;gap:var(--s-sm);flex:1;min-height:40px;padding:0 var(--s-base);border:1px solid transparent;border-radius:var(--r-full);background:transparent;color:var(--body);font:600 14px/1.25 var(--font);white-space:nowrap;cursor:pointer;transition:background-color .15s,color .15s,border-color .15s}
.seg button svg{width:16px;height:16px;flex:none}
.seg button:hover{color:var(--ink)}
.seg button[aria-selected="true"],.seg button[aria-pressed="true"]{background:var(--canvas);border-color:var(--border-input);color:var(--ink);box-shadow:var(--shadow-xs)}
.seg button:disabled{color:var(--muted-soft);cursor:not-allowed}
.seg.sm{display:inline-flex;max-width:100%;overflow-x:auto;margin-bottom:0;scrollbar-width:none}
.seg.sm::-webkit-scrollbar{display:none}
.seg.sm button{flex:none;min-height:36px;padding:0 var(--s-md);font-size:13px}
.seg.sm.fill{display:flex;width:100%}
.seg.sm.fill button{flex:1 0 auto}
.auth-brand{text-align:center;margin-bottom:var(--s-lg)}
.auth-brand p{color:var(--muted);margin:var(--s-xs) 0 0}

/* File drop zone. Copy: title "Seret & lepas file di sini", hint "atau klik untuk memilih · <format>, maks <size>".
   States: :hover / :focus-within, .is-dragover (file over it), .has-file (file chosen), .is-invalid (rejected file). */
.dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-sm);text-align:center;
  padding:var(--s-xl) var(--s-lg);border:1.5px dashed var(--border-input);border-radius:var(--r-xl);background:var(--surface-soft);color:var(--body);cursor:pointer;
  transition:border-color .15s,background-color .15s,box-shadow .15s}
.dropzone:hover{border-color:var(--primary);background:var(--primary-tint)}
.dropzone:focus-within{border-color:var(--primary);background:var(--primary-tint);outline:2px solid var(--primary);outline-offset:2px}
.dropzone.is-dragover{border-color:var(--primary);border-style:solid;background:var(--primary-tint);box-shadow:0 0 0 4px var(--primary-glow)}
.dropzone.has-file{border-style:solid;border-color:var(--primary);background:var(--primary-tint)}
.dropzone.is-invalid{border-color:var(--error-500);background:var(--error-50)}
.dropzone input[type=file]{position:absolute;inset:0;width:100%;height:100%;min-height:0;padding:0;opacity:0;cursor:pointer}
.dropzone-icon{display:grid;place-items:center;width:48px;height:48px;border-radius:50%;background:var(--canvas);border:1px solid var(--hairline);color:var(--primary-text)}
.dropzone-icon svg{width:22px;height:22px}
.dropzone-title{font-size:15px;font-weight:600;color:var(--ink);margin:0}
.dropzone-hint{font-size:13px;color:var(--muted);margin:0}
.dropzone-file{display:inline-flex;align-items:center;gap:var(--s-sm);max-width:100%;margin:0;font-size:13px;font-weight:600;color:var(--primary-text);word-break:break-word}
.dropzone-file svg{flex:none}
.dz-name{min-width:0;overflow-wrap:anywhere;color:var(--ink)}
.dz-size{flex:none;font-weight:500;color:var(--muted)}

/* ---------- Tables ---------- */
/* position:relative makes the wrapper the containing block of .sr-only header cells, so they cannot widen the page. */
.table-wrap{position:relative;overflow-x:auto;border:1px solid var(--hairline);border-radius:var(--r-lg);background:var(--canvas)}
table{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums}
th,td{text-align:left;padding:var(--s-md) var(--s-base);border-bottom:1px solid var(--hairline);font-size:14px;vertical-align:middle}
tbody td{height:52px}
th{background:var(--surface-soft);color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.04em;white-space:nowrap;padding-top:var(--s-md);padding-bottom:var(--s-md)}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover td{background:var(--surface-soft)}
td.actions,th.actions{text-align:right;white-space:nowrap}
td.actions .btn-row{justify-content:flex-end;flex-wrap:nowrap}
td.empty{color:var(--muted);text-align:center;padding:var(--s-xl) var(--s-base)}
td.empty .empty-state{padding:var(--s-base) 0}
tbody tr:hover td.empty{background:transparent}
.cell-title,.doc-title{font-weight:600;color:var(--ink)}
.cell-sub{display:block;font-size:12px;color:var(--muted);margin-top:var(--s-xxs)}
.cell-media{display:flex;align-items:center;gap:var(--s-md);min-width:0}
.cell-media > div{min-width:0}
.cell-media .cell-title,.cell-media .cell-sub{overflow-wrap:anywhere}
/* An empty table shows only its empty state (set .is-empty on .table-wrap when the body is the empty row). */
.table-wrap.is-empty thead{display:none}
/* Inline role picker in member/user tables. */
.role-select{width:auto;min-width:132px}
/* Responsive table helpers (<640px): secondary columns hide, their data folds into the primary cell. */
.show-sm{display:none}
@media (max-width:639.98px){
  .hide-sm{display:none!important}
  .show-sm{display:block}
  .table-wrap th,.table-wrap td{padding-left:var(--s-md);padding-right:var(--s-md)}
  .role-select{min-width:104px}
  /* .dense: wide data tables (CSV previews, job rows) trade cell padding for columns on phones. */
  .table-wrap.dense th,.table-wrap.dense td{padding-left:var(--s-sm);padding-right:var(--s-sm)}
}
/* Pagination row under a table or list. */
.pager{display:flex;align-items:center;justify-content:space-between;gap:var(--s-md);flex-wrap:wrap;margin-top:var(--s-base)}
.pager-info{margin:0;font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums}

/* ---------- Badges (status) ---------- */
.pill,.badge{display:inline-flex;align-items:center;gap:var(--s-xs);padding:var(--s-xs) var(--s-sm);border-radius:var(--r-full);font-size:12px;font-weight:600;line-height:1.2;letter-spacing:.02em;
  background:var(--surface-strong);color:var(--body);white-space:nowrap}
.pill::before,.badge.dot::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
.pill.completed,.pill.signed,.pill.approved,.pill.active,.pill.ok,.pill.success,.pill.delivered,.pill.published,
.pill.trialing,.pill.paid,.pill.won,.pill.valid{background:var(--success-50);color:var(--success-700)}
.pill.sent,.pill.pending,.pill.viewed,.pill.waiting,.pill.warning,.pill.scheduled,.pill.exhausted,.pill.full,
.pill.open,.pill.unapplied,.pill.challenge,.pill.new,.pill.contacted,.pill.suspended,.pill.grace,.pill.not_yet_valid{background:var(--warning-50);color:var(--warning-700)}
.pill.voided,.pill.declined,.pill.expired,.pill.failed,.pill.disabled,.pill.error,.pill.revoked,
.pill.past_due,.pill.void,.pill.lost,.pill.invalid,.pill.chargeback,.pill.clock_rollback{background:var(--error-50);color:var(--error-700)}
.pill.draft,.pill.delegated,.pill.neutral,.pill.inactive,
.pill.canceled,.pill.refunded,.pill.partially_refunded,.pill.replaced,.pill.archived,.pill.none,.pill.skipped_plan{background:var(--surface-strong);color:var(--muted)}
.pill.brand{background:var(--primary-tint);color:var(--primary-text)}
.pill.plain::before{display:none}

/* ---------- Feedback ---------- */
.muted{color:var(--muted)}
.text-sm{font-size:13px}.text-xs{font-size:12px}
.text-ink{color:var(--ink)}.text-right{text-align:right}.text-center{text-align:center}
.fw-600{font-weight:600}
.err{color:var(--error-text);font-size:13px;margin-top:var(--s-sm)}
.ok{color:var(--success-700);font-size:13px;margin-top:var(--s-sm)}
.err:empty,.ok:empty{display:none}
.alert{display:flex;gap:var(--s-md);align-items:flex-start;border-radius:var(--r-lg);padding:var(--s-md) var(--s-base);font-size:14px;border:1px solid var(--hairline);background:var(--surface-soft);margin-bottom:var(--s-base)}
.alert > svg{width:20px;height:20px;flex:none;margin-top:var(--s-xxs)}
.alert.success{background:var(--success-50);border-color:var(--success-100);color:var(--success-700)}
.alert.error{background:var(--error-50);border-color:var(--error-100);color:var(--error-700)}
.alert.warning{background:var(--warning-50);border-color:var(--warning-100);color:var(--warning-700)}
.alert.info{background:var(--primary-tint);border-color:var(--primary-border);color:var(--primary-strong-hover)}
.alert .mono{word-break:break-all}
.hidden{display:none!important}
.spinner{width:16px;height:16px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin .7s linear infinite;display:inline-block;flex:none}
@keyframes spin{to{transform:rotate(360deg)}}
/* UI.busy prepends a spinner: hide the button's own icon meanwhile so the width does not jump. */
.btn[aria-busy="true"] > svg,.btn[aria-busy="true"] > .icon{display:none}

/* Loading skeletons (+ .skeleton-row on placeholder table rows). Static under reduced motion. */
.skeleton{display:block;border-radius:var(--r-xs);background:linear-gradient(90deg,var(--hairline-soft) 25%,var(--hairline) 50%,var(--hairline-soft) 75%);background-size:200% 100%;animation:skeleton-shimmer 1.4s ease-in-out infinite}
@keyframes skeleton-shimmer{from{background-position:200% 0}to{background-position:-200% 0}}
.sk-line{height:12px}
.sk-line.sm{height:10px;margin-top:var(--s-xs)}
.sk-w1{width:180px;max-width:100%}
.sk-w2{width:96px;max-width:100%}
.sk-w3{width:40px;max-width:100%;margin-left:auto}
.sk-pill{width:72px;height:24px;border-radius:var(--r-full)}
.sk-btn{width:96px;height:36px;margin-left:auto;border-radius:var(--r-full)}
.sk-chip{width:36px;height:36px;border-radius:var(--r-sm)}
.sk-value{width:56px;height:24px}
.sk-thumb{width:80px;height:48px;border-radius:var(--r-sm)}
.skeleton-row:hover td{background:transparent}

/* Empty state (UI.emptyState) and error state (UI.errorState: alert-triangle chip + "Coba lagi") */
.empty-state{display:flex;flex-direction:column;align-items:center;text-align:center;gap:var(--s-sm);padding:var(--s-xxl) var(--s-base);color:var(--muted)}
.empty-icon{display:grid;place-items:center;width:48px;height:48px;margin-bottom:var(--s-xs);border-radius:50%;background:var(--primary-tint);color:var(--primary-text)}
.empty-icon svg{width:22px;height:22px}
.empty-title{margin:0;font-size:16px;font-weight:600;line-height:1.35;color:var(--ink)}
.empty-text{margin:0;max-width:420px;font-size:14px;color:var(--muted);overflow-wrap:anywhere}
.empty-state .btn{margin-top:var(--s-sm)}
/* .boxed: a free-standing empty state (not inside a table/card), e.g. the public news list. */
.empty-state.boxed{padding:var(--s-section) var(--s-base);border:1px dashed var(--border-strong);border-radius:var(--r-xl);background:var(--surface-soft)}

/* toasts (ui.js) */
.toast-region{position:fixed;right:var(--s-base);bottom:var(--s-base);z-index:80;display:flex;flex-direction:column;gap:var(--s-sm);max-width:min(400px,calc(100vw - 32px))}
.toast{display:flex;gap:var(--s-md);align-items:flex-start;background:var(--ink);color:var(--on-primary);border-radius:var(--r-lg);padding:var(--s-md) var(--s-sm) var(--s-md) var(--s-base);font-size:14px;box-shadow:var(--shadow-pop);animation:toast-in .18s ease-out}
.toast > svg{flex:none;margin-top:var(--s-xxs)}
.toast > span{flex:1;min-width:0;padding-top:var(--s-xxs);word-break:break-word}
.toast.success{background:var(--success-700)}.toast.error{background:var(--error-700)}.toast.warning{background:var(--warning-700)}
.toast button{display:inline-grid;place-items:center;flex:none;width:28px;height:28px;margin:calc(-1 * var(--s-xxs)) 0 calc(-1 * var(--s-xxs)) auto;padding:0;background:none;border:0;border-radius:var(--r-full);color:inherit;cursor:pointer;opacity:.85}
.toast button:hover{opacity:1;background:rgba(255,255,255,.14)}
.toast button svg{width:16px;height:16px}
.toast button:focus-visible{outline-color:var(--on-primary)}
@keyframes toast-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* dialogs (ui.js + page modals) */
.modal-bg{position:fixed;inset:0;background:var(--overlay);display:flex;align-items:center;justify-content:center;z-index:60;padding:var(--s-base)}
.modal{position:relative;background:var(--canvas);border-radius:var(--r-2xl);padding:var(--s-lg);max-width:520px;width:100%;max-height:calc(100vh - 32px);overflow:auto;box-shadow:var(--shadow-pop)}
/* openModal() makes the box focusable (tabindex=-1) as the fallback focus target; it needs no ring of its own. */
.modal:focus{outline:none}
.modal.wide{max-width:720px}
.modal h2,.modal h3{margin:0 0 var(--s-sm)}
.modal h2{font-size:20px}
/* Dialog header: title + close button (UI.modalHead / UI.modalClose → button.icon-btn.modal-close, 40px, "Tutup"). */
.modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-md);margin-bottom:var(--s-sm)}
.modal-head h2,.modal-head h3{margin:0;min-width:0;overflow-wrap:anywhere}
.modal-close{flex:none;margin:calc(-1 * var(--s-sm)) calc(-1 * var(--s-sm)) 0 0}
.modal-body{color:var(--body);font-size:15px;margin-bottom:var(--s-lg)}
.modal-actions{display:flex;gap:var(--s-sm);justify-content:flex-end;flex-wrap:wrap;margin-top:var(--s-lg)}
@media (max-width:479.98px){.modal{padding:var(--s-base) var(--s-base) var(--s-lg)}.modal-actions .btn{flex:1 1 auto}}

/* ---------- Stats (KPI tiles) ----------
   <div class="stats cols-6">
     <div class="stat"><div class="stat-top"><span class="stat-label">Terkirim</span><span class="stat-icon tone-warning">svg</span></div>
       <b class="stat-value">12<span class="stat-unit">%</span></b><small class="stat-sub">…</small></div>
   Grids: .stats (auto-fit) or orphan-free .cols-6 (2 → 3 → 6), .cols-4 (2 → 4), .cols-3 (1 → 3). */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--s-md)}
@media (max-width:480px){.stats{grid-template-columns:repeat(2,minmax(0,1fr))}}
.stats.cols-6,.stats.cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}
.stats.cols-3{grid-template-columns:minmax(0,1fr)}
@media (min-width:480px){.stats.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (min-width:640px){.stats{gap:var(--s-base)}.stats.cols-6{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (min-width:768px){.stats.cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media (min-width:1024px){.stats.cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}
.stats > .alert{grid-column:1/-1;margin:0}
/* A failed KPI load: UI.errorState({title, onRetry}) as the only child of the grid spans the full row. */
.stats > .empty-state{grid-column:1/-1;padding:var(--s-lg) var(--s-base);border:1px solid var(--hairline);border-radius:var(--r-lg);background:var(--canvas)}
.stat{display:flex;flex-direction:column;gap:var(--s-xs);min-width:0;background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--r-lg);padding:var(--s-base);box-shadow:var(--shadow-xs)}
.stat-top{display:flex;align-items:center;justify-content:space-between;gap:var(--s-sm);min-width:0;margin-bottom:var(--s-xs)}
.stat-label{min-width:0;font-size:12px;font-weight:500;line-height:1.35;color:var(--muted);overflow-wrap:anywhere}
.stat-value{display:block;font-size:24px;font-weight:700;line-height:1.2;letter-spacing:-.02em;color:var(--ink);font-variant-numeric:tabular-nums}
.stat-unit{margin-left:var(--s-xxs);font-size:14px;font-weight:600;letter-spacing:0;color:var(--muted)}
.stat-sub{display:block;font-size:12px;line-height:1.4;color:var(--muted)}
.stat-icon{display:grid;place-items:center;flex:none;width:36px;height:36px;border-radius:var(--r-sm);background:var(--primary-tint);color:var(--primary-text)}
.stat-icon svg{width:18px;height:18px}
.stat.accent .stat-value{color:var(--primary-text)}
/* Legacy markup: <div class="stat"><b>12</b><span>Label</span></div> */
.stat > b{display:block;font-size:24px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;line-height:1.2}
.stat > span:not(.stat-icon){font-size:12px;font-weight:500;color:var(--muted)}
.stat.accent > b{color:var(--primary-text)}

/* ---------- Event chips (UI.eventIcon / UI.eventIconHtml): ONE size for every activity list, timeline and
   notification (36px circle, 18px icon); the tone class comes from UI.eventMeta(type).tone. ---------- */
.event-icon{display:grid;place-items:center;flex:none;width:36px;height:36px;border-radius:50%;border:1px solid var(--hairline);background:var(--surface-strong);color:var(--body)}
.event-icon svg{width:18px;height:18px}

/* ---------- Tone chips (one scale everywhere: 50-shade fill, 700-shade icon) ----------
   Apply to any icon chip: .card-icon, .stat-icon, .empty-icon, activity/notification icons … */
.tone-brand{background:var(--primary-tint);color:var(--primary-text);border-color:var(--primary-border)}
.tone-success{background:var(--success-50);color:var(--success-700);border-color:var(--success-100)}
.tone-warning{background:var(--warning-50);color:var(--warning-700);border-color:var(--warning-100)}
.tone-error{background:var(--error-50);color:var(--error-700);border-color:var(--error-100)}
.tone-neutral{background:var(--surface-strong);color:var(--body);border-color:var(--hairline)}

/* ---------- Switch: <input type="checkbox" class="switch" role="switch"> or UI.switch() (button[role=switch]) ----------
   Track off = --muted (5.1:1 on white), on = --primary-strong, white knob, focus ring, forced-colors safe. */
.switch{appearance:none;-webkit-appearance:none;position:relative;display:inline-block;flex:none;width:44px;height:24px;min-height:0;margin:0;padding:0;border:0;border-radius:var(--r-full);background:var(--muted);cursor:pointer;vertical-align:middle;transition:background-color .15s}
.switch::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;background:var(--canvas);box-shadow:var(--shadow-xs);transition:transform .15s}
.switch:checked,.switch[aria-checked="true"]{background:var(--primary-strong)}
.switch:checked::after,.switch[aria-checked="true"]::after{transform:translateX(20px)}
.switch:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:var(--r-full)}
.switch:disabled,.switch[aria-disabled="true"]{opacity:.5;cursor:not-allowed}
input[type=checkbox].switch{width:44px;height:24px;accent-color:auto}
.switch-row{display:flex;align-items:center;justify-content:space-between;gap:var(--s-base)}
.switch-label{display:inline-flex;align-items:center;gap:var(--s-sm);margin:0;font-weight:500;color:var(--body);cursor:pointer}

/* ---------- Result card (token pages: loading / success / error / waiting) — UI.resultCard ---------- */
.result-card{width:100%;max-width:520px;margin:0 auto;padding:var(--s-xl) var(--s-lg);text-align:center;
  background:var(--surface-card);border:1px solid var(--hairline);border-radius:var(--r-xl);box-shadow:var(--shadow-xs)}
@media (min-width:640px){.result-card{padding:var(--s-xxl) var(--s-xl)}}
.result-card .result-icon{display:inline-grid;place-items:center;width:72px;height:72px;margin-bottom:var(--s-lg);border-radius:50%;background:var(--primary-tint);color:var(--primary-text)}
.result-card .result-icon svg{width:36px;height:36px}
.result-card .result-icon .spinner{width:28px;height:28px;border-width:3px}
.result-card .result-icon.success{background:var(--success-50);color:var(--success-700)}
.result-card .result-icon.error{background:var(--error-50);color:var(--error-700)}
.result-card .result-icon.warning{background:var(--warning-50);color:var(--warning-700)}
.result-card .result-title{margin:0 0 var(--s-sm);font-size:24px;line-height:1.25;overflow-wrap:anywhere}
.result-card .result-title:focus{outline:none}
.result-card .result-text{max-width:44ch;margin:0 auto var(--s-lg);color:var(--body);overflow-wrap:anywhere}
.result-card .result-text:last-child,.result-card .result-text:has(+ .result-actions.hidden){margin-bottom:0}
.result-card .result-actions{display:flex;justify-content:center;gap:var(--s-sm);flex-wrap:wrap}

/* ---------- Layout helpers ---------- */
.row{display:flex;gap:var(--s-sm);align-items:center;flex-wrap:wrap}
.stack{display:flex;flex-direction:column;gap:var(--s-md)}
.cluster{display:flex;flex-wrap:wrap;align-items:center}
.gap-xs{gap:var(--s-xs)}.gap-sm{gap:var(--s-sm)}.gap-md{gap:var(--s-md)}.gap-base{gap:var(--s-base)}.gap-lg{gap:var(--s-lg)}
.grid-2{display:grid;gap:var(--s-base);grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr))}
.grid-3{display:grid;gap:var(--s-base);grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr))}
.mt-0{margin-top:0}.mt-xs{margin-top:var(--s-xs)}.mt-sm{margin-top:var(--s-sm)}.mt-md{margin-top:var(--s-md)}.mt-base{margin-top:var(--s-base)}.mt-lg{margin-top:var(--s-lg)}.mt-xl{margin-top:var(--s-xl)}
.mb-0{margin-bottom:0}.mb-xs{margin-bottom:var(--s-xs)}.mb-sm{margin-bottom:var(--s-sm)}.mb-md{margin-bottom:var(--s-md)}.mb-base{margin-bottom:var(--s-base)}.mb-lg{margin-bottom:var(--s-lg)}
.w-full{width:100%}.grow{flex:1 1 auto}.nowrap{white-space:nowrap}.min-w-0{min-width:0}
.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kv{display:grid;grid-template-columns:max-content 1fr;gap:var(--s-sm) var(--s-base);font-size:14px}
.kv dt{color:var(--muted)}.kv dd{margin:0;color:var(--ink);min-width:0}
/* .kv-stack: label/value rows (audit "Keaslian", /verify result) that stack on phones. */
.kv.kv-stack{grid-template-columns:max-content minmax(0,1fr);gap:var(--s-md) var(--s-lg);align-items:center}
@media (max-width:639.98px){
  .kv.kv-stack{grid-template-columns:minmax(0,1fr);gap:0}
  .kv.kv-stack dt{margin-top:var(--s-md);font-size:13px}
  .kv.kv-stack dt:first-child{margin-top:0}
  .kv.kv-stack dd{margin-top:var(--s-xs)}
}
/* Copyable secret (API key, invite link, TOTP key): <div class="secret-row"><code class="mono secret-value"/>[copy .btn]</div> */
.secret-row{display:flex;align-items:center;gap:var(--s-sm);min-width:0;margin-top:var(--s-sm)}
.secret-row > .btn{flex:none}
.secret-value{flex:1;min-width:0;padding:var(--s-sm) var(--s-md);border:1px solid var(--hairline);border-radius:var(--r-sm);background:var(--surface-soft);color:var(--ink);font-size:13px;word-break:break-all}
/* Hash with a copy button, and a row of verification flags (pills). */
.hash-row{display:flex;align-items:center;gap:var(--s-sm);min-width:0}
.hash-row .mono{flex:1 1 auto;min-width:0;color:var(--ink)}
.hash-row .btn{flex:none}
.flag-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-sm)}

/* ---------- Editor / signer ---------- */
.editor{display:flex;gap:var(--s-lg);align-items:flex-start}
.panel{width:320px;flex:none;position:sticky;top:calc(var(--header-h) + var(--s-base));max-height:calc(100vh - var(--header-h) - var(--s-xl));overflow:auto}
.panel .card{padding:var(--s-base);margin-bottom:var(--s-base)}
.panel h3{font-size:15px;margin-bottom:var(--s-sm)}
@media (max-width:960px){.editor{flex-direction:column}.panel{width:100%;position:static;max-height:none}}
.pages{flex:1;display:flex;flex-direction:column;gap:var(--s-base);align-items:center;min-width:0;max-width:100%;overflow-x:auto}
.page-wrap{position:relative;box-shadow:var(--shadow-sm);background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--r-xs)}
.page-wrap canvas{display:block}
.page-label{font-size:12px;color:var(--muted);text-align:center;margin-top:var(--s-xs)}
.field{position:absolute;border:1.5px dashed var(--primary);background:var(--primary-tint);
  font-size:12px;font-weight:500;color:var(--primary-active);cursor:move;display:flex;align-items:center;justify-content:center;overflow:hidden;border-radius:var(--r-xs)}
.field .lbl{pointer-events:none;padding:var(--s-xxs) var(--s-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.field .del{position:absolute;top:-10px;right:-10px;background:var(--error-700);color:var(--on-primary);border:0;border-radius:50%;
  width:20px;height:20px;line-height:20px;text-align:center;font-size:12px;cursor:pointer;display:none;padding:0}
.field .del svg{width:12px;height:12px;vertical-align:middle}
.field:hover .del,.field:focus-within .del{display:block}
.field.mine{border-color:var(--primary);background:var(--primary-glow);color:var(--primary-active);cursor:pointer}
.field.mine:hover{background:var(--primary-border)}
.field.filled{border-style:solid;background:var(--success-50)}
.field.required-missing{border-color:var(--error-500);background:var(--error-50)}
.field img{max-width:100%;max-height:100%}
.tool{display:flex;width:100%;justify-content:flex-start;margin-bottom:var(--s-xs)}
.tool.active,.tool[aria-pressed="true"]{background:var(--primary-tint);border-color:var(--primary);color:var(--primary-active)}
.signer-item{display:flex;align-items:center;gap:var(--s-sm);padding:var(--s-sm) var(--s-md);border:1px solid var(--hairline);border-radius:var(--r-md);margin-bottom:var(--s-sm);font-size:13px}
.signer-item .grow{min-width:0;overflow:hidden;text-overflow:ellipsis}
.dot{width:12px;height:12px;border-radius:50%;flex:none}
.timeline{list-style:none;padding:0;margin:0}
.timeline li{padding:var(--s-md) 0;border-bottom:1px solid var(--hairline);font-size:14px}
.timeline li:last-child{border-bottom:0}
.timeline .ev{font-weight:600;color:var(--ink)}
.timeline .meta{font-size:12px;color:var(--muted)}
canvas.sigpad{border:1px solid var(--hairline);border-radius:var(--r-md);width:100%;height:180px;touch-action:none;background:var(--canvas)}
.sign-banner{position:sticky;top:var(--header-h);z-index:30}
.consent-box{max-height:220px;overflow:auto;background:var(--surface-soft);border:1px solid var(--hairline);border-radius:var(--r-md);padding:var(--s-md);font-size:13px}
.preview-img{max-width:100%;border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--canvas)}
.stamp-prev{margin-top:var(--s-sm);padding:var(--s-base);border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface-soft);display:flex;justify-content:center}
.stamp-prev img{max-width:100%;max-height:180px;object-fit:contain}
.att-name{word-break:break-word}

/* ===== Notifications (header bell, dropdown panel, notifications page) ===== */
.bell-wrap{position:relative;display:inline-flex}
.bell-badge{position:absolute;top:2px;right:2px;min-width:18px;height:18px;padding:0 var(--s-xs);border-radius:var(--r-full);background:var(--primary-strong);color:var(--on-primary);font-size:12px;font-weight:700;line-height:18px;text-align:center;box-shadow:0 0 0 2px var(--canvas)}
.bell-panel{position:absolute;right:0;top:calc(100% + var(--s-sm));z-index:60;width:min(380px,calc(100vw - 32px));background:var(--canvas);border:1px solid var(--hairline);border-radius:var(--r-lg);box-shadow:var(--shadow-pop);overflow:hidden}
@media (max-width:479.98px){.bell-panel{position:fixed;left:var(--s-base);right:var(--s-base);top:calc(var(--header-h) + var(--s-xs));width:auto}}
.bell-panel-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s-sm);padding:var(--s-md) var(--s-base);border-bottom:1px solid var(--hairline)}
.bell-panel-head h2{margin:0;font-size:16px}
.bell-panel-foot{padding:var(--s-sm) var(--s-base);border-top:1px solid var(--hairline);text-align:center;font-size:14px}
.notif-list{list-style:none;margin:0;padding:0}
.bell-panel .notif-list{max-height:min(420px,60vh);overflow-y:auto}
.notif-item{display:flex;align-items:flex-start;gap:var(--s-md);width:100%;padding:var(--s-md) var(--s-base);border:0;border-bottom:1px solid var(--hairline-soft);background:var(--canvas);color:var(--body);text-align:left;font:inherit;cursor:pointer}
.notif-item:hover{background:var(--surface-soft)}
/* The dropdown list scrolls (overflow clips outlines): draw the ring inside the item. */
.bell-panel .notif-item:focus-visible{outline-offset:-2px;border-radius:0}
.notif-item.unread{background:var(--primary-tint)}
.notif-dot{flex:none;width:8px;height:8px;margin-top:calc(var(--s-sm) - 1px);border-radius:50%;background:transparent}
.notif-item.unread .notif-dot{background:var(--primary)}
.notif-main{flex:1;min-width:0}
.notif-title{display:block;font-size:14px;font-weight:600;color:var(--ink);word-break:break-word}
.notif-body{display:block;font-size:13px;color:var(--muted);word-break:break-word}
.notif-time{display:block;margin-top:var(--s-xxs);font-size:12px;color:var(--muted)}
.notif-empty{padding:var(--s-lg) var(--s-base);text-align:center;color:var(--muted);font-size:14px}
.notif-page .notif-list{border:1px solid var(--hairline);border-radius:var(--r-lg);overflow:hidden}
.mute-grid{display:grid;gap:0 var(--s-base);grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}
.notif-page fieldset{border:0;padding:0;margin:0 0 var(--s-base)}
.notif-page legend{padding:0;margin-bottom:var(--s-xs);font-size:14px;font-weight:600;color:var(--ink)}

/* ===== Plans & billing (ui.js: UI.planGate, UI.paymentDialog, UI.meter, UI.upgradeState, header banner) ===== */
/* Plan badge on a locked control: lock + plan name ("Bisnis"); quota variant ("Kuota habis"). */
.plan-badge{display:inline-flex;align-items:center;gap:var(--s-xxs);flex:none;margin-left:var(--s-xs);padding:var(--s-xxs) var(--s-sm);border:1px solid var(--primary-border);border-radius:var(--r-full);
  background:var(--primary-tint);color:var(--primary-text);font:600 12px/1.2 var(--font);letter-spacing:.01em;white-space:nowrap;vertical-align:middle}
.plan-badge > svg{width:12px!important;height:12px!important;color:currentColor!important}
.plan-badge.is-quota{border-color:var(--warning-100);background:var(--warning-50);color:var(--warning-700)}
label .plan-badge,.check .plan-badge{margin-left:var(--s-sm)}
.menu-item .plan-badge{margin-left:auto}
.plan-badge.is-corner{position:absolute;top:var(--s-xs);right:var(--s-xs);margin:0}
/* Header banner (trial ending, quota ≥ 80 %, past due, seats over limit, license). */
.plan-banner{border-bottom:1px solid var(--primary-border);background:var(--primary-tint)}
.plan-banner.is-warning{border-bottom-color:var(--warning-100);background:var(--warning-50)}
.plan-banner.is-error{border-bottom-color:var(--error-100);background:var(--error-50)}
.plan-banner-inner{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s-sm) var(--s-md);max-width:var(--container);margin:0 auto;padding:var(--s-sm) var(--gutter)}
.plan-banner-icon{display:grid;place-items:center;flex:none;width:32px;height:32px;border-radius:50%;background:var(--canvas);color:var(--primary-text)}
.plan-banner.is-warning .plan-banner-icon{color:var(--warning-700)}
.plan-banner.is-error .plan-banner-icon{color:var(--error-700)}
.plan-banner-text{flex:1 1 320px;min-width:0;margin:0;font-size:14px;line-height:1.45;color:var(--body)}
.plan-banner-text b{font-weight:600;color:var(--ink)}
.plan-banner-actions{display:flex;align-items:center;gap:var(--s-xs);flex:none;margin-left:auto}
.plan-banner-close{width:36px;height:36px}
/* Usage meter (role=progressbar). Fill vs track ≥ 3:1 in every tone. */
.meter{display:flex;flex-direction:column;gap:var(--s-sm);min-width:0}
.meter-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-sm);min-width:0}
.meter-label{min-width:0;font-size:13px;font-weight:500;color:var(--ink)}
.meter-value{flex:none;font-size:13px;font-weight:600;color:var(--ink);white-space:nowrap}
.meter-track{position:relative;display:block;height:8px;border-radius:var(--r-full);background:var(--surface-strong);overflow:hidden}
.meter-fill{display:block;height:100%;min-width:2px;border-radius:inherit;background:var(--primary-strong);transition:width .3s ease}
.meter.is-warning .meter-fill{background:var(--warning-700)}
.meter.is-error .meter-fill{background:var(--error-700)}
.meter.is-warning .meter-value{color:var(--warning-700)}
.meter.is-error .meter-value{color:var(--error-700)}
.meter-sub{margin:0;font-size:12px;line-height:1.4;color:var(--muted)}
/* Upgrade / quota dialog */
.pay-lead{display:flex;align-items:flex-start;gap:var(--s-md);margin-bottom:var(--s-xs)}
.pay-lead .modal-body{margin:0;padding-top:var(--s-xs)}
.pay-icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border:1px solid;border-radius:var(--r-md)}
.pay-icon svg{width:20px;height:20px}
.pay-dialog .meter,.pay-kv{margin-top:var(--s-base)}
.pay-note{display:flex;align-items:flex-start;gap:var(--s-sm);margin:var(--s-base) 0 0;padding:var(--s-md);border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface-soft);font-size:14px;color:var(--body)}
.pay-note svg{flex:none;margin-top:var(--s-xxs);color:var(--muted)}
.plan-compare{margin-top:var(--s-base)}
.plan-compare table{border:1px solid var(--hairline);border-radius:var(--r-lg);border-collapse:separate;border-spacing:0;overflow:hidden}
.plan-compare th,.plan-compare td{height:auto;padding:var(--s-sm) var(--s-md);font-size:13px;letter-spacing:0;text-transform:none;vertical-align:middle}
.plan-compare thead th{background:var(--surface-soft);color:var(--ink);font-weight:600;white-space:normal;vertical-align:bottom}
.plan-compare thead th small{display:block;font-size:12px;font-weight:500;color:var(--muted)}
.plan-compare tbody th{background:none;color:var(--body);font-weight:500;white-space:normal}
.plan-compare tbody tr:last-child th{border-bottom:0}
.plan-compare .is-target,.plan-compare tbody tr:hover td.is-target{background:var(--primary-tint)}
.plan-compare thead th.is-target{color:var(--primary-text)}
.plan-compare tr.is-focus th{color:var(--ink);font-weight:600}
.plan-compare .hint{margin-top:var(--s-sm)}
.cmp-yes,.cmp-no{display:inline-flex;align-items:center}
.cmp-yes{color:var(--success-700)}
.cmp-no{color:var(--muted)}
/* Locked section placeholder (UI.upgradeState) */
.upgrade-state .upgrade-actions{flex-direction:column;justify-content:center;margin-top:var(--s-xs)}
.upgrade-state .upgrade-actions .hint{margin:0;text-align:center}

/* ===== User preferences ===== */
/* Reduced motion: no motion at all (a .01ms infinite loop would flicker). Spinners stop as a static ring. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
  .skeleton{animation:none!important}
}
/* Windows High Contrast / forced colors: backgrounds are discarded, so every state that relied on a fill
   gets a border, outline, underline or system-colour fill instead. */
@media (forced-colors:active){
  :where(input:not([type=checkbox]):not([type=radio]):not([type=color]),select,textarea):focus{outline:2px solid Highlight;outline-offset:1px}
  .switch{border:2px solid ButtonText;background:Canvas}
  .switch::after{top:2px;left:2px;width:16px;height:16px;forced-color-adjust:none;background:ButtonText;box-shadow:none}
  .switch:checked,.switch[aria-checked="true"]{border-color:Highlight}
  .switch:checked::after,.switch[aria-checked="true"]::after{background:Highlight;transform:translateX(20px)}
  .switch:disabled::after,.switch[aria-disabled="true"]::after{background:GrayText}
  .seg button[aria-selected="true"],.seg button[aria-pressed="true"]{forced-color-adjust:none;background:Highlight;color:HighlightText;border-color:Highlight}
  .tool.active,.tool[aria-pressed="true"]{outline:2px solid Highlight;outline-offset:-2px}
  .nav a[aria-current],.drawer-link[aria-current],.menu-item[aria-current],.site-nav a[aria-current],.site-drawer-link[aria-current]{text-decoration:underline;text-underline-offset:4px;text-decoration-thickness:2px}
  .bulk-progress-fill,.rate-fill,.notif-item.unread .notif-dot,.bell-badge{forced-color-adjust:none;background:Highlight;color:HighlightText}
  .dot{forced-color-adjust:none}
  .dropzone.is-dragover,.dropzone.has-file{border-color:Highlight}
  .skeleton{border:1px solid GrayText}
  .meter-track{border:1px solid CanvasText}
  .meter-fill{forced-color-adjust:none;background:Highlight}
  .plan-badge,.plan-banner{border:1px solid CanvasText}
}
