/* =====================================================================
   SwipeWise — unified design system for ALL logged-in pages.
   ONE token set + shared chrome components, linked by base.html
   (every logged-in page) and app.html (standalone recommender).
   Per-page <style> blocks build on these tokens; never redefine them.
   ===================================================================== */

/* ===== canonical divider (all logged-in pages) =====
   Standalone rule: .divider — 90% wide, centered, 1px dashed, line color at 55%.
   Row separators converge on the same treatment via --divider on a centered
   ::before/::after (declared in each page's rules): dashed, 55%, 90% width. */
.divider{width:90%;height:0;margin:16px auto;border:0;border-top:1px dashed var(--line);border-top:1px dashed var(--divider)}
/* ===== page impact box (A안): ONE navy emphasis box per main page,
   directly under the page title; the numbers in it are always the
   viewer's own data. Vertical rhythm is owned by the component:
   margin 16px top and bottom on every page (mobile + desktop), so
   the title-to-box and box-to-content gaps are identical everywhere;
   buttons inside are center-aligned on every page. Navy in light theme; dark theme lifts to the
   dark card navy with a line border so the box still separates from
   the navy page background. Flat, no shadow, no emoji. ===== */
.impact-box{background:#0a1633;border-radius:16px;padding:18px 20px;margin:16px 0;color:#fff}
.impact-box .ib-big{font-size:var(--fs-h2);font-weight:800;line-height:1.35}
.impact-box .gold{color:#ffd75e}
.impact-box .ib-sub{color:#aebadb;font-size:var(--fs-sm);margin-top:4px;line-height:1.45}
.impact-box .ib-btn{margin-top:12px;text-align:center}
.impact-box .ib-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.impact-box .ib-btns .btn{width:auto;margin-top:0;text-align:center}
.impact-box .btn.ib-btn-o{background:transparent;border:1.5px solid #ffd75e;color:#ffd75e}
:root[data-theme="dark"] .impact-box{background:#16295a;border:1px solid var(--line)}
@media (prefers-color-scheme:dark){
  :root[data-theme="system"] .impact-box{background:#16295a;border:1px solid var(--line)}
}


/* ===== design tokens — light ===== */
:root{
  --bg:#f6f5f1; --card:#ffffff; --surface2:#efede7; --card2:#fbfaf7;
  --gold:#9a7414; --gold-soft:#fbf0d3; --btn-ink:#ffffff;
  --txt:#1c1f26; --ink2:#3d434f; --muted:#6f7580;
  --line:#e4e1d8; --line2:#d8d3c6;
  --divider:color-mix(in srgb, var(--line) 55%, transparent);
  --divider-accent:color-mix(in srgb, var(--accent) 55%, transparent);
  --red:#c2410c; --green:#15803d;
  --accent:#0a6b4f; --accent-ink:#ffffff; --accent-soft:#e2f1ea;
  --input-bg:#ffffff;
  --pick-bg:#edf0f7; --pick-hover:#e1e8f4; --pick-card:#f6f7fb;
  --err-bg:#fdecea; --err-txt:#b3261e; --err-line:#f0c6c0;
  --ok-bg:#e6f4ea; --ok-txt:#137333; --ok-line:#b7e0c3;
  --radius:18px;
  /* ===== type scale (Ji approved 2026-10-22): H1 22/800 · H2 16/800 ·
     H3 15/700 · body 15/400 · small 13 (400, 700 when emphasized) ·
     numbers-only 26/800. Weights: 800/700/400 only. ===== */
  --fs-h1:22px; --fs-h2:16px; --fs-h3:15px; --fs-body:15px; --fs-sm:13px; --fs-num:26px;
  --radius-card:16px; --radius-ctl:12px; --radius-chip:10px; --radius-pill:999px; --radius-sheet:22px;
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:20px; --space-6:24px;
  --shadow:none;
  --sidebar-w:248px; --sidebar-wc:76px;
  color-scheme:light;
}
/* ===== design tokens — dark ===== */
:root[data-theme="dark"]{
  --bg:#0a1633; --card:#12234f; --surface2:#0e1c40; --card2:#16295a;
  --gold:#ffd75e; --gold-soft:#2a2410; --btn-ink:#1a1a1a;
  --txt:#f2f4fa; --ink2:#d7dcea; --muted:#9aa3b8;
  --line:#263a66; --line2:#31497d;
  --divider:color-mix(in srgb, var(--line) 55%, transparent);
  --divider-accent:color-mix(in srgb, var(--accent) 55%, transparent);
  --red:#ff8a80; --green:#7be2a0;
  --accent:#2fbc8a; --accent-ink:#07130e; --accent-soft:#143328;
  --input-bg:#0c1a3d;
  --pick-bg:#1a2f63; --pick-hover:#213872; --pick-card:#16295a;
  --err-bg:#3a1d1d; --err-txt:#ffb3b3; --err-line:#7a2e2e;
  --ok-bg:#17351f; --ok-txt:#b8f0c9; --ok-line:#2e6b3e;
  --radius:18px;
  --shadow:none;
  --sidebar-w:248px; --sidebar-wc:76px;
  color-scheme:dark;
}
/* ===== design tokens — system (follows OS) ===== */
@media (prefers-color-scheme: dark){
  :root[data-theme="system"]{
    --bg:#0a1633; --card:#12234f; --surface2:#0e1c40; --card2:#16295a;
    --gold:#ffd75e; --gold-soft:#2a2410; --btn-ink:#1a1a1a;
    --txt:#f2f4fa; --ink2:#d7dcea; --muted:#9aa3b8;
    --line:#263a66; --line2:#31497d;
    --divider:color-mix(in srgb, var(--line) 55%, transparent);
    --divider-accent:color-mix(in srgb, var(--accent) 55%, transparent);
    --red:#ff8a80; --green:#7be2a0;
    --accent:#2fbc8a; --accent-ink:#07130e; --accent-soft:#143328;
    --input-bg:#0c1a3d;
  --pick-bg:#1a2f63; --pick-hover:#213872; --pick-card:#16295a;
    --err-bg:#3a1d1d; --err-txt:#ffb3b3; --err-line:#7a2e2e;
    --ok-bg:#17351f; --ok-txt:#b8f0c9; --ok-line:#2e6b3e;
    --radius:18px;
    --shadow:none;
    --sidebar-w:248px; --sidebar-wc:76px;
    color-scheme:dark;
  }
}

*{box-sizing:border-box}

/* ===== page main titles: flat icon before the title (matches /app .sec-ic) ===== */
.ptitle{display:flex;align-items:center;gap:11px}
.pt-ic{width:22px;height:22px;flex:none;color:var(--muted)}

/* ===== shared chrome: sidebar nav items (base .snav / app .snl) ===== */
.snav,.snl{position:relative;display:flex;align-items:center;gap:13px;padding:11px 13px;border-radius:var(--radius-ctl);color:var(--muted);text-decoration:none;font-weight:700;font-size:var(--fs-body);white-space:nowrap}
.snav svg,.snl svg{width:21px;height:21px;flex-shrink:0}
.snav .sni,.snl .sni{width:21px;height:21px;flex-shrink:0;display:grid;place-items:center;font-size:17px}
.snav:hover,.snl:hover{background:var(--surface2);color:var(--txt);text-decoration:none}
.snav.on,.snl.on{background:var(--gold-soft);color:var(--gold)}
body.side-collapsed .snav,body.side-collapsed .snl{justify-content:center;padding:12px 0}

/* ===== shared chrome: back-to-top button ===== */
.totop{position:fixed;right:18px;bottom:32px;z-index:55;width:46px;height:46px;border-radius:50%;background:var(--card);color:var(--gold);border:1.5px solid var(--gold);font-size:19px;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transform:translateY(12px);transition:opacity .3s,transform .3s}
.totop.show{opacity:1;pointer-events:auto;transform:none}

/* ===== Unified app header (topbar + appbar identical) ===== */
.topbar,.appbar{position:sticky;top:0;background:color-mix(in srgb, var(--card) 88%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 22px}
.topbar .aburger,.appbar .aburger{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;color:var(--txt);font-size:30px;cursor:pointer;padding:10px;border-radius:var(--radius-ctl);line-height:1}
.topbar .brand-centered,.appbar .abrand{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:7px;text-decoration:none}
.topbar .brand-centered img,.appbar .abrand img{width:auto}

/* ===== shared chrome: logo day/night visibility ===== */
img.logo-night{display:none}
:root[data-theme="dark"] img.logo-day{display:none}
:root[data-theme="dark"] img.logo-night{display:block}
@media (prefers-color-scheme: dark){
  :root[data-theme="system"] img.logo-day{display:none}
  :root[data-theme="system"] img.logo-night{display:block}
}

/* ===== shared chrome: desktop sidebar (base .sidebar / app .sidenav) ===== */
.sidebar,.sidenav{position:fixed;left:0;top:0;bottom:0;width:var(--sidebar-w);background:var(--card);border-right:1px solid var(--line);flex-direction:column;z-index:80;padding:var(--space-5) 14px 14px}
body.side-collapsed .sidebar,body.side-collapsed .sidenav{width:var(--sidebar-wc)}
.side-nav,.snlinks{display:flex;flex-direction:column;gap:3px;flex:1;overflow-y:auto;overflow-x:hidden}
.side-brand-new,.sbrand{display:flex;align-items:center;justify-content:center;gap:8px;margin:2px var(--space-2) var(--space-5);text-decoration:none;flex-shrink:0;transform:translateX(-3px)}
body.side-collapsed .side-brand-new,body.side-collapsed .sbrand{display:flex;justify-content:center;margin:2px 0 20px;transform:none}
body.side-collapsed .side-brand-new img[src*="wordmark"],body.side-collapsed .sbrand img[src*="wordmark"]{display:none !important}
.sidebar .bellCount,.sidenav .sb-badge{margin-left:auto;font-style:normal;background:var(--red);color:#fff;font-size:var(--fs-sm);font-weight:700;border-radius:var(--radius-pill);padding:2px 7px}
@media(min-width:900px){body.side-collapsed .sidebar .bellCount,body.side-collapsed .sidenav .sb-badge{position:absolute;top:10px;left:calc(50% + 3px);margin:0;width:9px;height:9px;min-width:0;padding:0;font-size:0;line-height:0;color:transparent;border-radius:50%;box-shadow:0 0 0 2px var(--card)}}
.adrawer .dnav-main a.has-badge{display:flex;align-items:center}
.adrawer .dbadge{margin-left:auto;font-style:normal;background:var(--red);color:#fff;font-size:var(--fs-sm);font-weight:700;border-radius:var(--radius-pill);padding:2px 7px}
body.side-collapsed .snav .lbl,body.side-collapsed .snl .snt{display:none}
.side-foot,.sside-foot{margin-top:14px;border-top:1px solid var(--line);padding-top:10px;display:flex;flex-direction:column;gap:3px}
.slang-btn{width:100%;background:none;border:none;cursor:pointer;font-family:inherit;text-align:left}
.slang-caret{margin-left:auto;font-size:20px}
.slang-sub{display:flex;flex-direction:column;gap:4px;padding:4px 0 4px 34px}
.slang-sub[hidden]{display:none}
.slang-sub a{background:transparent;border:1px solid var(--line);color:var(--txt);border-radius:var(--radius-ctl);padding:9px;font-size:var(--fs-sm);font-weight:700;cursor:pointer;text-align:left;font-family:inherit;text-decoration:none;display:block}
.slang-sub a.cur{border-color:var(--gold);color:var(--gold)}
body.side-collapsed .slang-sub{display:none !important}
body.side-collapsed .slang-caret{display:none !important}
.side-collapse,.scollapse{margin-top:14px;border:1px solid var(--line);background:var(--card2);color:var(--muted);border-radius:var(--radius-ctl);padding:10px;cursor:pointer;font-size:16px;font-family:inherit;flex-shrink:0;display:flex;align-items:center;justify-content:flex-end}
.side-collapse .chev svg,.scollapse .chev svg{display:block}
body.side-collapsed .side-collapse,body.side-collapsed .scollapse{justify-content:center}
.side-collapse:hover,.scollapse:hover{color:var(--txt);border-color:var(--gold)}
.side-collapse .chev,.scollapse .chev{display:inline-block;transition:transform .18s ease}
body.side-collapsed .side-collapse .chev,body.side-collapsed .scollapse .chev{transform:rotate(180deg)}

/* ===== shared chrome: drawer close button (flat SVG icon, fixed size) ===== */
.adrawer .dhead{display:flex;align-items:center;justify-content:flex-end;flex:none;height:40px;margin:-6px 0 4px}
.adrawer .dx{flex:none;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:none;border:none;color:var(--muted);cursor:pointer;border-radius:var(--radius-ctl);padding:0}
.adrawer .dx svg{width:22px;height:22px}
.adrawer .dx:hover{color:var(--txt);background:var(--surface2)}

/* ===== Drawer language dropdown + door close (shared) ===== */
.dlang-btn{display:flex;align-items:center;gap:10px;width:100%;background:none;border:none;color:var(--txt);font-size:var(--fs-body);font-weight:700;cursor:pointer;padding:10px 8px;border-radius:var(--radius-ctl);font-family:inherit;text-align:left;margin-top:16px}
.adrawer .dlang-btn:hover{background:var(--surface2)}
.adrawer .dlang-btn .dglobe{display:inline-flex;flex:none}
.adrawer .dlang-caret{margin-left:auto;font-size:20px;color:var(--muted)}
.adrawer .dlang-sub{display:flex;gap:8px;padding:10px 2px 12px}
.adrawer .dlang-sub[hidden]{display:none}
.adrawer .dlang-sub a{flex:1;text-align:center;background:transparent;border:1.5px solid var(--line2);color:var(--txt);border-radius:var(--radius-ctl);padding:12px;font-size:15px;font-weight:700;text-decoration:none}
.adrawer .dlang-sub a.cur{border-color:var(--gold);color:var(--gold)}
/* drawer language row: mirrors the public (pre-login) drawer's
   two-button selector — divider on top, globe + English/한국어 side by
   side, always visible (no toggle). Current language = gold-dark
   border/text (public spec #85630e); dark themes use the bright gold,
   where gold-dark would be unreadable on the navy drawer. */
.adrawer .dlang2{display:flex;align-items:center;gap:10px;padding:16px 0 0;margin-top:12px;border-top:1px solid var(--line)}
.adrawer .dlang2 .dglobe{display:inline-flex;flex:none;color:var(--muted)}
.adrawer .dlang2 .dglobe svg{width:20px;height:20px;display:block}
.adrawer .dlang2 a{flex:1;text-align:center;background:transparent;border:1.5px solid var(--line2);color:var(--txt);border-radius:10px;padding:11px 6px;font-size:var(--fs-sm);font-weight:700;text-decoration:none}
.adrawer .dlang2 a.cur{border-color:#85630e;color:#85630e}
:root[data-theme="dark"] .adrawer .dlang2 a.cur{border-color:var(--gold);color:var(--gold)}
@media (prefers-color-scheme:dark){:root[data-theme="system"] .adrawer .dlang2 a.cur{border-color:var(--gold);color:var(--gold)}}
.adrawer .ddoor{margin-top:10px;display:flex;align-items:center;justify-content:flex-end;width:100%;padding:10px 12px;border:1px solid var(--line);background:var(--card2);color:var(--muted);border-radius:var(--radius-ctl);cursor:pointer;flex:none;font-family:inherit}
.adrawer .ddoor:hover{color:var(--txt);border-color:var(--gold)}
.adrawer .ddoor svg{width:22px;height:22px;display:block}

.dlogout .dni-svg{width:22px;height:22px;flex-shrink:0;margin-right:12px;color:var(--muted)}

/* ===== card picker: bank grid + card list (wallet add-card, register step 2) ===== */
.issuer-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-2);margin-top:var(--space-2)}
@media(min-width:900px){.issuer-grid{grid-template-columns:repeat(4,minmax(0,1fr))}}
.issuer-btn{min-width:0;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:1px;min-height:50px;background:var(--pick-bg);border:1px solid var(--line);border-radius:var(--radius-ctl);padding:10px;color:var(--txt);cursor:pointer;font-family:inherit;text-align:left;transition:background .15s,border-color .15s,transform .15s}
.issuer-btn:hover{background:var(--pick-hover);border-color:var(--gold);transform:translateY(-1px)}
.ib-name{font-size:var(--fs-sm);font-weight:700;line-height:19px;max-width:100%;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}
.ib-count{font-size:var(--fs-sm);font-weight:400;line-height:16px;color:var(--muted)}
.cardpick-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-2)}
@media(min-width:900px){.cardpick-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.cardpick{min-width:0;display:flex;align-items:center;gap:10px;padding:12px 14px;background:var(--pick-card);border:1px solid var(--line);border-radius:var(--radius-ctl);color:var(--txt);cursor:pointer;font-family:inherit;text-align:left;transition:background .15s,border-color .15s}
.cardpick:hover{background:var(--pick-hover);border-color:var(--gold)}
.cp-main{flex:1;min-width:0}
.cp-titlerow{display:flex;align-items:center;min-width:0}
.cp-name{flex:1;min-width:0;font-size:var(--fs-h3);font-weight:700;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.cp-partial{flex:none;font-size:var(--fs-sm);font-weight:700;color:var(--muted);background:var(--surface2);border-radius:var(--radius-chip);padding:1px 7px;margin-left:6px}
.cp-closed{flex:none;font-size:var(--fs-sm);font-weight:700;color:var(--muted);background:var(--surface2);border-radius:var(--radius-chip);padding:1px 7px;margin-left:6px}
.cp-fee{flex:none;font-size:var(--fs-sm);font-weight:700;padding:4px 10px;border-radius:var(--radius-pill);background:var(--gold-soft);color:var(--gold);white-space:nowrap;font-family:"IBM Plex Mono",ui-monospace,monospace;font-variant-numeric:tabular-nums}
.cardpick.added{opacity:.55;border-color:var(--green)}
.cardpick.added .cp-fee{background:var(--ok-bg);color:var(--ok-txt)}
.cp-family{grid-column:1 / -1;font-size:var(--fs-sm);font-weight:700;color:var(--muted);letter-spacing:.02em;margin:10px 2px -2px}
.cp-family:first-child{margin-top:0}
/* ===== 검색 필드 / Search Field (component): canonical field chrome
   with a flat magnifier inside-left and a clear button that appears
   only while the field has text. Used by the card pickers and
   /bonuses. No shadow. The /app quick search keeps its own row
   layout but reuses the same .swsearch-x clear button: its input
   (#qsearch) gets the same 42px right padding, and the native
   webkit cancel button is suppressed there too, so exactly one
   clear affordance ever shows. ===== */
.swsearch{position:relative;margin:10px 0 12px}
.swsearch>svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);width:18px;height:18px;color:var(--muted);pointer-events:none}
.swsearch input[type="search"]{width:100%;padding-left:40px;padding-right:42px}
.swsearch input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
#qsearch{padding-right:42px}
#qsearch::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.swsearch-x{position:absolute;right:6px;top:50%;transform:translateY(-50%);width:36px;height:36px;border:none;background:none;color:var(--muted);cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:50%;padding:0}
.swsearch-x:hover{color:var(--txt);background:var(--surface2)}
.swsearch-x svg{width:15px;height:15px}

/* ===== interaction states + numeric utilities + jump palette ===== */
.tnum{font-variant-numeric:tabular-nums}
.money{font-family:"IBM Plex Mono",ui-monospace,monospace;font-variant-numeric:tabular-nums}
a:focus-visible,button:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.cardpick:focus-visible,.issuer-btn:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.totop:hover{background:var(--gold-soft)}
/* ===== Cmd/Ctrl+K jump palette (base shell) ===== */
.swpal{position:fixed;inset:0;z-index:300;background:rgba(8,12,24,.48);display:flex;align-items:flex-start;justify-content:center;padding:12vh 16px 16px}
.swpal[hidden]{display:none}
.swpal-box{width:min(520px,100%);background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sheet);box-shadow:var(--shadow);overflow:hidden}
.swpal .swpal-box input{width:100%;border:none;border-bottom:1px solid var(--line);background:transparent;color:var(--txt);font-size:16px;padding:14px 16px;font-family:inherit;border-radius:0}
.swpal .swpal-box input:focus{outline:none;border-color:transparent;border-bottom-color:var(--gold);box-shadow:none}
.swpal-list{max-height:46vh;overflow-y:auto;padding:6px}
.swpal-item{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:var(--radius-ctl);color:var(--txt);text-decoration:none;font-size:var(--fs-body);font-weight:700;cursor:pointer}
.swpal-item:hover{text-decoration:none}
.swpal-item svg{width:20px;height:20px;flex-shrink:0;color:var(--muted)}
.swpal-item.sel{background:var(--gold-soft)}
.swpal-item.sel svg{color:var(--gold)}
.swpal-empty{padding:12px 16px 16px;color:var(--muted);font-size:var(--fs-sm)}
.swpal-empty[hidden]{display:none}
@media (prefers-reduced-motion:reduce){.issuer-btn,.cardpick,.totop{transition:none}}

/* ===== form fields: ONE canonical chrome + focus (base shell + /app) =====
   Every text-entry control: 16px text (so iOS never focus-zooms), 1px
   var(--line) border, var(--radius-ctl), var(--input-bg). Focus paints
   the SAME result everywhere: gold border + soft gold ring — identical
   to what .amount-box:focus-within paints on /app's amount box.
   Deliberate exceptions keep their own look via higher-specificity
   rules: borderless inner inputs (.amount-box input, palette inputs). */
input[type="text"],input[type="search"],input[type="number"],input[type="email"],input[type="password"],input[type="tel"],input[type="url"],input[type="date"],input[type="month"],textarea,select{background:var(--input-bg);border:1px solid var(--line);color:var(--txt);border-radius:var(--radius-ctl);padding:9px 12px;font-size:16px;line-height:1.5;font-family:inherit}
input[type="text"],input[type="email"],input[type="password"],input[type="number"],input[type="tel"],input[type="date"],input[type="month"],select{width:100%}
input[type="text"]:focus,input[type="search"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="tel"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,textarea:focus,select:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px color-mix(in srgb,var(--gold) 35%,transparent)}
/* Date/month fields must measure exactly like the text-like fields beside
   them: same 1.5 line-height (16px text -> 24px content + 18px padding +
   2px border = 44px box, the shared 44px control height). Native date
   controls, especially on touch
   devices, size themselves instead — flatten them there and pin the
   minimum height so the box can never come up short. */
input[type="number"]{line-height:1.5}
input[type="date"],input[type="month"]{line-height:1.5;height:44px;min-height:44px}
@media (pointer:coarse){input[type="date"],input[type="month"]{-webkit-appearance:none;appearance:none}}

/* ===== selects: one canonical down-caret + right padding everywhere ===== */
/* html select (0,0,2) outranks the base shell's select shorthand (0,0,1) for padding-right + background-image */
html select{appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236F7580' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;background-size:12px;padding-right:30px}
:root[data-theme="dark"] select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%239AA3B8' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
@media (prefers-color-scheme:dark){:root[data-theme="system"] select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%239AA3B8' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}}

/* ===== admin tables: ONE canonical spec (every /admin page) ===== */
table.adm{width:100%;border-collapse:collapse;font-size:13px}
table.adm th,table.adm td{text-align:left;padding:8px 6px;border-bottom:1px solid var(--line)}
table.adm th{color:var(--muted);font-weight:700;font-size:var(--fs-sm);white-space:nowrap}
/* Headers are short labels: nowrap above is load-bearing — Korean text
   breaks between any two characters, so a squeezed column stacks a short
   header vertically (the /admin/offers 활성 bug). Long-text columns
   absorb the squeeze instead. */
/* At 641px and up every admin table lays out at its natural width and
   scrolls inside its own card when it is wider than the card
   (width:max-content; min-width:100% so narrower tables still fill the
   card). Without max-content the table is pinned to width:100% and auto
   layout squeezes narrow columns to min-content — Korean text then wraps
   per character and dates split mid-token (the /admin/outbox +
   /admin/approvals crush, 2026-10-24: status cells 39-40px, dates 46px).
   The PAGE never overflows and action columns stay reachable by scrolling
   the table itself. .statlist is excluded: its fixed 72px value column
   keeps display:table. At 640px and below, plain tables scroll the same
   way and .stack tables fold into the card stack instead (rule below). */
@media(min-width:641px){table.adm:not(.statlist){display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%;width:max-content;min-width:100%}}
@media(max-width:640px){table.adm:not(.stack):not(.statlist){display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%;width:max-content;min-width:100%}}
/* Ranked label/count lists (.statlist + .sv): the value column is a fixed
   72px, right-aligned, tabular-nums — every value shares ONE right edge
   flush with the table end. One shared component (dashboard, analytics).
   .statlist is excluded from the scroll rules above (via :not) so the
   fixed value column survives. */
table.adm.statlist{table-layout:fixed}
table.adm.statlist td.sv{width:72px;text-align:right;font-variant-numeric:tabular-nums}
/* ===== admin table — mobile card stack (table.adm.stack): canonical spec
   (brand catalog, Tables & metrics). Opt-in for wide admin tables: at
   <=640px each row becomes a stacked block instead of a horizontal
   scroller, so no action column can be clipped off-screen. Line 1 is
   the identity cell (first td) with the role pill beside it; every
   other cell is a full-width meta line labeled by its data-th
   (templates fill data-th from the table's own header strings, so the
   labels follow the page language and no field is ever hidden); the
   role cell (.c-role) dissolves via display:contents so its pill joins
   line 1 and its action buttons wrap onto a final row. Full-width meta
   lines also keep dates/times whole (no mid-token breaks). Above
   640px a .stack table scrolls like any other admin table (rule above);
   only at 640px and below does it fold. ===== */
@media(max-width:640px){
  table.adm.stack{display:block;overflow:visible}
  table.adm.stack tbody{display:block}
  table.adm.stack tr{display:flex;flex-wrap:wrap;align-items:center;gap:4px var(--space-2);padding:10px 0;border-bottom:1px solid var(--line)}
  table.adm.stack tr:has(>th){display:none}
  table.adm.stack td{display:block;border-bottom:none;padding:2px 0;min-width:0}
  table.adm.stack td:first-child{order:1;flex:1 1 auto}
  table.adm.stack td[data-th]{order:3;flex:1 1 100%}
  table.adm.stack td[data-th]::before{content:attr(data-th);display:inline-block;min-width:88px;margin-right:var(--space-2);color:var(--muted);font-weight:700}
  table.adm.stack td.c-role{display:contents}
  table.adm.stack td.c-role .rolecell{display:contents}
  table.adm.stack .rolepill{order:2;flex:none}
  table.adm.stack td.c-role form,table.adm.stack td.c-role a.btn{order:4;flex:none}
}

/* ===== secondary pill (.pill-link): canonical spec (brand standards
   table). First defined page-locally in wallet.html / the CSV picker;
   promoted here so every page uses the one component. ===== */
.pill-link{display:inline-flex;align-items:center;justify-content:center;gap:6px;background:var(--surface2);border:1px solid var(--line);border-radius:999px;padding:10px 18px;font-size:var(--fs-h3);font-weight:700;color:var(--txt);cursor:pointer;min-height:44px;font-family:inherit;text-decoration:none}
.pill-link:hover{border-color:var(--gold);text-decoration:none}
button.pill-link[disabled]{opacity:.45;cursor:default}
button.pill-link[disabled]:hover{border-color:var(--line)}

/* ===== role pill (.rolepill): THE admin tier badge =====
   One shared component (brand catalog "역할 배지 (관리자)"): 일반 = line
   border + muted text, 관리자 (.adm) = navy border + navy text,
   수퍼관리자 (.super) = navy fill + white text — the same navy as
   .gate-ic / the active .chip (#12234f; dark #24386b + #3d5a9e ring).
   Gold never appears: gold is for CTAs and values only. First defined
   page-locally in admin_users.html with an off-palette gold treatment;
   promoted here 2026-10-23 (Ji) so no page redefines it. */
.rolepill{display:inline-flex;align-items:center;justify-content:center;line-height:1.2;padding:8px 16px;font-size:var(--fs-body);font-weight:700;border-radius:var(--radius-ctl);border:1px solid var(--line);color:var(--muted)}
.rolepill.adm{border-color:#12234f;color:#12234f}
.rolepill.super{background:#12234f;border-color:#12234f;color:#fff}
:root[data-theme="dark"] .rolepill.adm{border-color:#3d5a9e;color:var(--txt)}
:root[data-theme="dark"] .rolepill.super{background:#24386b;border-color:#3d5a9e;color:#fff}
@media (prefers-color-scheme:dark){:root[data-theme="system"] .rolepill.adm{border-color:#3d5a9e;color:var(--txt)}}
@media (prefers-color-scheme:dark){:root[data-theme="system"] .rolepill.super{background:#24386b;border-color:#3d5a9e;color:#fff}}

/* ===== Premium gate (.gate-card) — THE shared lock component =====
   Ji's standing rule (2026-10-22): every Premium gate/lock surface in
   SwipeWise renders through this ONE component (templates/_gate.html:
   gate_card / plock / lock_svg) — no bespoke per-page lock designs, and
   new Premium features must reuse it. Spec: brand catalog entry
   "Premium 게이트 (공유 컴포넌트)".
   Class A (section/page locks) = .gate-card: navy-circle lock icon +
   16px/800 feature title with the gold .plock chip + ONE plain-language
   line on what Premium unlocks here + gold 44px CTA to /pricing (shared
   key gate_cta) + optional .gate-note for a true per-surface fact only.
   Class B (inline micro-locks: settings rows, nudges, notes) = the
   .plock chip + lock glyph + .gate-note-line — same icon and chip,
   never a card. Flat, radius 16, 1px line border, no shadow; the circle
   lifts to the dark-navy palette in dark mode and to a translucent
   treatment inside the always-navy impact box. Gold stays reserved
   for values and CTAs. Margins are the component's own: 16px top
   and bottom (the impact-box principle) — pages add no spacing
   around a gate. */
.gate-card{display:flex;gap:14px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:20px;margin:16px 0}
.gate-ic{flex:none;width:40px;height:40px;border-radius:50%;background:#12234f;color:#fff;display:inline-grid;place-items:center;vertical-align:middle}
.gate-ic svg{width:20px;height:20px}
.gate-ic.sm{width:34px;height:34px}
.gate-ic.sm svg{width:17px;height:17px}
:root[data-theme="dark"] .gate-ic{background:#24386b;box-shadow:inset 0 0 0 1px #3d5a9e}
@media (prefers-color-scheme:dark){:root[data-theme="system"] .gate-ic{background:#24386b;box-shadow:inset 0 0 0 1px #3d5a9e}}
.impact-box .gate-ic{background:rgba(255,255,255,.14);color:#fff;box-shadow:inset 0 0 0 1px rgba(255,255,255,.35);margin-right:9px}
.gate-main{flex:1;min-width:0}
.gate-t{display:flex;align-items:center;flex-wrap:wrap;gap:8px;font-size:var(--fs-h2);font-weight:800;line-height:1.35}
.gate-d{margin:6px 0 0;line-height:1.5}
.gate-note{margin:6px 0 0;font-size:var(--fs-sm);color:var(--muted);line-height:1.45}
/* The CTA carries its gold face HERE (not just via the host page's
   .btn) so the shared gate renders to spec on shells that define no
   .btn of their own — first exercised inside the /app shell
   (2026-10-23). Values mirror base.html's .btn exactly. */
.gate-card .gate-cta{display:inline-flex;align-items:center;justify-content:center;width:auto;min-height:44px;padding:11px 22px;margin-top:14px;background:#ffd75e;color:#1a1a1a;border:none;border-radius:var(--radius-ctl);font-size:15px;font-weight:700;text-decoration:none}
.gate-card .gate-cta:hover{filter:brightness(1.05);text-decoration:none}
.plock{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-sm);font-weight:700;color:var(--gold);border:1px solid var(--gold);border-radius:var(--radius-pill);padding:2px 8px;white-space:nowrap;line-height:1.3}
.plock svg{width:13px;height:13px;flex:none}
.gate-note-line{color:var(--muted);font-size:var(--fs-sm);line-height:1.45}
.gate-note-line svg{width:14px;height:14px;vertical-align:-2px;margin-right:5px}

/* ===== icon toggle (.itoggle) — title-row round icon buttons =====
   Spec: brand catalog "아이콘 토글 버튼 (제목 행)". A 34px circle that
   lives at the right end of a section title row (first use: the /app
   store-search pin + household people toggles). OFF = card surface +
   1px line border + muted icon; ON (.on) = navy fill + white icon —
   the same navy as .gate-ic / the active .chip (#12234f; dark #24386b
   + #3d5a9e border). Icon-only: the accessible name comes from
   aria-label/title, never visible text. Gold never appears. */
.itoggle{flex:none;width:34px;height:34px;border-radius:50%;border:1px solid var(--line);background:var(--card);color:var(--muted);display:inline-grid;place-items:center;padding:0;cursor:pointer;font:inherit;text-decoration:none}
.itoggle svg{width:18px;height:18px;display:block}
.itoggle.on{background:#12234f;border-color:#12234f;color:#fff}
.itoggle[disabled]{opacity:.5;cursor:default}
:root[data-theme="dark"] .itoggle.on{background:#24386b;border-color:#3d5a9e}
@media (prefers-color-scheme:dark){:root[data-theme="system"] .itoggle.on{background:#24386b;border-color:#3d5a9e}}
/* Optical centering for the toggles + the quick-search magnifier: the
   svg boxes are already laid out dead-center (grid/flex, measured 0.00px
   box delta); these sub-pixel nudges center the INK MASS the eye anchors
   on instead — the pin's heavy head (ink centroid measured 0.83px high),
   the people glyph (0.29px right / 0.25px high), and the magnifier's
   ring, whose center sits at viewBox (11,11) = 0.92px up-left in its box
   (half-correction +0.5px toward it; the full ink centroid stays within
   0.6px). Transforms only — layout geometry is untouched. */
#qsPinBtn svg{transform:translateY(.8px)}
#qsHhToggle svg,.itoggle[href] svg{transform:translate(-.3px,.3px)}
.qsearch-btn svg{transform:translate(.5px,.5px)}
/* Locked variant (.itoggle.locked): a Premium-locked toggle stays
   VISIBLE and carries a small gold lock badge at the circle's
   bottom-right corner — the one gold exception on this component,
   from the .plock chip family (gold marks a Premium lock). Spec:
   brand catalog, the .itoggle entry. The people glyph inside takes
   the same optical nudge as the other people toggles; the badge
   glyph itself is never nudged. */
.itoggle.locked{position:relative}
.itoggle.locked>svg{transform:translate(-.3px,.3px)}
.itoggle .lk-badge{position:absolute;right:-4px;bottom:-4px;width:15px;height:15px;border-radius:50%;background:#ffd75e;color:#1a1a1a;border:1.5px solid var(--card);display:grid;place-items:center;pointer-events:none}
.itoggle .lk-badge svg{width:9px;height:9px;display:block;transform:none}

/* ===== candidate list (.cand-list) — pick-one dropdown rows =====
   Spec: brand catalog "후보 드롭다운 (매장 검색)". Opens under the
   /app store-search input after a location tap: up to 4 nearby stores,
   distance order, one row per store (name + distance). The selected
   row (.sel) is navy-filled with white text and carries the localized
   "선택됨 / Selected" label (.cand-sel); unselected rows are the card
   surface with a 1px line divider between rows. Flat, radius 12
   (control token), no shadow — same surface language as .gate-card. */
.cand-list{margin-top:var(--space-2);border:1px solid var(--line);border-radius:var(--radius-ctl);overflow:hidden;background:var(--card)}
.cand-row{display:flex;align-items:center;gap:var(--space-2);width:100%;padding:11px 12px;background:var(--card);border:0;border-top:1px solid var(--line);font:inherit;font-size:var(--fs-body);color:var(--txt);cursor:pointer;text-align:left}
.cand-row:first-child{border-top:0}
.cand-row .cand-sel{flex:none;font-size:var(--fs-sm);font-weight:700}
.cand-row .cand-name{flex:1;min-width:0}
.cand-row .cand-d{flex:none;font-size:var(--fs-sm);color:var(--muted)}
.cand-row.sel{background:#12234f;color:#fff}
.cand-row.sel .cand-d{color:#c9d4f2}
:root[data-theme="dark"] .cand-row.sel{background:#24386b}
@media (prefers-color-scheme:dark){:root[data-theme="system"] .cand-row.sel{background:#24386b}}
