/* GoodySMS - the whole app's stylesheet. See DESIGN.md for the reasoning.
   No build step: this file is served as written. */

:root{
  --navy-900:#060F2E;
  --navy-800:#0B1B48;
  --blue-500:#2F6BFF;
  --blue-400:#5A8CFF;
  --blue-300:#8FB0FF;
  --white:#FFFFFF;
  --text:#E8EDFB;
  --muted:#93A3CC;
  --line:rgba(143,176,255,.16);
  --card:rgba(255,255,255,.045);
  --ok:#4ADE80;
  --warn:#FBBF24;
  --danger:#FF7878;
  --shadow:0 24px 70px -30px rgba(0,0,0,.85);
  --radius:14px;
}

*{box-sizing:border-box}
html,body{margin:0;padding:0;overflow-x:hidden}
body{
  min-height:100svh;
  background:var(--navy-900);
  color:var(--text);
  font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  font-size:.95rem;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  display:flex;
  flex-direction:column;
}
a{color:var(--blue-300)}

/* ambient background, fixed so it never scrolls with content */
.grid{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:linear-gradient(var(--line) 1px,transparent 1px),linear-gradient(90deg,var(--line) 1px,transparent 1px);
  background-size:64px 64px;
  mask-image:radial-gradient(ellipse 70% 60% at 50% 0%,#000 10%,transparent 70%);
  -webkit-mask-image:radial-gradient(ellipse 70% 60% at 50% 0%,#000 10%,transparent 70%);
  opacity:.45;
}

/* ---- chrome ---------------------------------------------------------- */
.topbar{
  position:relative;z-index:2;border-bottom:1px solid var(--line);
  background:rgba(6,15,46,.85);backdrop-filter:blur(10px);
}
/* max() with env(safe-area-inset-*) keeps the topbar clear of the iPhone
   notch/Dynamic Island (top) and a landscape notch (left/right) without
   losing the normal padding on a device with no inset at all. */
.topbar-inner{
  max-width:1100px;margin:0 auto;display:flex;align-items:center;gap:16px;
  padding-top:max(12px, env(safe-area-inset-top));
  padding-bottom:12px;
  padding-left:max(16px, env(safe-area-inset-left));
  padding-right:max(16px, env(safe-area-inset-right));
}
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:1.1rem;letter-spacing:-.03em;color:var(--white);text-decoration:none;flex:none}
.brand span{color:var(--blue-500)}
.brand img{width:30px;height:30px}
.nav{display:flex;gap:4px;margin-left:auto;align-items:center;flex-wrap:wrap}
.nav a{
  padding:7px 12px;border-radius:9px;font-size:.88rem;font-weight:500;
  color:var(--muted);text-decoration:none;transition:color .15s,background .15s;
  white-space:nowrap;
}
.nav a:hover{color:var(--text);background:var(--card)}
.nav a.active{color:var(--white);background:var(--card)}

/* hamburger toggle - hidden until the mobile breakpoint below shows it */
.nav-toggle{
  display:none;flex:none;background:transparent;border:1px solid var(--line);border-radius:9px;
  width:38px;height:38px;align-items:center;justify-content:center;cursor:pointer;color:var(--text);
}
.nav-toggle svg{width:19px;height:19px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round}

/* wallet chip in the header - the number a customer checks most, so it stays
   visible even when the rest of the nav collapses on a phone */
.chip{
  display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border-radius:999px;
  border:1px solid var(--line);background:var(--card);font-size:.87rem;font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--text);text-decoration:none;white-space:nowrap;
  flex:none;
}
.chip small{color:var(--muted);font-weight:500;font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}

main{
  position:relative;z-index:1;flex:1;width:100%;max-width:1100px;margin:0 auto;
  padding-top:28px;padding-bottom:48px;
  padding-left:max(16px, env(safe-area-inset-left));
  padding-right:max(16px, env(safe-area-inset-right));
}

footer{
  position:relative;z-index:1;border-top:1px solid var(--line);
  text-align:center;font-size:.82rem;color:#6F82B4;
  padding-top:22px;
  padding-bottom:max(22px, env(safe-area-inset-bottom));
  padding-left:max(16px, env(safe-area-inset-left));
  padding-right:max(16px, env(safe-area-inset-right));
}
footer a{color:var(--blue-300);text-decoration:none}
footer a:hover{text-decoration:underline}

