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

   White canvas, one brand blue, navy for the rare dark band. Every colour is
   a token below; nothing in a rule further down is a hard-coded hex. */

@font-face{
  font-family:'Inter';
  src:url('fonts/InterVariable-latin.woff2') format('woff2');
  font-weight:100 900;font-style:normal;font-display:swap;
}

:root{
  /* brand */
  --blue-500:#2F6BFF;          /* the one action colour */
  --blue-600:#1F55E0;          /* hover darken */
  --blue-700:#1844B8;          /* pressed */
  --blue-50:#EEF3FF;           /* tinted fills: selected rows, chips */
  --blue-100:#DCE6FF;
  --navy-900:#060F2E;          /* dark bands only */
  --navy-800:#0B1B48;

  /* neutrals */
  --canvas:#FFFFFF;
  --surface:#F6F8FC;           /* page floor behind cards in the app */
  --surface-strong:#EDF1F8;    /* secondary buttons, input wells */
  --ink:#0A1530;               /* headings, numbers */
  --text:#2A3554;              /* running text */
  --muted:#66728F;             /* labels, meta */
  --muted-soft:#97A1B8;        /* placeholders */
  --line:#E1E6EF;              /* 1px hairlines */
  --line-soft:#EEF1F6;
  --card:#FFFFFF;
  --link:#1F55E0;

  /* semantic - meaning, never decoration */
  --ok:#05A35F;
  --ok-bg:#E8F7EF;
  --warn:#B26B00;
  --warn-bg:#FFF5E1;
  --danger:#CF202F;
  --danger-bg:#FDECEE;

  --shadow:0 1px 2px rgba(10,21,48,.04),0 4px 14px rgba(10,21,48,.04);
  --shadow-pop:0 18px 44px -12px rgba(10,21,48,.22);
  --radius:20px;
  --radius-sm:12px;
  --pill:999px;
  --focus:0 0 0 4px rgba(47,107,255,.18);
}

*{box-sizing:border-box}
html,body{margin:0;padding:0;overflow-x:hidden}
body{
  min-height:100svh;
  background:var(--surface);
  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;
  font-feature-settings:'cv11','ss01';
  display:flex;
  flex-direction:column;
}
a{color:var(--link)}

/* The old ambient grid, now a soft blue wash at the top of the page so the
   app does not read as a bare form on grey. */
.grid{
  position:absolute;left:0;right:0;top:0;height:340px;z-index:0;pointer-events:none;
  background:linear-gradient(180deg,var(--blue-50),rgba(238,243,255,0));
}

/* ---- chrome ---------------------------------------------------------- */
.topbar{
  position:sticky;top:0;z-index:5;border-bottom:1px solid var(--line);
  background:rgba(255,255,255,.9);backdrop-filter:saturate(1.4) blur(12px);
  -webkit-backdrop-filter:saturate(1.4) blur(12px);
}
/* 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:1200px;margin:0 auto;display:flex;align-items:center;gap:16px;min-height:64px;
  padding-top:max(10px, env(safe-area-inset-top));
  padding-bottom:10px;
  padding-left:max(16px, env(safe-area-inset-left));
  padding-right:max(16px, env(safe-area-inset-right));
}
/* Wordmark: NUMBA in ink, XS in brand blue - the split the logo uses. */
.brand{display:flex;align-items:center;gap:10px;font-weight:800;font-size:1.12rem;letter-spacing:-.02em;color:var(--ink);text-decoration:none;flex:none}
.brand .wm{color:var(--ink)}
.brand .wm span{color:var(--blue-500)}
.brand img{width:32px;height:32px;border-radius:9px}
.nav{display:flex;gap:2px;margin-left:auto;align-items:center;flex-wrap:wrap}
.nav a{
  padding:8px 13px;border-radius:var(--pill);font-size:.875rem;font-weight:500;
  color:var(--muted);text-decoration:none;transition:color .15s,background .15s;
  white-space:nowrap;
}
.nav a:hover{color:var(--ink);background:var(--surface-strong)}
.nav a.active{color:var(--blue-600);background:var(--blue-50)}
.nav a.btn,.nav a.btn:hover{color:#fff;background:var(--blue-500)}
.nav a.btn:hover{background:var(--blue-600)}

/* hamburger toggle - hidden until the mobile breakpoint below shows it */
.nav-toggle{
  display:none;flex:none;background:var(--canvas);border:1px solid var(--line);border-radius:var(--pill);
  width:40px;height:40px;align-items:center;justify-content:center;cursor:pointer;color:var(--ink);
}
.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:8px 14px;border-radius:var(--pill);
  border:1px solid var(--blue-100);background:var(--blue-50);font-size:.87rem;font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--blue-700);text-decoration:none;white-space:nowrap;
  flex:none;
}
.chip small{color:var(--muted);font-weight:600;font-size:.7rem;letter-spacing:.08em;text-transform:uppercase}

