#copilotFab{position:fixed;right:20px;bottom:20px;z-index:1200;display:none;align-items:center;gap:6px;padding:10px 16px;border:none;border-radius:24px;background:var(--green,#1d4ed8);color:#fff;font-weight:700;font-size:14px;font-family:inherit;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.18)}
#copilotFab:hover{filter:brightness(1.05)}
/* max-height LEAVES ROOM FOR THE TOPBAR. The panel is anchored to the bottom, so on a short
   viewport it grows upward until it covers the topbar -- and because its coach header is a
   blue gradient sitting directly under a blue "AI Advisor" button, the two merged into one
   block and the panel read as part of the bar (owner, 2026-09-13).
   Solved by arithmetic, not by taste: panelTop = 100vh - bottom(76) - min(560, 100vh - X),
   and the topbar is 64 tall, so X must be at least 76 + 64 to keep panelTop >= 64. 152 gives
   a 12px breathing gap. Measured before: overlapped on ANY viewport under 700px tall, which
   is where a 1366x768 laptop lands once browser chrome is taken off. */
#copilotPanel{position:fixed;right:20px;bottom:76px;z-index:1200;width:360px;max-width:calc(100vw - 40px);height:560px;max-height:calc(100vh - 152px);display:none;flex-direction:column;background:var(--surface,#fff);border:1px solid var(--border,#e8ecf1);border-radius:14px;box-shadow:0 12px 40px rgba(0,0,0,.22);overflow:hidden}
#copilotPanel.open{display:flex}
#copilotPanel .cp-head{padding:14px 16px;border-bottom:1px solid var(--border,#e8ecf1);display:flex;justify-content:space-between;align-items:flex-start;gap:8px}
#copilotPanel .cp-title{font-weight:700;font-size:14px}
#copilotPanel .cp-sub{font-size:12px;color:var(--ink3,#6b7488);white-space:nowrap}
#copilotPanel .cp-head>div:first-child{min-width:0}
#copilotPanel #copilotLang{max-width:104px}
#copilotPanel .cp-body{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:10px}
#copilotPanel .cp-foot{padding:12px;border-top:1px solid var(--border,#e8ecf1);display:flex;gap:8px}
/* min-width:0 IS THE FIX, and flex:1 alone is not (owner, 2026-09-14: "Ask button is still
   getting cropped"). A flex item's min-width defaults to AUTO, so an <input> refuses to
   shrink below its intrinsic width -- measured at 202px here -- and `flex:1` can only grow
   it. Everything under about 363px of panel therefore pushed Ask off the right edge: 10px
   over at 360, 50px at 320. Exactly the head bar's bug one row down; that row was fixed on
   13 Sep and this one was not. The mic and the button hold their size so only the field
   gives. Measured 280-375px after: zero overflow, input 112-207px. */
