/* Reconcile — refined light Nordic-fintech theme + smooth cross-page transitions */

/* ════════════════════════════════════════════════════════════════════════════
   DESIGN-SYSTEM FOUNDATION — iteration 1 (strictly non-breaking)
   Each change below is grounded in cognitive/behavioral science + WCAG 2.2 AA.
   NOTE: no token or selector was renamed/removed. Only (a) a few token VALUES
   were darkened for contrast, and (b) new additive rules/utilities/states.

   #  CHANGE                              PRINCIPLE                         WCAG
   ── ─────────────────────────────────  ────────────────────────────────  ────────────
   1  --ink-3 #8A97AD→#646F82             Perceivability: legible body text 1.4.3 AA
      --pos  #0B875B→#097A52              (darken to ≥4.5:1 on real bgs)    (contrast)
      --warn #B25E00→#A85800
      Before→After contrast on #FFFFFF:
        ink-3   2.95 → 5.08              (FAIL → PASS)
        pos     4.53 → 5.36              (badge text on pos-bg 3.98→4.67)
        warn    4.67 → 5.17              (badge text on warn-bg 4.20→4.65)
        ink-2  6.37 (unchanged, OK)  accent 6.82 (unchanged, OK)
        neg    5.30 (unchanged; badge on neg-bg 4.65 OK)
   2  :focus-visible ring                 Operability: keyboard visibility  2.4.7 / 2.4.11
   3  .btn min-height 40 / .sm 32         Fitts's Law: easy/large targets   2.5.8 (target size)
   4  .figure / .figure-label             Von Restorff: KPI numeral salience  —
   5  .amt-pos / .amt-neg (glyph+colour)  Colour-blind-safe sign semantics  1.4.1 (use of colour)
   7  .sr-only, forced-colors, selection  Robustness & micro-polish         1.3.1 / 1.4.11
   ════════════════════════════════════════════════════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,700;12..96,800&family=Hanken+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');

/* ── smooth transitions between the separate HTML pages (Chromium; degrades gracefully) ── */
@view-transition { navigation: auto; }
::view-transition-old(root){ animation: vt-out .16s ease both; }
::view-transition-new(root){ animation: vt-in .28s cubic-bezier(.16,1,.3,1) both; }
@keyframes vt-out{ to{ opacity:0; transform:translateY(-6px) } }
@keyframes vt-in{ from{ opacity:0; transform:translateY(10px) } }

:root{
  /* Native form controls (date/number/select, spinners, calendar) follow the APP theme,
     not the OS. Without this, <meta name="color-scheme" content="light dark"> in every
     page lets the browser paint native inputs from the OS scheme → dark fields on a
     light page when the OS is in dark mode. This CSS property overrides the meta tag. */
  color-scheme:light;
  /* ── Deep Teal-Ink palette (2026 refresh) — near-monochrome cool-neutral base +
     ONE rationed deep-teal accent. No gradient on the accent (flat, premium);
     green is reserved for the semantic --pos (positive amounts) only. ── */
  --bg:#F5F7F6; --bg-2:#FFFFFF;
  --ink:#122020; --ink-2:#516060; --ink-3:#657474; /* cool-neutral ink ramp; all ≥4.5:1 on #FFFFFF & --bg (WCAG 1.4.3) */
  --line:rgba(16,32,32,.10); --line-2:rgba(16,32,32,.18);
  --panel:#FFFFFF; --panel-2:#FAFBFB;
  --accent:#0C5E63; --accent-2:#0E7A80; --accent-grad:#0C5E63; /* accent-grad kept as a token for legacy refs but is now FLAT teal — no gradient (premium, non-cartoonish) */
  --accent-subtle:rgba(12,94,99,.08);
  /* Foreground for anything sitting ON --accent/--accent-grad. The accent INVERTS
     lightness between themes (#0C5E63 -> #42B8C0), so a hardcoded #fff cannot follow
     it: white-on-accent measures 7.5:1 in light and 2.37:1 in dark. Page-local pills
     kept re-inventing it and kept failing (tositteet .tt-act-approve, myyntilaskut
     .mi-seg button.on). One token, both themes. */
  /* Foreground for anything sitting ON a filled semantic token. ALL THREE tokens
     invert lightness in dark (accent #0C5E63->#42B8C0, pos #0F7A57->#3FD08A,
     neg #C8341A->#FF7A66), so a hardcoded #fff cannot follow any of them:
     white measures 7.51/5.33/5.30 in light but 2.37/1.98/2.55 in DARK — all fail.
     31 page-local declarations had each re-invented #fff and each failed the same
     way. One token per fill, both themes. */
  --on-accent:#FFFFFF; --on-pos:#FFFFFF; --on-neg:#FFFFFF; --on-warn:#FFFFFF;
  /* --brand: the solid brand accent. Pages reference var(--brand,#0BA15D); define it
     here (= --accent) so it is theme-correct rather than always the light literal. */
  --brand:#0C5E63;
  /* --actor-agent: the AI/agent actor colour (purple) — distinguishes agent-authored
     actions from the teal human/brand accent. Dark counterpart in the dark block. */
  /* Measured 3.87:1 at #7C5CDB (small, 800-weight) — under AA. The dark variant had
     already been lightened for contrast and light was left behind, on the one badge
     that carries the human-vs-agent distinction. #6341C4 = 5.32:1. */
  --actor-agent:#6341C4;
  --gold:#B07D1A;
  --pos:#0F7A57; --pos-bg:rgba(15,122,87,.11); /* semantic positive (kept green, distinct from teal accent); badge text ≥4.5:1 on pos-bg (WCAG 1.4.3) */
  --warn:#A85800; --warn-bg:rgba(255,153,31,.14); /* warn darkened from #B25E00 → badge text ≥4.5:1 on warn-bg (WCAG 1.4.3) */
  --neg:#C8341A; --neg-bg:rgba(222,53,11,.09);
  --appbar-h:60px;    /* the sticky top bar's height — see .appbar below */
  --radius:16px; --radius-sm:10px;
  /* Elevation — layered "contact + ambient" shadows (Stripe/iOS-grade soft depth).
     A tight 1px contact layer + progressively softer large-radius ambient layers,
     tinted with the warm ink so depth reads as light rather than grey. */
  --shadow-xs:0 1px 1.5px rgba(16,32,32,.05);
  --shadow-sm:0 1px 2px rgba(16,32,32,.05),0 1px 1px rgba(16,32,32,.03);
  --shadow:0 1px 2px rgba(16,32,32,.04),0 4px 10px -2px rgba(16,32,32,.06),0 14px 30px -8px rgba(16,32,32,.07);
  --shadow-lg:0 2px 4px rgba(16,32,32,.05),0 14px 30px -8px rgba(16,32,32,.10),0 32px 60px -16px rgba(16,32,32,.16);
  /* --accent-shadow: the ONE tinted elevation, used only under the primary action /
     active nav pill / brand mark. Everything else uses the neutral --shadow ladder. */
  --accent-shadow:0 4px 14px -2px rgba(12,94,99,.30);
  --ease:cubic-bezier(.16,1,.3,1);
  /* ── Motion system (additive; calm/predictable — finance conveys trust through steadiness) ──
     Durations: frequent <150ms, routine 160–240ms, entrance/exit 240–360ms.
     Easing: ease-out entering, ease-in exiting, ease-in-out for state changes. No bounce/elastic. */
  --dur-fast:140ms; --dur:200ms; --dur-enter:280ms; --dur-exit:200ms;
  --ease-out:cubic-bezier(.16,1,.3,1); --ease-in:cubic-bezier(.4,0,1,1); --ease-in-out:cubic-bezier(.65,0,.35,1);
  --font-display:'Bricolage Grotesque',system-ui,sans-serif;
  --font-body:'Hanken Grotesk',system-ui,sans-serif;
  --font-mono:'JetBrains Mono',ui-monospace,monospace;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  font-family:var(--font-body); color:var(--ink); font-size:14px; line-height:1.55;
  -webkit-font-smoothing:antialiased; min-height:100vh; position:relative;
  background:
    radial-gradient(60vmax 44vmax at 88% -12%, rgba(12,94,99,.05), transparent 62%),
    var(--bg);
}
.num{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
::selection{background:rgba(12,94,99,.15)}
::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-thumb{background:#C7CFCF;border-radius:99px;border:3px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:#B3BCBC;background-clip:padding-box}

/* ── App bar ── */
/* The shell wrapper must NOT form a containing block for its sticky appbar: as a
   plain <div> it's only as tall as the appbar, so position:sticky released after
   ~60px of scroll (the nav scrolled away) and every sticky thead (top:60px) then
   had a 60px empty band above it where the first row clipped. display:contents
   lets the appbar stick relative to <body>, so the nav stays pinned as intended. */
#shell{display:contents}
/* --appbar-h is the height any OTHER sticky element must offset itself by. It was
   referenced on two pages and DEFINED NOWHERE, so those `top: var(--appbar-h)` rules
   silently computed to 0 and the "sticky" toolbar sat UNDER this bar — its controls
   still hit-testing to whatever the appbar draws on top of them. */
.appbar{position:sticky;top:0;z-index:30;display:flex;align-items:center;gap:1rem;height:var(--appbar-h);
  padding:0 1.4rem;background:rgba(255,255,255,.94);
  -webkit-backdrop-filter:blur(12px) saturate(1.1);backdrop-filter:blur(12px) saturate(1.1);
  border-bottom:1px solid var(--line)}
.brand{display:flex;align-items:center;gap:.6rem;font-family:var(--font-display);font-weight:800;
  font-size:17px;color:var(--ink);letter-spacing:-.02em;text-decoration:none}
.brand .mark{width:29px;height:29px;border-radius:9px;background:var(--accent-grad);display:grid;
  place-items:center;color:var(--on-accent);font-weight:800;font-size:15px;box-shadow:var(--accent-shadow)}
/* Clean top bar: no heavy container — items are quiet by default, one bold accent
   pill marks the active page, hovers get a subtle wash. Links + menu buttons share
   one rule so they read as one row. */
.tabs{display:flex;align-items:center;gap:.05rem;margin-left:.25rem;background:transparent;padding:0;border:none}
.tabs a,.navgroup-btn{display:inline-flex;align-items:center;gap:.32rem;padding:.46rem .62rem;border:none;cursor:pointer;
  background:transparent;border-radius:999px;color:var(--ink-2);text-decoration:none;font-weight:600;font-size:13px;
  font-family:inherit;white-space:nowrap;transition:.16s var(--ease)}
.tabs a:hover,.navgroup-btn:hover{color:var(--ink);background:var(--accent-subtle)}
.tabs a.active,.navgroup-btn.active{color:var(--on-accent);background:var(--accent-grad);box-shadow:var(--accent-shadow)}
/* Grouped nav — APG menu button (click toggle + full keyboard; pointer hover opens
   too). Kirjanpito/Ohjaamo/Verot/Raportit collapse multi-screen jobs (Hick's law). */
.navgroup{position:relative;display:flex}
.navgroup-btn .caret{display:inline-flex;align-items:center;opacity:.6;transition:transform .2s var(--ease)}
.navgroup-btn .caret svg{width:13px;height:13px}
.navgroup.open .navgroup-btn{color:var(--ink);background:var(--accent-subtle)}
.navgroup.open .navgroup-btn.active{color:var(--on-accent);background:var(--accent-grad)}
.navgroup.open .navgroup-btn .caret{transform:rotate(180deg)}
.navdropdown{position:absolute;top:calc(100% + 10px);left:0;min-width:252px;display:flex;flex-direction:column;gap:.05rem;
  padding:.5rem;background:var(--panel);border:1px solid var(--line);border-radius:16px;
  box-shadow:0 24px 50px -22px rgba(0,0,0,.45),0 2px 6px -3px rgba(0,0,0,.12);
  opacity:0;visibility:hidden;transform:translateY(-8px) scale(.985);transform-origin:top left;
  transition:opacity .16s var(--ease),transform .16s var(--ease),visibility .16s;z-index:40}
.navgroup.open .navdropdown{opacity:1;visibility:visible;transform:none}
.nav-sec{font-family:var(--font-mono);font-size:10px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);padding:.6rem .6rem .28rem}
.nav-sec:first-child{padding-top:.25rem}
.navdropdown a{display:flex;align-items:center;gap:.62rem;padding:.5rem .6rem;border-radius:10px;color:var(--ink-2);
  text-decoration:none;font-weight:600;font-size:13px;white-space:nowrap;transition:.13s var(--ease)}
.navdropdown a .nav-ic{flex:none;display:grid;place-items:center;width:18px;height:18px;color:var(--ink-3);transition:.13s var(--ease)}
.navdropdown a .nav-ic svg{width:16px;height:16px}
.navdropdown a:hover{background:var(--accent-subtle);color:var(--accent)}
.navdropdown a:hover .nav-ic{color:var(--accent)}
.navdropdown a.active{background:var(--accent-subtle);color:var(--accent);box-shadow:inset 2px 0 0 var(--accent)}
.navdropdown a.active .nav-ic{color:var(--accent)}
.tabs-right{margin-left:0;background:transparent;border:none;padding:0}
.appbar-right{display:flex;align-items:center;gap:1rem;flex:none}
.appbar .spacer{flex:1}
.company-pick{display:flex;align-items:center;gap:.55rem;font-size:12px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.07em;font-weight:600}
.company-pick select{font-family:var(--font-body);font-size:13px;font-weight:600;color:var(--ink);
  text-transform:none;letter-spacing:0;padding:.45rem .8rem;border:1px solid var(--line-2);border-radius:999px;
  background:#fff;min-width:150px;max-width:230px;cursor:pointer;
  overflow:hidden;text-overflow:ellipsis}
.company-pick select:hover{border-color:var(--accent)}
/* Active-client dot — "you are in CLIENT X" persistent context (wrong-client safety). */
.company-pick:not(.acct)::before{content:"";flex:none;width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 3px var(--accent-subtle)}
.company-pick .adminbadge{display:inline-flex;align-items:center;gap:.3rem;font-size:10.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;color:var(--accent);background:var(--accent-subtle);
  border:1px solid rgba(12,94,99,.20);padding:.2rem .55rem;border-radius:999px}
.company-pick .adminsep{color:var(--ink-3);font-size:14px;margin:0 -.15rem}
/* Account menu — one compact avatar dropdown that consolidates Asetukset / Ylläpito /
   theme toggle / signed-in email / logout (they used to sit inline and clip off the
   right edge on <~1500px laptops). Reuses .navgroup + .navdropdown wholesale; only an
   avatar trigger and right-edge alignment are new. Company picker stays separate. */
.acctmenu{flex:none}
.acctmenu-btn{gap:.28rem;padding:.28rem .4rem}
.acctmenu-avatar{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  font-size:12px;font-weight:700;color:var(--on-accent);background:var(--accent-grad);box-shadow:var(--accent-shadow)}
.acctmenu-avatar svg{width:15px;height:15px}
/* On the active pill (settings/admin page) a green-gradient avatar would be green-on-green;
   swap it for a translucent white disc so it stays legible. */
.acctmenu-btn.active .acctmenu-avatar{background:rgba(255,255,255,.25);box-shadow:none}
.acctmenu .navdropdown{left:auto;right:0;min-width:220px;transform-origin:top right}
.acctmenu .acctmenu-glyph{font-size:15px}
.acctmenu-email{padding:.55rem .6rem;margin-top:.25rem;border-top:1px solid var(--line);
  font-size:11.5px;font-weight:600;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:240px}

/* ── Layout ── */
.page{max-width:1240px;margin:0 auto;padding:2.2rem 1.6rem 5rem}
.page-head{margin:.25rem 0 1.9rem}
.page-head h1{font-family:var(--font-display);font-weight:800;font-size:33px;line-height:1.05;
  letter-spacing:-.03em;color:var(--ink);margin:0 0 .4rem}
.page-head p{margin:0;color:var(--ink-2);font-size:14.5px;max-width:62ch}
.cols{display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem;align-items:start}
@media(max-width:960px){.cols{grid-template-columns:1fr}}
.stack{display:flex;flex-direction:column;gap:1.1rem}

/* ── Cards / columns ── */
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:1.3rem 1.4rem;animation:rise .5s var(--ease) both;position:relative}
.card h2{font-family:var(--font-display);font-weight:700;font-size:15px;margin:0 0 .9rem;color:var(--ink);
  display:flex;align-items:center;gap:.6rem;letter-spacing:-.01em}
