/**
 *                          ___                   _       _         _ 
 *                         / __)                 | |     | |       | |
 *     _ _ _ _ _ _ _ _ _ _| |__ _____  ____ _   _| |  _  | |__   __| |
 *    | | | | | | | | | (_   __|____ |/ ___) | | | |_/ ) |  _ \ / _  |
 *    | | | | | | | | | | | |  / ___ | |   | |_| |  _ ( _| |_) | (_| |
 *     \___/ \___/ \___(_)|_|  \_____|_|   |____/|_| \_|_)____/ \____|
 *                                                                    
 *
 * 	Author: MD OMAR FARUK
 * 	Author URI: www.faruk.bd
 * 	Author Contact: https://faruk.bd/#contact
 * 	Author Email: info@faruk.bd | farukmr@gmail.com
 * 	Copyright © 2026
 *                          ___                   _       _         _ 
 *                         / __)                 | |     | |       | |
 *     _ _ _ _ _ _ _ _ _ _| |__ _____  ____ _   _| |  _  | |__   __| |
 *    | | | | | | | | | (_   __|____ |/ ___) | | | |_/ ) |  _ \ / _  |
 *    | | | | | | | | | | | |  / ___ | |   | |_| |  _ ( _| |_) | (_| |
 *     \___/ \___/ \___(_)|_|  \_____|_|   |____/|_| \_|_)____/ \____|
 *                                                                    
 */
/* =====================================================================
   Hearing Center Business Suite - UI
   Colour tokens are injected by includes/theme.php (--brand, --accent, ...)
   ===================================================================== */

:root{
  --brand:#0f766e; --brand-rgb:15,118,110; --brand-dark:#0b5a54; --brand-light:#d7f0ed;
  --accent:#f59e0b; --accent-rgb:245,158,11; --accent-dark:#c47f08;
  --sidebar:#0b1220; --sidebar-2:#141d2f;
  --radius:14px;
  --font:'Segoe UI', system-ui, -apple-system, 'Noto Sans Bengali', sans-serif;

  --bg:#f4f6fb;
  --surface:#ffffff;
  --surface-2:#f8fafc;
  --line:#e4e8f0;
  --line-2:#eef1f6;
  --text:#0f172a;
  --text-2:#475569;
  --muted:#7b879c;
  --ok:#15803d; --ok-bg:#dcfce7;
  --warn:#b45309; --warn-bg:#fef3c7;
  --danger:#b91c1c; --danger-bg:#fee2e2;
  --info:#1d4ed8; --info-bg:#dbeafe;
  --shadow:0 1px 2px rgba(15,23,42,.04), 0 8px 24px rgba(15,23,42,.06);
  --shadow-lg:0 12px 40px rgba(15,23,42,.16);
  --sb-w:262px;
}

*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  font-family:var(--font);
  background:var(--bg);
  color:var(--text);
  font-size:14.5px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}
img{max-width:100%}
h1,h2,h3,h4{margin:0 0 .5rem;line-height:1.3;font-weight:700;letter-spacing:-.01em}
h1{font-size:1.5rem} h2{font-size:1.22rem} h3{font-size:1.05rem} h4{font-size:.95rem}
p{margin:0 0 .8rem}
code{background:var(--surface-2);border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-size:.88em}
hr{border:0;border-top:1px solid var(--line);margin:1.25rem 0}
.muted{color:var(--muted)}
.small{font-size:.84rem}
.bn{font-family:'Noto Sans Bengali',var(--font)}
.nowrap{white-space:nowrap}
.right{text-align:right} .center{text-align:center}
.mt0{margin-top:0} .mb0{margin-bottom:0}
.mt1{margin-top:.6rem} .mt2{margin-top:1.2rem} .mb2{margin-bottom:1.2rem}

/* ------------------------------------------------------------ layout */
.app{display:flex;min-height:100vh}

.sidebar{
  width:var(--sb-w);flex:0 0 var(--sb-w);
  background:linear-gradient(180deg,var(--sidebar) 0%,var(--sidebar-2) 100%);
  color:#c7d2e3;display:flex;flex-direction:column;
  /* The sidebar itself no longer scrolls: the brand and the menu
     filter used to scroll away with the menu, so searching again
     from the bottom of a sixty-entry list meant scrolling all the
     way back up first. Only .nav scrolls now. */
  position:sticky;top:0;height:100vh;overflow:hidden;z-index:40;
}
.sidebar::-webkit-scrollbar{width:6px}
.sidebar::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:3px}

.brand{
  display:flex;align-items:center;gap:.6rem;padding:1.05rem 1.15rem;
  color:#fff;font-weight:700;font-size:1.02rem;letter-spacing:-.01em;
  border-bottom:1px solid rgba(255,255,255,.08);
}
.brand img{max-height:34px;width:auto;border-radius:6px}
.brand-mark{
  width:34px;height:34px;border-radius:10px;flex:0 0 34px;
  background:linear-gradient(135deg,var(--brand),var(--accent));
  display:grid;place-items:center;color:#fff;font-weight:800;font-size:1rem;
}
.brand span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.nav{
  padding:.7rem .6rem 1.6rem;
  /* min-height:0 is what lets a flex child actually shrink and
     therefore scroll; without it the menu pushes the sidebar
     taller than the screen and nothing scrolls at all. */
  flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
}
.nav::-webkit-scrollbar{width:6px}
.nav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:3px}

