/* ============================================================
   Lucky Dragon — Staff UI Enhancement Layer  (enhance.css)
   Purely ADDITIVE polish: animations, shadows, depth, labels.
   ------------------------------------------------------------
   TO UNDO EVERYTHING:
     1. Delete the <link ... enhance.css> line in staff/index.html
     2. Delete this file (enhance.css)
   Nothing in styles.css / redesign.css / app.js is touched, so
   removing this file restores the exact previous look.
   ============================================================ */

:root{
  --ez:cubic-bezier(.22,.61,.36,1);
  --ez-out:cubic-bezier(.16,1,.3,1);
  --ez-pop:cubic-bezier(.34,1.56,.64,1);
  --dur:.18s;
  --lift:0 6px 18px rgba(0,0,0,.12);
  --lift-lg:0 14px 34px rgba(0,0,0,.20);
  --glow:0 6px 18px color-mix(in srgb,var(--primary) 42%,transparent);
}
@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--lift:0 8px 22px rgba(0,0,0,.45);--lift-lg:0 16px 40px rgba(0,0,0,.60)}}
:root[data-theme="dark"]{--lift:0 8px 22px rgba(0,0,0,.45);--lift-lg:0 16px 40px rgba(0,0,0,.60)}

/* ---- global smooth transitions -------------------------------------- */
button,select,input,textarea,a,
.conversation-card,.icon-button,.composer-button,.tap-button,
.header-avatar,.label-chip,.pane-tabs button,.media-filter button,
.theme-card,.send-button,dialog{
  transition:background-color var(--dur) var(--ez),color var(--dur) var(--ez),
             border-color var(--dur) var(--ez),box-shadow var(--dur) var(--ez),
             transform .2s var(--ez-out),filter var(--dur) var(--ez);
}

/* ---- keyframes ------------------------------------------------------- */
@keyframes dialogIn{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
@keyframes sheetIn{from{opacity:0;transform:translateY(40px)}to{opacity:1;transform:none}}
@keyframes slideDown{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@keyframes toastIn{from{opacity:0;transform:translate(-50%,18px) scale(.95)}to{opacity:1;transform:translate(-50%,0) scale(1)}}
@keyframes popIn{0%{opacity:0;transform:scale(.4)}60%{transform:scale(1.12)}100%{opacity:1;transform:scale(1)}}
@keyframes tipIn{from{opacity:0;transform:translate(-50%,4px)}to{opacity:1;transform:translate(-50%,0)}}
@keyframes shimmer{100%{background-position:200% 0}}
@keyframes softPulse{0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--primary) 40%,transparent)}50%{box-shadow:0 0 0 6px transparent}}

/* ---- structural depth ----------------------------------------------- */
.sidebar{box-shadow:4px 0 24px rgba(0,0,0,.05)}
.details-panel{box-shadow:-4px 0 24px rgba(0,0,0,.05)}
.conversation-header{box-shadow:0 3px 14px rgba(0,0,0,.05);position:relative;z-index:3}
.composer{box-shadow:0 -3px 16px rgba(0,0,0,.06);position:relative;z-index:2}
.toolbar{position:relative;z-index:2}
.pane-tabs{box-shadow:0 2px 8px rgba(0,0,0,.04)}

/* ---- generic buttons: give every button a bit of life --------------- */
/* Press feedback for normal buttons only. Buttons that rely on a transform
   for POSITIONING (the funnel, the scroll-to-latest button) are excluded, or
   this would clobber their centering and move them out from under the cursor. */
button:not(:disabled):not(.filter-toggle):not(.scroll-latest):not(.hover-reply-button):active{transform:translateY(1px) scale(.985)}
/* The reply icon centers itself with translateY(-50%); like the funnel and the
   scroll-to-latest button, it must never be moved/resized by press or hover, or
   the click lands off it. Lock its centering transform in every state. */
.hover-reply-button,
.hover-reply-button:hover,
.hover-reply-button:active,
.hover-reply-button:focus,
.hover-reply-button:focus-visible{transform:translateY(-50%)!important}
button:disabled{opacity:.55;cursor:not-allowed}