.card .step{display:inline-grid;place-items:center;width:24px;height:24px;border-radius:8px;
  background:var(--accent-grad);color:var(--on-accent);font-size:12px;font-weight:800;box-shadow:var(--accent-shadow)}
.col{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);
  overflow:hidden;animation:rise .5s var(--ease) both}
.col>header{padding:1rem 1.1rem;border-bottom:1px solid var(--line);display:flex;align-items:center;
  justify-content:space-between;gap:.5rem;background:var(--panel-2)}
.col>header h2{margin:0;font-family:var(--font-display);font-size:13px;font-weight:700;color:var(--ink);
  text-transform:uppercase;letter-spacing:.06em}
.col>header .count{font-family:var(--font-mono);font-size:13px;color:var(--accent);font-weight:700;
  background:var(--accent-subtle);padding:.1rem .55rem;border-radius:999px}
.col .body{padding:.8rem;display:flex;flex-direction:column;gap:.6rem;max-height:66vh;overflow:auto}

/* ── Items ── */
.item{border:1px solid var(--line);border-radius:var(--radius-sm);padding:.75rem .85rem;background:#fff;transition:.18s var(--ease)}
.item:hover{border-color:var(--line-2);box-shadow:var(--shadow-sm);transform:translateY(-1px)}
.item.high{border-left:3px solid var(--pos)}
.item.medium{border-left:3px solid var(--warn)}
.item .row{display:flex;align-items:baseline;justify-content:space-between;gap:.5rem}
.item .amt{font-family:var(--font-mono);font-weight:700;color:var(--ink)}
.item .who{font-weight:600;color:var(--ink)}
.item .meta{color:var(--ink-3);font-size:12px;margin-top:.3rem;line-height:1.5}

/* ── Badges ── */
.badge{display:inline-flex;align-items:center;gap:.3rem;font-family:var(--font-mono);font-size:10.5px;font-weight:700;
  padding:.16rem .55rem;border-radius:999px;text-transform:uppercase;letter-spacing:.05em}
.badge.high{background:var(--pos-bg);color:var(--pos)}
.badge.medium{background:var(--warn-bg);color:var(--warn)}
.badge.card11{background:#ECEFEF;color:var(--ink-2)}
.badge.basis{background:var(--accent-subtle);color:var(--accent);text-transform:none;letter-spacing:0}
.badge.dir{background:#ECEFEF;color:var(--ink-2)}

/* ── Buttons ── */
.btn{font-family:var(--font-body);font-weight:600;font-size:13px;cursor:pointer;padding:.55rem 1rem;border-radius:999px;
  border:1px solid var(--line-2);background:#fff;color:var(--ink);transition:.16s var(--ease);
  display:inline-flex;align-items:center;gap:.4rem}
/* An author `display` beats the UA [hidden]{display:none}, so EVERY `class="btn"
   … hidden` in the app was painting anyway — e.g. raportit's "Lataa CSV" sat there
   permanently as a dead, disabled button that `csvBtn.hidden = true` could not
   remove. Fix it once, at the source, for every .btn in web/. */
.btn[hidden]{display:none}
.btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-subtle);transform:translateY(-1px)}
.btn.primary{background:var(--accent-grad);border:none;color:var(--on-accent);box-shadow:var(--accent-shadow)}
.btn.primary:hover{box-shadow:0 8px 22px -2px rgba(12,94,99,.42);color:#fff;transform:translateY(-1px)}
.btn.sm{padding:.35rem .7rem;font-size:12px}
.btn.ghost{background:transparent;border-color:transparent;color:var(--accent)}
.btn.ghost:hover{background:var(--accent-subtle)}
/* Destructive action (confirmDialog danger=true). Token-driven → light+dark correct. */
.btn.danger{background:var(--neg);border:none;color:var(--on-neg);box-shadow:0 6px 16px var(--neg-bg)}
.btn.danger:hover{color:var(--on-neg);background:var(--neg);filter:brightness(1.06);transform:translateY(-1px)}
/* Ghost + danger = a subtle red-text delete (transparent bg, e.g. row "Poista").
   Needed because the solid-red .btn.danger background would otherwise sit under the
   red ghost text and make the label invisible (red-on-red). Higher specificity than
   either single rule, so it wins for the combination only. */
.btn.ghost.danger{background:transparent;border-color:transparent;color:var(--neg);box-shadow:none}
.btn.ghost.danger:hover{background:var(--neg-bg);color:var(--neg);filter:none;transform:none}
.btn:disabled{opacity:.5;cursor:not-allowed;transform:none}
/* Subtle press feedback — frequent interaction (<150ms feel), calm settle, no bounce.
   Overrides the hover translateY only while actively pressed. */
.btn:active:not(:disabled){transform:translateY(0) scale(.98);transition-duration:var(--dur-fast)}
.btnrow{display:flex;flex-wrap:wrap;gap:.55rem;align-items:center}

/* ── Inputs ── */
input[type=text],input:not([type]),input[type=email],textarea,select.in{font-family:var(--font-body);font-size:13px;
  color:var(--ink);padding:.55rem .7rem;border:1px solid var(--line-2);border-radius:var(--radius-sm);background:#fff;width:100%}
input::placeholder{color:var(--ink-3)}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-subtle)}
textarea{font-family:var(--font-mono);min-height:96px;resize:vertical;font-size:12.5px}
input[type=file]{font-size:13px;color:var(--ink-2)}
input[type=file]::file-selector-button{font-family:var(--font-body);font-weight:700;font-size:12px;margin-right:.7rem;
  padding:.45rem .8rem;border-radius:999px;border:1px solid var(--line-2);background:#fff;color:var(--ink);cursor:pointer}
input[type=file]::file-selector-button:hover{border-color:var(--accent);color:var(--accent)}
.field{display:flex;flex-direction:column;gap:.4rem;margin:.6rem 0}
.field select,.card select:not(.company-pick select){font-family:var(--font-body);font-size:13px;color:var(--ink);
  padding:.55rem .7rem;border:1px solid var(--line-2);border-radius:var(--radius-sm);background:#fff;width:100%}
.field label{font-size:12px;font-weight:600;color:var(--ink-2)}
.hint{font-size:12.5px;color:var(--ink-3);line-height:1.55}
.hint b{color:var(--ink-2);font-weight:600}
.status{font-size:12.5px;color:var(--ink-2);min-height:1em;margin-top:.5rem;font-family:var(--font-mono)}
.status.ok{color:var(--pos)} .status.err{color:var(--neg)}
.muted{color:var(--ink-3)}
/* ── Inline field validation (additive) ── */
.field-err{color:var(--neg);font-size:12px;margin-top:.25rem;display:none;line-height:1.45}
.field.invalid .field-err{display:block}
.field.invalid input,.field.invalid select{border-color:var(--neg);box-shadow:0 0 0 3px var(--neg-bg)}
.field.invalid input:focus,.field.invalid select:focus{border-color:var(--neg);box-shadow:0 0 0 3px var(--neg-bg)}
.field.ok input,.field.ok select{border-color:var(--pos)}

/* ── Käsinkirjaus / Muistiotosite (journal entry) — P0 F4 field primitives ──
   Reuses .field + the account combobox (.ap-cb). Token-driven → light+dark correct;
   native date/number inputs styled to match (color-scheme already light via :root). */
.je-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-sm);padding:1.3rem 1.4rem;margin:0 0 1.1rem}
.je-title{font-family:var(--font-display);font-weight:700;font-size:16px;letter-spacing:-.01em;margin:0 0 .15rem;display:flex;align-items:baseline;gap:.5rem}
.je-title .je-sub{font-family:var(--font-mono);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-3)}
.je-head{display:flex;gap:1rem;flex-wrap:wrap;margin:.9rem 0 .2rem}
.je-head .field{margin:0}
.je-date{flex:0 0 auto} .je-desc{flex:1 1 240px}
.je-table{width:100%;border-collapse:collapse;font-size:13px;margin-top:.5rem}
.je-table th{text-align:left;font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-3);font-weight:700;padding:.3rem .55rem .5rem}
.je-table th.r{text-align:right}
.je-table td{padding:.28rem .35rem;vertical-align:middle;border-bottom:1px solid var(--line)}
.je-table tr:last-child td{border-bottom:none}
.je-table td.r{text-align:right}
.je-acct{display:flex;align-items:center;gap:.55rem}
.je-acin{flex:1 1 auto;min-width:130px;width:auto}
.je-acname{font-size:12px;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:0 1 45%}
/* Invalid-account state in the manual-entry modal (KPL 2:5 § – must post to a real
   account). Assessed on blur / save, cleared on re-focus. */
.je-acin[aria-invalid="true"]{border-color:var(--warn);box-shadow:0 0 0 2px var(--warn-bg)}
.je-acname.err{color:var(--warn)}
.je-card input[type=date],.je-card .num-in{font-family:var(--font-body);font-size:13px;color:var(--ink);padding:.5rem .6rem;border:1px solid var(--line-2);border-radius:var(--radius-sm);background:var(--bg-2);width:100%}
.num-in{font-family:var(--font-mono);font-variant-numeric:tabular-nums;text-align:right}
.je-foot{display:flex;align-items:center;gap:.7rem;margin-top:.8rem;flex-wrap:wrap}
.je-foot .btn.primary{margin-left:auto}
.je-balance{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:12.5px;color:var(--ink-3)}
.je-balance.ok{color:var(--pos)} .je-balance.bad{color:var(--warn)}
.je-x{border:none;background:transparent;color:var(--ink-3);cursor:pointer;font-size:18px;line-height:1;width:28px;height:28px;border-radius:8px;transition:color .14s var(--ease),background .14s var(--ease)}
.je-x:hover{background:var(--neg-bg);color:var(--neg)}

/* ── Shared modal shell (app.js-injected Muistiotosite; reusable for dialogs) ── */
.mt-bg{position:fixed;inset:0;z-index:130;display:grid;place-items:start center;padding:7vh 1.2rem 1.2rem;background:rgba(16,28,22,.34);backdrop-filter:blur(2px);animation:kb-fade var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both}
.mt-bg[hidden]{display:none}
[data-theme="dark"] .mt-bg{background:rgba(0,0,0,.55)}
.mt-modal{position:relative;width:min(680px,100%);max-height:88vh;overflow:auto;animation:kb-pop var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both}
.mt-modal .je-card{margin:0}
.mt-x{position:absolute;top:.7rem;right:.8rem;width:32px;height:32px;display:grid;place-items:center;font-size:22px;line-height:1;color:var(--ink-3);cursor:pointer;background:transparent;border:none;border-radius:999px;z-index:1}
.mt-x:hover{color:var(--ink);background:var(--accent-subtle)}

