:root{
  --ink:#1f242b; --ink-2:#2c323a; --body:#6c747e; --muted:#9aa0a8;
  --canvas:#f4f3f0; --surface:#fff; --border:#e8e6e1; --divider:#f2f0ec;
  --accent:#cf6a38; --accent-hover:#b4571f; --accent-tint:#fbeee4; --accent-border:#eccaae;
  --accent-soft:#e6a878;
  --green:#3f7d62; --green-bg:#e9f2ed; --green-bd:#cfe3d8;
  --amber:#9c6a1f; --amber-bg:#f7efe0; --amber-bd:#ecdcc0;
  --xero:#13B5EA; --xero-bg:#e7f6fc; --xero-bd:#c3e8f5; --xero-ink:#0f92bd;
  --shadow:0 1px 2px rgba(40,35,25,.04);
  /* Elevation — kept deliberately soft to preserve the flat, paper-like canvas.
     Only used on hover of genuinely interactive cards, not as a resting halo. */
  --shadow-sm:var(--shadow);
  --shadow-md:0 4px 12px -5px rgba(47,36,22,.10);
  --shadow-lg:0 8px 22px rgba(31,36,43,.16);
  --shadow-xl:0 18px 50px rgba(31,36,43,.18);       /* modal dialogs only */
  --ring:0 0 0 3px rgba(207,106,56,.30);            /* accent keyboard-focus ring */
  --ease:cubic-bezier(.4,0,.2,1);
  /* A solid dark fill. Split from --ink because --ink is a *text* colour: in
     dark mode it is near-white, so anything using it as a background became a
     white block with white text on it. Buttons invert (light fill, dark text);
     the big brand panels stay dark and only their text lifts. */
  --fill-strong:#1f242b; --on-strong:#ffffff; --on-accent:#ffffff;
  --panel-dark:#1f242b; --on-panel:#ffffff;
  --red:#a8503f; --red-bg:#f6e8e4; --red-bd:#ecd2cb;
  /* Which connected mailbox or calendar a row came from (.src-tag). */
  --src-ms:#0f5ea8; --src-ms-bg:#e8f1fb; --src-ms-bd:#c6dcf3;
  --src-google:#b3261e; --src-google-bg:#fcebea; --src-google-bd:#f3cbc8;

  /* ---- Theme tokens --------------------------------------------------
     One token per distinct colour that used to be hardcoded in a rule or in
     a template's <style> block, each seeded with the exact value it replaced
     — so light mode is unchanged — and remapped in the dark block below.
     Brand colours (Xero, Microsoft, WhatsApp, Google, ...) are deliberately
     absent: they identify a third party and must not shift with the theme. */
  --surface:#ffffff;
  --surface-44:#fff7f6;
  --surface-39:#fafafa;
  --surface-15:#fafaf8;
  --surface-1:#faf9f7;
  --surface-38:#faf9f6;
  --surface-43:#fdf7f2;
  --surface-32:#f4f6f8;
  --surface-30:#f1fbf4;
  --surface-35:#f7f6f3;
  --surface-7:#eefaf1;
  --surface-34:#f6f5f2;
  --surface-2:#fde8e8;
  --surface-8:#fdf6e8;
  --surface-28:#f0f2f5;
  --surface-14:#f6f3ee;
  --surface-31:#f2f2f2;
  --surface-13:#f4f2ee;
  --surface-4:#eef0f3;
  --accent-tint:#fbeee4;
  --surface-42:#fdf3e2;
  --surface-10:#e8f6ee;
  --surface-36:#f9e9e5;
  --surface-29:#f1efe9;
  --red-bg:#f6e8e4;
  --surface-27:#f0eee9;
  --surface-41:#fdf2dc;
  --surface-12:#efede9;
  --surface-11:#efece6;
  --surface-40:#fcf3d9;
  --surface-5:#e5e9ef;
  --surface-37:#fae7d7;
  --surface-25:#e4e6eb;
  --surface-33:#f5e6d8;
  --surface-26:#e6e3dd;
  --surface-24:#d8d5cf;
  --surface-22:#c2ccd4;
  --surface-21:#b9b1a5;
  --surface-6:#9aa3ad;
  --surface-9:#e0a53d;
  --surface-23:#c58a4b;
  --accent:#cf6a38;
  --surface-19:#5c8a94;
  --surface-3:#c0392b;
  --surface-20:#b07d2a;
  --surface-17:#2e9e5b;
  --green:#3f7d62;
  --surface-18:#30363f;
  --surface-16:#2b313a;
  --line-1:#f4f2ee;
  --line-15:#f1efe9;
  --line-28:#f0ede8;
  --line-26:#e5e9ef;
  --line-13:#e4e8ec;
  --line-25:#e5e5e5;
  --line-8:#e0e3e8;
  --line-12:#d8dee4;
  --line-16:#f5c6c6;
  --line-4:#f2ddc7;
  --red-bd:#ecd2cb;
  --line-9:#f0d9c4;
  --line-24:#d0d5dd;
  --line-6:#dcd8d1;
  --line-2:#f0c4bc;
  --line-11:#d8d5cf;
  --line-14:#f0e2b6;
  --line-10:#bfe6cf;
  --line-23:#ccd0d5;
  --line-22:#c8ced4;
  --line-27:#ecc9ae;
  --line-21:#c6c1b9;
  --line-7:#e0b46a;
  --line-5:#7ec99a;
  --line-20:#8a8886;
  --line-3:#c0392b;
  --line-17:#1faa54;
  --line-19:#3a414c;
  --line-18:#333a44;
  --on-fill:#ffffff;
  --text-46:#eceae5;
  --text-44:#d9d6d0;
  --text-17:#d3d0ca;
  --text-43:#c8cdd4;
  --text-45:#e9c6ab;
  --text-16:#c2c7cd;
  --text-41:#c3c7cc;
  --text-42:#c6c2bb;
  --text-40:#b3b8bf;
  --text-39:#b0b5bc;
  --accent-soft:#e6a878;
  --text-36:#a3aeb8;
  --muted:#9aa0a8;
  --text-3:#8a97a3;
  --text-34:#8a9099;
  --text-15:#8a8d91;
  --text-38:#b07264;
  --text-33:#8a8886;
  --text-32:#8a8478;
  --text-1:#c0392b;
  --body:#6c747e;
  /* A solid dark fill. Split from --ink because --ink is a *text* colour: in
     dark mode it is near-white, so anything using it as a background became a
     white block with white text on it. Buttons invert (light fill, dark text);
     the big brand panels stay dark and only their text lifts. */
  --fill-strong:#1f242b; --on-strong:#ffffff; --on-accent:#ffffff;
  --panel-dark:#1f242b; --on-panel:#ffffff;
  --red:#a8503f;
  --text-27:#6c727b;
  --text-35:#9c7a3a;
  --text-11:#5a6b7a;
  --text-12:#65676b;
  --text-23:#2f9e5f;
  --text-13:#666666;
  --text-7:#5c6470;
  --text-20:#25a152;
  --text-31:#8a6d3b;
  --text-26:#5e5e5e;
  --text-29:#7c4437;
  --text-37:#a8720a;
  --text-14:#8a5a24;
  --text-25:#555555;
  --text-9:#1e824c;
  --text-24:#3a4b5a;
  --text-28:#7a5618;
  --text-30:#8a5a00;
  --text-2:#3a414a;
  --text-22:#2b333c;
  --text-10:#333333;
  --text-21:#26303c;
  --text-4:#1a2b3c;
  --text-8:#20272f;
  --text-19:#1c2b33;
  --text-18:#1a2230;
  --text-6:#1c1e21;
  --text-5:#1b1b1b;
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Hanken Grotesk',system-ui,sans-serif;-webkit-font-smoothing:antialiased;color:var(--ink);background:var(--canvas)}
a{color:var(--accent);text-decoration:none;transition:color .12s var(--ease)}
a:hover{color:var(--accent-hover)}
::selection{background:var(--accent-tint);color:var(--accent-hover)}
/* Accessibility: visible keyboard focus for interactive elements (WCAG 2.2 — 2.4.7).
   Mouse clicks stay clean via :focus-visible; only keyboard nav shows the ring. */
a:focus-visible,button:focus-visible,[role="button"]:focus-visible,[tabindex]:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible,.switch:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;border-radius:8px}
/* Visually hidden but announced by screen readers — for labelling icon-only
   or empty cells (e.g. a table's row-open column). */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* The input is still the control for the keyboard and for the form; it just
   isn't the thing you look at, because its label is drawn as a button or a
   card. Kept out of .sr-only because that is for text a screen reader should
   read and nobody should see — this is the opposite, a control everybody
   operates and nobody sees. Both pages that need it had their own copy of
   these four declarations, which is how they drift. */
.sr-control{position:absolute;opacity:0;width:0;height:0}
.mono{font-family:'IBM Plex Mono',monospace}
.display{font-family:'Bricolage Grotesque',sans-serif}
button{font-family:inherit}

/* Logo -------------------------------------------------------- */
.logo{display:flex;align-items:center;gap:12px}
.logo .mark{width:19px;height:auto;flex:none}
.logo .word{line-height:1}
.logo .word b{font-family:'Bricolage Grotesque',sans-serif;font-weight:700;font-size:15px;letter-spacing:.1em;color:var(--ink)}
.logo .word span{display:block;margin-top:2px;font-family:'IBM Plex Mono',monospace;font-weight:600;font-size:7.5px;letter-spacing:.3em;color:var(--accent)}
.logo.on-dark .word b{color:var(--on-fill)}