/* primary / accent buttons: gradient + colored glow + hover lift ------ */
.primary-button,.record-send{
  background:linear-gradient(135deg,color-mix(in srgb,var(--primary) 88%,#fff 12%),var(--primary));
  box-shadow:var(--glow);border:none;font-weight:700;letter-spacing:.2px;
}
.primary-button:hover,.record-send:hover{transform:translateY(-2px);box-shadow:0 10px 26px color-mix(in srgb,var(--primary) 50%,transparent);filter:brightness(1.05)}
.primary-button:active,.record-send:active{transform:translateY(0)}

/* danger buttons */
.danger-button,.remove-filters{transition:transform .18s var(--ez-out),box-shadow .18s var(--ez),filter .18s}
.danger-button:hover{transform:translateY(-1px);box-shadow:0 8px 20px color-mix(in srgb,var(--danger) 34%,transparent);filter:brightness(1.03)}

/* details-panel + menu action buttons: hover slide + shadow ----------- */
.details-panel section button,.menu-section button,.dialog-actions button{
  border-radius:11px;
}
.details-panel section button:hover,.menu-section button:hover{
  transform:translateX(3px);box-shadow:var(--lift);
  border-color:color-mix(in srgb,var(--primary) 45%,var(--line));
}

/* ---- icon buttons: circular hover halo + press ---------------------- */
.icon-button{position:relative;border-radius:11px}
.icon-button:hover{background:color-mix(in srgb,var(--primary) 12%,transparent);color:var(--primary);transform:translateY(-1px)}
.icon-button:active{transform:scale(.92)}
.alerts-button:hover{transform:translateY(-1px) rotate(-8deg)}

/* ---- BUTTON LABELS ------------------------------------------------- */
/* All header nav buttons (Alerts, Menu, Find, Details) are icon-only. */

/* ---- composer buttons: playful hover + instant tooltip from title --- */
.composer-button{position:relative;border-radius:12px}
.composer-button:hover{background:color-mix(in srgb,var(--primary) 14%,transparent);color:var(--primary);transform:translateY(-2px) scale(1.06)}
.composer-button:active{transform:scale(.9)}
/* Attach menu: camera / photos / voice / file, folded under the + so the phone
   composer row stays clean. A small floating card above the composer, placed by
   JS (positionStaffAttachMenu). */
.attach-menu{position:fixed;z-index:60;display:flex;flex-direction:column;gap:2px;
  min-width:196px;padding:7px;border-radius:16px;background:var(--panel);
  border:1px solid var(--border);box-shadow:0 12px 34px rgba(0,0,0,.34)}
.attach-menu.hidden{display:none}
.attach-option{display:flex;align-items:center;gap:12px;width:100%;padding:11px 12px;
  border:0;border-radius:11px;background:transparent;color:var(--text);
  font:inherit;font-size:15px;text-align:left;cursor:pointer}
.attach-option:hover{background:color-mix(in srgb,var(--primary) 12%,transparent)}
.attach-option:active{background:color-mix(in srgb,var(--primary) 18%,transparent)}
.attach-option .attach-emoji{font-size:18px;width:24px;text-align:center;flex:none}
.composer-button[title]:hover::after{
  content:attr(title);position:absolute;bottom:calc(100% + 9px);left:50%;
  transform:translateX(-50%);background:var(--text);color:var(--panel);
  padding:5px 9px;border-radius:8px;font-size:11px;font-weight:600;white-space:nowrap;
  pointer-events:none;box-shadow:var(--lift);z-index:40;animation:tipIn .14s var(--ez-out);
}

/* send button: gradient orb that pops on hover ------------------------ */
.send-button{background:linear-gradient(135deg,color-mix(in srgb,var(--primary) 85%,#fff 15%),var(--primary))!important;box-shadow:var(--glow)}
.send-button:hover{transform:translateY(-2px) scale(1.08);box-shadow:0 10px 26px color-mix(in srgb,var(--primary) 55%,transparent)}
.send-button:active{transform:scale(.94)}

/* ---- conversation cards: modern hover lift + active accent ---------- */
.conversation-card{border-radius:13px;margin:3px 7px;will-change:transform}
.conversation-card:hover{transform:translateX(3px);box-shadow:var(--lift);background:var(--hover)}
.conversation-card.active{box-shadow:inset 3px 0 0 var(--primary),var(--lift)}
.conversation-card.unread-card{box-shadow:inset 3px 0 0 var(--primary)}
.conversation-card.unread-card:hover{box-shadow:inset 3px 0 0 var(--primary),var(--lift)}

/* ---- filter panel reveal ------------------------------------------- */
#filterPanel:not(.hidden){animation:slideDown .22s var(--ez-out)}
/* Lock the funnel's vertical centering in EVERY state. Otherwise the global
   button-press transform (or any :active rule) overrides translateY(-50%) and
   drops the funnel ~20px, so the pointer ends up off it and the click is lost.
   The 180° flip lives on the child <svg>, so the button itself never moves. */
.filter-toggle,
.filter-toggle:hover,
.filter-toggle:active,
.filter-toggle:focus,
.filter-toggle:focus-visible,
.filter-toggle.active{transform:translateY(-50%)!important}
.filter-toggle svg{transition:transform .25s var(--ez-pop)}
.filter-toggle.active svg{transform:rotate(180deg)}
.filter-active-dot{animation:popIn .3s var(--ez-pop)}
#removeFiltersButton:not(.hidden){animation:slideDown .2s var(--ez-out)}

/* ---- pane tabs: animated active underline --------------------------- */
.pane-tabs button{position:relative;overflow:hidden}
.pane-tabs button::after{content:"";position:absolute;left:50%;right:50%;bottom:0;height:3px;border-radius:3px 3px 0 0;background:var(--primary);transition:left .25s var(--ez-out),right .25s var(--ez-out)}
.pane-tabs button.active::after{left:14%;right:14%}
.pane-tabs button:hover::after{left:32%;right:32%}

/* ---- dialogs: entrance + elevated shadow + blurred backdrop --------- */
dialog[open]{animation:dialogIn .22s var(--ez-out);box-shadow:var(--lift-lg)}
dialog.action-sheet[open]{animation:sheetIn .24s var(--ez-out)}
dialog::backdrop{background:rgba(15,20,30,.42);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
dialog header button[data-close]{border-radius:9px;transition:transform .2s var(--ez-out),background-color .2s}
dialog header button[data-close]:hover{transform:rotate(90deg);background:color-mix(in srgb,var(--danger) 16%,transparent);color:var(--danger)}

/* search results / list rows in dialogs */
.search-result:hover,.referrer-picker .search-result:hover{transform:translateX(3px);box-shadow:var(--lift)}

/* ---- toast ---------------------------------------------------------- */
.toast:not(.hidden){animation:toastIn .28s var(--ez-out);box-shadow:var(--lift-lg)}

/* ---- floating "scroll to latest" button ----------------------------- */
/* The base centers this with left:50% + transform:translateX(-50%). If ANY
   state changes that transform (a lift, a shrink, or an off-center appear
   frame) the button shifts out from under the pointer and the click is lost.
   So we LOCK the transform to the centering in every state (incl. the shared
   .tap-button:active) and only ever change shadow/brightness. The appear
   animation fades opacity only and never touches transform. Result: the button
   never moves or resizes, so a click always lands on it. */
.scroll-latest,
.scroll-latest:hover,
.scroll-latest:active,
.scroll-latest:focus,
.scroll-latest:focus-visible,
.scroll-latest.tap-button:active{transform:translateX(-50%)!important}
@keyframes scrollLatestIn{from{opacity:0}to{opacity:1}}
.scroll-latest:not(.hidden){animation:scrollLatestIn .18s ease}
.scroll-latest{box-shadow:var(--lift);transition:box-shadow var(--dur) var(--ez),filter var(--dur) var(--ez),background-color var(--dur) var(--ez)}
.scroll-latest:hover{box-shadow:var(--lift-lg);filter:brightness(1.03)}
.scroll-latest:active{filter:brightness(.92)}

/* ---- inputs & selects: focus glow + gentle lift --------------------- */
.search-wrap input:focus,.filter-row select:focus,.toolbar input:focus,
input:focus,textarea:focus,select:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 20%,transparent),var(--lift)!important}
.search-wrap:focus-within svg{color:var(--primary)}

/* ---- avatars: subtle ring + hover pop ------------------------------- */
.header-avatar{transition:transform .2s var(--ez-out),box-shadow .2s}
.header-avatar:hover{transform:scale(1.05)}
.online-dot{box-shadow:0 0 0 2px var(--panel)}
.online-dot:not(.hidden){animation:softPulse 2.4s var(--ez) infinite}

/* ---- typing indicator glow ----------------------------------------- */
.typing-indicator:not(.hidden){animation:slideDown .2s var(--ez-out)}

/* ---- loading shimmer for skeleton/edge loaders --------------------- */
.edge-loader:not(.hidden){animation:slideDown .2s var(--ez-out)}

/* ---- viewer (image lightbox) arrows -------------------------------- */
.viewer-arrow:hover{transform:scale(1.12)}
.viewer-close:hover{transform:rotate(90deg)}

/* ---- respect reduced-motion ---------------------------------------- */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
}

/* ---- games & site balance (details panel + connect dialog) ------------ */
.staff-wallet-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 12px;margin-bottom:8px;
  border-radius:12px;background:var(--hover)}
.staff-wallet-row span{color:var(--muted);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em}
.staff-wallet-row strong{font-size:19px;font-weight:800}
.staff-game-list{display:flex;flex-direction:column;gap:6px;margin-bottom:8px}
.staff-game-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--line);border-radius:10px}
.staff-game-label{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}
.staff-game-label strong{font-size:13.5px}
.staff-game-label small{color:var(--muted);font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.staff-game-label small.ok{color:#15803d}
.staff-game-label small.warn{color:#b45309}
.staff-game-balance{font-weight:700;font-size:13.5px;white-space:nowrap}
.link-button{background:none;border:none;color:var(--primary);font-size:12.5px;cursor:pointer;padding:2px 4px}
.game-connect-list{display:flex;flex-direction:column;gap:8px;padding:12px 14px}
.game-connect-row{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--line);border-radius:12px}
.game-connect-row .primary-button{width:auto;padding:8px 16px;white-space:nowrap}
#gameConnectForm{display:flex;flex-direction:column;gap:10px;padding:0 14px 16px}
#gameConnectName{margin:0;font-weight:700}
.game-connect-note{margin:0;color:var(--muted);font-size:12.5px}
/* panel sharing between brands */


.ghost-button.danger{color:#c0392b}
.game-captcha{align-self:flex-start;height:52px;border-radius:8px;background:#fff;border:1px solid var(--line)}
.inline-error{margin:0;color:#d92d20;font-size:13px;font-weight:600}

/* ---- games: bigger captcha, history rows, mini refresh ---------------- */
.game-captcha{align-self:center;height:96px;image-rendering:crisp-edges;border-radius:10px;background:#fff;
  border:1px solid var(--line);padding:4px}
#gameCaptchaInput{font-size:20px;letter-spacing:.28em;text-align:center;font-weight:700}
.mini-refresh{margin-left:auto;background:none;border:none;color:var(--primary);font-size:16px;cursor:pointer;
  padding:2px 6px;border-radius:8px;line-height:1}
.mini-refresh:hover{background:var(--hover)}
.staff-history-list{display:flex;flex-direction:column;gap:6px;padding:12px 14px;max-height:60vh;overflow-y:auto}
.staff-history-row{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--line);border-radius:10px}
.staff-history-row.voided{opacity:.55}
.staff-history-row.voided strong,.staff-history-row.voided .staff-history-amount{text-decoration:line-through}
.staff-history-amount{font-weight:800;font-size:14px;white-space:nowrap}
.staff-history-amount.in{color:#15803d}
.staff-history-amount.out{color:#b42318}
.link-button.danger{color:#b42318}

/* ---- game disconnect banner (all staff see it at once) ---------------- */
.game-alert-banner{position:fixed;top:0;left:0;right:0;z-index:60;display:block;width:100%;padding:11px 16px;border:none;
  background:#b45309;color:#fff;font-size:13.5px;font-weight:700;text-align:center;cursor:pointer;
  box-shadow:0 2px 10px rgba(0,0,0,.25)}
.game-alert-banner:hover{background:#92400e}
/* A dismiss "×" sitting over the banner's right edge. It's a SIBLING, not a child
   (the banner is itself a <button>, and banner.textContent= wipes any child); its
   higher z-index means a tap lands on it, not the banner's "get a new token". */
.game-alert-dismiss{position:fixed;top:0;right:0;z-index:61;border:none;background:transparent;color:#fff;
  font-size:20px;font-weight:700;line-height:1;padding:10px 16px;cursor:pointer;opacity:.9}
.game-alert-dismiss:hover{opacity:1;background:rgba(0,0,0,.18)}
.game-alert-dismiss.hidden{display:none}

/* ---- team chat: seen-by avatars + message info ----------------------- */
.team-seen-row{display:flex;gap:4px;justify-content:flex-end;padding:2px 12px 6px;flex-wrap:wrap}
.seen-avatar{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;
  background:linear-gradient(135deg,var(--primary),color-mix(in srgb,var(--primary) 55%,#000));
  color:#fff;font-size:9.5px;font-weight:800;letter-spacing:.02em;flex:0 0 auto;box-shadow:0 1px 3px rgba(0,0,0,.25)}
.info-section-head{margin:14px 0 6px;font-size:13px;font-weight:800;color:var(--text)}
.info-muted{margin:2px 0;color:var(--muted);font-size:12.5px}
.info-person{display:flex;align-items:center;gap:8px;padding:5px 0}
.info-person .seen-avatar{width:24px;height:24px;font-size:10.5px}
.info-person-name{flex:1;font-size:13.5px}
.info-person-time{color:var(--muted);font-size:12px;white-space:nowrap}

/* ---- staff reactions: "+" opens full emoji picker -------------------- */
.quick-reactions .more-reactions{font-size:20px;font-weight:700;line-height:1;color:var(--muted);
  min-width:38px;display:inline-flex;align-items:center;justify-content:center}
.quick-reactions .more-reactions:hover{color:var(--primary)}
.reaction-picker-sheet{border:none;border-radius:16px;padding:0;max-width:420px;width:92vw;
  background:var(--panel);color:var(--text)}
.reaction-picker-sheet header{display:flex;align-items:center;justify-content:space-between;
  padding:12px 16px;border-bottom:1px solid var(--line)}
.reaction-picker-sheet header button{background:none;border:0;font-size:20px;color:var(--muted);cursor:pointer}
.reaction-picker-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px;padding:12px;
  max-height:52vh;overflow-y:auto}
.reaction-picker-grid button{font-size:23px;background:none;border:0;border-radius:9px;padding:6px 0;cursor:pointer}
.reaction-picker-grid button:hover{background:var(--hover)}
@media(max-width:520px){.reaction-picker-grid{grid-template-columns:repeat(6,1fr)}}

/* ---- staff who-reacted popover (long-press a reaction chip) ----------- */
.reaction-info-sheet{border:none;border-radius:16px;padding:0;max-width:380px;width:90vw;
  background:var(--panel);color:var(--text)}
.reaction-info-sheet header{display:flex;align-items:center;justify-content:space-between;
  padding:12px 16px;border-bottom:1px solid var(--line)}
.reaction-info-sheet header button{background:none;border:0;font-size:20px;color:var(--muted);cursor:pointer}
.reaction-info-list{padding:6px 0 12px;max-height:56vh;overflow-y:auto}
.reaction-info-row{display:flex;align-items:center;gap:13px;padding:10px 18px;border-bottom:1px solid var(--line)}
.reaction-info-row:last-child{border-bottom:0}
.reaction-info-emoji{font-size:26px;line-height:1;filter:drop-shadow(0 2px 2px rgba(0,0,0,.28))}
.reaction-info-copy{display:flex;flex-direction:column;gap:2px}
.reaction-info-copy strong{font-size:14.5px}
.reaction-info-copy small{color:var(--muted);font-size:12.5px}
.reaction-chip{cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}

/* ---- monitoring mode: small floating draggable bubble ---------------- */
.monitor-bubble{position:fixed;z-index:80;display:inline-flex;align-items:center;gap:7px;
  padding:6px 8px 6px 12px;border-radius:999px;background:rgba(29,78,216,.68);
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);color:#fff;font-size:12px;font-weight:700;
  white-space:nowrap;cursor:grab;user-select:none;-webkit-user-select:none;touch-action:none;
  box-shadow:0 6px 18px rgba(0,0,0,.28);animation:monitorFloat 3.6s ease-in-out infinite}
.monitor-bubble.monitor-away{background:rgba(180,83,9,.72)}
.monitor-bubble.dragging{cursor:grabbing;animation:none;box-shadow:0 10px 26px rgba(0,0,0,.4)}
.monitor-bubble button{background:rgba(255,255,255,.24);border:0;color:#fff;width:19px;height:19px;
  border-radius:50%;font-size:14px;line-height:1;cursor:pointer;display:grid;place-items:center;flex:0 0 auto}
.monitor-bubble button:hover{background:rgba(255,255,255,.4)}
@keyframes monitorFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
@media(prefers-reduced-motion:reduce){.monitor-bubble{animation:none}}
.monitor-employee-list{display:flex;flex-direction:column;gap:6px;padding:6px 4px 12px;max-height:56vh;overflow-y:auto}
.monitor-employee-row{display:flex;flex-direction:column;gap:2px;text-align:left;padding:11px 13px;
  border:1px solid var(--line);border-radius:12px;background:var(--panel);color:var(--text);cursor:pointer}
.monitor-employee-row:hover{background:var(--hover)}
.monitor-employee-row strong{font-size:14px}
.monitor-employee-row small{color:var(--muted);font-size:12px}

/* ---- customer details: grouped, icon-led, animated ---------------------- */
.details-panel>#detailsBody{padding:12px;border-bottom:0;display:grid;gap:10px}
.details-panel .identity-card{display:flex;align-items:center;gap:12px;padding:14px 13px;border:1px solid var(--line);border-bottom:1px solid var(--line);border-radius:16px;position:relative;overflow:hidden;background:linear-gradient(135deg,color-mix(in srgb,var(--primary),transparent 90%),var(--panel) 62%);box-shadow:0 2px 4px rgba(0,0,0,.04),0 18px 34px -24px rgba(0,0,0,.65)}
.identity-card:before{content:"";position:absolute;top:-60%;left:0;width:55%;height:220%;pointer-events:none;background:linear-gradient(90deg,transparent,rgba(255,255,255,.22),transparent);animation:identitySheen 7.5s ease-in-out infinite}
@keyframes identitySheen{0%,72%{transform:translateX(-140%) rotate(18deg)}100%{transform:translateX(330%) rotate(18deg)}}
.identity-avatar{position:relative;width:52px;height:52px;flex:none;border-radius:50%;display:grid;place-items:center;background:#dbeafe;color:#0759bd;font-weight:700;font-size:21px;box-shadow:0 4px 14px rgba(0,0,0,.22),inset 0 1px 0 rgba(255,255,255,.55)}
.identity-avatar img{width:100%;height:100%;border-radius:50%;object-fit:cover}
.identity-dot{position:absolute;right:0;bottom:2px;width:13px;height:13px;border-radius:50%;border:2px solid var(--panel);background:var(--muted)}
.identity-dot.online{background:#31a24c;animation:identityPulse 2.8s ease-in-out infinite}
@keyframes identityPulse{0%,100%{box-shadow:0 0 0 0 rgba(49,162,76,.5)}50%{box-shadow:0 0 0 7px rgba(49,162,76,0)}}
.identity-copy{display:grid;gap:2px;min-width:0;position:relative}
.identity-copy strong{font-size:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.identity-copy span{font-size:12px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.detail-chips{display:flex;flex-wrap:wrap;gap:6px}
.detail-chip{display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:999px;border:1px solid var(--line);background:var(--panel2);font-size:12px;font-weight:600;cursor:default;box-shadow:0 1px 2px rgba(0,0,0,.05);transition:transform .32s cubic-bezier(.34,1.56,.64,1),box-shadow .32s ease}
.detail-chip:hover{transform:translateY(-2px);box-shadow:0 7px 16px -7px rgba(0,0,0,.5)}
.detail-chip i{font-style:normal;font-size:13px;filter:drop-shadow(0 1px 1px rgba(0,0,0,.25))}
.detail-chip.good{color:#15803d;border-color:color-mix(in srgb,#15803d,transparent 70%);background:color-mix(in srgb,#15803d,transparent 92%)}
.detail-chip.muted{color:var(--muted)}

.details-panel .detail-group{padding:0;border:1px solid var(--line);border-radius:14px;background:var(--panel);overflow:hidden;box-shadow:0 1px 2px rgba(0,0,0,.04),0 12px 26px -20px rgba(0,0,0,.55);transition:box-shadow .38s ease,border-color .38s ease}
.details-panel>.detail-group{margin:10px 12px}
.details-panel .detail-group:hover{border-color:color-mix(in srgb,var(--primary),var(--line) 62%)}
.details-panel .detail-group.open{box-shadow:0 2px 5px rgba(0,0,0,.05),0 20px 38px -24px rgba(0,0,0,.62)}
/* .details-panel button already sets a flat background, so these need the extra
   specificity or the header gradient silently loses. */
.details-panel .detail-group-head{position:relative;display:flex;align-items:center;gap:9px;width:100%;margin:0;padding:11px 12px;border:0;border-radius:0;background:linear-gradient(180deg,color-mix(in srgb,var(--panel2),transparent 25%),var(--panel));text-align:left;font-weight:700;font-size:13.5px;min-height:46px;transition:background .3s ease}
.details-panel .detail-group-head:hover{background:var(--hover)}
.detail-group-head:after{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--primary);opacity:0;transition:opacity .38s ease}
.detail-group.open .detail-group-head:after{opacity:1}
.dg-icon{font-size:16px;line-height:1;filter:drop-shadow(0 1px 2px rgba(0,0,0,.3));transition:transform .45s cubic-bezier(.34,1.56,.64,1)}
.detail-group.open .dg-icon{transform:scale(1.16) rotate(-6deg)}
.dg-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dg-badge{flex:none;min-width:20px;padding:1px 7px;border-radius:999px;background:color-mix(in srgb,var(--primary),transparent 86%);color:var(--primary);font-size:11px;font-weight:700;text-align:center}
.dg-caret{flex:none;color:var(--muted);font-size:12px;transition:transform .4s cubic-bezier(.4,0,.2,1)}
.detail-group.open .dg-caret{transform:rotate(180deg)}
.detail-group-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .42s cubic-bezier(.4,0,.2,1)}
.detail-group.open .detail-group-body{grid-template-rows:1fr}
.dg-inner{overflow:hidden;min-height:0;padding:0 12px;opacity:0;transform:translateY(-5px);transition:opacity .32s ease .05s,transform .38s ease .05s,padding .42s cubic-bezier(.4,0,.2,1)}
.detail-group.open .dg-inner{opacity:1;transform:none;padding:2px 12px 12px}
.dg-inner>button,.dg-inner>input{width:100%;margin:4px 0}
.dg-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin:0;padding:6px 0;border-bottom:1px dashed color-mix(in srgb,var(--line),transparent 45%);font-size:13px}
.dg-row:last-child{border-bottom:0}
.dg-row-label{flex:none;color:var(--muted)}
.dg-row-value{text-align:right;font-weight:600;overflow-wrap:anywhere}
.contact-card{padding:8px 0;border-bottom:1px dashed color-mix(in srgb,var(--line),transparent 45%)}
.contact-card:last-child{border-bottom:0}
.contact-card strong{display:block;font-size:13px;overflow-wrap:anywhere}
@media(prefers-reduced-motion:reduce){
  .identity-card:before,.identity-dot.online{animation:none}
  .detail-group-body,.dg-inner,.dg-caret,.dg-icon,.detail-chip,.detail-group{transition-duration:.01ms}
}

/* Pinned messages sits with the search control, not in the tab cluster: it
   takes over the margin-left:auto so the pair stays right-aligned together. */
.pane-tabs #staffPinnedButton{margin-left:auto;width:36px;height:36px;min-height:36px;padding:0;border-radius:9px;display:grid;place-items:center;background:var(--panel2);font-size:16px;line-height:1;transition:transform .3s cubic-bezier(.34,1.56,.64,1),background .25s ease}
.pane-tabs #staffPinnedButton:hover{background:var(--hover);transform:translateY(-1px) rotate(-12deg)}
.pane-tabs #staffPinnedButton+#conversationSearchButton{margin-left:6px}

/* Search scope: names by default, messages/notes one tap away. */
.search-scope{display:flex;align-items:center;flex-wrap:wrap;gap:5px;padding:2px 1px 0;font-size:12px;animation:slideDown .22s var(--ez-out)}
.search-scope>span{color:var(--muted);margin-right:2px}
.search-scope button{min-height:26px;padding:3px 10px;border-radius:999px;font-size:12px;font-weight:600;color:var(--muted);background:var(--panel2);border:1px solid var(--line)}
.search-scope button:hover{color:var(--primary);border-color:color-mix(in srgb,var(--primary) 45%,var(--line))}
.search-scope button.active{color:var(--primary);background:color-mix(in srgb,var(--primary) 14%,var(--panel));border-color:color-mix(in srgb,var(--primary) 45%,var(--line))}

/* ---- on-screen alert stack ---------------------------------------------
   Sits over the sidebar brand block and stops short of the ☰ menu button, so
   alerts never cover the control you need to dismiss them from.            */
.staff-alert-stack{position:fixed;z-index:10050;width:238px;max-width:calc(100vw - 96px);
  display:flex;flex-direction:column-reverse;gap:6px;pointer-events:none;
  bottom:max(10px,env(safe-area-inset-bottom));right:10px;left:auto;top:auto;align-items:flex-end}
/* Owner-chosen placement (staff /me -> alert_position). Newest card always sits
   above the previous one (column-reverse) whichever corner it lives in. Default,
   with no pos- class, stays bottom-right. */
.staff-alert-stack.pos-top-left,.staff-alert-stack.pos-top-center,.staff-alert-stack.pos-top-right{
  top:max(10px,env(safe-area-inset-top));bottom:auto}
.staff-alert-stack.pos-bottom-left,.staff-alert-stack.pos-bottom-center,.staff-alert-stack.pos-bottom-right{
  bottom:max(10px,env(safe-area-inset-bottom));top:auto}
.staff-alert-stack.pos-top-left,.staff-alert-stack.pos-bottom-left{left:10px;right:auto;transform:none;align-items:flex-start}
.staff-alert-stack.pos-top-right,.staff-alert-stack.pos-bottom-right{right:10px;left:auto;transform:none;align-items:flex-end}
.staff-alert-stack.pos-top-center,.staff-alert-stack.pos-bottom-center{
  left:50%;right:auto;transform:translateX(-50%);align-items:center}
.staff-alert{display:flex;align-items:flex-start;gap:6px;padding:9px 8px 9px 11px;border-radius:12px;
  border:1px solid var(--line);background:var(--panel);color:var(--text);pointer-events:auto;
  box-shadow:0 12px 34px -12px rgba(0,0,0,.5),0 0 0 1px color-mix(in srgb,var(--primary) 22%,transparent);
  animation:staffAlertIn .22s cubic-bezier(.16,1,.3,1)}
/* Neutral entrance so it reads right from any of the six corners, not just the
   right edge (a translateX slide looked wrong on left/centre placements). */
@keyframes staffAlertIn{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}
.staff-alert-copy{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;padding:0;margin:0;border:0;
  background:transparent;text-align:left;min-height:0;color:inherit;cursor:pointer}
.staff-alert-copy strong{font-size:12.5px;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.staff-alert-copy span{font-size:12px;line-height:1.35;color:var(--muted);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}
.staff-alert-copy span.hidden{display:none!important}
.staff-alert-close{flex:none;width:22px;height:22px;min-height:22px;padding:0;border:0;border-radius:50%;
  background:transparent;color:var(--muted);font-size:16px;line-height:1;display:grid;place-items:center;cursor:pointer}
.staff-alert-close:hover{background:var(--hover);color:var(--text)}

/* Owner "Manage labels" dialog: one row per label — the chip (tap to recolour)
   and a delete that removes it brand-wide. */
.manage-labels-body{display:flex;flex-direction:column;gap:8px;padding:14px 16px 18px;max-height:60vh;overflow:auto}
.manage-label-row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.manage-label-row .label-chip{cursor:pointer;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.manage-label-row .danger-button{flex:none;padding:6px 12px;font-size:13px}

/* Game history: the open button in the games section + the ledger dialog. */
.game-history-open{width:100%;margin-top:8px;padding:9px;border-radius:10px;background:var(--panel);border:1px solid var(--line);font-weight:600;cursor:pointer}
.game-history-open:hover{background:var(--hover)}
.game-history-body{display:flex;flex-direction:column;gap:6px;padding:12px 14px 16px;max-height:62vh;overflow:auto}
.gh-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 10px;border:1px solid var(--line);border-radius:10px;flex-wrap:wrap}
.gh-left{display:flex;flex-direction:column;min-width:0;flex:1}
.gh-left strong{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gh-left small{color:var(--muted);font-size:11px}
.gh-amt{font-weight:700;font-size:13px;white-space:nowrap}
.gh-amt.in{color:#16a34a}.gh-amt.out{color:#dc2626}
.gh-bal{color:var(--muted);font-size:11px;width:100%;text-align:right}
.gh-row.gh-failed,.gh-row.gh-parked{opacity:.6}

/* Unread notes: badge on the notes tab + NEW marks in the list. */
.pane-tabs button[data-pane="notes"]{position:relative}
.notes-badge{position:absolute;top:1px;right:3px;min-width:16px;height:16px;padding:0 4px;border-radius:8px;
  background:#dc2626;color:#fff;font-size:10px;font-weight:700;line-height:16px;text-align:center;box-shadow:0 0 0 2px var(--bg)}
.notes-new-banner{background:color-mix(in srgb,var(--primary) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--primary) 30%,transparent);color:var(--text);
  border-radius:10px;padding:7px 10px;font-size:12px;font-weight:600;margin-bottom:6px}
.note-card.note-new{border-left:3px solid var(--primary)}
.note-card header .note-who{flex:1;min-width:0}
.note-new-tag{background:var(--primary);color:#fff;font-size:10px;font-weight:700;padding:1px 6px;border-radius:8px}

/* ---- formatting toolbar + live preview ---------------------------------- */
.format-bar{display:flex;flex-wrap:wrap;gap:4px;padding:6px 4px 2px}
.format-bar button{min-height:30px;padding:3px 9px;border-radius:8px;font-size:13px;
  background:var(--panel2);border:1px solid var(--line);color:var(--text)}
.format-bar button:hover{background:var(--hover);border-color:color-mix(in srgb,var(--primary) 45%,var(--line))}
.composer-preview{margin:0 0 6px;padding:8px 10px;border-radius:12px;background:var(--panel2);
  border:1px solid var(--line);animation:slideDown .18s var(--ez-out)}
.composer-preview>small{display:block;font-size:10.5px;text-transform:uppercase;letter-spacing:.4px;
  color:var(--muted);margin-bottom:5px}
.composer-preview.preview-error{background:color-mix(in srgb,var(--danger) 10%,var(--panel));
  border-color:color-mix(in srgb,var(--danger) 42%,var(--line))}
.composer-preview.preview-error>small{color:var(--danger);text-transform:none;font-size:12px;letter-spacing:0}
.preview-bubble{padding:8px 11px;border-radius:14px;background:var(--bubble-in,var(--panel));
  font-size:13.5px;line-height:1.4;overflow-wrap:anywhere;white-space:pre-wrap}
.preview-chip{display:inline-block;padding:1px 7px;margin:0 1px;border-radius:7px;
  background:rgba(125,125,125,.22);font-weight:600}
.preview-button{display:block;margin:7px 0 1px;padding:8px 12px;border-radius:10px;
  background:var(--primary);color:#fff;font-weight:700;text-align:center}
.code-prompt-fields{display:grid;gap:10px}
.code-prompt-fields label{display:grid;gap:4px;font-size:13px;color:var(--muted)}
.code-prompt-fields input{padding:11px;font-size:15px}
.code-prompt-note{color:var(--muted);font-size:12px}

/* ---- prompt builder inside Saved replies -------------------------------- */
.prompt-builder{margin-top:4px;padding:10px 11px;border:1px solid var(--line);border-radius:12px;background:var(--panel2)}
.prompt-builder-head{display:flex;align-items:center;justify-content:space-between;gap:8px}
.prompt-builder-head strong{font-size:13px}
.prompt-builder-head button{min-height:28px;padding:3px 10px;border-radius:8px;font-size:12px}
.prompt-builder>small{display:block;margin:5px 0 8px;font-size:11.5px;line-height:1.45;color:var(--muted)}
.prompt-builder code{padding:1px 5px;border-radius:5px;background:var(--hover);font-size:11.5px}
.prompt-field-list{display:grid;gap:7px}
.prompt-field{display:grid;grid-template-columns:1fr 1.4fr auto auto auto;gap:6px;align-items:center}
.prompt-field input[type=text]{padding:7px 9px;font-size:13px;min-width:0}
.prompt-field select{padding:7px 6px;font-size:12px}
.prompt-field label{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;color:var(--muted);white-space:nowrap}
.prompt-field button{width:28px;height:28px;min-height:28px;padding:0;border-radius:8px;color:var(--danger)}
@media(max-width:760px){.prompt-field{grid-template-columns:1fr 1fr}}

/* Formatted messages inside the staff thread, matching the customer view. */
.bubble .preview-chip{display:inline-flex;align-items:center;gap:4px;padding:1px 7px;margin:0 1px;
  border:1px solid rgba(125,125,125,.35);border-radius:7px;background:rgba(125,125,125,.22);
  font:inherit;font-weight:600;color:inherit;vertical-align:baseline}
.bubble .preview-chip.copyable{cursor:pointer}
.bubble .preview-chip.copyable:hover{background:rgba(125,125,125,.34)}
.bubble .preview-button{display:block;margin:8px 0 2px;padding:9px 13px;border-radius:11px;
  background:rgba(255,255,255,.22);color:inherit;font-weight:700;text-align:center}
.employee .bubble .preview-button{background:rgba(255,255,255,.24)}
.customer .bubble .preview-button{background:var(--primary);color:#fff}

/* ---- animated emoji ----------------------------------------------------
   Ordinary glyphs animated with CSS: nothing to download, works offline,
   stays sharp at any size. Motion is disabled for anyone who asks for that. */
.fc-gif{display:inline-block;font-style:normal;line-height:1;vertical-align:-.12em;will-change:transform}
.fc-gif-loading{animation:fcgSpin 1.6s linear infinite}
.fc-gif-spinner{animation:fcgSpin 1s linear infinite}
.fc-gif-clock{animation:fcgSpin 2.4s steps(8) infinite}
.fc-gif-hourglass{animation:fcgFlip 2s ease-in-out infinite}
.fc-gif-check{animation:fcgPop 1.8s ease-out infinite}
.fc-gif-cross{animation:fcgShake .9s ease-in-out infinite}
.fc-gif-warning{animation:fcgBlink 1.1s ease-in-out infinite}
.fc-gif-bell{animation:fcgRing 1.6s ease-in-out infinite;transform-origin:50% 0}
.fc-gif-fire{animation:fcgFlicker .55s ease-in-out infinite alternate}
.fc-gif-money{animation:fcgBounce 1s ease-in-out infinite}
.fc-gif-party{animation:fcgShake 1.2s ease-in-out infinite}
.fc-gif-star{animation:fcgTwinkle 1.4s ease-in-out infinite}
.fc-gif-heart{animation:fcgBeat .9s ease-in-out infinite}
.fc-gif-wave{animation:fcgWave 1.1s ease-in-out infinite;transform-origin:70% 80%}
.fc-gif-thumbsup{animation:fcgPop 1.5s ease-out infinite}
.fc-gif-rocket{animation:fcgRise 1.6s ease-in-out infinite}
.fc-gif-gift{animation:fcgShake 1.6s ease-in-out infinite}
.fc-gif-crown{animation:fcgTwinkle 1.8s ease-in-out infinite}
.fc-gif-dice{animation:fcgSpin 1.4s ease-in-out infinite}
.fc-gif-gem{animation:fcgTwinkle 1.2s ease-in-out infinite}
@keyframes fcgSpin{to{transform:rotate(360deg)}}
@keyframes fcgFlip{0%,45%{transform:rotate(0)}55%,100%{transform:rotate(180deg)}}
@keyframes fcgPop{0%,70%,100%{transform:scale(1)}80%{transform:scale(1.28)}}
@keyframes fcgShake{0%,100%{transform:rotate(0)}25%{transform:rotate(11deg)}75%{transform:rotate(-11deg)}}
@keyframes fcgBlink{0%,100%{opacity:1}50%{opacity:.35}}
@keyframes fcgRing{0%,60%,100%{transform:rotate(0)}70%{transform:rotate(14deg)}85%{transform:rotate(-14deg)}}
@keyframes fcgFlicker{from{transform:scale(1) translateY(0);filter:brightness(1)}to{transform:scale(1.13) translateY(-1px);filter:brightness(1.25)}}
@keyframes fcgBounce{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
@keyframes fcgTwinkle{0%,100%{transform:scale(1) rotate(0);opacity:1}50%{transform:scale(1.22) rotate(18deg);opacity:.75}}
@keyframes fcgBeat{0%,100%{transform:scale(1)}30%{transform:scale(1.24)}45%{transform:scale(1.05)}}
@keyframes fcgWave{0%,100%{transform:rotate(0)}30%{transform:rotate(22deg)}60%{transform:rotate(-12deg)}}
@keyframes fcgRise{0%,100%{transform:translateY(0) rotate(0)}50%{transform:translateY(-6px) rotate(-8deg)}}
/* These are CONTENT — a staff member inserts one the way they would a GIF,
   and a GIF plays regardless of this setting. So reduced motion slows them
   right down rather than stopping them, which previously made them look
   broken on any device with battery saver or "remove animations" on.
   Decorative UI animation elsewhere still honours the setting fully. */
@media(prefers-reduced-motion:reduce){.fc-gif{animation-duration:3.2s!important}}
.contact-shared-note{display:block;margin:3px 0 2px;font-size:11.5px;color:var(--muted)}
.may-know-row{display:flex;align-items:stretch;gap:5px}
.may-know-row .may-know-person{flex:1;min-width:0}
.may-know-remove{flex:none;width:28px;min-height:28px;padding:0;border-radius:8px;color:var(--danger);align-self:center}
.may-know-remove:hover{background:color-mix(in srgb,var(--danger) 14%,transparent)}
.color-picker-body{display:grid;gap:12px;padding:14px}
.color-swatches{display:grid;grid-template-columns:repeat(auto-fill,minmax(42px,1fr));gap:8px}
.color-swatch{height:42px;min-height:42px;padding:0;border-radius:10px;border:1px solid rgba(125,125,125,.35);
  cursor:pointer;transition:transform .18s cubic-bezier(.34,1.56,.64,1),box-shadow .18s ease}
.color-swatch:hover{transform:translateY(-2px) scale(1.06);box-shadow:0 8px 18px -8px rgba(0,0,0,.6)}
.color-custom{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:13px;
  padding:9px 11px;border:1px solid var(--line);border-radius:11px;background:var(--panel2)}
.color-custom input[type=color]{width:52px;height:32px;padding:0;border-radius:8px;cursor:pointer}
.color-hint{color:var(--muted);font-size:12px;line-height:1.45}

/* Recharge and Cash Out sit side by side and are colour-coded, so the
   direction the money moves is decided by which button you press rather than
   by remembering a minus sign. */
.wallet-action-row{display:flex;gap:8px;margin:4px 0}
.wallet-action-row.hidden{display:none}
.dg-inner>.wallet-action-row>button{flex:1;width:auto;margin:0}
.wallet-action{position:relative;overflow:hidden;font-weight:600;transition:transform .18s ease,box-shadow .28s ease,filter .28s ease}
.wallet-action.recharge{border-color:rgba(52,199,89,.45);box-shadow:inset 0 0 0 1px rgba(52,199,89,.12)}
.wallet-action.cashout{border-color:rgba(255,149,0,.45);box-shadow:inset 0 0 0 1px rgba(255,149,0,.12)}
.wallet-action:hover{transform:translateY(-1px);filter:brightness(1.08)}
.wallet-action.recharge:hover{box-shadow:0 8px 18px -10px rgba(52,199,89,.8),inset 0 0 0 1px rgba(52,199,89,.3)}
.wallet-action.cashout:hover{box-shadow:0 8px 18px -10px rgba(255,149,0,.8),inset 0 0 0 1px rgba(255,149,0,.3)}
.wallet-action:active{transform:translateY(0) scale(.985)}
@media (prefers-reduced-motion:reduce){.wallet-action{transition-duration:.01ms}}

/* ---- reports: leaderboard + one person's record ---------------------- */
.report-body{padding:12px 14px 22px;display:flex;flex-direction:column;gap:12px}
.report-periods,.report-sorts{display:flex;flex-wrap:wrap;gap:6px}
.report-periods button,.report-sorts button{padding:6px 12px;border:1px solid var(--line);border-radius:999px;
  background:var(--panel2);color:var(--muted);font-size:12.5px;cursor:pointer;
  transition:background .22s ease,color .22s ease,border-color .22s ease,transform .16s ease}
.report-periods button:hover,.report-sorts button:hover{transform:translateY(-1px);color:var(--text)}
.report-periods button.active,.report-sorts button.active{background:var(--accent,#0084ff);border-color:transparent;color:#fff;font-weight:600}
.report-heading{margin:6px 0 0;font-size:13px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}
.report-lead{margin:0;font-size:13px;color:var(--muted)}
.report-totals{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:8px}
.report-totals.compact{grid-template-columns:repeat(auto-fit,minmax(92px,1fr))}
.report-card{padding:11px 12px;border:1px solid var(--line);border-radius:13px;background:var(--panel2);
  display:flex;flex-direction:column;gap:2px;box-shadow:inset 0 1px 0 rgba(255,255,255,.04)}
.report-card strong{font-size:16px;font-variant-numeric:tabular-nums}
.report-card small{font-size:11px;color:var(--muted)}
.report-card.in strong{color:#34c759}
.report-card.out strong{color:#ff9500}
.report-board{display:flex;flex-direction:column;gap:6px}
.report-row{display:grid;grid-template-columns:30px minmax(90px,1fr) auto;align-items:center;gap:8px;
  padding:9px 10px;border:1px solid var(--line);border-radius:12px;background:var(--panel2);
  transition:transform .18s ease,box-shadow .28s ease}
.report-row:hover{transform:translateY(-1px);box-shadow:0 8px 18px -12px rgba(0,0,0,.7)}
.report-rank{font-size:14px;text-align:center;color:var(--muted);font-variant-numeric:tabular-nums}
.report-name{border:0;background:transparent;color:var(--text);font-weight:600;font-size:13.5px;
  text-align:left;padding:0;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.report-name:hover:not(:disabled){text-decoration:underline}
.report-name:disabled{cursor:default}
.report-figures{display:flex;flex-wrap:wrap;gap:4px 10px;justify-content:flex-end}
.report-figure{display:flex;flex-direction:column;align-items:flex-end;min-width:58px}
.report-figure strong{font-size:12.5px;font-variant-numeric:tabular-nums}
.report-figure small{font-size:10px;color:var(--muted)}
.report-figure.in strong{color:#34c759}
.report-figure.out strong{color:#ff9500}
.image-attachment{position:relative}

/* Freeplay. Purple everywhere and never green, because green on this screen
   means money came in — and this did not. The block is inset and dimmer than
   the real figures so it cannot be mistaken for part of the totals above it. */
.report-card.promo strong,.report-figure.promo strong{color:#af7aff}
.report-freeplay{display:flex;flex-direction:column;gap:8px;padding:10px;
  border:1px dashed color-mix(in srgb,#af7aff 45%,var(--line));border-radius:14px;
  background:color-mix(in srgb,#af7aff 6%,transparent)}
.report-freeplay .report-heading{margin:0;color:#af7aff}
.report-freeplay .report-card{background:var(--panel)}
.report-empty{margin:0;padding:14px;text-align:center;color:var(--muted);font-size:13px}
.report-csv{margin-top:6px}
@media (max-width:520px){
  .report-row{grid-template-columns:26px 1fr;grid-template-areas:'rank name' 'figs figs'}
  .report-rank{grid-area:rank}.report-name{grid-area:name}
  .report-figures{grid-area:figs;justify-content:flex-start;margin-top:4px}
}
@media (prefers-reduced-motion:reduce){
  .report-row,.report-periods button,.report-sorts button{transition-duration:.01ms}
}

/* Storing a token is what connects a game; the login button is only a way to
   fetch one. Saying so here saves the same question being asked again. */
.game-connect-hint{margin:0 0 10px;padding:9px 11px;border-radius:11px;
  background:var(--panel2);border:1px solid var(--line);
  color:var(--muted);font-size:12px;line-height:1.5}
.game-connect-manual{color:var(--muted);font-size:11.5px;text-align:right;white-space:nowrap}

/* The inbox loads a page at a time; this is the marker at the bottom. */
.conversation-more{padding:14px;text-align:center;color:var(--muted);font-size:12.5px;letter-spacing:.02em}
/* A name change is only useful with the name it replaced. */
.name-history-change{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px}
.name-was{color:var(--muted);text-decoration:line-through;text-decoration-thickness:1px}
.name-arrow{color:var(--muted);font-size:12px}
.name-now{color:var(--text)}
.staff-game-move{display:flex;gap:6px;margin-left:auto}
.staff-game-move button{padding:3px 9px;font-size:12px;border-radius:8px}

/* Requests parked while a game panel was down. They clear themselves when a
   token arrives; these are the manual ways out. */
.staff-pending-list{display:flex;flex-direction:column;gap:6px;margin:2px 0 8px}
.staff-pending-head{margin:0;font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:#ff9500}
.staff-pending-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:9px 10px;border:1px solid rgba(255,149,0,.4);border-radius:12px;
  background:color-mix(in srgb,#ff9500 8%,var(--panel2));
  box-shadow:inset 0 0 0 1px rgba(255,149,0,.08)}
.staff-pending-row .staff-game-label{flex:1;min-width:130px}
.staff-pending-actions{display:flex;gap:6px;margin-left:auto}
.staff-pending-actions button{padding:4px 10px;font-size:12px;border-radius:9px}

/* Automatic customer messages — the wording of everything the system says on
   its own, kept apart from saved replies. */
.sysmsg-body{padding:12px 14px 22px;display:flex;flex-direction:column;gap:12px}
.sysmsg-intro{margin:0;padding:10px 12px;border-radius:11px;background:var(--panel2);
  border:1px solid var(--line);color:var(--muted);font-size:12.5px;line-height:1.55}
.sysmsg-card{display:flex;flex-direction:column;gap:7px;padding:12px;border:1px solid var(--line);
  border-radius:13px;background:var(--panel2);transition:opacity .25s ease,border-color .25s ease}
.sysmsg-card.off{opacity:.62;border-color:rgba(255,149,0,.4)}
.sysmsg-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.sysmsg-head strong{font-size:14px}
.sysmsg-toggle{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);cursor:pointer;user-select:none}
.sysmsg-toggle input{width:16px;height:16px;cursor:pointer}
.sysmsg-why{color:var(--muted);font-size:12px;line-height:1.5}
.sysmsg-text{width:100%;min-height:64px;resize:vertical;padding:9px 11px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel);color:var(--text);font:inherit;font-size:13px;line-height:1.5}
.sysmsg-chips{display:flex;flex-wrap:wrap;align-items:center;gap:5px}
.sysmsg-chips small{color:var(--muted);font-size:11px;margin-right:2px}
.sysmsg-chip{padding:3px 8px;border:1px solid var(--line);border-radius:999px;background:var(--panel);
  color:var(--muted);font-size:11.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;cursor:pointer;
  transition:transform .16s ease,color .2s ease}
.sysmsg-chip:hover{transform:translateY(-1px);color:var(--text)}
.sysmsg-actions{display:flex;align-items:center;gap:10px}
.sysmsg-actions .primary-button{padding:5px 14px;font-size:13px}
.sysmsg-status{color:var(--muted);font-size:11.5px;margin-left:auto}
.sysmsg-empty{padding:16px;text-align:center;color:var(--muted);font-size:13px}
@media (prefers-reduced-motion:reduce){.sysmsg-card,.sysmsg-chip{transition-duration:.01ms}}

/* Why a game card would not save, shown on the card itself. */
.sysmsg-status.gs-error{color:var(--danger,#e0245e);font-weight:600}

/* Per-game "keep the session alive" control. */
.gs-auto{display:grid;gap:6px}
.gs-auto-why{color:var(--muted);font-size:12px;line-height:1.45}
.gs-auto-line{display:flex;align-items:center;gap:8px;flex-wrap:wrap;cursor:pointer}
.gs-auto-line input[type=checkbox]{width:18px;height:18px;margin:0;flex:none}
.gs-auto-every{font-size:12.5px;color:var(--muted)}
.gs-auto-seconds{width:92px;padding:6px 8px}
.gs-auto-seconds:disabled{opacity:.5}

/* The connections screen: one Check button per game, beside its login button. */
.game-connect-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.game-connect-actions .ghost-button{padding:7px 13px;font-size:13px;font-weight:600;
  border:1px solid var(--line);border-radius:9px;background:transparent;color:var(--text);
  min-height:34px;cursor:pointer}
.game-connect-actions .ghost-button:hover:not(:disabled){background:var(--hover)}
.game-connect-actions .ghost-button:disabled{opacity:.55;cursor:default}

/* One click on a name in the chat header copies that name, a double click
   copies all of it. The only feedback is a brief pill, so nothing is added to
   the header that has to be read. */
.copyable-name{cursor:pointer;position:relative;user-select:none;-webkit-user-select:none}
/* `.header-copy span` styles the small grey meta line under the name. Splitting
   the name into word spans put it inside that selector, so the name has to take
   its size, weight and colour back from the <strong> it lives in. */
.copyable-name .name-part{font:inherit;color:inherit;letter-spacing:inherit;
  max-width:none;white-space:inherit;overflow:visible;text-overflow:clip;
  border-radius:6px;padding:0 2px;margin:0 -2px;
  transition:background .12s ease}
@media (hover:hover){.copyable-name .name-part:hover{background:rgba(128,128,140,.22)}}
.copyable-name .name-part:active{background:rgba(128,128,140,.3)}
.copied-pill{position:fixed;z-index:9999;transform:translate(-50%,-4px);
  padding:3px 10px;border-radius:999px;background:var(--primary,#0084ff);color:#fff;
  font-size:11.5px;font-weight:600;letter-spacing:.02em;white-space:nowrap;
  max-width:70vw;overflow:hidden;text-overflow:ellipsis;
  box-shadow:0 6px 16px -8px rgba(0,0,0,.6);
  opacity:0;pointer-events:none;transition:opacity .14s ease,transform .14s ease}
.copied-pill.show{opacity:1;transform:translate(-50%,0)}
@media (prefers-reduced-motion:reduce){.copied-pill{transition-duration:.01ms}}
/* The copy button shows it is working while the image is fetched and encoded. */
.image-copy-button.busy{opacity:.55;pointer-events:none}
.image-copy-button.busy svg{animation:fcSpinCopy .8s linear infinite}
@keyframes fcSpinCopy{to{transform:rotate(360deg)}}

/* Game agent logins and download links. */
.gs-card{gap:10px}
.gs-state{padding:2px 9px;border-radius:999px;font-size:11px;font-weight:600}
.gs-state.ok{background:color-mix(in srgb,#34c759 18%,transparent);color:#34c759}
.gs-state.warn{background:color-mix(in srgb,#ff9500 18%,transparent);color:#ff9500}
.gs-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}
.gs-field{display:flex;flex-direction:column;gap:3px;min-width:0}
.gs-field small{color:var(--muted);font-size:11px}
.gs-field input{width:100%;padding:8px 10px;border-radius:9px;border:1px solid var(--line);
  background:var(--panel);color:var(--text);font-size:13px}

/* A balance costs a call to the game's panel, so staff ask for one at a time. */
.staff-game-balance.tap-to-load{font-size:12px;font-weight:600;color:var(--primary,#0084ff);
  padding:4px 9px;border-radius:999px;background:rgba(0,132,255,.10);cursor:pointer;white-space:nowrap}
.staff-game-balance.tap-to-load:hover{background:rgba(0,132,255,.18)}
/* The game rows sat in one dense block; this gives each its own line and air. */
.staff-game-row{align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line)}
.staff-game-row:last-child{border-bottom:0}
.staff-game-move{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}

/* The customer's game rows: name + username on the left, the last known
   balance, its own refresh, then + / - / unlink as icons. Words took the space
   these rows needed for sixteen games. */
.staff-game-row{display:flex;align-items:center;gap:8px}
.staff-game-row .staff-game-label{flex:1;min-width:0}
.staff-game-row .staff-game-balance{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}
.staff-game-row .wallet-action{min-width:30px;padding:4px 8px;font-size:15px;line-height:1;font-weight:700}
.staff-game-row .gs-reread{font-size:14px;font-weight:400;opacity:.75}
.staff-game-row .gs-reread:hover:not(:disabled){opacity:1}
.staff-game-row .gs-reread:disabled{opacity:.4}
.staff-game-row .link-button{font-size:15px;padding:2px 6px;line-height:1}

/* The (i) beside a game balance, and what it says.

   Every game number on this screen is the stored one — the last answer that
   panel gave — and nothing about a two-day-old figure looks different from a
   live one. The marker is deliberately quiet: it is there for the moment
   somebody needs to know, not competing with the balance itself.

   It sits to the LEFT of the ↻ so the reading (how old) is next to the number
   it describes, and the action (read it now) stays where the hand already
   expects it. */
.staff-game-row .gs-age{
  background:none;border:0;margin:0;padding:0 1px;
  font-size:12px;line-height:1;color:var(--muted);opacity:.65;
  cursor:help;
  /* A 12px glyph is not a tap target. This keeps the ink small and the
     touchable area the size of a fingertip. */
  min-width:24px;min-height:24px;
  display:inline-flex;align-items:center;justify-content:center;
  /* Reclaims what that padding would otherwise add to a sixteen-game row. */
  margin-inline:-4px;
}
.staff-game-row .gs-age:hover,
.staff-game-row .gs-age:focus-visible{opacity:1;color:var(--primary)}

.gs-agetip{
  position:fixed;z-index:200;max-width:min(280px,calc(100vw - 16px));
  padding:8px 10px;border-radius:8px;
  background:#1c1c1e;color:#fff;
  font-size:12px;line-height:1.45;font-weight:400;
  box-shadow:0 6px 20px rgba(0,0,0,.28);
  /* Hidden with visibility rather than display, so it can still be measured
     before it is placed — otherwise it lands in the wrong spot on first show. */
  opacity:0;visibility:hidden;transition:opacity .12s ease;
  /* Never steals the pointer: hovering the tooltip must not count as leaving
     the button that opened it. */
  pointer-events:none;
}
.gs-agetip.is-on{opacity:1;visibility:visible}
@media(prefers-reduced-motion:reduce){.gs-agetip{transition:none}}

/* The owner's open/closed switch on each game card. */
.gs-power{display:inline-flex;align-items:center;gap:6px;margin-left:auto;margin-right:8px;
  font-size:12px;font-weight:700;color:var(--muted);cursor:pointer;user-select:none}
.gs-power input{width:34px;height:19px;margin:0;cursor:pointer}
/* The stronger "hide from customers entirely" switch sits right beside open/closed
   (not pushed to its own edge) and is tinted danger-red so it never reads as the
   same thing as merely closing a game. */
.gs-hide{margin-left:0}
.gs-hide input{accent-color:var(--danger,#e0245e)}
.gs-state.off{background:rgba(224,36,94,.14);color:var(--danger,#e0245e)}

/* Freeplay in the staff panel. Brass, and never styled like the cash row above
   it: staff quote these numbers to customers, and the two must not blur. */
.staff-freeplay-row{align-items:baseline}
.staff-freeplay-row strong{color:#9A7B12}
.staff-freeplay-worth{margin-left:8px;font-size:12px;color:var(--muted,#6b7480)}
.wallet-action.freeplay{background:rgba(154,123,18,.14);color:#7a610e}
.wallet-action.freeplay-out{background:rgba(0,0,0,.05)}
@media (prefers-color-scheme:dark){
  .staff-freeplay-row strong{color:#D9B75A}
  .wallet-action.freeplay{background:rgba(217,183,90,.18);color:#E8CE8A}
  .wallet-action.freeplay-out{background:rgba(255,255,255,.07)}
}

/* ---- live game activity ------------------------------------------------
   A feed that is read while something is going wrong, so it is built for
   scanning: failures carry colour, timings carry colour, and the newest row
   arrives at the top rather than making somebody scroll for it. */
#gameFeedDialog>header{gap:10px}
.feed-toggle{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--muted);white-space:nowrap}
.feed-toggle input{width:auto}
.feed-live{font-size:12px;color:#22c55e;margin-left:auto}

.feed-health{display:flex;flex-wrap:wrap;gap:8px;padding:12px 14px;border-bottom:1px solid var(--line)}
.feed-chip{display:flex;flex-direction:column;gap:2px;padding:8px 11px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel2);font-size:12px;min-width:150px}
.feed-chip strong{font-size:13px}
.feed-chip span{color:var(--muted)}
/* A panel that is failing is the reason this window exists. */
.feed-chip.is-bad{border-color:#ef4444;background:rgba(239,68,68,.08)}
.feed-chip.is-resting{opacity:.7}
.feed-chip em{color:#f59e0b;font-style:normal}
.feed-chip-speed.is-middling{color:#f59e0b}
.feed-chip-speed.is-slow{color:#ef4444}

.feed-list{overflow:auto;max-height:60dvh;padding:6px 0}
.feed-row{display:grid;grid-template-columns:74px 1fr auto 58px;gap:10px;align-items:baseline;
  padding:8px 14px;border-bottom:1px solid var(--line);font-size:13px}
.feed-row.is-fail{background:rgba(239,68,68,.07)}
/* Only the arrival is animated — a list that keeps moving is unreadable. */
.feed-row.is-new{animation:feedIn .35s ease}
@keyframes feedIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.feed-row.is-new{animation:none}}

.feed-when{color:var(--muted);font-size:12px;white-space:nowrap}
.feed-what{min-width:0}
.feed-who{border:0;background:transparent;padding:0;font:inherit;font-weight:600;
  color:var(--primary);cursor:pointer;text-align:left}
.feed-who:disabled{color:inherit;cursor:default}
.feed-who:hover:not(:disabled){text-decoration:underline}
.feed-said{color:inherit}
.feed-by{color:var(--muted);font-size:12px}
.feed-outcome{color:var(--muted);font-size:12px;text-align:right;max-width:34ch;
  overflow-wrap:anywhere}
.feed-row.is-fail .feed-outcome{color:#ef4444}
/* Tapping shows what the panel really said. */
.feed-outcome.has-detail{cursor:pointer;text-decoration:underline dotted}
.feed-took{text-align:right;font-variant-numeric:tabular-nums;color:var(--muted);font-size:12px}
.feed-took.is-middling{color:#f59e0b}
.feed-took.is-slow{color:#ef4444;font-weight:700}
.feed-empty{padding:26px 16px;text-align:center;color:var(--muted)}

@media(max-width:640px){
  .feed-row{grid-template-columns:1fr auto;row-gap:2px}
  .feed-when{grid-column:1}
  .feed-took{grid-column:2}
  .feed-what,.feed-outcome{grid-column:1/-1;text-align:left;max-width:none}
}

/* Day headings in the activity feed — seven days of rows need somewhere to
   break, or finding "that afternoon" means scrolling by feel. */
.feed-day{position:sticky;top:0;z-index:1;padding:7px 14px;
  background:var(--panel);border-bottom:1px solid var(--line);
  font-size:12px;font-weight:700;color:var(--muted);letter-spacing:.02em}

/* --------------------------------------------------------- panel groups
   Two tabs, because filling in a group's logins is shared work while
   choosing what this domain uses is local, and mixing them on one screen
   makes it easy to change every brand when you meant to change one. */
/* Wider than a normal sheet on purpose. Six columns in a 520px dialog left
   about 50px each for username, password and proxy — too narrow to read
   back what you typed, which is a poor way to enter a credential that is
   never shown again. */
#panelGroupsDialog{max-width:min(960px,96vw);width:min(960px,96vw)}
.panel-tabs{display:flex;gap:6px;margin:0 0 12px}
.panel-tab{flex:1;padding:9px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--panel);font:inherit;font-size:13.5px;font-weight:600;color:var(--muted);cursor:pointer}
.panel-tab.active{background:var(--primary);border-color:var(--primary);color:#fff}

.panel-group-new{display:flex;gap:8px;margin:0 0 14px}
.panel-group-new input{flex:1;min-width:0}

.panel-group{margin:0 0 16px;padding:12px;border:1px solid var(--line);border-radius:12px;background:var(--panel)}
.panel-group>header{display:flex;align-items:center;gap:10px;margin:0 0 10px;padding:0;border:0;min-height:0}
.panel-group>header strong{font-size:15px}
.panel-group-count{margin-left:auto;font-size:11.5px;font-weight:600;color:var(--muted);
  padding:2px 8px;border-radius:999px;background:var(--hover)}
/* Who owns a group, and whether it is shared. A group from another brand is
   read-only here: dimmer, and the "shared by" label instead of a checkbox. */
.panel-group-share{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--muted);cursor:pointer;white-space:nowrap}
.panel-group-share input{margin:0}
.panel-group-from{font-size:11px;color:var(--muted);font-style:italic;white-space:nowrap}
.panel-group-shared{opacity:.82;border-style:dashed}
.panel-group-shared .panel-cred-row input:disabled,
.panel-group-shared .panel-cred-row button:disabled{opacity:.6;cursor:not-allowed}

/* One line per game: name, username, password, proxy, state, save. It scrolls
   sideways rather than wrapping, so the columns stay lined up down the list. */
.panel-cred-row{display:grid;grid-template-columns:130px 1fr 1fr 1fr 110px auto;
  gap:8px;align-items:center;padding:6px 0;border-top:1px solid var(--line)}
.panel-cred-row:first-of-type{border-top:0}
.panel-cred-row label{font-size:13px;color:var(--muted);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.panel-cred-row input{min-width:0;padding:7px 9px;font-size:13px}
.panel-cred-state{font-size:11.5px;color:var(--muted);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.panel-cred-row button{padding:7px 14px;font-size:13px;white-space:nowrap}

.panel-choice-row{display:grid;grid-template-columns:1fr 220px;gap:10px;align-items:center;
  padding:8px 0;border-bottom:1px solid var(--line)}
.panel-choice-row label{font-size:14px}
.panel-choice-row select{width:100%;min-width:0}

/* Narrow screens: the six-column row cannot survive a phone, so it stacks and
   the labels carry the meaning instead of the column position. */
@media (max-width:900px){
  .panel-cred-row{grid-template-columns:1fr 1fr;gap:6px}
  .panel-cred-row label{grid-column:1 / -1;font-weight:600;color:var(--text)}
  .panel-cred-state{grid-column:1 / -1}
  .panel-choice-row{grid-template-columns:1fr;gap:4px}
}

/* The wallet tag beside a name in the conversation list. Quieter than the
   name and never wider than it needs to be, so it reads as an identifier
   rather than competing with the person. */
.row-tag{font-weight:600;font-size:11px;color:var(--primary);background:var(--selected);padding:1px 6px;border-radius:999px;vertical-align:middle}

/* The wallet tag under the customer's name in the details panel. Quiet enough
   not to compete with the name, but selectable at a glance — it is the thing
   staff are most often asked to read back. */
.identity-tag{
  align-self:flex-start;
  margin:2px 0 1px;padding:1px 8px;
  border:0;border-radius:999px;
  font:inherit;font-size:12px;font-weight:700;
  color:var(--primary);background:var(--selected);
  cursor:pointer;
}

/* A contact this account no longer holds. Dimmed and struck through so it reads
   as history at a glance — it is shown because it is part of the story, not
   because it is a way to reach anybody. */
.contact-card.contact-removed strong{opacity:.6;text-decoration:line-through}
.contact-card.contact-removed{opacity:.85}
/* Someone who USED to hold this contact, as opposed to someone who holds it
   alongside this account. Same button, quieter, so the two lists cannot be
   mistaken for each other. */
.detail-link-button.contact-past{opacity:.8;font-style:italic}

/* ------------------------------------------------------------ quick actions
   The owner's setup screen and the queue of customers who say they have sent
   money. Both are built in JS, so everything they use is declared here. */
.qa-admin.wide{max-width:min(720px,94vw)}
.qa-admin-body{padding:14px 16px 20px;display:flex;flex-direction:column;gap:10px;overflow-y:auto}
.qa-admin-heading{margin:12px 0 2px;font-size:13px;font-weight:700;letter-spacing:.02em;
  text-transform:uppercase;opacity:.7}
.qa-admin-note{margin:0;font-size:13px;line-height:1.45;opacity:.8}
.qa-admin-list{display:flex;flex-direction:column;gap:8px}
.qa-admin-row{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:10px;
  background:var(--panel-2,rgba(127,127,127,.08))}
/* A switched-off button is still readable — it is a row somebody is about to
   switch back on, not a disabled control. */
.qa-admin-row.is-off{opacity:.55}
.qa-admin-main{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}
.qa-admin-does{font-size:12px;opacity:.7;line-height:1.35}
.qa-admin-icon{width:52px;text-align:center;font-size:16px;padding:6px 4px;
  border:1px solid var(--line,rgba(127,127,127,.28));border-radius:8px;background:transparent;
  color:inherit}
.qa-admin-label{width:100%;padding:6px 8px;border:1px solid var(--line,rgba(127,127,127,.28));
  border-radius:8px;background:transparent;color:inherit;font-size:14px}
.qa-admin-move{min-width:32px;min-height:32px;border:0;border-radius:8px;background:transparent;
  color:inherit;font-size:15px;cursor:pointer}
.qa-admin-move:disabled{opacity:.3;cursor:default}
.qa-admin-move:hover:not(:disabled){background:var(--hover,rgba(127,127,127,.14))}
/* There is no base .ghost-button rule in this stylesheet — only .danger and a
   scoped one — so these declare their own look rather than inheriting nothing. */
.qa-admin-action{padding:7px 13px;border:1px solid var(--line,rgba(127,127,127,.28));
  border-radius:8px;background:transparent;color:inherit;font-size:13px;font-weight:600;
  cursor:pointer}
.qa-admin-action:hover:not(:disabled){background:var(--hover,rgba(127,127,127,.14))}
.qa-admin-action:disabled{opacity:.55;cursor:default}
.qa-admin-amounts{display:flex;gap:10px;flex-wrap:wrap}
.qa-field{display:flex;flex-direction:column;gap:4px;flex:1;min-width:180px;font-size:13px}
.qa-field.short{flex:0 0 160px;min-width:140px}
.qa-field span{opacity:.75}
.qa-field input{padding:8px 10px;border:1px solid var(--line,rgba(127,127,127,.28));
  border-radius:8px;background:transparent;color:inherit;font-size:14px}
.qa-queue-row{gap:10px}
.qa-queue-who{flex:0 0 auto;max-width:42%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  border:0;background:transparent;color:var(--accent,#2f6fed);font-weight:600;font-size:14px;
  text-align:left;cursor:pointer}
.qa-queue-who:disabled{color:inherit;opacity:.7;cursor:default}
.qa-queue-what{font-size:14px;font-weight:600}
.qa-customer-recharges{display:flex;flex-direction:column;gap:8px;margin-top:10px}
.qa-customer-recharges.hidden{display:none}
.qa-admin-say{display:inline-flex;align-items:center;gap:6px;margin-top:4px;
  font-size:12px;opacity:.85;cursor:pointer;user-select:none}
.qa-admin-say input{margin:0}
/* Two accounts on one device is the thing worth noticing on this screen, so
   it gets a colour rather than being one row among twenty. */
.qa-share-warn{background:rgba(220,150,20,.14);border:1px solid rgba(220,150,20,.4)}

/* ---------------------------------------------- the quick-actions editor
   A preview at the top and four tabs, because the first version put every
   setting on one scroll and read as an unfinished form. */
.qa-preview{border-radius:14px;padding:12px 10px;margin-bottom:4px;
  background:var(--panel-2,rgba(127,127,127,.10))}
.qa-preview-bar{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none}
.qa-preview-bar::-webkit-scrollbar{display:none}
.qa-preview-button{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:6px;min-width:76px;min-height:72px;padding:10px 10px 8px;
  border-radius:18px;background:var(--panel,#fff);
  box-shadow:0 1px 2px rgba(0,0,0,.12)}
.qa-preview-icon{display:flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:50%;font-size:17px;
  background:rgba(0,132,255,.13);color:#0084ff}
.qa-preview-icon svg{width:19px;height:19px;display:block}
.qa-preview-label{line-height:1.15;white-space:nowrap}

.qa-tabs{display:flex;gap:6px;margin:10px 0 2px;flex-wrap:wrap}
.qa-tab{padding:7px 14px;border:0;border-radius:999px;cursor:pointer;font-size:13px;
  font-weight:600;background:var(--panel-2,rgba(127,127,127,.10));color:inherit}
.qa-tab.is-on{background:var(--accent,#2f6fed);color:#fff}
.qa-pane{margin-top:6px}
.qa-pane > .hidden{display:none}

.qa-color-field{display:flex;align-items:center;gap:10px;padding:9px 10px;
  border-radius:10px;background:var(--panel-2,rgba(127,127,127,.08));font-size:13px}
.qa-color-field > span:first-child{flex:1}
.qa-color-controls{display:flex;align-items:center;gap:8px}
.qa-color-field input[type=color]{width:44px;height:30px;padding:0;border:0;
  background:none;cursor:pointer}
.qa-color-field input[type=range]{flex:1;max-width:190px}
/* The letter a customer will see when a method has no drawn mark. */
.qa-method-mark{display:flex;align-items:center;justify-content:center;
  width:32px;height:32px;border-radius:9px;flex:0 0 auto;
  background:var(--accent,#2f6fed);color:#fff;font-weight:700;font-size:15px}

/* The $$ picker: the buttons THIS customer can see, to point one out. Sits
   directly above the composer like the / picker, so the two feel like the
   same mechanism. */
.point-suggestions{position:absolute;bottom:100%;left:10px;right:10px;z-index:40;
  max-height:240px;overflow-y:auto;margin-bottom:6px;border-radius:12px;
  background:var(--panel,#fff);box-shadow:0 6px 24px rgba(0,0,0,.22);
  border:1px solid var(--line,rgba(127,127,127,.22))}
.point-suggestions.hidden{display:none}
.point-row{display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;padding:11px 14px;border:0;background:transparent;color:inherit;
  cursor:pointer;text-align:left;font-size:14px}
.point-row strong{font-weight:600}
.point-row small{opacity:.55;font-size:12px}
.point-row.is-on{background:var(--hover,rgba(127,127,127,.14))}
.point-empty{padding:12px 14px;font-size:13px;opacity:.7}
/* One button's own colours, folded away. Most buttons never need one, and
   eight open colour panels would bury the list itself. */
.qa-button-look{margin-top:6px}
.qa-button-look > summary{cursor:pointer;font-size:12px;opacity:.75;
  list-style:none;padding:3px 0;user-select:none}
.qa-button-look > summary::-webkit-details-marker{display:none}
.qa-button-look > summary::before{content:'▸ ';font-size:10px}
.qa-button-look[open] > summary::before{content:'▾ '}
.qa-button-look .qa-color-field{margin-top:5px;padding:6px 8px;font-size:12px}
.qa-button-look .qa-color-field input[type=color]{width:36px;height:24px}
/* Who paid whom. The amount is the thing being scanned, so it gets its own
   column rather than being buried in a sentence. */
.qa-transfer-amount{font-variant-numeric:tabular-nums;font-weight:700;font-size:14px;
  flex:0 0 auto;min-width:74px;text-align:right}
.qa-transfer.is-void{opacity:.55}
.qa-transfer.is-void .qa-transfer-amount{text-decoration:line-through}
/* Name filter on the live feed. Beside the Failures-only box, because they
   are the same kind of decision: narrow what is on screen. */
.feed-filter{flex:0 1 220px;min-width:150px;padding:6px 10px;font-size:13px;
  border:1px solid var(--line,rgba(127,127,127,.28));border-radius:8px;
  background:transparent;color:inherit}
.feed-filter::placeholder{opacity:.6}
/* Exact dates, under the quick periods. Both ends count in full. */
.report-dates{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap;margin:10px 0 2px}
.report-dates label{display:flex;flex-direction:column;gap:3px;font-size:12px;opacity:.8}
.report-dates input[type=date]{padding:6px 9px;font-size:13px;color:inherit;
  border:1px solid var(--line,rgba(127,127,127,.28));border-radius:8px;background:transparent}
.report-dates .ghost-button{padding:7px 13px;border:1px solid var(--line,rgba(127,127,127,.28));
  border-radius:8px;background:transparent;color:inherit;font-size:13px;font-weight:600;cursor:pointer}
.report-range-note{font-size:12px;opacity:.75}
.perm-tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px}
.perm-tab{padding:6px 12px;border:1px solid var(--line);border-radius:999px;background:var(--panel2);color:var(--text)}
.perm-tab.is-on{background:var(--primary);color:#fff;border-color:var(--primary)}
.perm-list{max-height:58dvh;overflow:auto}
.perm-cat{margin:12px 2px 2px;font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;opacity:.6}
.perm-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 4px;border-bottom:1px solid var(--line);cursor:pointer}
.perm-row span{flex:1;min-width:0}
.perm-seg{min-width:96px}
/* Trigger words editor: one row per shortcut button, an input in front of the
   name where staff type the comma-separated words that wave it. */
.trigger-words-list{max-height:62dvh;overflow:auto;display:flex;flex-direction:column;gap:8px;margin:4px 2px 2px}
.trigger-row{display:flex;align-items:flex-start;gap:10px;padding:6px 2px}
.trigger-row.is-off{opacity:.6}
.trigger-name{flex:0 0 30%;min-width:92px;font-weight:600;font-size:13.5px;padding-top:9px}
.trigger-input{flex:1;min-width:0;padding:8px 10px;font-size:13px;color:inherit;font-family:inherit;
  line-height:1.4;min-height:52px;max-height:120px;overflow-y:auto;resize:vertical;
  border:1px solid var(--line,rgba(127,127,127,.28));border-radius:8px;background:transparent}
.trigger-input::placeholder{color:var(--muted);opacity:.7}
@media (max-width:520px){
  .trigger-row{flex-direction:column;align-items:stretch;gap:4px}
  .trigger-name{flex:none;padding-top:0}
}
/* Details label picker: show the choices IN FLOW, not as an absolutely-placed
   dropdown — the details panel scrolls (overflow:auto), which was clipping the
   floating list to a sliver. In flow it can be as tall as it needs, scrolls on
   its own, and the panel scrolls to reveal it. */
.details-panel .label-combobox .suggestion-list{position:static;max-height:260px;
  margin-top:6px;box-shadow:none}
/* Multi-select label filter: a select-like button that opens a searchable list
   of labels, each ticked independently and showing its live customer count. */
.label-ms{position:relative;display:inline-block;min-width:132px}
.label-ms-btn{width:100%;text-align:left;padding:6px 24px 6px 10px;border:1px solid var(--line);
  border-radius:8px;background:var(--panel2);color:var(--text);font-size:13px;cursor:pointer;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.label-ms-btn::after{content:'▾';position:absolute;right:9px;top:50%;transform:translateY(-50%);opacity:.55;font-size:11px}
.label-ms-btn.has-sel{border-color:var(--primary);color:var(--primary);font-weight:600}
.label-ms-menu{position:absolute;left:0;top:calc(100% + 4px);z-index:40;width:min(270px,82vw);
  background:var(--panel);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);
  padding:6px;display:flex;flex-direction:column;gap:5px}
#labelFilterSearch{width:100%;padding:7px 9px;font-size:13px;color:inherit;background:var(--panel2);
  border:1px solid var(--line);border-radius:7px;outline:0}
.label-ms-list{max-height:260px;overflow:auto;display:flex;flex-direction:column;gap:2px}
.label-ms-item{display:flex;align-items:center;gap:8px;width:100%;padding:7px 8px;border:0;border-radius:7px;
  background:transparent;color:var(--text);font-size:13px;cursor:pointer;text-align:left}
.label-ms-item:hover{background:var(--hover,rgba(127,127,127,.12))}
.label-ms-item.is-on{background:var(--selected,rgba(0,132,255,.14))}
.label-ms-dot{width:11px;height:11px;border-radius:50%;flex:0 0 auto}
.label-ms-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.label-ms-count{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;min-width:22px;text-align:right}
.label-ms-check{width:14px;text-align:center;color:var(--primary);font-weight:700}
.label-ms-empty{padding:8px;color:var(--muted);font-size:13px;text-align:center}