#copilotPanel .cp-foot input{flex:1;min-width:0;padding:10px 12px;border:1.5px solid var(--border,#e8ecf1);border-radius:8px;font-size:14px;font-family:inherit;background:#fafbfc}
#copilotPanel .cp-foot .btn, #copilotPanel .cp-mic{flex:0 0 auto}
#cpClose{background:none;border:none;font-size:22px;line-height:1;cursor:pointer;color:var(--ink3,#6b7488)}
#copilotPanel .cp-head-right{display:flex;align-items:center;gap:8px}
#copilotLang{font-size:12px;padding:4px 6px;border:1px solid var(--border,#e8ecf1);border-radius:6px;font-family:inherit;background:#fff;cursor:pointer}
/* The line under the input (Guru ji, spec §6): empty until /api/ai/usage has been read; .low below a fifth of the allowance. */
#copilotPanel .cp-note{padding:7px 14px;font-size:11px;line-height:1.4;color:var(--ink3,#6b7488);background:#f7f9fb;border-top:1px solid var(--border,#e8ecf1)}
#copilotPanel .cp-note:empty,#copilotPanel.tour .cp-note{display:none}
#copilotPanel .cp-note.low{color:#b45309;background:#fffbeb}
.cp-tourbtn{background:none;border:1px solid var(--border,#e8ecf1);border-radius:6px;font-size:12px;font-family:inherit;padding:4px 8px;cursor:pointer;color:var(--ink2,#3a4252);white-space:nowrap}
.cp-tourbtn:hover{background:#f2f5f8}
/* Tour footer: replaces the ask-input footer while the walkthrough runs. */
.cp-tourfoot{display:none;padding:12px;border-top:1px solid var(--border,#e8ecf1);align-items:center;justify-content:space-between;gap:8px}
#copilotPanel.tour .cp-tourfoot{display:flex}
#copilotPanel.tour #copilotAskFoot{display:none}
.cp-tourstep{font-size:12px;color:var(--ink3,#6b7488)}
.cp-tourbtns{display:flex;gap:8px;align-items:center}
.cp-tourskip,.cp-tourback{background:none;border:1px solid var(--border,#e8ecf1);border-radius:8px;font-size:13px;font-family:inherit;padding:8px 12px;cursor:pointer;color:var(--ink2,#3a4252)}
.cp-tourskip:hover,.cp-tourback:hover{background:#f2f5f8}
.cp-tournext{padding:8px 14px;font-size:13px}
@media (max-width:480px){
  /* max-width:none MATTERS. left+right+width:auto asks for a symmetric 10px gutter, but the
     base rule's max-width:calc(100vw - 40px) is still in force and caps the box at a 20px
     gutter's width. An over-constrained fixed box drops `right` in LTR, so the panel anchored
     LEFT at 10px and left 30px of air on the right -- visibly shifted, which is what the owner
     saw. Measured on the live phone layout: 10/30 before, 10/10 after. */
  #copilotPanel{right:10px;left:10px;width:auto;max-width:none}
  /* THE HEAD BAR OVERLAPPED ITSELF ON A PHONE (owner, 2026-09-13). Five things -- the name, the
     sub-line, the speaker, Tour and a language select -- were laid out in one non-wrapping row
     built for 360px of desktop panel. On a narrow screen the select and the close button rode over
     the title. The row may wrap now, the name takes the first line to itself, and the controls sit
     under it at a size a thumb can hit. */
  #copilotPanel .cp-head{flex-wrap:wrap;row-gap:8px;padding:12px 12px}
  #copilotPanel .cp-head>div:first-child{flex:1 1 100%}
  #copilotPanel .cp-sub{white-space:normal}
  /* The controls WRAP too. Without that the row could only overflow: a select whose longest option
     is "हिन्दी (Hindi)" has a wide min-content, and on a 320px phone -- or merely on a machine with
     wider font metrics than mine, which is how CI caught this -- it pushed the close button off the
     panel's right edge. Wrapping moves it to its own line instead. */
  #copilotPanel .cp-head-right{flex:1 1 100%;flex-wrap:wrap;justify-content:flex-end;gap:6px;min-width:0}
  #copilotPanel #copilotLang{flex:0 1 auto;min-width:0;max-width:60%}
  #copilotPanel #cpClose{flex:0 0 auto}
  #copilotPanel .cp-tourbtn{padding:4px 8px}
  #copilotPanel #cpClose{font-size:22px;line-height:1;padding:0 4px}
}
/* Guru ji's panel: the mode control (only when the chat is open to the account), the first-open
   notice, an offer under a coach answer, and the starter chips in the greeting. */
#copilotPanel .cp-modes{margin:10px 14px 0}
#copilotPanel .cp-modes .seg-btn{min-height:32px;padding:6px;font-size:12.5px}
#copilotPanel:not(.guru) .cp-modes,#copilotPanel.tour .cp-modes{display:none}
#copilotPanel.mode-coach #cpSubHelp,#copilotPanel.mode-help #cpSubCoach{display:none}
#copilotPanel .cp-notice{display:none;margin:10px 14px 0;padding:10px 12px;border:1px solid #c7d2fe;background:#eef2ff;border-radius:10px;font-size:12px;line-height:1.5;color:var(--ink2,#3a4252)}
#copilotPanel .cp-notice.show{display:block}
#copilotPanel .cp-notice-ok{margin-top:8px;border:none;background:#4338ca;color:#fff;border-radius:6px;padding:5px 10px;font-family:inherit;font-size:12px;font-weight:600;cursor:pointer}
.cp-offer{display:inline-flex;align-items:center;gap:6px;margin-top:8px;border:1px solid var(--green,#1d4ed8);background:#fff;color:var(--green,#1d4ed8);border-radius:8px;padding:7px 12px;font-family:inherit;font-size:13px;font-weight:600;cursor:pointer;text-align:left}
.cp-offer:hover{background:#eff6ff}
.cp-action{margin-top:8px;font-weight:600}
.cp-starters{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.cp-starter{border:1px solid var(--border,#e8ecf1);background:#fff;border-radius:999px;padding:5px 10px;font-family:inherit;font-size:12px;color:var(--ink2,#3a4252);cursor:pointer}
.cp-starter:hover{background:#f2f5f8}
/* The "this is an earlier conversation" line above a restored thread, and its Clear. */
.cp-histnote{display:flex;align-items:center;gap:8px;justify-content:center;font-size:11.5px;color:var(--ink3,#6b7488);padding:2px 0 6px}
.cp-clear{border:none;background:none;color:var(--green,#1d4ed8);font-family:inherit;font-size:11.5px;font-weight:600;cursor:pointer;padding:0}
.cp-clear:hover{text-decoration:underline}
/* GURU JI'S COLOUR (owner, 2026-09-12). Coach mode wears indigo so the owner can see, before reading a
   word, which head they are talking to: the head goes deep indigo, the panel a soft violet wash, the
   Ask button, the offers and the user's own bubbles indigo. Help mode keeps the app's neutral grey and
   green. One class on the panel (.mode-coach, set by renderCopilotMode) carries all of it. */
#copilotPanel.mode-coach{background:#f5f3ff;border-color:#c7d2fe}
/* VIOLET, NOT BLUE -- and the reason is the topbar, not taste. The "AI Advisor" button up
   there is linear-gradient(135deg,#2563eb,#3b82f6); this head was
   linear-gradient(135deg,#1e3a8a,#4338ca). Two 135deg blue gradients in the same column,
   with the panel hanging directly below the button, read as one continuous element -- the
   owner's report was that the panel's text looked like it belonged to the top bar.
   Violet is not a new colour here: the rest of this mode is already #f5f3ff / #c7d2fe /
   #e0e7ff, and #7c3aed is the app's existing violet accent (campaigns.css, AUTO_BG). */
#copilotPanel.mode-coach .cp-head{background:linear-gradient(135deg,#5b21b6,#7c3aed);border-bottom-color:transparent;color:#fff}
#copilotPanel.mode-coach .cp-sub{color:#ddd6fe}
#copilotPanel.mode-coach .cp-tourbtn{color:#fff;border-color:rgba(255,255,255,.35);background:rgba(255,255,255,.08)}
#copilotPanel.mode-coach .cp-tourbtn:hover{background:rgba(255,255,255,.18)}
#copilotPanel.mode-coach #cpClose{color:#fff}
#copilotPanel.mode-coach .cp-modes{background:#e0e7ff;border-color:#c7d2fe}
#copilotPanel.mode-coach .cp-modes .seg-btn.on{color:#4338ca}
#copilotPanel.mode-coach .cp-notice{background:#fff}
#copilotPanel.mode-coach .bot-bubble{background:#fff;border:1px solid #e0e7ff}
#copilotPanel.mode-coach .user-bubble{background:#4338ca}
/* THE ASK BOX AND THE ANSWER BOX WERE THE SAME WHITE (owner, 2026-09-14). Measured, not
   guessed: in coach mode .bot-bubble computed rgb(255,255,255) and the input computed
   rgb(255,255,255) -- identical -- and both sit on the same violet wash at nearly the same
   width, so the thread and the thing you type into read as one continuous surface. The
   foot becomes a white band and the input a violet field inside it, which also puts the
   colours the right way round: the ANSWER is the white page, the INPUT is a control on it. */
#copilotPanel.mode-coach .cp-foot{background:#fff;border-top-color:#ddd6fe}
#copilotPanel.mode-coach .cp-foot input{background:#f1ecff;border-color:#a5b4fc;color:#312e81}
#copilotPanel.mode-coach .cp-foot input::placeholder{color:#6d5bbd}
#copilotPanel.mode-coach .cp-foot input:focus{border-color:#4338ca;outline:none}
#copilotPanel.mode-coach .cp-foot .btn{background:#4338ca;border-color:#4338ca}
#copilotPanel.mode-coach .cp-note{background:#eef2ff;color:#3730a3;border-top-color:#e0e7ff}
#copilotPanel.mode-coach .cp-note.low{background:#fffbeb;color:#b45309}
#copilotPanel.mode-coach .cp-offer{border-color:#4338ca;color:#4338ca}
#copilotPanel.mode-coach .cp-offer:hover{background:#eef2ff}
#copilotPanel.mode-coach .cp-starter{border-color:#c7d2fe;color:#3730a3}
#copilotPanel.mode-coach .cp-starter:hover{background:#eef2ff}
/* HELP MODE HAD NO HEAD. Coach mode wears indigo and reads as three bands; help mode left
   .cp-head with no background at all, so the title, the Help/AI Advisor tabs and the answer
   below them were one undifferentiated sheet of the panel's own white. Neutral grey rather
   than a colour: help mode is deliberately the app's plain voice, and it only needs a
   BOUNDARY, which is what the solid border does. */
#copilotPanel.mode-help .cp-head{background:#f7f9fc;border-bottom-color:#dfe5ee}
/* GURU JI'S VOICE: the speaker toggle (coach mode only), the Listen button under each answer, and the
   mic in the foot (only where the browser can listen: the panel gains .has-mic). */
#copilotPanel #cpVoice{display:none;padding:4px 7px}
#copilotPanel.mode-coach #cpVoice{display:inline-flex;align-items:center}
#copilotPanel.mode-coach #cpVoice.on{background:#fff;color:#4338ca;border-color:#fff}
.cp-voice-row{margin-top:8px}
.cp-listen{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--border,#e8ecf1);background:#fff;color:var(--ink2,#3a4252);border-radius:999px;padding:4px 10px;font-family:inherit;font-size:12px;font-weight:600;cursor:pointer}
.cp-listen .ic{width:14px;height:14px}
.cp-listen.speaking{background:#4338ca;color:#fff;border-color:#4338ca}
.cp-listen.speaking::after{content:"";width:6px;height:6px;border-radius:50%;background:#fff;animation:typingDot 1s infinite}
#copilotPanel .cp-mic{display:none;flex:0 0 auto;width:42px;border:1.5px solid var(--border,#e8ecf1);border-radius:8px;background:#fff;color:var(--ink2,#3a4252);cursor:pointer;align-items:center;justify-content:center}
#copilotPanel.has-mic .cp-mic{display:inline-flex}
#copilotPanel.tour .cp-mic{display:none}
#copilotPanel .cp-mic .ic{width:18px;height:18px}
#copilotPanel .cp-mic.listening{background:#dc2626;border-color:#dc2626;color:#fff;animation:cpPulse 1s infinite}
@keyframes cpPulse{0%,100%{box-shadow:0 0 0 0 rgba(220,38,38,.45)}50%{box-shadow:0 0 0 8px rgba(220,38,38,0)}}
/* Recorded audio is on its way to be transcribed: not listening any more, not idle either. */
#copilotPanel .cp-mic.thinking{background:#eef2ff;border-color:#c7d2fe;color:#4338ca;animation:typingDot 1s infinite}

.nh-steps{display:flex;flex-direction:column;gap:10px;margin-bottom:14px}
.nh-step{display:flex;align-items:center;gap:12px;background:var(--surface,#fff);border:1px solid var(--border);border-radius:12px;padding:11px 12px}
.nh-step-n{flex:none;width:24px;height:24px;border-radius:50%;background:var(--green-light);color:var(--green-dark,#166534);font-weight:800;font-size:12.5px;display:flex;align-items:center;justify-content:center}
.nh-step-t{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.35}
.nh-step-t b{font-size:13.5px;color:var(--ink,#0f172a)}
.nh-step-t span{font-size:11.5px;color:var(--ink3,#8a92a3)}
.nh-step-i{width:20px;height:20px;flex:none;color:#94a3b8;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}

.set-backbar{display:flex;align-items:center;gap:10px;padding:2px 0 14px;font-size:16px;font-weight:800;color:var(--ink)}
.set-back{width:34px;height:34px;border-radius:999px;border:1px solid var(--border);background:#fff;cursor:pointer;font-size:18px;line-height:1;color:var(--ink2)}
.set-subcard{background:linear-gradient(135deg,#2563eb,#1e40af);color:#fff;border-radius:16px;padding:18px;margin-bottom:6px}
.set-subcard .set-sc-t{font-size:15px;font-weight:800}
.set-subcard .set-sc-d{font-size:12.5px;opacity:.85;margin:2px 0 12px}
.set-subcard button{background:#fff;color:var(--green);border:none;border-radius:999px;padding:9px 18px;font-size:13px;font-weight:700;cursor:pointer}
.set-grp-label{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--ink3);margin:20px 4px 8px}
.set-grp{background:#fff;border:1px solid var(--border);border-radius:14px;overflow:hidden}
.set-row{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:14px 16px;border:none;border-bottom:1px solid var(--border);background:#fff;cursor:pointer;font:inherit;color:var(--ink)}
.set-row:last-child{border-bottom:none}
.set-row:hover{background:rgba(37,99,235,.05)}
.set-ico{width:30px;height:30px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;font-size:16px}
.set-ico svg{width:18px;height:18px;display:block;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ic-blue{background:rgba(37,99,235,.12);color:#2563eb}
.ic-purple{background:rgba(124,58,237,.13);color:#7c3aed}
.ic-teal{background:rgba(13,148,136,.15);color:#0d9488}
.ic-green{background:rgba(5,150,105,.15);color:#059669}
.ic-amber{background:rgba(217,119,6,.16);color:#c2710c}
.ic-pink{background:rgba(219,39,119,.13);color:#db2777}
.ic-slate{background:rgba(100,116,139,.18);color:#64748b}
.set-main{flex:1;min-width:0}
.set-title{font-size:14px;font-weight:600}
.set-val{font-size:13px;color:var(--ink3);margin-right:6px}
.set-chev{color:var(--ink3);font-size:18px;flex-shrink:0}
.set-wallet{background:#fff;border:1px solid var(--border);border-radius:14px;padding:16px}
.set-wa-head{display:flex;justify-content:space-between;align-items:center}
.set-wa-t{font-size:14px;font-weight:700;color:var(--ink)}
.set-wa-head button{background:var(--green);color:#fff;border:none;border-radius:999px;padding:7px 14px;font-size:12.5px;font-weight:700;cursor:pointer}
.set-wa-amt{font-size:30px;font-weight:800;color:var(--ink);margin:8px 0 4px}
.set-wa-amt .cur{font-size:18px;color:var(--ink3);margin-right:2px}
.set-wa-hist{font-size:12.5px;color:var(--green);font-weight:600;cursor:pointer}
.brand-box{border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:22px;background:#fafbfc}
.brand-box-t{font-size:13px;font-weight:800;color:var(--ink);margin-bottom:14px;display:flex;align-items:center;gap:6px}
.brand-box .brand-sec:last-of-type{margin-bottom:14px}
.brand-sec{margin-bottom:22px}
.brand-sec-t{font-size:14px;font-weight:700;color:var(--ink);margin-bottom:2px}
.brand-sec-sub{font-size:12px;color:var(--ink3);margin-bottom:10px}
.brand-file{display:flex;align-items:center;gap:12px;border:1px solid var(--border);border-radius:12px;padding:12px;background:#fff}
.brand-file.empty{justify-content:center;color:var(--ink3);font-size:13px;border-style:dashed;padding:22px;text-align:center}
.brand-file-img{width:44px;height:44px;border-radius:8px;object-fit:contain;background:#f6f8fa;border:1px solid var(--border)}
.brand-file-main{flex:1;min-width:0}
.brand-file-name{font-size:13.5px;font-weight:600;color:var(--ink)}
.brand-file-sub{font-size:12px;color:var(--ink3)}
.brand-file-x{width:28px;height:28px;border-radius:999px;border:1px solid var(--border);background:#f6f8fa;cursor:pointer;color:var(--ink3);flex-shrink:0}
.brand-btns{display:flex;gap:10px;margin-top:10px}.brand-btns .btn{flex:1}
.brand-usage{display:flex;gap:12px}
.brand-ucard{flex:1;border:1.5px solid var(--border);border-radius:12px;padding:14px;background:#fff;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:8px;font:inherit}
.brand-ucard.sel{border-color:var(--green);background:rgba(37,99,235,.05)}
.brand-prev{width:54px;height:54px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:18px;overflow:hidden}
.brand-prev img{max-width:100%;max-height:100%;object-fit:contain}
.brand-prev.t{background:repeating-conic-gradient(#e8ecf1 0 25%, #fff 0 50%) 50%/16px 16px;color:var(--ink)}
.brand-prev.b{background:#111;color:#fff}
.brand-ulbl{font-size:12.5px;font-weight:600;color:var(--ink)}
.brand-colors{display:flex;gap:12px}
.brand-ccard{flex:1;display:flex;align-items:center;gap:10px;border:1px solid var(--border);border-radius:12px;padding:10px 12px;background:#fff;cursor:pointer}
.brand-ccard input[type=color]{width:34px;height:34px;border:none;background:none;padding:0;cursor:pointer}
.brand-cinfo{display:flex;flex-direction:column;min-width:0}
.brand-cinfo .bcl{font-size:12px;color:var(--ink3)}
.brand-cinfo .bcv{font-size:13px;font-weight:700;color:var(--ink)}
.branch-row{display:flex;align-items:center;gap:10px;padding:12px;border:1px solid var(--border);border-radius:10px;margin-bottom:8px;cursor:pointer;background:#fff}
.branch-row:last-child{margin-bottom:0}
.branch-row:hover{background:rgba(37,99,235,.05)}
.off-subtabs{display:flex;gap:8px;margin-bottom:16px}
.off-subtab{flex:1;border:1px solid var(--border);background:#fff;border-radius:10px;padding:9px;font-size:13px;font-weight:700;color:var(--ink3);cursor:pointer;font-family:inherit}
.off-subtab.active{background:var(--green);color:#fff;border-color:var(--green)}
.train-tabs{display:flex;gap:8px;margin-bottom:18px;overflow-x:auto;padding-bottom:2px}
/* These strips scroll sideways (four screens use them, and on a phone ~190px of tabs
   sit off the right edge). Without a visible scrollbar the row reads as cut off rather
   than swipeable, so show a thin one instead of the platform default of none. */
.train-tabs{scrollbar-width:thin;scrollbar-color:var(--border) transparent}
.train-tabs::-webkit-scrollbar{height:3px}
.train-tabs::-webkit-scrollbar-track{background:transparent}
.train-tabs::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}
/* "Website URL / Upload Photo / Fill Manually". Three columns is right on a laptop and
   wrong on a phone — at 360-410px each button is ~112px and every label wraps to three
   lines. One per row below 640px; they are full-width targets, which is what a thumb
   wants anyway. */
.train-methods{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:20px}
@media (max-width:640px){ .train-methods{grid-template-columns:1fr;gap:9px} }
/* The remaining fixed-column grids, moved out of inline styles for the same reason:
   an inline grid-template-columns cannot be reached by a media query, so a row that
   stops fitting can only be fixed by editing markup. Classing them means a future
   label change is a CSS fix rather than a silent break.
   Measured before choosing breakpoints — four columns give 76px cells at 360px and
   65px at 320px, where "Asked (30d)" and "This week" wrap; two columns clear both and
   double the thumbnail size in the image picker. The three-column stat rows measure
   clean all the way down to 320px, so they keep their three columns. */
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
@media (max-width:640px){ .grid-4{grid-template-columns:repeat(2,1fr)} }
/* Settings -> Account plan cards. The sweep above missed this one and it was the
   worst offender: two 20px-padded pricing cards cannot fit 375px, so at phone width
   the PRO card rendered 53px PAST THE VIEWPORT EDGE - unreadable and untappable -
   while its section card overflowed by 69px and the buttons wrapped to three lines.
   minmax(0,1fr) not 1fr: plain 1fr means minmax(auto,1fr), whose auto floor is
   min-content, so the tracks refuse to shrink below the widest unbreakable word and
   burst the container instead. That is what produced the 93px overflow. */
/* Brief highlight on a deep-link target: without it a scrolled-to section looks
   identical to a screen that just happened to open there. */
@keyframes navFlash { 0%,100% { box-shadow:0 0 0 0 rgba(37,99,235,0); } 25%,60% { box-shadow:0 0 0 3px rgba(37,99,235,.35); } }
.nav-flash { animation: navFlash 1.5s ease; border-radius:12px; }
.plan-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}
/* The last inline grid in the app, classed to close the category rather than
   because it was broken: two logo tiles measure a clean 150px each at 375px, and
   two-up is right for a gallery you are comparing, so it keeps both columns at
   every width. minmax(0,1fr) so a future tile with a long button label cannot
   burst it the way the plan cards did. */
.logo-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:12px}
@media (max-width:640px){ .plan-grid{grid-template-columns:1fr} .plan-grid>.card{padding:16px} }

/* ── Settings → WhatsApp ─────────────────────────────────────────────────────
   One card shape for every state (connected / paused / needs-attention /
   connecting / awaiting coexistence / none), so the screen can never show a
   green tick and a "Connect a number" button at the same time again. */
.wa-lede{font-size:13px;color:var(--ink3);margin:0 0 14px;line-height:1.55}
.wa-num{display:flex;align-items:center;gap:14px;padding:18px;flex-wrap:wrap}
.wa-av{width:46px;height:46px;border-radius:13px;flex:none;display:grid;place-items:center;background:#16a34a16;color:#16a34a}
.wa-av.is-paused{background:var(--orange-light);color:#b45309}
.wa-av.is-err{background:var(--red-light);color:var(--red)}
.wa-av.is-idle{background:#eef1f6;color:var(--ink3)}
.wa-av .ic{width:23px;height:23px}
.wa-meta{flex:1;min-width:170px}
.wa-name{font-size:15px;font-weight:800;letter-spacing:-.01em;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.wa-sub{font-size:12.5px;color:var(--ink3);margin-top:3px;font-variant-numeric:tabular-nums}
.wa-pill{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:800;padding:3px 9px;border-radius:999px;white-space:nowrap}
.wa-pill i{width:6px;height:6px;border-radius:50%;background:currentColor;display:block}
.wa-pill.ok{background:#16a34a16;color:#15803d}
.wa-pill.warn{background:var(--orange-light);color:#b45309}
.wa-pill.err{background:var(--red-light);color:#b91c1c}
.wa-pill.info{background:var(--green-light);color:var(--green-dark)}
/* "Connected" alone never said whether anything was actually working. */
.wa-strip{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--border)}
.wa-strip>div{padding:13px 10px;text-align:center;border-right:1px solid var(--border)}
.wa-strip>div:last-child{border-right:0}
.wa-strip .k{font-size:11px;color:var(--ink3);font-weight:600}
.wa-strip .v{font-size:13px;font-weight:800;margin-top:3px}
.wa-strip .v.on{color:#16a34a}.wa-strip .v.off{color:var(--ink3)}.wa-strip .v.warn{color:#b45309}
.wa-note{display:flex;gap:11px;padding:14px 16px;border-top:1px solid var(--border);font-size:12.5px;line-height:1.6;color:var(--ink2)}
.wa-note .ic{width:17px;height:17px;flex:none;margin-top:1px}
.wa-note b{color:var(--ink)}
.wa-note.warn{background:#fffbeb;border-top-color:#fde68a;color:#78350f}
.wa-note.err{background:#fef2f2;border-top-color:#fecaca;color:#7f1d1d}
.wa-acts{display:flex;gap:9px;padding:14px 18px;border-top:1px solid var(--border);flex-wrap:wrap;align-items:center}
.wa-acts .wa-spacer{flex:1}
.wa-empty{padding:34px 20px;text-align:center}
.wa-empty .wa-eico{width:54px;height:54px;border-radius:16px;margin:0 auto 13px;display:grid;place-items:center;background:var(--green-light);color:var(--green)}
.wa-empty .wa-eico .ic{width:26px;height:26px}
.wa-empty h3{margin:0 0 6px;font-size:16px;font-weight:800}
.wa-empty p{margin:0 auto 17px;font-size:13px;color:var(--ink3);max-width:390px;line-height:1.6}
.wa-empty .wa-erow{display:flex;gap:9px;justify-content:center;flex-wrap:wrap}
.wa-empty .wa-ehelp{max-width:430px;margin:19px auto 0;padding-top:16px;border-top:1px solid var(--border);text-align:left;display:grid;gap:11px}
.wa-empty .wa-ehelp>div{display:flex;gap:10px;font-size:12.5px;line-height:1.6;color:var(--ink2)}
.wa-empty .wa-ehelp .ic{width:16px;height:16px;flex:none;margin-top:2px;color:var(--green)}
.wa-empty .wa-ehelp b{color:var(--ink)}
/* The connect dialog (8 Oct 2026): the number from the profile, then one question with three
   answers. Each answer is a whole button, so the tap target is the sentence, not a word. */
#whatsappModal .wac-intro{margin:8px 0 14px;font-size:13px;line-height:1.5;color:var(--ink2)}
/* The suggested number is something to CONFIRM (owner, 8 Oct: it "looks plain and user may miss
   to change it"): a tinted card, the number large, where it came from, a real Change button, and
   the question asked outright. */
#whatsappModal .wac-number{border:1.5px solid #c9dafb;border-radius:14px;padding:14px;margin:0 0 18px;background:#f5f8ff}
#whatsappModal .wac-nrow{display:flex;align-items:center;gap:12px}
#whatsappModal .wac-ico-num{background:#e6f6ec;color:#15803d}
#whatsappModal .wac-ntxt{flex:1;min-width:0}
#whatsappModal .wac-k{font-size:11px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--ink3)}
#whatsappModal .wac-show{margin-top:2px}
#whatsappModal .wac-show b{font-size:21px;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums;letter-spacing:.3px}
#whatsappModal .wac-srcrow{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 10px;margin-top:3px}
#whatsappModal .wac-src{font-size:12px;color:var(--ink3);font-variant-numeric:tabular-nums}
#whatsappModal .wac-link{border:none;background:none;padding:0;font:inherit;font-size:12px;font-weight:700;color:var(--green);cursor:pointer;text-decoration:underline;text-underline-offset:2px}
#whatsappModal .wac-change{flex:none;white-space:nowrap;background:var(--surface)}
#whatsappModal .wac-change .ic{width:14px;height:14px}
#whatsappModal .wac-edit{display:flex;gap:8px;align-items:stretch;margin-top:6px}
#whatsappModal .wac-field{display:flex;flex:1;min-width:0}
#whatsappModal .wac-edit .btn{flex:none}
#whatsappModal .wac-edit .btn:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
#whatsappModal .wac-show[hidden],#whatsappModal .wac-edit[hidden],#whatsappModal .wac-change[hidden],#whatsappModal .wac-link[hidden],#whatsappModal .wac-note[hidden],#whatsappModal .wac-err[hidden]{display:none}
#whatsappModal .wac-cc{display:flex;align-items:center;padding:0 11px;border:1px solid var(--border);border-right:none;border-radius:10px 0 0 10px;background:var(--surface);font-weight:700;color:var(--ink2)}
#whatsappModal .wac-edit input{flex:1;min-width:0;border-radius:0 10px 10px 0;font-family:var(--font);font-size:16px;font-weight:700;letter-spacing:.5px;font-variant-numeric:tabular-nums}
#whatsappModal .wac-ask{display:flex;gap:9px;align-items:flex-start;margin-top:12px;padding-top:11px;border-top:1px dashed #c9dafb;font-size:12.5px;line-height:1.5;color:var(--ink2)}
#whatsappModal .wac-ask .ic{flex:none;width:16px;height:16px;margin-top:2px;color:#b45309}
#whatsappModal .wac-ask b{color:var(--ink)}
@media (max-width:480px){#whatsappModal .wac-nrow{flex-wrap:wrap}#whatsappModal .wac-change{width:100%;justify-content:center}}
#whatsappModal .wac-paths{display:grid;gap:8px;margin-top:6px}
/* Three answers that read as three DIFFERENT things (owner, 8 Oct: "all are different options so
   make it so it looks different"): each has its own icon and colour, and a radio that fills. */
#whatsappModal .wac-path{display:flex;align-items:center;gap:12px;width:100%;text-align:left;border:1.5px solid #dfe5ee;border-radius:14px;background:var(--surface);padding:12px 14px;cursor:pointer;font:inherit;color:var(--ink);box-shadow:0 1px 2px rgba(15,23,42,.06);transition:border-color .15s,background .15s,box-shadow .15s}
#whatsappModal .wac-ico{flex:none;width:40px;height:40px;border-radius:12px;display:grid;place-items:center}
#whatsappModal .wac-ico .ic{width:20px;height:20px}
#whatsappModal .wac-path[data-path="app"] .wac-ico{background:#e6f6ec;color:#15803d}
#whatsappModal .wac-path[data-path="fresh"] .wac-ico{background:#e8f0ff;color:#2563eb}
#whatsappModal .wac-path[data-path="api"] .wac-ico{background:#f1eaff;color:#7c3aed}
#whatsappModal .wac-txt{flex:1;min-width:0}
#whatsappModal .wac-txt b{display:block;font-size:14px}
#whatsappModal .wac-txt em{display:block;font-style:normal;font-size:12.5px;line-height:1.45;color:var(--ink3);margin-top:2px}
#whatsappModal .wac-radio{flex:none;width:20px;height:20px;border-radius:50%;border:2px solid #c3ccd9;display:grid;place-items:center;background:var(--surface);transition:border-color .15s}
#whatsappModal .wac-radio::after{content:'';width:10px;height:10px;border-radius:50%;background:var(--green);transform:scale(0);transition:transform .15s}
#whatsappModal .wac-path:hover{border-color:#b6c6e6;box-shadow:0 3px 10px rgba(15,23,42,.08)}
#whatsappModal .wac-path:focus-visible{outline:2px solid var(--green);outline-offset:2px}
#whatsappModal .wac-path[aria-checked="true"]{border-color:var(--green);background:var(--green-light);box-shadow:0 0 0 3px rgba(37,99,235,.12)}
#whatsappModal .wac-path[aria-checked="true"] .wac-radio{border-color:var(--green)}
#whatsappModal .wac-path[aria-checked="true"] .wac-radio::after{transform:scale(1)}
@media (prefers-reduced-motion:reduce){#whatsappModal .wac-path,#whatsappModal .wac-radio,#whatsappModal .wac-radio::after{transition:none}}
#whatsappModal .wac-err{margin-top:8px;font-size:12.5px;font-weight:600;color:#b91c1c}
#whatsappModal .wac-note{margin:0 0 14px;padding:12px 14px;border-radius:10px;font-size:13px;line-height:1.55}
#whatsappModal .wac-note.is-app{background:#fff8e6;border:1px solid #f0c36d;color:#7a5b00}
#whatsappModal .wac-note.is-api{background:#eef4ff;border:1px solid #9db8e8;color:#1a3a6b}
#whatsappModal .wac-small{display:block;margin-top:8px;font-size:11.5px}
#whatsappModal .wac-fork{display:flex;gap:8px;margin-top:10px}
#whatsappModal .wac-fork .btn{flex:1;font-size:13px}
#whatsappModal .modal-actions .btn[hidden]{display:none}
.wa-foot{font-size:12px;color:var(--ink3);text-align:center;margin-top:10px;line-height:1.6}
@media (max-width:640px){
  .wa-strip{grid-template-columns:1fr}
  .wa-strip>div{border-right:0;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;text-align:left;padding:11px 16px}
  .wa-strip>div:last-child{border-bottom:0}
  .wa-strip .v{margin-top:0}
  .wa-acts .btn{flex:1;justify-content:center}
  .wa-acts .wa-spacer{display:none}
}
/* Free-text boxes on Train your AI. One class instead of six copies of an
   inline style — and the two properties those copies were missing are the ones
   that made saved text hard to read: no font-family (a bare textarea falls back
   to the browser's monospace, unlike every input around it) and no line-height.
   Height is managed by trainGrow(): rows= is only the floor, the box grows with
   its content up to max-height and then scrolls. */
.train-grow{width:100%;padding:10px 14px;border:1.5px solid var(--border);border-radius:8px;font-size:14px;background:#fafbfc;resize:vertical;font-family:inherit;color:var(--ink);line-height:1.55;min-height:58px;max-height:340px;overflow-y:auto}
.train-grow:focus{outline:none;border-color:var(--green);background:#fff}
.train-tab{flex:0 0 auto;border:1px solid var(--border);background:#fff;border-radius:999px;padding:8px 16px;font-size:13px;font-weight:700;color:var(--ink3);cursor:pointer;font-family:inherit;white-space:nowrap}
.train-tab.active{background:var(--green);color:#fff;border-color:var(--green)}
.bset-row{display:flex;align-items:center;gap:12px;padding:13px 2px;border-bottom:1px solid var(--border)}
.bset-row:last-child{border-bottom:none}
.bset-main{flex:1;min-width:0}
.bset-t{font-size:14px;font-weight:600;color:var(--ink)}
.bset-s{font-size:12.5px;color:var(--ink3);margin-top:2px}
.gsw{position:relative;display:inline-block;width:44px;height:26px;flex:0 0 auto;cursor:pointer}
.gsw input{opacity:0;width:0;height:0;position:absolute}
.gsw-track{position:absolute;inset:0;background:var(--border);border-radius:999px;transition:background .2s}
.gsw-track::before{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.gsw input:checked + .gsw-track{background:var(--green)}
.gsw input:checked + .gsw-track::before{transform:translateX(18px)}
.inv-head{display:grid;grid-template-columns:1fr 60px 90px 26px;gap:8px;font-size:10.5px;font-weight:700;color:var(--ink3);text-transform:uppercase;letter-spacing:.03em;padding:0 2px 7px}
.inv-row{display:grid;grid-template-columns:1fr 60px 90px 26px;gap:8px;align-items:center;margin-bottom:8px}
.inv-row input{border:1px solid var(--border);border-radius:8px;padding:9px 10px;font-size:13.5px;font-family:inherit;width:100%}
.inv-del{border:none;background:none;color:var(--red,#dc2626);cursor:pointer;font-size:15px;padding:2px}
.inv-tot{display:flex;justify-content:space-between;align-items:center;padding:7px 0;font-size:14px;color:var(--ink2)}
.inv-tot-grand{border-top:1.5px solid var(--border);margin-top:4px;padding-top:12px;font-size:17px;font-weight:800;color:var(--ink)}
.inv-lrow{display:flex;align-items:center;gap:10px;padding:12px 2px;border-bottom:1px solid var(--border)}
.inv-lrow:last-child{border-bottom:none}
.inv-lrow-main{flex:1;min-width:0}
.inv-lrow-t{font-size:14px;font-weight:600;color:var(--ink)}
.inv-lrow-sub{font-size:12px;color:var(--ink3);margin-top:2px}
.inv-badge{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;text-transform:capitalize}
.inv-badge.paid{background:#dcfce7;color:#15803d}
.inv-badge.unpaid{background:#fef9c3;color:#a16207}
.inv-badge.partial{background:#e0f2fe;color:#0369a1}
.pref-opt{display:block;width:100%;text-align:left;padding:12px 14px;border:1px solid var(--border);border-radius:10px;background:#fff;margin-bottom:8px;font-size:14px;font-weight:600;color:var(--ink);cursor:pointer;font-family:inherit}
.pref-opt.on{border-color:var(--green);color:var(--green)}
/* Dark mode — overrides the themeable CSS variables + the most common inline-light surfaces. */
.dark{
  --bg:#0e1320; --surface:#171d2b; --nav-bg:#0b1020;
  --ink:#e7ecf3; --ink2:#aeb9c9; --ink3:#8693a6; --border:#28324a;
  --shadow-sm:0 1px 2px rgba(0,0,0,.3); --shadow-md:0 4px 12px rgba(0,0,0,.4); --shadow-lg:0 8px 24px rgba(0,0,0,.5);
}
.dark body{background:var(--bg);color:var(--ink)}
.dark .card,.dark .set-row,.dark .set-wallet,.dark .set-subcard,.dark .pref-opt,.dark .cats-sheet,.dark .brand-box{background:var(--surface);border-color:var(--border)}
.dark input:not([type=color]):not([type=checkbox]),.dark textarea,.dark select{background:#1f2738!important;color:var(--ink)!important;border-color:var(--border)!important}
.dark [style*="background:#fafbfc"]{background:#1f2738!important}
.dark [style*="background:#fff"]:not(img):not(.gsw-track){background:var(--surface)!important}
.off-chips{display:flex;flex-wrap:wrap;gap:8px}
.off-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(37,99,235,.08);color:var(--green);border:1px solid rgba(37,99,235,.22);border-radius:999px;padding:6px 12px;font-size:13px;font-weight:600}
.off-chip button{border:none;background:none;color:var(--green);cursor:pointer;font-size:13px;padding:0;line-height:1}
.off-brochure{display:flex;align-items:center;gap:12px;border:1px solid var(--border);border-radius:10px;padding:12px}
.off-brochure.empty{justify-content:center;color:var(--ink3);font-size:13px;border-style:dashed;padding:18px;text-align:center}
.topbar-gear{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:10px;border:1px solid var(--border);background:#fff;color:var(--ink2);cursor:pointer;padding:0;flex-shrink:0}
.topbar-gear svg{width:20px;height:20px}
.topbar-gear:hover{background:#f6f8fa}
.topbar-gear.active{color:var(--green);border-color:var(--green);background:rgba(37,99,235,.06)}
/* Notification bell dropdown. Its positioning lives HERE rather than inline so the
   phone media query below can override it — inline styles would otherwise win. */
.notif-panel{position:absolute;top:calc(100% + 8px);right:0;width:340px;max-width:86vw;max-height:460px;overflow:auto;background:var(--card,#fff);border:1px solid var(--border);border-radius:14px;box-shadow:0 12px 32px rgba(0,0,0,.16);z-index:120}
.notif-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;border-bottom:1px solid var(--border);position:sticky;top:0;background:var(--card,#fff)}
/* On phones anchor it to the VIEWPORT instead of the bell (same treatment as
   #copilotPanel): a 340px menu hung off a button near the right edge runs off-screen. */
@media (max-width:480px){
  .notif-panel{position:fixed;top:calc(var(--topbar-h) + 6px);left:10px;right:10px;width:auto;max-width:none}
  /* Four controls plus a spelled-out "Upgrade" leave the title ~35px at 360px (it was
     wrapping the bar onto two lines). Drop to the icon, exactly as .askai-lbl does. */
  .upg-lbl{display:none}
  .btn-upgrade{padding:8px 11px}
  /* Reclaim the last few px so "GBP · Overview" fits without an ellipsis at 360px. */
  .topbar{padding:0 12px}
  .topbar-right{gap:8px}
  .topbar-left{gap:8px}
}
.cats-overlay{position:fixed;inset:0;background:rgba(26,26,46,.5);z-index:1200;opacity:0;visibility:hidden;transition:opacity .2s,visibility .2s}
.cats-overlay.show{opacity:1;visibility:visible}
.cats-sheet{position:fixed;left:50%;bottom:0;transform:translate(-50%,100%);width:100%;max-width:520px;background:#fff;border-radius:18px 18px 0 0;padding:20px 20px 26px;z-index:1210;max-height:90vh;overflow-y:auto;transition:transform .28s cubic-bezier(.22,1,.36,1);box-shadow:0 -10px 50px rgba(0,0,0,.2);pointer-events:none}
.cats-sheet.show{transform:translate(-50%,0);pointer-events:auto}
@media(min-width:760px){.cats-sheet{bottom:auto;top:50%;transform:translate(-50%,-46%);border-radius:18px;opacity:0;transition:transform .25s ease,opacity .2s}.cats-sheet.show{transform:translate(-50%,-50%);opacity:1}}
.cats-sheet h3{font-size:17px;font-weight:800;margin:0 0 16px;display:flex;justify-content:space-between;align-items:center;color:var(--ink)}
.cats-field{margin-bottom:12px}
.cats-hint{font-size:11.5px;color:var(--ink3);margin-top:5px;line-height:1.5}
.cats-field label{display:block;font-size:12px;font-weight:600;color:var(--ink3);margin-bottom:6px}
.cats-field input,.cats-field select,.cats-field textarea{width:100%;border:1px solid var(--border);border-radius:10px;padding:11px 12px;font-size:14px;font-family:inherit;color:var(--ink);background:#fbfcfd;box-sizing:border-box}
.cats-field input:focus,.cats-field select:focus,.cats-field textarea:focus{outline:none;border-color:var(--green);background:#fff}
.cats-field textarea{resize:vertical;min-height:60px}
.cats-row2{display:flex;gap:10px}.cats-row2>.cats-field{flex:1}
.cats-x{width:30px;height:30px;border-radius:999px;border:1px solid var(--border);background:#f6f8fa;cursor:pointer;font-size:14px;color:var(--ink3);line-height:1}
.cats-save{width:100%;border:none;border-radius:10px;padding:13px;font-size:15px;font-weight:700;color:#fff;background:var(--green);cursor:pointer;margin-top:6px}
.cats-del{color:#dc2626;background:none;border:none;font-size:13px;cursor:pointer;margin-top:8px;width:100%;padding:8px;font-weight:600}
.cats-chk{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink2);cursor:pointer}
.cats-chk input{width:auto}

  /* Redesigned Products & Services (catalog) — grouped, selectable rows + merged categories */
  .pc-toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:12px}
  .pc-search{flex:1;min-width:170px;position:relative}
  .pc-search svg{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--ink3)}
  .pc-search input{width:100%;font:inherit;font-size:14px;color:var(--ink);background:var(--surface,#fff);border:1.5px solid var(--border);border-radius:11px;padding:10px 12px 10px 36px}
  .pc-search input:focus{outline:none;border-color:#0877E8}
  .pc-btn{font:inherit;font-size:13.5px;font-weight:700;border-radius:11px;padding:10px 15px;cursor:pointer;display:inline-flex;align-items:center;gap:7px;white-space:nowrap;border:1.5px solid transparent}
  .pc-btn svg{width:16px;height:16px}
  .pc-btn-primary{background:#0877E8;color:#fff}
  .pc-btn-primary:hover{background:#0768cf}
  .pc-btn-outline{background:var(--surface,#fff);color:var(--ink2);border-color:var(--border)}
  .pc-btn-outline:hover{border-color:#0877E8;color:#0763bd}
  .pc-chips{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px;align-items:center}
  .pc-chip{font:inherit;font-size:12.5px;font-weight:650;color:var(--ink2);background:var(--surface,#fff);border:1px solid var(--border);border-radius:999px;padding:7px 13px;cursor:pointer;display:inline-flex;gap:6px;align-items:center}
  .pc-chip:hover{border-color:#0877E8}
  .pc-chip.on{background:#0877E8;border-color:#0877E8;color:#fff}
  .pc-ccnt{font-size:11px;font-weight:800;opacity:.65}
  .pc-chip.add{color:#0763bd;border-style:dashed;border-color:rgba(8,119,232,.4);background:rgba(8,119,232,.05)}
  #catAddRow{display:none;gap:8px;margin:-4px 0 14px;flex-wrap:wrap}
  #catAddRow input{font:inherit;font-size:13.5px;border:1.5px solid var(--border);border-radius:10px;padding:9px 12px;min-width:180px;background:var(--surface,#fff);color:var(--ink)}
  #catAddRow input:focus{outline:none;border-color:#0877E8}
  .pc-group{margin-bottom:16px}
  .pc-ghead{display:flex;align-items:center;gap:10px;padding:6px 2px 10px;cursor:pointer;user-select:none}
  .pc-chev{width:15px;height:15px;color:var(--ink3);transition:transform .18s;flex:none}
  .pc-group.pc-collapsed .pc-chev{transform:rotate(-90deg)}
  .pc-gname{font-size:12.5px;font-weight:800;letter-spacing:.02em;color:var(--ink);text-transform:uppercase}
  .pc-gcnt{font-size:11px;font-weight:700;color:var(--ink3);background:var(--chip,#f1f5fa);border:1px solid var(--border);border-radius:999px;padding:2px 8px}
  .pc-gact{margin-left:auto;display:flex;gap:2px;align-items:center;flex-wrap:wrap}
  .pc-gbtn{font:inherit;font-size:12px;font-weight:700;color:#0763bd;background:transparent;border:none;cursor:pointer;padding:5px 9px;border-radius:8px}
  .pc-gbtn:hover{background:rgba(8,119,232,.08)}
  .pc-gbtn.del{color:var(--ink3)}
  .pc-gbtn.del:hover{background:rgba(220,38,38,.08);color:#dc2626}
  .pc-rows{display:flex;flex-direction:column;gap:8px}
  .pc-group.pc-collapsed .pc-rows{display:none}
  .pc-row{display:flex;align-items:center;gap:13px;background:var(--surface,#fff);border:1px solid var(--border);border-radius:13px;padding:12px 14px;cursor:pointer;transition:.14s}
  .pc-row:hover{border-color:#0877E8;box-shadow:0 6px 18px -12px rgba(8,119,232,.5);transform:translateY(-1px)}
  .pc-ric{width:36px;height:36px;border-radius:10px;flex:none;display:grid;place-items:center;background:rgba(8,119,232,.1);color:#0877E8}
  .pc-ric svg{width:18px;height:18px}
  .pc-rmain{flex:1;min-width:0}
  .pc-rname{font-size:14px;font-weight:700;color:var(--ink)}
  .pc-rsub{font-size:12px;color:var(--ink3);margin-top:2px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
  .pc-dur{display:inline-flex;gap:4px;align-items:center}
  .pc-pill{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;color:#dc2626;background:rgba(220,38,38,.1)}
  /* Live Inventory (docs/live-inventory.md): a part's stock or a listing's status, and how
     old its price or last check is; amber once it is older than the business type allows. */
  .pc-st{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
  .pc-st.in_stock,.pc-st.available{color:#0f9d6e;background:rgba(15,157,110,.12)}
  .pc-st.out_of_stock,.pc-st.let,.pc-st.sold{color:var(--ink3);background:rgba(125,135,155,.14)}
  .pc-st.under_offer{color:#b45309;background:rgba(180,83,9,.12)}
  .pc-asof{display:inline-flex;gap:4px;align-items:center}
  .pc-asof.old{color:#b45309;font-weight:600}
  .pc-rprice.pc-gone{color:var(--ink3);text-decoration:line-through}
  .pc-chip-sep{width:1px;align-self:stretch;background:var(--border);margin:2px 4px}
  .cats-asof{font-size:12px;color:var(--ink3);margin:-4px 0 12px}
  .cats-asof.old{color:#b45309;font-weight:600}
  .pc-note{color:#b45309;font-weight:600}
  /* Live Inventory, the day's update (js/live-inventory.js): the strip above the list, and the
     sheet that reads the day's list and shows only what it changes. */
  .liv-strip{display:flex;align-items:center;gap:12px;flex-wrap:wrap;border-radius:12px;padding:11px 14px;margin:0 0 14px;font-size:13px;line-height:1.5}
  /* The weekly check on each listing (Live Inventory step 5): one tap, and the row stays put. */
  .liv-seg{margin-top:8px;max-width:420px;flex-wrap:wrap}
  .liv-seg .seg-btn{flex:1 1 auto;padding:5px 8px;font-size:12px;min-height:32px;white-space:nowrap}
  /* The daily count on each batch (Live Inventory step 6b): one number, confirmed in place. */
  .liv-seats{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap;font-size:12.5px;color:var(--ink2)}
  .liv-seats label{display:flex;align-items:center;gap:6px;font-weight:600}
  .liv-seats input{width:72px;min-height:32px;padding:4px 8px;border:1px solid var(--border);border-radius:8px;font:inherit;color:var(--ink);background:var(--card,#fff)}
  .liv-seats .btn{min-height:32px;padding:5px 12px;font-size:12px}
  .liv-strip>.ic{width:18px;height:18px;flex:none}
  .liv-strip>div{flex:1;min-width:220px}
  .liv-strip.warn{background:#fff7ed;border:1px solid #fed7aa;color:#9a3412}
  .liv-strip.due{background:#fffbeb;border:1px solid #fde68a;color:#92400e}
  .liv-strip.ok{background:#ecfdf5;border:1px solid #a7f3d0;color:#065f46}
  .dark .liv-strip.warn{background:#2a1d10;border-color:#7c2d12;color:#fdba74}
  .dark .liv-strip.due{background:#2a2410;border-color:#78591a;color:#fcd34d}
  .dark .liv-strip.ok{background:#0f2a1f;border-color:#065f46;color:#6ee7b7}
  .liv-sacts{display:flex;gap:8px;flex-wrap:wrap}
  .liv-sub{font-size:12.5px;color:var(--ink3);margin:4px 0 10px;line-height:1.5}
  .liv-err{font-size:12.5px;color:#dc2626;margin:8px 0 0}
  .liv-ta{width:100%;border:1px solid var(--border);border-radius:10px;padding:10px 12px;font:500 13px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:var(--surface,#fff);color:var(--ink);resize:vertical}
  .liv-foot{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:14px}
  @media(max-width:560px){.liv-foot{flex-direction:column-reverse}.liv-foot .btn{width:100%}}
  .liv-scan{height:6px;border-radius:999px;background:rgba(125,135,155,.18);overflow:hidden;margin:14px 0 6px}
  .liv-scan i{display:block;height:100%;width:40%;background:var(--green);animation:catsScan 1.1s ease-in-out infinite}
  @media (prefers-reduced-motion:reduce){.liv-scan i{animation:none}}
  .liv-badges{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 4px}
  .liv-badge{font-size:11px;font-weight:700;border-radius:999px;padding:2px 9px}
  .liv-badge.chg{background:rgba(8,119,232,.1);color:#0763bd}
  .liv-badge.new{background:rgba(15,157,110,.12);color:#0f9d6e}
  .liv-badge.miss{background:rgba(180,83,9,.12);color:#b45309}
  .liv-badge.same{background:rgba(125,135,155,.14);color:var(--ink3)}
  .liv-sec{font-size:13px;font-weight:700;color:var(--ink);margin:14px 0 4px}
  .liv-drow{display:flex;justify-content:space-between;gap:10px;align-items:center;padding:7px 0;border-bottom:1px solid var(--border);font-size:13px}
  .liv-dname{min-width:0;color:var(--ink2);overflow-wrap:anywhere}
  .liv-dname em{font-style:normal;font-size:11px;color:var(--ink3);margin-left:4px}
  .liv-dval{white-space:nowrap;color:var(--ink2)}
  .liv-dval s{color:var(--ink3)}
  .liv-muted{color:var(--ink3)}
  .liv-delta{font-size:11.5px;font-weight:700;margin-left:4px}
  .liv-delta.up{color:#b45309}
  .liv-delta.down{color:#2563eb}
  .liv-back{font-size:11px;font-weight:700;color:#0f9d6e;margin-left:4px}
  .liv-seg{margin-top:10px;max-width:460px;flex-wrap:wrap}
  .liv-seg .seg-btn{white-space:nowrap;font-size:12px;min-height:32px}
  /* The daily card on Home (step 3). */
  .liv-hcard{display:flex;flex-wrap:wrap;gap:12px;align-items:center;justify-content:space-between;border-radius:14px;padding:14px 16px;border:1px solid var(--border);background:var(--surface,#fff)}
  .liv-hcard.warn{border-color:#fed7aa;background:#fff7ed}
  .liv-hcard.due{border-color:#fde68a;background:#fffbeb}
  .dark .liv-hcard.warn{background:#2a1d10;border-color:#7c2d12}
  .dark .liv-hcard.due{background:#2a2410;border-color:#78591a}
  .liv-hmain{min-width:0;flex:1}
  .liv-hbig{font-size:16px;font-weight:800;color:var(--ink)}
  .liv-hsub,.liv-hwarn,.liv-hok{display:flex;gap:5px;align-items:center;font-size:12.5px;margin-top:4px}
  .liv-hsub{color:var(--ink3)}
  .liv-hwarn{color:#9a3412;font-weight:600}
  .liv-hcard.due .liv-hwarn{color:#92400e}
  .dark .liv-hwarn{color:#fdba74}
  .liv-hok{color:#047857;font-weight:600}
  .dark .liv-hok{color:#6ee7b7}
  .liv-hsub .ic,.liv-hwarn .ic,.liv-hok .ic{width:13px;height:13px;flex:none}
  .liv-hacts{display:flex;gap:8px;flex-wrap:wrap}
  .pc-rprice{font-size:15px;font-weight:800;color:var(--ink);white-space:nowrap}
  .pc-rprice .pc-none{font-size:12.5px;font-weight:600;color:var(--ink3)}
  .pc-rprice .pc-unit{font-size:12.5px;font-weight:600;color:var(--ink3)}
  .pc-rchev{color:var(--ink3);flex:none;width:17px;height:17px}
  .pc-addrow{display:flex;align-items:center;gap:8px;padding:11px 14px;border:1.5px dashed var(--border);border-radius:13px;color:#0763bd;font-size:13px;font-weight:700;cursor:pointer;background:rgba(8,119,232,.03)}
  .pc-addrow:hover{border-color:#0877E8;background:rgba(8,119,232,.07)}
  .pc-addrow svg{width:16px;height:16px}
  @keyframes catsScan{0%{transform:translateX(-100%)}100%{transform:translateX(250%)}}
  /* Selecting. The checkbox is a real input so the keyboard and screen readers get it
     for free; the row keeps its own click for opening a product when NOT selecting. */
  .pc-sel{width:19px;height:19px;flex-shrink:0;accent-color:#0877E8;cursor:pointer;margin:0}
  .pc-row.pc-picked{border-color:#0877E8;background:rgba(8,119,232,.06)}
  .pc-bulk{position:sticky;bottom:12px;z-index:20;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
    background:var(--surface,#fff);border:1px solid var(--border);border-radius:14px;padding:11px 14px;
    box-shadow:0 10px 30px -12px rgba(0,0,0,.28);margin-top:14px}
  .pc-bulk-n{font-size:13.5px;font-weight:700;color:var(--ink);margin-right:auto}
  .pc-bulk select{border:1px solid var(--border);border-radius:9px;padding:8px 10px;font-size:13px;font-family:inherit;background:#fbfcfd;color:var(--ink)}
  .pc-danger{border:1px solid #dc2626;color:#dc2626;background:#fff;border-radius:9px;padding:8px 14px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}
  .pc-danger:hover{background:#fef2f2}

/* ── Search & Rank: who is ahead of you ──────────────────────────────────────
   The panel sits above the keyword grid because being outranked is a fact about
   the whole screen, not about whichever keyword happens to be first. Nested under
   one keyword row it read as if it belonged to that row. */
/* THE MOCK'S PALETTE, SCOPED TO THIS SCREEN. The global tokens are the whole app's and
   restyling every screen to match one mock is not what was asked for -- so the rank tab
   overrides them for itself. Same values as #tab-gbp. */
#tab-rank{ --border:#e5e7eb; --ink:#111827; --ink2:#374151; --ink3:#6b7280;
  --green:#16a34a; --red:#b91c1c; --brand:#2563eb; }
/* Each of the three things the mock draws as a named card gets its name. The screen
   rendered all of them into one block, so they read as one panel with text in it. */
/* .rank-sec is gone: "Your keywords" is a gx-shead now, and the three other
   labels it styled became section titles. Removed rather than left behind --
   a class nothing emits is a claim that the screen still works that way. */
.rank-ahead{ background:var(--surface-2,#f7f8fa); border:1px solid var(--border); border-radius:12px; padding:14px; margin-top:12px; }
.rank-ahead.none{ font-size:13px; color:var(--ink3); }
.rank-ahead .ra-t{ font-size:12px; font-weight:800; letter-spacing:.02em; text-transform:uppercase; color:var(--ink3); }
.rank-ahead .ra-s{ font-size:13.5px; margin:4px 0 10px; }
/* THE GAP -- the sentence this panel exists for. It sits BETWEEN the count and the table
   because it answers the question the count raises: 'beaten on 6 of 10' by what? A reader
   who stops after two lines should have stopped on this one, so it gets a surface of its
   own rather than being a third grey paragraph. Numbers carry the weight; the prose does
   not, which is why only <b> darkens. */
.rank-ahead .ra-gap{ font-size:13px; line-height:1.55; color:var(--ink2);
  margin:0 0 10px; padding:9px 11px; border-radius:9px;
  background:var(--surface); border:1px solid var(--border); }
.rank-ahead .ra-gap b{ color:var(--ink); font-weight:700; }
/* .rv-st is display:block inside a .rv-row, where it is the rival's own line. Here it is
   mid-sentence, so it stays inline and takes the same amber the table uses. */
.rank-ahead .ra-gap .rv-st{ display:inline; font-size:12px; color:#b45309; font-weight:600; }
/* Who is beating you -- four columns, because a list of names is a leaderboard and
   the columns are what make it something to act on. Grid rather than a table so the
   name can wrap without dragging the numbers with it. Placement is by ORDER, so the
   movement cell keeps its shared .kw-mv class and still lands in column four. */
.rv-row{ display:grid; grid-template-columns:1fr auto auto auto; gap:10px; align-items:baseline;
  padding:8px 0; border-top:1px solid var(--border); }
.rv-row.head{ border-top:none; font-size:10.5px; font-weight:800; text-transform:uppercase;
  letter-spacing:.03em; color:var(--ink3); padding-bottom:4px; }
/* THREE COLUMNS, NOT AN INLINE RUN. With the chip added, a long rival name ("Digineoteric
   - Digital Marketing Agency") wrapped back to x=0 underneath the chip and broke the
   indent for that row only. A grid pins the index and the chip in their own columns so
   the name and its rating always share the third, however far the name wraps. */
.rv-row .rv-n{ min-width:0; font-size:13.5px; word-break:break-word;
  display:grid; grid-template-columns:16px 26px minmax(0,1fr); gap:0 8px; align-items:start; }
/* The header row has no chip and no index, just the word "Business" -- left on the grid
   it landed in the 16px first column and wrapped one letter per line. */
.rv-row.head .rv-n{ display:block; }
.rv-row .rv-n b{ grid-column:3; font-weight:700; }
.rv-row .rv-n i{ grid-column:1; font-style:normal; font-weight:800; color:var(--ink3);
  font-variant-numeric:tabular-nums; line-height:26px; }
/* AN INITIAL CHIP, so five near-identical lines can be scanned for one name without
   adding a word. The colour is hashed from the NAME, not the index -- row order changes
   between checks, and a colour that moved with position would imply something untrue. */
.rv-row .rv-n .rv-av{ grid-column:2; display:inline-flex; align-items:center;
  justify-content:center; width:26px; height:26px; border-radius:8px;
  font-size:11px; font-weight:800; color:#fff; letter-spacing:.2px; }
/* The rating is amber because that is what a rating looks like; the COUNT beside it stays
   quiet, so the star does not drag the eye to a number that is only context. */
.rv-row .rv-st{ grid-column:3; display:block; font-size:11.5px; color:#b45309;
  font-weight:700; font-variant-numeric:tabular-nums; }
.rv-row .rv-st .rv-rc{ color:var(--ink3); font-weight:600; }
.rv-row .rv-k,
.rv-row .rv-b{ font-size:12.5px; color:var(--ink3); white-space:nowrap;
  font-variant-numeric:tabular-nums; }
.rv-row .rv-b{ font-weight:700; color:var(--ink2, inherit); }
.rv-row.head .rv-k, .rv-row.head .rv-b, .rv-row.head .rv-m{ font-size:10.5px; font-weight:800; }
.rv-row .rv-m{ min-width:44px; text-align:right; }

/* One keyword, expanded -- the whole local pack with the owner's own row sitting in its
   real place among them. "You are #6" above a list of five other businesses makes the
   reader do the arithmetic; one list with their row in it is the same information and
   none of the work. */
.pack{ border:1px solid var(--border); border-radius:12px; overflow:hidden; margin-top:10px; }
.packh{ font-size:10px; font-weight:800; color:var(--ink3); text-transform:uppercase;
  letter-spacing:.05em; padding:8px 13px 4px; }
.pk{ display:flex; align-items:center; gap:8px; padding:6px 13px; font-size:12px; }
.pk i{ font-style:normal; font-weight:800; color:var(--ink3); min-width:16px;
  font-variant-numeric:tabular-nums; }
.pk b{ flex:1; min-width:0; font-weight:600; word-break:break-word; }
.pk .pk-st{ font-size:11px; color:var(--ink3); white-space:nowrap; font-variant-numeric:tabular-nums; }
.pk.took{ background:#fde8e6; }
.pk.you{ background:#e8f0fe; font-weight:700; }
.pk.you b{ font-weight:800; }
/* The two tags are opposites and must never be mistaken for each other at a glance. */
.tg{ font-style:normal; font-size:9px; font-weight:800; background:#d93025; color:#fff;
  border-radius:999px; padding:1px 6px; white-space:nowrap; }
.tg.you{ background:#1a56db; }
.pk .kw-mv{ margin-left:auto; }
.packn{ padding:7px 13px 10px; font-size:11px; color:var(--ink3); line-height:1.5; }

/* The name column carries the most text, so give the numbers room first on a phone. */
@media (max-width:420px){
  .rv-row{ grid-template-columns:1fr auto auto auto; gap:7px; }
  .rv-row .rv-k{ font-size:11.5px; }
}

/* ── Search & Rank: the keyword workspace ───────────────────────────────────
   The suggestion chips carry WHERE a keyword came from, because a term Google
   saw somebody type is evidence and one the model invented is a guess. */
.rank-sugg .rs-n{ display:block; font-size:10px; font-weight:600; opacity:.7; margin-top:1px; }
.rank-sugg.real{ border-color:#16a34a; }

/* Coverage: what people searched against what you watch. Sits under "who is
   ahead" because both are facts about the whole screen, not about one row. */
.rank-cov{ background:var(--surface-2,#f7f8fa); border:1px solid var(--border); border-radius:12px; padding:14px; margin-top:12px; }
.rank-cov.none{ font-size:12.5px; color:var(--ink3); }
/* The zero states. Deliberately NOT green and NOT a tick: "0 ahead of you" with
   nothing checked is an absence of measurement, and colouring it as success is how
   an empty screen starts reading as a won race. */
.rank-ahead .ra-hint{ font-size:12px; color:var(--ink3); margin-top:8px; }
.rank-cov-note{ font-size:12px; color:var(--ink3); margin:6px 0 10px; line-height:1.45; }
/* Three NAMED buckets, each with its own count, as the mock draws them. One panel of
   prose could not say "two of your keywords have never once appeared" as a thing to
   act on -- it read as a statistic about the screen. */
.rank-cov .bk{ border-top:1px solid var(--border); padding:10px 0 8px; }
.rank-cov .bk:first-of-type{ border-top:none; }
.rank-cov .bk b{ font-size:12.5px; display:flex; align-items:center; gap:6px; }
.rank-cov .bk b i{ font-style:normal; font-size:11px; font-weight:800; min-width:18px; text-align:center; border-radius:999px; padding:1px 6px; background:var(--surface-2,#eef0f3); color:var(--ink3); }
.rank-cov .bk.ok b i{ background:#e7f6ec; color:#16a34a; }
.rank-cov .bk.warn b i{ background:#fef3e2; color:#b45309; }
.rank-cov .bk.brand b i{ background:#e8f0fe; color:#1a56db; }
/* An EMPTY bucket keeps the neutral badge it starts with. The three semantic colours
   describe a population, and at zero there is none to describe -- worse, zero means
   the opposite thing in the first bucket from the other two, so colouring them would
   say three different things about one fact. Covers the no-report case too, where
   all three are zero. */
.rank-cov .bk.zero b i{ background:var(--surface-2,#eef0f3); color:var(--ink3); }
/* The area preview. Empty renders nothing at all - :empty rather than a JS branch,
   so a failed lookup cannot leave a stray box behind. */
.rank-cov .bk span{ display:block; font-size:11.5px; color:var(--ink3); margin-top:2px; }
.rank-cov .chips{ display:flex; flex-wrap:wrap; gap:5px; margin-top:7px; }
.rank-cov .chip{ font-size:11.5px; border:1px solid var(--border); border-radius:999px; padding:3px 9px; background:var(--surface); white-space:nowrap; max-width:100%; overflow:hidden; text-overflow:ellipsis; }
.rank-cov .chip.act{ cursor:pointer; border-color:#1a56db; color:#1a56db; font-weight:600; }
.rank-cov .chip.act:hover{ background:#e8f0fe; }

/* One ROW per keyword. Ten cards did not fit a screen; ten rows do, and the row carries
   the whole answer -- rank, movement, how many are ahead, who leads. */
.kw-row{ display:flex; align-items:center; gap:10px; padding:10px 2px; border-top:1px solid var(--border); }
.kw-row:first-child{ border-top:none; }

.kw-b{ flex:1; min-width:0; }
.kw-b b{ display:block; font-size:13.5px; font-weight:700; word-break:break-word; }
.kw-b span{ display:block; font-size:11.5px; color:var(--ink3); margin-top:1px; word-break:break-word; }
/* Advice, so it does not look like another field. Amber for the one that says
   content is the wrong lever, green for the one worth pushing -- and no colour
   at all on the states that carry no advice, which simply do not render. */
/* ADVICE ON ITS OWN GROUND, not just an accent rule -- the owner's colour pass, which
   #1520 applied to the section heads and not to the rows. A left border alone put this
   line in the same visual class as the two grey lines above it, and it is the only part
   of the row that wants doing something about. */
.kw-why{ display:block; font-style:normal; font-size:11px; margin-top:4px;
  line-height:1.4; border-left:3px solid; padding:5px 9px; border-radius:0 6px 6px 0; }
.kw-why.push{ color:#166534; border-color:#16a34a; background:#f0fdf4; }
.kw-why.hold{ color:#92400e; border-color:#f59e0b; background:#fffbeb; }
/* WHERE A KEYWORD CAME FROM, AS A CHIP. "you added" and "suggested" are different kinds
   of thing and were two colours of text inside one grey sentence. */
.kw-src{ font-style:normal; display:inline-block; padding:1px 7px; border-radius:999px;
  font-size:10px; font-weight:800; text-transform:uppercase; letter-spacing:.3px;
  vertical-align:1px; background:#f5f3ff; color:#6d28d9; }
.kw-src.own{ background:#eff6ff; color:#1d4ed8; }
/* The cell is a holder now; the grade below carries the weight. */
.kw-pos{ min-width:38px; text-align:right; }
/* A POSITION IS A GRADE, SO IT LOOKS LIKE ONE. Shared by the keyword rows and the rivals
   table so #1 means the same thing in both. Only the top of the scale is saturated: below
   it the badges differ by weight, because #12 and #18 are the same news. `none` is not
   "worst" -- it is "we looked and you were not in the twenty we can see". */
.pos{ display:inline-flex; align-items:center; justify-content:center; min-width:30px;
  padding:3px 8px; border-radius:999px; font-size:12px; font-weight:800;
  font-variant-numeric:tabular-nums; }
.pos.p1{ background:#fef3c7; color:#92400e; }
.pos.p2{ background:#fef9e7; color:#a16207; }
.pos.p3{ background:#f1f5f9; color:#475569; }
.pos.p4{ background:#f1f5f9; color:#64748b; font-weight:700; }
.pos.none{ background:#f8fafc; color:#b6c0cc; font-weight:700; }
/* THE HEADER. Both narrow columns render "--" for an unranked keyword and neither said
   which was which; "Who is beating you" sits directly above WITH a header.
   Its own class rather than .kw-row.head: `#rankGrid .kw-row` means "a tracked keyword"
   to four E2E assertions, and a header joining that set made it the first match. So the
   column layout is repeated here instead of inherited -- that is the point, not an
   oversight. */
.kw-head{ display:flex; align-items:center; gap:10px; padding:6px 2px; }
.kw-head > div{ font-size:10px; font-weight:800; text-transform:uppercase;
  letter-spacing:.4px; color:var(--ink3); }
.kw-head .kw-act{ width:58px; }
.kw-mv{ font-size:11.5px; font-weight:800; min-width:44px; text-align:right; }
.kw-mv.up{ color:#16a34a; } .kw-mv.down{ color:#d93025; }
.kw-mv.flat, .kw-mv.none{ color:var(--ink3); font-weight:600; }
.kw-act{ display:flex; gap:2px; }
.kw-act button{ background:none; border:none; cursor:pointer; color:var(--ink3); padding:4px; border-radius:6px; }
.kw-act button:hover{ background:var(--surface-2,#f1f3f5); color:var(--ink2); }
.rank-miss{ display:flex; align-items:center; gap:8px; width:100%; text-align:left; background:none; border:none; border-top:1px solid var(--border); padding:8px 0; cursor:pointer; }
.rank-miss .rm-t{ flex:1; min-width:0; font-size:13px; font-weight:600; word-break:break-word; }
.rank-miss .rm-a{ font-size:11px; font-weight:800; color:#1a56db; white-space:nowrap; }
.rank-miss:hover .rm-a{ text-decoration:underline; }

/* "Measure from my business" — the tap inside the distance warning (A2 + #1578).
   It sits INSIDE .kw-why.hold, so it borrows that block's amber and only has to read as
   pressable against it. Inline-block rather than a row action: the warning names the
   problem and the button is the second half of the same sentence. */
.kw-repoint{ display:inline-block; margin-left:2px; padding:2px 8px; font:inherit;
  font-size:11px; font-weight:600; line-height:1.5; cursor:pointer;
  color:#92400e; background:#fff; border:1px solid #f59e0b; border-radius:999px; }
.kw-repoint:hover{ background:#fffbeb; }
.kw-repoint:disabled{ opacity:.6; cursor:default; }

/* THE KEYWORD LIST AS A GRID (owner, 2026-09-29: "it should be at the same place for every
   keyword"). Nine columns, the header repeating them, and the advice line spanning the facts
   under its keyword. A missing fact is a dash in its own column, so nothing shifts.
   Below 1200px the sidebar leaves too little room for nine, so each row folds its four facts
   into labelled cells under the keyword and the header hides. Positions are EXPLICIT there:
   grid auto-placement never goes back, and the icons would drop below the facts. */
.kw-row, .kw-head{ display:grid; grid-template-columns:22px minmax(170px,1fr) 52px 46px 54px
  minmax(110px,.8fr) 92px 92px 60px; column-gap:12px; align-items:center; }
.kw-fs{ display:contents; }
.kw-n{ font-size:11.5px; font-weight:700; color:var(--ink3); text-align:right; font-variant-numeric:tabular-nums; }
.kw-t{ display:flex; flex-wrap:wrap; align-items:center; gap:4px 7px; }
.kw-f{ min-width:0; font-size:12.5px; color:var(--ink2); font-variant-numeric:tabular-nums; }
.kw-f.lead{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.kw-f.nil{ color:#b6c0cc; }
.kw-f.good{ color:#16a34a; font-weight:700; }
.kw-f::before{ display:none; }
.kw-head .kw-f{ font-size:10px; font-weight:800; text-transform:uppercase; letter-spacing:.4px; color:var(--ink3); }
.kw-row .kw-why{ grid-column:2 / -1; }
/* JUST ADDED: tinted until it is clicked or ten minutes pass (rank-rows.js), then it fades
   back to the others rather than snapping. */
.kw-row{ transition:background-color .8s ease, box-shadow .8s ease; }
.kw-row.kw-new{ background:#ecfdf5; box-shadow:inset 3px 0 0 #10b981; cursor:pointer; }
.kw-src.fresh{ background:#d1fae5; color:#047857; }
.kw-row:not(.kw-new) .kw-src.fresh{ display:none; }
@media (max-width:1199px){
  .kw-head{ display:none; }
  .kw-row{ grid-template-columns:20px minmax(0,1fr) auto auto auto; row-gap:8px; }
  .kw-row .kw-n{ grid-area:1 / 1; }
  .kw-row .kw-b{ grid-area:1 / 2; }
  .kw-row .kw-pos{ grid-area:1 / 3; }
  .kw-row .kw-mv{ grid-area:1 / 4; }
  .kw-row .kw-act{ grid-area:1 / 5; }
  .kw-row .kw-fs{ display:grid; grid-area:2 / 2 / 3 / -1; grid-template-columns:repeat(4,minmax(0,1fr)); gap:4px 12px; }
  .kw-row .kw-why{ grid-area:3 / 2 / 4 / -1; margin-top:0; }
  .kw-f::before{ content:attr(data-l); display:block; font-size:9.5px; font-weight:800;
    text-transform:uppercase; letter-spacing:.3px; color:var(--ink3); margin-bottom:1px; }
}
@media (max-width:560px){
  .kw-row .kw-fs{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}

/* WHAT YOUR AI KNOWS — the checklist (Train your AI v2, owner approved 3 Oct 2026). Drawn by
   KNOW in js/train-your-ai.js. A row carries its state in its dot as well as its words, so
   what needs attention reads at a glance: green answered, grey "doesn't apply", amber gap. */
.kn-meter-t{display:flex;justify-content:space-between;align-items:baseline;gap:10px;font-size:12.5px;color:var(--ink3);margin-bottom:6px}
.kn-meter-t b{font-size:13px;color:var(--ink2);white-space:nowrap;font-variant-numeric:tabular-nums}
.kn-bar{height:7px;background:#eef0f3;border-radius:999px;overflow:hidden}
.kn-bar i{display:block;height:100%;border-radius:999px;transition:width .3s}
.kn-gaps{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:11px}
.kn-gaps-l{font-size:12px;font-weight:700;color:var(--ink3);margin-right:2px}
.kn-gap{font:inherit;font-size:12px;font-weight:600;color:#9a3412;background:#fff4ec;border:1px solid #fbd5b5;border-radius:999px;padding:4px 10px;cursor:pointer}
.kn-gap:hover{background:#ffe8d6}
.kn-allset{display:flex;align-items:center;gap:7px;margin-top:11px;font-size:12.5px;font-weight:700;color:#0f9d6e}
.kn-allset .ic{width:15px;height:15px}
.kn-group{font-size:11.5px;font-weight:750;letter-spacing:.07em;text-transform:uppercase;color:var(--ink3);margin:16px 0 4px}
.kn-group:first-child{margin-top:4px}
.kn-typenote{font-size:12.5px;color:var(--ink3);margin:2px 0 8px;line-height:1.5}
.kn-row{display:flex;gap:11px;align-items:flex-start;padding:11px 0;border-top:1px solid var(--border)}
.kn-dot{width:20px;height:20px;flex:none;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:800;margin-top:1px}
.kn-dot .ic{width:12px;height:12px}
.kn-dot.ok{background:#e6f6ef;color:#0f9d6e}
.kn-dot.na{background:#eef0f3;color:var(--ink3)}
.kn-dot.miss{background:#fff1e6;color:#c2410c}
/* "TO CHECK" (Train your AI v2, step 4a-2): an answer the AI still gives, which one of the
   owner's own sources disagreed with and nobody picked. Amber, not red: nothing is missing
   and nothing is broken -- it is their word that is missing. */
.kn-dot.check{background:#fef3c7;color:#92610b}
.kn-main{flex:1;min-width:0}
.kn-lbl{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:13px;font-weight:650;color:var(--ink2)}
.kn-src{display:inline-block;font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
.kn-val{font-size:13px;color:var(--ink2);margin-top:3px;word-break:break-word;line-height:1.45}
.kn-val.muted{color:var(--ink3)}
.kn-val.miss{color:#c2410c;font-weight:600;font-size:12.5px}
.kn-check{font-size:12px;color:#92610b;background:#fffbeb;border-left:2px solid #fcd34d;border-radius:0 6px 6px 0;
  padding:5px 9px;margin-top:5px;line-height:1.5;word-break:break-word}
.kn-row.tocheck{background:linear-gradient(90deg,rgba(253,230,138,.14),transparent 60%)}
.kn-gap.check{color:#92610b;background:#fffbeb;border-color:#fcd34d}
.kn-gap.check:hover{background:#fef3c7}
.kn-note{display:flex;gap:6px;align-items:flex-start;margin-top:5px;font-size:12px;color:#92610b}
.kn-note .ic{width:13px;height:13px;flex:none;margin-top:2px}
.kn-acts{display:flex;flex-direction:column;align-items:flex-end;gap:2px;flex:none}
.kn-act{background:none;border:none;font:inherit;color:#f97316;font-size:12.5px;font-weight:700;cursor:pointer;padding:2px 4px;white-space:nowrap}
.kn-act.quiet{color:var(--ink3);font-weight:600;font-size:12px}
.kn-act:focus-visible,.kn-gap:focus-visible{outline:2px solid #f97316;outline-offset:2px;border-radius:6px}
/* Train your AI → Payment methods: tap to add or remove. */
.train-paychips{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px}
.train-paychip{font:inherit;font-size:12px;font-weight:600;color:var(--ink2);background:var(--surface,#fff);border:1px solid var(--border);border-radius:999px;padding:5px 11px;cursor:pointer}
.train-paychip.on{color:#0763bd;background:rgba(8,119,232,.08);border-color:rgba(8,119,232,.35)}

/* An option a pick REFUSES: the website's hours where the week could not be read whole, which
   Google would apply as a closed day (services/hours-text.js). Shown, never takeable. */
.wif-seg .seg-btn[disabled]{opacity:.45;cursor:not-allowed}

/* READ MY WEBSITE — the whole-site reader (Train your AI v2, step 3; the mock approved 3 Oct
   2026). Drawn by js/site-reader.js into #siteRead. Each page's state is a chip as well as a
   word, so a glance down the list says how far the reading has got. */
.sr-title{display:flex;align-items:center;gap:7px;font-size:15px;font-weight:700;color:var(--ink)}
.sr-title .ic{width:16px;height:16px;color:#0f9d6e}
.sr-sub{font-size:13px;color:var(--ink3);margin:6px 0 12px;line-height:1.5}
.sr-rules{font-size:12px;color:var(--ink3);margin:12px 0 0;line-height:1.55}
.sr-finding{display:flex;gap:10px;align-items:center;font-size:13.5px;color:var(--ink2);padding:14px 0}
.sr-spin{display:inline-block;width:12px;height:12px;border:2px solid #cfd8e3;border-top-color:var(--green);border-radius:50%;animation:spin .8s linear infinite;flex:none}
.sr-bar{height:6px;background:#eef0f3;border-radius:999px;overflow:hidden;margin:4px 0 10px}
.sr-bar i{display:block;height:100%;background:var(--green);border-radius:999px;transition:width .3s}
.sr-pages{display:flex;flex-direction:column;border:1px solid var(--border);border-radius:10px;overflow:hidden;margin-top:8px;background:var(--surface)}
.sr-page{display:flex;justify-content:space-between;gap:12px;padding:9px 12px;border-top:1px solid var(--border);font-size:12.5px}
.sr-page:first-child{border-top:none}
.sr-pmain{min-width:0;display:flex;flex-direction:column}
.sr-pmain b{color:var(--ink);font-weight:650}
.sr-pmain span{color:var(--ink3);font-size:11.5px;word-break:break-all}
.sr-pside{text-align:right;display:flex;flex-direction:column;align-items:flex-end;gap:2px;max-width:55%}
.sr-pside em{font-style:normal;color:var(--ink3);font-size:11.5px}
.sr-chip{display:inline-flex;align-items:center;gap:5px;font-weight:700;font-size:11.5px;border-radius:999px;padding:2px 9px;white-space:nowrap}
.sr-chip.read{background:#e6f6ef;color:#0f9d6e}
.sr-chip.reading{background:var(--green-light);color:var(--green)}
.sr-chip.wait,.sr-chip.skip{background:#f3f5f8;color:var(--ink3)}
.sr-chip.fail{background:#fff1e6;color:#c2410c}
.sr-more{display:block;background:none;border:none;font:inherit;font-size:12.5px;font-weight:700;color:#f97316;cursor:pointer;padding:8px 0 2px;text-align:left}
.sr-more span{color:var(--ink3);font-weight:500}
.sr-stop{margin-top:12px}
.sr-failed{font-size:13px;color:#9a3412;line-height:1.5;background:#fff4ec;border:1px solid #fbd5b5;border-radius:10px;padding:11px 13px;margin-top:14px}
.sr-failed .btn{margin-top:10px}
.sr-done{margin-top:14px;padding-top:14px;border-top:1px solid var(--border)}
.sr-details{margin-top:12px}
.sr-details summary{cursor:pointer;font-size:13px;font-weight:700;color:var(--ink2)}
.sr-more:focus-visible,.sr-details summary:focus-visible{outline:2px solid #f97316;outline-offset:2px;border-radius:6px}
@media (max-width:560px){.sr-page{flex-direction:column;gap:4px}.sr-pside{align-items:flex-start;text-align:left;max-width:none}}
@media (prefers-reduced-motion:reduce){.sr-spin{animation:none}.sr-bar i{transition:none}}

/* WHAT I FOUND — a finished reading beside what the AI already knows (Train your AI v2, step 4;
   the mock approved 3 Oct 2026). Drawn by js/site-review.js into #siteRead. What still needs the
   owner (to pick, to answer) is a badge as well as a count, so the top line says what is left. */
.wif-sum{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 4px}
.wif-badge{font-size:11px;font-weight:700;border-radius:999px;padding:2px 9px;white-space:nowrap}
.wif-badge.chg{background:var(--green-light);color:var(--green)}
.wif-badge.new{background:#e6f7f1;color:#0f9d6e}
.wif-badge.pick{background:var(--orange-light);color:#b45309}
.wif-badge.miss{background:var(--red-light);color:#b91c1c}
.wif-badge.pack{background:var(--purple-light);color:#6d28d9}
.wif-badge.same{background:#f3f5f8;color:var(--ink2)}
.wif-src{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap;background:#e6f4f5;color:#0e7c86}
.wif-sec{display:flex;gap:7px;align-items:center;font-size:14px;font-weight:700;color:var(--ink);margin:20px 0 10px}
.wif-sec .ic{width:15px;height:15px;color:var(--ink3)}
.wif-card{border:1px solid var(--border);border-radius:12px;padding:12px 14px;margin-bottom:10px;background:var(--surface)}
.wif-h{display:flex;flex-wrap:wrap;gap:7px;align-items:center;font-size:13.5px;font-weight:700;color:var(--ink);margin-bottom:8px}
.wif-sides{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:8px;margin-bottom:10px}
.wif-side{display:flex;flex-wrap:wrap;gap:6px;align-items:center;align-content:flex-start;border:1px solid var(--border);border-radius:10px;padding:9px 11px;background:var(--bg)}
.wif-side.on{border-color:var(--green);background:var(--green-light)}
.wif-side-v{flex-basis:100%;font-size:13px;color:var(--ink2);overflow-wrap:anywhere}
.wif-fix{flex-basis:100%;font-size:12.5px;font-weight:600;color:var(--ink);overflow-wrap:anywhere}
.wif-src.mine{background:#f3f5f8;color:var(--ink2)}
.wif-seg{max-width:460px;flex-wrap:wrap}
.wif-seg .seg-btn{font-size:12.5px;flex:1 1 auto;white-space:nowrap}
.wif-note{font-size:12px;color:var(--ink3);margin:8px 0 0;line-height:1.5}
.wif-note.warn{color:#b45309}
.wif-chips{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.wif-chip{border:1px solid var(--border);background:var(--surface);border-radius:999px;padding:6px 13px;font:600 12.5px var(--font);color:var(--ink2);cursor:pointer}
.wif-chip.on{border-color:var(--green);background:var(--green-light);color:var(--green)}
.wif-chip.na.on{border-color:var(--ink3);background:#eef0f3;color:var(--ink)}
.wif-chip:disabled{opacity:.45;cursor:default}
.wif-in{flex:1;min-width:180px;max-width:420px;border:1px solid var(--border);border-radius:9px;padding:8px 10px;font:500 13px var(--font);color:var(--ink);background:var(--surface)}
textarea.wif-in{max-width:none;flex-basis:100%;resize:vertical}
.wif-in:focus{outline:none;border-color:var(--green)}
.wif-money{font-weight:600;color:var(--ink3)}
.wif-date{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--ink3)}
.wif-date input{border:1px solid var(--border);border-radius:8px;padding:4px 7px;font:500 12.5px var(--font)}
.wif-date.need input{border-color:#f97316}
.wif-check{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--ink3)}
.wif-check input{width:auto}
.wif-rows{border-top:1px solid var(--border)}
.wif-row{padding:10px 0;border-bottom:1px solid var(--border)}
.wif-row.kept .wif-val,.wif-row.kept .wif-items,.wif-row.kept .wif-chips,.wif-row.kept .wif-was{opacity:.45}
.wif-lbl{display:flex;flex-wrap:wrap;gap:7px;align-items:center;font-size:13px;font-weight:650;color:var(--ink)}
.wif-keep{margin-left:auto;background:none;border:none;font:700 12px var(--font);color:var(--ink3);cursor:pointer;padding:2px 0;white-space:nowrap}
.wif-keep:hover{color:var(--ink)}
.wif-val{font-size:13px;color:var(--ink2);margin-top:4px;overflow-wrap:anywhere}
.wif-was{font-size:12px;color:var(--ink3);margin-top:4px;overflow-wrap:anywhere}
.wif-dim{color:var(--ink3)}
.wif-items{display:flex;flex-direction:column;max-height:220px;overflow:auto;margin-top:6px;font-size:12.5px}
.wif-items div{display:flex;justify-content:space-between;gap:10px;padding:3px 0;border-bottom:1px dashed var(--border)}
.wif-foot{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:18px}
.wif-saved{display:flex;gap:6px;align-items:flex-start;margin-top:14px;font-size:13px;font-weight:600;color:#0f9d6e;line-height:1.5}
.wif-saved .ic{flex:none;width:15px;height:15px;margin-top:2px}
.wif-chip:focus-visible,.wif-keep:focus-visible{outline:2px solid var(--green);outline-offset:2px}
.dark .wif-side{background:#1f2738}
.dark .wif-chip.na.on,.dark .wif-badge.same,.dark .wif-src.mine{background:#28324a;color:var(--ink)}
@media (max-width:560px){.wif-foot{flex-direction:column-reverse}.wif-foot .btn{width:100%}.wif-keep{margin-left:0}}

/* WHICH GOOGLE PROFILE IS THIS BUSINESS (js/gbp-listing.js). The rows are the wizard's own
   .ob-listing cards (css/onboarding.css), so the dialog in Settings and the setup wizard ask
   the same question the same way; these add the Verified line and the Settings card. */
.gpl-intro{margin:0 0 12px;font-size:14px;line-height:1.5;color:var(--ink2)}
.gpl-rows{max-height:52vh;overflow-y:auto;padding:2px}
.gpl-msg{margin:10px 0 0;font-size:13px;color:var(--red)}
.gpl-hold{margin:12px 0 0;font-size:13px;line-height:1.45;color:#92400e;background:#fffbeb;border-radius:10px;padding:9px 12px}
.gpl-hold:empty{display:none}
.dark .gpl-hold{background:#3a2a10;color:#fbbf24}
.gpl-msg:empty{display:none}
.gpl-ok,.gpl-no{display:inline-flex;align-items:center;gap:5px;margin-top:3px;font-size:12px;font-weight:650;line-height:1.35}
.gpl-ok{color:#047857}.gpl-no{color:#b45309}
.gpl-ok .ic,.gpl-no .ic{flex:none;width:13px;height:13px}
.gpl-in-use{display:flex;flex-direction:column;gap:3px;margin-top:9px;font-size:12.5px;color:var(--ink3);line-height:1.45}
.gpl-in-use b{font-size:14px;color:var(--ink)}
.gpl-n{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin-top:4px}
.gpl-use:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
.gpl-wait{display:flex;gap:7px;align-items:flex-start;margin-top:5px;font-size:12.5px;line-height:1.5;color:#92400e}
.gpl-wait .ic{flex:none;width:14px;height:14px;margin-top:2px}
.gpl-link{color:var(--green);font-weight:650;text-decoration:underline;text-underline-offset:2px}
.dark .gpl-wait{color:#fbbf24}
#gbpListingModal .modal:focus{outline:none}
.dark .gpl-ok{color:#34d399}.dark .gpl-no{color:#fbbf24}

/* Business Details (8 Oct 2026): one short hint per box, and the customer-facing boxes under a
   single line that says they are shared, instead of the same phrase on every label. */
.bp-hint{font-size:11.5px;line-height:1.45;color:var(--ink3);margin-top:6px}
.bp-hint a{color:var(--green,#16a34a);font-weight:600;cursor:pointer}
.bp-hint #setEmailShown{font-weight:600}
.bp-sub{font-size:13.5px;font-weight:700;color:var(--ink);margin:4px 0 2px}
.bp-lead{margin:0 0 12px}
.form-group label .bp-opt{font-weight:400;text-transform:none;letter-spacing:0;color:var(--ink3)}