main{
  position:relative;z-index:1;flex:1;width:100%;max-width:1200px;margin:0 auto;
  padding-top:32px;padding-bottom:56px;
  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);background:var(--canvas);
  text-align:center;font-size:.82rem;color:var(--muted);
  padding-top:24px;
  padding-bottom:max(24px, 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(--text);text-decoration:none;font-weight:500}
footer a:hover{color:var(--blue-600)}

/* ---- type ------------------------------------------------------------ */
/* Display weight stays modest (600, not 800): calm and institutional, the
   way a bank talks rather than a trading app. */
h1{margin:0 0 6px;font-size:1.85rem;font-weight:600;letter-spacing:-.025em;line-height:1.15;color:var(--ink)}
h2{margin:0 0 14px;font-size:1.08rem;font-weight:600;letter-spacing:-.01em;color:var(--ink)}
h3{color:var(--ink)}
.lead{margin:0 0 26px;color:var(--muted);font-size:1rem}
.label{font-size:.8rem;font-weight:500;color:var(--muted)}
.money{font-weight:600;font-variant-numeric:tabular-nums;color:var(--ink)}
.mono{font-family:ui-monospace,SFMono-Regular,'JetBrains Mono',Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
strong{color:var(--ink)}

/* ---- cards ----------------------------------------------------------- */
.card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px;box-shadow:var(--shadow);
}
.card + .card{margin-top:16px}
/* ...but not side by side in a grid, where the margin pushes one column down. */
.grid-2 > .card + .card,.grid-3 > .card + .card,.stat-grid > .card + .card{margin-top:0}
.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.75rem;font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums;letter-spacing:-.025em}
.stat small{display:block;margin-top:2px;font-size:.74rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}

/* The wallet balance card is the one dark surface inside the app: the number
   a customer checks first gets the brand's navy, the way a bank app puts the
   card on top. */