/* Buttons ----------------------------------------------------- */
.btn{height:46px;padding:0 22px;border:none;border-radius:11px;cursor:pointer;font-weight:600;font-size:14px;display:inline-flex;align-items:center;justify-content:center;gap:8px;transition:transform .1s var(--ease),background .14s var(--ease),border-color .14s var(--ease),box-shadow .14s var(--ease)}
.btn:active{transform:scale(.985)}
.btn-primary{background:var(--fill-strong);color:var(--on-strong)}
.btn-primary:hover{background:var(--ink-2)}
.btn-outline{background:var(--surface);color:var(--ink);border:1px solid var(--ink)}
.btn-outline:hover{background:var(--surface-1)}
.btn-xero{background:var(--xero);color:var(--on-fill)}
.btn-xero:hover{background:#0fa3d4}
.btn-block{width:100%}
.btn-x{width:20px;height:20px;border-radius:5px;background:var(--surface);color:var(--xero);font-weight:800;font-size:12px;display:flex;align-items:center;justify-content:center}

/* Forms ------------------------------------------------------- */
label{font-weight:600;font-size:12px;color:var(--text-7)}
.field{width:100%;height:44px;border:1px solid var(--border);background:var(--surface-1);border-radius:10px;padding:0 13px;font-size:13px;font-weight:500;color:var(--ink-2);outline:none;transition:border-color .14s var(--ease),background .14s var(--ease),box-shadow .14s var(--ease)}
.field:hover{border-color:var(--line-6)}
.field:focus{border-color:var(--accent);background:var(--surface);box-shadow:var(--ring)}
select.field{padding:0 11px}

/* Pills ------------------------------------------------------- */
.pill{display:inline-flex;align-items:center;gap:6px;font-weight:600;font-size:10.5px;border-radius:999px;padding:4px 9px}
.pill-amber{color:var(--amber);background:var(--amber-bg);border:1px solid var(--amber-bd)}
.pill-green{color:var(--green);background:var(--green-bg);border:1px solid var(--green-bd)}
.pill-xero{color:var(--xero-ink);background:var(--xero-bg);border:1px solid var(--xero-bd);font-size:11.5px;padding:6px 12px}

/* Cards ------------------------------------------------------- */
.card{background:var(--surface);border:1px solid var(--border);border-radius:18px;box-shadow:var(--shadow);transition:box-shadow .18s var(--ease),transform .18s var(--ease),border-color .18s var(--ease)}

/* ===== LOGIN ================================================= */
.login{min-height:100vh;display:flex}
.login .brand{width:44%;flex:none;background:var(--panel-dark);color:var(--on-panel);display:flex;flex-direction:column;justify-content:space-between;padding:46px 52px;position:relative;overflow:hidden}
.login .brand .eyebrow{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:.07em;color:var(--accent-soft)}
.login .brand h1{margin-top:16px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:38px;line-height:1.14;letter-spacing:-.01em;max-width:460px}
.login .brand p{margin-top:16px;font-size:15px;line-height:1.6;color:var(--text-40);max-width:410px}
.login .brand .foot{font-size:12px;color:var(--text-27)}
.login .brand .watermark{position:absolute;right:-70px;bottom:-90px;width:400px;height:auto;opacity:.05}
.login .panel{flex:1;display:flex;align-items:center;justify-content:center;padding:40px}
.login .panel .inner{width:100%;max-width:384px}
.login h2{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:27px;letter-spacing:-.01em}
.login .sub{margin-top:8px;font-size:14px;color:var(--body)}
.stack{display:flex;flex-direction:column;gap:15px;margin-top:24px}
.field-group{display:flex;flex-direction:column;gap:7px}
.row-between{display:flex;align-items:center;justify-content:space-between}
.note{margin-top:18px;display:flex;gap:10px;align-items:flex-start;border-radius:12px;padding:12px 14px;font-size:12px;line-height:1.45}
.note-amber{background:var(--accent-tint);border:1px solid var(--accent-border);color:var(--text-14)}
.note-green{background:var(--green-bg);border:1px solid var(--green-bd);color:var(--green)}

/* ===== LANDING =============================================== */
.landing{min-height:100vh;background:var(--canvas)}
.landing-nav{max-width:1160px;margin:0 auto;padding:26px 34px;display:flex;align-items:center;justify-content:space-between}
.landing-nav .actions{display:flex;align-items:center;gap:12px}
.landing-nav .btn{height:40px;padding:0 18px;font-size:13px}
.landing-hero{max-width:760px;margin:0 auto;padding:70px 34px 20px;text-align:center}
.landing-hero .eyebrow{font-size:12px;letter-spacing:.07em;color:var(--accent)}
.landing-hero h1{margin:16px auto 0;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:46px;line-height:1.14;letter-spacing:-.01em;color:var(--ink);max-width:620px}
.landing-hero p{margin:18px auto 0;font-size:16px;line-height:1.6;color:var(--body);max-width:480px}
.landing-hero .cta{margin-top:30px;display:flex;align-items:center;justify-content:center;gap:14px}
.landing-hero .cta .fine{font-size:12px;color:var(--muted)}
.landing-features{max-width:1160px;margin:50px auto 0;padding:0 34px 70px;display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.landing-features .card{padding:22px 20px}
.landing-features .tic{width:40px;height:40px;border-radius:11px;background:var(--accent-tint);display:flex;align-items:center;justify-content:center}
.landing-features h3{margin-top:14px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:15px}
.landing-features p{margin-top:6px;font-size:12.5px;line-height:1.5;color:var(--body)}
.landing-foot{border-top:1px solid var(--border);padding:22px 34px;text-align:center;font-size:12px;color:var(--muted)}

/* ===== TOPBAR =============================================== */
.topbar{background:var(--surface);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:14px 34px}
.topbar .right{display:flex;align-items:center;gap:16px;font-size:12.5px;color:var(--muted)}
.topbar .sep{margin-left:8px;padding-left:16px;border-left:1px solid var(--border);font-weight:600;font-size:13px;color:var(--text-2)}

/* ===== ONBOARDING =========================================== */
.setup{max-width:1160px;margin:0 auto;padding:34px 34px 60px;display:flex;gap:30px}
.stepper{width:250px;flex:none}
.stepper .kicker{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.06em;color:var(--accent)}
.stepper h1{margin-top:12px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:24px;line-height:1.15}
.stepper p{margin-top:10px;font-size:13px;line-height:1.55;color:var(--body)}
.steps{margin-top:26px}
.step{display:flex;gap:13px;align-items:flex-start}
.step .col{display:flex;flex-direction:column;align-items:center;flex:none}
.dot{width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:13px;background:var(--surface);color:var(--text-39);border:1.5px solid var(--border)}
.dot.active{background:var(--fill-strong);color:var(--on-strong);border-color:var(--fill-strong)}
.dot.done{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.step .line{width:2px;height:34px;background:var(--border)}
.step .line.done{background:var(--accent)}
.step .label{padding-top:4px}
.step .label .t{font-weight:600;font-size:13.5px;color:var(--muted)}
.step .label.on .t{color:var(--ink)}
.step .label .d{margin-top:3px;font-size:11.5px;color:var(--muted)}

.panel-wrap{flex:1;min-width:0;display:flex;gap:22px;align-items:flex-start}
.form-card{flex:1;padding:26px 28px}
.form-card h2{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:18px}
.form-card .lede{margin-top:6px;font-size:13px;line-height:1.5;color:var(--body)}
.grid-2{margin-top:22px;display:grid;grid-template-columns:1fr 1fr;gap:16px}
.grid-2 .span2{grid-column:1/3}
.actions{margin-top:24px;display:flex;justify-content:flex-end;align-items:center}
.actions.between{justify-content:space-between}

.instr{width:290px;flex:none;background:var(--panel-dark);border-radius:18px;padding:22px 22px 24px;color:var(--on-panel)}
.instr .kicker{font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.07em;color:var(--accent-soft)}
.instr h3{margin-top:14px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:14px}
.instr ol{margin-top:16px;list-style:none;display:flex;flex-direction:column;gap:15px}
.instr li{display:flex;gap:11px;font-size:12.5px;line-height:1.5;color:var(--text-43)}
.instr li b{color:var(--on-fill);font-weight:600}
.instr .num{width:21px;height:21px;border-radius:50%;background:var(--accent);color:var(--on-accent);font-weight:700;font-size:11px;display:flex;align-items:center;justify-content:center;flex:none}
.instr .fine{margin-top:20px;padding-top:16px;border-top:1px solid var(--line-18);font-size:11.5px;line-height:1.5;color:var(--text-34)}

/* connector choices */
.connectors{margin-top:20px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
.connector{border:1px solid var(--border);background:var(--surface);border-radius:14px;padding:16px 15px;position:relative}
.connector.selected{border:2px solid var(--xero);background:#f2fbfe}
.connector.soon{opacity:.6}
.connector .glyph{width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:16px;color:var(--on-fill)}
.connector .name{margin-top:11px;font-weight:600;font-size:14px}
.connector .meta{margin-top:4px;font-size:11px;color:var(--muted)}
.connector .check{position:absolute;top:11px;right:11px;width:19px;height:19px;border-radius:50%;background:var(--xero);display:flex;align-items:center;justify-content:center}
.scopes{margin-top:12px;display:flex;flex-direction:column;gap:9px}
.scope{display:flex;align-items:center;gap:12px;border:1px solid var(--border);border-radius:11px;padding:12px 14px}
.scope .t{font-weight:600;font-size:12.5px;color:var(--ink-2)}
.scope .d{margin-top:2px;font-size:11px;color:var(--muted)}
.switch{width:38px;height:22px;border-radius:999px;background:var(--surface-24);position:relative;flex:none;cursor:pointer;border:none;transition:background .12s}
.switch.on{background:var(--accent)}
.switch::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:var(--surface);transition:left .12s}
.switch.on::after{left:18px}

/* ===== XERO CONSENT ========================================= */
.xero-page{min-height:100vh;background:var(--surface-32);display:flex;flex-direction:column}
.xero-bar{background:var(--surface);border-bottom:1px solid var(--line-13);display:flex;align-items:center;justify-content:space-between;padding:15px 30px}
.xero-bar .brand{display:flex;align-items:center;gap:11px;font-weight:600;font-size:16px;color:var(--text-4)}
.xero-badge{width:34px;height:34px;border-radius:50%;background:var(--xero);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:17px;color:var(--on-fill)}
.xero-body{flex:1;display:flex;align-items:center;justify-content:center;padding:40px 20px}
.xero-card{width:100%;max-width:440px;background:var(--surface);border:1px solid var(--line-13);border-radius:16px;padding:30px 30px 26px;box-shadow:0 6px 24px rgba(26,43,60,.08)}
.pairing{display:flex;align-items:center;justify-content:center;gap:14px}
.pairing .dots{display:flex;gap:5px}
.pairing .dots span{width:5px;height:5px;border-radius:50%;background:var(--surface-22)}
.xero-card h1{margin-top:20px;text-align:center;font-size:20px;line-height:1.3;color:var(--text-4)}
.org{margin-top:22px}
.org .box{margin-top:7px;display:flex;align-items:center;gap:11px;border:1px solid var(--line-12);border-radius:10px;padding:11px 13px}
.org .ini{width:30px;height:30px;border-radius:7px;background:var(--xero-bg);color:var(--xero-ink);font-weight:700;font-size:12px;display:flex;align-items:center;justify-content:center;flex:none}
.perm-title{margin-top:20px;font-weight:600;font-size:12px;color:var(--text-11)}
.perms{margin-top:11px;display:flex;flex-direction:column;gap:10px}
.perms li{display:flex;gap:10px;align-items:flex-start;list-style:none;font-size:12.5px;line-height:1.4;color:var(--text-24)}
.xero-actions{margin-top:24px;display:flex;flex-direction:column;gap:11px}
.xero-fine{margin-top:18px;text-align:center;font-size:11px;line-height:1.5;color:var(--text-36)}
.btn-cancel{height:47px;border:1px solid var(--line-12);background:var(--surface);color:var(--text-11);border-radius:10px;cursor:pointer;font-weight:600;font-size:14px}

/* ===== DASHBOARD ============================================ */
.wrap{max-width:1560px;margin:0 auto;padding:30px 44px 60px}
/* The head owns the gap between itself and the page. Without it, pages whose
   first section brings no top margin of its own (the widget canvases, where
   `#widgets .widget{margin-top:0}`) had their action buttons touching the first
   card. Margins collapse with a following element's own top margin, so pages
   that already space themselves are unaffected. */
/* No flex-wrap here on purpose: with wrapping on, a long lede is measured at its
   max-content width, so the actions break onto their own line instead of the text
   simply shrinking. Wrapping is switched on below the breakpoint, where a single
   row genuinely doesn't fit. */
.page-head{display:flex;align-items:flex-end;justify-content:space-between;
  gap:16px;margin-bottom:18px}
.page-head>:first-child{min-width:0}
@media(max-width:720px){.page-head{flex-wrap:wrap}}
.page-head h1{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:26px}
.page-head .lede{margin-top:7px;font-size:13.5px;color:var(--body)}
.stats{margin-top:22px;display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
.stat{padding:24px 26px}
.stat .k{font-weight:600;font-size:12.5px;color:var(--muted)}
.stat .v{margin-top:12px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:34px}
.stat .v.sm{font-size:24px}
.stat .s{margin-top:7px;font-weight:500;font-size:11.5px}
/* A stat that is also the way in to the page it summarises (Home: Customers &
   quotes). .stat carries the type; this adds only what a link needs — the whole
   tile is the target, so there is no separate "view" affordance to miss. */
.stat-link{display:block;text-decoration:none;color:inherit;transition:border-color .12s,transform .12s}
.stat-link:hover{border-color:var(--accent);transform:translateY(-1px)}
.stat-link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.upload{margin-top:16px;background:var(--accent-tint);border:1.5px dashed var(--accent-border);border-radius:16px;padding:26px 20px;display:flex;align-items:center;gap:18px;cursor:pointer}
.upload .ic{width:50px;height:50px;border-radius:13px;background:var(--surface);border:1px solid var(--accent-border);display:flex;align-items:center;justify-content:center;flex:none}
.upload .t{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:15px}
.upload .d{margin-top:5px;font-size:12.5px;line-height:1.45;color:var(--body)}
.queue-head{margin-top:24px;display:flex;align-items:center;justify-content:space-between}
.queue-head h2{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:16px}
.table{margin-top:14px;background:var(--surface);border:1px solid var(--border);border-radius:16px;box-shadow:var(--shadow);overflow:hidden}
.trow{display:grid;grid-template-columns:1.6fr 1fr .8fr .9fr .9fr;align-items:center;padding:15px 20px;border-bottom:1px solid var(--line-1)}
.trow:last-child{border-bottom:none}
.thead{padding:12px 20px;border-bottom:1px solid var(--divider);font-family:'IBM Plex Mono',monospace;font-weight:600;font-size:10.5px;letter-spacing:.03em;color:var(--muted)}
.doc{display:flex;align-items:center;gap:10px;min-width:0}
.doc .n{font-weight:600;font-size:12.5px;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cell{font-weight:500;font-size:12.5px;color:var(--text-2)}
.cell.muted{font-size:12px;color:var(--body)}
.cell.amt{text-align:right;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:13px;color:var(--ink)}
.cell.right{text-align:right}

/* extra pill colours */
.pill-grey{color:var(--text-7);background:var(--surface-4);border:1px solid var(--line-8)}
.pill-red{color:var(--red);background:var(--red-bg);border:1px solid var(--red-bd)}
.pill-blue{color:var(--accent);background:var(--accent-tint);border:1px solid var(--accent-border)}

/* ===== APP SHELL (sidebar) ================================== */
.app{display:flex;min-height:100vh;align-items:flex-start}
/* Sidebar is pinned to the viewport: it stays on screen while the main
   column scrolls, is exactly one viewport tall, and scrolls internally only
   if its own nav ever outgrows a short screen. */
.sidebar{width:248px;flex:none;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;padding:20px 16px;position:sticky;top:0;height:100vh;overflow-y:auto}
.sidebar .nav{display:flex;flex-direction:column;gap:4px;flex:1}
.sidebar .nav a{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:10px;color:var(--body);font-weight:600;font-size:13.5px}
.sidebar .nav a .ic{color:var(--muted);flex:none}
.sidebar .nav a:hover{background:var(--surface-1);color:var(--ink)}
.sidebar .nav a.active{background:var(--accent-tint);color:var(--accent)}
.sidebar .nav a.active .ic{color:var(--accent)}
#tk-nav{display:flex;flex-direction:column;gap:4px}
#tk-nav a.tk-dragging{opacity:.4}
.side-foot{border-top:1px solid var(--divider);padding-top:14px}
.side-user{display:flex;align-items:center;gap:11px;padding:4px 6px}
.side-user .avatar{width:34px;height:34px;border-radius:9px;background:var(--fill-strong);color:var(--on-strong);font-weight:700;font-size:12px;display:flex;align-items:center;justify-content:center;flex:none}
.side-user .nm{font-weight:600;font-size:12.5px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side-user .em{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side-signout{margin-top:10px;width:100%;height:38px;border:1px solid var(--border);background:var(--surface);border-radius:10px;color:var(--body);font-weight:600;font-size:12.5px;cursor:pointer}
.side-signout:hover{color:var(--ink);border-color:var(--line-11)}
.main{flex:1;min-width:0;min-height:100vh;background:var(--canvas)}

/* Sidebar rail ------------------------------------------------------------
   The sidebar collapses to an icon-only strip. Width and label visibility are
   driven by .nav-rail on .app (server-rendered from the saved preference, so
   there's no flash of the full sidebar on first paint). Labels are hidden with
   display:none rather than opacity/width so they don't stay in the tab order or
   get read out; each link carries a title attribute, so hovering still names it. */
.side-top{display:flex;align-items:center;gap:8px;padding:6px 8px 20px}
.side-top .logo{flex:1;min-width:0}
.nav-toggle{flex:none;width:28px;height:28px;display:flex;align-items:center;justify-content:center;
  border:1px solid transparent;border-radius:8px;background:none;color:var(--muted);cursor:pointer;
  transition:background .12s var(--ease),color .12s var(--ease),border-color .12s var(--ease)}
.nav-toggle:hover{background:var(--surface-1);color:var(--ink);border-color:var(--border)}
.nav-toggle:focus-visible{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
.nav-toggle svg{transition:transform .18s var(--ease)}

.app.nav-rail .sidebar{width:56px;padding-left:8px;padding-right:8px}
.app.nav-rail .nav-label,
.app.nav-rail .logo .word,
.app.nav-rail .nav-group,
.app.nav-rail .side-user > div,
.app.nav-rail .side-signout{display:none}
/* Toggle sits under the mark and flips to point the other way. */
.app.nav-rail .side-top{flex-direction:column;gap:10px;padding:6px 0 16px}
.app.nav-rail .side-top .logo{flex:none;justify-content:center}
.app.nav-rail .nav-toggle svg{transform:rotate(180deg)}
/* Centre the icons and keep the active marker readable at rail width. */
.app.nav-rail .sidebar .nav a{justify-content:center;gap:0;padding:10px 0}
.app.nav-rail .sidebar .nav a.active::before{display:none}
.app.nav-rail .side-user{justify-content:center;padding:4px 0}
.app.nav-rail .side-foot{display:flex;flex-direction:column;align-items:center}
/* The Accounting "setup pending" dot would otherwise be pushed off the rail by
   its flex:1 label; pin it to the icon instead. */
.app.nav-rail .sidebar .nav a{position:relative}
.app.nav-rail .setup-dot{position:absolute;top:7px;right:9px}
/* Respect a reduced-motion preference — this is a width animation. */
.sidebar{transition:width .16s var(--ease),padding .16s var(--ease)}
@media (prefers-reduced-motion:reduce){
  .sidebar,.nav-toggle svg{transition:none}
}

/* ===== HOME ================================================= */
.home-head{display:flex;align-items:flex-start;justify-content:space-between}
.home-head-ctl{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}

/* Trial status strip: how long is left, and where to do something about it. */
.home-trial{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:16px;padding:10px 14px;font-size:12.5px;font-weight:600;color:var(--accent);background:var(--accent-tint);border:1px solid var(--accent-border);border-radius:10px}
.home-trial-exp{color:var(--text-1);background:var(--surface-2);border-color:var(--line-16)}
.home-trial a{margin-left:auto;color:inherit;text-decoration:underline}

/* First-run checklist. */
.home-setup{margin-top:16px;padding:18px 20px}
.home-setup-h{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:17px;margin:0}
.home-setup-sub{margin-top:5px;font-size:12.5px;color:var(--muted)}
.home-setup-list{margin-top:14px;display:flex;flex-direction:column;gap:8px}
.home-setup-top{display:flex;align-items:flex-start;gap:12px}
.home-setup-top>div{flex:1;min-width:0}
/* Minimised: the card keeps its heading and how far through you are, and gives
   the rest of Home back. Both states ship in the markup and CSS chooses, so the
   toggle needs no DOM rebuilding and works server-rendered. */
.home-setup-min{padding:14px 20px}
.home-setup-min .home-setup-list{display:none}
.setup-sub-min,.setup-plus-bar{display:none}
.home-setup-min .setup-sub-open{display:none}
.home-setup-min .setup-sub-min{display:inline}
.home-setup-min .setup-plus-bar{display:inline}
.home-setup-min-btn{flex:none;width:28px;height:28px;display:flex;align-items:center;justify-content:center;padding:0;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--muted);font-family:inherit;cursor:pointer;transition:border-color .12s,color .12s}
.home-setup-min-btn:hover{border-color:var(--accent);color:var(--accent)}
.home-step{display:flex;align-items:center;gap:12px;padding:11px 13px;border:1px solid var(--border);border-radius:10px;text-decoration:none;color:inherit;transition:border-color .12s,box-shadow .12s}
.home-step:hover{border-color:var(--accent);box-shadow:0 3px 10px rgba(31,36,43,.06)}
/* A completed step stays on the list, greyed with a tick — the point is seeing
   what is left against what is done, not having items vanish. */
.home-step-done{opacity:.62}
.home-step-done:hover{opacity:.8}
.home-step-tick{width:20px;height:20px;border-radius:50%;border:1.5px solid var(--border);display:flex;align-items:center;justify-content:center;flex:none;color:var(--on-fill)}
.home-step-done .home-step-tick{background:var(--green);border-color:transparent}
.home-step-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.home-step-tx b{font-size:13.5px;font-weight:600}
.home-step-tx span{font-size:12px;color:var(--muted)}
.home-step-state{font-size:11px;font-weight:600;color:var(--muted);flex:none}

/* Appearance picker — a segmented control of real radios, so it works without
   JS and reads correctly to a screen reader. The radio itself is hidden; the
   label is the control. */
.theme-pick{display:flex;align-items:center;gap:8px}
.theme-seg{display:inline-flex;padding:3px;background:var(--surface-1);border:1px solid var(--border);border-radius:11px}
.theme-opt{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 11px;border-radius:8px;cursor:pointer;
  font-weight:600;font-size:12px;color:var(--body);white-space:nowrap;
  transition:background .12s var(--ease),color .12s var(--ease),box-shadow .12s var(--ease)}
.theme-opt svg{flex:none;opacity:.75}
.theme-opt:hover{color:var(--ink)}
.theme-opt.on{background:var(--surface);color:var(--accent);box-shadow:var(--shadow-sm)}
.theme-opt.on svg{opacity:1}
.theme-opt:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px}
@media (max-width:640px){.theme-opt span{display:none}.theme-opt{padding:0 10px}}
.ask{margin-top:20px;background:var(--panel-dark);border-radius:20px;padding:24px 26px;box-shadow:var(--shadow-lg)}
.ask-label{display:flex;align-items:center;gap:8px;font-weight:600;font-size:13px;color:var(--text-45)}
.ask-answer{margin-top:13px;font-weight:500;font-size:16.5px;line-height:1.45;color:var(--on-fill)}
.ask-answer b{font-weight:700}
.ask-input{margin-top:16px;display:flex;align-items:center;gap:10px;background:var(--surface-16);border:1px solid var(--line-19);border-radius:12px;padding:13px 15px;font-weight:500;font-size:13px;color:var(--muted)}
.ask-send{margin-left:auto;width:28px;height:28px;border-radius:8px;background:var(--accent);display:flex;align-items:center;justify-content:center;flex:none}
.section-head{margin-top:24px;display:flex;align-items:center;justify-content:space-between}
.section-head h2{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:16px}
.section-head a{font-weight:600;font-size:12.5px}
.section-head + .card{margin-top:14px}
.sched{display:flex;align-items:center;gap:14px;padding:16px 0}
.sched.divide{border-bottom:1px solid var(--divider)}
.sched .time{width:52px;font-weight:600;font-size:13px;color:var(--accent);flex:none}
.sched .t{font-weight:600;font-size:14px;color:var(--ink-2)}
.sched .d{margin-top:3px;font-weight:500;font-size:12px;color:var(--muted)}
.toolkit{margin-top:14px;display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.tool{display:flex;align-items:center;gap:15px;padding:22px 22px}
.tool:hover{border-color:var(--accent-border);box-shadow:var(--shadow-md);transform:translateY(-2px)}
.tool svg:last-child{transition:transform .16s var(--ease)}
.tool:hover svg:last-child{transform:translateX(3px)}
.tool .tic{width:42px;height:42px;border-radius:12px;background:var(--accent-tint);display:flex;align-items:center;justify-content:center;flex:none}
.tool .tt{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:14.5px;color:var(--ink)}
.tool .td{margin-top:3px;font-size:12px;color:var(--body)}

/* ===== JOBS ================================================= */
.pipeline{margin-top:20px;display:flex;gap:14px;flex-wrap:wrap}
.chip{flex:1;min-width:96px;padding:17px 18px;text-align:center}
.chip .cv{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:24px}
.chip .cl{margin-top:6px;font-weight:600;font-size:11.5px;color:var(--muted)}
.jobs-grid{margin-top:18px;display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.job{padding:16px 17px}
.job-top{display:flex;align-items:center;justify-content:space-between}
.job .jn{font-weight:600;font-size:12px;color:var(--accent)}
.job-cust{margin-top:11px;font-weight:600;font-size:15px;color:var(--ink)}
.job-title{margin-top:4px;font-weight:500;font-size:12.5px;color:var(--body)}
.job-foot{margin-top:14px;display:flex;align-items:center;justify-content:space-between}
.job-foot .sched-note{font-weight:500;font-size:11.5px;color:var(--muted)}
.job-amt{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:15px;color:var(--ink)}

/* ===== INFO HUB ============================================= */
.alert-strip{margin-top:20px;display:flex;align-items:flex-start;gap:12px;background:var(--amber-bg);border:1px solid var(--amber-bd);border-radius:14px;padding:14px 16px;font-size:12.5px;line-height:1.45;color:var(--text-28)}
.alert-strip b{font-weight:600}
/* Something has already lapsed rather than being about to — read as a breach. */
.alert-strip-red{background:var(--red-bg);border-color:var(--red-bd)}
/* Stacked alerts read as one group, so they sit closer to each other than to the
   sections around them. Without this each carried the full 20px and the run of
   them looked like separate, unrelated blocks. */
.alert-strip+.alert-strip{margin-top:10px}
.compliance{margin-top:14px;overflow:hidden}
.comp-head{padding:15px 18px;border-bottom:1px solid var(--divider);display:flex;align-items:center;gap:12px}
.comp-ic{width:34px;height:34px;border-radius:10px;background:var(--accent-tint);display:flex;align-items:center;justify-content:center;flex:none}
.comp-title{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:14px}
.comp-count{margin-top:3px;font-weight:500;font-size:11px;color:var(--muted)}
.comp-body{padding:4px 18px 10px}
.comp-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 0}
.comp-row.divide{border-bottom:1px solid var(--line-1)}
.cr-name{font-weight:600;font-size:12.5px;color:var(--ink-2)}
/* Info Hub "Due next quarter": a month heading above each group of rows. Sits
   inside .comp-body, so the rows keep the same rhythm as every other Info Hub
   card and only the heading is new. */
.ih-month+.ih-month{margin-top:6px}
.ih-month-head{display:flex;align-items:center;justify-content:space-between;padding:11px 0 5px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:11.5px;letter-spacing:.02em;text-transform:uppercase;color:var(--muted)}
.ih-month-head span{font-weight:600;font-size:10.5px;color:var(--text-7);background:var(--surface-4);border:1px solid var(--line-8);border-radius:999px;padding:2px 8px;text-transform:none;letter-spacing:0}
.ih-quarter .cr-name a{color:inherit;text-decoration:none}
.ih-quarter .cr-name a:hover{text-decoration:underline}
/* Amber word, not an amber pill: the pill on this row already carries the date,
   and a second coloured badge would compete with it for the same glance. */
.ih-unassigned{color:var(--amber);font-weight:600}
/* The renewal control on a record row. Same size and weight as .cr-edit and
   .cr-move beside it; .on marks a renewal already in train, so the row says
   somebody is on it without opening anything. */
.cr-renewal{color:var(--amber);font-weight:600}
.cr-renew{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid var(--line-8);background:var(--surface);border-radius:9px;color:var(--muted);cursor:pointer;transition:color .15s var(--ease),border-color .15s var(--ease)}
.cr-renew:hover{color:var(--body);border-color:var(--border)}
.cr-renew.on{color:var(--amber);border-color:var(--amber-bd);background:var(--amber-bg)}
.cr-exp{margin-top:4px;font-weight:500;font-size:11px;color:var(--muted)}

/* ===== PORTAL EXTRAS ======================================== */
.sidebar a.logo{display:flex;align-items:center;gap:12px;text-decoration:none}
.nav-group{padding:16px 12px 7px;font-family:'IBM Plex Mono',monospace;font-weight:600;font-size:10px;color:var(--muted);letter-spacing:.18em}
.setup-dot{width:8px;height:8px;border-radius:50%;background:var(--accent);flex:none}
.btn-customise{display:inline-flex;align-items:center;gap:8px;height:38px;padding:0 16px;border:1px solid var(--border);background:var(--surface);color:var(--body);border-radius:10px;font-weight:600;font-size:12.5px}
.btn-customise:hover{color:var(--ink)}
.btn-customise.on{background:var(--fill-strong);border-color:var(--fill-strong);color:var(--on-strong)}
.edit-note{margin-top:14px;display:flex;gap:10px;align-items:flex-start;background:var(--accent-tint);border:1px solid var(--accent-border);border-radius:12px;padding:11px 14px;font-weight:500;font-size:12px;line-height:1.5;color:var(--text-14)}
.edit-note b{font-weight:700}
.widget{margin-top:18px}
/* Home's widget stack. Each home partial carries its own leading margin (.ask,
   .stats, .section-head); combined with a flex gap that would double up, so the
   stack owns the vertical rhythm and the partials' margins are zeroed inside it.
   Roomier than the toolkit pages' 16px because these are full page sections. */
/* The margin matches the gap, so the first section clears whatever precedes it
   (the page head, an alert strip, the edit note) by the same amount that
   separates the sections from each other. It was 0 before. */
#widgets.home-stack{gap:26px;margin-top:26px}
#widgets.home-stack>.widget>:first-child,
#widgets.home-stack .ask,
#widgets.home-stack .stats,
#widgets.home-stack .section-head{margin-top:0}
.widget[draggable="true"]{cursor:grab}
.widget-bar{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.widget-label{font-weight:600;font-size:11px;color:var(--muted);letter-spacing:.1em}
.widget-ctl{position:relative}
/* Direct child only: the gear popover is also inside .widget-ctl, and an
   unscoped `button` here was overriding .wcfg-save (higher specificity), which
   rendered the popover's Apply as a 28px white square with white text on it. */
.widget-ctl>form{display:flex;gap:6px}
.widget-ctl>form button{width:28px;height:28px;border:1px solid var(--border);background:var(--surface);border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center}
/* Customisable toolkit-page widgets (Analytics/Accounting/Office/Info Hub).
   The .widget is a plain layout cell; the card chrome lives in each partial. */
#widgets .widget{margin-top:0}
#widgets.w-stack{display:flex;flex-direction:column;gap:16px}
.widget.w-dragging{opacity:.5}
/* Gear popover — per-widget configuration */
.wcfg-btn svg{pointer-events:none}
.wcfg-pop{position:absolute;top:34px;right:0;z-index:20;min-width:210px;background:var(--surface);border:1px solid var(--border);border-radius:11px;box-shadow:var(--shadow-lg);padding:12px 13px}
.wcfg-pop form{display:flex;flex-direction:column;gap:9px}
.wcfg-row{display:flex;align-items:center;gap:9px;font-size:12.5px;font-weight:500;color:var(--body);cursor:pointer}
.wcfg-row.wcfg-col{flex-direction:column;align-items:flex-start;gap:5px;cursor:default}
.wcfg-grouplabel{font-weight:600;font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.wcfg-sub{display:flex;align-items:center;gap:9px;font-size:12.5px;font-weight:500;color:var(--body);cursor:pointer}
/* The whole label is the hit target, so give it a hover so that reads. The
   group wrapper (.wcfg-col) is a container, not a control — no hover on it. */
.wcfg-row:not(.wcfg-col),.wcfg-sub{padding:3px 6px;margin:0 -6px;border-radius:7px;
  transition:background .12s var(--ease),color .12s var(--ease)}
.wcfg-row:not(.wcfg-col):hover,.wcfg-sub:hover{background:var(--surface-1);color:var(--ink)}

/* The popover's tick boxes are the shared control — see "Tick boxes" below. */
.wcfg-pop select{height:32px;border:1px solid var(--border);border-radius:8px;padding:0 8px;font-size:12.5px;font-family:inherit;color:var(--ink);background:var(--surface);width:100%}
.wcfg-save{align-self:flex-end;margin-top:2px;height:32px;padding:0 18px;border:none;border-radius:8px;background:var(--fill-strong);color:var(--on-strong);font-weight:600;font-size:12px;cursor:pointer;
  transition:background .12s var(--ease)}
.wcfg-save:hover{background:var(--accent)}

/* ===== CUSTOMISE PANEL ======================================
   A vertical rail pinned to the right while a page is in edit mode, listing
   every widget the page has. Widgets are dragged between the rail and the
   canvas to show/hide them, so the rail doubles as the parking bay for
   anything not currently on the page. Used by pages whose #widgets carries
   data-canvas="1" (see app/_widget_panel.html + app/_widget_canvas.html). */
:root{--wpanel-w:296px}
.wpanel{position:fixed;top:0;right:0;bottom:0;z-index:40;width:var(--wpanel-w);display:flex;flex-direction:column;
  background:var(--surface);border-left:1px solid var(--border);box-shadow:-8px 0 26px rgba(31,36,43,.07)}
.wpanel-head{flex:none;padding:18px 18px 14px;border-bottom:1px solid var(--divider)}
.wpanel-head .t{display:flex;align-items:center;gap:9px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:15px;color:var(--ink)}
.wpanel-head .t svg{color:var(--accent);flex:none}
.wpanel-head .d{margin-top:7px;font-size:11.5px;line-height:1.5;color:var(--muted)}
.wpanel-body{flex:1;min-height:0;overflow-y:auto;padding:16px 18px 18px}
.wpanel-foot{flex:none;padding:13px 18px;border-top:1px solid var(--divider);display:flex;gap:9px;align-items:center}
.wpanel-foot .btn{flex:1;justify-content:center}
/* Content shifts left rather than sliding under the rail. */
.wrap.wpanel-open{padding-right:calc(var(--wpanel-w) + 30px);max-width:none;margin:0}

/* A group of chips ("On this page" / "Available") */
.wgroup+.wgroup{margin-top:18px}
.wgroup-h{display:flex;align-items:center;gap:7px;font-size:10.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--muted);margin-bottom:9px}
.wgroup-h .n{margin-left:auto;font-weight:600;letter-spacing:0;font-variant-numeric:tabular-nums}
/* The available list is also a drop target — drag a widget here to remove it. */
.wgroup-drop{min-height:62px;border:1.5px dashed var(--border);border-radius:12px;padding:8px;display:flex;flex-direction:column;gap:7px;
  transition:border-color .14s var(--ease),background .14s var(--ease)}
.wgroup-drop.is-over{border-color:var(--accent);background:var(--accent-tint)}
.wgroup-empty{padding:12px 6px;text-align:center;font-size:11.5px;line-height:1.5;color:var(--muted)}

/* One widget chip */
.wchip{display:flex;align-items:center;gap:9px;padding:9px 10px;background:var(--surface);border:1px solid var(--border);border-radius:10px;
  cursor:grab;transition:border-color .12s var(--ease),box-shadow .12s var(--ease),opacity .12s var(--ease)}
.wchip:hover{border-color:var(--accent-border);box-shadow:var(--shadow-sm)}
.wchip.w-dragging{opacity:.45}
.wchip .grip{flex:none;color:var(--text-42)}
.wchip:hover .grip{color:var(--accent)}
.wchip .lbl{flex:1;min-width:0;font-weight:600;font-size:12.5px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wchip .span{flex:none;font-size:10.5px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}
.wchip-btn{flex:none;width:24px;height:24px;border:1px solid var(--border);background:var(--surface);border-radius:7px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;color:var(--muted);transition:all .12s var(--ease)}
.wchip-btn:hover{border-color:var(--accent);background:var(--accent-tint);color:var(--accent)}
.wchip.is-off{background:var(--surface-1)}
.wchip.is-off .lbl{color:var(--body)}

/* A card row whose cards are individually customisable. Auto-fit rather than a
   fixed four, so pulling a card out re-balances the row instead of leaving a
   hole; .tile-drag marks the row as a drop target mid-drag. */
.stats.stats-fit{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.tile[draggable="true"]{cursor:grab}
.tile.w-dragging{opacity:.4}
[data-tilebox].tile-over{outline:2px dashed var(--accent-border);outline-offset:7px;border-radius:14px}
.t-slot{border:1.5px dashed var(--accent);border-radius:14px;background:var(--accent-tint);min-height:76px}

/* Card sub-chips nested under a category in the rail */
.wsub{margin:5px 0 2px 21px;display:flex;flex-direction:column;gap:5px}
.wsub-chip{display:flex;align-items:center;gap:7px;padding:5px 8px;background:var(--surface);border:1px solid var(--divider);border-radius:8px;
  cursor:grab;transition:border-color .12s var(--ease),opacity .12s var(--ease)}
.wsub-chip:hover{border-color:var(--accent-border)}
.wsub-chip.w-dragging{opacity:.45}
.wsub-chip .grip{flex:none;color:var(--text-17)}
.wsub-chip .lbl{flex:1;min-width:0;font-size:11.5px;font-weight:600;color:var(--body);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wsub-chip.is-off{background:var(--surface-35);border-style:dashed}
.wsub-chip.is-off .lbl{color:var(--muted)}
.wsub-btn{flex:none;width:20px;height:20px;border:1px solid var(--border);background:var(--surface);border-radius:6px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;color:var(--muted);transition:all .12s var(--ease)}
.wsub-btn:hover{border-color:var(--accent);background:var(--accent-tint);color:var(--accent)}

/* Canvas affordances while dragging */
#widgets.is-dragging .widget{transition:none}
.w-slot{border:1.5px dashed var(--accent);border-radius:14px;background:var(--accent-tint);min-height:90px}
#widgets.w-canvas-over{outline:2px dashed var(--accent-border);outline-offset:8px;border-radius:16px}

@media (max-width:900px){
  .wpanel{position:static;width:auto;border-left:none;border-top:1px solid var(--border);box-shadow:none;margin-top:20px}
  .wrap.wpanel-open{padding-right:44px;max-width:1560px;margin:0 auto}
}

.ask{background:var(--panel-dark);border-radius:20px;padding:20px 22px;box-shadow:var(--shadow-lg)}
.ask-send{transition:transform .12s var(--ease),background .12s var(--ease)}
.ask-send:hover{background:var(--accent-hover);transform:scale(1.08)}
.ask-input{transition:border-color .14s var(--ease),background .14s var(--ease)}
.ask-input:focus-within{border-color:var(--accent-soft);background:var(--surface-18)}
.btn-xero{display:inline-flex;align-items:center;gap:9px;height:44px;padding:0 20px;border:none;background:#13B5EA;color:var(--on-fill);border-radius:11px;cursor:pointer;font-weight:600;font-size:13.5px}
.btn-x{width:20px;height:20px;border-radius:5px;background:var(--surface);color:#13B5EA;font-weight:800;font-size:12px;display:flex;align-items:center;justify-content:center}
.copy-panel{margin-top:12px;background:var(--surface-1);border:1px solid var(--border);border-radius:12px;padding:14px 15px;display:flex;flex-direction:column;gap:12px}
.copy-k{font-weight:600;font-size:11px;color:var(--muted)}
.copy-row{margin-top:6px;display:flex;align-items:center;gap:9px}
.copy-row code{flex:1;min-width:0;font-family:'IBM Plex Mono',monospace;font-weight:500;font-size:12px;color:var(--ink);background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:9px 11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.copy-btn{height:34px;padding:0 13px;border:1px solid var(--border);background:var(--surface);border-radius:8px;cursor:pointer;font-weight:600;font-size:11.5px;color:var(--accent);flex:none}
.copy-btn.ok{color:var(--green)}
.hint-blue{margin-top:14px;display:flex;gap:9px;align-items:flex-start;background:var(--xero-bg);border:1px solid var(--xero-bd);border-radius:11px;padding:11px 13px;font-weight:500;font-size:11.5px;line-height:1.5;color:#0f7ba1}
.field.mono{font-family:'IBM Plex Mono',monospace;font-size:12.5px}
.instr a{color:var(--accent-soft)}

/* ===== AESTHETIC REFINEMENTS ================================
   Additive polish layered on the existing system — depth, motion
   feedback, and wayfinding. Palette unchanged; all colours derived
   from existing tokens. */

/* Upload dropzone — reads as an actionable target on hover */
.upload{transition:border-color .16s var(--ease),background .16s var(--ease),box-shadow .16s var(--ease)}
.upload:hover{border-color:var(--accent);background:var(--surface-37);box-shadow:var(--shadow-md)}
.upload .ic{transition:transform .16s var(--ease)}
.upload:hover .ic{transform:translateY(-2px)}

/* Table rows — subtle hover feedback for scannable rows */
.table .trow{transition:background .12s var(--ease)}
.table .trow:hover{background:var(--surface-1)}

/* Sidebar — smoother nav transitions + a subtle active-item inset rail
   (drawn inside the link so it never triggers horizontal overflow) */
.sidebar .nav a{transition:background .12s var(--ease),color .12s var(--ease)}
.sidebar .nav a.active{position:relative;overflow:hidden}
.sidebar .nav a.active::before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:3px;background:var(--accent)}
.side-signout{transition:color .12s var(--ease),border-color .12s var(--ease),background .12s var(--ease)}

/* Onboarding connector tiles — hover feedback when selectable */
.connector{transition:border-color .16s var(--ease),box-shadow .16s var(--ease),transform .16s var(--ease)}
.connector:not(.soon):not(.selected):hover{border-color:var(--accent-border);box-shadow:var(--shadow-md);transform:translateY(-2px)}

/* Copy / customise buttons — consistent motion language */
.btn-customise{transition:background .12s var(--ease),border-color .12s var(--ease),color .12s var(--ease)}
.copy-btn{transition:border-color .12s var(--ease),color .12s var(--ease),background .12s var(--ease)}
.copy-btn:hover{border-color:var(--accent-border);background:var(--accent-tint)}

/* ===== SHARED COMPONENTS ====================================
   One definition each for the chrome every toolkit page needs.
   These used to be copy-pasted into each page's <style> block, which let
   them drift apart; pages now inherit from here and only add what's
   genuinely page-specific. */

/* Modal dialogs — centred, soft-shadowed, and never taller than the
   viewport (long forms scroll inside the dialog rather than off-screen). */
dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;max-height:88vh;overflow:auto;
  background:var(--surface);color:var(--ink);border:1px solid var(--border);border-radius:16px;padding:22px;
  box-shadow:var(--shadow-xl)}
dialog::backdrop{background:rgba(31,36,43,.38);backdrop-filter:blur(2px)}
dialog[open]{animation:dlg-in .16s var(--ease)}
@keyframes dlg-in{from{opacity:0;transform:translate(-50%,-47%)}to{opacity:1;transform:translate(-50%,-50%)}}
dialog h2{font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:15px}

/* Dialog form controls */
.dlg-field{height:38px;padding:0 12px;border:1px solid var(--border);border-radius:9px;font-size:13px;font-family:inherit;
  color:var(--ink);background:var(--surface);outline:none;transition:border-color .14s var(--ease),box-shadow .14s var(--ease)}
.dlg-field:hover{border-color:var(--line-6)}
.dlg-field:focus{border-color:var(--accent);box-shadow:var(--ring)}
.dlg-field::placeholder{color:var(--muted)}
.dlg-row{display:flex;gap:10px;align-items:center}
.dlg-row>label{font-size:12px;color:var(--muted);font-weight:600;min-width:58px}
.dlg-actions{display:flex;gap:10px;justify-content:flex-end}
.btn-cancel{transition:border-color .12s var(--ease),color .12s var(--ease),background .12s var(--ease)}
.btn-cancel:hover{color:var(--ink);border-color:var(--line-22);background:var(--surface-1)}

/* Flash strips — one look for every page's "saved / removed / failed" note.
   The page-prefixed aliases are kept so existing markup keeps working. */
/* Vertical margins on both sides so the strip sits right whether it follows the
   page head or precedes content that brings its own top margin (which collapses). */
.flash,.job-flash,.ih-flash{margin:16px 0 14px;padding:11px 15px;border-radius:12px;font-size:13px;font-weight:500;line-height:1.45}
.flash-green,.job-flash-green,.ih-flash-green{background:var(--green-bg);border:1px solid var(--green-bd);color:var(--green)}
.flash-amber,.job-flash-amber,.ih-flash-amber{background:var(--amber-bg);border:1px solid var(--amber-bd);color:var(--amber)}
.flash-red,.job-flash-red,.ih-flash-red{background:var(--red-bg);border:1px solid var(--red-bd);color:var(--red)}

/* Empty states — a card with a glyph, a line, and the action that fixes it.
   Replaces the loose grey sentences pages used to drop under a heading.
   The top margin lives here because every empty state follows page content. */
.blank{margin-top:16px;padding:44px 30px;text-align:center}
.blank .glyph{width:52px;height:52px;margin:0 auto;border-radius:15px;display:flex;align-items:center;justify-content:center;
  background:var(--accent-tint);border:1px solid var(--accent-border);color:var(--accent)}
.blank .t{margin-top:16px;font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:16px;color:var(--ink)}
.blank .d{margin-top:7px;font-size:13px;line-height:1.55;color:var(--body);max-width:430px;margin-left:auto;margin-right:auto}
.blank .a{margin-top:20px;display:flex;align-items:center;justify-content:center;gap:10px}

/* Button sizes — pages were repeating these three declarations inline. */
.btn-sm{height:38px;padding:0 16px;font-size:12.5px;border-radius:10px}
.btn-xs{height:32px;padding:0 13px;font-size:12px;border-radius:9px;gap:6px}
/* Same size as .btn-sm; the name is what the toolkit pages already use. */
.crm-btn-sm{height:38px;padding:0 16px;font-size:12.5px;border-radius:10px;
  display:inline-flex;align-items:center;gap:7px;white-space:nowrap;text-decoration:none}

/* The action row in a page head. */
.crm-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}
.crm-actions form{display:flex}

/* Row-action buttons inside a table or card — Edit / Turn off / Restore. */
.ji-btn{height:26px;padding:0 9px;border:1px solid var(--border);border-radius:8px;background:var(--surface);
  color:var(--body);font-family:inherit;font-size:11.5px;font-weight:600;cursor:pointer;
  display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
  transition:border-color .12s var(--ease),color .12s var(--ease),background .12s var(--ease)}
.ji-btn:hover{border-color:var(--accent-border);color:var(--accent);background:var(--accent-tint)}

/* Record tables — the directory, the rules list, the history pages. Every
   toolkit page that lists records uses this shell; it lived in one page's
   <style> block, so the others rendered as a bare unstyled table. */
.crm-card{margin-top:14px;padding:0}
.crm-table{width:100%;border-collapse:collapse;font-size:13px}
/* Sticky header — a list can run long, so column labels stay in view. Uses an
   inset shadow rather than border-bottom: collapsed borders don't stick. */
.crm-table th{position:sticky;top:0;z-index:2;text-align:left;padding:11px 16px;font-size:10.5px;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;color:var(--muted);background:var(--surface-1);white-space:nowrap;
  box-shadow:inset 0 -1px 0 var(--border)}
.crm-table thead th:first-child{border-top-left-radius:17px}
.crm-table thead th:last-child{border-top-right-radius:17px}
.crm-table tbody tr:last-child td:first-child{border-bottom-left-radius:17px}
.crm-table tbody tr:last-child td:last-child{border-bottom-right-radius:17px}
.crm-table th.num,.crm-table td.num{text-align:right;font-variant-numeric:tabular-nums}
.crm-table td{padding:12px 16px;vertical-align:middle}
.crm-table tbody tr{transition:background .12s var(--ease)}
.crm-table tbody tr + tr td{border-top:1px solid var(--divider)}
.crm-table tbody tr:hover{background:var(--surface-1)}
.crm-table .nil{color:var(--text-41)}
.crm-table .sub{display:block;margin-top:2px;font-size:11.5px;color:var(--muted)}
.crm-table .c-name b{font-weight:600;font-size:13px;color:var(--ink)}
/* The chevron column is furniture: as narrow as its content. */
.crm-table th.chev,.crm-table td.chev{width:1%}
/* Right-aligned row actions, kept on one line. */
.crm-table .row-acts,.crm-table .rule-acts{display:flex;gap:6px;justify-content:flex-end;align-items:center;white-space:nowrap}
.crm-table .row-acts form,.crm-table .rule-acts form{display:flex}

/* Numbers read as columns, not as text: every figure the same width. */
.stat .v,.chip .cv,.cell.amt,.job-amt,.kpi-v{font-variant-numeric:tabular-nums}

/* Stat cards — lift on hover only where the card is a link/button target;
   the resting state stays flat to keep the canvas calm. */
.stat .k{letter-spacing:.01em}
a.card:hover,button.card:hover,.card-link:hover{border-color:var(--accent-border);box-shadow:var(--shadow-md)}

/* Section headings shared by the detail pages */
.section-h{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:11px;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-bottom:12px}

/* Small pills (table cells, inline labels) */
/* The provider a mail row or calendar event came from, when a business has
   both Outlook and Google connected. */
.src-tag{display:inline-block;flex:none;font-size:9.5px;font-weight:700;letter-spacing:.02em;line-height:1.4;padding:0 5px;border-radius:5px;vertical-align:1px;white-space:nowrap}
.src-microsoft{color:var(--src-ms);background:var(--src-ms-bg);border:1px solid var(--src-ms-bd)}
.src-google{color:var(--src-google);background:var(--src-google-bg);border:1px solid var(--src-google-bd)}
.src-letter{min-width:13px;padding:0 3px;text-align:center}
/* Calendar chips take their provider's colour, so the badge can stay small. */
.cal-chip.chip-src-microsoft{color:var(--src-ms);background:var(--src-ms-bg);border-color:var(--src-ms-bd)}
.cal-chip.chip-src-google{color:var(--src-google);background:var(--src-google-bg);border-color:var(--src-google-bd)}
.cal-chip .src-tag{background:var(--surface);}
.src-strip{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;margin:-4px 0 14px;font-size:12px;color:var(--muted)}
.src-strip-lead{font-weight:600}
.src-strip-item{display:inline-flex;align-items:center;gap:5px;color:var(--text-2);min-width:0;max-width:100%}
.src-strip-addr{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pill-sm{font-size:10.5px;padding:3px 9px;white-space:nowrap}

/* Customer tags — used on the CRM directory, detail page and pipeline cards */
.crm-tag{display:inline-block;font-size:11px;padding:2px 9px;background:var(--surface-13);border:1px solid var(--border);
  border-radius:999px;margin:1px 3px 1px 0;color:var(--body);white-space:nowrap}
.crm-tag.is-more{color:var(--muted);cursor:default}

/* Tick boxes — every checkbox in the product, drawn once.

   The native control paints its checked state in the *user agent's* accent,
   which on Chrome is a blue this palette never chose and cannot influence. The
   usual answer, `accent-color`, only moves that fill: the tick stays white on a
   solid block, so the control still reads as a coloured square with something
   in it rather than as a tick. Here the box keeps its --surface fill in both
   states and only the tick arrives, in --ink.

   Both are theme tokens, so a white box with a black tick by day is a dark box
   with a light tick at night — the same control, not a white chip burned into
   every night-mode form. That is the reason not to write #fff and #000 here.

   Drawn in CSS rather than as a background-image because an SVG data URI cannot
   read a custom property: a themed tick that way needs two copies of the image
   and a rule to choose between them. */
input[type=checkbox]{appearance:none;-webkit-appearance:none;position:relative;flex:none;
  box-sizing:border-box;width:16px;height:16px;margin:0;vertical-align:-3px;
  border:1.5px solid var(--line-21);border-radius:5px;background:var(--surface);cursor:pointer;
  transition:border-color .12s var(--ease),box-shadow .12s var(--ease)}
input[type=checkbox]:hover:not(:disabled){border-color:var(--ink)}
input[type=checkbox]:checked,input[type=checkbox]:indeterminate{border-color:var(--ink)}
/* Tick = the bottom and right edges of an empty box, rotated 45°. Centred with
   a transform so it stays put if the box size ever changes. */
input[type=checkbox]:checked::after{content:'';position:absolute;left:50%;top:50%;
  width:4.5px;height:8.5px;border:solid var(--ink);border-width:0 2px 2px 0;
  transform:translate(-50%,-60%) rotate(45deg)}
/* Partial selection — the "Select all" boxes above the scan lists set it from
   JS. Suppressing the native control suppressed the native dash along with the
   native tick, and a select-all that reads as plainly off while half its rows
   are ticked is worse than not having one. Declared after :checked so it wins
   on a box that is both, which is exactly what those scripts produce. */
input[type=checkbox]:indeterminate::after{content:'';position:absolute;left:50%;top:50%;
  width:8px;height:2px;border:0;border-radius:1px;background:var(--ink);
  transform:translate(-50%,-50%)}
input[type=checkbox]:focus-visible{outline:none;border-color:var(--ink);box-shadow:var(--ring)}
/* Muted rather than faded: several of these sit inside a wrapper that already
   dims itself, and two opacities multiply into something unreadable. */
input[type=checkbox]:disabled{cursor:not-allowed;border-color:var(--border);background:var(--divider)}
input[type=checkbox]:disabled:checked::after{border-color:var(--muted)}

/* Radio buttons — the same box, round, with a dot instead of a tick.

   Excluded: any control wearing .sr-control, whose label is drawn as a button
   or a card and whose input is deliberately invisible. That exclusion is not
   cosmetic. A bare input[type=radio] rule has the same specificity as the
   .sr-control rule above and sits later in the file, so it would win, and the
   two pickers that hide their radios would sprout one — inside the theme
   segment and inside every credit-pack card. Excluding a marker class rather
   than naming those two pages is what stops the third card-style picker
   somebody adds later from being a bug nobody predicted. */
input[type=radio]:not(.sr-control){appearance:none;-webkit-appearance:none;position:relative;flex:none;
  box-sizing:border-box;width:16px;height:16px;margin:0;vertical-align:-3px;
  border:1.5px solid var(--line-21);border-radius:50%;background:var(--surface);cursor:pointer;
  transition:border-color .12s var(--ease),box-shadow .12s var(--ease)}
input[type=radio]:not(.sr-control):hover:not(:disabled){border-color:var(--ink)}
input[type=radio]:not(.sr-control):checked{border-color:var(--ink)}
input[type=radio]:not(.sr-control):checked::after{content:'';position:absolute;left:50%;top:50%;
  width:8px;height:8px;border-radius:50%;background:var(--ink);transform:translate(-50%,-50%)}
input[type=radio]:not(.sr-control):focus-visible{outline:none;border-color:var(--ink);box-shadow:var(--ring)}
input[type=radio]:not(.sr-control):disabled{cursor:not-allowed;border-color:var(--border);background:var(--divider)}
input[type=radio]:not(.sr-control):disabled:checked::after{background:var(--muted)}

/* Respect users who prefer reduced motion (WCAG 2.2 — 2.3.3) */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{transition-duration:.01ms !important;animation-duration:.01ms !important}
  .tool:hover,.connector:hover,.upload:hover{transform:none}
}


/* ===== NIGHT MODE ============================================
   Chosen on the Home page and stored per user; the shell stamps data-theme
   on <html> before first paint, so there's no flash of the light theme and
   only one selector to maintain here.
   The core palette is hand-authored — a purely mechanical inversion put
   cards underneath the canvas and washed the accent out to a pale peach.
   The rest is derived from each light value with its hue preserved, mapping
   lightness onto an elevation ladder rather than flipping it. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --src-ms:#7fb6ec; --src-ms-bg:#172636; --src-ms-bd:#27405a;
  --src-google:#f0938b; --src-google-bg:#361b19; --src-google-bd:#5a2c28;
  --accent-border:#5a3d28;
  --accent-hover:#f09a6e;
  --accent-soft:#c4794f;
  --accent-tint:#33241a;
  --accent:#e2885a;
  --amber-bd:#4a3b24;
  --amber-bg:#2b2317;
  --amber:#d8a860;
  --body:#a6adb6;
  --border:#333941;
  --canvas:#15171a;
  --divider:#262a30;
  --green-bd:#2e463a;
  --green-bg:#1a2a22;
  --green:#82c3a3;
  --ink-2:#d5d9df;
  --ink:#e9ebee;
  --muted:#7b828c;
  --red-bd:#4a302b;
  --red-bg:#2c1d1a;
  --red:#e08b7c;
  --surface:#1e2126;
  --surface-44:#321d1a;
  --surface-39:#24262a;
  --surface-15:#24262b;
  --surface-1:#2d2922;
  --surface-38:#2d2a22;
  --surface-43:#35271b;
  --surface-32:#23292e;
  --surface-30:#1d3424;
  --surface-35:#2f2c23;
  --surface-7:#1e3524;
  --surface-34:#302d24;
  --surface-2:#381d1d;
  --surface-8:#382f1d;
  --surface-28:#252931;
  --surface-14:#312c24;
  --surface-31:#2a2c31;
  --surface-13:#312d25;
  --surface-4:#2b2e32;
  --accent-tint:#33241a;
  --surface-42:#3a301e;
  --surface-10:#23362b;
  --surface-36:#3a241f;
  --surface-29:#343127;
  --red-bg:#2c1d1a;
  --surface-27:#343127;
  --surface-41:#3d331f;
  --surface-12:#2f3137;
  --surface-11:#363128;
  --surface-40:#3e3620;
  --surface-5:#292e36;
  --surface-37:#3f2f21;
  --surface-25:#32353b;
  --surface-33:#403123;
  --surface-26:#373a40;
  --surface-24:#42454d;
  --surface-22:#464a53;
  --surface-21:#464a53;
  --surface-6:#464a53;
  --surface-9:#58482d;
  --surface-23:#534331;
  --accent:#e2885a;
  --surface-19:#39484c;
  --surface-3:#57312d;
  --surface-20:#57472e;
  --surface-17:#2e9e5b;
  --green:#82c3a3;
  --surface-18:#43474f;
  --surface-16:#3f434a;
  --line-1:#484339;
  --line-15:#4b473b;
  --line-28:#4c463b;
  --line-26:#3c434d;
  --line-13:#404650;
  --line-25:#424853;
  --line-8:#434853;
  --line-12:#434c55;
  --line-16:#633535;
  --line-4:#624d37;
  --red-bd:#4a302b;
  --line-9:#634d39;
  --line-24:#4b515e;
  --line-6:#4b515e;
  --line-2:#68413a;
  --line-11:#4d5360;
  --line-14:#6b5f3a;
  --line-10:#426350;
  --line-23:#4f5563;
  --line-22:#505765;
  --line-27:#6e533e;
  --line-21:#525866;
  --line-7:#776341;
  --line-5:#4b6d58;
  --line-20:#525866;
  --line-3:#764742;
  --line-17:#23be5e;
  --line-19:#535861;
  --line-18:#4c5059;
  --on-fill:#ffffff;
  --text-46:#737b8b;
  --text-44:#7f8695;
  --text-17:#838a98;
  --text-43:#838a99;
  --text-45:#dc9d6c;
  --text-16:#878e9c;
  --text-41:#878e9c;
  --text-42:#8b929f;
  --text-40:#8f96a3;
  --text-39:#9198a5;
  --accent-soft:#c4794f;
  --text-36:#969da9;
  --muted:#7b828c;
  --text-3:#a4aab4;
  --text-34:#a7acb7;
  --text-15:#aaafb9;
  --text-38:#d6b4ac;
  --text-33:#adb2bb;
  --text-32:#b1b6bf;
  --text-1:#edaea7;
  --body:#a6adb6;
  --red:#e08b7c;
  --text-27:#b9bdc6;
  --text-35:#e6d6b8;
  --text-11:#bfc3ca;
  --text-12:#c0c4cb;
  --text-23:#b7ebcd;
  --text-13:#c2c5cc;
  --text-7:#c2c5cc;
  --text-20:#b3efc9;
  --text-31:#e4d6be;
  --text-26:#c6cad0;
  --text-29:#e4c6bf;
  --text-37:#f5dcad;
  --text-14:#edd3b5;
  --text-25:#cccfd5;
  --text-9:#b3efcf;
  --text-24:#c3d2df;
  --text-28:#f1dab1;
  --text-30:#f5dcad;
  --text-2:#d7dade;
  --text-22:#e0e2e5;
  --text-10:#e0e2e6;
  --text-21:#c3d0df;
  --text-4:#bed1e4;
  --text-8:#c3d0df;
  --text-19:#c3d5df;
  --text-18:#c3cddf;
  --text-6:#ebedef;
  --text-5:#ebedef;
  /* Depth against a dark canvas needs opacity, not a soft warm haze. */
  --shadow:0 1px 2px rgba(0,0,0,.40);
  --shadow-md:0 4px 14px -4px rgba(0,0,0,.55);
  --shadow-lg:0 10px 26px rgba(0,0,0,.60);
  --shadow-xl:0 20px 54px rgba(0,0,0,.68);
  /* --xero stays exactly as Xero's blue: it is the mark. Its tint and rule are
     UI surfaces rather than brand, so they darken, and the ink on top lightens
     to keep contrast against them. */
  --fill-strong:#e9ebee; --on-strong:#15171a;
  /* The accent lightens in dark, so text on an accent fill goes dark. */
  --on-accent:#241209;
  --panel-dark:#282e36; --on-panel:#e9ebee;
  /* Borders carried barely 1.4:1 against the dark surface — effectively
     invisible. Lifted so structure still reads. */
  --border:#3d444e; --divider:#343a43;
  --xero-bg:#12252e; --xero-bd:#1d3d4b; --xero-ink:#4cbfe4;
  --ring:0 0 0 3px rgba(226,136,90,.38);
}
:root{color-scheme:light}

/* SVG colours written as presentation attributes rather than CSS. A CSS rule
   outranks a presentation attribute, so these can be re-pointed at tokens by
   exact value without editing the ~130 inline icons that carry them. Brand marks
   (Xero, Microsoft, WhatsApp, AroFlo, the Office tiles) are intentionally left
   out — they must look the same in either theme. */
:root[data-theme="dark"] svg[stroke="#cf6a38"]{stroke:var(--accent)}
:root[data-theme="dark"] svg[fill="#cf6a38"]{fill:var(--accent)}
:root[data-theme="dark"] svg[stroke="#b4571f"]{stroke:var(--accent-hover)}
:root[data-theme="dark"] svg[stroke="#e6a878"]{stroke:var(--accent-soft)}
:root[data-theme="dark"] svg[fill="#e6a878"]{fill:var(--accent-soft)}
:root[data-theme="dark"] svg[stroke="#6c747e"]{stroke:var(--body)}
:root[data-theme="dark"] svg[stroke="#9aa0a8"]{stroke:var(--muted)}
:root[data-theme="dark"] svg[stroke="#8a97a3"]{stroke:var(--muted)}
:root[data-theme="dark"] svg[stroke="#c2c7cd"]{stroke:var(--muted)}
:root[data-theme="dark"] svg[stroke="#b07d2a"]{stroke:var(--amber)}
:root[data-theme="dark"] svg[stroke="#2f9e5f"]{stroke:var(--green)}
:root[data-theme="dark"] svg[stroke="#25a152"]{stroke:var(--green)}
/* White-on-a-coloured-fill icons stay white; white *sheet* fills follow the
   surface, which is why these two are split by attribute. */
:root[data-theme="dark"] svg[fill="#fff"]:not([stroke]){fill:var(--surface)}

/* Legal text: the public /privacy/ page and the scroll box on the signup forms. */
.legal{font-size:13px;line-height:1.55;color:var(--body)}
.legal h2{font-size:14px;margin:18px 0 6px}
.legal h2:first-child{margin-top:0}
.legal p{margin:0 0 8px}
.legal ul{margin:0 0 8px;padding-left:20px}
.legal table{width:100%;border-collapse:collapse;margin:4px 0 10px;font-size:12px}
.legal th,.legal td{text-align:left;vertical-align:top;padding:6px 8px;border:1px solid var(--surface-5)}
.legal th{background:var(--surface-1)}
.legal-page{max-width:760px;margin:0 auto;padding:40px 16px 64px}
.legal-page h1{margin:0 0 4px}
.legal-page .legal{font-size:14px}
.legal-meta{color:var(--text-3);font-size:13px;margin:0 0 24px}
.policy-box{max-height:220px;overflow-y:auto;border:1px solid var(--surface-5);border-radius:10px;padding:12px 14px;background:var(--surface-1)}
.policy-box .legal{font-size:12px}
.policy-box .legal h2{font-size:12.5px}
.policy-accept{display:flex;gap:9px;align-items:flex-start;font-size:13px;font-weight:500;color:var(--body);cursor:pointer}
.policy-accept input{margin-top:2px;flex:none;accent-color:var(--accent)}