/* ── Account combobox popover — shared P0 F4 primitive (token-driven, light+dark) ── */
.acpop{position:absolute;z-index:140;list-style:none;margin:0;padding:.35rem;background:var(--panel);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-lg);max-height:300px;overflow:auto;min-width:280px;animation:kb-fade .12s var(--ease) both}
.acpop[hidden]{display:none}
.acpop .acgrp{font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-3);padding:.4rem .6rem .25rem}
.acpop .acopt{display:flex;align-items:baseline;gap:.6rem;padding:.45rem .6rem;border-radius:8px;cursor:pointer}
.acpop .acopt .acnum{font-family:var(--font-mono);font-weight:700;color:var(--ink);font-size:12.5px;min-width:46px}
.acpop .acopt .acname{color:var(--ink-2);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acpop .acopt.active,.acpop .acopt:hover{background:var(--accent-subtle)}
.acpop .acmore{padding:.7rem;color:var(--ink-3);font-size:12.5px;text-align:center}

/* ── Ledger table ── */
table.ledger{width:100%;border-collapse:collapse;margin-top:.7rem;font-size:13px}
table.ledger th{text-align:left;font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-3);font-weight:700;padding:.35rem .5rem;border-bottom:1px solid var(--line)}
table.ledger td{padding:.42rem .5rem;border-bottom:1px solid #E8ECEC;color:var(--ink)}
table.ledger td.n{font-family:var(--font-mono);text-align:right;font-variant-numeric:tabular-nums}
table.ledger tr:last-child td{border-bottom:none}

/* ── misc ── */
.empty{color:var(--ink-3);font-size:13px;text-align:center;padding:1.8rem .5rem}

/* ════════════════ EMPTY-STATE PATTERN (purely additive) ════════════════
   Grounded in: Nielsen #1 "visibility of system status" + #9 "help users
   recognize/recover", the goal-gradient effect (always surface the next step),
   and a calm, trustworthy fintech tone (this is money software).
   STRICTLY NON-BREAKING: bare `<div class="empty">text</div>` is unchanged —
   the rules below only style OPTIONAL children (.empty-ic, h3, p, .empty-cta).
   ───────────────────────────────────────────────────────────────────────── */

/* When an .empty contains a structured first-run block, give it breathing room
   and centre its children. Plain-text .empty has no children → unaffected. */
.empty.empty-rich{
  display:flex; flex-direction:column; align-items:center; gap:.55rem;
  padding:2.6rem 1.4rem; max-width:46ch; margin:0 auto;
}
/* Optional icon disc — calm accent-tinted, never alarming. */
.empty .empty-ic{
  display:grid; place-items:center; width:52px; height:52px; border-radius:14px;
  background:var(--accent-subtle); color:var(--accent); font-size:24px; line-height:1;
  border:1px solid rgba(12,94,99,.16); margin-bottom:.15rem;
}
/* Title line — confident but quiet. */
.empty h3{
  font-family:var(--font-display); font-weight:700; font-size:16px;
  letter-spacing:-.01em; color:var(--ink); margin:0;
}
/* Muted description — one reassuring sentence. */
.empty p{
  margin:0; color:var(--ink-3); font-size:13px; line-height:1.55; max-width:42ch;
}
/* The primary next-step CTA (reuses .btn; just adds spacing). */
.empty .empty-cta{ margin-top:.6rem; }
.empty .empty-cta .btn{ text-decoration:none; }
.toast{position:fixed;right:1.4rem;bottom:1.4rem;background:var(--ink);color:#fff;padding:.8rem 1.1rem;
  border-radius:var(--radius-sm);box-shadow:var(--shadow-lg);font-size:13px;font-weight:500;opacity:0;
  transform:translateY(10px);transition:.3s var(--ease);z-index:60;max-width:380px}
.toast.show{opacity:1;transform:none}
.toast.err{background:var(--neg)}
.proposal-id{font-family:var(--font-display);font-weight:700;color:var(--ink);font-size:15px}
.acct-row{display:flex;align-items:center;gap:.55rem;margin:.7rem 0;flex-wrap:wrap}
.acct-row .acctname{font-size:12px;color:var(--ink-2);min-width:120px;font-weight:600}
@keyframes rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.stack>.card:nth-child(2),.cols>*:nth-child(2){animation-delay:.05s}
.stack>.card:nth-child(3),.cols>*:nth-child(3){animation-delay:.1s}
.stack>.card:nth-child(4){animation-delay:.15s} .stack>.card:nth-child(5){animation-delay:.2s}
@media (prefers-reduced-motion: reduce){
  /* Neutralise BOTH animations and transitions (the drawer / bulk-bar / view-
     transition slides are CSS transitions, not @keyframes) so motion-sensitive
     users get no movement — WCAG 2.3.3. Near-zero (not 0) keeps transitionend /
     animationend handlers firing. */
  *{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  ::view-transition-old(root),::view-transition-new(root){animation:none}
}

/* ════════════════ FOUNDATION ADDITIONS (purely additive) ════════════════ */

/* (2) Visible keyboard focus — WCAG 2.4.7 / 2.4.11. Operability.
   A clear ring appears for keyboard/AT users; mouse focus stays clean.
   The existing input box-shadow :focus is preserved and complements this. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
summary:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
}
/* Suppress the ring when focus came from a pointer (keep box-shadow on inputs). */
a:focus:not(:focus-visible),
button:focus:not(:focus-visible),
.btn:focus:not(:focus-visible),
[tabindex]:focus:not(:focus-visible),
summary:focus:not(:focus-visible){ outline:none }
/* High-contrast / forced-colors users get a system-colored ring. */
@media (forced-colors: active){
  a:focus-visible,button:focus-visible,.btn:focus-visible,
  input:focus-visible,select:focus-visible,textarea:focus-visible,
  [tabindex]:focus-visible,summary:focus-visible{ outline:2px solid Highlight }
}

/* (3) Fitts's Law — comfortable, predictable target sizes (WCAG 2.5.8).
   min-height + line-height only, so existing paddings / pill shapes are intact
   (bulk bar, segmented .tabs pills, .btnrow all keep their layout). */
.btn{ min-height:40px; line-height:1.2 }
.btn.sm{ min-height:32px }

/* (4) Von Restorff effect — make the ONE key number on a screen pop.
   Opt-in: does not restyle any existing element. */
.figure{
  font-family:var(--font-display),var(--font-mono);
  font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1;
  font-weight:800; font-size:28px; line-height:1.05;
  letter-spacing:-.02em; color:var(--ink);
}
.figure-label{
  display:block; font-family:var(--font-mono);
  font-size:10.5px; font-weight:700; text-transform:uppercase;
  letter-spacing:.08em; color:var(--ink-3);
}

/* (5) Colour-blind-safe sign semantics — WCAG 1.4.1 (don't rely on colour alone).
   Sign is conveyed by a GLYPH + colour. Opt-in; euro()/existing amounts untouched. */
.amt-pos{ color:var(--pos); font-variant-numeric:tabular-nums }
.amt-pos::before{ content:"+\00a0" }
.amt-neg{ color:var(--neg); font-variant-numeric:tabular-nums }
.amt-neg::before{ content:"\2212\00a0" } /* U+2212 true minus */

/* (7) Accessible-name helper — visually hidden, available to screen readers. */
.sr-only{
  position:absolute!important; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0;
}

/* Skip-to-content link (WCAG 2.4.1 Bypass Blocks). Off-screen until focused; on
   keyboard focus it pins top-left above the sticky appbar (z-index:30). */
.skip-link{
  position:absolute; left:-9999px; top:0; z-index:100;
  font-family:var(--font-body); font-weight:700; font-size:13px; text-decoration:none;
}
.skip-link:focus,.skip-link:focus-visible{
  left:.5rem; top:.5rem; padding:.5rem .9rem; border-radius:var(--radius-sm);
  background:var(--accent); color:var(--on-accent); box-shadow:var(--shadow-lg);
}

/* ════════════════ PERCEIVED-PERFORMANCE LAYER (purely additive) ════════════════
   Grounded in: the Doherty threshold (<400ms perceived response), skeleton-screen
   research (structure first → lower perceived wait), Nielsen #1 "visibility of
   system status", and WCAG 2.2 (1.3.1 structure, 4.1.2 name/role/value, 4.1.3
   status messages). Light/Nordic; respects prefers-reduced-motion. App-wide.

   #  UTILITY               PURPOSE
   ── ───────────────────── ────────────────────────────────────────────────────
   8  .skeleton             Shimmer placeholder so layout appears within ~100ms
   9  .btn.is-busy          Inline spinner + dim → immediate action acknowledgment
   10 [aria-busy] cursor    Progress cursor for any busy region
   ════════════════════════════════════════════════════════════════════════════ */

/* (8) Skeleton placeholder — a subtle grey shimmer sweep while data loads. */
@keyframes ap-shimmer{ 0%{ background-position:200% 0 } 100%{ background-position:-200% 0 } }
.skeleton{
  display:block; min-height:14px; border-radius:8px;
  background:linear-gradient(100deg, #ECEFEF 30%, #F3F6F6 50%, #ECEFEF 70%);
  background-size:200% 100%;
  animation:ap-shimmer 1.4s var(--ease) infinite;
  /* never reads as real content to AT */
  color:transparent; user-select:none; pointer-events:none;
}
.skeleton.sk-text{ height:.9em; margin:.2rem 0 }
.skeleton.sk-lg{ min-height:42px }

/* (9) Busy button — inline spinner via ::after, slight dim, stable width.
   Pair with aria-busy="true" / disabled (set by JS) for AT + interaction lock. */
@keyframes ap-spin{ to{ transform:rotate(360deg) } }
.btn.is-busy{
  pointer-events:none; opacity:.72; position:relative;
}
.btn.is-busy::after{
  content:""; width:13px; height:13px; flex:none; border-radius:50%;
  border:2px solid currentColor; border-top-color:transparent;
  animation:ap-spin .7s linear infinite;
}
/* primary buttons render white text → spinner inherits via currentColor. */

/* Progress cursor for any busy region (aria-busy is set by withBusy()). */
[aria-busy="true"]{ cursor:progress }

/* Reduced-motion: replace shimmer/spin with a calm static state (no animation). */
@media (prefers-reduced-motion: reduce){
  .skeleton{
    animation:none;
    background:#ECEFEF;
  }
  .btn.is-busy::after{ animation:none }
  /* Drop the decorative press scale — keep only functional feedback. */
  .btn:active:not(:disabled){ transform:none }
}

/* ════════════════ KEYBOARD-SHORTCUTS LAYER (purely additive) ════════════════
   Expert-path efficiency (Gmail/Linear): a fast keyboard path (Hick's law) kept
   discoverable via a "?" help dialog. Generic `kb-`/`kbsheet-` prefixes so these
   never collide with page-scoped ap-/rp-/wz- styles. Built by app.js, app-wide.
   ───────────────────────────────────────────────────────────────────────── */

/* Small keycap chip — mono glyph, subtle border + inset shadow. */
.kbd{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:1.5em; padding:.12rem .42rem;
  font-family:var(--font-mono); font-size:11.5px; font-weight:700; line-height:1.4;
  color:var(--ink-2); background:#F3F6F6;
  border:1px solid var(--line-2); border-radius:7px;
  box-shadow:0 1px 0 var(--line-2), inset 0 1px 0 #fff;
}

/* Backdrop — dims the page, centres the panel, closes on click-through. */
.kbsheet-bg{
  position:fixed; inset:0; z-index:120;
  display:grid; place-items:center;
  padding:1.4rem;
  background:rgba(16,28,22,.34);
  backdrop-filter:blur(2px);
  animation:kb-fade var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both;
}
.kbsheet-bg[hidden]{ display:none }

/* Centred modal panel — theme tokens, calm scale/fade entrance. */
.kbsheet{
  width:min(420px,100%); max-height:86vh; overflow:auto;
  background:var(--panel); color:var(--ink);
  border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-lg);
  padding:1.5rem 1.6rem 1.3rem; position:relative;
  animation:kb-pop var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both;
}
.kbsheet:focus{ outline:none }
.kbsheet-title{
  font-family:var(--font-display); font-weight:800; font-size:19px;
  letter-spacing:-.02em; color:var(--ink); margin:0 0 1rem;
}
.kbsheet h4{
  font-family:var(--font-mono); font-size:10.5px; font-weight:700;
  text-transform:uppercase; letter-spacing:.08em; color:var(--ink-3);
  margin:1.1rem 0 .5rem;
}
.kbsheet h4:first-of-type{ margin-top:.2rem }
/* One shortcut per row: keycaps left, description right. */
.kbsheet-row{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:.34rem 0; font-size:13px; color:var(--ink-2);
  border-bottom:1px solid #E8ECEC;
}
.kbsheet-row:last-child{ border-bottom:none }
.kbsheet-row>span:first-child{ display:inline-flex; gap:.3rem; flex:none }
.kbsheet-row>span:last-child{ text-align:right }
/* Close button (×) — top-right of the panel. */
.kbsheet-x{
  position:absolute; top:.7rem; right:.8rem;
  width:32px; height:32px; display:grid; place-items:center;
  font-size:22px; line-height:1; color:var(--ink-3); cursor:pointer;
  background:transparent; border:none; border-radius:999px; transition:.16s var(--ease);
}
.kbsheet-x:hover{ color:var(--ink); background:var(--accent-subtle) }

@keyframes kb-fade{ from{ opacity:0 } to{ opacity:1 } }
@keyframes kb-pop{ from{ opacity:0; transform:translateY(8px) scale(.97) } to{ opacity:1; transform:none } }

/* Respect reduced-motion: no entrance animation. */
@media (prefers-reduced-motion: reduce){
  .kbsheet-bg,.kbsheet{ animation:none }
}

/* ════════════════ COMMAND PALETTE (⌘K) — purely additive ════════════════
   Expert-path command launcher (Linear/Stripe/Notion). Built by app.js and
   appended to <body>. Generic cmdk- prefix → no collision with ap-/rp-/wz-/
   kbsheet-. All colours via theme tokens, so light & dark are both correct. */

/* Backdrop — dims the page, anchors the panel near top-centre. */
.cmdk-bg{
  position:fixed; inset:0; z-index:140;
  display:flex; justify-content:center; align-items:flex-start;
  padding:12vh 1.4rem 1.4rem;
  background:rgba(16,28,22,.34);
  backdrop-filter:blur(2px);
  animation:cmdk-fade var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both;
}
.cmdk-bg[hidden]{ display:none }

/* The panel — ~560px, calm scale/fade entrance. */
.cmdk{
  width:min(560px,100%); max-height:70vh; display:flex; flex-direction:column;
  background:var(--panel); color:var(--ink);
  border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-lg); overflow:hidden;
  animation:cmdk-pop var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both;
}

/* Borderless large search field. */
.cmdk-input{
  width:100%; box-sizing:border-box; border:none; outline:none; background:transparent;
  font-family:var(--font-body); font-size:17px; color:var(--ink);
  padding:1.05rem 1.25rem; border-bottom:1px solid var(--line);
}
.cmdk-input::placeholder{ color:var(--ink-3) }
.cmdk-input:focus{ outline:none; border-color:var(--line); box-shadow:none }

/* Scrollable list of options. */
.cmdk-list{
  list-style:none; margin:0; padding:.4rem; overflow-y:auto;
}
.cmdk-opt{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:.6rem .85rem; border-radius:var(--radius-sm);
  font-size:14px; color:var(--ink); cursor:pointer; user-select:none;
}
.cmdk-opt-label{ font-weight:600 }
.cmdk-opt-hint{ font-size:12px; color:var(--ink-3); font-weight:600; flex:none }
.cmdk-opt[aria-selected="true"],
.cmdk-opt:hover{ background:var(--accent-subtle) }
.cmdk-opt[aria-selected="true"] .cmdk-opt-hint{ color:var(--accent) }
.cmdk-empty{
  list-style:none; padding:1.4rem .85rem; text-align:center;
  font-size:13px; color:var(--ink-3);
}

@keyframes cmdk-fade{ from{ opacity:0 } to{ opacity:1 } }
@keyframes cmdk-pop{ from{ opacity:0; transform:translateY(-8px) scale(.97) } to{ opacity:1; transform:none } }

/* Respect reduced-motion: no entrance animation. */
@media (prefers-reduced-motion: reduce){
  .cmdk-bg,.cmdk{ animation:none }
}

/* ════════════════ INFO-TOOLTIP COMPONENT (purely additive) ════════════════
   Reduces cognitive load by explaining Finnish VAT/accounting jargon inline
   (Nielsen #6 recognition-over-recall, #10 help & documentation).
   Reusable pattern:
     <button type="button" class="tip" aria-label="Selitys">
       ⓘ<span class="tip-bub" role="tooltip">…</span>
     </button>
   The bubble is hidden by default and revealed on hover, keyboard focus
   (:focus-visible), and :focus-within — so it is fully keyboard-reachable:
   Tab to the ⓘ shows it; blur (Tab away / Esc-driven blur) hides it.
   Token-driven → correct in light + dark. Respects prefers-reduced-motion.
   ───────────────────────────────────────────────────────────────────────── */

/* The ⓘ trigger — small, subtle, circular muted glyph. type="button" so it
   never submits a form. Inline so it sits next to label text without breaking
   table cells / right-alignment (the glyph is in the LEFT/label cell only). */
.tip{
  position:relative; display:inline-flex; align-items:center; justify-content:center;
  width:16px; height:16px; margin-left:.34em; padding:0; flex:none;
  vertical-align:middle; font-family:var(--font-body); font-size:11px; font-weight:700;
  line-height:1; color:var(--ink-3); background:transparent;
  border:1px solid var(--line-2); border-radius:999px;
  cursor:help; transition:color .16s var(--ease), border-color .16s var(--ease), background .16s var(--ease);
}
.tip:hover,
.tip:focus-visible{ color:var(--accent); border-color:var(--accent); background:var(--accent-subtle) }

/* The popover bubble — hidden until the trigger is hovered/focused. Uses panel
   tokens so it is dark-on-light in light mode and light-on-dark in dark mode. */
.tip .tip-bub{
  position:absolute; left:50%; bottom:calc(100% + 9px); transform:translateX(-50%) translateY(4px);
  z-index:80; width:max-content; max-width:240px;
  padding:.55rem .7rem; text-align:left;
  font-family:var(--font-body); font-size:12px; font-weight:500; line-height:1.45;
  color:var(--ink); background:var(--panel);
  border:1px solid var(--line); border-radius:var(--radius-sm);
  box-shadow:var(--shadow-lg);
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .16s var(--ease), transform .16s var(--ease), visibility 0s linear .16s;
}
/* Little arrow under the bubble, pointing at the ⓘ. */
.tip .tip-bub::after{
  content:""; position:absolute; top:100%; left:50%; transform:translateX(-50%);
  border:6px solid transparent; border-top-color:var(--panel);
  /* a faint border-coloured backing arrow for the 1px outline */
  filter:drop-shadow(0 1px 0 var(--line));
}
/* Reveal on hover / keyboard focus / focus inside the trigger. */
.tip:hover .tip-bub,
.tip:focus-visible .tip-bub,
.tip:focus-within .tip-bub{
  opacity:1; visibility:visible; transform:translateX(-50%) translateY(0);
  transition:opacity .16s var(--ease), transform .16s var(--ease), visibility 0s;
}

/* If the bubble would clip off the top (near a card top edge), authors can add
   .tip-bub.below to flip it under the glyph — supported but optional. */
.tip .tip-bub.below{ top:calc(100% + 9px); bottom:auto; transform:translateX(-50%) translateY(-4px) }
.tip .tip-bub.below::after{ top:auto; bottom:100%; border-top-color:transparent; border-bottom-color:var(--panel); filter:drop-shadow(0 -1px 0 var(--line)) }
.tip:hover .tip-bub.below,
.tip:focus-visible .tip-bub.below,
.tip:focus-within .tip-bub.below{ transform:translateX(-50%) translateY(0) }

/* Reduced-motion: no fade/slide — bubble simply toggles visibility. */
@media (prefers-reduced-motion: reduce){
  .tip .tip-bub{ transition:none }
  .tip:hover .tip-bub,
  .tip:focus-visible .tip-bub,
  .tip:focus-within .tip-bub{ transition:none }
}

/* ════════════════════════════════════════════════════════════════════════════
   DARK MODE — opt-in, token-driven "Nordic fintech" palette (strictly additive)
   ════════════════════════════════════════════════════════════════════════════
   Activated only when <html data-theme="dark"> (set early by app.js from
   localStorage; default is LIGHT). Light mode (no attr / data-theme="light")
   is byte-for-byte unchanged — nothing below this banner touches it.

   Two parts:
     A. Redefine EVERY :root token for dark with verified WCAG 2.2 AA contrast.
     B. Override the hardcoded light literals that live in component rules above
        AND in the per-page <style> blocks. Because [data-theme="dark"] is an
        attribute selector, its specificity (0,1,x) beats the page rules' plain
        class selectors (0,1,0) / element rules even though page <style> loads
        AFTER theme.css — so these overrides win without !important.

   Key contrast ratios (computed; foreground vs the stated dark surface):
     --ink   #E8EDF5 on --panel #161D2B ......... 14.35:1  (AAA)
     --ink-2 #AEB9CC on --panel ................. 8.52:1   (AAA)
     --ink-3 #8A96AC on --panel ................. 5.65:1   (AA; on --bg 6.18, on --panel-2 5.27)
     --accent#5BA0FF on --panel ................. 6.36:1   (AA; on --panel-2 5.93)
     --pos   #3FD08A on --panel ................. 8.52:1   ; pos badge text on pos-bg 6.17:1
     --warn  #F2A33C on --panel ................. 8.10:1   ; warn badge text on warn-bg 5.75:1
     --neg   #FF7A66 on --panel ................. 6.61:1   ; neg badge text on neg-bg 5.16:1
     --gold  #E0A94A on --panel ................. 7.99:1   (AAA)
     accent text on --accent-subtle ............. 4.86:1   (AA)
     #fff on --accent-grad endpoints (#1A56BF→#2563D6) 6.71:1 / 5.48:1 (AA — pills stay legible)
   ════════════════════════════════════════════════════════════════════════════ */

/* ── A. Dark token set — redefine every token, same names, dark values ── */
:root[data-theme="dark"]{
  color-scheme:dark; /* native controls follow the app's dark theme too */
  /* Deep Teal-Ink — dark counterpart: cool near-black ground, one lighter-teal
     accent (raised luminance for ≥4.5:1 on the dark panel), --pos stays green. */
  --bg:#0D1416; --bg-2:#141B1D;
  --ink:#EEF2F1; --ink-2:#A6B4B2; --ink-3:#7C8A88;
  --line:#203031; --line-2:#33474A;
  --panel:#141C1E; --panel-2:#1A2426;
  --accent:#42B8C0; --accent-2:#5FCED4; --accent-grad:#42B8C0; /* flat teal — no gradient */
  /* ink-on-fill: 6.58 / 7.84 / 6.66 against the dark theme's lighter tokens */
  --on-accent:#06282A; --on-pos:#042A1B; --on-neg:#3A0C05; --on-warn:#3A2200;
  --accent-subtle:rgba(66,184,192,.16);
  --brand:#42B8C0;            /* = dark --accent (var(--brand,#0BA15D) callers) */
  --actor-agent:#B7A0FF;      /* agent purple, lightened for ≥4.5:1 on dark --panel */
  --gold:#E0A94A;
  --pos:#3FD08A; --pos-bg:rgba(63,208,138,.16);
  --warn:#F2A33C; --warn-bg:rgba(242,163,60,.18);
  --neg:#FF7A66; --neg-bg:rgba(255,122,102,.16);
  /* shadows: darker + deeper, layered like light mode but on a dark canvas */
  --shadow-xs:0 1px 1.5px rgba(0,0,0,.5);
  --shadow-sm:0 1px 2px rgba(0,0,0,.5),0 1px 1px rgba(0,0,0,.4);
  --shadow:0 1px 2px rgba(0,0,0,.5),0 6px 16px -4px rgba(0,0,0,.5),0 16px 36px -10px rgba(0,0,0,.55);
  --shadow-lg:0 4px 8px rgba(0,0,0,.5),0 18px 40px -10px rgba(0,0,0,.6),0 36px 70px -18px rgba(0,0,0,.7);
  --accent-shadow:0 4px 14px -2px rgba(0,0,0,.55);
}

/* Quick, calm colour cross-fade on theme flip (skip under reduced-motion). */
@media (prefers-reduced-motion: no-preference){
  :root[data-theme] body{ transition:background-color .25s var(--ease), color .25s var(--ease) }
}

/* ── B. Override hardcoded light literals under dark ── */

/* body radial-gradient (was tuned for the light --bg) → dark glows over dark --bg */
[data-theme="dark"] body{
  background:
    radial-gradient(60vmax 44vmax at 88% -12%, rgba(66,184,192,.09), transparent 62%),
    var(--bg);
}
[data-theme="dark"] ::selection{ background:rgba(66,184,192,.28) }

/* scrollbar thumbs (#C7CFCF / #B3BCBC) → dark track-friendly */
[data-theme="dark"] ::-webkit-scrollbar-thumb{ background:#2C3A33 }
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover{ background:#3A4A40 }

/* appbar backdrop rgba(255,255,255,.82) → translucent dark panel */
[data-theme="dark"] .appbar{ background:rgba(14,20,32,.94) }

/* segmented .tabs container #ECEFEF → dark panel-2 */
[data-theme="dark"] .tabs{ background:var(--panel-2) }

/* company switcher select #fff → dark panel-2 */
[data-theme="dark"] .company-pick select{ background:var(--panel-2) }

/* surfaces & controls that hardcode #fff in component rules above */
[data-theme="dark"] .item,
[data-theme="dark"] .btn,
[data-theme="dark"] input[type=text],
[data-theme="dark"] input:not([type]),
[data-theme="dark"] input[type=email],
[data-theme="dark"] textarea,
[data-theme="dark"] select.in,
[data-theme="dark"] .field select,
[data-theme="dark"] .card select:not(.company-pick select),
[data-theme="dark"] input[type=file]::file-selector-button{ background:var(--panel-2) }
/* …but that rule has the SAME specificity as .btn.primary and comes later, so it was
   winning: the primary CTA computed to --panel-2, byte-identical to the secondary
   buttons beside it ("+ Uusi lasku" was the LEAST prominent button in its own row).
   Restore the accent, and use the token for its foreground. */
[data-theme="dark"] .btn.primary{ background:var(--accent-grad); color:var(--on-accent) }

/* badges that hardcode #ECEFEF */
[data-theme="dark"] .badge.card11,
[data-theme="dark"] .badge.dir{ background:var(--panel-2); color:var(--ink-2) }

/* ledger table row borders #E8ECEC (global) */
[data-theme="dark"] table.ledger td{ border-bottom-color:var(--line) }

/* command-palette backdrop — deepen like other dark drawers (was rgba(16,28,22,.34)) */
[data-theme="dark"] .cmdk-bg{ background:rgba(0,0,0,.55) }

/* keycap chip + its inset highlight (#F3F6F6 base, inset #fff) */
[data-theme="dark"] .kbd{
  background:var(--panel-2); color:var(--ink-2);
  box-shadow:0 1px 0 var(--line), inset 0 1px 0 rgba(255,255,255,.04);
}

/* skeleton shimmer base (#ECEFEF / #F3F6F6) → dark shimmer */
[data-theme="dark"] .skeleton{
  background:linear-gradient(100deg, #1C2433 30%, #28324A 50%, #1C2433 70%);
  background-size:200% 100%;
}
@media (prefers-reduced-motion: reduce){
  [data-theme="dark"] .skeleton{ background:#1C2433 }
}

/* ── Page-scoped: approve.html (.ap-* / .acpop / .dr-* / .cfm-*) ── */
[data-theme="dark"] .ap-bar{ background:var(--bg) }                          /* opaque: sticky bar must not bleed scrolled rows */
[data-theme="dark"] .ap-seg{ background:var(--panel-2) }                     /* was #ECEFEF */
[data-theme="dark"] .ap-seg button:not(.on) .c{ background:var(--bg); color:var(--ink-3) } /* count pill was #fff */
[data-theme="dark"] .ap-tblwrap{ background:var(--panel) }                   /* was #fff */
[data-theme="dark"] .ap-tbl tbody td{ border-bottom-color:var(--line) }      /* was #E8ECEC */
[data-theme="dark"] .ap-tbl tbody tr.sel{ background:rgba(66,184,192,.10) }  /* teal-tinted selected row */
[data-theme="dark"] .ap-accin,
[data-theme="dark"] .ap-vatsel{ background:var(--panel-2); color:var(--ink) }/* inputs were #fff */
[data-theme="dark"] .acpop{ background:var(--panel) }                        /* popover was #fff */
[data-theme="dark"] .acpop .acgrp{ background:var(--panel) }                 /* sticky group header was #fff */
[data-theme="dark"] .ap-filters{ background:var(--panel) }                   /* filter bar was #fff */
[data-theme="dark"] .ap-filters input,
[data-theme="dark"] .ap-filters select{ background:var(--panel-2); color:var(--ink) } /* were #fff */
[data-theme="dark"] .ap-drawer-bg{ background:rgba(0,0,0,.55) }              /* was rgba(20,30,50,.34) */
[data-theme="dark"] .ap-drawer{ background:var(--panel) }                    /* was #fff */
[data-theme="dark"] .ap-cfm-bg{ background:rgba(0,0,0,.55) }                 /* was rgba(20,30,50,.34) */
[data-theme="dark"] .ap-cfm{ background:var(--panel) }                       /* was #fff */
/* .ap-bulk pill already uses --ink as bg + #fff text → on dark, --ink is light,
   which would invert it. Keep it a sensible DARK pill: dark surface, light text. */
[data-theme="dark"] .ap-bulk{ background:#202A3D; color:var(--ink); border:1px solid var(--line) }
[data-theme="dark"] .ap-bulk .sep{ background:rgba(255,255,255,.14) }
[data-theme="dark"] .ap-bulk input{ background:var(--panel-2); color:var(--ink) }
[data-theme="dark"] .ap-bulk .btn.ghost{ color:var(--accent-2) }            /* was #cfe0ff */
[data-theme="dark"] .ap-bulk .btn.ghost:hover{ background:rgba(255,255,255,.10) }

/* ── Row-density: Compact mode (approve table) — strictly additive ──────────────
   Comfortable (default) is unchanged. `density-compact` lives on <body>, so it
   survives render()'s table rebuilds. Scoped to .ap-tbl so nothing else shifts.
   Uses tokens only → correct in light + dark. Keeps controls tappable. */
.density-compact .ap-tbl tbody td{ padding:.34rem .7rem }
.density-compact .ap-tbl tbody td.chk{ padding-left:.85rem }   /* keep checkbox column gutter */
.density-compact .ap-meta{ font-size:11px; margin-top:.05rem; gap:.35rem }
.density-compact .ap-split,
.density-compact .ap-accnm{ margin-top:.1rem; font-size:10.5px }
.density-compact .ap-accin{ padding:.26rem .45rem }
.density-compact .ap-vatsel{ padding:.22rem .35rem }
.density-compact .ap-tbl tbody .btn.sm{ padding:.3rem .65rem }
/* Calm switch between densities (respect reduced-motion). */
@media (prefers-reduced-motion: no-preference){
  .ap-tbl tbody td,
  .ap-meta, .ap-split, .ap-accnm, .ap-accin, .ap-vatsel{
    transition:padding var(--dur,200ms) var(--ease), font-size var(--dur,200ms) var(--ease), margin-top var(--dur,200ms) var(--ease);
  }
}

/* ── Page-scoped: reports.html (.rp-*) ── */
[data-theme="dark"] .rp-seg{ background:var(--panel-2) }                     /* was #ECEFEF */
[data-theme="dark"] table.rp-tbl td{ border-bottom-color:var(--line) }      /* was #E8ECEC */
/* trend bar "selected/deeper" shades #d57b16 / #13a06a → keep warm/green but readable */
[data-theme="dark"] .rp-hero.pay::before{ background:linear-gradient(180deg,var(--warn),#C77E25) }
[data-theme="dark"] .rp-hero.ref::before{ background:linear-gradient(180deg,var(--pos),#2FA876) }
[data-theme="dark"] .rp-bar.on.pay .fill{ background:#C77E25 }
[data-theme="dark"] .rp-bar.on.ref .fill{ background:#2FA876 }

/* ── Page-scoped: index.html (.wz-*) ── */
[data-theme="dark"] .wz-dots .node{ background:var(--panel-2); border-color:var(--line-2) } /* was #fff / #DCE2E2 */
[data-theme="dark"] .wz-prog-bar{ background:var(--panel-2) }               /* was #E7EBEB */
[data-theme="dark"] .wz-drop .ic{ background:var(--panel-2) }               /* was #fff */
[data-theme="dark"] .wz-arrow{ background:var(--panel-2) }                  /* was #fff */
[data-theme="dark"] .wz-kbd{ background:var(--panel-2) }                    /* was #ECEFEF */

/* ════════════════════════════════════════════════════════════════════════════
   RESPONSIVE MOBILE NAV (strictly additive) — hamburger + slide-down menu
   ════════════════════════════════════════════════════════════════════════════
   Desktop (≥1280px): .navtoggle hidden, .tabs + .appbar-right inline as today —
   nothing changes. Below 1280px: the .tabs pill row is hidden and replaced by
   a hamburger button that reveals .navmenu, a token-driven slide-down sheet that
   holds the nav links (vertical, ≥44px tap targets) plus — moved in by app.js
   while open — the company picker + theme toggle + account actions, so every
   control is reachable. Light/dark safe; calm fade/slide disabled under
   prefers-reduced-motion; keyboard-accessible (focusable button, focus ring,
   Esc/outside-click close handled in JS). */
.navtoggle{
  display:none; /* shown only ≤860px */
  width:40px; height:40px; flex:none; margin-left:.2rem;
  align-items:center; justify-content:center;
  border-radius:var(--radius-sm); border:1px solid var(--line-2);
  background:var(--panel); color:var(--ink); cursor:pointer;
  transition:.16s var(--ease);
}
.navtoggle:hover{ border-color:var(--accent); color:var(--accent) }
.navtoggle:active{ transform:scale(.96) }
.navtoggle-bars{ display:inline-grid; gap:4px; width:18px }
.navtoggle-bars span{ display:block; height:2px; border-radius:2px; background:currentColor; transition:.18s var(--ease) }
.navtoggle[aria-expanded="true"] .navtoggle-bars span:nth-child(1){ transform:translateY(6px) rotate(45deg) }
.navtoggle[aria-expanded="true"] .navtoggle-bars span:nth-child(2){ opacity:0 }
.navtoggle[aria-expanded="true"] .navtoggle-bars span:nth-child(3){ transform:translateY(-6px) rotate(-45deg) }

/* The slide-down panel. Lives below the sticky bar (top:60px), high z-index so
   it sits above page content; full-width; scrolls if it overflows the viewport. */
.navmenu{
  display:none; /* shown only ≤860px (and not [hidden]) */
  position:fixed; top:60px; left:0; right:0; z-index:29;
  max-height:calc(100vh - 60px); overflow-y:auto;
  padding:.7rem 1rem 1.1rem;
  background:var(--panel); border-bottom:1px solid var(--line);
  box-shadow:var(--shadow-lg);
  opacity:0; transform:translateY(-8px);
  transition:opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}
.navmenu.open{ opacity:1; transform:translateY(0) }
.navmenu-tabs{ display:flex; flex-direction:column; gap:.2rem }
.navmenu-tabs a{
  display:flex; align-items:center; min-height:46px; padding:.55rem .85rem;
  border-radius:var(--radius-sm); color:var(--ink-2); text-decoration:none;
  font-weight:600; font-size:15px; transition:.16s var(--ease);
}
.navmenu-tabs a:hover{ background:var(--accent-subtle); color:var(--ink) }
.navmenu-tabs a.active{ color:var(--on-accent); background:var(--accent-grad) }
.navmenu-extra{ margin-top:.7rem; padding-top:.7rem; border-top:1px solid var(--line) }
.navmenu-extra:empty{ display:none }
/* The moved-in app-bar controls stack vertically and go full-width on mobile. */
.navmenu-extra .appbar-right{ display:flex; flex-direction:column; align-items:stretch; gap:.7rem }
.navmenu-extra .company-pick{ flex-wrap:wrap; gap:.5rem }
.navmenu-extra .company-pick select{ width:100%; min-width:0; max-width:none; flex:1 }
.navmenu-extra .company-pick.acct{ align-items:center; justify-content:flex-start; gap:.7rem }
/* In the mobile sheet the account menu is shown EXPANDED (no gear/collapse) so
   Asetukset + theme + email + logout are all directly reachable — not hidden one
   tap deep in an absolutely-positioned dropdown. */
.navmenu-extra .acctmenu{ width:100% }
.navmenu-extra .acctmenu .navgroup-btn{ display:none }
.navmenu-extra .acctmenu .navdropdown{ position:static; right:auto; opacity:1; visibility:visible;
  transform:none; box-shadow:none; border:none; padding:0; min-width:0; background:transparent }
.navmenu-extra .acctmenu .navdropdown a{ padding:.7rem .2rem; font-size:14px }
.navmenu-extra .acctmenu .acctmenu-email{ padding:.6rem .2rem; max-width:none }

@media (prefers-reduced-motion: reduce){
  .navmenu{ transition:none; transform:none }
  .navtoggle-bars span{ transition:none }
}

@media (max-width:1279px){
  .appbar{ gap:.8rem; padding:0 1rem }
  .tabs{ display:none }              /* desktop pill nav hidden below the laptop breakpoint */
  .navtoggle{ display:inline-flex }  /* hamburger appears */
  .navmenu{ display:block }          /* panel participates when shown… */
  .navmenu[hidden]{ display:none }   /* …but the [hidden] attr still hides it when closed */
  /* The picker/account block lives in the menu on mobile, not the bar. */
  .appbar > .appbar-right{ display:none }
}

/* Belt-and-braces: never show the toggle at/above the desktop breakpoint. */
@media (min-width:1280px){
  .navtoggle{ display:none }
  .navmenu{ display:none }
}

/* Dark mode: panel + toggle sit on the dark surface. */
[data-theme="dark"] .navtoggle{ background:var(--panel-2); border-color:var(--line-2) }
[data-theme="dark"] .navmenu{ background:var(--panel); border-bottom-color:var(--line) }
[data-theme="dark"] .navmenu-extra{ border-top-color:var(--line) }

/* ════════════════════════════════════════════════════════════════════════════
   PRINT / PDF LAYER — clean ink-on-paper document (strictly additive)
   ════════════════════════════════════════════════════════════════════════════
   Accountants print or save-to-PDF the ALV report for tax filing / records, so
   it must render as a crisp black-on-white document with all app chrome removed.
   Screen appearance is untouched — every rule below lives inside @media print.

   - Force a light palette even when data-theme="dark" (override the core tokens
     to ink-on-paper values) so a PDF saved in dark mode still prints clean.
   - Hide non-document chrome (appbar, skip link, theme toggle, toasts, the
     keyboard-shortcuts sheet, fixed bars).
   - Flatten shadows / heavy rounded cards to thin borders so it prints sharp.
   - Sane page margin; let content flow (no overflow clipping); avoid awkward
     breaks inside rows / cards.
   ──────────────────────────────────────────────────────────────────────────── */
@media print{
  /* Light, ink-on-paper tokens REGARDLESS of dark mode. */
  :root, :root[data-theme="dark"]{
    --bg:#fff; --bg-2:#fff;
    --panel:#fff; --panel-2:#fff;
    --ink:#000; --ink-2:#222; --ink-3:#444;
    --line:#ccc; --line-2:#999;
    --accent:#000; --accent-2:#000; --accent-subtle:transparent;
    --shadow-sm:none; --shadow:none; --shadow-lg:none;
  }
  @page{ margin:18mm }
  html,body{ background:#fff !important; color:#000 }
  /* No background gradients/glows on paper. */
  body,
  [data-theme="dark"] body{ background:#fff !important; background-image:none !important }

  /* Hide non-document chrome + interactive/fixed bars. */
  .appbar, .skip-link, .toast,
  .kbsheet-bg, .kbsheet,
  .cmdk-bg, .cmdk,
  .ap-bar, .ap-bulk, .ap-filters{ display:none !important }

  /* Flatten cards/panels: thin borders, no shadow, no heavy radius. */
  .card, .col, .rp-hero, .rp-card, .rp-trend{
    box-shadow:none !important;
    border:1px solid var(--line) !important;
    border-radius:0 !important;
  }
  /* Allow content to flow rather than be clipped on paper. */
  .card, .col, .col .body, .rp-hero, .rp-card{ overflow:visible !important }

  /* Remove decorative glows / colour bars that don't belong on paper. */
  .rp-hero .glow, .rp-hero::before{ display:none !important }

  /* Avoid awkward page breaks. */
  tr, .card, .rp-card, .rp-hero{ break-inside:avoid }

  /* Crisp ink on white for backgrounds-as-ink elements. */
  *{ -webkit-print-color-adjust:exact; print-color-adjust:exact }
}

/* ── Shared AI-suggestion confidence chip + rationale (app.js confidenceChip) ──
   Surfaces the "why" + confidence the backend computes (AI-native: human sees the
   evidence before approving — vastuukysymys). Tiers use the existing pos/warn/ink
   tokens so light + dark both stay WCAG-correct without new colours.
     high (≥.8) → green  | med (≥.5) → amber | low/unknown → grey  */
.conf-chip{display:inline-flex;align-items:center;gap:.4rem;padding:.12rem .5rem;
  border-radius:999px;font-size:11.5px;font-weight:600;line-height:1.5;white-space:nowrap;
  border:1px solid transparent;vertical-align:middle}
.conf-chip .conf-dot{width:7px;height:7px;border-radius:50%;flex:none}
.conf-chip.high{color:var(--pos);background:var(--pos-bg);border-color:color-mix(in srgb,var(--pos) 28%,transparent)}
.conf-chip.high .conf-dot{background:var(--pos)}
.conf-chip.med{color:var(--warn);background:var(--warn-bg);border-color:color-mix(in srgb,var(--warn) 28%,transparent)}
.conf-chip.med .conf-dot{background:var(--warn)}
.conf-chip.low{color:var(--ink-3);background:rgba(100,111,130,.12);border-color:var(--line-2)}
.conf-chip.low .conf-dot{background:var(--ink-3)}
/* One-line rationale shown next to the chip; truncates so rows stay tidy. */
.why-line{display:inline-block;max-width:46ch;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;vertical-align:middle;margin-left:.5rem;font-size:12px;color:var(--ink-3)}

/* ── Shared legal-basis accordion items (app.js renderLegalBasis) ── */
.lb-item{margin:.45rem 0;padding-left:.6rem;border-left:2px solid var(--line);
  font-size:12.5px;color:var(--ink-2);line-height:1.5}
.lb-item b{color:var(--ink)}
.lb-item a{color:var(--accent);text-decoration:none}
.lb-item a:hover{text-decoration:underline}

/* ── Floating Avustaja (AI assistant) widget — app-wide FAB + non-modal panel ── */
.asst-fab{position:fixed;right:1.1rem;bottom:1.1rem;z-index:1200;width:54px;height:54px;border-radius:50%;border:none;cursor:pointer;background:var(--accent-grad,var(--accent));color:var(--on-accent);font-size:22px;box-shadow:0 6px 20px rgba(0,0,0,.22);display:flex;align-items:center;justify-content:center;transition:transform .12s}
.asst-fab:hover{transform:scale(1.06)}
.asst-fab:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.asst-panel{position:fixed;right:1.1rem;bottom:5rem;z-index:1200;width:380px;max-width:calc(100vw - 2rem);height:min(70vh,560px);display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:16px;box-shadow:0 18px 50px rgba(0,0,0,.30);overflow:hidden}
.asst-panel[hidden]{display:none}
.asst-head{display:flex;align-items:center;justify-content:space-between;padding:.7rem .9rem;border-bottom:1px solid var(--line)}
.asst-title{font-family:var(--font-display);font-weight:800;font-size:15px;color:var(--ink);margin-right:auto}
/* Header controls clustered right, each a real ≥30px tap target (WCAG 2.5.8). */
.asst-actions{display:flex;align-items:center;gap:.15rem}
.asst-icon{background:none;border:none;color:var(--ink-3);font-size:15px;cursor:pointer;line-height:1;
  width:30px;height:30px;display:grid;place-items:center;border-radius:8px;padding:0;transition:.14s var(--ease)}
.asst-icon:hover{color:var(--ink);background:var(--accent-subtle)}
.asst-icon:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.asst-icon-close:hover{color:var(--neg);background:var(--neg-bg)}
/* keep the legacy .asst-close alias working if referenced elsewhere */
.asst-close{background:none;border:none;color:var(--ink-3);font-size:16px;cursor:pointer;line-height:1;padding:.2rem}
.asst-close:hover{color:var(--ink)}
.asst-log{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:.7rem;padding:.9rem}
.asst-intro{color:var(--ink-2);font-size:12.5px;line-height:1.5}
.asst-privacy-link{display:inline-block;margin-top:.35rem;color:var(--ink-3);text-decoration:underline;text-underline-offset:2px}
.asst-privacy-link:hover{color:var(--ink-2)}
/* Empty-state starter chips — fill the panel void with one-tap example prompts.
   Quiet by default, teal wash on hover; wrap to a tidy grid. */
.asst-suggest{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.9rem}
.asst-sugg{font-family:var(--font-body);font-size:12.5px;font-weight:600;color:var(--ink-2);
  background:var(--panel-2,var(--bg));border:1px solid var(--line-2);border-radius:999px;
  padding:.4rem .75rem;cursor:pointer;transition:.14s var(--ease);text-align:left;line-height:1.3}
.asst-sugg:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-subtle)}
.asst-sugg:active{transform:scale(.98)}
.asst-sugg:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.asst-meta{font-size:10.5px;color:var(--ink-3);font-family:var(--font-mono,monospace);text-align:right;padding:0 .9rem;min-height:13px}
.asst-bar{display:flex;gap:.5rem;padding:.7rem .9rem;border-top:1px solid var(--line)}
.asst-bar input{flex:1;font-size:13.5px;padding:.6rem .75rem;border:1px solid var(--line);border-radius:11px;background:var(--panel-2,var(--bg));color:var(--ink)}
.asst-bar input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.asst-panel .msg{max-width:88%;padding:.6rem .8rem;border-radius:13px;font-size:13.5px;line-height:1.5;white-space:pre-wrap;word-break:break-word}
.asst-panel .msg.user{align-self:flex-end;background:var(--accent-grad,var(--accent));color:var(--on-accent);border-bottom-right-radius:4px}
.asst-panel .msg.bot{align-self:flex-start;background:var(--bg);border:1px solid var(--line);color:var(--ink);border-bottom-left-radius:4px}
.asst-panel .tool{align-self:flex-start;font-family:var(--font-mono,monospace);font-size:11px;color:var(--ink-3);background:var(--bg);border:1px dashed var(--line);border-radius:9px;padding:.3rem .55rem;word-break:break-word}
/* Designed error card: not a full-width mono log line — a bordered notice on the
   neg tint, with an inline "Yritä uudelleen" resend. */
.asst-panel .tool.err{align-self:flex-start;max-width:92%;display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;
  font-family:var(--font-body);font-size:12.5px;line-height:1.45;color:var(--neg);
  background:var(--neg-bg);border:1px solid color-mix(in srgb,var(--neg) 35%,transparent);border-style:solid}
.asst-retry{font-family:var(--font-body);font-size:12px;font-weight:700;cursor:pointer;
  color:var(--neg);background:transparent;border:1px solid color-mix(in srgb,var(--neg) 40%,transparent);
  border-radius:999px;padding:.22rem .6rem;transition:.14s var(--ease)}
.asst-retry:hover{background:color-mix(in srgb,var(--neg) 12%,transparent)}
.asst-retry:focus-visible{outline:2px solid var(--neg);outline-offset:1px}
/* Send button becomes a Stop while a turn streams (feedback + cost-safety). */
.asst-panel .btn.asst-stop{background:var(--panel-2,var(--bg));color:var(--ink-2);border:1px solid var(--line-2);box-shadow:none}
.asst-panel .btn.asst-stop:hover{color:var(--neg);border-color:color-mix(in srgb,var(--neg) 40%,transparent);background:var(--neg-bg)}
/* Mobile: the FAB and the panel's Lähetä/Keskeytä button both live in the thumb
   zone — hide the FAB while the panel is open so they don't compete. */
@media(max-width:560px){ body.asst-open .asst-fab{display:none} }
.asst-panel .staged{align-self:flex-start;max-width:90%;background:var(--warn-bg,rgba(230,160,20,.12));border:1px solid var(--line);border-radius:13px;padding:.6rem .8rem}
.asst-panel .staged-h{display:flex;gap:.35rem;font-size:12.5px;font-weight:700;color:var(--warn,#b8860b);margin:0 0 .25rem}
.asst-panel .staged-args{font-family:var(--font-mono,monospace);font-size:11.5px;color:var(--ink-2);word-break:break-word;margin:0 0 .5rem}
.asst-panel .staged-tool{color:var(--ink);font-weight:700}
/* S1/D6b: always-visible "Muisti päivittyi" chip on remember/forget — sibling of
   the turn (never inside the collapsed work disclosure) so a memory write/removal
   is never hidden from the human. */
.asst-panel .asst-mem-chip{align-self:flex-start;max-width:90%;background:var(--pos-bg);border:1px solid var(--line);border-radius:13px;padding:.5rem .75rem;animation:asstFade .2s ease both}
.asst-panel .asst-mem-chip-h{display:flex;align-items:center;gap:.35rem;font-size:12px;font-weight:700;color:var(--pos);margin:0 0 .3rem}
.asst-panel .asst-mem-chip-h .ic{width:14px;height:14px}
.asst-panel .asst-mem-chip-note{font-size:12px;line-height:1.45;color:var(--ink-2);word-break:break-word}
.asst-panel .asst-mem-chip-note+.asst-mem-chip-note{margin-top:.2rem}
.asst-panel .asst-mem-chip-note b{color:var(--ink)}
/* Legal neuvonta (Phase 6): research progress · sources panel · refuse state */
.asst-panel .asst-progress{align-self:stretch;display:flex;flex-direction:column;gap:.25rem;padding:.5rem .65rem;background:var(--bg);border:1px solid var(--line);border-radius:11px;transition:opacity .3s}
.asst-panel .asst-progress.collapsed{opacity:.5}
.asst-panel .asst-pline{display:flex;align-items:center;gap:.45rem;font-size:11.5px;color:var(--ink-2);font-family:var(--font-mono,monospace)}
.asst-panel .asst-pdot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--accent);animation:asstPulse 1s ease-in-out infinite}
.asst-panel .asst-pline.done .asst-pdot{background:var(--pos);animation:none}
.asst-panel .asst-pline.failed .asst-pdot{background:var(--ink-3);animation:none}
.asst-panel .asst-plabel{color:var(--ink);font-weight:700}
.asst-panel .asst-pstate{margin-left:auto;color:var(--ink-3)}
@keyframes asstPulse{0%,100%{opacity:1}50%{opacity:.35}}
.asst-panel .asst-sources{align-self:flex-start;max-width:100%;background:var(--bg);border:1px solid var(--line);border-radius:13px;padding:.6rem .7rem}
.asst-panel .src-h{font-size:11px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3);margin-bottom:.45rem}
.asst-panel .src-chips{display:flex;flex-wrap:wrap;gap:.4rem}
.asst-panel .src-chip{display:inline-flex;align-items:center;max-width:100%;padding:.22rem .55rem;border-radius:9px;font-size:11.5px;font-weight:600;color:var(--accent);background:color-mix(in srgb,var(--accent) 9%,transparent);border:1px solid color-mix(in srgb,var(--accent) 26%,transparent);text-decoration:none;cursor:help;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.asst-panel a.src-chip:hover{background:color-mix(in srgb,var(--accent) 16%,transparent);text-decoration:none}
.asst-panel .src-chip.superseded{color:var(--ink-3);background:rgba(100,111,130,.1);border-color:var(--line-2,var(--line))}
.asst-panel .src-rev{font-size:10px;color:var(--ink-3);margin-top:.45rem;font-family:var(--font-mono,monospace)}
.asst-panel .asst-refuse{align-self:flex-start;max-width:90%;background:var(--warn-bg,rgba(230,160,20,.12));border:1px solid color-mix(in srgb,var(--warn,#b8860b) 35%,transparent);border-radius:13px;padding:.55rem .75rem;font-size:12.5px;line-height:1.45;color:var(--ink-2)}
/* assistant markdown prose — bot messages render mdToHtml() (app.js), so style
   the generated block elements; user messages keep pre-wrap for raw line breaks */
.asst-panel .msg.bot{white-space:normal}
.asst-panel .msg.bot>:first-child{margin-top:0}
.asst-panel .msg.bot>:last-child{margin-bottom:0}
.asst-panel .msg.bot p{margin:.5rem 0}
.asst-panel .msg.bot h4,.asst-panel .msg.bot h5,.asst-panel .msg.bot h6{margin:.75rem 0 .35rem;font-family:var(--font-display,inherit);font-weight:800;line-height:1.25;color:var(--ink)}
.asst-panel .msg.bot h4{font-size:15.5px}
.asst-panel .msg.bot h5{font-size:13.5px}
.asst-panel .msg.bot h6{font-size:12px;color:var(--ink-2);text-transform:uppercase;letter-spacing:.04em}
.asst-panel .msg.bot ul,.asst-panel .msg.bot ol{margin:.45rem 0;padding-left:1.25rem;display:flex;flex-direction:column;gap:.25rem}
.asst-panel .msg.bot li{line-height:1.5}
.asst-panel .msg.bot li::marker{color:var(--accent)}
.asst-panel .msg.bot strong{font-weight:800;color:var(--ink)}
.asst-panel .msg.bot em{font-style:italic}
.asst-panel .msg.bot a{color:var(--accent);text-decoration:underline;text-underline-offset:2px;word-break:break-word}
.asst-panel .msg.bot code{font-family:var(--font-mono,monospace);font-size:.86em;background:color-mix(in srgb,var(--ink) 9%,transparent);padding:.08em .35em;border-radius:5px}
.asst-panel .msg.bot pre{margin:.55rem 0;background:#1c2128;border-radius:10px;padding:.7rem .8rem;overflow-x:auto;position:relative}
.asst-panel .msg.bot pre code{background:none;padding:0;font-size:12px;color:#e6edf3}
.asst-panel .msg.bot pre[data-lang]::before{content:attr(data-lang);position:absolute;top:0;right:0;font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:#8b949e;background:#0d1117;padding:.12rem .5rem;border-radius:0 10px 0 8px}
.asst-panel .msg.bot blockquote{margin:.55rem 0;padding:.35rem .75rem;border-left:3px solid var(--accent);background:color-mix(in srgb,var(--accent) 7%,transparent);color:var(--ink-2);border-radius:0 8px 8px 0}
.asst-panel .msg.bot hr{border:none;border-top:1px solid var(--line);margin:.75rem 0}
/* turn layout: collapsible WORK disclosure (reasoning + tool calls) above the answer */
.asst-panel .asst-turn{align-self:stretch;display:flex;flex-direction:column;gap:.55rem}
.asst-panel .asst-work{border:1px solid var(--line);border-radius:11px;background:var(--bg);overflow:hidden}
.asst-panel .asst-work>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.45rem;padding:.5rem .7rem;font-size:11.5px;font-weight:700;color:var(--ink-2);user-select:none}
.asst-panel .asst-work>summary::-webkit-details-marker{display:none}
.asst-panel .asst-work>summary::after{content:'▾';color:var(--ink-3);transition:transform .15s;font-size:10px}
.asst-panel .asst-work:not([open])>summary::after{transform:rotate(-90deg)}
.asst-panel .asst-work:not([open])>summary{color:var(--ink-3);font-weight:600}
.asst-panel .asst-work-spin{width:9px;height:9px;border-radius:50%;border:2px solid color-mix(in srgb,var(--accent) 30%,transparent);border-top-color:var(--accent);animation:asstSpin .7s linear infinite;flex:none}
.asst-panel .asst-work--done .asst-work-spin{border:none;background:var(--pos,#2e9e6b);animation:none;width:7px;height:7px}
.asst-panel .asst-work-count{margin-left:auto;font-weight:500;color:var(--ink-3)}
@keyframes asstSpin{to{transform:rotate(360deg)}}
.asst-panel .asst-work-body{display:flex;flex-direction:column;gap:.4rem;padding:.45rem .7rem .6rem;border-top:1px solid var(--line)}
.asst-panel .asst-reason{font-size:12px;line-height:1.5;color:var(--ink-3)}
.asst-panel .asst-reason>:first-child{margin-top:0}.asst-panel .asst-reason>:last-child{margin-bottom:0}
.asst-panel .asst-reason h4,.asst-panel .asst-reason h5,.asst-panel .asst-reason h6{font-size:12px;margin:.4rem 0 .2rem;color:var(--ink-2)}
.asst-panel .asst-reason p{margin:.3rem 0}.asst-panel .asst-reason ul,.asst-panel .asst-reason ol{margin:.3rem 0;padding-left:1.1rem}
.asst-panel .asst-tool{font-family:var(--font-mono,monospace);font-size:10.5px;color:var(--ink-3);word-break:break-word;line-height:1.4}
.asst-panel .asst-tool{animation:asstFade .18s ease both}
.asst-panel .asst-tool.run{color:var(--accent)}
.asst-panel .asst-tool.ok{color:var(--ink-2)}
.asst-panel .asst-tool.err{color:#c2410c}
.asst-panel .asst-turn>.msg.bot,.asst-panel .asst-sources{animation:asstFade .2s ease both}
@keyframes asstFade{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:none}}
/* fullscreen mode — a large centered panel (toggle ⤢) */
.asst-panel.asst-panel--full{top:3vh;bottom:3vh;height:94vh;left:50%;right:auto;transform:translateX(-50%);width:min(960px,94vw);max-width:94vw;border-radius:18px}
.asst-panel.asst-panel--full .asst-log{padding:1.3rem clamp(1.3rem,5vw,3rem)}
.asst-panel.asst-panel--full .msg{max-width:92%;font-size:14.5px}
.asst-panel.asst-panel--full .asst-bar{padding:1rem clamp(1.3rem,5vw,3rem)}
@media(max-width:560px){.asst-panel{right:.5rem;left:.5rem;width:auto;bottom:4.5rem;height:72vh}
  .asst-panel.asst-panel--full{inset:2vh 2vw;width:auto;transform:none;height:96vh}}
@media print{.asst-fab,.asst-panel{display:none!important}}

/* ════════════════════════════════════════════════════════════════════════════
   SPATIAL PRIMITIVES — reusable layouts for the page-layout overhaul (additive)
   ════════════════════════════════════════════════════════════════════════════
   Replaces the "one long scroll of inline form + list" with SPATIAL structure:
     • .dialog-*   — accessible add/edit MODAL (app.js openDialog), ARIA APG
                     dialog pattern (role=dialog, aria-modal, focus trap, Esc).
     • .ms / .ms-* — master-detail (list pane ↔ detail pane), stacks ≤720px.
     • .tabs-strip / .tab / .tabpanel — per-record TAB strip (app.js wireTabs),
                     ARIA APG tabs (roving tabindex, Arrow/Home/End).
     • .secnav / .secbody — settings SECTION-NAV (app.js wireSections).
     • .dt         — clean data-TABLE (right-aligned numerics, hover rows).
   All token-driven (--panel/--line/--ink/--accent…) ⇒ correct in light + dark.
   Visual language matches the existing .cmdk/.kbsheet modals + .card surfaces so
   these feel native, not generic. Respects prefers-reduced-motion + print.
   NOTE: the tab strip is named .tabs-strip (NOT .tabs) on purpose — .tabs is the
   app-bar nav pill row; reusing it would collide. Page agents use .tabs-strip.
   ──────────────────────────────────────────────────────────────────────────── */

/* ── 1. DIALOG (openDialog) — centred modal, matches .cmdk/.kbsheet chrome ── */
.dialog-bg{
  position:fixed; inset:0; z-index:150;
  display:grid; place-items:center; padding:1.4rem;
  background:rgba(16,28,22,.34); backdrop-filter:blur(2px);
  animation:cmdk-fade var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both;
}
.dialog-bg[hidden]{ display:none }
.dialog{
  width:min(520px,100%); max-height:88vh; display:flex; flex-direction:column;
  background:var(--panel); color:var(--ink);
  border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-lg); overflow:hidden; position:relative;
  animation:kb-pop var(--dur-enter,280ms) var(--ease-out,cubic-bezier(.16,1,.3,1)) both;
}
.dialog:focus{ outline:none }
.dialog-head{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:1.1rem 1.3rem .9rem; border-bottom:1px solid var(--line);
}
.dialog-title{
  font-family:var(--font-display); font-weight:800; font-size:18px;
  letter-spacing:-.02em; color:var(--ink); margin:0;
}
.dialog-x{
  width:32px; height:32px; flex:none; display:grid; place-items:center;
  font-size:21px; line-height:1; color:var(--ink-3); cursor:pointer;
  background:transparent; border:none; border-radius:999px; transition:.16s var(--ease);
}
.dialog-x:hover{ color:var(--ink); background:var(--accent-subtle) }
/* Scrollable body — holds the caller's bodyHtml (typically .field rows). */
.dialog-body{ padding:1.1rem 1.3rem; overflow-y:auto; flex:1 }
.dialog-body>.field:first-child{ margin-top:0 }
.dialog-body>.field:last-child{ margin-bottom:0 }
/* Sticky footer with the cancel/submit actions. */
.dialog-foot{
  display:flex; align-items:center; justify-content:flex-end; gap:.6rem;
  padding:.9rem 1.3rem 1.1rem; border-top:1px solid var(--line);
  background:var(--panel-2);
}
.dialog-err{
  margin:0 1.3rem; padding:.6rem .8rem; border-radius:var(--radius-sm);
  background:var(--neg-bg); color:var(--neg); font-size:12.5px; font-weight:600;
  border:1px solid color-mix(in srgb,var(--neg) 30%,transparent); display:none;
}
.dialog-err.show{ display:block; margin-bottom:.2rem }
/* confirmDialog body message (aria-describedby target). */
.dlg-msg{ margin:0; color:var(--ink-2); font-size:13.5px; line-height:1.55 }
@media (max-width:560px){
  .dialog{ width:100%; max-height:92vh }
  .dialog-foot{ flex-direction:column-reverse; align-items:stretch }
  .dialog-foot .btn{ width:100%; justify-content:center }
}

/* ── 2. MASTER-DETAIL (.ms) — list pane ↔ detail pane; stacks ≤720px ── */
.ms{
  display:grid; grid-template-columns:minmax(240px,300px) 1fr; gap:1.1rem;
  align-items:start;
}
.ms-list{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow); overflow:hidden; display:flex; flex-direction:column;
  max-height:74vh;
}
.ms-list-head{ padding:.7rem .8rem; border-bottom:1px solid var(--line); background:var(--panel-2) }
.ms-search{ width:100%; font-size:13px }   /* inherits the global input rule */
.ms-items{ overflow-y:auto; padding:.45rem; display:flex; flex-direction:column; gap:.2rem }
/* One selectable row in the list. role=button; .is-sel = current selection. */
.ms-item{
  display:flex; flex-direction:column; gap:.15rem;
  padding:.55rem .7rem; border-radius:var(--radius-sm);
  cursor:pointer; color:var(--ink); border:1px solid transparent;
  transition:.14s var(--ease); text-align:left; background:transparent; font:inherit;
}
.ms-item:hover{ background:var(--accent-subtle) }
.ms-item.is-sel{ background:var(--accent-subtle); border-color:color-mix(in srgb,var(--accent) 30%,transparent) }
.ms-item .ms-item-t{ font-weight:600; font-size:13.5px; color:var(--ink); line-height:1.3 }
.ms-item .ms-item-s{ font-size:12px; color:var(--ink-3); line-height:1.4 }
.ms-item.is-sel .ms-item-t{ color:var(--accent) }
.ms-list-empty{ padding:1.4rem .8rem; text-align:center; color:var(--ink-3); font-size:13px }
/* The detail pane is a normal card the page fills. */
.ms-detail{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow); padding:1.3rem 1.4rem; min-height:200px;
}
.ms-detail-empty{ color:var(--ink-3); font-size:13.5px; display:grid; place-items:center; min-height:200px; text-align:center }
@media (max-width:720px){
  .ms{ grid-template-columns:1fr }
  .ms-list{ max-height:46vh }
}

/* ── 3. TAB STRIP (.tabs-strip, wireTabs) — ARIA APG tabs, per-record ── */
.tabs-strip{
  display:flex; gap:.15rem; padding:.25rem; margin:0 0 1.2rem;
  background:var(--panel-2); border:1px solid var(--line); border-radius:999px;
  width:fit-content; max-width:100%; overflow-x:auto;
}
.tab{
  appearance:none; border:none; cursor:pointer; white-space:nowrap;
  padding:.45rem 1rem; border-radius:999px; font-family:inherit;
  font-weight:600; font-size:13px; color:var(--ink-2); background:transparent;
  transition:.16s var(--ease);
}
.tab:hover{ color:var(--ink) }
.tab[aria-selected="true"]{ color:var(--on-accent); background:var(--accent-grad); box-shadow:var(--accent-shadow) }
.tabpanel{ animation:rise .32s var(--ease) both }
.tabpanel[hidden]{ display:none }
.tabpanel:focus{ outline:none }

/* ── 4. SECTION-NAV (.secnav / .secbody, wireSections) — settings ── */
.secwrap{ display:grid; grid-template-columns:minmax(180px,220px) 1fr; gap:1.4rem; align-items:start }
.secnav{ display:flex; flex-direction:column; gap:.15rem; position:sticky; top:76px }
.secnav-item{
  display:flex; align-items:center; gap:.5rem; text-align:left;
  padding:.55rem .8rem; border-radius:var(--radius-sm); cursor:pointer;
  font-family:inherit; font-weight:600; font-size:13.5px; color:var(--ink-2);
  background:transparent; border:1px solid transparent; border-left:3px solid transparent;
  transition:.14s var(--ease);
}
.secnav-item:hover{ background:var(--accent-subtle); color:var(--ink) }
.secnav-item[aria-current="true"]{
  color:var(--accent); background:var(--accent-subtle);
  border-left-color:var(--accent); font-weight:700;
}
.secbody>[data-section]{ animation:rise .32s var(--ease) both }
.secbody>[data-section][hidden]{ display:none }
@media (max-width:720px){
  .secwrap{ grid-template-columns:1fr }
  .secnav{ position:static; flex-direction:row; flex-wrap:wrap; gap:.3rem;
    background:var(--panel-2); border:1px solid var(--line); border-radius:999px; padding:.25rem }
  .secnav-item{ border-left:none; border-radius:999px; padding:.4rem .85rem; font-size:13px }
  .secnav-item[aria-current="true"]{ color:var(--on-accent); background:var(--accent-grad); border-left:none }
}

/* ── 5. DATA TABLE (.dt) — clean rows, right-aligned numerics, hover ── */
.dt-wrap{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow);
}
/* Horizontal scroll for wide tables ONLY on narrow screens. On desktop the wrap
   must NOT be a scroll container: `overflow-x:auto` forces the browser to compute
   overflow-y as `auto` too, which made the wrap a scroll container and pinned the
   sticky thead to the WRAP (riding page scroll) instead of the viewport — so the
   header didn't stay put and the first row clipped under it. (mirrors mi-tblwrap.) */
@media (max-width:820px){ .dt-wrap{ overflow-x:auto } }
.dt-wrap .dt{ margin:0 }
table.dt{ width:100%; border-collapse:collapse; font-size:13px }
table.dt thead th{
  text-align:left; font-family:var(--font-mono); font-size:10.5px;
  text-transform:uppercase; letter-spacing:.05em; color:var(--ink-3); font-weight:700;
  padding:.72rem .95rem; border-bottom:1px solid var(--line-2); background:var(--panel-2);
  position:sticky; top:0; z-index:1; white-space:nowrap;
}
table.dt tbody td{
  padding:.66rem .95rem; border-bottom:1px solid var(--line); color:var(--ink);
  vertical-align:middle;
}
table.dt tbody tr:last-child td{ border-bottom:none }
table.dt tbody tr{ transition:background .14s var(--ease) }
table.dt tbody tr:hover{ background:var(--accent-subtle) }
/* Right-aligned tabular numerics — add class="n" to the cell (th + td). */
table.dt th.n, table.dt td.n{ text-align:right; font-family:var(--font-mono);
  font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1; white-space:nowrap }
/* Clickable rows (master-detail in a table). */
table.dt tbody tr.is-clickable{ cursor:pointer }
table.dt tbody tr.is-sel{ background:var(--accent-subtle) }
table.dt tbody tr.is-sel td:first-child{ box-shadow:inset 3px 0 0 var(--accent) }
/* Sortable headers (window.makeSortable). Header text becomes a button; the
   sort indicator is driven entirely by aria-sort so it can't drift out of sync. */
table.dt th .dt-sort{ background:none; border:0; padding:0; margin:0; font:inherit; color:inherit;
  letter-spacing:inherit; text-transform:inherit; cursor:pointer; display:inline-flex;
  align-items:center; gap:.35rem; width:100% }
table.dt th.n .dt-sort{ justify-content:flex-end }
table.dt th .dt-sort:hover{ color:var(--ink-2) }
table.dt th .dt-sort:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; border-radius:6px }
table.dt th[aria-sort] .dt-sort{ color:var(--accent) }
.dt-sort-ind{ font-size:9px; opacity:.4; transition:opacity .12s }
table.dt th[aria-sort] .dt-sort-ind{ opacity:1 }
table.dt th .dt-sort-ind::before{ content:"\2195" }        /* ↕ idle */
table.dt th[aria-sort="ascending"]  .dt-sort-ind::before{ content:"\25B2" }  /* ▲ */
table.dt th[aria-sort="descending"] .dt-sort-ind::before{ content:"\25BC" }  /* ▼ */
@media (prefers-reduced-motion:reduce){ .dt-sort-ind{ transition:none } }
table.dt .dt-empty td{ text-align:center; color:var(--ink-3); padding:1.6rem .85rem }
@media (max-width:640px){
  table.dt thead th, table.dt tbody td{ padding:.5rem .6rem }
}

/* ── Dark-mode overrides for hardcoded light literals in this section ── */
[data-theme="dark"] .dialog-bg{ background:rgba(0,0,0,.55) }
/* This dark override forced #fff back onto the accent-filled tab (2.37:1) — it
   predates --on-accent and is exactly what that token exists to prevent. */
[data-theme="dark"] .tab[aria-selected="true"]{ color:var(--on-accent) }

/* ── Reduced-motion: drop the entrance animations ── */
@media (prefers-reduced-motion: reduce){
  .dialog-bg,.dialog,.tabpanel,.secbody>[data-section]{ animation:none }
}

/* ── Print: spatial chrome should not leak onto paper ── */
@media print{
  .dialog-bg,.dialog{ display:none !important }
  .ms{ grid-template-columns:1fr }
  .ms-list{ max-height:none }
  table.dt thead th{ position:static }
}

/* ── Breadcrumbs (renderShell) — "you are here" under the app bar ── */
.crumbs{ border-bottom:1px solid var(--line); background:var(--panel) }
.crumbs-in{ max-width:1200px; margin:0 auto; padding:.5rem 1.4rem; display:flex; align-items:center;
  gap:.4rem; font-size:12.5px; color:var(--ink-3); flex-wrap:wrap }
.crumbs a{ color:var(--ink-2); text-decoration:none; font-weight:600 }
.crumbs a:hover{ color:var(--accent) }
.crumbs [aria-current="page"]{ color:var(--ink); font-weight:700 }
.crumb-sep{ color:var(--ink-4,var(--ink-3)); opacity:.6 }
@media print{ .crumbs{ display:none } }

/* ── Bank-flow stepper (flowSteps): Tuo → Täsmäytä → Hyväksy "you are here" ── */
.flowsteps{ display:flex; align-items:center; gap:.35rem; flex-wrap:wrap; margin:0 0 1.4rem }
.flowstep{ display:inline-flex; align-items:center; gap:.5rem; padding:.4rem .8rem; border-radius:999px;
  font-size:13px; font-weight:650; text-decoration:none; border:1px solid var(--line); background:var(--panel);
  color:var(--ink-3); transition:background .14s var(--ease),border-color .14s var(--ease) }
a.flowstep:hover{ border-color:var(--accent); color:var(--accent) }
.flowstep.current{ background:var(--accent-grad); border-color:transparent; color:var(--on-accent);
  box-shadow:var(--accent-shadow) }
.flowstep.done{ color:var(--ink-2) }
.flowstep.todo{ opacity:.7 }
.flowstep-n{ display:inline-grid; place-items:center; width:20px; height:20px; border-radius:50%;
  font-family:var(--font-mono); font-size:11px; font-weight:700; background:var(--panel-2); color:var(--ink-3) }
/* was a translucent-white scrim + #fff — 4.13 light / 1.95 dark. An INVERSE fill
   (on-accent chip, accent digit) reads as "current" and measures 7.51 / 6.58. */
.flowstep.current .flowstep-n{ background:var(--on-accent); color:var(--accent) }
.flowstep.done .flowstep-n{ background:var(--pos-bg); color:var(--pos) }
.flowstep.done .flowstep-n svg{ width:13px; height:13px }
.flowstep-sep{ color:var(--ink-3); opacity:.5 }
@media (max-width:560px){ .flowstep-l{ display:none } .flowstep{ padding:.4rem .55rem } }


/* ── Agent launchpad (Kirjanpito Spec 3 / S3-2) — "AI-työkalut" button row ──
   A compact toolbar dropped into a Kirjanpito view header (Tositteet /
   Saldoluettelo): fires the already-built sweep engines and surfaces the result
   inline. Token-driven so light + dark stay correct. */
.kp-launch{ display:flex; flex-wrap:wrap; align-items:center; gap:.5rem; margin:.2rem 0 1.2rem }
.kp-launch-lbl{ font-family:var(--font-mono); font-size:10px; font-weight:700; text-transform:uppercase;
  letter-spacing:.07em; color:var(--ink-3); margin-right:.15rem }
.kp-tool{ font-family:var(--font-body); font-size:13px; font-weight:650; cursor:pointer;
  padding:.4rem .8rem; border-radius:999px; border:1px solid var(--line); background:var(--panel);
  color:var(--ink); white-space:nowrap }
.kp-tool:hover:not(:disabled){ border-color:var(--accent); color:var(--accent) }
.kp-tool:focus-visible{ outline:2px solid var(--accent); outline-offset:1px }
.kp-tool:disabled{ cursor:default; opacity:.55 }
.kp-launch-status{ font-size:12.5px; color:var(--ink-2) }
.kp-launch-status a{ color:var(--accent); text-decoration:none; font-weight:650 }
.kp-launch-status a:hover{ text-decoration:underline }
@media print{ .kp-launch{ display:none !important } }

/* ── iOS auto-zoom guard ──────────────────────────────────────────────────────
   Mobile Safari zooms the page when a focused form control has font-size < 16px.
   Scoped to coarse pointers (touch) so the desktop type scale is untouched. */
@media (pointer:coarse){
  input,textarea,select,.in{ font-size:16px }
}

/* ── Dropzone keyboard/drag affordance (wireDropzone) ─────────────────────────
   The visible button is the real trigger; the file input is .sr-only (still
   tab-reachable). .is-dragover is toggled by wireDropzone during a drag. */
.dropzone.is-dragover{ border-color:var(--accent); background:var(--accent-subtle) }

/* ── apply-to-similar modal (banded checklist) ──────────────────────────────
   After a HUMAN accepts a single draft, offer to carry that same, human-chosen
   account onto look-alike drafts. Shared by approve.html + tositteet.html; the
   DOM is built lazily by window.offerSimilar (app.js). The checklist IS the
   vastuukysymys gate: the human confirms the SET the account is applied to —
   nothing auto-fans out. */
/* Above the Avustaja FAB (z-index:1200) so a modal never sits under the floating
   assistant button — on mobile the FAB otherwise clips the primary CTA. */
.ap-sim-bg{position:fixed;inset:0;z-index:1300;background:rgba(16,28,22,.34);opacity:0;pointer-events:none;visibility:hidden;
  transition:opacity .18s var(--ease),visibility 0s linear .18s;display:grid;place-items:center;padding:1rem}
/* visibility flips to hidden only after the fade-out, so a CLOSED modal/drawer
   leaves the accessibility tree (opacity:0 alone keeps role=dialog focusable). */
.ap-sim-bg.show{opacity:1;pointer-events:auto;visibility:visible;transition:opacity .18s var(--ease)}
.ap-sim{background:#fff;border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-lg);
  max-width:720px;width:100%;min-width:0;max-height:86vh;display:flex;flex-direction:column;
  transform:translateY(8px) scale(.985);transition:transform .2s var(--ease)}
/* min-width:0 lets the grid item shrink to the viewport; wide tables scroll
   inside .sim-body instead of pushing the whole drawer off-screen on phones. */
.ap-sim .sim-body{min-width:0}
.ap-sim-bg.show .ap-sim{transform:none}
.ap-sim .sim-head{display:flex;align-items:flex-start;gap:.6rem;padding:1.2rem 1.4rem .3rem}
.ap-sim .sim-head h3{font-family:var(--font-display);font-weight:800;font-size:19px;line-height:1.2;color:var(--ink);margin:0;flex:1}
.ap-sim .sim-x{background:transparent;border:none;font-size:22px;line-height:1;color:var(--ink-3);cursor:pointer;padding:.1rem .35rem;border-radius:8px}
.ap-sim .sim-x:hover{background:var(--panel-2);color:var(--ink)}
.ap-sim .sim-x:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ap-sim .sim-sub{margin:0;padding:.15rem 1.4rem 1rem;color:var(--ink-2);font-size:13.5px;line-height:1.5}
.ap-sim .sim-sub b{color:var(--ink);font-weight:700}
.ap-sim .sim-body{overflow:auto;padding:0 1.4rem;flex:1;-webkit-overflow-scrolling:touch}
.ap-sim .sim-foot{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap;
  padding:.9rem 1.4rem 1.1rem;border-top:1px solid var(--line);margin-top:.3rem}
.ap-sim .sim-sum{font-family:var(--font-mono);font-size:12px;color:var(--ink-2);font-variant-numeric:tabular-nums}
.ap-sim .sim-foot-btns{display:flex;flex-wrap:wrap;gap:.5rem;margin-left:auto;justify-content:flex-end}

.sim-sec{margin:0 0 1.1rem}
.sim-sec-head{display:flex;align-items:center;justify-content:space-between;gap:.6rem;
  position:sticky;top:0;background:#fff;padding:.5rem 0 .3rem;z-index:1}
.sim-sec-head h4{font-family:var(--font-mono);font-size:11px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-2);font-weight:700;margin:0;display:flex;align-items:center;gap:.45rem}
.sim-sec-head .sim-c{font-family:var(--font-mono);font-size:10px;background:var(--panel-2);color:var(--ink-3);
  border-radius:999px;padding:.05rem .45rem;font-weight:700;min-width:16px;text-align:center}
.sim-sel-actions{display:flex;gap:.4rem}
.sim-sel-actions button{font-family:var(--font-body);font-size:11.5px;font-weight:600;color:var(--accent);
  background:transparent;border:none;cursor:pointer;padding:.15rem .4rem;border-radius:6px}
.sim-sel-actions button:hover{background:var(--accent-subtle)}
.sim-sel-actions button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* "Tarkista ensin" (review) band — warn tone, NOT pre-checked (needs a human eye) */
.sim-sec-review .sim-sec-head h4{color:var(--warn)}
.sim-sec-review .sim-sec-head .sim-c{background:var(--warn-bg);color:var(--warn)}
.sim-review-note{margin:.1rem 0 .4rem;font-size:11.5px;color:var(--warn);line-height:1.4}
.sim-sec-review table.sim-tbl tbody tr{background:var(--warn-bg)}

table.sim-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
table.sim-tbl th{font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700;text-align:left;padding:.35rem .5rem;border-bottom:1px solid var(--line);white-space:nowrap}
table.sim-tbl th.r,table.sim-tbl td.r{text-align:right}
table.sim-tbl td{padding:.45rem .5rem;border-bottom:1px solid var(--line);vertical-align:middle;color:var(--ink)}
table.sim-tbl tbody tr:last-child td{border-bottom:none}
table.sim-tbl td.chk,table.sim-tbl th.chk{width:34px;text-align:center;padding-left:.2rem}
table.sim-tbl .mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums;white-space:nowrap}
table.sim-tbl tbody tr:hover{background:var(--accent-subtle)}
.sim-cp{font-weight:600;color:var(--ink)}
.sim-accnm{color:var(--ink-3);font-size:10.5px;display:block;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (prefers-reduced-motion:reduce){
  .ap-sim,.ap-sim-bg{transition:none}
}
@media (max-width:640px){
  .ap-sim{max-height:92vh}
  .ap-sim .sim-body{overflow-x:auto}
  table.sim-tbl{min-width:460px}
}

/* ── voucher drawer (window.openVoucher) ── ledger drill-down, .ap-sim shell ── */
.ap-sim.vd{max-width:600px}
.vd .sim-sub{padding-bottom:.7rem}
.vd-tag{display:inline-flex;align-items:center;font-family:var(--font-mono);font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.04em;color:var(--ink-2);background:var(--panel-2);
  border:1px solid var(--line);border-radius:999px;padding:.05rem .45rem;margin-left:.35rem;white-space:nowrap}
.vd-tag.warn{color:var(--warn-ink,#8a5a00);background:var(--warn-subtle,#fff4e0);border-color:transparent}
table.vd-legs{width:100%;border-collapse:collapse;font-size:13px;margin:.2rem 0 .4rem}
table.vd-legs td,table.vd-legs th{padding:.4rem .5rem;border-bottom:1px solid var(--line)}
table.vd-legs .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
table.vd-legs th.r{text-align:right}
table.vd-legs .vd-vat{color:var(--ink-3);font-size:12px}
table.vd-legs tr.tot td{font-weight:700;border-bottom:none;border-top:2px solid var(--ink-4,var(--line))}
/* Per-voucher legal basis — decision-level Lakiperuste (replaces generic page footers) */
.vd-legal{margin:.7rem 0 .2rem;padding:.65rem .75rem;background:var(--panel-2);border:1px solid var(--line);border-radius:10px}
.vd-legal-h{display:flex;align-items:center;gap:.35rem;font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;
  letter-spacing:.06em;font-weight:700;color:var(--ink-3);margin-bottom:.35rem}
.vd-legal-h .ic{width:13px;height:13px}
.vd-legal-main{margin:0 0 .3rem;font-size:12.5px;line-height:1.5;color:var(--ink)}
.vd-legal-base{margin:0;font-size:11.5px;line-height:1.5;color:var(--ink-3)}
.vd-ok{display:inline-flex;align-items:center;gap:.3rem;color:var(--pos,#1a7f4b);font-weight:600}
.vd-bad{display:inline-flex;align-items:center;gap:.3rem;color:var(--neg,#b3261e);font-weight:600}
.vd-ok .ic,.vd-bad .ic{width:14px;height:14px}
/* Ledger lines that drill: subtle affordance the tosite cell is a button. */
.rc-tosite-drill{background:none;border:none;padding:0;margin:0;font:inherit;color:var(--accent);
  cursor:pointer;text-decoration:underline;text-decoration-color:color-mix(in srgb,var(--accent) 35%,transparent);
  text-underline-offset:2px}
.rc-tosite-drill:hover{text-decoration-color:var(--accent)}
.rc-tosite-drill:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}

/* ── generic drill-down drawer (window.openDrawer) ── shares the .ap-sim shell ── */
.ap-sim.dw2{max-width:640px}
.ap-sim.dw2.dw-wide{max-width:860px}
/* key/value grid (invoice header, employee facts) */
.dw-kv{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:.7rem 1.2rem;margin:.2rem 0 .4rem}
.dw-kv .k{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3);font-weight:700}
.dw-kv .v{font-size:14px;color:var(--ink);margin-top:.1rem}
.dw-kv .v.num{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.dw-kv .v.over{color:var(--neg);font-weight:700}
.dw-kv .v.big{font-size:16px;font-weight:700}
/* section heading inside a drawer */
.dw-sec{margin:1.2rem 0 .5rem;font-family:var(--font-display);font-weight:700;font-size:13.5px;color:var(--ink);
  display:flex;align-items:center;gap:.4rem}
.dw-sec .ic{width:15px;height:15px;color:var(--ink-3)}
/* line-items / breakdown table */
table.dw-lines{width:100%;border-collapse:collapse;font-size:13px;margin:.1rem 0 .3rem}
table.dw-lines th{text-align:left;font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700;padding:.35rem .5rem;border-bottom:1px solid var(--line);white-space:nowrap}
table.dw-lines td{padding:.4rem .5rem;border-bottom:1px solid var(--line);color:var(--ink);vertical-align:top}
table.dw-lines th.r,table.dw-lines td.r{text-align:right}
table.dw-lines td.num,table.dw-lines th.r{font-family:var(--font-mono);font-variant-numeric:tabular-nums;white-space:nowrap}
table.dw-lines tr.tot td{font-weight:700;border-bottom:none;border-top:2px solid var(--line-2)}
table.dw-lines tr.sub td{color:var(--ink-2);border-bottom:1px dashed var(--line)}
table.dw-lines .muted{color:var(--ink-3);font-size:12px}
/* compliance requirement checklist (AVL 209 e §) */
.dw-req{list-style:none;margin:.3rem 0 0;padding:0;font-size:13px}
.dw-req li{display:flex;gap:.5rem;align-items:flex-start;padding:.3rem 0;border-bottom:1px solid var(--line)}
.dw-req li:last-child{border-bottom:none}
.dw-req .mark{flex:0 0 auto;width:1.2em;text-align:center;font-weight:800}
.dw-req .mark.ok{color:var(--pos)} .dw-req .mark.bad{color:var(--neg)}
.dw-req .lbl{color:var(--ink)} .dw-req .note{display:block;color:var(--ink-3);font-size:11.5px}
/* net-pay / total emphasis row for payslip + invoice */
.dw-net{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin:.6rem 0 .2rem;
  padding:.7rem .85rem;border-radius:10px;background:var(--panel-2);border:1px solid var(--line)}
.dw-net .lab{font-size:12px;font-weight:700;color:var(--ink-2)}
.dw-net .amt{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-weight:800;font-size:20px;color:var(--ink)}
.dw-badge{display:inline-block;padding:.15rem .55rem;border-radius:999px;font-size:11px;font-weight:700;white-space:nowrap}
.dw-badge.ok{background:var(--pos-bg);color:var(--pos)} .dw-badge.bad{background:var(--neg-bg);color:var(--neg)}
.dw-badge.warn{background:var(--warn-bg);color:var(--warn)} .dw-badge.muted{background:var(--panel-2);color:var(--ink-2)}
.dw-badge.accent{background:var(--accent-subtle);color:var(--accent)}

/* ── split editor (window.openSplitEditor) ── shares the .ap-sim shell ── */
.sp-modal{max-width:640px}
.sp-src-badge{display:inline-flex;align-items:center;gap:.3rem;font-family:var(--font-mono);font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.04em;color:var(--accent);background:var(--accent-subtle);
  border-radius:999px;padding:.1rem .5rem;margin-left:.4rem;white-space:nowrap}
.sp-src-badge .ic{width:13px;height:13px}
.sp-body{padding-bottom:.4rem}
table.sp-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
table.sp-tbl th{font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700;text-align:left;padding:.35rem .5rem;border-bottom:1px solid var(--line);white-space:nowrap}
table.sp-tbl th.r{text-align:right}
table.sp-tbl th.sp-th-del{width:34px}
table.sp-tbl td{padding:.5rem .5rem;border-bottom:1px solid var(--line);vertical-align:top}
table.sp-tbl tbody tr:last-child td{border-bottom:none}
.sp-td-acct{min-width:150px}
.sp-acct{width:100%;font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:13px;color:var(--ink);
  padding:.45rem .55rem;border:1px solid var(--line-2);border-radius:var(--radius-sm);background:var(--bg-2)}
.sp-acct:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.sp-acctnm{display:block;color:var(--ink-3);font-size:10.5px;margin-top:.2rem;line-height:1.3;
  max-width:190px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sp-caution{display:flex;align-items:flex-start;gap:.3rem;margin-top:.3rem;color:var(--warn);font-size:10.5px;line-height:1.35;max-width:210px}
.sp-caution[hidden]{display:none}   /* the `hidden` toggle must beat display:flex — else a lone ⚠ shows under non-edustus rows */
.sp-caution .ic{flex:none;width:13px;height:13px;margin-top:1px}
.sp-td-amt{width:120px}
.sp-amt{width:100%;font-family:var(--font-mono);font-variant-numeric:tabular-nums;text-align:right;font-size:13px;color:var(--ink);
  padding:.45rem .55rem;border:1px solid var(--line-2);border-radius:var(--radius-sm);background:var(--bg-2)}
.sp-amt:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.sp-td-vat{width:96px}
.sp-vat{width:100%;font-size:12.5px;padding:.42rem .4rem;border:1px solid var(--line-2);border-radius:var(--radius-sm);background:var(--bg-2)}
.sp-vat:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.sp-prev{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:10.5px;color:var(--ink-3);
  line-height:1.4;display:inline-block;padding-top:.45rem}
.sp-td-del{width:34px;text-align:center}
.sp-del{background:transparent;border:none;color:var(--ink-3);cursor:pointer;padding:.4rem;border-radius:8px;line-height:0}
.sp-del:hover{background:var(--neg-bg);color:var(--neg)}
.sp-del:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.sp-addrow{display:inline-flex;align-items:center;gap:.4rem;margin:.7rem 0 .2rem;font-family:var(--font-body);
  font-size:12.5px;font-weight:600;color:var(--accent);background:transparent;border:1px dashed var(--line-2);
  border-radius:999px;padding:.4rem .85rem;cursor:pointer}
.sp-addrow:hover{background:var(--accent-subtle);border-color:var(--accent)}
.sp-addrow:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.sp-addrow .ic{width:14px;height:14px}
.sp-foot .sp-remainder{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:13px;font-weight:700;color:var(--ink-2)}
.sp-foot .sp-remainder.sp-ok{color:var(--pos)}
.sp-foot .sp-remainder.sp-bad{color:var(--neg)}
.sp-foot .btn.ghost.sm{margin-right:.2rem}
@media (max-width:640px){
  .sp-modal{max-height:94vh}
  table.sp-tbl,table.sp-tbl thead,table.sp-tbl tbody,table.sp-tbl th,table.sp-tbl td,table.sp-tbl tr{display:block}
  table.sp-tbl thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  table.sp-tbl tr.sp-row{border:1px solid var(--line);border-radius:var(--radius-sm);padding:.5rem;margin-bottom:.6rem}
  table.sp-tbl tr.sp-row td{border:none;padding:.3rem 0;width:auto}
  .sp-td-amt,.sp-td-vat{width:auto}
  .sp-td-acct::before{content:"Tili";display:block;font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3);margin-bottom:.2rem}
  .sp-td-amt::before{content:"Osuus €";display:block;font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3);margin-bottom:.2rem}
  .sp-td-vat::before{content:"ALV-kanta";display:block;font-family:var(--font-mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3);margin-bottom:.2rem}
  .sp-td-del{text-align:right}
  .sp-prev{padding-top:0}
  .sp-foot .sp-remainder{width:100%}
}