.stat-balance{
  background:radial-gradient(120% 140% at 100% 0%,#1E4FD8 0%,var(--navy-800) 55%,var(--navy-900) 100%);
  border-color:transparent;color:#fff;
}
.stat-balance b{color:#fff}
.stat-balance .stat-label,.stat-balance small{color:#A9BBEA}
.stat-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}
.stat-label{font-size:.74rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.stat-action{
  display:inline-flex;align-items:center;gap:5px;flex:none;white-space:nowrap;
  padding:7px 13px;border-radius:var(--pill);font-size:.76rem;font-weight:600;text-decoration:none;
  background:var(--blue-500);color:#fff;transition:background .15s;
}
.stat-action:hover{background:var(--blue-600)}
.stat-balance .stat-action{background:#fff;color:var(--blue-700)}
.stat-balance .stat-action:hover{background:var(--blue-50)}
.stat-action svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;flex:none}

/* ---- 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:16px}
.field > span, .field > label{display:block;margin-bottom:6px;font-size:.85rem;font-weight:500;color:var(--text)}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=tel],input[type=url],select,textarea{
  width:100%;min-height:48px;padding:12px 16px;border-radius:var(--radius-sm);border:1px solid var(--line);
  background:var(--canvas);color:var(--ink);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}
select option{background:var(--canvas);color:var(--ink)}
input::placeholder,textarea::placeholder{color:var(--muted-soft)}
input:hover,select:hover,textarea:hover{border-color:#C9D2E3}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--blue-500);box-shadow:var(--focus)}
input:disabled,select:disabled{opacity:.6;cursor:not-allowed;background:var(--surface)}

/* ---- 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:48px}
.pw-toggle{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  display:flex;align-items:center;justify-content:center;
  width:36px;height:36px;padding:0;border:0;border-radius:var(--pill);
  background:transparent;color:var(--muted);cursor:pointer;
  transition:color .15s,background .15s;
}
.pw-toggle:hover{color:var(--blue-600);background:var(--blue-50)}
.pw-toggle:focus-visible{outline:none;box-shadow:var(--focus)}
.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:2px}
  .field .pw > input{padding-right:50px}
}

/* ---- custom dropdown (assets/select.js) ------------------------------- */
.nx-select{position:relative}
.nx-select-trigger{
  width:100%;min-height:48px;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:12px 16px;border-radius:var(--radius-sm);border:1px solid var(--line);
  background:var(--canvas);color:var(--ink);font:inherit;font-size:.95rem;
  cursor:pointer;text-align:left;transition:border-color .2s,box-shadow .2s;
}
.nx-select-trigger:hover{border-color:#C9D2E3}
.nx-select-trigger:focus{outline:none}
.nx-select.is-open .nx-select-trigger,.nx-select-trigger:focus-visible{
  border-color:var(--blue-500);box-shadow:var(--focus);
}
.nx-select.is-disabled .nx-select-trigger{opacity:.6;cursor:not-allowed;background:var(--surface)}
.nx-select-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}
.nx-select-value.is-placeholder{color:var(--muted-soft)}
.nx-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}
.nx-select.is-open .nx-select-caret{transform:rotate(180deg);stroke:var(--blue-500)}

.nx-select-panel{
  position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:20;
  background:var(--canvas);border:1px solid var(--line);border-radius:16px;
  box-shadow:var(--shadow-pop);overflow:hidden;
  animation:nxSelectIn .14s ease both;
}
.nx-select-panel-up{top:auto;bottom:calc(100% + 6px)}
@keyframes nxSelectIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

.nx-select-search{padding:8px;border-bottom:1px solid var(--line-soft)}
.nx-select-search input{
  width:100%;min-height:40px;padding:9px 14px;border-radius:var(--pill);border:0;
  background:var(--surface-strong);color:var(--ink);font:inherit;font-size:.9rem;
}
.nx-select-search input::placeholder{color:var(--muted-soft)}
.nx-select-search input:focus{outline:none;box-shadow:var(--focus)}

.nx-select-list{list-style:none;margin:0;padding:6px;max-height:280px;overflow-y:auto;-webkit-overflow-scrolling:touch}
.nx-select-option{
  padding:10px 12px;border-radius:10px;font-size:.92rem;color:var(--text);cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.nx-select-option:hover,.nx-select-option.is-active{background:var(--surface-strong);color:var(--ink)}
.nx-select-option.is-selected{background:var(--blue-50);color:var(--blue-700);font-weight:600}
.nx-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. */
  .nx-select-trigger{padding:13px 16px}
  .nx-select-option{padding:12px}
  .nx-select-list{max-height:min(280px, 45vh)}
}

/* ---- buttons: every action is a pill ---------------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;
  padding:11px 22px;border:0;border-radius:var(--pill);cursor:pointer;font:inherit;font-weight:600;font-size:.94rem;
  color:#fff;background:var(--blue-500);
  transition:background .15s,opacity .15s,box-shadow .15s;text-decoration:none;white-space:nowrap;
}
.btn:hover{background:var(--blue-600)}
.btn:active{background:var(--blue-700)}
.btn:focus-visible{outline:none;box-shadow:var(--focus)}
.btn[disabled],.btn.is-busy{background:#A9BCE8;cursor:not-allowed}
.btn-block{width:100%}
.btn-secondary,.btn-ghost{background:var(--surface-strong);color:var(--ink)}
.btn-secondary:hover,.btn-ghost:hover{background:#E1E7F2}
.btn-secondary:active,.btn-ghost:active{background:#D6DEEC}
/* outlined, never filled: a filled red button invites the mis-click */
.btn-danger{background:transparent;border:1px solid rgba(207,32,47,.4);color:var(--danger)}
.btn-danger:hover{background:var(--danger-bg)}

/* ---- 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 16px;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:12px 16px;border-radius:14px;
  border:1px solid var(--line);background:var(--canvas);cursor:pointer;
  transition:border-color .15s,background .15s;
}
.pool:hover{border-color:#C9D2E3}
.pool:has(input:checked){border-color:var(--blue-500);background:var(--blue-50)}
.pool:has(input:focus-visible){box-shadow:var(--focus)}
.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(--ink);font-size:.92rem}
.pool-stock{grid-area:stock;font-size:.78rem;color:var(--muted)}
.pool-price{grid-area:price;color:var(--ink)}
.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(--ink)}

/* ---- notices --------------------------------------------------------- */
.notice{margin:0 0 16px;font-size:.9rem;padding:12px 16px;border-radius:14px;border:1px solid var(--line);background:var(--canvas);color:var(--text)}
.notice.ok{color:#05683D;background:var(--ok-bg);border-color:#BFE8D2}
.notice.err{color:#A3121F;background:var(--danger-bg);border-color:#F6C6CB}
.notice.warn{color:#7A4A00;background:var(--warn-bg);border-color:#F5DCA6}

/* ---- 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:4;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:var(--warn-bg);border-bottom:1px solid #F5DCA6;
  font-size:.85rem;color:#7A4A00;
}
.impersonation-bar strong{color:#5C3700}
.impersonation-bar .btn{min-height:34px;padding:6px 14px;font-size:.82rem}

/* ---- badges ---------------------------------------------------------- */
.badge{
  display:inline-flex;align-items:center;gap:6px;padding:4px 11px;border-radius:var(--pill);
  font-size:.7rem;font-weight:600;letter-spacing:.07em;text-transform:uppercase;
  background:var(--surface-strong);color:var(--muted);white-space:nowrap;
}
.badge-active{color:var(--warn);background:var(--warn-bg)}
.badge-received{color:var(--ok);background:var(--ok-bg)}
.badge-refunded,.badge-cancelled{color:var(--danger);background:var(--danger-bg)}
.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:.72rem;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);border-bottom:1px solid var(--line);white-space:nowrap;
}
td{padding:14px 12px;border-bottom:1px solid var(--line-soft);vertical-align:middle;color:var(--text)}
tr:last-child td{border-bottom:0}
tbody tr:hover td{background:#FAFBFE}
td.num{text-align:right;font-variant-numeric:tabular-nums}
.empty{padding:40px 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;flex-wrap:wrap;
  padding:24px;border-radius:var(--radius);
  border:1px solid #BFE8D2;background:var(--ok-bg);
}
.code-box b{font-size:2.2rem;font-weight:700;letter-spacing:.14em;color:var(--ink);font-variant-numeric:tabular-nums}

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

/* ---- auth pages ------------------------------------------------------ */
.auth{max-width:440px;margin:40px auto;width:100%}
.auth .card{padding:32px;box-shadow:var(--shadow-pop);border-color:var(--line-soft)}
.auth-logo{display:flex;flex-direction:column;align-items:center;gap:12px;margin-bottom:24px;text-decoration:none}
.auth-logo img{width:56px;height:56px;border-radius:16px}
.auth-logo b{font-size:1.4rem;font-weight:800;letter-spacing:-.02em;color:var(--ink)}
.auth-logo b span{color:var(--blue-500)}
.auth-alt{margin:20px 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 .6s cubic-bezier(.2,.7,.3,1) backwards}
.rise-2{animation-delay:.05s}
.rise-3{animation-delay:.1s}
@keyframes rise{from{opacity:0;transform:translateY(12px)}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(47,107,255,.25);border-top-color:var(--blue-500);animation:spin .7s linear infinite;flex:none}
.btn .spin{border-color:rgba(255,255,255,.35);border-top-color:#fff}
@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}

/* FAQ blocks on the public service pages. <details>, so no script and the
   answers stay in the DOM to be indexed. */
.faq details{border-bottom:1px solid var(--line);padding:0}
.faq summary{cursor:pointer;padding:16px 0;font-weight:600;color:var(--ink);list-style:none;display:flex;justify-content:space-between;gap:14px;align-items:flex-start}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'+';color:var(--blue-500);font-weight:600;font-size:1.2rem;line-height:1.1;flex:none}
.faq details[open] summary::after{content:'\2212'}
.faq details p{margin:0 0 16px;color:var(--muted);font-size:.92rem}

@media (max-width:720px){
  main{padding-top:22px;padding-bottom:40px}
  h1{font-size:1.45rem}
  .topbar-inner{gap:10px;min-height:58px}
  .code-box b{font-size:1.7rem}
  .grid-3{grid-template-columns:1fr}
  .stat-grid .stat b{font-size:1.1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .stat-grid .card{padding:12px 14px}
  .card{padding:18px}

  /* 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 positioned ancestor). */
  .nav-toggle{display:inline-flex}
  .chip-mobile-order{margin-left:auto}
  .nav{
    display:none;position:absolute;top:100%;left:0;right:0;z-index:6;
    flex-direction:column;align-items:stretch;flex-wrap:nowrap;gap:2px;
    margin-left:0;background:var(--canvas);border-bottom:1px solid var(--line);
    box-shadow:var(--shadow-pop);
    padding:10px max(16px, env(safe-area-inset-right)) max(12px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  }
  .nav.open{display:flex}
  .nav a{padding:12px 14px;border-radius:12px;font-size:.95rem}
  .nav-signout{border-top:1px solid var(--line);margin-top:4px;padding-top:14px!important;border-radius:0!important}

  /* The logged-out nav is only a couple of items 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:4px;
  }
  .nav-guest a{padding:8px 10px;font-size:.85rem}
  .nav-guest .nav-hide-sm{display:none}

  /* 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 12px}
}

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

/* 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 14px;border-radius:var(--pill);background:var(--surface-strong);font-size:.85rem;color:var(--ink);font-weight:500}
/* Countries get the quieter treatment: they are context for the services, not
   the thing being chosen. */
.pills-sm li{font-size:.8rem;padding:6px 12px;color:var(--muted);background:var(--canvas);border:1px solid var(--line);font-weight:400}
.pill-count{margin:0 0 14px;font-size:.85rem;color:var(--muted)}

/* ---- rental SMS rows (assets/extras.js) ------------------------------- */
.msg-row{display:block;padding:10px 0;border-bottom:1px solid var(--line-soft);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;min-height:42px;padding:9px 14px;font-size:.88rem}
.tb input[type=search],.tb input[type=date]{
  border-radius:var(--pill);border:1px solid var(--line);background:var(--canvas);
  color:var(--ink);font:inherit;font-size:.88rem;color-scheme:light;
  transition:border-color .2s,box-shadow .2s;
}
.tb select{border-radius:var(--pill)}
.tb input[type=search]:focus,.tb input[type=date]:focus{outline:none;border-color:var(--blue-500);box-shadow:var(--focus)}
.tb input[type=search]::placeholder{color:var(--muted-soft)}
.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{min-height:42px;padding:9px 18px;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(--ink)}
th a.sort.is-sorted{color:var(--blue-600)}
.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:var(--pill);border:1px solid var(--line);background:var(--canvas);color:var(--text);font-size:.85rem;font-weight:600;text-decoration:none}
a.pg:hover{border-color:var(--blue-500);color:var(--blue-600)}
.pg.is-current{background:var(--blue-500);border-color:var(--blue-500);color:#fff}
.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:10px 0;border-bottom:1px solid var(--line-soft)}
.detail-row:last-child{border-bottom:0}
.detail-label{font-size:.74rem;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 16px;margin-bottom:12px;border:1px solid var(--line);border-radius:16px;background:var(--canvas);box-shadow:var(--shadow)}
  .tbl-cards tbody tr:hover td{background:none}
  .tbl-cards td{display:flex;align-items:center;justify-content:space-between;padding:7px 0;border-bottom:1px solid var(--line-soft);text-align:right}
  .tbl-cards td:last-child{border-bottom:0}
  .tbl-cards td::before{content:attr(data-label);font-size:.72rem;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}
}

/* ---- site footer (includes/footer.php) -------------------------------- */
.site-footer{text-align:left;padding-top:40px}
.site-footer-inner{max-width:1200px;margin:0 auto;display:grid;grid-template-columns:2fr 1fr 1fr;gap:32px}
.site-footer-brand p{margin:12px 0 0;max-width:320px;color:var(--muted);font-size:.85rem;line-height:1.6}
.site-footer-col{display:flex;flex-direction:column;gap:8px}
.site-footer-col b{font-size:.72rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink);margin-bottom:4px}
.site-footer-col a{font-weight:400;color:var(--muted)}
.site-footer-legal{max-width:1200px;margin:32px auto 0;padding-top:18px;border-top:1px solid var(--line-soft);font-size:.78rem;color:var(--muted-soft)}
@media (max-width:720px){
  .site-footer-inner{grid-template-columns:1fr 1fr;gap:24px}
  .site-footer-brand{grid-column:1 / -1}
}