/* The block above the menu: brand and filter, always visible. */
.sb-top{flex:0 0 auto;background:rgba(0,0,0,.12);padding-bottom:.55rem}
.sb-top .brand{border-bottom:1px solid rgba(255,255,255,.08);margin-bottom:.55rem}
.sb-top .nav-find{margin:0 .6rem}
.sb-top .nav-find-none{margin:0 .6rem}
.nav-group{
  font-size:.68rem;text-transform:uppercase;letter-spacing:.12em;
  color:#66748d;padding:1rem .7rem .35rem;font-weight:700;
}
.nav a{
  display:flex;align-items:center;gap:.65rem;
  padding:.56rem .72rem;margin-bottom:2px;border-radius:10px;
  color:#c1cde0;font-size:.9rem;font-weight:500;text-decoration:none;
  transition:background .15s,color .15s;
}
.nav a:hover{background:rgba(255,255,255,.07);color:#fff;text-decoration:none}
.nav a.active{
  background:linear-gradient(90deg,rgba(var(--brand-rgb),.95),rgba(var(--brand-rgb),.55));
  color:#fff;box-shadow:0 4px 14px rgba(var(--brand-rgb),.35);
}
.nav .ico{width:20px;text-align:center;font-size:1.02rem;flex:0 0 20px}
.nav .pill{
  margin-left:auto;background:var(--accent);color:#231603;
  font-size:.66rem;font-weight:800;border-radius:20px;padding:1px 7px;
}
.nav a.active .pill{background:#fff;color:var(--brand-dark)}

.sb-foot{
  padding:.85rem 1.1rem;border-top:1px solid rgba(255,255,255,.08);
  font-size:.75rem;color:#7c8aa3;
}
.sb-foot strong{color:#aebbd0;display:block;font-size:.8rem}

.main{flex:1;min-width:0;display:flex;flex-direction:column}

.topbar{
  background:var(--surface);border-bottom:1px solid var(--line);
  padding:.7rem 1.3rem;display:flex;align-items:center;gap:.9rem;
  position:sticky;top:0;z-index:30;
}
.topbar h1{font-size:1.12rem;margin:0}
.topbar .sub{font-size:.78rem;color:var(--muted);margin-top:-2px}
.topbar-spacer{flex:1}
.menu-btn{
  display:none;background:none;border:1px solid var(--line);border-radius:9px;
  width:38px;height:38px;font-size:1.15rem;cursor:pointer;color:var(--text-2);
}

.content{padding:1.3rem;flex:1}
.content-narrow{max-width:900px}

/* --------------------------------------------------------- status chips */
.sync-chip,.lic-chip{
  display:inline-flex;align-items:center;gap:.4rem;font-size:.74rem;font-weight:700;
  padding:.28rem .6rem;border-radius:20px;border:1px solid var(--line);
  background:var(--surface-2);color:var(--text-2);white-space:nowrap;
}
.sync-chip .dot{width:8px;height:8px;border-radius:50%;background:var(--ok)}
.sync-chip.off .dot{background:var(--danger)}
.sync-chip.busy .dot{background:var(--accent);animation:pulse 1s infinite}
@keyframes pulse{50%{opacity:.25}}
.lic-chip.ok{background:var(--ok-bg);color:var(--ok);border-color:transparent}
.lic-chip.warn{background:var(--warn-bg);color:var(--warn);border-color:transparent}
.lic-chip.danger{background:var(--danger-bg);color:var(--danger);border-color:transparent}

/* ------------------------------------------------------------ user menu */
.umenu{position:relative}
.umenu-btn{
  display:flex;align-items:center;gap:.55rem;background:none;border:1px solid var(--line);
  border-radius:30px;padding:.25rem .7rem .25rem .3rem;cursor:pointer;font:inherit;color:var(--text);
}
.umenu-btn:hover{background:var(--surface-2)}
.avatar{
  width:32px;height:32px;border-radius:50%;flex:0 0 32px;object-fit:cover;
  background:linear-gradient(135deg,var(--brand),var(--accent));
  display:grid;place-items:center;color:#fff;font-weight:700;font-size:.85rem;
}
.umenu-name{font-size:.85rem;font-weight:600;line-height:1.15;text-align:left}
.umenu-name small{display:block;font-weight:400;color:var(--muted);font-size:.72rem}
.dropdown{
  position:absolute;right:0;top:calc(100% + 8px);min-width:230px;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow-lg);padding:.4rem;display:none;z-index:60;
}
.dropdown.open{display:block}
.dropdown a,.dropdown button{
  display:flex;align-items:center;gap:.55rem;width:100%;
  padding:.5rem .65rem;border-radius:8px;font-size:.87rem;color:var(--text);
  background:none;border:0;cursor:pointer;font:inherit;text-align:left;text-decoration:none;
}
.dropdown a:hover,.dropdown button:hover{background:var(--surface-2);text-decoration:none}
.dropdown .sep{height:1px;background:var(--line);margin:.35rem 0}

/* --------------------------------------------------------- notifications */
.bell{
  position:relative;background:none;border:1px solid var(--line);border-radius:10px;
  width:38px;height:38px;cursor:pointer;font-size:1.05rem;color:var(--text-2);
}
.bell:hover{background:var(--surface-2)}
.bell .count{
  position:absolute;top:-6px;right:-6px;background:var(--danger);color:#fff;
  font-size:.65rem;font-weight:800;border-radius:20px;padding:1px 5px;min-width:17px;
}
.notif-panel{
  position:absolute;right:0;top:calc(100% + 8px);width:340px;max-width:calc(100vw - 24px);
  background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow-lg);display:none;z-index:60;overflow:hidden;
}
.notif-panel.open{display:block}
.notif-panel header{
  padding:.7rem .9rem;border-bottom:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;font-weight:700;font-size:.9rem;
}
.notif-list{max-height:60vh;overflow-y:auto}
.notif-item{display:flex;gap:.65rem;padding:.7rem .9rem;border-bottom:1px solid var(--line-2)}
.notif-item.unread{background:rgba(var(--brand-rgb),.05)}
.notif-item .ni{font-size:1.15rem;line-height:1}
.notif-item h5{margin:0 0 2px;font-size:.86rem;font-weight:700}
.notif-item p{margin:0;font-size:.8rem;color:var(--text-2)}
.notif-item time{font-size:.72rem;color:var(--muted)}
.notif-empty{padding:1.6rem;text-align:center;color:var(--muted);font-size:.86rem}

/* ------------------------------------------------------------- cards */
.card{
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:1.1rem;overflow:hidden;
}
.card-h{
  padding:.85rem 1.1rem;border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;
}
.card-h h2,.card-h h3{margin:0;font-size:1rem}
.card-h .spacer{flex:1}
.card-b{padding:1.1rem}
.card-b.tight{padding:0}
.card-f{padding:.8rem 1.1rem;border-top:1px solid var(--line);background:var(--surface-2)}

.grid{display:grid;gap:1.1rem}
.g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.g4{grid-template-columns:repeat(4,minmax(0,1fr))}
.g-2-1{grid-template-columns:2fr 1fr}
.g-1-2{grid-template-columns:1fr 2fr}

/* --------------------------------------------------------- stat tiles */
.stats{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:1rem;margin-bottom:1.2rem}
.stat{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:1rem 1.1rem;box-shadow:var(--shadow);position:relative;overflow:hidden;
  display:block;color:inherit;text-decoration:none;transition:transform .15s,box-shadow .15s;
}
a.stat:hover{transform:translateY(-2px);box-shadow:var(--shadow-lg);text-decoration:none}
.stat::after{content:'';position:absolute;inset:0 auto 0 0;width:4px;background:var(--brand)}
.stat.a::after{background:var(--accent)}
.stat.g::after{background:var(--ok)}
.stat.r::after{background:var(--danger)}
.stat.b::after{background:var(--info)}
.stat .lbl{font-size:.76rem;color:var(--muted);text-transform:uppercase;letter-spacing:.07em;font-weight:700}
.stat .val{font-size:1.65rem;font-weight:800;letter-spacing:-.02em;line-height:1.25}
.stat .sub{font-size:.78rem;color:var(--text-2)}
.stat .ico{position:absolute;right:.9rem;top:.85rem;font-size:1.5rem;opacity:.24}

/* ------------------------------------------------------------ tables */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.tbl{width:100%;border-collapse:collapse;font-size:.88rem;min-width:600px}
table.tbl th{
  text-align:left;padding:.68rem .85rem;background:var(--surface-2);
  border-bottom:1px solid var(--line);font-weight:700;font-size:.76rem;
  text-transform:uppercase;letter-spacing:.06em;color:var(--text-2);white-space:nowrap;
}
table.tbl td{padding:.68rem .85rem;border-bottom:1px solid var(--line-2);vertical-align:middle}
table.tbl tbody tr:hover{background:rgba(var(--brand-rgb),.035)}
table.tbl tbody tr:last-child td{border-bottom:0}
table.tbl .num{text-align:right;font-variant-numeric:tabular-nums}
table.tbl .actions{white-space:nowrap;text-align:right}
.tbl-title{font-weight:600;color:var(--text)}
.tbl-sub{font-size:.78rem;color:var(--muted)}
.empty{padding:2.6rem 1rem;text-align:center;color:var(--muted)}
.empty .big{font-size:2.2rem;display:block;margin-bottom:.4rem;opacity:.55}

/* ------------------------------------------------------------ badges */
.badge{
  display:inline-block;padding:.2rem .55rem;border-radius:20px;
  font-size:.72rem;font-weight:700;letter-spacing:.01em;white-space:nowrap;
}
.badge-ok{background:var(--ok-bg);color:var(--ok)}
.badge-warn{background:var(--warn-bg);color:var(--warn)}
.badge-danger{background:var(--danger-bg);color:var(--danger)}
.badge-info{background:var(--info-bg);color:var(--info)}
.badge-muted{background:#eef1f6;color:var(--muted)}
.badge-brand{background:var(--brand-light);color:var(--brand-dark)}

/* ------------------------------------------------------------ buttons */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.45rem;
  padding:.52rem 1rem;border-radius:10px;border:1px solid transparent;
  font:inherit;font-size:.87rem;font-weight:600;cursor:pointer;
  text-decoration:none;transition:filter .15s,box-shadow .15s,background .15s;white-space:nowrap;
}
.btn:hover{text-decoration:none;filter:brightness(1.06)}
.btn:active{transform:translateY(1px)}
.btn:disabled{opacity:.55;cursor:not-allowed}
.btn-primary{background:var(--brand);color:#fff;box-shadow:0 3px 12px rgba(var(--brand-rgb),.3)}
.btn-accent{background:var(--accent);color:#231603;box-shadow:0 3px 12px rgba(var(--accent-rgb),.3)}
.btn-light{background:var(--surface);color:var(--text);border-color:var(--line)}
.btn-light:hover{background:var(--surface-2)}
.btn-danger{background:var(--danger);color:#fff}
.btn-ok{background:var(--ok);color:#fff}
.btn-wa{background:#25d366;color:#062e15}
.btn-outline{background:transparent;color:var(--brand);border-color:var(--brand)}
.btn-sm{padding:.34rem .7rem;font-size:.79rem;border-radius:8px}
.btn-xs{padding:.2rem .5rem;font-size:.73rem;border-radius:7px}
.btn-block{width:100%}
.btn-icon{width:34px;height:34px;padding:0;border-radius:9px}
.btn-row{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center}

/* ------------------------------------------------------------- forms */
.form-grid{display:grid;gap:1rem}
.f2{grid-template-columns:repeat(2,minmax(0,1fr))}
.f3{grid-template-columns:repeat(3,minmax(0,1fr))}
.f4{grid-template-columns:repeat(4,minmax(0,1fr))}
.field{display:flex;flex-direction:column;gap:.32rem;min-width:0}
.field.span2{grid-column:span 2}
.field.span3{grid-column:span 3}
.field.span4{grid-column:span 4}
label{font-size:.83rem;font-weight:600;color:var(--text-2)}
label .req{color:var(--danger)}
.hint{font-size:.76rem;color:var(--muted)}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=date],
input[type=time],input[type=url],input[type=tel],input[type=search],input[type=datetime-local],
select,textarea{
  width:100%;padding:.55rem .72rem;border:1px solid var(--line);border-radius:10px;
  font:inherit;font-size:.88rem;background:var(--surface);color:var(--text);
  transition:border-color .15s,box-shadow .15s;
}
input:focus,select:focus,textarea:focus{
  outline:0;border-color:var(--brand);box-shadow:0 0 0 3px rgba(var(--brand-rgb),.16);
}
input[readonly],input:disabled,select:disabled,textarea:disabled{background:var(--surface-2);color:var(--muted)}
textarea{resize:vertical;min-height:92px}
input[type=color]{width:56px;height:38px;padding:2px;border-radius:9px;border:1px solid var(--line);background:var(--surface);cursor:pointer}
input[type=file]{font-size:.84rem}
.check{display:flex;align-items:center;gap:.5rem;font-size:.87rem;font-weight:500;color:var(--text)}
.check input{width:auto;margin:0}
.checks{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:.4rem .9rem}
.switch{position:relative;display:inline-block;width:44px;height:24px;flex:0 0 44px}
.switch input{opacity:0;width:0;height:0}
.switch .sl{
  position:absolute;inset:0;background:#cbd5e1;border-radius:24px;
  cursor:pointer;transition:background .18s;
}
.switch .sl::before{
  content:'';position:absolute;height:18px;width:18px;left:3px;top:3px;
  background:#fff;border-radius:50%;transition:transform .18s;
}
.switch input:checked + .sl{background:var(--brand)}
.switch input:checked + .sl::before{transform:translateX(20px)}
.input-group{display:flex;gap:.4rem}
.input-group .btn{flex:0 0 auto}

/* ------------------------------------------------------------- flash */
.flash{
  display:flex;align-items:flex-start;gap:.6rem;padding:.7rem 1rem;border-radius:11px;
  margin-bottom:.8rem;font-size:.88rem;border:1px solid transparent;
}
.flash span{flex:1}
.flash-x{background:none;border:0;font-size:1.2rem;line-height:1;cursor:pointer;color:inherit;opacity:.6}
.flash-success{background:var(--ok-bg);color:#14532d;border-color:#bbf7d0}
.flash-error{background:var(--danger-bg);color:#7f1d1d;border-color:#fecaca}
.flash-warning{background:var(--warn-bg);color:#78350f;border-color:#fde68a}
.flash-info{background:var(--info-bg);color:#1e3a8a;border-color:#bfdbfe}

/* ------------------------------------------------------------- misc */
.toolbar{
  display:flex;gap:.6rem;flex-wrap:wrap;align-items:center;margin-bottom:1rem;
}
.toolbar form{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center}
.toolbar .grow{flex:1;min-width:180px}
.pager{display:flex;gap:.3rem;justify-content:center;padding:1rem;flex-wrap:wrap}
.pager a,.pager span{
  padding:.34rem .7rem;border-radius:8px;border:1px solid var(--line);
  font-size:.83rem;color:var(--text-2);text-decoration:none;background:var(--surface);
}
.pager a:hover{background:var(--surface-2);text-decoration:none}
.pager .cur{background:var(--brand);color:#fff;border-color:var(--brand);font-weight:700}
.pager .off{opacity:.45}
.tabs{display:flex;gap:.3rem;border-bottom:1px solid var(--line);margin-bottom:1.1rem;overflow-x:auto}
.tabs a{
  padding:.55rem .95rem;font-size:.87rem;font-weight:600;color:var(--text-2);
  border-bottom:2px solid transparent;white-space:nowrap;text-decoration:none;
}
.tabs a:hover{color:var(--brand);text-decoration:none}
.tabs a.active{color:var(--brand);border-bottom-color:var(--brand)}
.kv{display:grid;grid-template-columns:auto 1fr;gap:.45rem 1rem;font-size:.88rem}
.kv dt{color:var(--muted);font-weight:600}
.kv dd{margin:0;font-weight:500}
.thumb{width:42px;height:42px;border-radius:9px;object-fit:cover;border:1px solid var(--line);background:var(--surface-2)}
.thumb-lg{width:76px;height:76px;border-radius:12px;object-fit:cover;border:1px solid var(--line)}
.chip{
  display:inline-flex;align-items:center;gap:.3rem;background:var(--surface-2);
  border:1px solid var(--line);border-radius:20px;padding:.16rem .6rem;font-size:.76rem;
}
.progress{height:7px;background:var(--line-2);border-radius:10px;overflow:hidden}
.progress i{display:block;height:100%;background:var(--brand);border-radius:10px}
.color-row{display:flex;align-items:center;gap:.5rem}
.color-row input[type=text]{max-width:120px}

/* ------------------------------------------------------------ modals */
.modal-backdrop{
  position:fixed;inset:0;background:rgba(15,23,42,.55);backdrop-filter:blur(2px);
  display:grid;place-items:center;padding:1.2rem;z-index:100;
}
.modal-card{
  background:var(--surface);border-radius:18px;max-width:440px;width:100%;
  padding:1.7rem;text-align:center;box-shadow:var(--shadow-lg);
}
.modal-card.wide{max-width:760px;text-align:left}
.modal-icon{font-size:2.6rem;margin-bottom:.4rem}
.modal-window{background:var(--warn-bg);color:var(--warn);border-radius:9px;padding:.45rem;font-size:.86rem}
.modal-msg{color:var(--text-2);font-size:.88rem}
.modal-actions{display:flex;gap:.55rem;justify-content:center;margin-top:1.1rem;flex-wrap:wrap}

/* ------------------------------------------------- centred state pages */
.page-center{display:grid;place-items:center;min-height:100vh;padding:1.5rem;background:var(--bg)}
.state-card{
  background:var(--surface);border:1px solid var(--line);border-radius:20px;
  box-shadow:var(--shadow-lg);padding:2.2rem;max-width:520px;width:100%;text-align:center;
}
.state-icon{font-size:3rem;margin-bottom:.5rem}
.state-actions{display:flex;gap:.6rem;justify-content:center;margin-top:1.3rem;flex-wrap:wrap}
.license-card{max-width:640px;text-align:left}
.license-card h1,.license-card > p{text-align:center}
.license-card .state-icon{text-align:center}
.license-meta{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.7rem;
  background:var(--surface-2);border-radius:12px;padding:.9rem;margin:1.1rem 0;
}
.license-meta span{display:block;font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
.license-meta strong{font-size:.9rem;word-break:break-all}
.license-note{background:var(--warn-bg);color:var(--warn);border-radius:10px;padding:.6rem .85rem;font-size:.85rem}
.support-box{border:1px dashed var(--line);border-radius:12px;padding:1rem;margin-top:1rem}
.support-box h3{margin:0 0 .6rem;font-size:.92rem}
.support-box ul{list-style:none;margin:0;padding:0;display:grid;gap:.4rem;font-size:.87rem}
.support-box li{display:flex;gap:.6rem}
.support-box li span{color:var(--muted);min-width:80px}

/* -------------------------------------------------------- auth pages */
.auth{
  min-height:100vh;display:grid;grid-template-columns:1.05fr .95fr;
  background:var(--bg);
}
.auth-art{
  background:linear-gradient(150deg,var(--sidebar) 0%,var(--brand-dark) 65%,var(--brand) 100%);
  color:#fff;padding:3rem 3.2rem;display:flex;flex-direction:column;justify-content:center;position:relative;overflow:hidden;
}
.auth-art::before,.auth-art::after{
  content:'';position:absolute;border-radius:50%;opacity:.16;
}
.auth-art::before{width:420px;height:420px;background:var(--accent);right:-140px;top:-120px}
.auth-art::after{width:320px;height:320px;background:#fff;left:-120px;bottom:-110px;opacity:.07}
.auth-art .brand{border:0;padding:0;margin-bottom:2rem;position:relative}
.auth-art h2{font-size:2rem;line-height:1.25;position:relative;margin-bottom:.8rem}
.auth-art p{color:rgba(255,255,255,.82);font-size:.98rem;position:relative;max-width:44ch}
.auth-points{list-style:none;padding:0;margin:1.8rem 0 0;display:grid;gap:.75rem;position:relative}
.auth-points li{display:flex;gap:.7rem;align-items:flex-start;font-size:.9rem;color:rgba(255,255,255,.9)}
.auth-points .tick{
  width:22px;height:22px;border-radius:50%;background:rgba(255,255,255,.16);
  display:grid;place-items:center;flex:0 0 22px;font-size:.72rem;
}
.auth-form{display:flex;align-items:center;justify-content:center;padding:2.4rem 1.5rem}
.auth-box{width:100%;max-width:400px}
.auth-box h1{font-size:1.55rem;margin-bottom:.25rem}
.auth-box .lead{color:var(--muted);margin-bottom:1.4rem;font-size:.9rem}
.auth-box .field{margin-bottom:.9rem}
.auth-alt{margin-top:1.2rem;text-align:center;font-size:.86rem;color:var(--muted)}
.auth-foot{margin-top:1.6rem;text-align:center;font-size:.76rem;color:var(--muted)}
.pw-wrap{position:relative}
.pw-wrap input{padding-right:2.6rem}
.pw-toggle{
  position:absolute;right:.4rem;top:50%;transform:translateY(-50%);
  background:none;border:0;cursor:pointer;font-size:1rem;color:var(--muted);padding:.3rem;
}

/* ------------------------------------------------------------ invoice */
.inv-sheet{background:#fff;padding:2rem;max-width:820px;margin:0 auto;color:#0f172a}
.inv-head{display:flex;justify-content:space-between;gap:1.5rem;flex-wrap:wrap;border-bottom:2px solid var(--brand);padding-bottom:1rem;margin-bottom:1.2rem}
.inv-head h1{color:var(--brand);font-size:1.7rem;margin:0}
.inv-logo{max-height:64px}
.inv-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:1.2rem;margin-bottom:1.2rem}
.inv-meta h4{font-size:.72rem;text-transform:uppercase;letter-spacing:.09em;color:var(--muted);margin-bottom:.3rem}
table.inv-tbl{width:100%;border-collapse:collapse;font-size:.87rem}
table.inv-tbl th{background:var(--brand);color:#fff;padding:.55rem .7rem;text-align:left;font-size:.76rem;text-transform:uppercase;letter-spacing:.05em}
table.inv-tbl td{padding:.55rem .7rem;border-bottom:1px solid var(--line)}
table.inv-tbl .num{text-align:right;font-variant-numeric:tabular-nums}
.inv-total{margin-left:auto;max-width:320px;margin-top:1rem}
.inv-total .row{display:flex;justify-content:space-between;padding:.35rem 0;font-size:.9rem}
.inv-total .row.grand{border-top:2px solid var(--brand);margin-top:.4rem;padding-top:.6rem;font-size:1.1rem;font-weight:800;color:var(--brand)}
.inv-serials{font-size:.76rem;color:var(--muted);display:block}

/* -------------------------------------------------------- addon banners
   Drawn by includes/addon-banner.php, so there is no image to load and no
   size to guess: the SVG fills whatever box it is given. The box keeps its
   aspect ratio inline, because the ratio changes with where it is used — wide
   and short in a grid, taller on a product page. */
.addon-banner{
  position:relative;overflow:hidden;border-radius:12px;line-height:0;
  background:var(--surface-2);
}
.addon-banner svg,
.addon-banner img{width:100%;height:100%;display:block;object-fit:cover}
.addon-banner.flush{border-radius:0}

/* ------------------------------------------------------- addon cards */
.mod-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1.1rem}
.mod{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);display:flex;flex-direction:column;position:relative;overflow:hidden;
}
.mod.on{border-color:var(--brand);box-shadow:0 0 0 1px var(--brand),var(--shadow)}
.mod > .addon-banner{border-radius:0;flex:0 0 auto}
.mod .mbody{padding:1.05rem 1.15rem 1.15rem;display:flex;flex-direction:column;gap:.6rem;flex:1}
.mod .mh{display:flex;align-items:flex-start;gap:.7rem}
.mod .mico{
  width:44px;height:44px;border-radius:12px;flex:0 0 44px;display:grid;place-items:center;
  background:var(--brand-light);font-size:1.4rem;
}
.mod h3{margin:0;font-size:1rem}
.mod .ver{font-size:.74rem;color:var(--muted)}
.mod p{font-size:.85rem;color:var(--text-2);margin:0;flex:1}
.mod .mf{display:flex;gap:.45rem;align-items:center;flex-wrap:wrap;padding-top:.55rem;border-top:1px solid var(--line-2)}
/* Over the banner, not over the card: the badge has to stay legible on any of
   the generated colours, so it gets its own dark plate rather than the panel's
   surface colour. */
.tier{position:absolute;top:.7rem;right:.7rem;z-index:2}
.tier .badge{box-shadow:0 1px 6px rgba(0,0,0,.35)}

/* ----------------------------------------------------------- tickets */
.thread{display:grid;gap:.9rem}
.msg{border:1px solid var(--line);border-radius:12px;overflow:hidden}
.msg header{
  padding:.55rem .85rem;background:var(--surface-2);border-bottom:1px solid var(--line);
  display:flex;gap:.6rem;align-items:center;font-size:.83rem;
}
.msg header .who{font-weight:700}
.msg header time{margin-left:auto;color:var(--muted);font-size:.76rem}
.msg .body{padding:.9rem;font-size:.9rem;white-space:pre-wrap;word-break:break-word}
.msg.staff{border-color:var(--brand)}
.msg.staff header{background:var(--brand-light);color:var(--brand-dark)}
.attach{display:flex;gap:.45rem;flex-wrap:wrap;padding:0 .9rem .8rem}
.attach a{
  display:inline-flex;align-items:center;gap:.35rem;font-size:.78rem;
  background:var(--surface-2);border:1px solid var(--line);border-radius:8px;padding:.25rem .55rem;
}

/* --------------------------------------------------------- printing */
@media print{
  .sidebar,.topbar,.no-print,.toolbar,.pager{display:none !important}
  body{background:#fff}
  .content{padding:0}
  .card{border:0;box-shadow:none;margin:0}
  .inv-sheet{padding:0;max-width:100%}
  @page{margin:12mm}
}

/* -------------------------------------------------------- responsive */
@media (max-width:1200px){
  .g4{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:1024px){
  .g-2-1,.g-1-2,.g3{grid-template-columns:1fr}
}
@media (max-width:900px){
  .menu-btn{display:block}
  .sidebar{
    position:fixed;left:0;top:0;bottom:0;transform:translateX(-100%);
    transition:transform .22s ease;box-shadow:var(--shadow-lg);
  }
  .sidebar.open{transform:translateX(0)}
  .sb-overlay{
    position:fixed;inset:0;background:rgba(15,23,42,.5);z-index:35;display:none;
  }
  .sb-overlay.show{display:block}
  .g2,.g3,.g4,.f2,.f3{grid-template-columns:1fr}
  .field.span2,.field.span3{grid-column:span 1}
  .content{padding:.9rem}
  .topbar{padding:.6rem .9rem}
  .umenu-name{display:none}
}
@media (max-width:600px){
  .stats{grid-template-columns:1fr 1fr;gap:.7rem}
  .stat{padding:.8rem}
  .stat .val{font-size:1.3rem}
  .card-b{padding:.85rem}
  .topbar h1{font-size:1rem}
}

/* ------------------------------------------------------ currency switch */
.cur-toggle{display:inline-flex;border:1px solid var(--line);border-radius:30px;overflow:hidden;background:var(--surface)}
.cur-toggle a{
  padding:.3rem .85rem;font-size:.8rem;font-weight:700;color:var(--text-2);
  text-decoration:none;transition:background .15s,color .15s;
}
.cur-toggle a:hover{background:var(--surface-2);text-decoration:none}
.cur-toggle a.on{background:var(--brand);color:#fff}

/* ---------------------------------------------------------- addon store */
.store-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1.1rem}
.scard{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);display:flex;flex-direction:column;overflow:hidden;position:relative;
}
.scard .cover{
  height:120px;background:linear-gradient(135deg,var(--brand-light),var(--surface-2));
  display:grid;place-items:center;font-size:2.6rem;border-bottom:1px solid var(--line);
}
.scard .cover img{width:100%;height:100%;object-fit:cover}
.scard .sb{padding:1rem;display:flex;flex-direction:column;gap:.5rem;flex:1}
.scard h3{margin:0;font-size:1rem}
.scard .tag{font-size:.82rem;color:var(--muted);margin:0;flex:1}
.scard .price{font-size:1.25rem;font-weight:800;color:var(--brand);letter-spacing:-.02em}
.scard .price small{font-size:.72rem;font-weight:600;color:var(--muted);letter-spacing:0}
.scard .sf{padding:.75rem 1rem;border-top:1px solid var(--line-2);display:flex;gap:.45rem;flex-wrap:wrap}
.scard .owned{position:absolute;top:.7rem;right:.7rem}

/* --------------------------------------------------------- product page */
.pp-hero{display:grid;grid-template-columns:1.4fr 1fr;gap:1.6rem;align-items:start}
.pp-hero h1{font-size:1.9rem;margin-bottom:.3rem}
.pp-lead{font-size:1.02rem;color:var(--text-2)}
.pp-buy{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
        padding:1.2rem;box-shadow:var(--shadow);position:sticky;top:1rem}
.pp-buy .price{font-size:2rem;font-weight:800;color:var(--brand);letter-spacing:-.02em;line-height:1.1}
.pp-shots{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:.8rem}
.pp-shots a{display:block;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:var(--surface-2)}
.pp-shots img{display:block;width:100%;height:150px;object-fit:cover}
.pp-body{font-size:.95rem;line-height:1.75;white-space:pre-line}
.feat-list{list-style:none;padding:0;margin:0;display:grid;gap:.45rem;font-size:.9rem}
.feat-list li::before{content:'\2713';color:var(--ok);font-weight:700;margin-right:.5rem}

/* A block of example code on the developer notes. Scrolls inside itself: a
   line of PHP is longer than a column and must never widen the page. */
.code-block{
  background:var(--surface-2);border:1px solid var(--line);border-radius:10px;
  padding:.8rem .9rem;font-size:.75rem;line-height:1.6;overflow-x:auto;
  margin:.35rem 0 1.1rem;white-space:pre;
  font-family:ui-monospace,SFMono-Regular,Consolas,"Liberation Mono",monospace;
}

/* A banner small enough to sit inside a table row, next to the addon's name. */
.addon-chip{
  width:104px;flex:0 0 104px;border-radius:8px;overflow:hidden;line-height:0;aspect-ratio:3 / 1;
}
.addon-chip svg,.addon-chip img{width:100%;height:100%;display:block;object-fit:cover}
.tbl-with-chip{display:flex;align-items:center;gap:.7rem;min-width:0}
@media(max-width:900px){.pp-hero{grid-template-columns:1fr}.pp-buy{position:static}}

/* ------------------------------------------------------------- checkout */
.co-sum{background:var(--surface-2);border-radius:12px;padding:1rem}
.co-sum .row{display:flex;justify-content:space-between;padding:.3rem 0;font-size:.9rem}
.co-sum .row.total{border-top:2px solid var(--brand);margin-top:.5rem;padding-top:.6rem;
                   font-size:1.15rem;font-weight:800;color:var(--brand)}
.gw-list{display:grid;gap:.6rem}
.gw{border:1px solid var(--line);border-radius:12px;padding:.85rem;cursor:pointer;display:flex;gap:.7rem;align-items:flex-start}
.gw:hover{background:var(--surface-2)}
.gw input{margin-top:.25rem}
.gw .gi{font-size:1.5rem}
.gw h4{margin:0 0 .15rem;font-size:.94rem}
.gw p{margin:0;font-size:.82rem;color:var(--muted)}
.gw.on{border-color:var(--brand);box-shadow:0 0 0 1px var(--brand)}

/* ---- notifications: a bell row is a link to the full text ---- */
a.notif-item{color:inherit;text-decoration:none;transition:background .12s}
a.notif-item:hover{background:var(--surface-2);text-decoration:none}
.notif-foot{
  padding:.55rem .9rem;border-top:1px solid var(--line-2);text-align:center;
  background:var(--surface-2);border-radius:0 0 var(--radius) var(--radius);
}
.notif-foot a{font-size:.8rem;font-weight:600}
.notif-full{white-space:pre-wrap;line-height:1.7;font-size:.95rem}
.notif-full a{word-break:break-word}
.notif-meta{
  display:flex;flex-wrap:wrap;gap:.5rem 1.2rem;font-size:.78rem;color:var(--muted);
  border-top:1px solid var(--line-2);margin-top:1.1rem;padding-top:.8rem;
}
.notif-hero{display:flex;gap:.9rem;align-items:flex-start}
.notif-hero .big-ico{
  font-size:1.7rem;line-height:1;flex:0 0 auto;width:44px;height:44px;border-radius:12px;
  display:flex;align-items:center;justify-content:center;background:var(--surface-2);
}

/* ---- the built-in rich-text editor ---- */
.rte{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);overflow:hidden}
.rte.drag{outline:2px dashed var(--brand);outline-offset:-4px}
.rte-bar{
  display:flex;flex-wrap:wrap;gap:.15rem;align-items:center;padding:.4rem;
  background:var(--surface-2);border-bottom:1px solid var(--line-2);position:sticky;top:0;z-index:2;
}
.rte-b{
  min-width:30px;height:30px;padding:0 .45rem;border:1px solid transparent;border-radius:7px;
  background:transparent;color:var(--text);font-size:.82rem;line-height:1;cursor:pointer;
}
.rte-b:hover{background:var(--surface);border-color:var(--line)}
.rte-b.on{background:var(--brand);border-color:var(--brand);color:#fff}
.rte-sep{width:1px;height:20px;background:var(--line);margin:0 .2rem}
.rte-color{
  width:30px;height:30px;padding:2px;border:1px solid var(--line);border-radius:7px;
  background:var(--surface);cursor:pointer;
}
.rte-area{
  min-height:190px;max-height:60vh;overflow-y:auto;padding:.9rem 1rem;
  font-size:.95rem;line-height:1.7;color:var(--text);outline:none;
}
.rte-area:focus{box-shadow:inset 0 0 0 2px rgba(var(--brand-rgb),.16)}
.rte-area img{max-width:100%;height:auto;border-radius:8px}
.rte-area blockquote{
  margin:.8rem 0;padding:.5rem .9rem;border-left:3px solid var(--brand);
  background:var(--surface-2);color:var(--text-2);
}
.rte-area code{background:var(--surface-2);padding:.1rem .35rem;border-radius:5px;font-size:.88em}
.rte-area h2{font-size:1.25rem;margin:.8rem 0 .4rem}
.rte-area h3{font-size:1.05rem;margin:.7rem 0 .35rem}
.rte-area ul,.rte-area ol{margin:.5rem 0 .5rem 1.4rem}
.rte-area a{color:var(--brand);text-decoration:underline}
.rte-src{
  width:100%;min-height:190px;border:0;padding:.9rem 1rem;resize:vertical;
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:.82rem;line-height:1.6;
  background:var(--surface);color:var(--text);outline:none;
}
.rte-video{position:relative;padding-bottom:56.25%;height:0;margin:.8rem 0}
.rte-video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;border-radius:10px}
.rte-note{
  padding:.4rem .9rem;font-size:.78rem;color:var(--muted);
  background:var(--surface-2);border-top:1px solid var(--line-2);
}
@media (max-width:640px){
  .rte-b{min-width:34px;height:34px}
  .rte-area{min-height:150px;padding:.75rem}
}

/* ---- the credit line every script carries ---- */
.foot-credit{
  padding:1.1rem 1.2rem 1.6rem;text-align:center;font-size:.8rem;color:var(--muted);
  line-height:1.6;
}
.foot-credit a{color:var(--brand);font-weight:600}
.foot-credit img{max-width:100%;height:auto;vertical-align:middle;max-height:28px}
.foot-credit p{margin:0}
@media print{ .foot-credit{display:none} }

/* ---- export / import picker ---- */
.dt-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:.5rem}
.dt-item{
  display:flex;align-items:center;gap:.6rem;padding:.6rem .7rem;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);
}
.dt-item:hover{border-color:var(--brand)}
.dt-item input{flex:0 0 auto}
.dt-item .ico{font-size:1.1rem;line-height:1}
.dt-item strong{display:block;font-size:.86rem}
.dt-item small{color:var(--muted);font-size:.74rem}

/* ---- a command you are meant to copy ---- */
.copy-row{
  display:flex;gap:.5rem;align-items:center;background:var(--surface-2);
  border:1px solid var(--line-2);border-radius:var(--radius);padding:.5rem .6rem;
}
.copy-row code{
  flex:1;min-width:0;overflow-x:auto;white-space:nowrap;font-size:.76rem;
  background:transparent;padding:0;
}

/* ---- the connection notice ---- */
.hcs-net-pop{
  position:fixed;left:50%;bottom:22px;transform:translate(-50%,140%);
  z-index:9999;display:flex;gap:.85rem;align-items:flex-start;
  width:min(520px,calc(100vw - 24px));padding:1rem 1.1rem;
  background:var(--surface);border:1px solid var(--line);
  border-left:4px solid var(--brand);border-radius:14px;
  box-shadow:0 18px 44px rgba(15,23,42,.24);
  opacity:0;transition:transform .26s cubic-bezier(.2,.8,.3,1),opacity .26s;
}
.hcs-net-pop.show{transform:translate(-50%,0);opacity:1}
.hcs-net-pop.is-off{border-left-color:var(--danger)}
.hcs-net-pop.is-on{border-left-color:var(--ok)}
.hcs-net-pop .np-ico{font-size:1.5rem;line-height:1;flex:0 0 auto;margin-top:.1rem}
.hcs-net-pop .np-body{flex:1;min-width:0}
.hcs-net-pop h4{margin:0 0 .25rem;font-size:.95rem;font-weight:700}
.hcs-net-pop p{margin:0;font-size:.84rem;line-height:1.6;color:var(--text-2)}
.hcs-net-pop .np-x{
  flex:0 0 auto;border:0;background:transparent;color:var(--muted);
  font-size:1.25rem;line-height:1;cursor:pointer;padding:0 .1rem;
}
.hcs-net-pop .np-x:hover{color:var(--text)}
.np-list{list-style:none;margin:.6rem 0 0;padding:0;font-size:.8rem;line-height:1.75}
.np-list li{padding-left:1.35rem;position:relative;color:var(--text-2)}
.np-list li::before{position:absolute;left:0;top:0;font-weight:700}
.np-list li.yes::before{content:'\2713';color:var(--ok)}
.np-list li.no::before{content:'\2715';color:var(--danger)}
.np-sync{display:flex;align-items:center;gap:.5rem;margin-top:.6rem;font-size:.8rem;color:var(--text-2)}
.np-dot{
  width:9px;height:9px;border-radius:50%;background:var(--brand);flex:0 0 auto;
  animation:npPulse 1.1s ease-in-out infinite;
}
.np-dot.done{background:var(--ok);animation:none}
@keyframes npPulse{0%,100%{opacity:.3;transform:scale(.8)}50%{opacity:1;transform:scale(1.15)}}
@media (max-width:520px){
  .hcs-net-pop{bottom:12px;padding:.85rem .9rem;gap:.6rem}
  .hcs-net-pop h4{font-size:.9rem}
}
@media (prefers-reduced-motion:reduce){
  .hcs-net-pop{transition:opacity .2s}
  .np-dot{animation:none}
}

/* ---- nothing may push the page sideways ----
   Grid and flex items default to min-width:auto, which means a wide table or a
   long word makes the whole page scroll instead of the box that holds it. This
   is the rule that keeps every screen inside the viewport on a phone. */
.main, .content, .card, .card-b, .card-h, .card-f,
.grid > *, .g2 > *, .g-2-1 > *, .stats > *, .form-grid > *{ min-width:0 }
.table-wrap{ max-width:100%; overflow-x:auto }
.card, .content, .main{ max-width:100% }
.tbl-sub, .tbl-title{ overflow-wrap:break-word }
.notif-item p, .notif-item h5{ overflow-wrap:anywhere }
code, .small code{ overflow-wrap:anywhere }

@media (max-width:640px){
  /* Two- and three-column forms become one column; nothing is worth
     squeezing to 90px on a phone. */
  .form-grid.f2, .form-grid.f3, .form-grid.f4{ grid-template-columns:1fr }
  .field.span2, .field.span3, .field.span4{ grid-column:auto }
  .g2, .g-2-1{ grid-template-columns:1fr }
  .stats{ grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:.7rem }
  .toolbar{ gap:.45rem }
  .toolbar form{ width:100% }
  .toolbar .grow{ flex:1 1 100%; min-width:0 }
  .btn{ padding:.5rem .8rem }
  .card-h{ flex-wrap:wrap; gap:.4rem }
  .card-h h2{ font-size:1rem }
  .inv-sheet{ padding:1rem }
  .inv-head{ gap:.8rem }
  .inv-head h1{ font-size:1.3rem }
  .dt-grid{ grid-template-columns:1fr }
}

@media (max-width:420px){
  .stats{ grid-template-columns:1fr }
  .umenu-name{ display:none }
  .btn-row{ flex-wrap:wrap }
  .btn-row .btn{ flex:1 1 auto }
}

/* ---- the top bar has to fit a phone too ---- */
.topbar > div:first-of-type, .topbar .tb-title{ min-width:0 }
.topbar h1{
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;
}
.topbar .sub{
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;
}
@media (max-width:760px){
  .topbar{ padding:.6rem .9rem; gap:.55rem }
  .topbar h1{ font-size:1rem }
  .topbar .sub{ display:none }
  .lic-chip{ display:none }          /* the licence state lives on its own page */
}
@media (max-width:420px){
  .topbar{ gap:.4rem; padding:.55rem .7rem }
  .umenu-btn{ padding:.25rem .3rem }
}

/* ---- price + details on a module card ---- */
.mstore{
  display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;
  padding:.5rem .6rem;margin-top:.2rem;border-radius:var(--radius);
  background:var(--surface-2);border:1px solid var(--line-2);
}
.mprice{font-size:1.02rem;font-weight:800;color:var(--brand)}
.mstore .btn{margin-left:auto}

/* ---- repair and mould jobs ---- */
.jchips{display:flex;gap:.4rem;flex-wrap:wrap;margin-bottom:1rem}
.jchip{
  display:inline-flex;align-items:center;gap:.4rem;padding:.35rem .75rem;
  border:1px solid var(--line);border-radius:30px;background:var(--surface);
  font-size:.8rem;font-weight:600;color:var(--text-2);text-decoration:none;
}
.jchip:hover{border-color:var(--brand);color:var(--brand);text-decoration:none}
.jchip.on{background:var(--brand);border-color:var(--brand);color:#fff}
.jchip span{
  font-size:.72rem;padding:.05rem .4rem;border-radius:20px;
  background:var(--surface-2);color:var(--text-2);
}
.jchip.on span{background:rgba(255,255,255,.24);color:#fff}

.jtl{list-style:none;margin:0;padding:0;position:relative}
.jtl::before{
  content:'';position:absolute;left:15px;top:6px;bottom:6px;width:2px;background:var(--line);
}
.jtl li{position:relative;display:flex;gap:.85rem;padding:0 0 1.1rem}
.jtl li:last-child{padding-bottom:0}
.jtl li.internal{opacity:.72}
.jtl-dot{
  position:relative;z-index:1;flex:0 0 32px;width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;font-size:.9rem;
  background:var(--surface);border:2px solid var(--line);
}
.jtl li.internal .jtl-dot{border-style:dashed}
.jtl li > div{flex:1;min-width:0;padding-top:.25rem}
.jtl strong{font-size:.88rem}
.jtl p{margin:.2rem 0 0;font-size:.84rem;color:var(--text-2);white-space:pre-wrap}
.jtl time{display:block;margin-top:.25rem;font-size:.74rem;color:var(--muted)}

.mono{font-family:ui-monospace,Menlo,Consolas,monospace}

@media (max-width:640px){
  .jtl::before{left:13px}
  .jtl-dot{flex:0 0 28px;width:28px;height:28px;font-size:.8rem}
  .jchip{padding:.3rem .6rem;font-size:.76rem}
}

/* The footer every panel shares: what this is on the left, where to go on the
   right. It stacks on a phone rather than squeezing into one line. */
/* The footer sits inside the same column as the page content — run out to
   the full window width and the two ends drift so far apart they stop
   reading as one line. */
.foot{padding:0 1.3rem 1.4rem;font-size:.78rem;color:var(--muted)}
@media (max-width:720px){ .foot{padding:0 .9rem 1.1rem} }
.foot-bar{max-width:1180px;margin:0 auto;padding:.85rem 1.1rem;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius)}
.foot-credit-line{max-width:1180px;margin:.5rem auto 0}
.foot-bar{display:flex;flex-wrap:wrap;gap:.6rem 1.2rem;align-items:center;justify-content:space-between}
.foot-left{min-width:0}
.foot-app{font-weight:700;color:var(--text)}
.foot-ver{opacity:.7}
.foot-right{display:flex;flex-wrap:wrap;gap:.3rem 1rem}
.foot-right a{color:var(--muted);text-decoration:none;border-bottom:1px dotted var(--line-2)}
.foot-right a:hover{color:var(--brand);border-bottom-color:var(--brand)}
.foot-credit-line{margin-top:.5rem;text-align:center;opacity:.85}
@media (max-width:560px){
  .foot-bar{flex-direction:column;align-items:flex-start;gap:.5rem}
  .foot-right{gap:.3rem .8rem}
}

/* The little heading above a package's module chips. */
.pkg-mod-head{font-size:.68rem;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);margin:.7rem 0 .35rem;display:flex;align-items:center;gap:.4rem}

/* The tier badge sits in the card's top corner, so the heading beside it has to
   stop short of that corner — otherwise a long module name wraps underneath the
   badge and the second line is hidden by it. The reserve is sized for the wider
   of the two badges ("Premium"); long names then wrap where they should. */
.mod h3{overflow-wrap:anywhere}

/* The language switch in the top bar: two or three short words, not a dropdown,
   because picking a language should be one click and not two. */
/* The pill that holds the language button.

   No overflow:hidden here, however tempting it looks for a rounded box.
   The menu inside is position:absolute and hangs *below* this element, so
   clipping the box clips the whole menu away: the button toggled, the
   class changed, display:block applied, and nothing appeared on screen.
   The rounding is put on the button instead, which is the thing that
   actually needs it. */
.langpick{display:inline-flex;border:1px solid var(--line);border-radius:999px;
  background:var(--surface);flex-shrink:0}
.langpick > button{border-radius:999px}
.langpick-b{padding:.3rem .6rem;font-size:.76rem;color:var(--muted);text-decoration:none;line-height:1.4}
.langpick-b + .langpick-b{border-left:1px solid var(--line)}
.langpick-b.on{background:var(--brand);color:#fff;font-weight:700}
.langpick-b:hover:not(.on){background:var(--surface-2);color:var(--text)}
@media (max-width:560px){ .langpick-b{padding:.28rem .45rem;font-size:.72rem} }

/* ------------------------------------------------- public front page bits */
.home-track{background:var(--brand-light);border-radius:var(--radius);padding:1.6rem;margin-top:2.6rem}
.home-track-in{display:flex;flex-wrap:wrap;gap:1rem;align-items:center;justify-content:space-between}
.home-track-form{display:flex;gap:.5rem;flex-wrap:wrap}
.home-track-form input{min-width:200px;text-transform:uppercase;
  font-family:ui-monospace,Menlo,Consolas,monospace}

.home-steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem;margin-top:1.2rem}
.home-step{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:1.2rem;position:relative}
.home-step-n{display:grid;place-items:center;width:30px;height:30px;border-radius:50%;
  background:var(--brand);color:#fff;font-weight:800;font-size:.85rem;margin-bottom:.6rem}
.home-step h3{margin:0 0 .3rem;font-size:1rem}
.home-step p{margin:0;font-size:.86rem;color:var(--text-2);line-height:1.6}

.home-figs{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1rem;margin-top:2.6rem}
.home-fig{text-align:center;padding:1.2rem;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius)}
.home-fig strong{display:block;font-size:1.9rem;font-weight:800;color:var(--brand);letter-spacing:-.02em}
.home-fig span{display:block;font-size:.82rem;color:var(--muted);margin-top:.2rem}

.home-faq{max-width:760px;margin:1.2rem auto 0}
.home-q{background:var(--surface);border:1px solid var(--line);border-radius:10px;
  padding:.85rem 1rem;margin-bottom:.55rem}
.home-q summary{cursor:pointer;font-weight:700;font-size:.92rem;list-style:none}
.home-q summary::-webkit-details-marker{display:none}
.home-q summary::after{content:'+';float:right;color:var(--muted);font-weight:400}
.home-q[open] summary::after{content:'\2212'}
.home-q p{margin:.6rem 0 0;font-size:.88rem;color:var(--text-2);line-height:1.7}

.home-cta{text-align:center;margin-top:3rem;padding:2.4rem 1.2rem;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius)}
.home-cta h2{margin:0 0 .3rem}
.home-cta p{margin:0;color:var(--muted)}
@media (max-width:560px){
  .home-track-in{flex-direction:column;align-items:stretch}
  .home-track-form input{flex:1}
}

/* The top bar has to fit a phone. The language switch shows each language's own
   name where there is room and its code where there is not, and the sync chip
   keeps its dot and drops its words — adding the switch had pushed every panel
   page wider than the screen. */
.langpick-b .lp-code{display:none}
@media (max-width:620px){
  .langpick-b .lp-full{display:none}
  .langpick-b .lp-code{display:inline}
  .langpick-b{padding:.3rem .5rem;font-weight:700;letter-spacing:.02em}
  .sync-chip .txt{display:none}
  .sync-chip{padding-left:.5rem;padding-right:.5rem}
}

/* ------------------------------------------------- website manager (CRUD) */
.crud-h{margin:1.4rem 0 .2rem;grid-column:1/-1;font-size:.95rem;color:var(--text)}
.crud-h:first-child{margin-top:0}
.crud-grid .field.span2{grid-column:1/-1}
.crud-switch{display:flex;align-items:center;gap:.6rem;padding-top:.2rem}
.crud-switch-t{font-size:.85rem;color:var(--text-2)}
.crud-img{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}
.crud-img img{width:74px;height:74px;object-fit:cover;border-radius:10px;border:1px solid var(--line)}
.crud-img-del{display:flex;align-items:center;gap:.3rem;font-size:.78rem;color:var(--danger);font-weight:600}
.crud-img input[type=file]{flex:1;min-width:180px;font-size:.82rem}
.inline-search{display:flex;gap:.4rem;align-items:center}
.inline-search input{padding:.36rem .6rem;border:1px solid var(--line);border-radius:8px;font:inherit;font-size:.84rem;background:var(--surface);color:var(--text)}
.ord{width:74px;padding:.3rem .45rem;border:1px solid var(--line);border-radius:7px;font:inherit;font-size:.84rem;background:var(--surface);color:var(--text)}
.thumb.ph{display:inline-grid;place-items:center;font-size:1.1rem;opacity:.5}
.sec-pick{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:.7rem;margin-bottom:1.2rem}
.sec-tile{
  display:flex;flex-direction:column;gap:.2rem;padding:.9rem;border:1px solid var(--line);
  border-radius:11px;background:var(--surface);color:var(--text);transition:.15s;
}
.sec-tile:hover{border-color:var(--brand);box-shadow:var(--shadow);text-decoration:none}
.sec-ico{font-size:1.4rem;line-height:1}
.sec-tile strong{font-size:.9rem}
.sec-tile small{color:var(--muted);font-size:.75rem;line-height:1.4}
.rep{display:flex;flex-direction:column;gap:.5rem;margin-bottom:.6rem}
.rep-row{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr)) 34px;gap:.5rem;
  align-items:end;padding:.6rem;border:1px solid var(--line);border-radius:10px;background:var(--surface-2);
}
.rep-cell{display:flex;flex-direction:column;gap:.2rem;min-width:0}
.rep-lab{font-size:.72rem;color:var(--muted);font-weight:600}
.rep-row input,.rep-row textarea,.rep-row select{
  padding:.4rem .55rem;border:1px solid var(--line);border-radius:8px;font:inherit;font-size:.85rem;
  background:var(--surface);color:var(--text);width:100%;
}
.rep-del{height:32px}
tr.dim{opacity:.55}
.menu-rows{display:flex;flex-direction:column;gap:.55rem}
.menu-row{
  display:grid;grid-template-columns:22px 1.4fr 1fr 1.5fr 1fr 70px 1fr 1fr 46px;gap:.5rem;
  align-items:end;padding:.6rem;border:1px solid var(--line);border-radius:10px;background:var(--surface-2);
}
.menu-row.is-child{margin-left:1.6rem;border-left:3px solid var(--brand)}
.mr-cell{display:flex;flex-direction:column;gap:.2rem;min-width:0}
.menu-row input,.menu-row select{
  padding:.4rem .5rem;border:1px solid var(--line);border-radius:8px;font:inherit;font-size:.84rem;
  background:var(--surface);color:var(--text);width:100%;min-width:0;
}
@media (max-width:900px){
  .menu-row{grid-template-columns:22px 1fr}
  .menu-row.is-child{margin-left:.6rem}
}

/* ------------------------------------------------- dragging menu entries
   The top strip has three places to be, and typing a number into an "order"
   box to move something from the middle to the right is not how anybody
   thinks about it. The lanes are the strip, laid out the way it will look,
   and an entry is dragged into the one it belongs in.

   The number boxes are still there and still work — they are what a keyboard
   uses, and what makes this legible with JavaScript switched off. Dragging
   simply writes into them. */
.mr-grip{
  cursor:grab;display:flex;align-items:center;justify-content:center;
  align-self:stretch;color:var(--muted);font-size:1rem;line-height:1;
  border-radius:6px;user-select:none;touch-action:none;
}
.mr-grip:hover{background:var(--line-2);color:var(--text)}
.mr-grip:active{cursor:grabbing}
.menu-row.dragging{opacity:.45;box-shadow:0 8px 24px rgba(0,0,0,.18)}

.menu-lanes{display:grid;grid-template-columns:repeat(3,1fr);gap:.9rem}
@media (max-width:1100px){.menu-lanes{grid-template-columns:1fr}}
.menu-lane{
  display:flex;flex-direction:column;gap:.55rem;min-height:96px;padding:.6rem;
  border:1px dashed var(--line);border-radius:12px;background:var(--surface);
}
.menu-lane.over{border-color:var(--brand);background:var(--brand-light)}
.menu-lane > h4{
  margin:0;font-size:.72rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--muted);display:flex;align-items:center;gap:.4rem;
}
.menu-lane .lane-empty{
  color:var(--muted);font-size:.82rem;text-align:center;padding:1.1rem .5rem;
  border-radius:8px;background:var(--surface-2);
}
.menu-lane:not(:empty) .lane-empty:not(:only-of-type){display:none}
/* Inside a lane there is a third of the width, so the nine columns become one
   and everything but the label folds away until it is wanted. Two labels
   sharing a line above two half-width boxes reads as one confusing label. */
.menu-lane .menu-row{
  grid-template-columns:22px 1fr;align-items:start;gap:.4rem;padding:.5rem;
}
.menu-lane .menu-row .mr-grip{grid-row:1 / -1}
.menu-lane .menu-row .mr-cell{grid-column:2}
.menu-lane .menu-row .mr-cell:not(.mr-lab){display:none}
.menu-lane .menu-row.open .mr-cell{display:flex}
.menu-lane .mr-toggle{
  grid-column:2;justify-self:start;background:none;border:0;padding:.15rem 0;
  color:var(--brand);font:inherit;font-size:.76rem;font-weight:600;cursor:pointer;
}
.menu-lane .mr-toggle:hover{text-decoration:underline}
/* The wide list has no need of it: everything is already on screen. */
.menu-rows > .menu-row .mr-toggle{display:none}
.quote-box{
  background:var(--surface-2);border:1px solid var(--line);border-left:3px solid var(--brand);
  border-radius:0 10px 10px 0;padding:.9rem 1.1rem;color:var(--text-2);font-size:.92rem;line-height:1.7;
}
.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:.9rem}
.media-item{border:1px solid var(--line);border-radius:11px;overflow:hidden;background:var(--surface)}
.media-thumb{display:block;aspect-ratio:4/3;background:var(--surface-2)}
.media-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.media-meta{padding:.6rem .65rem;display:flex;flex-direction:column;gap:.3rem}
.media-meta strong{font-size:.8rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.media-meta span{font-size:.72rem;color:var(--muted)}
.media-url,.media-alt{
  width:100%;padding:.25rem .4rem;border:1px solid var(--line);border-radius:6px;
  font-size:.72rem;background:var(--surface-2);color:var(--text-2);
}
.stat-row{display:flex;gap:.7rem;flex-wrap:wrap;margin-bottom:1rem}
.stat-mini{
  flex:1;min-width:120px;background:var(--surface-2);border:1px solid var(--line);
  border-radius:11px;padding:.75rem .9rem;
}
.stat-mini strong{display:block;font-size:1.5rem;line-height:1.1;color:var(--brand)}
.stat-mini span{font-size:.8rem;color:var(--muted)}
.stat-mini.warn strong{color:var(--warn)}

/* ------------------------------------------------------- patient file */
.pv{display:grid;grid-template-columns:320px 1fr;gap:1.1rem;align-items:start}
.pv-side .card{position:sticky;top:1rem}
.pv-head{text-align:center}
.pv-photo{
  width:104px;height:104px;margin:0 auto .8rem;border-radius:50%;overflow:hidden;
  border:3px solid var(--brand-light);background:var(--surface-2);
}
.pv-photo img{width:100%;height:100%;object-fit:cover}
.pv-photo.ph{display:grid;place-items:center;font-size:2.6rem;font-weight:800;color:var(--brand);background:var(--brand-light)}
.pv-head h2{margin:0 0 .1rem;font-size:1.15rem}
.pv-pid{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:.82rem;color:var(--muted);margin:.2rem 0 .5rem}
.pv-facts{display:flex;flex-direction:column;gap:.45rem;border-top:1px solid var(--line)}
.pv-fact{display:flex;justify-content:space-between;gap:.8rem;font-size:.85rem;align-items:baseline}
.pv-fact span{color:var(--muted);flex:0 0 auto}
.pv-fact strong{text-align:right;font-weight:600;min-width:0;word-break:break-word}
.pv-main{display:flex;flex-direction:column;gap:1.1rem;min-width:0}

.timeline{display:flex;flex-direction:column;gap:.1rem;position:relative}
.tl-item{display:flex;gap:.8rem;padding-bottom:1rem;position:relative}
.tl-item::before{content:'';position:absolute;left:6px;top:16px;bottom:0;width:1px;background:var(--line)}
.tl-item:last-child::before{display:none}
.tl-dot{
  flex:0 0 auto;width:13px;height:13px;border-radius:50%;background:var(--brand);
  margin-top:5px;box-shadow:0 0 0 3px var(--brand-light);
}
.tl-body{flex:1;min-width:0}
.tl-head{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.25rem}
.tl-body p{margin:0;color:var(--text-2);font-size:.9rem;line-height:1.65}
@media (max-width:1000px){
  .pv{grid-template-columns:1fr}
  .pv-side .card{position:static}
}

/* -------------------------------------------------- appointment slots */
.slot-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:.5rem}
.slot{
  display:flex;flex-direction:column;gap:.1rem;padding:.55rem .5rem;cursor:pointer;
  border:1px solid var(--line);border-radius:10px;background:var(--surface);
  color:var(--text);font:inherit;text-align:center;transition:.14s;
}
.slot strong{font-size:.86rem}
.slot small{font-size:.7rem;color:var(--muted)}
.slot:hover:not(:disabled){border-color:var(--brand);background:var(--brand-light)}
.slot.on{background:var(--brand);border-color:var(--brand);color:#fff}
.slot.on small{color:rgba(255,255,255,.8)}
.slot.full,.slot:disabled{opacity:.42;cursor:not-allowed;background:var(--surface-2)}

/* ------------------------------------------------- patient type-ahead */
.pp-drop{
  position:absolute;top:100%;left:0;right:0;z-index:40;max-height:280px;overflow-y:auto;
  background:var(--surface);border:1px solid var(--line);border-radius:11px;
  box-shadow:var(--shadow-lg);margin-top:.25rem;
}
.pp-row{padding:.5rem .7rem;cursor:pointer;display:flex;flex-direction:column;gap:.1rem;border-bottom:1px solid var(--line-2)}
.pp-row:last-child{border-bottom:0}
.pp-row:hover,.pp-row.on{background:var(--brand-light)}
.pp-row strong{font-size:.9rem}
.pp-row small{font-size:.75rem;color:var(--muted)}

/* ------------------------------------------------------------ audiology */
.f4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:820px){ .f4{grid-template-columns:repeat(2,minmax(0,1fr))} }

.audio-grid th{font-weight:600;font-size:.8rem;white-space:nowrap}
.audio-grid td{padding:.25rem}
.audio-grid input{
  width:100%;min-width:52px;padding:.3rem .25rem;text-align:center;border:1px solid var(--line);
  border-radius:7px;font:inherit;font-size:.85rem;background:var(--surface);color:var(--text);
}
.audio-grid tr.ear-r th{color:#dc2626}
.audio-grid tr.ear-l th{color:#2563eb}
.audio-grid.sm td,.audio-grid.sm th{font-size:.8rem;text-align:center;padding:.3rem}
.audio-grid.sm th:first-child{text-align:left;white-space:normal}

.audio-split{display:grid;grid-template-columns:minmax(300px,460px) 1fr;gap:1.4rem;align-items:start}
.audiogram{background:var(--surface);border:1px solid var(--line);border-radius:10px}
.audio-key{display:flex;gap:.9rem;flex-wrap:wrap;margin-top:.5rem;font-size:.75rem;color:var(--muted)}
.audio-key i{display:inline-block;width:12px;height:12px;margin-right:.25rem;vertical-align:-2px}
.k-o{border:2px solid #dc2626;border-radius:50%}
.k-x{background:linear-gradient(45deg,transparent 44%,#2563eb 44%,#2563eb 56%,transparent 56%),
     linear-gradient(-45deg,transparent 44%,#2563eb 44%,#2563eb 56%,transparent 56%)}
.k-lt{border-left:2px solid #dc2626;border-top:2px solid #dc2626;transform:rotate(-45deg)}
.k-gt{border-right:2px solid #2563eb;border-top:2px solid #2563eb;transform:rotate(45deg)}

.ear-cards{display:grid;grid-template-columns:1fr 1fr;gap:.8rem}
.ear-card{border:1px solid var(--line);border-radius:11px;padding:.8rem .9rem;background:var(--surface-2)}
.ear-card.r{border-top:3px solid #dc2626}
.ear-card.l{border-top:3px solid #2563eb}
.ear-card h4{margin:0 0 .3rem;font-size:.85rem}
.ear-pta{font-size:1.05rem}
.ear-card ul{list-style:none;margin:.5rem 0 0;padding:0;font-size:.8rem;color:var(--text-2)}
.ear-card li{padding:.12rem 0}

.report-head{display:flex;justify-content:space-between;gap:1.4rem;align-items:flex-start;flex-wrap:wrap}
.report-sign{display:flex;justify-content:flex-end;margin-top:2.4rem}
.report-sign div{text-align:center;min-width:200px}
.report-sign span{display:block;border-top:1px solid var(--text-2);margin-bottom:.3rem}
.report-sign small{color:var(--muted);font-size:.8rem}
@media (max-width:900px){ .audio-split{grid-template-columns:1fr} }
@media print{
  .card{box-shadow:none;border:0}
  .print-area{page-break-inside:avoid}
}

/* --------------------------------------------------- document line editor */
.doc-lines td{padding:.3rem}
.doc-lines input,.doc-lines select{
  width:100%;padding:.4rem .5rem;border:1px solid var(--line);border-radius:8px;
  font:inherit;font-size:.86rem;background:var(--surface);color:var(--text);min-width:0;
}
.doc-lines input.right{text-align:right}
.doc-lines .l-total{font-weight:700;white-space:nowrap}
.doc-foot{display:grid;grid-template-columns:1fr 340px;gap:1.6rem;align-items:start}
.doc-totals{display:flex;flex-direction:column;gap:.45rem}
.doc-totals>div{display:flex;justify-content:space-between;align-items:center;gap:.8rem;font-size:.9rem}
.doc-totals span{color:var(--muted)}
.doc-totals input{
  width:130px;text-align:right;padding:.35rem .5rem;border:1px solid var(--line);
  border-radius:8px;font:inherit;font-size:.86rem;background:var(--surface);color:var(--text);
}
.doc-totals .grand{
  border-top:1px solid var(--line);padding-top:.6rem;margin-top:.3rem;font-size:1.05rem;
}
.doc-totals .grand strong{color:var(--brand);font-size:1.2rem}
@media (max-width:820px){ .doc-foot{grid-template-columns:1fr} }

/* ------------------------------------------------------------- the till */
.till{display:grid;grid-template-columns:1fr 340px;gap:1.1rem;align-items:start}
.till-left{display:flex;flex-direction:column;gap:1.1rem;min-width:0}
.till-right .card{position:sticky;top:1rem}
.till-search{
  padding:.45rem .7rem;border:1px solid var(--line);border-radius:9px;font:inherit;
  font-size:.88rem;min-width:240px;background:var(--surface);color:var(--text);
}
.prod-hits{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:.5rem}
.prod-hit{
  display:flex;flex-direction:column;gap:.1rem;padding:.6rem .7rem;cursor:pointer;text-align:left;
  border:1px solid var(--line);border-radius:10px;background:var(--surface);color:var(--text);font:inherit;
}
.prod-hit:hover{border-color:var(--brand);background:var(--brand-light)}
.prod-hit.out{opacity:.62}
.prod-hit strong{font-size:.86rem}
.prod-hit small{font-size:.72rem;color:var(--muted)}
.prod-hit span{font-size:.8rem;font-weight:700;color:var(--brand);margin-top:.15rem}
.prod-hit em{font-style:normal;font-weight:400;color:var(--muted);font-size:.72rem}
.till-line .l-serial{margin-top:.3rem}
@media (max-width:1000px){
  .till{grid-template-columns:1fr}
  .till-right .card{position:static}
}

/* ------------------------------------------------------------- reports */
.rep-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:.8rem}
.rep-card{
  background:var(--surface-2);border:1px solid var(--line);border-radius:12px;
  padding:.9rem 1rem;display:flex;flex-direction:column;gap:.15rem;
}
.rep-card span{font-size:.78rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
.rep-card strong{font-size:1.45rem;line-height:1.15;color:var(--text);letter-spacing:-.02em}
.rep-card small{font-size:.76rem;color:var(--muted)}
.rep-card.warn{border-color:#fde68a;background:var(--warn-bg)}
.rep-card.warn strong{color:var(--warn)}
.rep-card.ok strong{color:var(--ok)}
.rep-scroll{overflow-x:auto}
.rep-chart{min-width:320px;display:block}
.rep-bar{height:8px;background:var(--line-2);border-radius:4px;overflow:hidden}
.rep-bar i{display:block;height:100%;background:var(--brand);border-radius:4px}
.rep-two{display:grid;grid-template-columns:1fr 1fr;gap:1.1rem;align-items:start}
.rep-two>.card{margin:0}
@media (max-width:980px){ .rep-two{grid-template-columns:1fr} }
.lbl{
  display:inline-block;padding:.14rem .55rem;border-radius:999px;color:#fff;
  font-size:.72rem;font-weight:700;letter-spacing:.01em;
}
.pl-group th{background:var(--surface-2);font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.pl-total th{border-top:1px solid var(--line);font-weight:700}
.pl-net th{border-top:2px solid var(--text-2);font-size:1.05rem}
.cmt{border:1px solid var(--line);border-radius:11px;padding:.9rem 1rem;margin-bottom:.8rem;background:var(--surface)}
.cmt-h{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin-bottom:.4rem}
.cmt-b{margin:0 0 .5rem;color:var(--text-2);font-size:.92rem;line-height:1.7}
.cmt-f{display:flex;gap:.4rem;align-items:center;flex-wrap:wrap;margin-top:.5rem}
.cmt-f input{flex:1;min-width:180px;padding:.35rem .55rem;border:1px solid var(--line);border-radius:8px;font:inherit;font-size:.84rem;background:var(--surface);color:var(--text)}

/* ------------------------------------- sidebar: where am I, at a glance */
.nav a.active{
  position:relative;
  background:linear-gradient(90deg,rgba(var(--brand-rgb),.95),rgba(var(--brand-rgb),.45));
  color:#fff;font-weight:600;
  box-shadow:0 4px 14px rgba(var(--brand-rgb),.35);
}
/* A bar on the edge reads faster than a colour change, and survives being
   half-scrolled off the top of a long list. */
.nav a.active::before{
  content:'';position:absolute;left:-.6rem;top:50%;transform:translateY(-50%);
  width:4px;height:62%;border-radius:0 4px 4px 0;background:var(--accent);
}
.nav a.active .ico{transform:scale(1.08)}
.nav-group.on{color:var(--accent)}

/* --------------------------------------------------- "view site" in the bar */
.site-chip{
  display:inline-flex;align-items:center;gap:.35rem;flex:0 0 auto;
  padding:.3rem .7rem;border-radius:20px;border:1px solid var(--line);
  background:var(--surface);color:var(--text-2);
  font-size:.78rem;font-weight:600;white-space:nowrap;
}
.site-chip:hover{border-color:var(--brand);color:var(--brand);text-decoration:none;background:var(--brand-light)}
.site-chip span:first-child{font-size:.92rem;line-height:1}
@media (max-width:820px){ .site-chip-t{display:none} .site-chip{padding:.3rem .5rem} }

/* ------------------------------------------- editor: the library browser */
.rte-modal{
  position:fixed;inset:0;z-index:200;background:rgba(8,12,22,.62);
  display:flex;align-items:center;justify-content:center;padding:1.2rem;
}
.rte-modal-box{
  background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow-lg);
  width:min(860px,100%);max-height:86vh;display:flex;flex-direction:column;overflow:hidden;
}
.rte-modal-h{
  display:flex;align-items:center;gap:.7rem;padding:.9rem 1.1rem;
  border-bottom:1px solid var(--line);
}
.rte-modal-h strong{font-size:.98rem;flex:0 0 auto}
.rte-modal-q{
  flex:1;min-width:0;padding:.42rem .7rem;border:1px solid var(--line);border-radius:9px;
  font:inherit;font-size:.86rem;background:var(--surface);color:var(--text);
}
.rte-modal-x{
  flex:0 0 auto;width:30px;height:30px;border:0;border-radius:8px;cursor:pointer;
  background:var(--surface-2);color:var(--text-2);font-size:1.1rem;line-height:1;
}
.rte-modal-x:hover{background:var(--danger-bg);color:var(--danger)}
.rte-modal-grid{
  padding:1rem;overflow-y:auto;display:grid;gap:.7rem;
  grid-template-columns:repeat(auto-fill,minmax(140px,1fr));
}
.rte-pick{
  border:1px solid var(--line);border-radius:10px;background:var(--surface);
  padding:0;cursor:pointer;overflow:hidden;display:flex;flex-direction:column;text-align:left;
}
.rte-pick:hover{border-color:var(--brand);box-shadow:var(--shadow)}
.rte-pick img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;background:var(--surface-2)}
.rte-pick small{
  padding:.35rem .5rem;font-size:.7rem;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.rte-modal-empty{grid-column:1/-1;text-align:center;color:var(--muted);padding:2rem 0;margin:0}
.rte-modal-f{
  display:flex;align-items:center;gap:.8rem;padding:.8rem 1.1rem;
  border-top:1px solid var(--line);flex-wrap:wrap;
}
.rte-modal-note{font-size:.8rem;color:var(--muted);flex:1;min-width:180px}
.rte-modal-up{
  border:1px solid var(--line);background:var(--surface);color:var(--text);
  padding:.4rem .8rem;border-radius:9px;font:inherit;font-size:.84rem;cursor:pointer;width:auto;
}
.rte-modal-up:hover{border-color:var(--brand);color:var(--brand)}
@media (max-width:600px){
  .rte-modal{padding:.5rem}
  .rte-modal-grid{grid-template-columns:repeat(auto-fill,minmax(110px,1fr))}
  .rte-modal-h{flex-wrap:wrap}
}

/* ------------------------------------------- page builder: drag to reorder */
.sec-pos{display:flex;align-items:center;gap:.4rem}
.sec-grip{
  cursor:grab;color:var(--muted);font-size:.9rem;line-height:1;letter-spacing:-3px;
  user-select:none;padding:.2rem .1rem;
}
.sec-grip:active{cursor:grabbing}
.sec-row.is-dragging{opacity:.45}
.sec-row.drop-above td{box-shadow:inset 0 3px 0 var(--brand)}
.sec-row.drop-below td{box-shadow:inset 0 -3px 0 var(--brand)}

/* ---------------------------------------------- licence: purchases arrive */
.lic-collect{
  display:flex;align-items:center;gap:1rem;flex-wrap:wrap;
  padding:.9rem 1rem;border:1px solid var(--brand-light);border-radius:11px;
  background:var(--brand-light);
}
.lic-collect>div:first-child{flex:1;min-width:220px}
.lic-collect strong{font-size:.92rem;color:var(--brand-dark)}

/* --------------------------------------------------- live visitor dot */
.live-dot{
  display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--ok);
  margin-right:.3rem;vertical-align:1px;box-shadow:0 0 0 0 rgba(21,128,61,.5);
  animation:livePulse 2s infinite;
}
@keyframes livePulse{
  70%{box-shadow:0 0 0 7px rgba(21,128,61,0)}
  100%{box-shadow:0 0 0 0 rgba(21,128,61,0)}
}
@media (prefers-reduced-motion: reduce){ .live-dot{animation:none} }

/* =====================================================================
   Panels on a phone.

   The top bar carries a burger, the page title, a link to the website,
   the licence chip, the language switch, notifications and the user
   menu. On a 375px screen that is about 190px of controls, which left
   the title with 95px and turned "Visitor Analytics" into "Visitor An…".

   So below 640px the bar becomes two rows: the controls keep the first,
   the title gets the whole of the second. Nothing is dropped — every
   control a person needs on a desk is one they need on a phone too.
   ===================================================================== */
@media (max-width:640px){
  .topbar{flex-wrap:wrap;row-gap:.15rem;padding:.55rem .8rem}
  .tb-title{order:9;flex:1 1 100%;min-width:0}
  .topbar-spacer{flex:1 1 auto}
  .topbar h1{font-size:1.02rem;white-space:normal;overflow:visible;line-height:1.3}
  /* The subtitle is a sentence of explanation. On a phone it costs more
     screen than it gives, and the page itself says the same thing. */
  .topbar .sub{display:none}
  .menu-btn{flex:0 0 auto}
}

/* The sidebar drawer: keep it clear of a notch, and stop a flick inside
   it from scrolling the page underneath. */
@media (max-width:900px){
  .sidebar{
    width:min(262px,84vw);
    padding-top:env(safe-area-inset-top);
    padding-bottom:env(safe-area-inset-bottom);
    overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  }
  body.sb-open{overflow:hidden}
}

/* Buttons, tabs and toolbars that were laid out for a desk. */
@media (max-width:560px){
  /* A row of buttons should stack rather than squeeze to nothing. */
  .btn-row{flex-wrap:wrap}
  .btn-row .btn{flex:1 1 auto;justify-content:center}
  .card-h{flex-wrap:wrap;gap:.5rem;row-gap:.6rem}
  .card-h .btn-row{width:100%}
  /* Filter bars: one control per line beats six half-width ones. */
  .filters,.filter-bar{flex-direction:column;align-items:stretch}
  .filters input,.filters select,.filter-bar input,.filter-bar select{width:100%}
  /* Tables scroll inside their wrapper; make it obvious they can. */
  .table-wrap{-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
  .stats{grid-template-columns:1fr 1fr}
  .pager{flex-wrap:wrap;justify-content:center}
  /* A modal that is taller than the phone has to be able to scroll. */
  .modal-box{max-height:92vh;overflow-y:auto;width:calc(100vw - 1.4rem)}
}

/* Nothing in a panel may push the page sideways; wide things scroll in
   their own box instead. `clip` rather than `hidden`: `hidden` turns the
   body into a scroll container and the sticky sidebar and top bar stop
   sticking. */
body{overflow-x:hidden}
@supports (overflow-x:clip){ body{overflow-x:clip} }

/* ------------------------------------------------- wide tables on a phone
   A table with eight columns cannot fit a 375px screen and should not try.
   It already scrolls inside .table-wrap; two things were missing.

   One: the browser was squeezing the key column until "HCBS-ADDON-
   AUDIOLOGY-0001" broke across four lines. Codes, keys, dates, money and
   serials are single tokens — let them keep their line and let the table
   be as wide as it needs.

   Two: nothing said the table scrolled. The shadows below appear only on
   the edge that has more content, using background-attachment:local, so
   they need no JavaScript and cost nothing when the table already fits. */
table.tbl code,table.tbl .code,table.tbl .mono,
table.tbl td.num,table.tbl th.num,table.tbl td.nowrap,
table.tbl .badge,table.tbl .chip{white-space:nowrap}

.table-wrap{
  background:
    linear-gradient(to right,var(--surface) 30%,rgba(255,255,255,0)),
    linear-gradient(to right,rgba(255,255,255,0),var(--surface) 70%) 100% 0,
    radial-gradient(farthest-side at 0 50%,rgba(15,23,42,.16),rgba(15,23,42,0)),
    radial-gradient(farthest-side at 100% 50%,rgba(15,23,42,.16),rgba(15,23,42,0)) 100% 0;
  background-repeat:no-repeat;
  background-size:34px 100%,34px 100%,13px 100%,13px 100%;
  background-attachment:local,local,scroll,scroll;
}

/* The stat card's icon is decoration sitting in the top-right corner. On a
   half-width card a long label such as "Domains in use" ran underneath it.
   Reserve the corner rather than shrinking the label. */
.stat .lbl,.stat .val{padding-right:2.2rem}
@media (max-width:560px){
  .stat .ico{right:.7rem;top:.7rem;font-size:1.25rem}
  .stat .lbl{font-size:.72rem;letter-spacing:.05em}
}

/* =====================================================================
   The sidebar, in blocks.

   Once a few modules are on, the menu runs to sixty-odd entries, and a
   flat list of sixty is a list you scan three times looking for
   something you already know is there. Each category is now its own
   bordered block: the eye can reject a whole block at a glance instead
   of reading every line in it.

   The header sticks to the top of the sidebar while its own block
   scrolls past, so you always know which block you are in.
   ===================================================================== */
.nav-sec{
  border:1px solid rgba(255,255,255,.09);
  border-radius:12px;
  margin:.55rem 0;
  background:rgba(255,255,255,.025);
}
.nav-sec .nav-group{
  position:sticky;top:0;z-index:2;
  margin:0;padding:.5rem .75rem .45rem;
  background:rgba(13,21,38,.92);
  backdrop-filter:blur(6px);
  border-bottom:1px solid rgba(255,255,255,.07);
  border-radius:11px 11px 0 0;
  display:flex;align-items:center;gap:.5rem;
}
/* A short rule before the label, so the header reads as a divider even
   where the border is faint. */
.nav-sec .nav-group::before{
  content:'';width:12px;height:2px;border-radius:2px;
  background:var(--accent);opacity:.75;flex:0 0 12px;
}
.nav-sec-in{padding:.35rem}
.nav-sec-in a{margin-bottom:1px}

/* The block holding the page you are on is lifted out of the stack. */
.nav-sec:has(a.active){
  border-color:rgba(var(--brand-rgb),.55);
  background:rgba(var(--brand-rgb),.10);
}
.nav-sec:has(a.active) .nav-group{color:var(--accent)}

/* Dashboard sits above the first block with no header of its own. */
.nav > a:first-child{margin-bottom:.5rem}

/* ------------------------------------------------------- menu filter */
.nav-find{position:relative;margin:.15rem .1rem .5rem}
.nav-find input{
  width:100%;padding:.48rem .7rem .48rem 2rem;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);
  border-radius:10px;color:#e6ecf7;font:inherit;font-size:.85rem;
}
.nav-find input::placeholder{color:#7c8aa3}
.nav-find input:focus{
  outline:0;border-color:rgba(var(--brand-rgb),.7);
  background:rgba(255,255,255,.09);
}
.nav-find::before{
  content:'\1F50D';position:absolute;left:.6rem;top:50%;
  transform:translateY(-50%);font-size:.8rem;opacity:.55;pointer-events:none;
}
/* What the filter hides. Kept as a class rather than an inline style so
   clearing the box is one class removal, not a style rebuild. */
.nav .is-hidden{display:none !important}
.nav-find-none{
  display:none;padding:.8rem .75rem;color:#7c8aa3;font-size:.84rem;text-align:center;
}
.nav-find-none.on{display:block}

/* A browser without :has still gets the boxes, just not the highlight. */
@supports not selector(:has(a)){
  .nav-sec{background:rgba(255,255,255,.03)}
}

/* =====================================================================
   The top bar, as icons.

   It used to spell everything out — "View site", "Active", "Online",
   the user's full name and role — and a page with a long title had
   nowhere left to put it, so the bar broke onto a second line.

   Every control right of the title is now a 36px square. The words are
   in the tooltip and, where there is more to say, in the control's own
   menu. The title takes whatever is left and scales with it.
   ===================================================================== */
.tb-icon{
  display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;flex:0 0 36px;padding:0;
  border:1px solid var(--line);border-radius:10px;
  background:var(--surface);color:var(--text-2);
  font-size:1rem;line-height:1;cursor:pointer;text-decoration:none;
  position:relative;transition:background .15s,border-color .15s,color .15s;
}
.tb-icon:hover{background:var(--surface-2);color:var(--text);text-decoration:none}
.tb-icon .lp-code{font-size:.74rem;font-weight:800;letter-spacing:.04em}

/* The licence key, coloured by state. The word is in the tooltip. */
.tb-icon.lic-chip.ok{border-color:rgba(22,163,74,.45);color:#15803d;background:rgba(22,163,74,.09)}
.tb-icon.lic-chip.warn{border-color:rgba(217,119,6,.45);color:#b45309;background:rgba(217,119,6,.1)}
.tb-icon.lic-chip.danger{border-color:rgba(220,38,38,.45);color:#b91c1c;background:rgba(220,38,38,.09)}

/* Sync: a dot, green when it is talking to the server. */
.tb-icon.sync-chip .dot{
  width:10px;height:10px;border-radius:50%;background:var(--ok);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 22%,transparent);
}
.tb-icon.sync-chip.off .dot{background:var(--muted);box-shadow:none}
.tb-icon.sync-chip.busy .dot{background:var(--warn)}
.tb-dot-count{
  position:absolute;top:-5px;right:-5px;min-width:17px;height:17px;padding:0 4px;
  border-radius:9px;background:var(--danger);color:#fff;
  font-size:.62rem;font-weight:800;line-height:17px;text-align:center;
}

/* Just the picture. */
.umenu-btn.only-avatar{
  padding:0;border:0;background:none;cursor:pointer;
  width:36px;height:36px;flex:0 0 36px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
}
.umenu-btn.only-avatar .avatar{width:36px;height:36px;font-size:.92rem}
.umenu-btn.only-avatar:hover .avatar{box-shadow:0 0 0 3px var(--brand-light)}

/* --------------------------------------------------- inside a dropdown */
.dropdown .dd-head{
  padding:.45rem .65rem .3rem;font-size:.7rem;font-weight:800;
  text-transform:uppercase;letter-spacing:.09em;color:var(--muted);
}
.dropdown .dd-note{padding:.15rem .65rem .45rem;font-size:.82rem;color:var(--text-2)}
.dropdown .dd-user{
  padding:.55rem .65rem;margin-bottom:.3rem;border-bottom:1px solid var(--line);
  display:flex;flex-direction:column;gap:.1rem;
}
.dropdown .dd-user strong{font-size:.92rem;line-height:1.3}
.dropdown .dd-user small{color:var(--muted);font-size:.78rem}
.dropdown a.on{background:var(--brand-light);font-weight:600}
.dropdown .dd-tick{margin-left:auto;color:var(--brand);font-weight:800}
.langpick .dropdown{min-width:180px}
.langpick .dropdown .lp-code{
  font-size:.68rem;font-weight:800;color:var(--muted);
  border:1px solid var(--line);border-radius:5px;padding:.05rem .3rem;
}

/* -------------------------------------------------------- the title */
/* Fluid, so a long page name shrinks to fit rather than shoving the
   controls onto a second row. */
.topbar h1{
  font-size:clamp(.98rem,1.35vw + .5rem,1.22rem);
  line-height:1.25;margin:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.topbar .sub{
  font-size:clamp(.72rem,.45vw + .58rem,.82rem);
  color:var(--muted);line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.tb-title{min-width:0;flex:0 1 auto}
/* Only above the phone breakpoint: below it the bar deliberately wraps
   so the title gets a full row of its own. */
@media (min-width:641px){ .topbar{gap:.45rem;flex-wrap:nowrap} }

@supports not (color: color-mix(in srgb, red 50%, blue)){
  .tb-icon.sync-chip .dot{box-shadow:0 0 0 3px rgba(22,163,74,.22)}
}

/* ------------------------------------------------ the social-link repeater */
.soc-more{margin-top:1.4rem;padding-top:1rem;border-top:1px solid var(--line)}
.soc-rows{display:grid;gap:.5rem;margin-bottom:.8rem}
.soc-row{display:grid;grid-template-columns:64px minmax(0,1fr) minmax(0,1.6fr) 38px;gap:.5rem;align-items:center}
.soc-row input{
  padding:.55rem .7rem;border:1px solid var(--line);border-radius:9px;
  font:inherit;font-size:.9rem;background:var(--surface);color:var(--text);width:100%;
}
.soc-row input:focus{outline:0;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-light)}
.soc-row .soc-i{text-align:center;font-size:1.05rem}
.soc-del{padding:.4rem .55rem;line-height:1;color:var(--danger)}
@media (max-width:640px){
  /* Three boxes side by side on a phone is three boxes too narrow to read. */
  .soc-row{grid-template-columns:64px minmax(0,1fr) 38px;grid-template-areas:'i l d' 'u u u';row-gap:.4rem}
  .soc-row .soc-i{grid-area:i}
  .soc-row input[name="soc_label[]"]{grid-area:l}
  .soc-row input[name="soc_url[]"]{grid-area:u}
  .soc-row .soc-del{grid-area:d}
}

/* =====================================================================
   table.table is the same thing as table.tbl.

   Both names were in use — 125 places said "tbl", 58 said "table", and
   the stylesheet only knew the first. Everything written with the second
   name rendered as a bare browser table: 1px cell padding, no header
   band, no row rules, columns collapsed to their text with the rest of
   the card left empty. That included includes/admin-crud.php, so every
   generated list screen looked like that.

   Aliasing rather than renaming 58 tags in 38 files: the rename can miss
   one and nobody notices until a screenshot arrives, and the next person
   to type the wrong one is served either way.
   ===================================================================== */
table.table{
  width:100%;border-collapse:collapse;font-size:.88rem;min-width:600px;
}
table.table th{
  text-align:left;padding:.68rem .85rem;background:var(--surface-2);
  border-bottom:1px solid var(--line);font-weight:700;font-size:.76rem;
  text-transform:uppercase;letter-spacing:.06em;color:var(--text-2);white-space:nowrap;
}
table.table td{padding:.68rem .85rem;border-bottom:1px solid var(--line-2);vertical-align:middle}
table.table tbody tr:last-child td{border-bottom:0}
table.table tbody tr:hover{background:var(--surface-2)}
table.table td.num,table.table th.num,table.table td.right,table.table th.right{text-align:right}
table.table td.center,table.table th.center{text-align:center}
table.table code,table.table .code,table.table .mono,
table.table td.num,table.table th.num,table.table td.nowrap,
table.table .badge,table.table .chip{white-space:nowrap}

/* A short table — a two-column summary inside a card — should not be
   forced to 600px and made to scroll for no reason. */
table.table.tight,table.tbl.tight,
table.table[style*="min-width:auto"],table.tbl[style*="min-width:auto"]{min-width:0}

/* =====================================================================
   Filter rows.

   Every list screen has a filter bar built as `<form style="display:flex;
   flex-wrap:wrap">`. The global form rule gives every input and select
   `width:100%`, so inside a wrapping flex row each control claimed a whole
   line and a four-control filter became four stacked rows the full width
   of the card — on a 1400px screen.

   A flex item should be sized by flex, not by a blanket width. Matching on
   the inline style rather than adding a class to thirty-three forms: the
   class can be forgotten on the thirty-fourth, and this cannot.
   ===================================================================== */
form[style*="display:flex"] > input,
form[style*="display:flex"] > select,
form[style*="display:flex"] > .pw-wrap,
.toolbar input, .toolbar select,
.filters input, .filters select{
  width:auto;
}
/* The search box is the one that should soak up the leftover room. */
form[style*="display:flex"] > input[type=search]{flex:1 1 220px;min-width:180px}

@media (max-width:560px){
  /* On a phone the stack is right — one control per line, each full width. */
  form[style*="display:flex"] > input,
  form[style*="display:flex"] > select,
  .toolbar input, .toolbar select,
  .filters input, .filters select{width:100%}
}

/* The network picker made the repeater a five-column row. */
.soc-row{grid-template-columns:150px 64px minmax(0,1fr) minmax(0,1.4fr) 38px}
.soc-row .soc-n{
  padding:.55rem .5rem;border:1px solid var(--line);border-radius:9px;
  font:inherit;font-size:.86rem;background:var(--surface);color:var(--text);width:100%;
}
@media (max-width:760px){
  .soc-row{grid-template-columns:minmax(0,1fr) 64px 38px;grid-template-areas:'n i d' 'l l l' 'u u u';row-gap:.4rem}
  .soc-row .soc-n{grid-area:n}
  .soc-row .soc-i{grid-area:i}
  .soc-row input[name="soc_label[]"]{grid-area:l}
  .soc-row input[name="soc_url[]"]{grid-area:u}
  .soc-row .soc-del{grid-area:d}
}

.pretty-test{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap;margin-top:1rem;
  padding-top:.9rem;border-top:1px solid var(--line)}

/* ------------------------------------------------------- office visits */
.ov-who,.ov-opts{display:flex;gap:.9rem;flex-wrap:wrap}
.ov-radio{display:inline-flex;align-items:center;gap:.4rem;font-size:.9rem;cursor:pointer}
.ov-shot{max-width:220px;border-radius:8px;border:1px solid var(--line);display:block}

.ov-list{display:grid;gap:.9rem}
.ov-item{display:flex;gap:.9rem;padding:.8rem;border:1px solid var(--line);border-radius:12px;
  background:var(--surface)}
.ov-when{flex:0 0 130px;font-size:.82rem;color:var(--muted);font-weight:600}
.ov-body{flex:1;min-width:0}
.ov-reason{font-weight:700;margin-bottom:.3rem}
.ov-body p{margin:.2rem 0 .5rem;font-size:.92rem}
.ov-offer{background:var(--brand-light);border-radius:9px;padding:.5rem .7rem;font-size:.9rem;
  margin:.4rem 0;display:flex;gap:.5rem;flex-wrap:wrap;align-items:baseline}
.ov-offer.dead{background:var(--surface-2);color:var(--muted);text-decoration:line-through}
.ov-until{font-size:.8rem;color:var(--muted);margin-left:auto;text-decoration:none}
.ov-staff{font-size:.82rem;color:var(--muted);margin-top:.4rem}
@media (max-width:600px){
  .ov-item{flex-direction:column;gap:.35rem}
  .ov-when{flex:0 0 auto}
  .ov-shot{max-width:100%}
}

/* -------------------------------------------------------- the chat panel */
.chat-split{align-items:start}
.chat-list{max-height:70vh;overflow-y:auto}
.chat-row{
  display:block;padding:.7rem .9rem;border-bottom:1px solid var(--line-2);
  color:inherit;text-decoration:none;border-left:3px solid transparent;
}
.chat-row:hover{background:var(--surface-2);text-decoration:none}
.chat-row.on{background:var(--brand-light);border-left-color:var(--brand)}
.chat-row.hot{border-left-color:var(--warn)}
.chat-row-h{display:flex;align-items:baseline;gap:.6rem}
.chat-row-h strong{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-row-h time{font-size:.76rem;color:var(--muted);flex:0 0 auto}
.chat-row-m{display:flex;gap:.3rem;flex-wrap:wrap;margin:.3rem 0}
.chat-row-s{font-size:.78rem;color:var(--muted)}
.chip.warn{background:#fef3c7;color:#92400e}
.chip.muted{background:var(--surface-2);color:var(--muted)}

.chat-who{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:.5rem}
.chat-who div{display:flex;flex-direction:column;gap:.1rem}
.chat-who span{font-size:.72rem;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:700}
.chat-who strong{font-size:.88rem;overflow-wrap:break-word}

.chat-thread{max-height:52vh;overflow-y:auto;display:flex;flex-direction:column;gap:.6rem;
  background:var(--surface-2)}
.cm{max-width:84%;padding:.55rem .8rem;border-radius:12px;font-size:.9rem}
/* pre-wrap alone keeps the line breaks. The page used to call nl2br() as
   well, so every newline was drawn twice and each bot answer had a hole
   through the middle of it. */
.cm-b{white-space:pre-wrap;overflow-wrap:break-word}
.cm-m{font-size:.7rem;color:var(--muted);margin-top:.25rem}
.cm-visitor{background:var(--brand);color:#fff;align-self:flex-end}
.cm-visitor .cm-m{color:rgba(255,255,255,.75)}
.cm-bot{background:var(--surface);border:1px solid var(--line);align-self:flex-start}
.cm-staff{background:#fffbeb;border:1px solid #fde68a;align-self:flex-start}
@media (max-width:900px){
  .chat-split{grid-template-columns:1fr}
  .chat-list{max-height:40vh}
  .cm{max-width:92%}
}

/* The website discount: an amount and its unit, side by side. */
.pl-disc{display:flex;gap:.3rem}
.pl-disc input{flex:1;min-width:0}
.pl-disc select{width:64px;flex:0 0 64px;padding:.4rem .3rem;border:1px solid var(--line);
  border-radius:8px;background:var(--surface);color:var(--text);font:inherit;font-size:.85rem}

/* A class that sets display beats the browser's own [hidden] rule, so an
   element told to hide stays on screen. One line here rather than one per
   component, because the next one would be found the same slow way. */
[hidden]{display:none !important}

/* ------------------------------------------------- the conversations screen
   Three columns, and the widths are the argument. The list is a way of
   choosing a conversation, so it is narrow. The conversation is where the
   work happens, so it takes the room that is left. Who the visitor is sits
   beside the messages rather than above them, because it is read *while*
   replying — above the thread it would push the messages off the screen,
   which is exactly what it used to do. */
.chat-3{
  display:grid;gap:1rem;align-items:start;
  grid-template-columns:minmax(220px,16rem) minmax(0,1fr) minmax(230px,17rem);
}
.chat-3 > .card{margin:0;min-width:0}
.chat-col-talk{display:flex;flex-direction:column}

.chat-filter{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;width:100%}
.chat-filter input[type=search]{flex:1;min-width:11rem}

.chat-head-acts{display:flex;gap:.3rem;margin-left:auto}

/* The dot that says the panel is still listening. Green when the last check
   came back, grey when it did not — which is how somebody finds out the
   office internet has gone rather than that nobody is writing to them. */
.chat-live{
  font-size:.6rem;color:var(--muted);margin-left:.5rem;line-height:1;
  transition:color .3s;
}
.chat-live.on{color:#16a34a}

.chat-thread{min-height:22rem;max-height:56vh}

/* Nothing said yet, and something being said. */
.cm-typing .cm-b{display:flex;gap:.25rem;padding:.15rem 0}
.cm-typing i{
  width:.42rem;height:.42rem;border-radius:50%;background:var(--muted);
  animation:cmDot 1.2s infinite ease-in-out;
}
.cm-typing i:nth-child(2){animation-delay:.15s}
.cm-typing i:nth-child(3){animation-delay:.3s}
@keyframes cmDot{0%,60%,100%{opacity:.25;transform:translateY(0)}30%{opacity:1;transform:translateY(-2px)}}
@media (prefers-reduced-motion:reduce){
  .cm-typing i{animation:none;opacity:.5}
}

/* What came with a message. A picture is shown, a document is named: turning
   both into the same grey rectangle means somebody has to open each one to
   find out which is the photo they asked for. */
.cm-img{display:block;margin-top:.4rem;border-radius:9px;overflow:hidden;max-width:16rem}
.cm-img img{display:block;width:100%;height:auto}
.cm-audio{display:block;margin-top:.4rem;width:100%;max-width:16rem}
.cm-file{
  display:flex;align-items:center;gap:.5rem;margin-top:.4rem;padding:.45rem .6rem;
  border:1px solid var(--line);border-radius:9px;background:var(--surface);
  color:inherit;text-decoration:none;
}
.cm-file-i{font-size:1.1rem;flex:0 0 auto}
.cm-file-t{display:flex;flex-direction:column;min-width:0}
.cm-file-t b{font-size:.82rem;overflow-wrap:anywhere}
.cm-file-t small{font-size:.7rem;color:var(--muted)}

/* Writing a reply. */
.chat-compose{flex-direction:column;align-items:stretch;gap:.5rem}
.chat-compose form{width:100%}
.chat-tools{display:flex;gap:.4rem;flex-wrap:wrap;align-items:center;margin-bottom:.5rem}
.chat-tools label.btn{cursor:pointer;margin:0}
.chat-file-name{font-size:.76rem;color:var(--muted);overflow-wrap:anywhere}
.chat-send{display:flex;gap:.5rem;align-items:flex-end}
.chat-send textarea{flex:1;min-width:0;resize:vertical}
.chat-compose .hint{margin:.4rem 0 0}

/* A wider dropdown, for things with two lines in them. */
.dropdown.wide{width:min(21rem,86vw)}
.dropdown.wide .canned{display:flex;flex-direction:column;gap:.1rem;align-items:flex-start}
.dropdown.wide .canned strong{font-size:.85rem}
.dropdown.wide .canned small{font-size:.74rem;color:var(--muted)}
.dropdown .dd-more{font-size:.78rem;color:var(--brand);border-top:1px solid var(--line)}

.emoji-pop{padding-bottom:.4rem}
.emoji-tabs{display:flex;gap:.2rem;padding:.3rem .5rem;border-bottom:1px solid var(--line);
  overflow-x:auto}
.emoji-tabs button{
  border:0;background:none;font:inherit;font-size:.76rem;color:var(--muted);
  padding:.25rem .45rem;border-radius:6px;cursor:pointer;white-space:nowrap;
}
.emoji-tabs button.on{background:var(--surface-2);color:var(--text);font-weight:600}
.emoji-grid{
  display:grid;grid-template-columns:repeat(8,1fr);gap:.1rem;
  padding:.4rem .5rem;max-height:12rem;overflow-y:auto;
}
.emoji-grid button{
  border:0;background:none;font-size:1.15rem;line-height:1;padding:.3rem;
  border-radius:6px;cursor:pointer;
}
.emoji-grid button:hover{background:var(--surface-2)}

/* ------------------------------------------------------------ visitor info
   A label and a value on one line, the way a form reads when it is finished
   rather than when it is being filled in. */
/* Label on the left, value on the right — but a value that will not fit
   beside its label drops onto its own line rather than pushing out past
   the edge of the panel, which is what a long date and a full address
   were doing. */
.vi{margin:0;font-size:.84rem}
.vi > div{
  display:flex;justify-content:space-between;align-items:baseline;
  gap:.5rem;padding:.28rem 0;flex-wrap:wrap;
}
.vi dt{color:var(--muted);flex:0 0 auto;margin:0;white-space:nowrap}
.vi dd{
  margin:0;text-align:right;overflow-wrap:anywhere;
  min-width:0;flex:1 1 auto;
}
.vi-sep{border-top:1px solid var(--line);margin-top:.5rem;padding-top:.4rem}
.vi-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.78rem}
.vi-good{color:#15803d;font-weight:600}
.vi-bad{color:#b91c1c;font-weight:600}
.vi-box{
  margin-top:.7rem;padding:.55rem .65rem;border:1px solid var(--line);
  border-radius:9px;background:var(--surface-2);font-size:.82rem;
}
.vi-box div + div{margin-top:.3rem}
.vi-box b{font-weight:600}
.vi-i{margin-right:.25rem}

@media (max-width:1200px){
  /* Who they are drops under the conversation before the list does: the list
     is how you get anywhere, the details are worth scrolling for. */
  .chat-3{grid-template-columns:minmax(200px,14rem) minmax(0,1fr)}
  .chat-col-who{grid-column:1 / -1}
  .vi{columns:2;column-gap:1.4rem}
  .vi > div{break-inside:avoid}
}
@media (max-width:860px){
  .chat-3{grid-template-columns:1fr}
  .chat-list{max-height:16rem}
  .chat-thread{max-height:60vh}
  .cm{max-width:92%}
  .vi{columns:1}
  .emoji-grid{grid-template-columns:repeat(7,1fr)}
}

/* The example address on the Permalinks screen. It is a whole URL and would
   otherwise push the table — and with it the page — sideways. */
.pl-eg{max-width:22rem}
.pl-eg a{overflow-wrap:anywhere}
.pl-eg a + br + a{margin-top:.15rem;display:inline-block}
.pl-fmt{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap}
.pl-fmt select{padding:.35rem .5rem;border:1px solid var(--line);border-radius:8px;font:inherit;background:var(--card);color:inherit}

/* The pill that holds a base word, with its leading slash outside the box so
   nobody types a second one. */
.input-pre{display:flex;align-items:center;gap:.25rem}
.input-pre > span{color:var(--muted);font-family:ui-monospace,Menlo,Consolas,monospace}
.input-pre input{flex:1;min-width:0}
.pl-slug{margin:0}
.pl-slug .input-pre input{min-width:8rem}

/* ------------------------------------------------------------ the trail
   Under the page title: Dashboard / Users / Add a user, each part but the
   last a link back to it. Small and quiet — it is a way back, not a heading. */
.crumbs{
  display:flex;align-items:center;gap:.3rem;flex-wrap:wrap;
  margin-top:.25rem;font-size:.78rem;line-height:1.5;
}
.crumbs a{color:var(--muted);text-decoration:none}
.crumbs a:hover{color:var(--brand);text-decoration:underline}
.crumbs span{color:var(--text-2);font-weight:600}
.crumbs i{color:var(--line);font-style:normal;user-select:none}

/* The brand is a link now, so it must not pick up link colours. */
a.brand{text-decoration:none;color:inherit}
a.brand:hover{text-decoration:none}

@media (max-width:640px){
  /* On a phone the middle of a long trail is the part worth losing: the way
     home and where you are standing are what somebody actually needs. */
  .crumbs{font-size:.74rem}
  .crumbs a:not(:first-child),
  .crumbs i:not(:last-of-type){display:none}
}

/* ------------------------------------------------- licence keys in prose
   A key that shares a face with the sentence around it disappears into it,
   and people copy half of one. Anywhere a key is printed inside text — a
   notification, a support reply, a licence screen — it gets a box of its own.
   The box wraps rather than clipping: on a phone a key is wider than the
   column, and a key cut off at the edge is worse than one on two lines. */
.lickey{
  display:inline-block;font-family:ui-monospace,SFMono-Regular,Consolas,"Liberation Mono",monospace;
  font-size:.94em;font-weight:700;letter-spacing:.06em;
  background:var(--surface-2);border:1px dashed var(--line);border-radius:7px;
  padding:.1em .5em;margin:.1em 0;color:var(--text);
  word-break:break-all;white-space:normal;
}
.notif-full .lickey{font-size:1.02rem;padding:.25em .7em;background:var(--brand-light);
  border-color:var(--brand);color:var(--brand-ink,var(--text))}

/* --------------------------------------------------- finding one addon
   Thirty-odd cards is more than anybody scrolls through looking for one.
   The box filters what is already on the page as you type, so there is no
   round trip to wait for. */
.addon-find{
  display:flex;align-items:center;gap:.5rem;margin:0 0 1.1rem;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:.15rem .8rem;box-shadow:var(--shadow);
}
.addon-find .af-ico{opacity:.5;font-size:.95rem;line-height:1}
.addon-find input{
  flex:1;min-width:0;border:0;background:none;padding:.62rem 0;
  font:inherit;font-size:.92rem;color:var(--text);
}
.addon-find input:focus{outline:0}
.addon-find input::-webkit-search-cancel-button{display:none}
.addon-find .af-clear{
  border:0;background:none;cursor:pointer;font-size:1.1rem;line-height:1;
  color:var(--muted);padding:.2rem .35rem;border-radius:6px;
}
.addon-find .af-clear:hover{background:var(--surface-2);color:var(--text)}
.addon-find .af-count{font-size:.78rem;color:var(--muted);white-space:nowrap}

/* ==================================================== test report creator
   The writing screens. The printed page carries its own stylesheet — it is a
   different document with a different job, and sharing one with the panel is
   how a report ends up with a sidebar's margins on it. */

/* Picking which kind of report to write. */
.tr-pick{display:grid;grid-template-columns:repeat(auto-fill,minmax(15rem,1fr));gap:.6rem}
.tr-pick-i{
  display:flex;align-items:center;gap:.7rem;padding:.7rem .8rem;
  border:1px solid var(--line);border-radius:12px;background:var(--card);
  color:inherit;text-decoration:none;transition:border-color .15s,transform .15s;
}
.tr-pick-i:hover{border-color:var(--brand);transform:translateY(-1px);text-decoration:none}
.tr-pick-ico{font-size:1.5rem;line-height:1}
.tr-pick-t strong{display:block;font-size:.92rem;line-height:1.3}
.tr-pick-t small{display:block;font-size:.74rem;color:var(--muted);margin-top:.1rem}

/* One row of tabs across the design and phrase screens. */
.tr-tabs{display:flex;gap:.3rem;flex-wrap:wrap;margin-bottom:1rem}
.tr-tabs a{
  padding:.4rem .8rem;border-radius:999px;border:1px solid var(--line);
  background:var(--card);color:var(--muted);font-size:.85rem;font-weight:600;
  text-decoration:none;white-space:nowrap;
}
.tr-tabs a:hover{border-color:var(--brand);color:var(--brand);text-decoration:none}
.tr-tabs a.on{background:var(--brand);border-color:var(--brand);color:#fff}

/* ------------------------------------------------------------ audiogram */
.tr-audio{display:grid;grid-template-columns:repeat(auto-fit,minmax(19rem,1fr));gap:1rem}
.tr-chart{margin:0;border:1px solid var(--line);border-radius:12px;padding:.6rem;background:var(--card)}
.tr-chart figcaption{
  display:flex;justify-content:space-between;align-items:baseline;gap:.5rem;
  font-weight:700;margin-bottom:.35rem;
}
.tr-chart .tr-pta{font-weight:600;font-size:.8rem;color:var(--muted);text-align:right}
.tr-chart-r figcaption span{color:#c62828}
.tr-chart-l figcaption span{color:#1565c0}
.tr-chart canvas{width:100%;height:auto;display:block;cursor:crosshair;border-radius:8px}

.tr-legend{display:flex;gap:1rem;flex-wrap:wrap;align-items:center;margin:.7rem 0 .3rem;font-size:.8rem;color:var(--muted)}
.tr-legend i{display:inline-block;width:.85rem;height:.85rem;border-radius:3px;vertical-align:-2px;margin-right:.2rem}
.tr-legend i.m-x{background:#c62828}
.tr-legend i.m-o{background:#1565c0}
.tr-legend i.m-b{background:#0f766e}

.tr-thr table{min-width:44rem}
.tr-thr input.tr-db{width:100%;min-width:3.2rem;text-align:center;padding:.3rem .2rem}
.tr-rows td input,.tr-rows td select{width:100%}

/* ------------------------------------------------------------- findings */
.tr-boxes{display:grid;gap:.9rem}
.tr-box{position:relative}
.tr-box-h{display:flex;align-items:center;gap:.6rem;margin-bottom:.25rem;flex-wrap:wrap}
.tr-box-h label[for]{font-weight:700;font-size:.82rem;letter-spacing:.03em;text-transform:uppercase}
.tr-box-print{margin-left:auto;font-size:.8rem}
.tr-box textarea{width:100%}

/* The suggestion list sits over whatever is under the box, so a long list
   does not push the rest of the form down while somebody is typing. */
.tr-sug-list{
  position:absolute;left:0;right:0;z-index:30;margin-top:-.2rem;
  background:var(--card);border:1px solid var(--line);border-radius:10px;
  box-shadow:0 14px 34px rgba(15,23,42,.16);overflow:hidden;max-height:14rem;overflow-y:auto;
}
.tr-sug-i{
  display:block;width:100%;text-align:left;border:0;background:none;
  padding:.45rem .7rem;font:inherit;font-size:.86rem;color:inherit;cursor:pointer;
}
.tr-sug-i:hover,.tr-sug-i.on{background:var(--surface-2, #f1f5f9);color:var(--brand)}

/* ------------------------------------------------------------- pictures */
.tr-bg-row{display:flex;gap:1rem;flex-wrap:wrap;align-items:center;margin-bottom:.8rem;font-size:.85rem}
.tr-pics{display:grid;grid-template-columns:repeat(auto-fill,minmax(13rem,1fr));gap:.8rem}
.tr-pic{
  margin:0;border:1px solid var(--line);border-radius:12px;overflow:hidden;
  background:var(--card);display:flex;flex-direction:column;
}
.tr-pic-img{
  /* A chequerboard, so a picture whose background really was removed looks
     removed rather than looking white on white. */
  background:
    linear-gradient(45deg,#e2e8f0 25%,transparent 25%,transparent 75%,#e2e8f0 75%) 0 0/16px 16px,
    linear-gradient(45deg,#e2e8f0 25%,#f8fafc 25%,#f8fafc 75%,#e2e8f0 75%) 8px 8px/16px 16px;
  display:grid;place-items:center;min-height:8.5rem;padding:.4rem;
}
.tr-pic-img img{max-width:100%;max-height:11rem;display:block}
.tr-pic figcaption{padding:.5rem;display:grid;gap:.4rem}
.tr-pic figcaption input[type=text]{width:100%;font-size:.82rem}
.tr-pic-w{display:flex;align-items:center;gap:.4rem;font-size:.76rem;color:var(--muted)}
.tr-pic-w input[type=range]{flex:1;min-width:0}
.tr-pic-w b{min-width:2.6rem;text-align:right;font-variant-numeric:tabular-nums}
.tr-pic-x{align-self:start}

.tr-pic-new{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.3rem;
  min-height:12rem;border-style:dashed;color:var(--muted);font-size:.82rem;cursor:pointer;
}
.tr-pic-new:hover{border-color:var(--brand);color:var(--brand)}
.tr-pic-plus{font-size:1.9rem;line-height:1}

@media (max-width:760px){
  .tr-audio{grid-template-columns:1fr}
  .tr-box-print{margin-left:0}
}

/* ------------------------------------------------- message templates
   Each template is a box with its own footer: what it will cost to send, and
   the words it may use. The cost line is the point of the whole screen — a
   text is 160 characters in English and 70 the moment one Bengali letter
   appears, and a reminder that quietly became three messages is a bill
   nobody can account for. */
.tpl-group{
  margin:1.4rem 0 .6rem;font-size:.78rem;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted);
}
.tpl-group:first-of-type{margin-top:.2rem}
.tpl{
  border:1px solid var(--line);border-radius:12px;padding:.75rem .85rem;
  margin-bottom:.7rem;background:var(--card);
}
.tpl-h{display:flex;align-items:center;gap:.5rem;margin-bottom:.35rem}
.tpl-h label{font-weight:700;font-size:.88rem}
.tpl textarea{width:100%;font-family:inherit}
.tpl-f{
  display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;
  margin-top:.4rem;font-size:.76rem;
}
.tpl-count{color:var(--muted);font-variant-numeric:tabular-nums}
.tpl-vars{display:flex;gap:.25rem;flex-wrap:wrap;margin-left:auto}
.tpl-var{
  border:1px solid var(--line);background:var(--surface-2);color:var(--muted);
  border-radius:999px;padding:.1rem .45rem;font:inherit;font-size:.72rem;
  cursor:pointer;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
.tpl-var:hover{border-color:var(--brand);color:var(--brand)}

/* The QR on an invoice. Small, in the corner, and it prints — the whole point
   of it is on paper. */
.inv-qr{margin-top:.6rem;text-align:right}
.inv-qr img{display:inline-block;background:#fff}
.inv-qr small{display:block;font-size:.68rem;color:var(--muted);max-width:120px;margin-left:auto}

/* ------------------------------------------------------- e-mail & message templates (round L)
   The list of templates, the editor beside it, and the preview frame. Wide
   enough to read a subject line, and it folds to one card per row on a phone
   rather than scrolling sideways. */
table.tbl.mt-tbl{min-width:640px}
.mt-tbl tr.mt-group td{background:var(--surface-2);font-size:.72rem;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted);padding:.5rem .8rem}
.mt-tbl tr.mt-off td{opacity:.6}
.mt-tbl .mt-subj{max-width:280px;overflow-wrap:anywhere}
.mt-tbl td.actions,.mt-tbl th.actions{min-width:0}
.mt-state{display:flex;gap:.3rem;flex-wrap:wrap;align-items:center}
.mt-vars{display:flex;flex-wrap:wrap;gap:.3rem;align-items:center;margin-top:.7rem}
.mt-vars code{font-size:.74rem;background:var(--surface-2);border:1px solid var(--line);border-radius:6px;padding:.05rem .35rem}
.mt-layout{display:grid;gap:.9rem}
.mt-lab{display:block;font-size:.72rem;color:var(--muted);font-weight:600;margin-bottom:.45rem}
.mt-preview{width:100%;height:640px;border:1px solid var(--line);border-radius:12px;background:#f1f5f9;display:block}
@media (max-width:640px){.mt-preview{height:500px}}
/* The first line of a message, so the list says what each one actually sends
   rather than only what it is called. */
.tpl-peek{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.75rem;opacity:.85;
  overflow-wrap:anywhere;white-space:normal}

/* An addon that is sold for this script but is not installed here. The same
   card as the rest, so the wall reads as one list, with a dashed edge to say
   there is nothing of it on this server yet. */
.mod.mod-off-site{border-style:dashed}
.mod.mod-off-site .mbody h3{color:var(--text-2)}

/* ------------------------------------------------- the commission sheet
   A document that leaves the building with the centre's name on it, so it
   is laid out for paper first: black on white, no shadows, no rounded
   cards, and a totals block that cannot drift away from its table. */
.cs-sheet{max-width:860px;margin:0 auto;color:#111;font-size:.9rem}
.cs-head{display:flex;justify-content:space-between;gap:1.4rem;flex-wrap:wrap;
  padding-bottom:.9rem;border-bottom:2px solid var(--line)}
.cs-brand{display:flex;gap:.9rem;align-items:flex-start;min-width:0}
.cs-logo{max-height:56px;width:auto}
.cs-head h1{font-size:1.15rem;margin:0 0 .15rem}
.cs-title{text-align:right}
.cs-title h2{font-size:1.05rem;margin:0 0 .15rem;text-transform:uppercase;letter-spacing:.06em}
.cs-sub{font-size:.78rem;color:var(--muted);line-height:1.5}
.cs-lab{display:block;font-size:.68rem;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);font-weight:700;margin-bottom:.1rem}
.cs-to{display:flex;justify-content:space-between;gap:1.4rem;flex-wrap:wrap;margin:1rem 0 1.1rem}
.cs-empty{padding:2rem 0;text-align:center;color:var(--muted)}
.cs-tbl{width:100%;border-collapse:collapse;font-size:.84rem}
.cs-tbl th{text-align:left;padding:.5rem .6rem;border-bottom:1.5px solid var(--line);
  font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.cs-tbl td{padding:.5rem .6rem;border-bottom:1px solid var(--line-2);vertical-align:top}
.cs-tbl tfoot td{border-bottom:0;padding:.35rem .6rem}
.cs-tbl tfoot tr.cs-total td{font-weight:800;border-top:1.5px solid var(--line);font-size:.92rem}
.cs-tbl .right{text-align:right}
.cs-note{margin:1.2rem 0 0;font-size:.8rem;color:var(--text-2)}
.cs-sign{display:flex;justify-content:space-between;gap:2rem;margin-top:3rem;flex-wrap:wrap}
.cs-sign > div{flex:1;min-width:180px;text-align:center;font-size:.8rem;color:var(--text-2)}
.cs-sign span{display:block;border-top:1px solid var(--line);margin-bottom:.35rem}
.cs-foot{margin-top:1.4rem;text-align:center;font-size:.74rem;color:var(--muted)}
@media print{
  .cs-sheet{max-width:100%;font-size:11pt}
  .cs-tbl{font-size:10pt}
  .cs-tbl tr{page-break-inside:avoid}
}
@media (max-width:640px){
  .cs-title{text-align:left}
  .cs-to > .right{text-align:left}
}

/* ------------------------------------------------- product verification
   The public page is one card in the middle of the screen with one box on
   it, because that is the whole job. The answer below it has to be
   readable at a glance and at arm's length, on a phone, by somebody who is
   already worried. */
.vp-sec{padding:2.4rem 0}
.vp-card{
  max-width:560px;margin:0 auto;text-align:center;
  background:var(--surface);border:1px solid var(--line);border-radius:18px;
  padding:2rem 1.6rem;box-shadow:var(--shadow);
}
.vp-ico{font-size:2.6rem;line-height:1}
.vp-card h1{font-size:1.5rem;margin:.5rem 0 .5rem}
.vp-form{display:flex;gap:.5rem;margin:1.2rem 0 .4rem;flex-wrap:wrap}
.vp-input{
  flex:1;min-width:200px;padding:.75rem .9rem;border:1px solid var(--line);
  border-radius:12px;font:inherit;font-size:1.02rem;letter-spacing:.06em;
  text-align:center;text-transform:uppercase;background:var(--surface);color:var(--text);
}
.vp-input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-light)}
.vp-result{
  display:flex;gap:.9rem;align-items:flex-start;text-align:left;
  margin:1.2rem 0 .4rem;padding:1rem 1.1rem;border-radius:14px;border:1px solid var(--line);
}
.vp-result.ok{border-color:rgba(22,163,74,.4);background:rgba(22,163,74,.07)}
.vp-result.bad{border-color:rgba(220,38,38,.35);background:rgba(220,38,38,.06)}
.vp-mark{
  flex:0 0 40px;width:40px;height:40px;border-radius:50%;display:grid;place-items:center;
  font-size:1.3rem;font-weight:800;color:#fff;background:var(--muted);
}
.vp-result.ok .vp-mark{background:var(--ok)}
.vp-result.bad .vp-mark{background:var(--danger)}
.vp-result strong{display:block;font-size:1.05rem}
.vp-name{font-size:.95rem;font-weight:600;margin-top:.15rem}
.vp-lines{display:grid;grid-template-columns:auto 1fr;gap:.15rem .8rem;margin:.6rem 0 0;font-size:.85rem}
.vp-lines dt{color:var(--muted)}
.vp-lines dd{margin:0;font-weight:600}
.vp-q{margin-top:.6rem;font-size:.78rem;color:var(--muted)}
.vp-q code{overflow-wrap:anywhere}
.vp-help{font-size:.8rem;color:var(--muted);margin:1.2rem 0 1rem;line-height:1.7}
@media (max-width:520px){
  .vp-card{padding:1.5rem 1.1rem}
  .vp-lines{grid-template-columns:1fr}
  .vp-lines dt{margin-top:.35rem}
}

/* The name of the message being edited, on a line of its own so it can be
   translated like any other heading. */
.tpl-name{margin:0 0 .3rem;font-size:.98rem;font-weight:700}