/* ---- type ------------------------------------------------------------ */
h1{margin:0 0 6px;font-size:1.6rem;font-weight:700;letter-spacing:-.03em;color:var(--white)}
h2{margin:0 0 14px;font-size:1.05rem;font-weight:600;color:var(--white)}
.lead{margin:0 0 24px;color:var(--muted)}
.label{font-size:.8rem;font-weight:500;color:var(--muted)}
.money{font-weight:600;font-variant-numeric:tabular-nums}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}

/* ---- cards ----------------------------------------------------------- */
.card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:18px;box-shadow:var(--shadow);
}
.card + .card{margin-top:16px}
.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}
/* Fixed at 3 columns (not auto-fit) above the breakpoint below: auto-fit on
   an exactly-3-item row settles at 2 columns somewhere in the middle of the
   viewport range and orphans the 3rd card alone on its own row. Below the
   breakpoint it stacks to one column outright instead of ever hitting that
   awkward 2-then-1 state. */
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.stat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:12px}
.stat-grid > *{min-width:0;overflow:hidden}

/* big number on the dashboard */
.stat b{display:block;font-size:1.7rem;font-weight:700;color:var(--white);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.stat small{display:block;margin-top:2px;font-size:.78rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}

/* the wallet balance card gets its own treatment - it's the number a
   customer checks first, and the one action ("add funds") worth surfacing
   without a trip to Quick actions below */
.stat-balance{
  background:linear-gradient(160deg, rgba(47,107,255,.14), rgba(255,255,255,.045));
  border-color:rgba(47,107,255,.3);
}
.stat-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:10px}
.stat-label{font-size:.78rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);padding-top:7px}
.stat-head-actions{display:flex;flex-direction:column;align-items:flex-end;gap:8px}
.stat-action{
  display:inline-flex;align-items:center;gap:5px;flex:none;white-space:nowrap;
  padding:6px 12px;border-radius:999px;font-size:.76rem;font-weight:600;text-decoration:none;
  background:rgba(47,107,255,.16);border:1px solid rgba(47,107,255,.4);color:var(--blue-300);
  transition:background .15s,transform .15s;
}
.stat-action:hover{background:rgba(47,107,255,.28);transform:translateY(-1px)}
.stat-action svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;flex:none}

/* "Transaction history" quick link under Add funds in the balance card */
.stat-link{
  display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  font-size:.8rem;font-weight:500;color:var(--blue-300);text-decoration:none;
}
.stat-link:hover{color:var(--text)}
.stat-link svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;flex:none}
.stat-link-chevron{width:11px!important;height:11px!important;opacity:.7}

