:root {
  --bg:#f5f6f9; --panel:#ffffff; --fg:#1f2633; --muted:#6b7280;
  --accent:#5b5bf0;           /* indigo — links, active nav, secondary actions */
  --accent-ink:#4a46d6;
  --green:#12b886;            /* emerald — primary call-to-action */
  --green-ink:#0e9d74;
  --line:#e6e8ee; --line-soft:#eef0f4;
  --note:#fff8e6; --note-line:#f1e2b6;
  --danger:#e11d48; --sidebar:#171a2b; --brand:#E30613;
}
* { box-sizing:border-box; }
body { margin:0; font:15px/1.5 system-ui,Segoe UI,Roboto,sans-serif; background:var(--bg); color:var(--fg); }
a { color:var(--accent); text-decoration:none; } a:hover { text-decoration:underline; }

header.top { background:var(--sidebar); color:#eceefb; padding:11px 20px; display:flex; align-items:center; gap:16px; }
header.top a.brand { display:inline-flex; align-items:center; gap:9px; font-weight:700; text-decoration:none; }
header.top a.brand:hover { text-decoration:none; }
header.top a.brand:hover .logo-img { filter:brightness(1.12); }
.logo-img { height:19px; width:auto; display:block; }
header.top .brand .sub { font-weight:400; color:#c7cbe6; font-size:14px; }
.login .brandhead { display:flex; align-items:center; gap:9px; }
.login .brandhead .logo-img { height:24px; }
header.top nav { display:flex; gap:16px; margin-left:auto; align-items:center; font-size:14px; }
header.top nav a { color:#c7cbe6; }
header.top nav a:hover { color:#fff; text-decoration:none; }
.langswitch { display:inline-flex; gap:4px; align-items:center; }
.langswitch a { font-size:12px; font-weight:600; padding:2px 7px; border-radius:6px; opacity:.65; }
.langswitch a.on { opacity:1; background:rgba(255,255,255,.14); }
header.top .langswitch a { color:#c7cbe6; }
header.top .langswitch a.on { color:#fff; }
.authbar { display:flex; justify-content:flex-end; padding:10px 18px; }
.authbar .langswitch a { color:var(--muted); }
.authbar .langswitch a.on { background:#e7e9fb; color:var(--accent-ink); }

.wrap { max-width:1120px; margin:0 auto; padding:20px 22px 60px; }
/* The inbox list has 7 columns and benefits from more width on large screens;
   reading pages (ticket detail, settings) keep the narrower 1120 for legibility. */
.wrap.wide { max-width:1500px; }
.flash { background:#eef2ff; border:1px solid #d9defb; color:#3a3f8f; padding:9px 13px; border-radius:9px; margin:10px 0; }

/* preset view chips */
.presets { display:flex; flex-wrap:wrap; gap:6px; margin:16px 0 12px; }
.presets.savedrow { margin:-4px 0 12px; padding-top:10px; border-top:1px solid var(--line); }
.presets.savedrow .chip { font-weight:600; }
.presets.savedrow .chip.on { background:var(--sidebar); border-color:var(--sidebar); }
.chip { display:inline-flex; align-items:center; gap:6px; padding:6px 13px; border-radius:20px;
  border:1px solid var(--line); background:#fff; color:var(--fg); font-size:13px; font-weight:600; text-decoration:none; }
.chip:hover { border-color:var(--accent); color:var(--accent); text-decoration:none; }
.chip.on { background:var(--accent); color:#fff; border-color:var(--accent); }
.chip-count { font-size:11.5px; font-weight:700; background:var(--line-soft); color:var(--muted);
  border-radius:10px; padding:1px 7px; min-width:18px; text-align:center; }
.chip:hover .chip-count { background:#e7e9fb; color:var(--accent-ink); }
.chip.on .chip-count { background:rgba(255,255,255,.22); color:#fff; }

/* filters + search */
.toolbar { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin:14px 0; }
.toolbar input[type=search], .toolbar select { padding:9px 11px; border:1px solid var(--line); border-radius:9px; background:#fff; font:inherit; color:var(--fg); }
.toolbar input[type=search] { flex:1; min-width:220px; }
.search-spin { color:var(--accent); font-size:13px; font-weight:600; }
.toolbar input:focus, .toolbar select:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(91,91,240,.15); }

/* ticket list */
table.tickets { width:100%; border-collapse:separate; border-spacing:0; background:var(--panel); border:1px solid var(--line); border-radius:12px; overflow:hidden; box-shadow:0 1px 2px rgba(20,23,40,.04); }
table.tickets th, table.tickets td { text-align:left; padding:11px 14px; border-bottom:1px solid var(--line-soft); vertical-align:top; }
table.tickets th { font-size:11.5px; text-transform:uppercase; letter-spacing:.5px; color:var(--muted); background:#fafbfc; font-weight:600; }
table.tickets tr:last-child td { border-bottom:0; }
table.tickets tbody tr:hover td { background:#fafbff; }
table.tickets tr.unread td { font-weight:600; }
table.tickets tr.unread td:first-child { box-shadow:inset 3px 0 0 var(--accent); }
/* Junk still shows under 'All' rather than being filtered out, but reads as
   clearly secondary. Declared after .unread so it also cancels that bolding —
   an unread spam ticket shouldn't shout. Badges set their own colour, so the
   red status-spam pill stays legible. */
table.tickets tr.is-spam td,
table.tickets tr.is-spam td .subject { color:var(--muted); font-weight:400; }
table.tickets tr.is-spam .snippet { opacity:.75; }
/* Age at a glance. Mail from the last 24h is tinted, the day before that more
   faintly, older not at all — so the top of the list reads as "today" without
   having to scan the Updated column. Deliberately below the :hover rule, which
   is more specific and still wins, so hovering a row is still visible. */
table.tickets tr.fresh24 td { background:#e9f1ff; }
table.tickets tr.fresh48 td { background:#f4f8ff; }
table.tickets tr.fresh24.is-spam td,
table.tickets tr.fresh48.is-spam td { background:transparent; }   /* junk stays quiet */
/* Column sizing: Subject stays the flexible column; the short columns shrink to
   their content (width:1% + nowrap) so the date never wraps, and Customer is
   capped with an ellipsis instead of sprawling across the freed space. */
table.tickets .col-customer { max-width:200px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
table.tickets .col-channel, table.tickets .col-status, table.tickets .col-updated { width:1%; white-space:nowrap; }
.tm { color:var(--muted); font-size:.85em; white-space:nowrap; }
.history { list-style:none; margin:0; padding:0; font-size:13px; }
.history li { padding:6px 0; border-bottom:1px solid var(--line-soft); }
.history li:last-child { border-bottom:0; }
.history .hist-what { display:block; color:var(--fg); }
.history .hist-meta { color:var(--muted); font-size:12px; }
.att-list { display:flex; flex-wrap:wrap; gap:6px; margin:8px 0 0; }
.att-chip { display:inline-flex; align-items:center; gap:4px; background:#eef2ff; border:1px solid #d9defb;
  border-radius:16px; padding:3px 6px 3px 10px; font-size:13px; }
.att-chip small { color:var(--muted); }
.att-chip button { border:0; background:transparent; cursor:pointer; font-size:15px; line-height:1; color:var(--muted); padding:0 2px; }
.att-chip button:hover { color:var(--brand); }
details.inv-panel { background:#eef8f1; border:1px solid #c7e6d3; }
.inv-panel > summary { cursor:pointer; font-weight:700; font-size:15px; list-style:none; color:#177a4b; }
.inv-panel > summary::-webkit-details-marker { display:none; }
.inv-panel > summary::before { content:'▸ '; color:var(--muted); }
.inv-panel[open] > summary::before { content:'▾ '; }
.inv-panel[open] > summary { margin-bottom:10px; }
.inv-pending { margin-top:10px; padding:10px 12px; border:1px solid var(--line); border-radius:9px; background:#f4fbf6; }
.inv-pending ul { margin:6px 0; padding-left:2px; list-style:none; }
.inv-pending li { display:flex; align-items:center; gap:8px; padding:2px 0; }
.inv-pending li span { font-family:ui-monospace,monospace; font-size:13px; }
/* Which company's BaseLinker a result or queued invoice belongs to. Order ids and
   invoice ids repeat across the two accounts, so the label is not decoration. */
.bl-acct { display:inline-block; padding:0 6px; margin-right:6px; border-radius:5px;
           background:#dcecf7; color:#14608c; font:600 11px/1.7 ui-monospace,monospace;
           letter-spacing:.04em; text-transform:uppercase; }
.inv-pending li span.bl-acct { font-size:11px; }
details.teach { margin:10px 0; border:1px dashed var(--line); border-radius:9px; padding:8px 12px; background:#fafbff; }
details.teach summary { cursor:pointer; color:var(--accent-ink, #3a3f8f); font-size:13px; font-weight:600; }
details.teach[open] summary { margin-bottom:4px; }
.subject { display:block; color:var(--fg); }
.snippet { color:var(--muted); font-weight:400; font-size:13px; }

/* badges / tags / status pills */
.badge { display:inline-block; padding:2px 10px; border-radius:20px; font-size:12px; font-weight:600; border:1px solid transparent; }
.badge.channel { background:var(--line-soft); color:#4b5563; }
.badge.status-new { background:#e1effe; color:#1e63c9; }
.badge.status-open { background:#e7e5fd; color:#5145cd; }
.badge.status-pending { background:#fef3c7; color:#96650c; }
.badge.status-waiting_customer { background:#eceff3; color:#556072; }
/* Closed reads as black rather than as another colour in the status palette:
   it is the one terminal state, and the contrast is what makes a closed row
   scannable down a long inbox. Uses the header's near-black so it matches the
   chrome instead of introducing a second black. */
.badge.status-closed { background:var(--sidebar); color:#fff; }
.badge.status-spam { background:#fde2e1; color:#a8231b; }
.tag { display:inline-block; padding:1px 8px; border-radius:6px; font-size:12px; background:var(--line-soft); color:#5b6472; margin-right:4px; }
/* stable per-tag color palette (see tag_color filter) */
.tag.c0 { background:#e1effe; color:#1e63c9; }
.tag.c1 { background:#d8f3e3; color:#0f7a56; }
.tag.c2 { background:#fef3c7; color:#96650c; }
.tag.c3 { background:#ede9fd; color:#6d43c9; }
.tag.c4 { background:#fde7f0; color:#b83280; }
.tag.c5 { background:#d5f2ee; color:#0e7c86; }
.tag.c6 { background:#ffe8d6; color:#b5591b; }
.tag.c7 { background:#e5e3fd; color:#5145cd; }
.tag.c8 { background:#fde3e3; color:#c22; }
.tag.c9 { background:#eaf5cf; color:#5a7a12; }
.tag.c10 { background:#d9f0fb; color:#1076a8; }
.tag.c11 { background:#eceff3; color:#556072; }
/* CANCEL — an alarm, not a category: solid red so it is impossible to skim past */
.tag.alert { background:#d92020; color:#fff; font-weight:700; letter-spacing:.02em; }
/* editable tag chips on the ticket page */
.tagchips { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:8px; }
.tagchips .tag { display:inline-flex; align-items:center; gap:4px; padding:3px 6px 3px 9px; margin:0; font-weight:600; }
.tagx { background:none; border:0; color:inherit; opacity:.6; cursor:pointer; font-size:14px; line-height:1; padding:0; }
.tagx:hover { opacity:1; }
.tag-input { width:100%; padding:7px 10px; border:1px solid var(--line); border-radius:8px; font:inherit; }
.tag-input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(91,91,240,.15); }

/* ticket detail */
.tnav { display:flex; align-items:center; gap:8px; margin-bottom:6px;
  position:sticky; top:0; z-index:5; background:var(--bg);
  padding:8px 0; border-bottom:1px solid var(--line); }
.tnav-spacer { flex:1; }
.tnav-pos { font-size:13px; color:var(--muted); margin-right:2px; }
.tnav-btn { display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px;
  border:1px solid var(--line); border-radius:8px; background:#fff; color:var(--fg); font-size:15px; text-decoration:none; }
.tnav-btn:hover { border-color:var(--accent); color:var(--accent); text-decoration:none; }
.tnav-btn.disabled { opacity:.4; cursor:default; }
.grid { display:grid; grid-template-columns:1fr 340px; gap:20px; align-items:start; }
.side { position:sticky; top:54px; align-self:start; }
/* Status control. Sized here rather than inline so the media query can grow it.
   Full width of its card and a tall hit area: it is the control reached for most
   often, and as a small pill it was genuinely hard to click. */
.status-select { width:100%; font-size:15px; font-weight:700; padding:10px 12px;
  border-radius:10px; cursor:pointer; }

/* One column below 900px. `display:contents` dissolves the sidebar box so its
   cards become items of the grid itself — which is what lets the status card be
   ordered above the conversation. Without it `order` could only shuffle cards
   within the sidebar, and the whole sidebar would have to move as one block,
   dragging History and Details above the thread too. */
@media (max-width:900px){
  .grid { display:flex; flex-direction:column; grid-template-columns:1fr; }
  .side { display:contents; }
  .side .card { margin-bottom:14px; }
  .statuscard { order:-1; }
}
.thread { display:flex; flex-direction:column; gap:12px; }
.msg { background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:12px 14px; box-shadow:0 1px 2px rgba(20,23,40,.04); }
.msg.outbound { background:#f2f7ff; border-color:#d8e6fb; }
.msg .meta { font-size:12px; color:var(--muted); margin-bottom:6px; display:flex; gap:10px; flex-wrap:wrap; align-items:center; }
.msg .body { white-space:pre-wrap; }
.msg .htmlbody { width:100%; min-height:60px; border:0; background:#fff; border-radius:8px; display:block; }
.msg .meta .viewtoggle { margin-left:auto; cursor:pointer; color:var(--accent); font-size:12px; }
/* Only the first toggle pushes off the left; a second auto margin would split
   the free space and strand "Plain text" in the middle of the row. */
.msg .meta .viewtoggle ~ .viewtoggle { margin-left:0; }
/* A translation is not the customer's own words. It gets its own tinted box
   below the message, in a colour used nowhere else — outbound replies are blue
   and private notes are yellow, so teal cannot be mistaken for either. */
.msg .tr-box { margin-bottom:10px; border:1px solid #bfe8d9; border-left:3px solid var(--green);
  background:#f0faf6; border-radius:10px; padding:8px 11px 10px; }
.msg .tr-box .tr-head { display:flex; gap:8px; align-items:center; flex-wrap:wrap;
  font-size:12px; font-weight:600; color:var(--green-ink); margin-bottom:6px; }
.msg .tr-box .tr-pair { font-weight:400; color:var(--muted); }
.msg .tr-box .tr-close { margin-left:auto; color:var(--muted); font-size:13px; line-height:1; }
.msg .tr-box .body { white-space:pre-wrap; }
.msg .tr-box .tr-fail { color:var(--danger); font-size:13px; }
.msg .atts { margin-top:10px; display:flex; flex-wrap:wrap; gap:10px; align-items:flex-start; }
.att-img img { max-width:170px; max-height:170px; border:1px solid var(--line); border-radius:8px;
  display:block; object-fit:cover; background:#f3f4f8; }
.att-img:hover img { border-color:var(--accent); }
.att-file { display:inline-flex; align-items:center; gap:8px; border:1px solid var(--line);
  border-radius:8px; padding:6px 10px; background:#fff; }
.att-ico { font-size:18px; }
.att-name { color:var(--fg); font-size:13px; max-width:240px; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.att-dl { color:var(--muted); font-size:15px; text-decoration:none; }
.att-dl:hover { color:var(--accent); }
.filter-hint { font-size:12px; color:var(--muted); margin:-4px 0 10px 2px; }
.filter-form { display:flex; gap:12px; align-items:flex-end; flex-wrap:wrap; }
.filter-form > div { flex:1; min-width:180px; }
.filter-form label { display:block; font-size:12px; font-weight:600; color:var(--muted); margin-bottom:4px; }
.filter-form input { width:100%; padding:8px 10px; border:1px solid var(--line); border-radius:8px; font:inherit; }
.filter-form input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(91,91,240,.15); }
.cbcell { width:34px; text-align:center; }
.cbcell input { width:16px; height:16px; cursor:pointer; }
.bulk-bar { display:flex; align-items:center; gap:12px; margin:0 0 12px; padding:9px 14px;
  background:#eef0fb; border:1px solid #d9defb; border-radius:10px; font-size:14px; }
.bulk-bar #bulk-count { font-weight:600; color:var(--accent-ink); }
.bulk-bar select { padding:6px 8px; border:1px solid var(--line); border-radius:7px; background:#fff; font:inherit; }
.bulk-bar .btn { padding:7px 13px; }
.imgbar { background:#f3f4f8; border:1px solid var(--line); border-radius:8px; padding:6px 11px; font-size:12.5px; color:#4b5563; margin-bottom:8px; display:flex; align-items:center; gap:6px; }
.linklike { background:none; border:0; color:var(--accent); cursor:pointer; font:inherit; font-weight:600; padding:0; }
.linklike:hover { text-decoration:underline; }

/* private internal notes */
.notes-card { background:var(--note); border:1px solid var(--note-line); border-radius:12px; padding:14px; }
.notes-card h3 { margin:0 0 8px; font-size:12px; text-transform:uppercase; letter-spacing:.5px; color:#8a6d1f; }
.pnote { border-top:1px solid var(--note-line); padding:8px 0; }
.pnote:first-child { border-top:0; padding-top:0; }
.pnote-meta { font-size:12px; color:#8a6d1f; margin-bottom:3px; }
.pnote-body { white-space:pre-wrap; font-size:14px; color:#5b4a1a; }
.pnote-del { float:right; background:none; border:0; color:#8a6d1f; opacity:.6; cursor:pointer; font-size:14px; line-height:1; padding:0; }
.pnote-del:hover { opacity:1; }
.note-input { width:100%; padding:9px 11px; border:1px solid var(--note-line); border-radius:8px; font:14px/1.5 system-ui; background:#fff; resize:vertical; }
.note-input:focus { outline:none; border-color:#d9b94a; box-shadow:0 0 0 3px rgba(217,185,74,.2); }

.side .card { background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:14px; margin-bottom:14px; box-shadow:0 1px 2px rgba(20,23,40,.04); }
.side .card h3 { margin:0 0 8px; font-size:12px; text-transform:uppercase; letter-spacing:.5px; color:var(--muted); }
.kv { font-size:14px; margin:3px 0; } .kv b { color:var(--muted); font-weight:600; }

/* reply box */
/* The composer needs to look unlike a message. Before this it had no container
   styling at all — only the textarea was styled, white with a hairline border,
   which is exactly what an inbound message card looks like. The eye slid past
   the boundary between reading and writing. The accent top bar, the lifted
   shadow and the heading below say "this is where you type" structurally, not
   just by hue — the indigo AI-notes box already lives inside here, so tinting
   the whole panel indigo would have muddled the two. */
.replybox { background:var(--panel); border:1px solid var(--line);
  border-top:3px solid var(--accent); border-radius:12px; padding:14px;
  box-shadow:0 2px 12px rgba(20,23,40,.08); }
.reply-head { display:flex; align-items:center; gap:7px; margin:0 0 10px;
  font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.5px;
  color:var(--accent-ink); }
.reply-head::before { content:"\270E"; font-size:14px; }
.replybox textarea { width:100%; min-height:160px; padding:12px; border:1px solid var(--line); border-radius:9px; font:14px/1.5 system-ui; background:#fff; resize:vertical; color:var(--fg); overflow:hidden; }
.replybox textarea:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(91,91,240,.15); }
.tpl-menu { position:fixed; z-index:50; display:none; background:#fff; border:1px solid var(--line);
  border-radius:10px; box-shadow:0 8px 24px rgba(20,23,40,.16); max-height:230px; overflow-y:auto;
  min-width:250px; padding:4px; }
.tpl-item { display:flex; align-items:center; gap:8px; padding:7px 10px; border-radius:7px; cursor:pointer; font-size:14px; }
.tpl-item.on { background:#eef0fb; }
.tpl-title { font-weight:600; }
.tpl-sc { font-size:12px; color:var(--accent); }
.tpl-lang { margin-left:auto; font-size:11px; color:var(--muted); background:var(--line-soft); padding:1px 6px; border-radius:6px; }
.reply-tabs { display:flex; gap:4px; align-items:center; margin-bottom:-1px; }
.rtab { border:1px solid var(--line); border-bottom:0; background:#f1f2f6; color:var(--muted);
  padding:6px 13px; border-radius:9px 9px 0 0; font:inherit; font-size:13px; font-weight:600; cursor:pointer; }
.rtab.on { background:#fff; color:var(--fg); }
.rtab .muted { font-weight:400; opacity:.7; }
.rtab-hint { font-size:12px; color:var(--accent); margin-left:8px; }
.reply-tabs + textarea { border-top-left-radius:0; }
/* AI internal notes: indigo (info), distinct from the yellow private-notes card */
.replybox .notes { background:#eef2ff; border:1px solid #d9defb; border-radius:9px; padding:10px 12px; font-size:13px; color:#3a3f8f; margin:8px 0; }
.replybox .notes ul { margin:4px 0 0 18px; padding:0; }
/* reply recipient: normally just confirms where it goes, highlighted when unknown */
.reply-to { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 8px; }
.reply-to label { font-size:13px; font-weight:600; color:var(--muted); min-width:22px; }
.reply-to input { flex:1; min-width:220px; padding:7px 10px; border:1px solid var(--line);
  border-radius:8px; font:inherit; font-size:13px; color:var(--fg); background:#fff; }
.reply-to input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(91,91,240,.15); }
.reply-to.missing input { border-color:#e5a3a3; background:#fdf6f6; }
.reply-to.missing .snippet { color:#8d1f1f; flex-basis:100%; }
.newticket { text-decoration:none; margin-left:auto; }
.newticket:hover { text-decoration:none; }
.compose-row { display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.compose-row label { font-size:13px; font-weight:600; color:var(--muted); min-width:60px; }
.compose-row input, .compose-row select { flex:1; padding:8px 10px; border:1px solid var(--line);
  border-radius:8px; font:inherit; font-size:14px; color:var(--fg); background:#fff; }
.compose-row input:focus, .compose-row select:focus { outline:none; border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(91,91,240,.15); }
#compose-form textarea { width:100%; padding:12px; border:1px solid var(--line); border-radius:9px;
  font:14px/1.5 system-ui; background:#fff; resize:vertical; color:var(--fg); }
/* a blocked send (e.g. translation failed) — red, right above the Send button */
.reply-err { background:#fdecec; border:1px solid #f5c2c2; border-radius:9px; padding:9px 12px;
  font-size:13px; color:#8d1f1f; margin:8px 0 0; }

.btn { padding:9px 16px; border:0; border-radius:9px; font:inherit; font-weight:600; cursor:pointer; background:var(--green); color:#fff; }
.btn:hover { background:var(--green-ink); }
.btn.secondary { background:var(--accent); } .btn.secondary:hover { background:var(--accent-ink); }
.btn.ghost { background:var(--line-soft); color:var(--fg); } .btn.ghost:hover { background:#e2e5ec; }
.btn.danger { background:var(--danger); } .btn.danger:hover { filter:brightness(.93); }
.btn:disabled { opacity:.5; cursor:wait; }
.actions { display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; align-items:center; }
.marketplace-cta { display:block; text-align:center; background:var(--accent); color:#fff; padding:11px; border-radius:9px; font-weight:600; margin:8px 0; }
.marketplace-cta:hover { background:var(--accent-ink); text-decoration:none; }
.canned { display:flex; gap:6px; flex-wrap:wrap; margin:8px 0; }
.canned button { font-size:12px; padding:4px 10px; border:1px solid var(--line); border-radius:20px; background:#fff; cursor:pointer; color:var(--fg); }
.canned button:hover { border-color:var(--accent); color:var(--accent); }
.spinner { color:var(--muted); font-size:13px; display:none; }
.htmx-request .spinner { display:inline; }

/* Any htmx control that takes a noticeable moment: the ring takes the label's
   place while the request is in flight, so the control shows it is working
   instead of looking inert. Regenerating a draft is the slow one — 30-90s. */
.busy .busy-ring { display:none; }
.busy.htmx-request .busy-label { display:none; }
.busy.htmx-request .busy-ring {
  display:inline-block; width:13px; height:13px; vertical-align:-2px;
  border:2px solid var(--line); border-top-color:var(--accent);
  border-radius:50%; animation:busy-spin .7s linear infinite;
}
/* On a filled button the accent ring disappears into the background; .ghost is
   pale with dark text, so it keeps the default ring. Buttons carrying this also
   set hx-disabled-elt, and .btn:disabled already dims them and shows a wait
   cursor — nothing to add here. */
.btn.busy.htmx-request:not(.ghost) .busy-ring {
  border-color:rgba(255,255,255,.45); border-top-color:#fff;
}
@keyframes busy-spin { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce) {
  .busy.htmx-request .busy-ring { animation:none; border-top-color:var(--accent); }
}

/* login / register */
.login { max-width:360px; margin:7vh auto; background:var(--panel); border:1px solid var(--line); border-radius:14px; padding:28px; box-shadow:0 6px 24px rgba(20,23,40,.07); }
.login h1 { font-size:20px; margin:0 0 16px; }
.login .brandhead .logo { font-family:'Syncopate', system-ui, sans-serif; font-weight:700; letter-spacing:0; color:var(--brand); }
.login label { display:block; font-size:13px; font-weight:600; margin:12px 0 5px; }
.login input { width:100%; padding:10px 12px; border:1px solid var(--line); border-radius:9px; font:inherit; }
.login input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(91,91,240,.15); }
.login .btn { width:100%; margin-top:18px; }

/* stats */
table.stats { border-collapse:collapse; background:#fff; border:1px solid var(--line); border-radius:10px; overflow:hidden; }
table.stats th, table.stats td { padding:9px 15px; border-bottom:1px solid var(--line-soft); text-align:left; }
table.stats th { background:#fafbfc; font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.4px; }

.err { color:var(--danger); background:#fff; border:1px solid var(--line); border-radius:9px; padding:16px; margin-top:20px; white-space:pre-wrap; }

/* ------- mobile ------- */
@media (max-width:640px) {
  html, body { overflow-x:hidden; }
  .wrap { padding:12px 12px 48px; }
  header.top { flex-wrap:wrap; gap:6px 12px; padding:9px 12px; }
  header.top nav { gap:12px; row-gap:4px; flex-wrap:wrap; font-size:13px; }

  .presets { gap:5px; margin:12px 0 10px; }
  .chip { padding:5px 11px; }
  .toolbar { gap:8px; }
  .toolbar input[type=search] { flex:1 1 100%; }
  .toolbar .btn { flex:0 0 auto; }
  .toolbar select { flex:1 1 42%; min-width:0; }

  /* ticket list -> stacked cards */
  table.tickets { border:0; box-shadow:none; background:transparent; border-radius:0; }
  table.tickets thead { display:none; }
  table.tickets, table.tickets tbody { display:block; }
  table.tickets tr { display:block; position:relative; background:var(--panel);
    border:1px solid var(--line); border-radius:11px; margin-bottom:8px; padding:12px 14px;
    box-shadow:0 1px 2px rgba(20,23,40,.05); }
  table.tickets tbody tr:hover td { background:transparent; }
  /* The row is the card here and the cells are inline, so the age tint has to
     move to the row — on the cells it would stripe the text runs instead. */
  table.tickets tr.fresh24 { background:#e9f1ff; }
  table.tickets tr.fresh48 { background:#f4f8ff; }
  table.tickets tr.fresh24 td, table.tickets tr.fresh48 td { background:transparent; }
  table.tickets td { display:inline; border:0; padding:0; }
  table.tickets td.cbcell { position:absolute; top:12px; right:12px; width:auto; }
  table.tickets .col-subject { display:block; padding-right:28px; }
  table.tickets .col-subject .subject { font-size:15px; }
  table.tickets .col-customer { display:block; color:var(--muted); font-size:13px; margin-top:3px;
    max-width:none; white-space:normal; overflow:visible; }
  table.tickets .col-channel, table.tickets .col-tags,
  table.tickets .col-status, table.tickets .col-updated {
    display:inline-flex; align-items:center; flex-wrap:wrap; gap:4px; margin:8px 8px 0 0; width:auto; }
  table.tickets .col-updated { color:var(--muted); font-size:12px; }

  /* Status is the control reached for most often on a phone, so give it a real
     touch target. 16px specifically: below that iOS zooms the page on focus. */
  .statuscard { margin-bottom:14px; }
  .status-select { width:100%; font-size:16px; font-weight:700; padding:12px 14px;
    border-radius:12px; }
  table.tickets tr.unread { border-left:3px solid var(--accent); }
  table.tickets tr.unread td:first-child { box-shadow:none; }

  /* ticket detail already stacks (<=900); keep the reply usable */
  .grid { gap:14px; }
}

/* Ticket reference. Monospace so a number is unambiguous when read aloud or
   pasted, and visually quieter than the subject it sits beside. */
.tref { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:14px;
        color:var(--muted); background:var(--line-soft); border:1px solid var(--line);
        border-radius:6px; padding:2px 7px; margin-right:8px; cursor:pointer;
        vertical-align:middle; }
.tref:hover { color:var(--fg); background:#fff; }
.tref-inline { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; color:var(--muted);
               margin-right:6px; }

/* products — stock status. Three states, and colour is never the only signal:
   'out' also reads as the word, so the row still says what it means to anyone
   who cannot separate the red from the amber. */
.badge.bad  { background:#fde2e1; color:#a8231b; }
.badge.warn { background:#fef3c7; color:#96650c; }
.badge.good { background:#d8f3e3; color:#0f7a56; }
.muted { color:var(--muted); font-size:13px; }
.hs { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.errbox { background:#fde2e1; border:1px solid #f5c6c4; color:#a8231b;
          padding:9px 13px; border-radius:9px; margin:10px 0; }
.okbox { background:#d8f3e3; border:1px solid #b6e5cd; color:#0f7a56;
         padding:9px 13px; border-radius:9px; margin:10px 0; }
.formgrid { display:grid; grid-template-columns:190px 1fr; gap:10px 14px; align-items:center;
            max-width:640px; margin:12px 0; }
.formgrid label { font-size:13px; font-weight:600; color:var(--muted); }
.formgrid input, .formgrid textarea { padding:8px 11px; border:1px solid var(--line);
            border-radius:9px; font:inherit; color:var(--fg); background:#fff; }
.formgrid .hint { grid-column:2; font-size:12px; color:var(--muted); margin-top:-4px; }