/* ---- icon circles (dashboard stats, quick actions, order rows) ------- */
.icon-circle{
  display:flex;align-items:center;justify-content:center;flex:none;
  width:38px;height:38px;border-radius:50%;
}
.icon-circle svg{width:18px;height:18px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.icon-circle.ic-blue{background:var(--blue-500)}
.icon-circle.ic-purple{background:#7C5CFF}
.icon-circle.ic-green{background:var(--ok)}
.icon-circle.ic-orange{background:#FF9F43}
.icon-circle.ic-teal{background:#2AB6D9}
.icon-circle.ic-muted{background:rgba(255,255,255,.08)}

/* stat card with a leading icon circle, used on the dashboard in place of
   the plain label/number stack when an icon adds scannability. Stacked
   (icon above number/label), not side-by-side - three of these sit in a
   row on a 393px phone and a horizontal layout has no room left for the
   text once the circle and its gap are accounted for. */
.stat-icon{display:flex;flex-direction:column;align-items:flex-start;gap:9px}
.stat-icon .stat-icon-text{min-width:0;width:100%}
.stat-icon b{display:block;font-size:1.15rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stat-icon small{display:block;margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---- quick actions grid (dashboard.php) ------------------------------- */
.qa-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:4px}
.qa-tile{
  display:flex;align-items:center;gap:10px;padding:13px 14px;border-radius:13px;
  border:1px solid var(--line);background:rgba(255,255,255,.03);text-decoration:none;
  color:var(--text);transition:border-color .15s,background .15s,transform .15s;
}
.qa-tile:hover{border-color:rgba(143,176,255,.35);transform:translateY(-1px)}
.qa-tile-primary{
  background:linear-gradient(180deg,var(--blue-400),var(--blue-500));border:0;color:#fff;
  box-shadow:0 10px 26px -10px rgba(47,107,255,.85);
}
.qa-tile-label{flex:1;min-width:0;font-weight:600;font-size:.92rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.qa-tile-chevron{width:16px;height:16px;flex:none;stroke:currentColor;opacity:.6;fill:none;stroke-width:2;stroke-linecap:round}
@media (max-width:420px){
  .qa-tile{padding:11px 12px}
  .qa-tile-label{font-size:.86rem}
  .icon-circle{width:32px;height:32px}
  .icon-circle svg{width:15px;height:15px}
}

/* ---- floating Telegram support widget (every page, includes/footer.php) */
.tg-fab{
  position:fixed;z-index:4;display:flex;align-items:center;justify-content:center;
  width:52px;height:52px;border-radius:50%;background:#2AB6D9;color:#fff;
  box-shadow:0 14px 30px -10px rgba(42,182,217,.65);
  bottom:max(20px, calc(env(safe-area-inset-bottom) + 14px));
  right:max(16px, calc(env(safe-area-inset-right) + 10px));
  transition:transform .15s,box-shadow .15s;
}
.tg-fab:hover{transform:translateY(-2px) scale(1.04);box-shadow:0 18px 36px -10px rgba(42,182,217,.8)}
.tg-fab svg{width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* ---- Telegram support banner ------------------------------------------ */
.tg-banner{
  display:flex;align-items:center;gap:14px;padding:16px 18px;border-radius:var(--radius);
  border:1px solid rgba(42,182,217,.35);background:rgba(42,182,217,.08);text-decoration:none;color:var(--text);
  transition:border-color .15s,background .15s;
}
.tg-banner:hover{border-color:rgba(42,182,217,.6);background:rgba(42,182,217,.13)}
.tg-banner-text{flex:1;min-width:0}
.tg-banner-text b{display:block;color:var(--white);font-size:.95rem}
.tg-banner-text span{display:block;color:var(--muted);font-size:.82rem;margin-top:2px}
.tg-banner-arrow{width:18px;height:18px;flex:none;stroke:#2AB6D9;fill:none;stroke-width:2;stroke-linecap:round}

/* ---- order row with a leading platform icon --------------------------- */
.order-row{display:flex;align-items:center;gap:11px;padding:9px 0;border-bottom:1px solid var(--line);text-decoration:none;color:inherit}
.order-row:last-child{border-bottom:0}
.order-row-mid{flex:1;min-width:0}
.order-row-mid b{display:block;font-size:.9rem;font-weight:600;color:var(--white);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.order-row-mid small{display:block;color:var(--muted);font-size:.78rem;margin-top:1px}
.order-row-end{flex:none;display:flex;align-items:center;gap:8px}
.order-row-chevron{width:15px;height:15px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round}

/* ---- forms ----------------------------------------------------------- */
/* .field wraps either a <label class="field"><span>...</span><input></label>
   (native inputs) or a <div class="field"><label for="...">...</label><div
   id="mount"></div></div> (a custom dropdown, whose trigger button is built
   by select.js after the label's for= id) - both need the same caption
   styling, so the selector covers span and label as the caption element. */
.field{display:block;margin-bottom:14px}
.field > span, .field > label{display:block;margin-bottom:6px;font-size:.85rem;font-weight:500;color:var(--muted)}
input[type=text],input[type=email],input[type=password],input[type=number],select,textarea{
  width:100%;padding:12px 14px;border-radius:11px;border:1px solid var(--line);
  background:rgba(255,255,255,.05);color:var(--white);font:inherit;font-size:.95rem;
  transition:border-color .2s,box-shadow .2s;
}
select{appearance:none;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 20px) calc(50% + 2px),calc(100% - 15px) calc(50% + 2px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:40px}
/* the dropdown list itself is drawn by the OS, so it needs its own colours */
select option{background:var(--navy-800);color:var(--text)}
input::placeholder,textarea::placeholder{color:#6F82B4}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--blue-500);box-shadow:0 0 0 4px rgba(47,107,255,.2)}
input:disabled,select:disabled{opacity:.55;cursor:not-allowed}

/* ---- password show/hide (assets/password-toggle.js) ------------------- */
/* The wrapper hugs the input so the button can sit over its right edge
   without the .field markup changing on any of the six pages that have a
   password field. The extra right padding is what keeps a long password from
   running underneath the button. */
.pw{position:relative}
.field .pw > input{padding-right:46px}
.pw-toggle{
  position:absolute;right:5px;top:50%;transform:translateY(-50%);
  display:flex;align-items:center;justify-content:center;
  width:36px;height:36px;padding:0;border:0;border-radius:9px;
  background:transparent;color:var(--muted);cursor:pointer;
  transition:color .15s,background .15s;
}
.pw-toggle:hover{color:var(--blue-300);background:rgba(143,176,255,.08)}
.pw-toggle:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(47,107,255,.35)}
.pw-toggle svg{
  width:19px;height:19px;fill:none;stroke:currentColor;
  stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;
}
@media (max-width:520px){
  /* A comfortable tap target on a phone. The button is centred in the field,
     so growing it does not change the field's height. */
  .pw-toggle{width:44px;height:40px;right:1px}
  .field .pw > input{padding-right:50px}
}

/* ---- custom dropdown (assets/select.js) ------------------------------- */
.gs-select{position:relative}
.gs-select-trigger{
  width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:12px 14px;border-radius:11px;border:1px solid var(--line);
  background:rgba(255,255,255,.05);color:var(--white);font:inherit;font-size:.95rem;
  cursor:pointer;text-align:left;transition:border-color .2s,box-shadow .2s;
}
.gs-select-trigger:hover{border-color:rgba(143,176,255,.35)}
.gs-select-trigger:focus{outline:none}
.gs-select.is-open .gs-select-trigger,.gs-select-trigger:focus-visible{
  border-color:var(--blue-500);box-shadow:0 0 0 4px rgba(47,107,255,.2);
}
.gs-select.is-disabled .gs-select-trigger{opacity:.55;cursor:not-allowed}
.gs-select-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}
.gs-select-value.is-placeholder{color:#6F82B4}
.gs-select-caret{width:16px;height:16px;flex:none;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .18s}
.gs-select.is-open .gs-select-caret{transform:rotate(180deg);stroke:var(--blue-300)}

.gs-select-panel{
  position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:20;
  background:var(--navy-800);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 20px 44px -14px rgba(0,0,0,.65);overflow:hidden;
  animation:gsSelectIn .14s ease both;
}
.gs-select-panel-up{top:auto;bottom:calc(100% + 6px)}
@keyframes gsSelectIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

.gs-select-search{padding:8px;border-bottom:1px solid var(--line)}
.gs-select-search input{
  width:100%;padding:9px 12px;border-radius:9px;border:1px solid var(--line);
  background:rgba(255,255,255,.05);color:var(--white);font:inherit;font-size:.9rem;
}
.gs-select-search input::placeholder{color:#6F82B4}
.gs-select-search input:focus{outline:none;border-color:var(--blue-500)}

.gs-select-list{list-style:none;margin:0;padding:6px;max-height:280px;overflow-y:auto;-webkit-overflow-scrolling:touch}
.gs-select-option{
  padding:10px 12px;border-radius:8px;font-size:.92rem;color:var(--text);cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.gs-select-option:hover,.gs-select-option.is-active{background:var(--card);color:var(--white)}
.gs-select-option.is-selected{background:rgba(47,107,255,.15);color:var(--blue-300);font-weight:600}
.gs-select-empty{padding:16px;text-align:center;color:var(--muted);font-size:.88rem}

@media (max-width:520px){
  /* Bigger tap targets and a taller sheet-like panel on a phone. */
  .gs-select-trigger{padding:13px 14px}
  .gs-select-option{padding:12px}
  .gs-select-list{max-height:min(280px, 45vh)}
}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:12px 20px;border:0;border-radius:11px;cursor:pointer;font:inherit;font-weight:600;font-size:.94rem;
  color:#fff;background:linear-gradient(180deg,var(--blue-400),var(--blue-500));
  box-shadow:0 10px 26px -10px rgba(47,107,255,.85);
  transition:transform .15s,box-shadow .15s,opacity .15s;text-decoration:none;
}
.btn:hover{transform:translateY(-1px);box-shadow:0 16px 32px -12px rgba(47,107,255,.95)}
.btn:active{transform:translateY(0)}
.btn[disabled],.btn.is-busy{opacity:.55;cursor:not-allowed;transform:none;box-shadow:none}
.btn-block{width:100%}
.btn-secondary{background:transparent;border:1px solid var(--line);box-shadow:none;color:var(--text)}
.btn-secondary:hover{background:var(--card);box-shadow:none}
/* outlined, never filled: a filled red button invites the mis-click */
.btn-danger{background:transparent;border:1px solid rgba(255,120,120,.45);box-shadow:none;color:var(--danger)}
.btn-danger:hover{background:rgba(255,120,120,.08);box-shadow:none}

/* ---- pool picker (buy.php) -------------------------------------------- */
/* One row per upstream pool: radio, name, stock, price. The whole row is the
   <label>, so the tap target is the full width on a phone. */
.pools{border:0;margin:0 0 14px;padding:0;min-width:0}
.pools legend{padding:0;margin-bottom:8px}
.pool-list{display:grid;gap:8px;max-height:320px;overflow-y:auto}
.pool{
  display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:"radio name price" "radio stock price";
  align-items:center;column-gap:12px;padding:11px 14px;border-radius:11px;
  border:1px solid var(--line);background:rgba(255,255,255,.03);cursor:pointer;
  transition:border-color .15s,background .15s;
}
.pool:hover{border-color:rgba(143,176,255,.35)}
.pool:has(input:checked){border-color:var(--blue-500);background:rgba(47,107,255,.1)}
.pool:has(input:focus-visible){box-shadow:0 0 0 3px rgba(47,107,255,.35)}
.pool input{grid-area:radio;margin:0;accent-color:var(--blue-500);width:16px;height:16px}
.pool-name{grid-area:name;font-weight:600;color:var(--white);font-size:.92rem}
.pool-stock{grid-area:stock;font-size:.78rem;color:var(--muted)}
.pool-price{grid-area:price;color:var(--white)}
.pool.is-out{opacity:.5;cursor:not-allowed}

/* ---- consent checkbox (wallet.php deposit agreement) ------------------ */
.agree{display:flex;gap:10px;align-items:flex-start;margin:0 0 16px;font-size:.85rem;color:var(--muted);line-height:1.5;cursor:pointer}
.agree input{flex:none;margin:3px 0 0;width:16px;height:16px;accent-color:var(--blue-500)}
.agree strong{color:var(--white)}

/* ---- notices --------------------------------------------------------- */
.notice{margin:0 0 16px;font-size:.9rem;padding:11px 14px;border-radius:11px;border:1px solid var(--line);background:var(--card)}
.notice.ok{color:#8FF0BC;border-color:rgba(74,222,128,.3)}
.notice.err{color:var(--danger);border-color:rgba(255,120,120,.3)}
.notice.warn{color:var(--warn);border-color:rgba(251,191,36,.3)}

/* ---- impersonation banner -------------------------------------------- */
/* Shown on every signed-in page while an admin is signed in as a customer
   (see includes/auth.php login-as-user). Amber on purpose: it must read as
   "this is not your account" at a glance, not blend into the topbar. */
.impersonation-bar{
  position:relative;z-index:2;display:flex;align-items:center;justify-content:space-between;
  flex-wrap:wrap;gap:10px;
  padding:10px max(16px,env(safe-area-inset-right)) 10px max(16px,env(safe-area-inset-left));
  background:rgba(251,191,36,.12);border-bottom:1px solid rgba(251,191,36,.35);
  font-size:.85rem;color:var(--warn);
}
.impersonation-bar .btn{padding:7px 14px;font-size:.82rem}

/* ---- badges ---------------------------------------------------------- */
.badge{
  display:inline-flex;align-items:center;gap:6px;padding:4px 11px;border-radius:999px;
  font-size:.72rem;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  border:1px solid var(--line);background:var(--card);color:var(--muted);white-space:nowrap;
}
.badge-active{color:var(--warn);border-color:rgba(251,191,36,.45);background:rgba(251,191,36,.08)}
.badge-received{color:var(--ok);border-color:rgba(74,222,128,.45);background:rgba(74,222,128,.08)}
.badge-refunded,.badge-cancelled{color:var(--danger);border-color:rgba(255,120,120,.4);background:rgba(255,120,120,.07)}
.badge-expired{color:var(--muted)}
.dot{width:7px;height:7px;border-radius:50%;background:currentColor;flex:none}
.dot-pulse{box-shadow:0 0 0 0 currentColor;animation:pulse 2s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 8px transparent}100%{box-shadow:0 0 0 0 transparent}}

/* ---- tables ---------------------------------------------------------- */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:.89rem}
th{
  text-align:left;padding:10px 12px;font-size:.74rem;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);border-bottom:1px solid var(--line);white-space:nowrap;
}
td{padding:12px;border-bottom:1px solid var(--line);vertical-align:middle}
tr:last-child td{border-bottom:0}
td.num{text-align:right;font-variant-numeric:tabular-nums}
.empty{padding:36px 16px;text-align:center;color:var(--muted)}

/* ---- the received SMS code - the thing the customer came for --------- */
.code-box{
  display:flex;align-items:center;justify-content:center;gap:14px;
  padding:22px;border-radius:var(--radius);
  border:1px solid rgba(74,222,128,.4);background:rgba(74,222,128,.07);
}
.code-box b{font-size:2.1rem;font-weight:700;letter-spacing:.14em;color:var(--white);font-variant-numeric:tabular-nums}

/* click-to-copy, used for the number and the code */
.copy{
  display:inline-flex;align-items:center;gap:8px;padding:9px 14px;border-radius:10px;
  border:1px solid var(--line);background:var(--card);cursor:pointer;
  font:inherit;font-weight:600;color:var(--text);font-variant-numeric:tabular-nums;
}
.copy:hover{border-color:var(--blue-500)}
.copy.copied{border-color:var(--ok);color:var(--ok)}

/* ---- auth pages ------------------------------------------------------ */
.auth{max-width:420px;margin:44px auto;width:100%}
.auth .card{padding:26px}
.auth-logo{display:flex;flex-direction:column;align-items:center;gap:10px;margin-bottom:22px;text-decoration:none}
.auth-logo img{width:54px;height:54px}
.auth-logo b{font-size:1.35rem;font-weight:800;letter-spacing:-.03em;color:var(--white)}
.auth-logo b span{color:var(--blue-500)}
.auth-alt{margin:18px 0 0;text-align:center;font-size:.88rem;color:var(--muted)}

/* ---- entrance -------------------------------------------------------- */
/* fill-mode is `backwards`, NOT `both`, and that is load-bearing.
   `both` keeps the animation's final transform applied forever, and Chrome
   computes a filled transform animation as the identity matrix -
   matrix(1,0,0,1,0,0) - which is not `none`. Any non-none transform makes the
   element a stacking context, so every .rise card became one permanently and
   trapped the z-index of anything positioned inside it. That is the bug where
   the buy page's open service list rendered underneath the "How it works"
   card: the dropdown's z-index:20 was scoped to its own card, and the next
   card painted over it. `backwards` still holds the start state through the
   delay and still animates, but drops the fill at the end, so the transform
   reverts to none and the element stops being a stacking context. The end
   state (opacity 1, translateY 0) is identical to the un-animated state, so
   nothing flashes. */
.rise{animation:rise .8s cubic-bezier(.2,.7,.3,1) backwards}
.rise-2{animation-delay:.06s}
.rise-3{animation-delay:.12s}
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}

/* small spinner for in-flight buttons and polling */
.spin{width:15px;height:15px;border-radius:50%;border:2px solid rgba(255,255,255,.28);border-top-color:#fff;animation:spin .7s linear infinite;flex:none}
@keyframes spin{to{transform:rotate(360deg)}}

.muted{color:var(--muted)}
.right{text-align:right}
.center{text-align:center}
.row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.row-between{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.stack-8 > * + *{margin-top:8px}
.stack-16 > * + *{margin-top:16px}
.hidden{display:none!important}

@media (max-width:720px){
  main{padding-top:20px;padding-bottom:40px}
  h1{font-size:1.35rem}
  .topbar-inner{gap:10px}
  .code-box b{font-size:1.7rem}
  .grid-3{grid-template-columns:1fr}
  .stat-grid .stat b{font-size:.95rem;overflow-wrap:break-word;white-space:normal}
  .stat-grid .stat small{white-space:normal;overflow-wrap:break-word}
  .stat-grid .card{padding:10px 12px}

  /* Collapse the link list behind the hamburger: brand, wallet balance and
     the toggle stay in the topbar row; everything else (Dashboard, Buy,
     Orders, Wallet, Profile, Admin, Sign out / the admin nav) drops into a
     panel anchored under .topbar (which is the position:relative ancestor). */
  .nav-toggle{display:inline-flex}
  .nav{
    display:none;position:absolute;top:100%;left:0;right:0;z-index:3;
    flex-direction:column;align-items:stretch;flex-wrap:nowrap;gap:2px;
    margin-left:0;background:var(--navy-800);border-bottom:1px solid var(--line);
    box-shadow:0 18px 34px -12px rgba(0,0,0,.65);
    padding:10px max(16px, env(safe-area-inset-right)) max(10px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  }
  .nav.open{display:flex}
  .nav a{padding:11px 12px}
  .nav-signout{border-top:1px solid var(--line);margin-top:4px;padding-top:14px!important}

  /* The logged-out nav is only two items (Sign in / Get started) and has no
     hamburger toggle to reveal it - it must stay inline, not collapse like
     the logged-in link list does. Without this override the general .nav
     rule above hides it with no way to open it. */
  .nav-guest{
    display:flex!important;position:static;flex-direction:row;flex-wrap:nowrap;
    background:none;border:0;box-shadow:none;padding:0;margin-left:auto;gap:8px;
  }
  .nav-guest a{padding:8px 10px;font-size:.85rem}

  /* A large balance ("₦1,234,567.00") plus the brand and the toggle can get
     tight at a 393px iPhone viewport - drop the "Balance" label first since
     the pill shape and the money format already say what the number is. */
  .chip small{display:none}
  .chip{padding:7px 11px}
}

@media (max-width:400px){
  .brand{font-size:1rem}
  .brand img{width:26px;height:26px}
}

/* Coverage page. A <ul> of pills lists the whole catalogue without a wall of
   prose and wraps cleanly from 320px up, which matters because every visitor
   here is assumed to be on a phone (see header.php). */
.pills{display:flex;flex-wrap:wrap;gap:8px;margin:0;padding:0;list-style:none}
.pills li{padding:7px 13px;border-radius:999px;border:1px solid var(--line);background:var(--card);font-size:.85rem;color:var(--text)}
/* Countries get the quieter treatment: they are context for the services, not
   the thing being chosen. */
.pills-sm li{font-size:.8rem;padding:6px 11px;color:var(--muted)}
.pill-count{margin:0 0 14px;font-size:.85rem;color:var(--muted)}

/* ---- rental SMS rows (assets/extras.js) ------------------------------- */
/* Carried over from the removed Pay Bills feature; kept because the rental
   inbox renders each received message with this class. */
.msg-row{display:block;padding:9px 0;border-bottom:1px solid var(--line);text-decoration:none;color:inherit;font-size:.88rem}
.msg-row:last-child{border-bottom:0}

/* ---- admin tables: search / filter / sort / pages (includes/AdminTable.php) ---- */
/* The bar wraps instead of overflowing: every control has min-width:0 and flexes,
   so on a 393px phone it stacks into rows rather than pushing the page wider. */
.tb{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 16px}
.tb input[type=search],.tb input[type=date],.tb select{min-width:0;width:auto;padding:10px 12px;font-size:.88rem}
/* The app's base input rule covers text/email/password/number only, so search and
   date would fall back to the browser's white controls. color-scheme:dark also
   darkens the native date-picker icon and popup. */
.tb input[type=search],.tb input[type=date]{
  border-radius:11px;border:1px solid var(--line);background:rgba(255,255,255,.05);
  color:var(--white);font:inherit;font-size:.88rem;color-scheme:dark;
  transition:border-color .2s,box-shadow .2s;
}
.tb input[type=search]:focus,.tb input[type=date]:focus{outline:none;border-color:var(--blue-500);box-shadow:0 0 0 4px rgba(47,107,255,.2)}
.tb input[type=search]::placeholder{color:#6F82B4}
.tb input[type=search]::-webkit-search-cancel-button{filter:invert(1);opacity:.6}
.tb input[type=search]{flex:1 1 220px;max-width:340px}
.tb select{flex:0 1 auto;max-width:100%;padding-right:34px}
.tb .btn{padding:10px 16px;flex:none}
.tb-date{display:flex;align-items:center;gap:6px;color:var(--muted);font-size:.8rem}
.tb-date span{flex:none}
.tb-date input{flex:1 1 130px}
th a.sort{color:inherit;text-decoration:none;white-space:nowrap}
th a.sort:hover{color:var(--white)}
th a.sort.is-sorted{color:var(--blue-300)}
.pager-wrap{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;margin-top:14px}
.pager-info{margin:0;font-size:.85rem}
.pager{display:flex;flex-wrap:wrap;gap:6px}
.pg{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:36px;padding:0 10px;border-radius:9px;border:1px solid var(--line);background:var(--card);color:var(--text);font-size:.85rem;font-weight:600;text-decoration:none}
a.pg:hover{border-color:var(--blue-500)}
.pg.is-current{background:rgba(47,107,255,.2);border-color:var(--blue-500);color:var(--white)}
.pg.is-disabled{opacity:.4}
.pg.is-gap{border-color:transparent;background:none;min-width:20px;padding:0}
@media (max-width:520px){
  .tb input[type=search]{flex:1 1 100%;max-width:none}
  .tb select{flex:1 1 calc(50% - 4px)}
  .tb-date{flex:1 1 calc(50% - 4px)}
  .tb .btn{flex:1 1 calc(50% - 4px)}
  .pager-wrap{justify-content:center}
}

/* ---- manage user detail rows (admin/user.php) ------------------------- */
.detail-list{display:flex;flex-direction:column;gap:0}
.detail-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 0;border-bottom:1px solid rgba(143,176,255,.06)}
.detail-row:last-child{border-bottom:0}
.detail-label{font-size:.78rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);flex:none}

/* ---- responsive admin table - card layout on mobile ------------------- */
@media (max-width:720px){
  .hide-mobile{display:none!important}
  .tbl-cards .table-wrap{overflow:visible}
  .tbl-cards table{display:block}
  .tbl-cards thead{clip:rect(0,0,0,0);position:absolute;height:1px;width:1px;overflow:hidden}
  .tbl-cards tbody{display:block}
  .tbl-cards tr{display:block;padding:14px;margin-bottom:12px;border:1px solid var(--line);border-radius:var(--radius);background:var(--card);box-shadow:var(--shadow)}
  .tbl-cards td{display:flex;align-items:center;justify-content:space-between;padding:6px 0;border-bottom:1px solid rgba(143,176,255,.06);text-align:right}
  .tbl-cards td:last-child{border-bottom:0}
  .tbl-cards td::before{content:attr(data-label);font-size:.74rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);flex:none;margin-right:12px;text-align:left}
  .tbl-cards td[data-label=""]::before{display:none}
  .tbl-cards td[data-label=""]{display:block;text-align:left}
  .tbl-cards td[data-label=""]:first-child{padding-bottom:10px;margin-bottom:4px;border-bottom:1px solid var(--line)}
  .tbl-cards td[data-label=""]:last-child{padding-top:6px;margin-top:2px}
  .tbl-cards td[data-label=""] .btn{width:100%}
  .tbl-cards td.empty{display:block;text-align:center;border:0;margin:0;padding:36px 16px}
}

/* Must stay last: it overrides every animation and transition above. */
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}
